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 exeception. 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 static int dash_arith(const char *);
1452 #ifdef CONFIG_ASH_RANDOM_SUPPORT
1453 static unsigned long rseed;
1454 static void change_random(const char *);
1455 # ifndef DYNAMIC_VAR
1456 # define DYNAMIC_VAR
1460 /* $NetBSD: init.h,v 1.9 2002/11/24 22:35:40 christos Exp $ */
1462 static void reset(void);
1464 /* $NetBSD: var.h,v 1.21 2003/01/22 20:36:04 dsl Exp $ */
1471 #define VEXPORT 0x01 /* variable is exported */
1472 #define VREADONLY 0x02 /* variable cannot be modified */
1473 #define VSTRFIXED 0x04 /* variable struct is statically allocated */
1474 #define VTEXTFIXED 0x08 /* text is statically allocated */
1475 #define VSTACK 0x10 /* text is allocated on the stack */
1476 #define VUNSET 0x20 /* the variable is not set */
1477 #define VNOFUNC 0x40 /* don't call the callback function */
1478 #define VNOSET 0x80 /* do not set variable - just readonly test */
1479 #define VNOSAVE 0x100 /* when text is on the heap before setvareq */
1481 # define VDYNAMIC 0x200 /* dynamic variable */
1487 struct var *next; /* next entry in hash list */
1488 int flags; /* flags are defined above */
1489 const char *text; /* name=value */
1490 void (*func)(const char *); /* function to be called when */
1491 /* the variable gets set/unset */
1495 struct localvar *next; /* next local variable in list */
1496 struct var *vp; /* the variable that was made local */
1497 int flags; /* saved flags */
1498 const char *text; /* saved text */
1502 static struct localvar *localvars;
1508 #ifdef CONFIG_ASH_GETOPTS
1509 static void getoptsreset(const char *);
1512 #ifdef CONFIG_LOCALE_SUPPORT
1514 static void change_lc_all(const char *value);
1515 static void change_lc_ctype(const char *value);
1521 static const char defpathvar[] = "PATH=/usr/local/bin:/usr/bin:/sbin:/bin";
1523 static const char defifsvar[] = "IFS= \t\n";
1524 #define defifs (defifsvar + 4)
1526 static const char defifs[] = " \t\n";
1530 static struct var varinit[] = {
1532 { 0, VSTRFIXED|VTEXTFIXED, defifsvar, 0 },
1534 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", 0 },
1537 #ifdef CONFIG_ASH_MAIL
1538 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail },
1539 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail },
1542 { 0, VSTRFIXED|VTEXTFIXED, defpathvar, changepath },
1543 { 0, VSTRFIXED|VTEXTFIXED, "PS1=$ ", 0 },
1544 { 0, VSTRFIXED|VTEXTFIXED, "PS2=> ", 0 },
1545 { 0, VSTRFIXED|VTEXTFIXED, "PS4=+ ", 0 },
1546 #ifdef CONFIG_ASH_GETOPTS
1547 { 0, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset },
1549 #ifdef CONFIG_ASH_RANDOM_SUPPORT
1550 {0, VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random },
1552 #ifdef CONFIG_LOCALE_SUPPORT
1553 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0", change_lc_all },
1554 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0", change_lc_ctype },
1556 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
1557 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0", NULL },
1561 #define vifs varinit[0]
1562 #ifdef CONFIG_ASH_MAIL
1563 #define vmail (&vifs)[1]
1564 #define vmpath (&vmail)[1]
1568 #define vpath (&vmpath)[1]
1569 #define vps1 (&vpath)[1]
1570 #define vps2 (&vps1)[1]
1571 #define vps4 (&vps2)[1]
1572 #define voptind (&vps4)[1]
1573 #ifdef CONFIG_ASH_GETOPTS
1574 #define vrandom (&voptind)[1]
1576 #define vrandom (&vps4)[1]
1578 #define defpath (defpathvar + 5)
1581 * The following macros access the values of the above variables.
1582 * They have to skip over the name. They return the null string
1583 * for unset variables.
1586 #define ifsval() (vifs.text + 4)
1587 #define ifsset() ((vifs.flags & VUNSET) == 0)
1588 #define mailval() (vmail.text + 5)
1589 #define mpathval() (vmpath.text + 9)
1590 #define pathval() (vpath.text + 5)
1591 #define ps1val() (vps1.text + 4)
1592 #define ps2val() (vps2.text + 4)
1593 #define ps4val() (vps4.text + 4)
1594 #define optindval() (voptind.text + 7)
1596 #define mpathset() ((vmpath.flags & VUNSET) == 0)
1598 static void setvar(const char *, const char *, int);
1599 static void setvareq(char *, int);
1600 static void listsetvar(struct strlist *, int);
1601 static char *lookupvar(const char *);
1602 static char *bltinlookup(const char *);
1603 static char **listvars(int, int, char ***);
1604 #define environment() listvars(VEXPORT, VUNSET, 0)
1605 static int showvars(const char *, int, int);
1606 static void poplocalvars(void);
1607 static int unsetvar(const char *);
1608 #ifdef CONFIG_ASH_GETOPTS
1609 static int setvarsafe(const char *, const char *, int);
1611 static int varcmp(const char *, const char *);
1612 static struct var **hashvar(const char *);
1615 static inline int varequal(const char *a, const char *b) {
1616 return !varcmp(a, b);
1620 static int loopnest; /* current loop nesting level */
1623 * The parsefile structure pointed to by the global variable parsefile
1624 * contains information about the current file being read.
1629 struct redirtab *next;
1634 static struct redirtab *redirlist;
1635 static int nullredirs;
1637 extern char **environ;
1639 /* $NetBSD: output.h,v 1.16 2002/11/24 22:35:42 christos Exp $ */
1642 static void outstr(const char *, FILE *);
1643 static void outcslow(int, FILE *);
1644 static void flushall(void);
1645 static void flusherr(void);
1646 static int out1fmt(const char *, ...)
1647 __attribute__((__format__(__printf__,1,2)));
1648 static int fmtstr(char *, size_t, const char *, ...)
1649 __attribute__((__format__(__printf__,3,4)));
1651 static int preverrout_fd; /* save fd2 before print debug if xflag is set. */
1654 static void out1str(const char *p)
1659 static void out2str(const char *p)
1666 * Initialization code.
1670 * This routine initializes the builtin variables.
1681 * PS1 depends on uid
1683 #if defined(CONFIG_FEATURE_COMMAND_EDITING) && defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
1684 vps1.text = "PS1=\\w \\$ ";
1687 vps1.text = "PS1=# ";
1690 end = vp + sizeof(varinit) / sizeof(varinit[0]);
1692 vpp = hashvar(vp->text);
1695 } while (++vp < end);
1704 basepf.nextc = basepf.buf = basebuf;
1709 signal(SIGCHLD, SIG_DFL);
1718 for (envp = environ ; *envp ; envp++) {
1719 if (strchr(*envp, '=')) {
1720 setvareq(*envp, VEXPORT|VTEXTFIXED);
1724 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
1725 setvar("PPID", ppid, 0);
1730 /* PEOF (the end of file marker) */
1733 * The input line number. Input.c just defines this variable, and saves
1734 * and restores it when files are pushed and popped. The user of this
1735 * package must set its value.
1738 static int pgetc(void);
1739 static int pgetc2(void);
1740 static int preadbuffer(void);
1741 static void pungetc(void);
1742 static void pushstring(char *, void *);
1743 static void popstring(void);
1744 static void setinputfile(const char *, int);
1745 static void setinputfd(int, int);
1746 static void setinputstring(char *);
1747 static void popfile(void);
1748 static void popallfiles(void);
1749 static void closescript(void);
1752 /* $NetBSD: jobs.h,v 1.17 2003/01/22 20:36:04 dsl Exp $ */
1755 /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
1758 #define FORK_NOJOB 2
1760 /* mode flags for showjob(s) */
1761 #define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
1762 #define SHOW_PID 0x04 /* include process pid */
1763 #define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
1767 * A job structure contains information about a job. A job is either a
1768 * single process or a set of processes contained in a pipeline. In the
1769 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1774 pid_t pid; /* process id */
1775 int status; /* last process status from wait() */
1776 char *cmd; /* text of command being run */
1780 struct procstat ps0; /* status of process */
1781 struct procstat *ps; /* status or processes when more than one */
1783 int stopstatus; /* status of a stopped job */
1786 nprocs: 16, /* number of processes */
1788 #define JOBRUNNING 0 /* at least one proc running */
1789 #define JOBSTOPPED 1 /* all procs are stopped */
1790 #define JOBDONE 2 /* all procs are completed */
1792 sigint: 1, /* job was killed by SIGINT */
1793 jobctl: 1, /* job running under job control */
1795 waited: 1, /* true if this entry has been waited for */
1796 used: 1, /* true if this entry is in used */
1797 changed: 1; /* true if status has changed */
1798 struct job *prev_job; /* previous job */
1801 static pid_t backgndpid; /* pid of last background process */
1802 static int job_warning; /* user was warned about stopped jobs */
1804 static int jobctl; /* true if doing job control */
1807 static struct job *makejob(union node *, int);
1808 static int forkshell(struct job *, union node *, int);
1809 static int waitforjob(struct job *);
1810 static int stoppedjobs(void);
1813 #define setjobctl(on) /* do nothing */
1815 static void setjobctl(int);
1816 static void showjobs(FILE *, int);
1819 /* $NetBSD: main.h,v 1.9 2002/11/24 22:35:41 christos Exp $ */
1822 /* pid of main shell */
1824 /* true if we aren't a child of the main shell */
1825 static int rootshell;
1827 static void readcmdfile(char *);
1828 static void cmdloop(int);
1830 /* $NetBSD: memalloc.h,v 1.13 2003/01/22 20:36:04 dsl Exp $ */
1834 struct stack_block *stackp;
1837 struct stackmark *marknext;
1840 /* minimum size of a block */
1841 #define MINSIZE SHELL_ALIGN(504)
1843 struct stack_block {
1844 struct stack_block *prev;
1845 char space[MINSIZE];
1848 static struct stack_block stackbase;
1849 static struct stack_block *stackp = &stackbase;
1850 static struct stackmark *markp;
1851 static char *stacknxt = stackbase.space;
1852 static size_t stacknleft = MINSIZE;
1853 static char *sstrend = stackbase.space + MINSIZE;
1854 static int herefd = -1;
1857 static pointer ckmalloc(size_t);
1858 static pointer ckrealloc(pointer, size_t);
1859 static char *savestr(const char *);
1860 static pointer stalloc(size_t);
1861 static void stunalloc(pointer);
1862 static void setstackmark(struct stackmark *);
1863 static void popstackmark(struct stackmark *);
1864 static void growstackblock(void);
1865 static void *growstackstr(void);
1866 static char *makestrspace(size_t, char *);
1867 static char *stnputs(const char *, size_t, char *);
1868 static char *stputs(const char *, char *);
1871 static inline char *_STPUTC(char c, char *p) {
1878 #define stackblock() ((void *)stacknxt)
1879 #define stackblocksize() stacknleft
1880 #define STARTSTACKSTR(p) ((p) = stackblock())
1881 #define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1882 #define CHECKSTRSPACE(n, p) \
1886 size_t m = sstrend - q; \
1888 (p) = makestrspace(l, q); \
1891 #define USTPUTC(c, p) (*p++ = (c))
1892 #define STACKSTRNUL(p) ((p) == sstrend? (p = growstackstr(), *p = '\0') : (*p = '\0'))
1893 #define STUNPUTC(p) (--p)
1894 #define STTOPC(p) p[-1]
1895 #define STADJUST(amount, p) (p += (amount))
1897 #define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1898 #define ungrabstackstr(s, p) stunalloc((s))
1899 #define stackstrend() ((void *)sstrend)
1901 #define ckfree(p) free((pointer)(p))
1903 /* $NetBSD: mystring.h,v 1.10 2002/11/24 22:35:42 christos Exp $ */
1906 #define DOLATSTRLEN 4
1908 static char *prefix(const char *, const char *);
1909 static int number(const char *);
1910 static int is_number(const char *);
1911 static char *single_quote(const char *);
1912 static char *sstrdup(const char *);
1914 #define equal(s1, s2) (strcmp(s1, s2) == 0)
1915 #define scopy(s1, s2) ((void)strcpy(s2, s1))
1917 /* $NetBSD: options.h,v 1.16 2003/01/22 20:36:04 dsl Exp $ */
1920 int nparam; /* # of positional parameters (without $0) */
1921 unsigned char malloc; /* if parameter list dynamically allocated */
1922 char **p; /* parameter list */
1923 #ifdef CONFIG_ASH_GETOPTS
1924 int optind; /* next parameter to be processed by getopts */
1925 int optoff; /* used by getopts */
1930 #define eflag optlist[0]
1931 #define fflag optlist[1]
1932 #define Iflag optlist[2]
1933 #define iflag optlist[3]
1934 #define mflag optlist[4]
1935 #define nflag optlist[5]
1936 #define sflag optlist[6]
1937 #define xflag optlist[7]
1938 #define vflag optlist[8]
1939 #define Cflag optlist[9]
1940 #define aflag optlist[10]
1941 #define bflag optlist[11]
1942 #define uflag optlist[12]
1943 #define qflag optlist[13]
1946 #define nolog optlist[14]
1947 #define debug optlist[15]
1953 /* $NetBSD: options.c,v 1.33 2003/01/22 20:36:04 dsl Exp $ */
1956 static const char *const optletters_optnames[NOPTS] = {
1977 #define optletters(n) optletters_optnames[(n)][0]
1978 #define optnames(n) (&optletters_optnames[(n)][1])
1981 static char optlist[NOPTS];
1984 static char *arg0; /* value of $0 */
1985 static struct shparam shellparam; /* $@ current positional parameters */
1986 static char **argptr; /* argument list for builtin commands */
1987 static char *optionarg; /* set by nextopt (like getopt) */
1988 static char *optptr; /* used by nextopt */
1990 static char *minusc; /* argument to -c option */
1993 static void procargs(int, char **);
1994 static void optschanged(void);
1995 static void setparam(char **);
1996 static void freeparam(volatile struct shparam *);
1997 static int shiftcmd(int, char **);
1998 static int setcmd(int, char **);
1999 static int nextopt(const char *);
2001 /* $NetBSD: redir.h,v 1.14 2002/11/24 22:35:43 christos Exp $ */
2003 /* flags passed to redirect */
2004 #define REDIR_PUSH 01 /* save previous values of file descriptors */
2005 #define REDIR_SAVEFD2 03 /* set preverrout */
2008 static void redirect(union node *, int);
2009 static void popredir(int);
2010 static void clearredir(int);
2011 static int copyfd(int, int);
2012 static int redirectsafe(union node *, int);
2014 /* $NetBSD: show.h,v 1.6 2003/01/22 20:36:04 dsl Exp $ */
2018 static void showtree(union node *);
2019 static void trace(const char *, ...);
2020 static void tracev(const char *, va_list);
2021 static void trargs(char **);
2022 static void trputc(int);
2023 static void trputs(const char *);
2024 static void opentrace(void);
2027 /* $NetBSD: trap.h,v 1.16 2002/11/24 22:35:43 christos Exp $ */
2030 /* trap handler commands */
2031 static char *trap[NSIG];
2032 /* current value of signal */
2033 static char sigmode[NSIG - 1];
2034 /* indicates specified signal received */
2035 static char gotsig[NSIG - 1];
2037 static void clear_traps(void);
2038 static void setsignal(int);
2039 static void ignoresig(int);
2040 static void onsig(int);
2041 static void dotrap(void);
2042 static void setinteractive(int);
2043 static void exitshell(void) __attribute__((__noreturn__));
2044 static int decode_signal(const char *, int);
2047 * This routine is called when an error or an interrupt occurs in an
2048 * interactive shell and control is returned to the main command loop.
2063 parselleft = parsenleft = 0; /* clear input buffer */
2067 /* from parser.c: */
2080 #ifdef CONFIG_ASH_ALIAS
2081 static struct alias *atab[ATABSIZE];
2083 static void setalias(const char *, const char *);
2084 static struct alias *freealias(struct alias *);
2085 static struct alias **__lookupalias(const char *);
2088 setalias(const char *name, const char *val)
2090 struct alias *ap, **app;
2092 app = __lookupalias(name);
2096 if (!(ap->flag & ALIASINUSE)) {
2099 ap->val = savestr(val);
2100 ap->flag &= ~ALIASDEAD;
2103 ap = ckmalloc(sizeof (struct alias));
2104 ap->name = savestr(name);
2105 ap->val = savestr(val);
2114 unalias(const char *name)
2118 app = __lookupalias(name);
2122 *app = freealias(*app);
2133 struct alias *ap, **app;
2137 for (i = 0; i < ATABSIZE; i++) {
2139 for (ap = *app; ap; ap = *app) {
2140 *app = freealias(*app);
2149 static struct alias *
2150 lookupalias(const char *name, int check)
2152 struct alias *ap = *__lookupalias(name);
2154 if (check && ap && (ap->flag & ALIASINUSE))
2160 * TODO - sort output
2163 aliascmd(int argc, char **argv)
2172 for (i = 0; i < ATABSIZE; i++)
2173 for (ap = atab[i]; ap; ap = ap->next) {
2178 while ((n = *++argv) != NULL) {
2179 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
2180 if ((ap = *__lookupalias(n)) == NULL) {
2181 fprintf(stderr, "%s: %s not found\n", "alias", n);
2195 unaliascmd(int argc, char **argv)
2199 while ((i = nextopt("a")) != '\0') {
2205 for (i = 0; *argptr; argptr++) {
2206 if (unalias(*argptr)) {
2207 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
2215 static struct alias *
2216 freealias(struct alias *ap) {
2219 if (ap->flag & ALIASINUSE) {
2220 ap->flag |= ALIASDEAD;
2232 printalias(const struct alias *ap) {
2233 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
2236 static struct alias **
2237 __lookupalias(const char *name) {
2238 unsigned int hashval;
2245 ch = (unsigned char)*p;
2249 ch = (unsigned char)*++p;
2251 app = &atab[hashval % ATABSIZE];
2253 for (; *app; app = &(*app)->next) {
2254 if (equal(name, (*app)->name)) {
2261 #endif /* CONFIG_ASH_ALIAS */
2264 /* $NetBSD: cd.c,v 1.30 2003/01/22 20:36:03 dsl Exp $ */
2267 * The cd and pwd commands.
2270 #define CD_PHYSICAL 1
2273 static int docd(const char *, int);
2274 static int cdopt(void);
2276 static char *curdir = nullstr; /* current working directory */
2277 static char *physdir = nullstr; /* physical working directory */
2286 while ((i = nextopt("LP"))) {
2288 flags ^= CD_PHYSICAL;
2297 cdcmd(int argc, char **argv)
2309 dest = bltinlookup(homestr);
2310 else if (dest[0] == '-' && dest[1] == '\0') {
2311 dest = bltinlookup("OLDPWD");
2334 if (!(path = bltinlookup("CDPATH"))) {
2342 p = padvance(&path, dest);
2343 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2347 if (!docd(p, flags))
2352 error("can't cd to %s", dest);
2355 if (flags & CD_PRINT)
2356 out1fmt(snlfmt, curdir);
2362 * Update curdir (the name of the current directory) in response to a
2366 static inline const char *
2367 updatepwd(const char *dir)
2374 cdcomppath = sstrdup(dir);
2377 if (curdir == nullstr)
2379 new = stputs(curdir, new);
2381 new = makestrspace(strlen(dir) + 2, new);
2382 lim = stackblock() + 1;
2386 if (new > lim && *lim == '/')
2391 if (dir[1] == '/' && dir[2] != '/') {
2397 p = strtok(cdcomppath, "/");
2401 if (p[1] == '.' && p[2] == '\0') {
2408 } else if (p[1] == '\0')
2412 new = stputs(p, new);
2420 return stackblock();
2424 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2425 * know that the current directory has changed.
2429 docd(const char *dest, int flags)
2431 const char *dir = 0;
2434 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2437 if (!(flags & CD_PHYSICAL)) {
2438 dir = updatepwd(dest);
2453 * Find out what the current directory is. If we already know the current
2454 * directory, this routine returns immediately.
2456 static inline char *
2459 char *dir = getcwd(0, 0);
2460 return dir ? dir : nullstr;
2464 pwdcmd(int argc, char **argv)
2467 const char *dir = curdir;
2471 if (physdir == nullstr)
2475 out1fmt(snlfmt, dir);
2480 setpwd(const char *val, int setold)
2484 oldcur = dir = curdir;
2487 setvar("OLDPWD", oldcur, VEXPORT);
2490 if (physdir != nullstr) {
2491 if (physdir != oldcur)
2495 if (oldcur == val || !val) {
2502 if (oldcur != dir && oldcur != nullstr) {
2507 setvar("PWD", dir, VEXPORT);
2510 /* $NetBSD: error.c,v 1.30 2003/01/22 20:36:03 dsl Exp $ */
2513 * Errors and exceptions.
2517 * Code to handle exceptions in C.
2522 static void exverror(int, const char *, va_list)
2523 __attribute__((__noreturn__));
2526 * Called to raise an exception. Since C doesn't include exceptions, we
2527 * just do a longjmp to the exception handler. The type of exception is
2528 * stored in the global variable "exception".
2535 if (handler == NULL)
2541 longjmp(handler->loc, 1);
2546 * Called from trap.c when a SIGINT is received. (If the user specifies
2547 * that SIGINT is to be trapped or ignored using the trap builtin, then
2548 * this routine is not called.) Suppressint is nonzero when interrupts
2549 * are held using the INTOFF macro. (The test for iflag is just
2550 * defensive programming.)
2560 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
2561 if (!(rootshell && iflag)) {
2562 signal(SIGINT, SIG_DFL);
2572 exvwarning(const char *msg, va_list ap)
2585 fprintf(errs, fmt, name, startlinno);
2586 vfprintf(errs, msg, ap);
2587 outcslow('\n', errs);
2591 * Exverror is called to raise the error exception. If the second argument
2592 * is not NULL then error prints an error message using printf style
2593 * formatting. It then raises the error exception.
2596 exverror(int cond, const char *msg, va_list ap)
2600 TRACE(("exverror(%d, \"", cond));
2602 TRACE(("\") pid=%d\n", getpid()));
2604 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
2607 exvwarning(msg, ap);
2616 error(const char *msg, ...)
2621 exverror(EXERROR, msg, ap);
2628 exerror(int cond, const char *msg, ...)
2633 exverror(cond, msg, ap);
2639 * error/warning routines for external builtins
2643 sh_warnx(const char *fmt, ...)
2648 exvwarning(fmt, ap);
2654 * Return a string describing an error. The returned string may be a
2655 * pointer to a static buffer that will be overwritten on the next call.
2656 * Action describes the operation that got the error.
2660 errmsg(int e, const char *em)
2662 if(e == ENOENT || e == ENOTDIR) {
2670 /* $NetBSD: eval.c,v 1.71 2003/01/23 03:33:16 rafal Exp $ */
2673 * Evaluate a command.
2676 /* flags in argument to evaltree */
2677 #define EV_EXIT 01 /* exit after evaluating tree */
2678 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2679 #define EV_BACKCMD 04 /* command executing within back quotes */
2682 static void evalloop(union node *, int);
2683 static void evalfor(union node *, int);
2684 static void evalcase(union node *, int);
2685 static void evalsubshell(union node *, int);
2686 static void expredir(union node *);
2687 static void evalpipe(union node *, int);
2688 static void evalcommand(union node *, int);
2689 static int evalbltin(const struct builtincmd *, int, char **);
2690 static int evalfun(struct funcnode *, int, char **, int);
2691 static void prehash(union node *);
2692 static int bltincmd(int, char **);
2695 static const struct builtincmd bltin = {
2701 * Called to reset things after an exception.
2705 * The eval commmand.
2709 evalcmd(int argc, char **argv)
2718 STARTSTACKSTR(concat);
2721 concat = stputs(p, concat);
2722 if ((p = *ap++) == NULL)
2724 STPUTC(' ', concat);
2726 STPUTC('\0', concat);
2727 p = grabstackstr(concat);
2736 * Execute a command or commands contained in a string.
2743 struct stackmark smark;
2745 setstackmark(&smark);
2748 while ((n = parsecmd(0)) != NEOF) {
2750 popstackmark(&smark);
2755 popstackmark(&smark);
2761 * Evaluate a parse tree. The value is left in the global variable
2766 evaltree(union node *n, int flags)
2769 void (*evalfn)(union node *, int);
2773 TRACE(("evaltree(NULL) called\n"));
2776 TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
2777 getpid(), n, n->type, flags));
2781 out1fmt("Node type = %d\n", n->type);
2786 evaltree(n->nnot.com, EV_TESTED);
2787 status = !exitstatus;
2790 expredir(n->nredir.redirect);
2791 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
2793 evaltree(n->nredir.n, flags & EV_TESTED);
2794 status = exitstatus;
2799 evalfn = evalcommand;
2801 if (eflag && !(flags & EV_TESTED))
2813 evalfn = evalsubshell;
2825 #error NAND + 1 != NOR
2827 #if NOR + 1 != NSEMI
2828 #error NOR + 1 != NSEMI
2830 isor = n->type - NAND;
2833 (flags | ((isor >> 1) - 1)) & EV_TESTED
2835 if (!exitstatus == isor)
2847 evaltree(n->nif.test, EV_TESTED);
2850 if (exitstatus == 0) {
2853 } else if (n->nif.elsepart) {
2854 n = n->nif.elsepart;
2859 defun(n->narg.text, n->narg.next);
2863 exitstatus = status;
2869 if (flags & EV_EXIT || checkexit & exitstatus)
2874 #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
2877 void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
2881 evalloop(union node *n, int flags)
2891 evaltree(n->nbinary.ch1, EV_TESTED);
2893 skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
2897 if (evalskip == SKIPBREAK && --skipcount <= 0)
2902 if (n->type != NWHILE)
2906 evaltree(n->nbinary.ch2, flags);
2907 status = exitstatus;
2912 exitstatus = status;
2918 evalfor(union node *n, int flags)
2920 struct arglist arglist;
2923 struct stackmark smark;
2925 setstackmark(&smark);
2926 arglist.lastp = &arglist.list;
2927 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
2928 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
2933 *arglist.lastp = NULL;
2938 for (sp = arglist.list ; sp ; sp = sp->next) {
2939 setvar(n->nfor.var, sp->text, 0);
2940 evaltree(n->nfor.body, flags);
2942 if (evalskip == SKIPCONT && --skipcount <= 0) {
2946 if (evalskip == SKIPBREAK && --skipcount <= 0)
2953 popstackmark(&smark);
2959 evalcase(union node *n, int flags)
2963 struct arglist arglist;
2964 struct stackmark smark;
2966 setstackmark(&smark);
2967 arglist.lastp = &arglist.list;
2968 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
2970 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2971 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
2972 if (casematch(patp, arglist.list->text)) {
2973 if (evalskip == 0) {
2974 evaltree(cp->nclist.body, flags);
2981 popstackmark(&smark);
2987 * Kick off a subshell to evaluate a tree.
2991 evalsubshell(union node *n, int flags)
2994 int backgnd = (n->type == NBACKGND);
2997 expredir(n->nredir.redirect);
2998 if (!backgnd && flags & EV_EXIT && !trap[0])
3002 if (forkshell(jp, n, backgnd) == 0) {
3006 flags &=~ EV_TESTED;
3008 redirect(n->nredir.redirect, 0);
3009 evaltreenr(n->nredir.n, flags);
3014 status = waitforjob(jp);
3015 exitstatus = status;
3022 * Compute the names of the files in a redirection list.
3026 expredir(union node *n)
3030 for (redir = n ; redir ; redir = redir->nfile.next) {
3032 fn.lastp = &fn.list;
3033 switch (redir->type) {
3039 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
3040 redir->nfile.expfname = fn.list->text;
3044 if (redir->ndup.vname) {
3045 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
3046 fixredir(redir, fn.list->text, 1);
3056 * Evaluate a pipeline. All the processes in the pipeline are children
3057 * of the process creating the pipeline. (This differs from some versions
3058 * of the shell, which make the last process in a pipeline the parent
3063 evalpipe(union node *n, int flags)
3066 struct nodelist *lp;
3071 TRACE(("evalpipe(0x%lx) called\n", (long)n));
3073 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
3077 jp = makejob(n, pipelen);
3079 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
3083 if (pipe(pip) < 0) {
3085 error("Pipe call failed");
3088 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
3101 evaltreenr(lp->n, flags);
3109 if (n->npipe.backgnd == 0) {
3110 exitstatus = waitforjob(jp);
3111 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
3119 * Execute a command inside back quotes. If it's a builtin command, we
3120 * want to save its output in a block obtained from malloc. Otherwise
3121 * we fork off a subprocess and get the output of the command via a pipe.
3122 * Should be called with interrupts off.
3126 evalbackcmd(union node *n, struct backcmd *result)
3138 saveherefd = herefd;
3146 error("Pipe call failed");
3148 if (forkshell(jp, n, FORK_NOJOB) == 0) {
3157 evaltreenr(n, EV_EXIT);
3161 result->fd = pip[0];
3164 herefd = saveherefd;
3166 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
3167 result->fd, result->buf, result->nleft, result->jp));
3170 #ifdef CONFIG_ASH_CMDCMD
3171 static inline char **
3172 parse_command_args(char **argv, const char **path)
3184 if (c == '-' && !*cp) {
3194 /* run 'typecmd' for other options */
3197 } while ((c = *cp++));
3206 * Execute a simple command.
3210 evalcommand(union node *cmd, int flags)
3212 struct stackmark smark;
3214 struct arglist arglist;
3215 struct arglist varlist;
3218 const struct strlist *sp;
3219 struct cmdentry cmdentry;
3228 /* First expand the arguments. */
3229 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
3230 setstackmark(&smark);
3231 back_exitstatus = 0;
3233 cmdentry.cmdtype = CMDBUILTIN;
3234 cmdentry.u.cmd = &bltin;
3235 varlist.lastp = &varlist.list;
3236 *varlist.lastp = NULL;
3237 arglist.lastp = &arglist.list;
3238 *arglist.lastp = NULL;
3241 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
3242 struct strlist **spp;
3244 spp = arglist.lastp;
3245 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
3246 for (sp = *spp; sp; sp = sp->next)
3250 argv = nargv = stalloc(sizeof (char *) * (argc + 1));
3251 for (sp = arglist.list ; sp ; sp = sp->next) {
3252 TRACE(("evalcommand arg: %s\n", sp->text));
3253 *nargv++ = sp->text;
3258 if (iflag && funcnest == 0 && argc > 0)
3259 lastarg = nargv[-1];
3262 expredir(cmd->ncmd.redirect);
3263 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH|REDIR_SAVEFD2);
3266 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
3267 struct strlist **spp;
3270 spp = varlist.lastp;
3271 expandarg(argp, &varlist, EXP_VARTILDE);
3274 * Modify the command lookup path, if a PATH= assignment
3278 if (varequal(p, path))
3282 /* Print the command if xflag is set. */
3285 const char *p = " %s";
3288 dprintf(preverrout_fd, p, ps4val());
3291 for(n = 0; n < 2; n++) {
3293 dprintf(preverrout_fd, p, sp->text);
3301 bb_full_write(preverrout_fd, "\n", 1);
3307 /* Now locate the command. */
3309 const char *oldpath;
3310 int cmd_flag = DO_ERR;
3315 find_command(argv[0], &cmdentry, cmd_flag, path);
3316 if (cmdentry.cmdtype == CMDUNKNOWN) {
3322 /* implement bltin and command here */
3323 if (cmdentry.cmdtype != CMDBUILTIN)
3326 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
3327 if (cmdentry.u.cmd == EXECCMD)
3329 #ifdef CONFIG_ASH_CMDCMD
3330 if (cmdentry.u.cmd == COMMANDCMD) {
3333 nargv = parse_command_args(argv, &path);
3336 argc -= nargv - argv;
3338 cmd_flag |= DO_NOFUNC;
3346 /* We have a redirection error. */
3350 exitstatus = status;
3354 /* Execute the command. */
3355 switch (cmdentry.cmdtype) {
3357 /* Fork off a child process if necessary. */
3358 if (!(flags & EV_EXIT) || trap[0]) {
3360 jp = makejob(cmd, 1);
3361 if (forkshell(jp, cmd, FORK_FG) != 0) {
3362 exitstatus = waitforjob(jp);
3368 listsetvar(varlist.list, VEXPORT|VSTACK);
3369 shellexec(argv, path, cmdentry.u.index);
3373 cmdenviron = varlist.list;
3375 struct strlist *list = cmdenviron;
3377 if (spclbltin > 0 || argc == 0) {
3379 if (cmd_is_exec && argc > 1)
3382 listsetvar(list, i);
3384 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
3399 exit_status = j + 128;
3400 exitstatus = exit_status;
3402 if (i == EXINT || spclbltin > 0) {
3404 longjmp(handler->loc, 1);
3411 listsetvar(varlist.list, 0);
3412 if (evalfun(cmdentry.u.func, argc, argv, flags))
3418 popredir(cmd_is_exec);
3420 /* dsl: I think this is intended to be used to support
3421 * '_' in 'vi' command mode during line editing...
3422 * However I implemented that within libedit itself.
3424 setvar("_", lastarg, 0);
3425 popstackmark(&smark);
3429 evalbltin(const struct builtincmd *cmd, int argc, char **argv) {
3430 char *volatile savecmdname;
3431 struct jmploc *volatile savehandler;
3432 struct jmploc jmploc;
3435 savecmdname = commandname;
3436 if ((i = setjmp(jmploc.loc)))
3438 savehandler = handler;
3440 commandname = argv[0];
3442 optptr = NULL; /* initialize nextopt */
3443 exitstatus = (*cmd->builtin)(argc, argv);
3446 exitstatus |= ferror(stdout);
3447 commandname = savecmdname;
3449 handler = savehandler;
3455 evalfun(struct funcnode *func, int argc, char **argv, int flags)
3457 volatile struct shparam saveparam;
3458 struct localvar *volatile savelocalvars;
3459 struct jmploc *volatile savehandler;
3460 struct jmploc jmploc;
3463 saveparam = shellparam;
3464 savelocalvars = localvars;
3465 if ((e = setjmp(jmploc.loc))) {
3469 savehandler = handler;
3472 shellparam.malloc = 0;
3475 shellparam.nparam = argc - 1;
3476 shellparam.p = argv + 1;
3477 #ifdef CONFIG_ASH_GETOPTS
3478 shellparam.optind = 1;
3479 shellparam.optoff = -1;
3482 evaltree(&func->n, flags & EV_TESTED);
3488 localvars = savelocalvars;
3489 freeparam(&shellparam);
3490 shellparam = saveparam;
3491 handler = savehandler;
3493 if (evalskip == SKIPFUNC) {
3502 goodname(const char *p)
3504 return !*endofname(p);
3508 * Search for a command. This is called before we fork so that the
3509 * location of the command will be available in the parent as well as
3510 * the child. The check for "goodname" is an overly conservative
3511 * check that the name will not be subject to expansion.
3515 prehash(union node *n)
3517 struct cmdentry entry;
3519 if (n->type == NCMD && n->ncmd.args)
3520 if (goodname(n->ncmd.args->narg.text))
3521 find_command(n->ncmd.args->narg.text, &entry, 0,
3528 * Builtin commands. Builtin commands whose functions are closely
3529 * tied to evaluation are implemented here.
3537 bltincmd(int argc, char **argv)
3540 * Preserve exitstatus of a previous possible redirection
3543 return back_exitstatus;
3548 * Handle break and continue commands. Break, continue, and return are
3549 * all handled by setting the evalskip flag. The evaluation routines
3550 * above all check this flag, and if it is set they start skipping
3551 * commands rather than executing them. The variable skipcount is
3552 * the number of loops to break/continue, or the number of function
3553 * levels to return. (The latter is always 1.) It should probably
3554 * be an error to break out of more loops than exist, but it isn't
3555 * in the standard shell so we don't make it one here.
3559 breakcmd(int argc, char **argv)
3561 int n = argc > 1 ? number(argv[1]) : 1;
3564 error(illnum, argv[1]);
3568 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
3576 * The return command.
3580 returncmd(int argc, char **argv)
3582 int ret = argc > 1 ? number(argv[1]) : exitstatus;
3585 evalskip = SKIPFUNC;
3590 /* Do what ksh does; skip the rest of the file */
3591 evalskip = SKIPFILE;
3599 falsecmd(int argc, char **argv)
3606 truecmd(int argc, char **argv)
3613 execcmd(int argc, char **argv)
3616 iflag = 0; /* exit on error */
3619 shellexec(argv + 1, pathval(), 0);
3625 /* $NetBSD: exec.c,v 1.35 2003/01/22 20:36:04 dsl Exp $ */
3628 * When commands are first encountered, they are entered in a hash table.
3629 * This ensures that a full path search will not have to be done for them
3630 * on each invocation.
3632 * We should investigate converting to a linear search, even though that
3633 * would make the command name "hash" a misnomer.
3636 #define CMDTABLESIZE 31 /* should be prime */
3637 #define ARB 1 /* actual size determined at run time */
3642 struct tblentry *next; /* next entry in hash chain */
3643 union param param; /* definition of builtin function */
3644 short cmdtype; /* index identifying command */
3645 char rehash; /* if set, cd done since entry created */
3646 char cmdname[ARB]; /* name of command */
3650 static struct tblentry *cmdtable[CMDTABLESIZE];
3651 static int builtinloc = -1; /* index in path of %builtin, or -1 */
3654 static void tryexec(char *, char **, char **);
3655 static void clearcmdentry(int);
3656 static struct tblentry *cmdlookup(const char *, int);
3657 static void delete_cmd_entry(void);
3661 * Exec a program. Never returns. If you change this routine, you may
3662 * have to change the find_command routine as well.
3666 shellexec(char **argv, const char *path, int idx)
3673 envp = environment();
3674 if (strchr(argv[0], '/') != NULL
3675 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3676 || find_applet_by_name(argv[0])
3679 tryexec(argv[0], argv, envp);
3683 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3684 if (--idx < 0 && pathopt == NULL) {
3685 tryexec(cmdname, argv, envp);
3686 if (errno != ENOENT && errno != ENOTDIR)
3693 /* Map to POSIX errors */
3705 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
3706 argv[0], e, suppressint ));
3707 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3713 tryexec(char *cmd, char **argv, char **envp)
3716 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3720 #ifdef CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN
3721 name = bb_get_last_path_component(name);
3722 if(find_applet_by_name(name) != NULL)
3725 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(long);
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 len = fmtstr(expdest, 32, "%ld", num);
5917 STADJUST(len, expdest);
5922 varunset(const char *end, const char *var, const char *umsg, int varflags)
5928 msg = "parameter not set";
5930 if (*end == CTLENDVAR) {
5931 if (varflags & VSNUL)
5936 error("%.*s: %s%s", end - var - 1, var, msg, tail);
5940 /* $NetBSD: input.c,v 1.37 2002/11/24 22:35:40 christos Exp $ */
5943 * This implements the input routines used by the parser.
5946 #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
5947 #define IBUFSIZ (BUFSIZ + 1)
5949 static void pushfile(void);
5952 * Read a line from the script.
5955 static inline char *
5956 pfgets(char *line, int len)
5962 while (--nleft > 0) {
5979 * Read a character from the script, returning PEOF on end of file.
5980 * Nul characters in the input are silently discarded.
5983 #define pgetc_as_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
5985 #ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
5986 #define pgetc_macro() pgetc()
5990 return pgetc_as_macro();
5993 #define pgetc_macro() pgetc_as_macro()
5997 return pgetc_macro();
6003 * Same as pgetc(), but ignores PEOA.
6005 #ifdef CONFIG_ASH_ALIAS
6006 static int pgetc2(void)
6012 } while (c == PEOA);
6016 static inline int pgetc2(void)
6018 return pgetc_macro();
6023 #ifdef CONFIG_FEATURE_COMMAND_EDITING
6024 static const char *cmdedit_prompt;
6025 static inline void putprompt(const char *s)
6030 static inline void putprompt(const char *s)
6040 char *buf = parsefile->buf;
6044 #ifdef CONFIG_FEATURE_COMMAND_EDITING
6045 if (!iflag || parsefile->fd)
6046 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6048 cmdedit_path_lookup = pathval();
6049 nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
6051 /* Ctrl+C presend */
6061 /* Ctrl+D presend */
6066 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6070 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6071 int flags = fcntl(0, F_GETFL, 0);
6072 if (flags >= 0 && flags & O_NONBLOCK) {
6073 flags &=~ O_NONBLOCK;
6074 if (fcntl(0, F_SETFL, flags) >= 0) {
6075 out2str("sh: turning off NDELAY mode\n");
6085 * Refill the input buffer and return the next input character:
6087 * 1) If a string was pushed back on the input, pop it;
6088 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6089 * from a string so we can't refill the buffer, return EOF.
6090 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6091 * 4) Process input up to the next newline, deleting nul characters.
6101 while (parsefile->strpush) {
6102 #ifdef CONFIG_ASH_ALIAS
6103 if (parsenleft == -1 && parsefile->strpush->ap &&
6104 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
6109 if (--parsenleft >= 0)
6110 return (*parsenextc++);
6112 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6117 if (parselleft <= 0) {
6118 if ((parselleft = preadfd()) <= 0) {
6119 parselleft = parsenleft = EOF_NLEFT;
6126 /* delete nul characters */
6127 for (more = 1; more;) {
6134 parsenleft = q - parsenextc;
6135 more = 0; /* Stop processing here */
6142 if (--parselleft <= 0 && more) {
6143 parsenleft = q - parsenextc - 1;
6154 out2str(parsenextc);
6159 return *parsenextc++;
6163 * Undo the last call to pgetc. Only one character may be pushed back.
6164 * PEOF may be pushed back.
6175 * Push a string back onto the input at this current parsefile level.
6176 * We handle aliases this way.
6179 pushstring(char *s, void *ap)
6186 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6187 if (parsefile->strpush) {
6188 sp = ckmalloc(sizeof (struct strpush));
6189 sp->prev = parsefile->strpush;
6190 parsefile->strpush = sp;
6192 sp = parsefile->strpush = &(parsefile->basestrpush);
6193 sp->prevstring = parsenextc;
6194 sp->prevnleft = parsenleft;
6195 #ifdef CONFIG_ASH_ALIAS
6196 sp->ap = (struct alias *)ap;
6198 ((struct alias *)ap)->flag |= ALIASINUSE;
6210 struct strpush *sp = parsefile->strpush;
6213 #ifdef CONFIG_ASH_ALIAS
6215 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6216 checkkwd |= CHKALIAS;
6218 if (sp->string != sp->ap->val) {
6221 sp->ap->flag &= ~ALIASINUSE;
6222 if (sp->ap->flag & ALIASDEAD) {
6223 unalias(sp->ap->name);
6227 parsenextc = sp->prevstring;
6228 parsenleft = sp->prevnleft;
6229 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6230 parsefile->strpush = sp->prev;
6231 if (sp != &(parsefile->basestrpush))
6237 * Set the input to take input from a file. If push is set, push the
6238 * old input onto the stack first.
6242 setinputfile(const char *fname, int push)
6248 if ((fd = open(fname, O_RDONLY)) < 0)
6249 error("Can't open %s", fname);
6251 fd2 = copyfd(fd, 10);
6254 error("Out of file descriptors");
6257 setinputfd(fd, push);
6263 * Like setinputfile, but takes an open file descriptor. Call this with
6268 setinputfd(int fd, int push)
6270 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
6276 if (parsefile->buf == NULL)
6277 parsefile->buf = ckmalloc(IBUFSIZ);
6278 parselleft = parsenleft = 0;
6284 * Like setinputfile, but takes input from a string.
6288 setinputstring(char *string)
6292 parsenextc = string;
6293 parsenleft = strlen(string);
6294 parsefile->buf = NULL;
6301 * To handle the "." command, a stack of input files is used. Pushfile
6302 * adds a new entry to the stack and popfile restores the previous level.
6308 struct parsefile *pf;
6310 parsefile->nleft = parsenleft;
6311 parsefile->lleft = parselleft;
6312 parsefile->nextc = parsenextc;
6313 parsefile->linno = plinno;
6314 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
6315 pf->prev = parsefile;
6318 pf->basestrpush.prev = NULL;
6326 struct parsefile *pf = parsefile;
6335 parsefile = pf->prev;
6337 parsenleft = parsefile->nleft;
6338 parselleft = parsefile->lleft;
6339 parsenextc = parsefile->nextc;
6340 plinno = parsefile->linno;
6346 * Return to top level.
6352 while (parsefile != &basepf)
6358 * Close the file(s) that the shell is reading commands from. Called
6359 * after a fork is done.
6366 if (parsefile->fd > 0) {
6367 close(parsefile->fd);
6372 /* $NetBSD: jobs.c,v 1.56 2002/11/25 12:13:03 agc Exp $ */
6374 /* mode flags for set_curjob */
6375 #define CUR_DELETE 2
6376 #define CUR_RUNNING 1
6377 #define CUR_STOPPED 0
6379 /* mode flags for dowait */
6380 #define DOWAIT_NORMAL 0
6381 #define DOWAIT_BLOCK 1
6384 static struct job *jobtab;
6386 static unsigned njobs;
6388 /* pgrp of shell on invocation */
6389 static int initialpgrp;
6390 static int ttyfd = -1;
6393 static struct job *curjob;
6394 /* number of presumed living untracked jobs */
6397 static void set_curjob(struct job *, unsigned);
6399 static int restartjob(struct job *, int);
6400 static void xtcsetpgrp(int, pid_t);
6401 static char *commandtext(union node *);
6402 static void cmdlist(union node *, int);
6403 static void cmdtxt(union node *);
6404 static void cmdputs(const char *);
6405 static void showpipe(struct job *, FILE *);
6407 static int sprint_status(char *, int, int);
6408 static void freejob(struct job *);
6409 static struct job *getjob(const char *, int);
6410 static struct job *growjobtab(void);
6411 static void forkchild(struct job *, union node *, int);
6412 static void forkparent(struct job *, union node *, int, pid_t);
6413 static int dowait(int, struct job *);
6414 static int getstatus(struct job *);
6417 set_curjob(struct job *jp, unsigned mode)
6420 struct job **jpp, **curp;
6422 /* first remove from list */
6423 jpp = curp = &curjob;
6428 jpp = &jp1->prev_job;
6430 *jpp = jp1->prev_job;
6432 /* Then re-insert in correct position */
6440 /* job being deleted */
6443 /* newly created job or backgrounded job,
6444 put after all stopped jobs. */
6448 if (!jp1 || jp1->state != JOBSTOPPED)
6451 jpp = &jp1->prev_job;
6457 /* newly stopped job - becomes curjob */
6458 jp->prev_job = *jpp;
6466 * Turn job control on and off.
6468 * Note: This code assumes that the third arg to ioctl is a character
6469 * pointer, which is true on Berkeley systems but not System V. Since
6470 * System V doesn't have job control yet, this isn't a problem now.
6472 * Called with interrupts off.
6481 if (on == jobctl || rootshell == 0)
6485 ofd = fd = open(_PATH_TTY, O_RDWR);
6488 while (!isatty(fd) && --fd >= 0)
6491 fd = fcntl(fd, F_DUPFD, 10);
6495 fcntl(fd, F_SETFD, FD_CLOEXEC);
6496 do { /* while we are in the background */
6497 if ((pgrp = tcgetpgrp(fd)) < 0) {
6499 sh_warnx("can't access tty; job control turned off");
6503 if (pgrp == getpgrp())
6514 xtcsetpgrp(fd, pgrp);
6516 /* turning job control off */
6519 xtcsetpgrp(fd, pgrp);
6533 killcmd(int argc, char **argv)
6544 "Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6545 "kill -l [exitstatus]"
6549 if (**++argv == '-') {
6550 signo = decode_signal(*argv + 1, 1);
6554 while ((c = nextopt("ls:")) != '\0')
6564 signo = decode_signal(optionarg, 1);
6567 "invalid signal number or name: %s",
6578 if (!list && signo < 0)
6581 if ((signo < 0 || !*argv) ^ list) {
6589 for (i = 1; i < NSIG; i++) {
6590 name = u_signal_names(0, &i, 1);
6592 out1fmt(snlfmt, name);
6596 name = u_signal_names(*argptr, &signo, -1);
6598 out1fmt(snlfmt, name);
6600 error("invalid signal number or exit status: %s", *argptr);
6606 if (**argv == '%') {
6607 jp = getjob(*argv, 0);
6608 pid = -jp->ps[0].pid;
6610 pid = number(*argv);
6611 if (kill(pid, signo) != 0) {
6621 #if defined(JOBS) || defined(DEBUG)
6623 jobno(const struct job *jp)
6625 return jp - jobtab + 1;
6631 fgcmd(int argc, char **argv)
6638 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
6643 jp = getjob(*argv, 1);
6644 if (mode == FORK_BG) {
6645 set_curjob(jp, CUR_RUNNING);
6646 fprintf(out, "[%d] ", jobno(jp));
6648 outstr(jp->ps->cmd, out);
6650 retval = restartjob(jp, mode);
6651 } while (*argv && *++argv);
6655 static int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
6659 restartjob(struct job *jp, int mode)
6661 struct procstat *ps;
6667 if (jp->state == JOBDONE)
6669 jp->state = JOBRUNNING;
6671 if (mode == FORK_FG)
6672 xtcsetpgrp(ttyfd, pgid);
6673 killpg(pgid, SIGCONT);
6677 if (WIFSTOPPED(ps->status)) {
6680 } while (ps++, --i);
6682 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
6689 sprint_status(char *s, int status, int sigonly)
6695 if (!WIFEXITED(status)) {
6697 if (WIFSTOPPED(status))
6698 st = WSTOPSIG(status);
6701 st = WTERMSIG(status);
6703 if (st == SIGINT || st == SIGPIPE)
6706 if (WIFSTOPPED(status))
6711 col = fmtstr(s, 32, strsignal(st));
6712 if (WCOREDUMP(status)) {
6713 col += fmtstr(s + col, 16, " (core dumped)");
6715 } else if (!sigonly) {
6716 st = WEXITSTATUS(status);
6718 col = fmtstr(s, 16, "Done(%d)", st);
6720 col = fmtstr(s, 16, "Done");
6729 showjob(FILE *out, struct job *jp, int mode)
6731 struct procstat *ps;
6732 struct procstat *psend;
6739 if (mode & SHOW_PGID) {
6740 /* just output process (group) id of pipeline */
6741 fprintf(out, "%d\n", ps->pid);
6745 col = fmtstr(s, 16, "[%d] ", jobno(jp));
6750 else if (curjob && jp == curjob->prev_job)
6753 if (mode & SHOW_PID)
6754 col += fmtstr(s + col, 16, "%d ", ps->pid);
6756 psend = ps + jp->nprocs;
6758 if (jp->state == JOBRUNNING) {
6759 scopy("Running", s + col);
6760 col += strlen("Running");
6762 int status = psend[-1].status;
6764 if (jp->state == JOBSTOPPED)
6765 status = jp->stopstatus;
6767 col += sprint_status(s + col, status, 0);
6773 /* for each process */
6774 col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
6777 fprintf(out, "%s%*c%s",
6778 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
6780 if (!(mode & SHOW_PID)) {
6784 if (++ps == psend) {
6785 outcslow('\n', out);
6792 if (jp->state == JOBDONE) {
6793 TRACE(("showjob: freeing job %d\n", jobno(jp)));
6800 jobscmd(int argc, char **argv)
6806 while ((m = nextopt("lp")))
6816 showjob(out, getjob(*argv,0), mode);
6819 showjobs(out, mode);
6826 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6827 * statuses have changed since the last call to showjobs.
6831 showjobs(FILE *out, int mode)
6835 TRACE(("showjobs(%x) called\n", mode));
6837 /* If not even one one job changed, there is nothing to do */
6838 while (dowait(DOWAIT_NORMAL, NULL) > 0)
6841 for (jp = curjob; jp; jp = jp->prev_job) {
6842 if (!(mode & SHOW_CHANGED) || jp->changed)
6843 showjob(out, jp, mode);
6849 * Mark a job structure as unused.
6853 freejob(struct job *jp)
6855 struct procstat *ps;
6859 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
6860 if (ps->cmd != nullstr)
6863 if (jp->ps != &jp->ps0)
6866 set_curjob(jp, CUR_DELETE);
6872 waitcmd(int argc, char **argv)
6885 /* wait for all jobs */
6890 /* no running procs */
6893 if (jp->state == JOBRUNNING)
6898 dowait(DOWAIT_BLOCK, 0);
6904 if (**argv != '%') {
6905 pid_t pid = number(*argv);
6909 if (job->ps[job->nprocs - 1].pid == pid)
6911 job = job->prev_job;
6917 job = getjob(*argv, 0);
6918 /* loop until process terminated or stopped */
6919 while (job->state == JOBRUNNING)
6920 dowait(DOWAIT_BLOCK, 0);
6922 retval = getstatus(job);
6933 * Convert a job name to a job structure.
6937 getjob(const char *name, int getctl)
6941 const char *err_msg = "No such job: %s";
6945 char *(*match)(const char *, const char *);
6960 if (c == '+' || c == '%') {
6962 err_msg = "No current job";
6964 } else if (c == '-') {
6967 err_msg = "No previous job";
6978 jp = jobtab + num - 1;
6995 if (match(jp->ps[0].cmd, p)) {
6999 err_msg = "%s: ambiguous";
7006 err_msg = "job %s not created under job control";
7007 if (getctl && jp->jobctl == 0)
7012 error(err_msg, name);
7017 * Return a new job structure.
7018 * Called with interrupts off.
7022 makejob(union node *node, int nprocs)
7027 for (i = njobs, jp = jobtab ; ; jp++) {
7034 if (jp->state != JOBDONE || !jp->waited)
7043 memset(jp, 0, sizeof(*jp));
7048 jp->prev_job = curjob;
7053 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
7055 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
7065 struct job *jp, *jq;
7067 len = njobs * sizeof(*jp);
7069 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
7071 offset = (char *)jp - (char *)jq;
7073 /* Relocate pointers */
7076 jq = (struct job *)((char *)jq + l);
7080 #define joff(p) ((struct job *)((char *)(p) + l))
7081 #define jmove(p) (p) = (void *)((char *)(p) + offset)
7082 if (likely(joff(jp)->ps == &jq->ps0))
7083 jmove(joff(jp)->ps);
7084 if (joff(jp)->prev_job)
7085 jmove(joff(jp)->prev_job);
7095 jp = (struct job *)((char *)jp + len);
7099 } while (--jq >= jp);
7105 * Fork off a subshell. If we are doing job control, give the subshell its
7106 * own process group. Jp is a job structure that the job is to be added to.
7107 * N is the command that will be evaluated by the child. Both jp and n may
7108 * be NULL. The mode parameter can be one of the following:
7109 * FORK_FG - Fork off a foreground process.
7110 * FORK_BG - Fork off a background process.
7111 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
7112 * process group even if job control is on.
7114 * When job control is turned off, background processes have their standard
7115 * input redirected to /dev/null (except for the second and later processes
7118 * Called with interrupts off.
7122 forkchild(struct job *jp, union node *n, int mode)
7126 TRACE(("Child shell %d\n", getpid()));
7127 wasroot = rootshell;
7133 /* do job control only in root shell */
7135 if (mode != FORK_NOJOB && jp->jobctl && wasroot) {
7138 if (jp->nprocs == 0)
7141 pgrp = jp->ps[0].pid;
7142 /* This can fail because we are doing it in the parent also */
7143 (void)setpgid(0, pgrp);
7144 if (mode == FORK_FG)
7145 xtcsetpgrp(ttyfd, pgrp);
7150 if (mode == FORK_BG) {
7153 if (jp->nprocs == 0) {
7155 if (open(_PATH_DEVNULL, O_RDONLY) != 0)
7156 error("Can't open %s", _PATH_DEVNULL);
7159 if (wasroot && iflag) {
7164 for (jp = curjob; jp; jp = jp->prev_job)
7170 forkparent(struct job *jp, union node *n, int mode, pid_t pid)
7172 TRACE(("In parent shell: child = %d\n", pid));
7174 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
7179 if (mode != FORK_NOJOB && jp->jobctl) {
7182 if (jp->nprocs == 0)
7185 pgrp = jp->ps[0].pid;
7186 /* This can fail because we are doing it in the child also */
7187 (void)setpgid(pid, pgrp);
7190 if (mode == FORK_BG) {
7191 backgndpid = pid; /* set $! */
7192 set_curjob(jp, CUR_RUNNING);
7195 struct procstat *ps = &jp->ps[jp->nprocs++];
7201 ps->cmd = commandtext(n);
7207 forkshell(struct job *jp, union node *n, int mode)
7211 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
7214 TRACE(("Fork failed, errno=%d", errno));
7217 error("Cannot fork");
7220 forkchild(jp, n, mode);
7222 forkparent(jp, n, mode, pid);
7227 * Wait for job to finish.
7229 * Under job control we have the problem that while a child process is
7230 * running interrupts generated by the user are sent to the child but not
7231 * to the shell. This means that an infinite loop started by an inter-
7232 * active user may be hard to kill. With job control turned off, an
7233 * interactive user may place an interactive program inside a loop. If
7234 * the interactive program catches interrupts, the user doesn't want
7235 * these interrupts to also abort the loop. The approach we take here
7236 * is to have the shell ignore interrupt signals while waiting for a
7237 * forground process to terminate, and then send itself an interrupt
7238 * signal if the child process was terminated by an interrupt signal.
7239 * Unfortunately, some programs want to do a bit of cleanup and then
7240 * exit on interrupt; unless these processes terminate themselves by
7241 * sending a signal to themselves (instead of calling exit) they will
7242 * confuse this approach.
7244 * Called with interrupts off.
7248 waitforjob(struct job *jp)
7252 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
7253 while (jp->state == JOBRUNNING) {
7254 dowait(DOWAIT_BLOCK, jp);
7259 xtcsetpgrp(ttyfd, rootpid);
7261 * This is truly gross.
7262 * If we're doing job control, then we did a TIOCSPGRP which
7263 * caused us (the shell) to no longer be in the controlling
7264 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7265 * intuit from the subprocess exit status whether a SIGINT
7266 * occurred, and if so interrupt ourselves. Yuck. - mycroft
7271 if (jp->state == JOBDONE)
7279 * Do a wait system call. If job control is compiled in, we accept
7280 * stopped processes. If block is zero, we return a value of zero
7281 * rather than blocking.
7283 * System V doesn't have a non-blocking wait system call. It does
7284 * have a SIGCLD signal that is sent to a process when one of it's
7285 * children dies. The obvious way to use SIGCLD would be to install
7286 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7287 * was received, and have waitproc bump another counter when it got
7288 * the status of a process. Waitproc would then know that a wait
7289 * system call would not block if the two counters were different.
7290 * This approach doesn't work because if a process has children that
7291 * have not been waited for, System V will send it a SIGCLD when it
7292 * installs a signal handler for SIGCLD. What this means is that when
7293 * a child exits, the shell will be sent SIGCLD signals continuously
7294 * until is runs out of stack space, unless it does a wait call before
7295 * restoring the signal handler. The code below takes advantage of
7296 * this (mis)feature by installing a signal handler for SIGCLD and
7297 * then checking to see whether it was called. If there are any
7298 * children to be waited for, it will be.
7300 * If neither SYSV nor BSD is defined, we don't implement nonblocking
7301 * waits at all. In this case, the user will not be informed when
7302 * a background process until the next time she runs a real program
7303 * (as opposed to running a builtin command or just typing return),
7304 * and the jobs command may give out of date information.
7308 waitproc(int block, int *status)
7318 return wait3(status, flags, (struct rusage *)NULL);
7322 * Wait for a process to terminate.
7326 dowait(int block, struct job *job)
7331 struct job *thisjob;
7334 TRACE(("dowait(%d) called\n", block));
7335 pid = waitproc(block, &status);
7336 TRACE(("wait returns pid %d, status=%d\n", pid, status));
7341 for (jp = curjob; jp; jp = jp->prev_job) {
7342 struct procstat *sp;
7343 struct procstat *spend;
7344 if (jp->state == JOBDONE)
7347 spend = jp->ps + jp->nprocs;
7350 if (sp->pid == pid) {
7351 TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
7352 sp->status = status;
7355 if (sp->status == -1)
7358 if (state == JOBRUNNING)
7360 if (WIFSTOPPED(sp->status)) {
7361 jp->stopstatus = sp->status;
7365 } while (++sp < spend);
7370 if (!WIFSTOPPED(status))
7377 if (state != JOBRUNNING) {
7378 thisjob->changed = 1;
7380 if (thisjob->state != state) {
7381 TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
7382 thisjob->state = state;
7384 if (state == JOBSTOPPED) {
7385 set_curjob(thisjob, CUR_STOPPED);
7394 if (thisjob && thisjob == job) {
7398 len = sprint_status(s, status, 1);
7410 * return 1 if there are stopped jobs, otherwise 0
7423 if (jp && jp->state == JOBSTOPPED) {
7424 out2str("You have stopped jobs.\n");
7434 * Return a string identifying a command (to be printed by the
7439 static char *cmdnextc;
7442 commandtext(union node *n)
7446 STARTSTACKSTR(cmdnextc);
7448 name = stackblock();
7449 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
7450 name, cmdnextc, cmdnextc));
7451 return savestr(name);
7455 cmdtxt(union node *n)
7458 struct nodelist *lp;
7470 lp = n->npipe.cmdlist;
7488 cmdtxt(n->nbinary.ch1);
7504 cmdtxt(n->nif.test);
7507 if (n->nif.elsepart) {
7510 n = n->nif.elsepart;
7526 cmdtxt(n->nbinary.ch1);
7536 cmdputs(n->nfor.var);
7538 cmdlist(n->nfor.args, 1);
7543 cmdputs(n->narg.text);
7547 cmdlist(n->ncmd.args, 1);
7548 cmdlist(n->ncmd.redirect, 0);
7561 cmdputs(n->ncase.expr->narg.text);
7563 for (np = n->ncase.cases; np; np = np->nclist.next) {
7564 cmdtxt(np->nclist.pattern);
7566 cmdtxt(np->nclist.body);
7592 s[0] = n->nfile.fd + '0';
7596 if (n->type == NTOFD || n->type == NFROMFD) {
7597 s[0] = n->ndup.dupfd + '0';
7608 cmdlist(union node *np, int sep)
7610 for (; np; np = np->narg.next) {
7614 if (sep && np->narg.next)
7620 cmdputs(const char *s)
7622 const char *p, *str;
7623 char c, cc[2] = " ";
7627 static const char *const vstype[16] = {
7628 nullstr, "}", "-", "+", "?", "=",
7629 "%", "%%", "#", "##", nullstr
7632 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
7634 while ((c = *p++) != 0) {
7642 if ((subtype & VSTYPE) == VSLENGTH)
7646 if (!(subtype & VSQUOTE) != !(quoted & 1)) {
7664 case CTLBACKQ+CTLQUOTE:
7667 #ifdef CONFIG_ASH_MATH_SUPPORT
7682 str = vstype[subtype & VSTYPE];
7683 if (subtype & VSNUL)
7694 /* These can only happen inside quotes */
7706 while ((c = *str++)) {
7711 USTPUTC('"', nextc);
7719 showpipe(struct job *jp, FILE *out)
7721 struct procstat *sp;
7722 struct procstat *spend;
7724 spend = jp->ps + jp->nprocs;
7725 for (sp = jp->ps + 1; sp < spend; sp++)
7726 fprintf(out, " | %s", sp->cmd);
7727 outcslow('\n', out);
7732 xtcsetpgrp(int fd, pid_t pgrp)
7734 if (tcsetpgrp(fd, pgrp))
7735 error("Cannot set tty process group (%m)");
7740 getstatus(struct job *job) {
7744 status = job->ps[job->nprocs - 1].status;
7745 retval = WEXITSTATUS(status);
7746 if (!WIFEXITED(status)) {
7748 retval = WSTOPSIG(status);
7749 if (!WIFSTOPPED(status))
7752 /* XXX: limits number of signals */
7753 retval = WTERMSIG(status);
7755 if (retval == SIGINT)
7761 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
7762 jobno(job), job->nprocs, status, retval));
7766 #ifdef CONFIG_ASH_MAIL
7767 /* $NetBSD: mail.c,v 1.15 2002/11/24 22:35:40 christos Exp $ */
7770 * Routines to check for mail. (Perhaps make part of main.c?)
7773 #define MAXMBOXES 10
7775 /* times of mailboxes */
7776 static time_t mailtime[MAXMBOXES];
7777 /* Set if MAIL or MAILPATH is changed. */
7778 static int mail_var_path_changed;
7783 * Print appropriate message(s) if mail has arrived.
7784 * If mail_var_path_changed is set,
7785 * then the value of MAIL has mail_var_path_changed,
7786 * so we just update the values.
7796 struct stackmark smark;
7799 setstackmark(&smark);
7800 mpath = mpathset() ? mpathval() : mailval();
7801 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
7802 p = padvance(&mpath, nullstr);
7807 for (q = p ; *q ; q++);
7812 q[-1] = '\0'; /* delete trailing '/' */
7813 if (stat(p, &statb) < 0) {
7817 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
7820 pathopt ? pathopt : "you have mail"
7823 *mtp = statb.st_mtime;
7825 mail_var_path_changed = 0;
7826 popstackmark(&smark);
7831 changemail(const char *val)
7833 mail_var_path_changed++;
7836 #endif /* CONFIG_ASH_MAIL */
7838 /* $NetBSD: main.c,v 1.46 2002/12/11 19:12:18 christos Exp $ */
7842 static short profile_buf[16384];
7846 static int isloginsh;
7848 static void read_profile(const char *);
7851 * Main routine. We initialize things, parse the arguments, execute
7852 * profiles if we're a login shell, and then call cmdloop to execute
7853 * commands. The setjmp call sets up the location to jump to when an
7854 * exception occurs. When an exception occurs the variable "state"
7855 * is used to figure out how far we had gotten.
7859 ash_main(int argc, char **argv)
7863 struct jmploc jmploc;
7864 struct stackmark smark;
7867 dash_errno = __errno_location();
7871 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7874 if (setjmp(jmploc.loc)) {
7881 switch (exception) {
7891 status = exitstatus;
7894 exitstatus = status;
7896 if (e == EXEXIT || state == 0 || iflag == 0 || ! rootshell)
7900 outcslow('\n', stderr);
7902 popstackmark(&smark);
7903 FORCEINTON; /* enable interrupts */
7906 else if (state == 2)
7908 else if (state == 3)
7916 trputs("Shell args: "); trargs(argv);
7920 #ifdef CONFIG_ASH_RANDOM_SUPPORT
7921 rseed = rootpid + ((time_t)time((time_t *)0));
7925 setstackmark(&smark);
7926 procargs(argc, argv);
7927 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7929 const char *hp = lookupvar("HISTFILE");
7932 hp = lookupvar("HOME");
7934 char *defhp = concat_path_file(hp, ".ash_history");
7935 setvar("HISTFILE", defhp, 0);
7941 if (argv[0] && argv[0][0] == '-')
7945 read_profile("/etc/profile");
7948 read_profile(".profile");
7954 getuid() == geteuid() && getgid() == getegid() &&
7958 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
7959 read_profile(shinit);
7967 if (sflag || minusc == NULL) {
7968 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7970 const char *hp = lookupvar("HISTFILE");
7973 load_history ( hp );
7976 state4: /* XXX ??? - why isn't this before the "if" statement */
7984 extern void _mcleanup(void);
7994 * Read and execute commands. "Top" is nonzero for the top level command
7995 * loop; it turns on prompting if the shell is interactive.
8002 struct stackmark smark;
8006 TRACE(("cmdloop(%d) called\n", top));
8008 setstackmark(&smark);
8013 showjobs(stderr, SHOW_CHANGED);
8018 #ifdef CONFIG_ASH_MAIL
8022 n = parsecmd(inter);
8023 /* showtree(n); DEBUG */
8025 if (!top || numeof >= 50)
8027 if (!stoppedjobs()) {
8030 out2str("\nUse \"exit\" to leave shell.\n");
8033 } else if (n != NULL && nflag == 0) {
8034 job_warning = (job_warning == 2) ? 1 : 0;
8038 popstackmark(&smark);
8048 * Read /etc/profile or .profile. Return on error.
8052 read_profile(const char *name)
8059 if ((fd = open(name, O_RDONLY)) >= 0)
8064 /* -q turns off -x and -v just when executing init files */
8067 xflag = 0, xflag_set = 1;
8069 vflag = 0, vflag_set = 1;
8083 * Read a file containing shell functions.
8087 readcmdfile(char *name)
8092 if ((fd = open(name, O_RDONLY)) >= 0)
8095 error("Can't open %s", name);
8103 * Take commands from a file. To be compatible we should do a path
8104 * search for the file, which is necessary to find sub-commands.
8107 static inline char *
8108 find_dot_file(char *name)
8111 const char *path = pathval();
8114 /* don't try this for absolute or relative paths */
8115 if (strchr(name, '/'))
8118 while ((fullname = padvance(&path, name)) != NULL) {
8119 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
8121 * Don't bother freeing here, since it will
8122 * be freed by the caller.
8126 stunalloc(fullname);
8129 /* not found in the PATH */
8130 error(not_found_msg, name);
8135 dotcmd(int argc, char **argv)
8139 if (argc >= 2) { /* That's what SVR2 does */
8141 struct stackmark smark;
8143 setstackmark(&smark);
8144 fullname = find_dot_file(argv[1]);
8145 setinputfile(fullname, 1);
8146 commandname = fullname;
8149 popstackmark(&smark);
8156 exitcmd(int argc, char **argv)
8161 exitstatus = number(argv[1]);
8166 /* $NetBSD: memalloc.c,v 1.27 2003/01/22 20:36:04 dsl Exp $ */
8169 * Same for malloc, realloc, but returns an error when out of space.
8173 ckrealloc(pointer p, size_t nbytes)
8175 p = realloc(p, nbytes);
8177 error(bb_msg_memory_exhausted);
8182 ckmalloc(size_t nbytes)
8184 return ckrealloc(NULL, nbytes);
8188 * Make a copy of a string in safe storage.
8192 savestr(const char *s)
8194 char *p = strdup(s);
8196 error(bb_msg_memory_exhausted);
8202 * Parse trees for commands are allocated in lifo order, so we use a stack
8203 * to make this more efficient, and also to avoid all sorts of exception
8204 * handling code to handle interrupts in the middle of a parse.
8206 * The size 504 was chosen because the Ultrix malloc handles that size
8212 stalloc(size_t nbytes)
8217 aligned = SHELL_ALIGN(nbytes);
8218 if (aligned > stacknleft) {
8221 struct stack_block *sp;
8223 blocksize = aligned;
8224 if (blocksize < MINSIZE)
8225 blocksize = MINSIZE;
8226 len = sizeof(struct stack_block) - MINSIZE + blocksize;
8227 if (len < blocksize)
8228 error(bb_msg_memory_exhausted);
8232 stacknxt = sp->space;
8233 stacknleft = blocksize;
8234 sstrend = stacknxt + blocksize;
8239 stacknxt += aligned;
8240 stacknleft -= aligned;
8246 stunalloc(pointer p)
8249 if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
8250 write(2, "stunalloc\n", 10);
8254 stacknleft += stacknxt - (char *)p;
8260 setstackmark(struct stackmark *mark)
8262 mark->stackp = stackp;
8263 mark->stacknxt = stacknxt;
8264 mark->stacknleft = stacknleft;
8265 mark->marknext = markp;
8271 popstackmark(struct stackmark *mark)
8273 struct stack_block *sp;
8276 markp = mark->marknext;
8277 while (stackp != mark->stackp) {
8282 stacknxt = mark->stacknxt;
8283 stacknleft = mark->stacknleft;
8284 sstrend = mark->stacknxt + mark->stacknleft;
8290 * When the parser reads in a string, it wants to stick the string on the
8291 * stack and only adjust the stack pointer when it knows how big the
8292 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8293 * of space on top of the stack and stackblocklen returns the length of
8294 * this block. Growstackblock will grow this space by at least one byte,
8295 * possibly moving it (like realloc). Grabstackblock actually allocates the
8296 * part of the block that has been used.
8300 growstackblock(void)
8304 newlen = stacknleft * 2;
8305 if (newlen < stacknleft)
8306 error(bb_msg_memory_exhausted);
8310 if (stacknxt == stackp->space && stackp != &stackbase) {
8311 struct stack_block *oldstackp;
8312 struct stackmark *xmark;
8313 struct stack_block *sp;
8314 struct stack_block *prevstackp;
8320 prevstackp = sp->prev;
8321 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
8322 sp = ckrealloc((pointer)sp, grosslen);
8323 sp->prev = prevstackp;
8325 stacknxt = sp->space;
8326 stacknleft = newlen;
8327 sstrend = sp->space + newlen;
8330 * Stack marks pointing to the start of the old block
8331 * must be relocated to point to the new block
8334 while (xmark != NULL && xmark->stackp == oldstackp) {
8335 xmark->stackp = stackp;
8336 xmark->stacknxt = stacknxt;
8337 xmark->stacknleft = stacknleft;
8338 xmark = xmark->marknext;
8342 char *oldspace = stacknxt;
8343 int oldlen = stacknleft;
8344 char *p = stalloc(newlen);
8346 /* free the space we just allocated */
8347 stacknxt = memcpy(p, oldspace, oldlen);
8348 stacknleft += newlen;
8353 grabstackblock(size_t len)
8355 len = SHELL_ALIGN(len);
8361 * The following routines are somewhat easier to use than the above.
8362 * The user declares a variable of type STACKSTR, which may be declared
8363 * to be a register. The macro STARTSTACKSTR initializes things. Then
8364 * the user uses the macro STPUTC to add characters to the string. In
8365 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8366 * grown as necessary. When the user is done, she can just leave the
8367 * string there and refer to it using stackblock(). Or she can allocate
8368 * the space for it using grabstackstr(). If it is necessary to allow
8369 * someone else to use the stack temporarily and then continue to grow
8370 * the string, the user should use grabstack to allocate the space, and
8371 * then call ungrabstr(p) to return to the previous mode of operation.
8373 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8374 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8375 * is space for at least one character.
8381 size_t len = stackblocksize();
8382 if (herefd >= 0 && len >= 1024) {
8383 bb_full_write(herefd, stackblock(), len);
8384 return stackblock();
8387 return stackblock() + len;
8391 * Called from CHECKSTRSPACE.
8395 makestrspace(size_t newlen, char *p)
8397 size_t len = p - stacknxt;
8398 size_t size = stackblocksize();
8403 size = stackblocksize();
8405 if (nleft >= newlen)
8409 return stackblock() + len;
8413 stnputs(const char *s, size_t n, char *p)
8415 p = makestrspace(n, p);
8416 p = mempcpy(p, s, n);
8421 stputs(const char *s, char *p)
8423 return stnputs(s, strlen(s), p);
8426 /* $NetBSD: mystring.c,v 1.15 2002/11/24 22:35:42 christos Exp $ */
8431 * number(s) Convert a string of digits to an integer.
8432 * is_number(s) Return true if s is a string of digits.
8436 * prefix -- see if pfx is a prefix of string.
8440 prefix(const char *string, const char *pfx)
8443 if (*pfx++ != *string++)
8446 return (char *) string;
8451 * Convert a string of digits to an integer, printing an error message on
8456 number(const char *s)
8466 * Check for a valid number. This should be elsewhere.
8470 is_number(const char *p)
8475 } while (*++p != '\0');
8481 * Produce a possibly single quoted string suitable as input to the shell.
8482 * The return string is allocated on the stack.
8486 single_quote(const char *s) {
8495 len = strchrnul(s, '\'') - s;
8497 q = p = makestrspace(len + 3, p);
8500 q = mempcpy(q, s, len);
8506 len = strspn(s, "'");
8510 q = p = makestrspace(len + 3, p);
8513 q = mempcpy(q, s, len);
8522 return stackblock();
8526 * Like strdup but works with the ash stack.
8530 sstrdup(const char *p)
8532 size_t len = strlen(p) + 1;
8533 return memcpy(stalloc(len), p, len);
8538 calcsize(union node *n)
8542 funcblocksize += nodesize[n->type];
8545 calcsize(n->ncmd.redirect);
8546 calcsize(n->ncmd.args);
8547 calcsize(n->ncmd.assign);
8550 sizenodelist(n->npipe.cmdlist);
8555 calcsize(n->nredir.redirect);
8556 calcsize(n->nredir.n);
8563 calcsize(n->nbinary.ch2);
8564 calcsize(n->nbinary.ch1);
8567 calcsize(n->nif.elsepart);
8568 calcsize(n->nif.ifpart);
8569 calcsize(n->nif.test);
8572 funcstringsize += strlen(n->nfor.var) + 1;
8573 calcsize(n->nfor.body);
8574 calcsize(n->nfor.args);
8577 calcsize(n->ncase.cases);
8578 calcsize(n->ncase.expr);
8581 calcsize(n->nclist.body);
8582 calcsize(n->nclist.pattern);
8583 calcsize(n->nclist.next);
8587 sizenodelist(n->narg.backquote);
8588 funcstringsize += strlen(n->narg.text) + 1;
8589 calcsize(n->narg.next);
8596 calcsize(n->nfile.fname);
8597 calcsize(n->nfile.next);
8601 calcsize(n->ndup.vname);
8602 calcsize(n->ndup.next);
8606 calcsize(n->nhere.doc);
8607 calcsize(n->nhere.next);
8610 calcsize(n->nnot.com);
8617 sizenodelist(struct nodelist *lp)
8620 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8628 copynode(union node *n)
8635 funcblock = (char *) funcblock + nodesize[n->type];
8638 new->ncmd.redirect = copynode(n->ncmd.redirect);
8639 new->ncmd.args = copynode(n->ncmd.args);
8640 new->ncmd.assign = copynode(n->ncmd.assign);
8643 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8644 new->npipe.backgnd = n->npipe.backgnd;
8649 new->nredir.redirect = copynode(n->nredir.redirect);
8650 new->nredir.n = copynode(n->nredir.n);
8657 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8658 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8661 new->nif.elsepart = copynode(n->nif.elsepart);
8662 new->nif.ifpart = copynode(n->nif.ifpart);
8663 new->nif.test = copynode(n->nif.test);
8666 new->nfor.var = nodesavestr(n->nfor.var);
8667 new->nfor.body = copynode(n->nfor.body);
8668 new->nfor.args = copynode(n->nfor.args);
8671 new->ncase.cases = copynode(n->ncase.cases);
8672 new->ncase.expr = copynode(n->ncase.expr);
8675 new->nclist.body = copynode(n->nclist.body);
8676 new->nclist.pattern = copynode(n->nclist.pattern);
8677 new->nclist.next = copynode(n->nclist.next);
8681 new->narg.backquote = copynodelist(n->narg.backquote);
8682 new->narg.text = nodesavestr(n->narg.text);
8683 new->narg.next = copynode(n->narg.next);
8690 new->nfile.fname = copynode(n->nfile.fname);
8691 new->nfile.fd = n->nfile.fd;
8692 new->nfile.next = copynode(n->nfile.next);
8696 new->ndup.vname = copynode(n->ndup.vname);
8697 new->ndup.dupfd = n->ndup.dupfd;
8698 new->ndup.fd = n->ndup.fd;
8699 new->ndup.next = copynode(n->ndup.next);
8703 new->nhere.doc = copynode(n->nhere.doc);
8704 new->nhere.fd = n->nhere.fd;
8705 new->nhere.next = copynode(n->nhere.next);
8708 new->nnot.com = copynode(n->nnot.com);
8711 new->type = n->type;
8716 static struct nodelist *
8717 copynodelist(struct nodelist *lp)
8719 struct nodelist *start;
8720 struct nodelist **lpp;
8725 funcblock = (char *) funcblock +
8726 SHELL_ALIGN(sizeof(struct nodelist));
8727 (*lpp)->n = copynode(lp->n);
8729 lpp = &(*lpp)->next;
8737 nodesavestr(char *s)
8739 char *rtn = funcstring;
8741 funcstring = stpcpy(funcstring, s) + 1;
8747 * Free a parse tree.
8751 freefunc(struct funcnode *f)
8753 if (f && --f->count < 0)
8758 static void options(int);
8759 static void setoption(int, int);
8763 * Process the shell command line arguments.
8767 procargs(int argc, char **argv)
8770 const char *xminusc;
8777 for (i = 0; i < NOPTS; i++)
8783 if (*xargv == NULL) {
8785 error("-c requires an argument");
8788 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8792 for (i = 0; i < NOPTS; i++)
8793 if (optlist[i] == 2)
8798 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8803 } else if (!sflag) {
8804 setinputfile(*xargv, 0);
8810 shellparam.p = xargv;
8811 #ifdef CONFIG_ASH_GETOPTS
8812 shellparam.optind = 1;
8813 shellparam.optoff = -1;
8815 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
8817 shellparam.nparam++;
8830 setinteractive(iflag);
8835 minus_o(char *name, int val)
8840 out1str("Current option settings\n");
8841 for (i = 0; i < NOPTS; i++)
8842 out1fmt("%-16s%s\n", optnames(i),
8843 optlist[i] ? "on" : "off");
8845 for (i = 0; i < NOPTS; i++)
8846 if (equal(name, optnames(i))) {
8850 error("Illegal option -o %s", name);
8855 * Process shell options. The global variable argptr contains a pointer
8856 * to the argument list; we advance it past the options.
8860 options(int cmdline)
8868 while ((p = *argptr) != NULL) {
8870 if ((c = *p++) == '-') {
8872 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8874 /* "-" means turn off -x and -v */
8877 /* "--" means reset params */
8878 else if (*argptr == NULL)
8881 break; /* "-" or "--" terminates options */
8883 } else if (c == '+') {
8889 while ((c = *p++) != '\0') {
8890 if (c == 'c' && cmdline) {
8891 minusc = p; /* command is after shell args*/
8892 } else if (c == 'o') {
8893 minus_o(*argptr, val);
8896 } else if (cmdline && (c == '-')) { // long options
8897 if (strcmp(p, "login") == 0)
8909 setoption(int flag, int val)
8913 for (i = 0; i < NOPTS; i++)
8914 if (optletters(i) == flag) {
8918 error("Illegal option -%c", flag);
8925 * Set the shell parameters.
8929 setparam(char **argv)
8935 for (nparam = 0 ; argv[nparam] ; nparam++);
8936 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
8938 *ap++ = savestr(*argv++);
8941 freeparam(&shellparam);
8942 shellparam.malloc = 1;
8943 shellparam.nparam = nparam;
8944 shellparam.p = newparam;
8945 #ifdef CONFIG_ASH_GETOPTS
8946 shellparam.optind = 1;
8947 shellparam.optoff = -1;
8953 * Free the list of positional parameters.
8957 freeparam(volatile struct shparam *param)
8961 if (param->malloc) {
8962 for (ap = param->p ; *ap ; ap++)
8971 * The shift builtin command.
8975 shiftcmd(int argc, char **argv)
8982 n = number(argv[1]);
8983 if (n > shellparam.nparam)
8984 error("can't shift that many");
8986 shellparam.nparam -= n;
8987 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
8988 if (shellparam.malloc)
8992 while ((*ap2++ = *ap1++) != NULL);
8993 #ifdef CONFIG_ASH_GETOPTS
8994 shellparam.optind = 1;
8995 shellparam.optoff = -1;
9004 * The set command builtin.
9008 setcmd(int argc, char **argv)
9011 return showvars(nullstr, 0, VUNSET);
9015 if (*argptr != NULL) {
9023 #ifdef CONFIG_ASH_GETOPTS
9028 shellparam.optind = number(value);
9029 shellparam.optoff = -1;
9033 #ifdef CONFIG_LOCALE_SUPPORT
9034 static void change_lc_all(const char *value)
9036 if (value != 0 && *value != 0)
9037 setlocale(LC_ALL, value);
9040 static void change_lc_ctype(const char *value)
9042 if (value != 0 && *value != 0)
9043 setlocale(LC_CTYPE, value);
9048 #ifdef CONFIG_ASH_RANDOM_SUPPORT
9049 /* Roughly copied from bash.. */
9050 static void change_random(const char *value)
9053 /* "get", generate */
9056 rseed = rseed * 1103515245 + 12345;
9057 sprintf(buf, "%d", (unsigned int)((rseed & 32767)));
9058 /* set without recursion */
9059 setvar(vrandom.text, buf, VNOFUNC);
9060 vrandom.flags &= ~VNOFUNC;
9063 rseed = strtoul(value, (char **)NULL, 10);
9069 #ifdef CONFIG_ASH_GETOPTS
9071 getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
9080 if(*param_optind < 1)
9082 optnext = optfirst + *param_optind - 1;
9084 if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff)
9087 p = optnext[-1] + *optoff;
9088 if (p == NULL || *p == '\0') {
9089 /* Current word is done, advance */
9091 if (p == NULL || *p != '-' || *++p == '\0') {
9098 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
9103 for (q = optstr; *q != c; ) {
9105 if (optstr[0] == ':') {
9108 err |= setvarsafe("OPTARG", s, 0);
9110 fprintf(stderr, "Illegal option -%c\n", c);
9111 (void) unsetvar("OPTARG");
9121 if (*p == '\0' && (p = *optnext) == NULL) {
9122 if (optstr[0] == ':') {
9125 err |= setvarsafe("OPTARG", s, 0);
9128 fprintf(stderr, "No arg for -%c option\n", c);
9129 (void) unsetvar("OPTARG");
9137 err |= setvarsafe("OPTARG", p, 0);
9140 err |= setvarsafe("OPTARG", nullstr, 0);
9143 *optoff = p ? p - *(optnext - 1) : -1;
9144 *param_optind = optnext - optfirst + 1;
9145 fmtstr(s, sizeof(s), "%d", *param_optind);
9146 err |= setvarsafe("OPTIND", s, VNOFUNC);
9149 err |= setvarsafe(optvar, s, 0);
9160 * The getopts builtin. Shellparam.optnext points to the next argument
9161 * to be processed. Shellparam.optptr points to the next character to
9162 * be processed in the current argument. If shellparam.optnext is NULL,
9163 * then it's the first time getopts has been called.
9167 getoptscmd(int argc, char **argv)
9172 error("Usage: getopts optstring var [arg]");
9173 else if (argc == 3) {
9174 optbase = shellparam.p;
9175 if (shellparam.optind > shellparam.nparam + 1) {
9176 shellparam.optind = 1;
9177 shellparam.optoff = -1;
9182 if (shellparam.optind > argc - 2) {
9183 shellparam.optind = 1;
9184 shellparam.optoff = -1;
9188 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9189 &shellparam.optoff);
9191 #endif /* CONFIG_ASH_GETOPTS */
9194 * XXX - should get rid of. have all builtins use getopt(3). the
9195 * library getopt must have the BSD extension static variable "optreset"
9196 * otherwise it can't be used within the shell safely.
9198 * Standard option processing (a la getopt) for builtin routines. The
9199 * only argument that is passed to nextopt is the option string; the
9200 * other arguments are unnecessary. It return the character, or '\0' on
9205 nextopt(const char *optstring)
9211 if ((p = optptr) == NULL || *p == '\0') {
9213 if (p == NULL || *p != '-' || *++p == '\0')
9216 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
9220 for (q = optstring ; *q != c ; ) {
9222 error("Illegal option -%c", c);
9227 if (*p == '\0' && (p = *argptr++) == NULL)
9228 error("No arg for -%c option", c);
9237 /* $NetBSD: output.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
9240 outstr(const char *p, FILE *file)
9265 outcslow(int c, FILE *dest)
9275 out1fmt(const char *fmt, ...)
9282 r = vprintf(fmt, ap);
9290 fmtstr(char *outbuf, size_t length, const char *fmt, ...)
9297 ret = vsnprintf(outbuf, length, fmt, ap);
9305 /* $NetBSD: parser.c,v 1.54 2002/11/24 22:35:42 christos Exp $ */
9309 * Shell command parser.
9312 #define EOFMARKLEN 79
9316 struct heredoc *next; /* next here document in list */
9317 union node *here; /* redirection node */
9318 char *eofmark; /* string indicating end of input */
9319 int striptabs; /* if set, strip leading tabs */
9324 static struct heredoc *heredoclist; /* list of here documents to read */
9327 static union node *list(int);
9328 static union node *andor(void);
9329 static union node *pipeline(void);
9330 static union node *command(void);
9331 static union node *simplecmd(void);
9332 static union node *makename(void);
9333 static void parsefname(void);
9334 static void parseheredoc(void);
9335 static char peektoken(void);
9336 static int readtoken(void);
9337 static int xxreadtoken(void);
9338 static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
9339 static int noexpand(char *);
9340 static void synexpect(int) __attribute__((__noreturn__));
9341 static void synerror(const char *) __attribute__((__noreturn__));
9342 static void setprompt(int);
9347 isassignment(const char *p)
9349 const char *q = endofname(p);
9357 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9358 * valid parse tree indicating a blank line.)
9362 parsecmd(int interact)
9367 doprompt = interact;
9369 setprompt(doprompt);
9384 union node *n1, *n2, *n3;
9387 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9388 if (nlflag == 2 && peektoken())
9394 if (tok == TBACKGND) {
9395 if (n2->type == NPIPE) {
9396 n2->npipe.backgnd = 1;
9398 if (n2->type != NREDIR) {
9399 n3 = stalloc(sizeof(struct nredir));
9401 n3->nredir.redirect = NULL;
9404 n2->type = NBACKGND;
9411 n3 = (union node *)stalloc(sizeof (struct nbinary));
9413 n3->nbinary.ch1 = n1;
9414 n3->nbinary.ch2 = n2;
9430 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9438 pungetc(); /* push back EOF on input */
9454 union node *n1, *n2, *n3;
9459 if ((t = readtoken()) == TAND) {
9461 } else if (t == TOR) {
9467 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9469 n3 = (union node *)stalloc(sizeof (struct nbinary));
9471 n3->nbinary.ch1 = n1;
9472 n3->nbinary.ch2 = n2;
9482 union node *n1, *n2, *pipenode;
9483 struct nodelist *lp, *prev;
9487 TRACE(("pipeline: entered\n"));
9488 if (readtoken() == TNOT) {
9490 checkkwd = CHKKWD | CHKALIAS;
9494 if (readtoken() == TPIPE) {
9495 pipenode = (union node *)stalloc(sizeof (struct npipe));
9496 pipenode->type = NPIPE;
9497 pipenode->npipe.backgnd = 0;
9498 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9499 pipenode->npipe.cmdlist = lp;
9503 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9504 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9507 } while (readtoken() == TPIPE);
9513 n2 = (union node *)stalloc(sizeof (struct nnot));
9526 union node *n1, *n2;
9527 union node *ap, **app;
9528 union node *cp, **cpp;
9529 union node *redir, **rpp;
9536 switch (readtoken()) {
9541 n1 = (union node *)stalloc(sizeof (struct nif));
9543 n1->nif.test = list(0);
9544 if (readtoken() != TTHEN)
9546 n1->nif.ifpart = list(0);
9548 while (readtoken() == TELIF) {
9549 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
9550 n2 = n2->nif.elsepart;
9552 n2->nif.test = list(0);
9553 if (readtoken() != TTHEN)
9555 n2->nif.ifpart = list(0);
9557 if (lasttoken == TELSE)
9558 n2->nif.elsepart = list(0);
9560 n2->nif.elsepart = NULL;
9568 n1 = (union node *)stalloc(sizeof (struct nbinary));
9569 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
9570 n1->nbinary.ch1 = list(0);
9571 if ((got=readtoken()) != TDO) {
9572 TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
9575 n1->nbinary.ch2 = list(0);
9580 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9581 synerror("Bad for loop variable");
9582 n1 = (union node *)stalloc(sizeof (struct nfor));
9584 n1->nfor.var = wordtext;
9585 checkkwd = CHKKWD | CHKALIAS;
9586 if (readtoken() == TIN) {
9588 while (readtoken() == TWORD) {
9589 n2 = (union node *)stalloc(sizeof (struct narg));
9591 n2->narg.text = wordtext;
9592 n2->narg.backquote = backquotelist;
9594 app = &n2->narg.next;
9598 if (lasttoken != TNL && lasttoken != TSEMI)
9601 n2 = (union node *)stalloc(sizeof (struct narg));
9603 n2->narg.text = (char *)dolatstr;
9604 n2->narg.backquote = NULL;
9605 n2->narg.next = NULL;
9608 * Newline or semicolon here is optional (but note
9609 * that the original Bourne shell only allowed NL).
9611 if (lasttoken != TNL && lasttoken != TSEMI)
9614 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9615 if (readtoken() != TDO)
9617 n1->nfor.body = list(0);
9621 n1 = (union node *)stalloc(sizeof (struct ncase));
9623 if (readtoken() != TWORD)
9625 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
9627 n2->narg.text = wordtext;
9628 n2->narg.backquote = backquotelist;
9629 n2->narg.next = NULL;
9631 checkkwd = CHKKWD | CHKALIAS;
9632 } while (readtoken() == TNL);
9633 if (lasttoken != TIN)
9635 cpp = &n1->ncase.cases;
9637 checkkwd = CHKNL | CHKKWD;
9640 if (lasttoken == TLP)
9642 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
9644 app = &cp->nclist.pattern;
9646 *app = ap = (union node *)stalloc(sizeof (struct narg));
9648 ap->narg.text = wordtext;
9649 ap->narg.backquote = backquotelist;
9650 if (readtoken() != TPIPE)
9652 app = &ap->narg.next;
9655 ap->narg.next = NULL;
9656 if (lasttoken != TRP)
9658 cp->nclist.body = list(2);
9660 cpp = &cp->nclist.next;
9662 checkkwd = CHKNL | CHKKWD;
9663 if ((t = readtoken()) != TESAC) {
9665 synexpect(TENDCASE);
9673 n1 = (union node *)stalloc(sizeof (struct nredir));
9674 n1->type = NSUBSHELL;
9675 n1->nredir.n = list(0);
9676 n1->nredir.redirect = NULL;
9689 if (readtoken() != t)
9693 /* Now check for redirection which may follow command */
9694 checkkwd = CHKKWD | CHKALIAS;
9696 while (readtoken() == TREDIR) {
9697 *rpp = n2 = redirnode;
9698 rpp = &n2->nfile.next;
9704 if (n1->type != NSUBSHELL) {
9705 n2 = (union node *)stalloc(sizeof (struct nredir));
9710 n1->nredir.redirect = redir;
9719 union node *args, **app;
9720 union node *n = NULL;
9721 union node *vars, **vpp;
9722 union node **rpp, *redir;
9732 savecheckkwd = CHKALIAS;
9734 checkkwd = savecheckkwd;
9735 switch (readtoken()) {
9737 n = (union node *)stalloc(sizeof (struct narg));
9739 n->narg.text = wordtext;
9740 n->narg.backquote = backquotelist;
9741 if (savecheckkwd && isassignment(wordtext)) {
9743 vpp = &n->narg.next;
9746 app = &n->narg.next;
9751 *rpp = n = redirnode;
9752 rpp = &n->nfile.next;
9753 parsefname(); /* read name of redirection file */
9757 args && app == &args->narg.next &&
9760 struct builtincmd *bcmd;
9763 /* We have a function */
9764 if (readtoken() != TRP)
9766 name = n->narg.text;
9768 !goodname(name) || (
9769 (bcmd = find_builtin(name)) &&
9770 IS_BUILTIN_SPECIAL(bcmd)
9773 synerror("Bad function name");
9775 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9776 n->narg.next = command();
9789 n = (union node *)stalloc(sizeof (struct ncmd));
9791 n->ncmd.args = args;
9792 n->ncmd.assign = vars;
9793 n->ncmd.redirect = redir;
9802 n = (union node *)stalloc(sizeof (struct narg));
9804 n->narg.next = NULL;
9805 n->narg.text = wordtext;
9806 n->narg.backquote = backquotelist;
9810 void fixredir(union node *n, const char *text, int err)
9812 TRACE(("Fix redir %s %d\n", text, err));
9814 n->ndup.vname = NULL;
9816 if (is_digit(text[0]) && text[1] == '\0')
9817 n->ndup.dupfd = digit_val(text[0]);
9818 else if (text[0] == '-' && text[1] == '\0')
9823 synerror("Bad fd number");
9825 n->ndup.vname = makename();
9833 union node *n = redirnode;
9835 if (readtoken() != TWORD)
9837 if (n->type == NHERE) {
9838 struct heredoc *here = heredoc;
9844 TRACE(("Here document %d\n", n->type));
9845 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
9846 synerror("Illegal eof marker for << redirection");
9847 rmescapes(wordtext);
9848 here->eofmark = wordtext;
9850 if (heredoclist == NULL)
9853 for (p = heredoclist ; p->next ; p = p->next);
9856 } else if (n->type == NTOFD || n->type == NFROMFD) {
9857 fixredir(n, wordtext, 0);
9859 n->nfile.fname = makename();
9865 * Input any here documents.
9871 struct heredoc *here;
9882 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9883 here->eofmark, here->striptabs);
9884 n = (union node *)stalloc(sizeof (struct narg));
9885 n->narg.type = NARG;
9886 n->narg.next = NULL;
9887 n->narg.text = wordtext;
9888 n->narg.backquote = backquotelist;
9889 here->here->nhere.doc = n;
9894 static char peektoken(void)
9900 return tokname_array[t][0];
9908 int alreadyseen = tokpushback;
9911 #ifdef CONFIG_ASH_ALIAS
9920 if (checkkwd & CHKNL) {
9927 if (t != TWORD || quoteflag) {
9932 * check for keywords
9934 if (checkkwd & CHKKWD) {
9935 const char *const *pp;
9937 if ((pp = findkwd(wordtext))) {
9938 lasttoken = t = pp - tokname_array;
9939 TRACE(("keyword %s recognized\n", tokname(t)));
9944 if (checkkwd & CHKALIAS) {
9945 #ifdef CONFIG_ASH_ALIAS
9947 if ((ap = lookupalias(wordtext, 1)) != NULL) {
9949 pushstring(ap->val, ap);
9959 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
9961 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
9968 * Read the next input token.
9969 * If the token is a word, we set backquotelist to the list of cmds in
9970 * backquotes. We set quoteflag to true if any part of the word was
9972 * If the token is TREDIR, then we set redirnode to a structure containing
9974 * In all cases, the variable startlinno is set to the number of the line
9975 * on which the token starts.
9977 * [Change comment: here documents and internal procedures]
9978 * [Readtoken shouldn't have any arguments. Perhaps we should make the
9979 * word parsing code into a separate routine. In this case, readtoken
9980 * doesn't need to have any internal procedures, but parseword does.
9981 * We could also make parseoperator in essence the main routine, and
9982 * have parseword (readtoken1?) handle both words and redirection.]
9985 #define NEW_xxreadtoken
9986 #ifdef NEW_xxreadtoken
9988 /* singles must be first! */
9989 static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
9991 static const char xxreadtoken_tokens[] = {
9992 TNL, TLP, TRP, /* only single occurrence allowed */
9993 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
9994 TEOF, /* corresponds to trailing nul */
9995 TAND, TOR, TENDCASE, /* if double occurrence */
9998 #define xxreadtoken_doubles \
9999 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
10000 #define xxreadtoken_singles \
10001 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
10003 static int xxreadtoken()
10015 startlinno = plinno;
10016 for (;;) { /* until token or start of word found */
10019 if ((c != ' ') && (c != '\t')
10020 #ifdef CONFIG_ASH_ALIAS
10025 while ((c = pgetc()) != '\n' && c != PEOF);
10027 } else if (c == '\\') {
10028 if (pgetc() != '\n') {
10032 startlinno = ++plinno;
10037 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10042 needprompt = doprompt;
10045 p = strchr(xxreadtoken_chars, c);
10048 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
10051 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
10052 if (pgetc() == *p) { /* double occurrence? */
10053 p += xxreadtoken_doubles + 1;
10060 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
10068 #define RETURN(token) return lasttoken = token
10083 startlinno = plinno;
10084 for (;;) { /* until token or start of word found */
10087 case ' ': case '\t':
10088 #ifdef CONFIG_ASH_ALIAS
10093 while ((c = pgetc()) != '\n' && c != PEOF);
10097 if (pgetc() == '\n') {
10098 startlinno = ++plinno;
10107 needprompt = doprompt;
10112 if (pgetc() == '&')
10117 if (pgetc() == '|')
10122 if (pgetc() == ';')
10135 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10138 #endif /* NEW_xxreadtoken */
10142 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10143 * is not NULL, read a here document. In the latter case, eofmark is the
10144 * word which marks the end of the document and striptabs is true if
10145 * leading tabs should be stripped from the document. The argument firstc
10146 * is the first character of the input token or document.
10148 * Because C does not have internal subroutines, I have simulated them
10149 * using goto's to implement the subroutine linkage. The following macros
10150 * will run code that appears at the end of readtoken1.
10153 #define CHECKEND() {goto checkend; checkend_return:;}
10154 #define PARSEREDIR() {goto parseredir; parseredir_return:;}
10155 #define PARSESUB() {goto parsesub; parsesub_return:;}
10156 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10157 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10158 #define PARSEARITH() {goto parsearith; parsearith_return:;}
10161 readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
10166 char line[EOFMARKLEN + 1];
10167 struct nodelist *bqlist;
10170 int varnest; /* levels of variables expansion */
10171 int arinest; /* levels of arithmetic expansion */
10172 int parenlevel; /* levels of parens in arithmetic */
10173 int dqvarnest; /* levels of variables expansion within double quotes */
10175 int prevsyntax; /* syntax before arithmetic */
10177 /* Avoid longjmp clobbering */
10183 (void) &parenlevel;
10186 (void) &prevsyntax;
10190 startlinno = plinno;
10192 if (syntax == DQSYNTAX)
10201 STARTSTACKSTR(out);
10202 loop: { /* for each line, until end of word */
10203 CHECKEND(); /* set c to PEOF if at end of here document */
10204 for (;;) { /* until end of line or end of word */
10205 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10206 switch(SIT(c, syntax)) {
10207 case CNL: /* '\n' */
10208 if (syntax == BASESYNTAX)
10209 goto endword; /* exit outer loop */
10215 goto loop; /* continue outer loop */
10220 if (eofmark == NULL || dblquote)
10221 USTPUTC(CTLESC, out);
10224 case CBACK: /* backslash */
10227 USTPUTC(CTLESC, out);
10228 USTPUTC('\\', out);
10230 } else if (c == '\n') {
10236 c != '\\' && c != '`' &&
10242 USTPUTC(CTLESC, out);
10243 USTPUTC('\\', out);
10245 if (SIT(c, SQSYNTAX) == CCTL)
10246 USTPUTC(CTLESC, out);
10254 if (eofmark == NULL) {
10255 USTPUTC(CTLQUOTEMARK, out);
10263 if (eofmark != NULL && arinest == 0 &&
10267 if (dqvarnest == 0) {
10268 syntax = BASESYNTAX;
10275 case CVAR: /* '$' */
10276 PARSESUB(); /* parse substitution */
10278 case CENDVAR: /* '}' */
10281 if (dqvarnest > 0) {
10284 USTPUTC(CTLENDVAR, out);
10289 #ifdef CONFIG_ASH_MATH_SUPPORT
10290 case CLP: /* '(' in arithmetic */
10294 case CRP: /* ')' in arithmetic */
10295 if (parenlevel > 0) {
10299 if (pgetc() == ')') {
10300 if (--arinest == 0) {
10301 USTPUTC(CTLENDARI, out);
10302 syntax = prevsyntax;
10303 if (syntax == DQSYNTAX)
10311 * unbalanced parens
10312 * (don't 2nd guess - no error)
10320 case CBQUOTE: /* '`' */
10324 goto endword; /* exit outer loop */
10329 goto endword; /* exit outer loop */
10330 #ifdef CONFIG_ASH_ALIAS
10340 #ifdef CONFIG_ASH_MATH_SUPPORT
10341 if (syntax == ARISYNTAX)
10342 synerror("Missing '))'");
10344 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10345 synerror("Unterminated quoted string");
10346 if (varnest != 0) {
10347 startlinno = plinno;
10349 synerror("Missing '}'");
10351 USTPUTC('\0', out);
10352 len = out - (char *)stackblock();
10353 out = stackblock();
10354 if (eofmark == NULL) {
10355 if ((c == '>' || c == '<')
10358 && (*out == '\0' || is_digit(*out))) {
10360 return lasttoken = TREDIR;
10365 quoteflag = quotef;
10366 backquotelist = bqlist;
10367 grabstackblock(len);
10369 return lasttoken = TWORD;
10370 /* end of readtoken routine */
10375 * Check to see whether we are at the end of the here document. When this
10376 * is called, c is set to the first character of the next input line. If
10377 * we are at the end of the here document, this routine sets the c to PEOF.
10382 #ifdef CONFIG_ASH_ALIAS
10388 while (c == '\t') {
10392 if (c == *eofmark) {
10393 if (pfgets(line, sizeof line) != NULL) {
10397 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10398 if (*p == '\n' && *q == '\0') {
10401 needprompt = doprompt;
10403 pushstring(line, NULL);
10408 goto checkend_return;
10413 * Parse a redirection operator. The variable "out" points to a string
10414 * specifying the fd to be redirected. The variable "c" contains the
10415 * first character of the redirection operator.
10422 np = (union node *)stalloc(sizeof (struct nfile));
10427 np->type = NAPPEND;
10429 np->type = NCLOBBER;
10436 } else { /* c == '<' */
10438 switch (c = pgetc()) {
10440 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10441 np = (union node *)stalloc(sizeof (struct nhere));
10445 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10446 heredoc->here = np;
10447 if ((c = pgetc()) == '-') {
10448 heredoc->striptabs = 1;
10450 heredoc->striptabs = 0;
10456 np->type = NFROMFD;
10460 np->type = NFROMTO;
10470 np->nfile.fd = digit_val(fd);
10472 goto parseredir_return;
10477 * Parse a substitution. At this point, we have read the dollar sign
10478 * and nothing else.
10486 static const char types[] = "}-+?=";
10490 c <= PEOA_OR_PEOF ||
10491 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10495 } else if (c == '(') { /* $(command) or $((arith)) */
10496 if (pgetc() == '(') {
10497 #ifdef CONFIG_ASH_MATH_SUPPORT
10500 synerror("We unsupport $((arith))");
10507 USTPUTC(CTLVAR, out);
10508 typeloc = out - (char *)stackblock();
10509 USTPUTC(VSNORMAL, out);
10510 subtype = VSNORMAL;
10514 if ((c = pgetc()) == '}')
10517 subtype = VSLENGTH;
10522 if (c > PEOA_OR_PEOF && is_name(c)) {
10526 } while (c > PEOA_OR_PEOF && is_in_name(c));
10527 } else if (is_digit(c)) {
10531 } while (is_digit(c));
10533 else if (is_special(c)) {
10538 badsub: synerror("Bad substitution");
10542 if (subtype == 0) {
10549 p = strchr(types, c);
10552 subtype = p - types + VSNORMAL;
10558 subtype = c == '#' ? VSTRIMLEFT :
10571 if (dblquote || arinest)
10573 *((char *)stackblock() + typeloc) = subtype | flags;
10574 if (subtype != VSNORMAL) {
10576 if (dblquote || arinest) {
10581 goto parsesub_return;
10586 * Called to parse command substitutions. Newstyle is set if the command
10587 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10588 * list of commands (passed by reference), and savelen is the number of
10589 * characters on the top of the stack which must be preserved.
10593 struct nodelist **nlpp;
10596 char *volatile str;
10597 struct jmploc jmploc;
10598 struct jmploc *volatile savehandler;
10602 (void) &saveprompt;
10605 savepbq = parsebackquote;
10606 if (setjmp(jmploc.loc)) {
10609 parsebackquote = 0;
10610 handler = savehandler;
10611 longjmp(handler->loc, 1);
10615 savelen = out - (char *)stackblock();
10617 str = ckmalloc(savelen);
10618 memcpy(str, stackblock(), savelen);
10620 savehandler = handler;
10624 /* We must read until the closing backquote, giving special
10625 treatment to some slashes, and then push the string and
10626 reread it as input, interpreting it normally. */
10633 STARTSTACKSTR(pout);
10639 switch (pc = pgetc()) {
10644 if ((pc = pgetc()) == '\n') {
10649 * If eating a newline, avoid putting
10650 * the newline into the new character
10651 * stream (via the STPUTC after the
10656 if (pc != '\\' && pc != '`' && pc != '$'
10657 && (!dblquote || pc != '"'))
10658 STPUTC('\\', pout);
10659 if (pc > PEOA_OR_PEOF) {
10665 #ifdef CONFIG_ASH_ALIAS
10668 startlinno = plinno;
10669 synerror("EOF in backquote substitution");
10673 needprompt = doprompt;
10682 STPUTC('\0', pout);
10683 psavelen = pout - (char *)stackblock();
10684 if (psavelen > 0) {
10685 pstr = grabstackstr(pout);
10686 setinputstring(pstr);
10691 nlpp = &(*nlpp)->next;
10692 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10693 (*nlpp)->next = NULL;
10694 parsebackquote = oldstyle;
10697 saveprompt = doprompt;
10704 doprompt = saveprompt;
10706 if (readtoken() != TRP)
10713 * Start reading from old file again, ignoring any pushed back
10714 * tokens left from the backquote parsing
10719 while (stackblocksize() <= savelen)
10721 STARTSTACKSTR(out);
10723 memcpy(out, str, savelen);
10724 STADJUST(savelen, out);
10730 parsebackquote = savepbq;
10731 handler = savehandler;
10732 if (arinest || dblquote)
10733 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10735 USTPUTC(CTLBACKQ, out);
10737 goto parsebackq_oldreturn;
10739 goto parsebackq_newreturn;
10742 #ifdef CONFIG_ASH_MATH_SUPPORT
10744 * Parse an arithmetic expansion (indicate start of one and set state)
10748 if (++arinest == 1) {
10749 prevsyntax = syntax;
10750 syntax = ARISYNTAX;
10751 USTPUTC(CTLARI, out);
10758 * we collapse embedded arithmetic expansion to
10759 * parenthesis, which should be equivalent
10763 goto parsearith_return;
10767 } /* end of readtoken */
10772 * Returns true if the text contains nothing to expand (no dollar signs
10777 noexpand(char *text)
10783 while ((c = *p++) != '\0') {
10784 if (c == CTLQUOTEMARK)
10788 else if (SIT(c, BASESYNTAX) == CCTL)
10796 * Return of a legal variable name (a letter or underscore followed by zero or
10797 * more letters, underscores, and digits).
10801 endofname(const char *name)
10809 if (! is_in_name(*p))
10817 * Called when an unexpected token is read during the parse. The argument
10818 * is the token that is expected, or -1 if more than one type of token can
10819 * occur at this point.
10822 static void synexpect(int token)
10827 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10829 sprintf(msg + l, " (expecting %s)", tokname(token));
10835 synerror(const char *msg)
10837 error("Syntax error: %s", msg);
10843 * called by editline -- any expansions to the prompt
10844 * should be added here.
10847 static void setprompt(int whichprompt)
10849 const char *prompt;
10851 switch (whichprompt) {
10865 static const char *const *findkwd(const char *s)
10867 return bsearch(s, tokname_array + KWDOFFSET,
10868 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
10869 sizeof(const char *), pstrcmp);
10872 /* $NetBSD: redir.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
10875 * Code for dealing with input/output redirection.
10878 #define EMPTY -2 /* marks an unused slot in redirtab */
10880 # define PIPESIZE 4096 /* amount of buffering in a pipe */
10882 # define PIPESIZE PIPE_BUF
10886 * Open a file in noclobber mode.
10887 * The code was copied from bash.
10890 noclobberopen(const char *fname)
10893 struct stat finfo, finfo2;
10896 * If the file exists and is a regular file, return an error
10899 r = stat(fname, &finfo);
10900 if (r == 0 && S_ISREG(finfo.st_mode)) {
10906 * If the file was not present (r != 0), make sure we open it
10907 * exclusively so that if it is created before we open it, our open
10908 * will fail. Make sure that we do not truncate an existing file.
10909 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10910 * file was not a regular file, we leave O_EXCL off.
10913 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10914 fd = open(fname, O_WRONLY|O_CREAT, 0666);
10916 /* If the open failed, return the file descriptor right away. */
10921 * OK, the open succeeded, but the file may have been changed from a
10922 * non-regular file to a regular file between the stat and the open.
10923 * We are assuming that the O_EXCL open handles the case where FILENAME
10924 * did not exist and is symlinked to an existing file between the stat
10929 * If we can open it and fstat the file descriptor, and neither check
10930 * revealed that it was a regular file, and the file has not been
10931 * replaced, return the file descriptor.
10933 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10934 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
10937 /* The file has been replaced. badness. */
10944 * Handle here documents. Normally we fork off a process to write the
10945 * data to a pipe. If the document is short, we can stuff the data in
10946 * the pipe without forking.
10950 openhere(union node *redir)
10956 error("Pipe call failed");
10957 if (redir->type == NHERE) {
10958 len = strlen(redir->nhere.doc->narg.text);
10959 if (len <= PIPESIZE) {
10960 bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
10964 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
10966 signal(SIGINT, SIG_IGN);
10967 signal(SIGQUIT, SIG_IGN);
10968 signal(SIGHUP, SIG_IGN);
10970 signal(SIGTSTP, SIG_IGN);
10972 signal(SIGPIPE, SIG_DFL);
10973 if (redir->type == NHERE)
10974 bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
10976 expandhere(redir->nhere.doc, pip[1]);
10985 openredirect(union node *redir)
10990 switch (redir->nfile.type) {
10992 fname = redir->nfile.expfname;
10993 if ((f = open(fname, O_RDONLY)) < 0)
10997 fname = redir->nfile.expfname;
10998 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
11002 /* Take care of noclobber mode. */
11004 fname = redir->nfile.expfname;
11005 if ((f = noclobberopen(fname)) < 0)
11011 fname = redir->nfile.expfname;
11012 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
11016 fname = redir->nfile.expfname;
11017 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
11024 /* Fall through to eliminate warning. */
11031 f = openhere(redir);
11037 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
11039 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11043 dupredirect(union node *redir, int f)
11045 int fd = redir->nfile.fd;
11047 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11048 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
11049 copyfd(redir->ndup.dupfd, fd);
11062 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11063 * old file descriptors are stashed away so that the redirection can be
11064 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11065 * standard output, and the standard error if it becomes a duplicate of
11066 * stdout, is saved in memory.
11070 redirect(union node *redir, int flags)
11073 struct redirtab *sv;
11084 if (flags & REDIR_PUSH) {
11085 struct redirtab *q;
11086 q = ckmalloc(sizeof (struct redirtab));
11087 q->next = redirlist;
11089 q->nullredirs = nullredirs - 1;
11090 for (i = 0 ; i < 10 ; i++)
11091 q->renamed[i] = EMPTY;
11098 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
11099 n->ndup.dupfd == fd)
11100 continue; /* redirect from/to same file descriptor */
11102 newfd = openredirect(n);
11105 if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
11106 i = fcntl(fd, F_DUPFD, 10);
11113 error("%d: %m", fd);
11123 dupredirect(n, newfd);
11124 } while ((n = n->nfile.next));
11126 if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
11127 preverrout_fd = sv->renamed[2];
11132 * Undo the effects of the last redirection.
11138 struct redirtab *rp;
11141 if (--nullredirs >= 0)
11145 for (i = 0 ; i < 10 ; i++) {
11146 if (rp->renamed[i] != EMPTY) {
11149 copyfd(rp->renamed[i], i);
11151 close(rp->renamed[i]);
11154 redirlist = rp->next;
11155 nullredirs = rp->nullredirs;
11161 * Undo all redirections. Called on error or interrupt.
11165 * Discard all saved file descriptors.
11169 clearredir(int drop)
11181 * Copy a file descriptor to be >= to. Returns -1
11182 * if the source file descriptor is closed, EMPTY if there are no unused
11183 * file descriptors left.
11187 copyfd(int from, int to)
11191 newfd = fcntl(from, F_DUPFD, to);
11193 if (errno == EMFILE)
11196 error("%d: %m", from);
11203 redirectsafe(union node *redir, int flags)
11206 volatile int saveint;
11207 struct jmploc *volatile savehandler = handler;
11208 struct jmploc jmploc;
11211 if (!(err = setjmp(jmploc.loc) * 2)) {
11213 redirect(redir, flags);
11215 handler = savehandler;
11216 if (err && exception != EXERROR)
11217 longjmp(handler->loc, 1);
11218 RESTOREINT(saveint);
11222 /* $NetBSD: show.c,v 1.24 2003/01/22 20:36:04 dsl Exp $ */
11225 static void shtree(union node *, int, char *, FILE*);
11226 static void shcmd(union node *, FILE *);
11227 static void sharg(union node *, FILE *);
11228 static void indent(int, char *, FILE *);
11229 static void trstring(char *);
11233 showtree(union node *n)
11235 trputs("showtree called\n");
11236 shtree(n, 1, NULL, stdout);
11241 shtree(union node *n, int ind, char *pfx, FILE *fp)
11243 struct nodelist *lp;
11249 indent(ind, pfx, fp);
11260 shtree(n->nbinary.ch1, ind, NULL, fp);
11263 shtree(n->nbinary.ch2, ind, NULL, fp);
11271 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
11276 if (n->npipe.backgnd)
11282 fprintf(fp, "<node type %d>", n->type);
11291 shcmd(union node *cmd, FILE *fp)
11299 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11305 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11308 switch (np->nfile.type) {
11309 case NTO: s = ">"; dftfd = 1; break;
11310 case NCLOBBER: s = ">|"; dftfd = 1; break;
11311 case NAPPEND: s = ">>"; dftfd = 1; break;
11312 case NTOFD: s = ">&"; dftfd = 1; break;
11313 case NFROM: s = "<"; dftfd = 0; break;
11314 case NFROMFD: s = "<&"; dftfd = 0; break;
11315 case NFROMTO: s = "<>"; dftfd = 0; break;
11316 default: s = "*error*"; dftfd = 0; break;
11318 if (np->nfile.fd != dftfd)
11319 fprintf(fp, "%d", np->nfile.fd);
11321 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11322 fprintf(fp, "%d", np->ndup.dupfd);
11324 sharg(np->nfile.fname, fp);
11333 sharg(union node *arg, FILE *fp)
11336 struct nodelist *bqlist;
11339 if (arg->type != NARG) {
11340 out1fmt("<node type %d>\n", arg->type);
11343 bqlist = arg->narg.backquote;
11344 for (p = arg->narg.text ; *p ; p++) {
11353 if (subtype == VSLENGTH)
11359 if (subtype & VSNUL)
11362 switch (subtype & VSTYPE) {
11381 case VSTRIMLEFTMAX:
11388 case VSTRIMRIGHTMAX:
11395 out1fmt("<subtype %d>", subtype);
11402 case CTLBACKQ|CTLQUOTE:
11405 shtree(bqlist->n, -1, NULL, fp);
11417 indent(int amount, char *pfx, FILE *fp)
11421 for (i = 0 ; i < amount ; i++) {
11422 if (pfx && i == amount - 1)
11443 putc(c, tracefile);
11447 trace(const char *fmt, ...)
11454 (void) vfprintf(tracefile, fmt, va);
11459 tracev(const char *fmt, va_list va)
11463 (void) vfprintf(tracefile, fmt, va);
11468 trputs(const char *s)
11472 fputs(s, tracefile);
11484 putc('"', tracefile);
11485 for (p = s ; *p ; p++) {
11487 case '\n': c = 'n'; goto backslash;
11488 case '\t': c = 't'; goto backslash;
11489 case '\r': c = 'r'; goto backslash;
11490 case '"': c = '"'; goto backslash;
11491 case '\\': c = '\\'; goto backslash;
11492 case CTLESC: c = 'e'; goto backslash;
11493 case CTLVAR: c = 'v'; goto backslash;
11494 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11495 case CTLBACKQ: c = 'q'; goto backslash;
11496 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
11497 backslash: putc('\\', tracefile);
11498 putc(c, tracefile);
11501 if (*p >= ' ' && *p <= '~')
11502 putc(*p, tracefile);
11504 putc('\\', tracefile);
11505 putc(*p >> 6 & 03, tracefile);
11506 putc(*p >> 3 & 07, tracefile);
11507 putc(*p & 07, tracefile);
11512 putc('"', tracefile);
11524 putc(' ', tracefile);
11526 putc('\n', tracefile);
11542 /* leave open because libedit might be using it */
11545 scopy("./trace", s);
11547 if (!freopen(s, "a", tracefile)) {
11548 fprintf(stderr, "Can't re-open %s\n", s);
11553 if ((tracefile = fopen(s, "a")) == NULL) {
11554 fprintf(stderr, "Can't open %s\n", s);
11560 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11561 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11563 setlinebuf(tracefile);
11564 fputs("\nTracing started.\n", tracefile);
11569 /* $NetBSD: trap.c,v 1.28 2002/11/24 22:35:43 christos Exp $ */
11572 * Sigmode records the current value of the signal handlers for the various
11573 * modes. A value of zero means that the current handler is not known.
11574 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
11577 #define S_DFL 1 /* default signal handling (SIG_DFL) */
11578 #define S_CATCH 2 /* signal is caught */
11579 #define S_IGN 3 /* signal is ignored (SIG_IGN) */
11580 #define S_HARD_IGN 4 /* signal is ignored permenantly */
11581 #define S_RESET 5 /* temporary - to reset a hard ignored sig */
11586 * The trap builtin.
11590 trapcmd(int argc, char **argv)
11599 for (signo = 0 ; signo < NSIG ; signo++) {
11600 if (trap[signo] != NULL) {
11603 sn = u_signal_names(0, &signo, 0);
11606 out1fmt("trap -- %s %s\n",
11607 single_quote(trap[signo]), sn);
11617 if ((signo = decode_signal(*ap, 0)) < 0)
11618 error("%s: bad trap", *ap);
11621 if (action[0] == '-' && action[1] == '\0')
11624 action = savestr(action);
11627 ckfree(trap[signo]);
11628 trap[signo] = action;
11639 * Clear traps on a fork.
11647 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
11648 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
11652 if (tp != &trap[0])
11653 setsignal(tp - trap);
11661 * Set the signal handler for the specified signal. The routine figures
11662 * out what it should be set to.
11666 setsignal(int signo)
11670 struct sigaction act;
11672 if ((t = trap[signo]) == NULL)
11674 else if (*t != '\0')
11678 if (rootshell && action == S_DFL) {
11681 if (iflag || minusc || sflag == 0)
11704 t = &sigmode[signo - 1];
11708 * current setting unknown
11710 if (sigaction(signo, 0, &act) == -1) {
11712 * Pretend it worked; maybe we should give a warning
11713 * here, but other shells don't. We don't alter
11714 * sigmode, so that we retry every time.
11718 if (act.sa_handler == SIG_IGN) {
11719 if (mflag && (signo == SIGTSTP ||
11720 signo == SIGTTIN || signo == SIGTTOU)) {
11721 tsig = S_IGN; /* don't hard ignore these */
11725 tsig = S_RESET; /* force to be set */
11728 if (tsig == S_HARD_IGN || tsig == action)
11732 act.sa_handler = onsig;
11735 act.sa_handler = SIG_IGN;
11738 act.sa_handler = SIG_DFL;
11742 sigfillset(&act.sa_mask);
11743 sigaction(signo, &act, 0);
11751 ignoresig(int signo)
11753 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11754 signal(signo, SIG_IGN);
11756 sigmode[signo - 1] = S_HARD_IGN;
11767 gotsig[signo - 1] = 1;
11768 pendingsigs = signo;
11770 if (exsig || (signo == SIGINT && !trap[SIGINT])) {
11779 * Called to execute a trap. Perhaps we should avoid entering new trap
11780 * handlers while we are executing a trap handler.
11790 savestatus = exitstatus;
11792 while (pendingsigs = 0, barrier(), (p = memchr(q, 1, NSIG - 1))) {
11794 p = trap[p - q + 1];
11798 exitstatus = savestatus;
11804 * Controls whether the shell is interactive or not.
11808 setinteractive(int on)
11810 static int is_interactive;
11812 if (++on == is_interactive)
11814 is_interactive = on;
11816 setsignal(SIGQUIT);
11817 setsignal(SIGTERM);
11818 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11819 if(is_interactive > 1) {
11820 /* Looks like they want an interactive shell */
11821 static int do_banner;
11825 "\n\n" BB_BANNER " Built-in shell (ash)\n"
11826 "Enter 'help' for a list of built-in commands.\n\n");
11834 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11835 /*** List the available builtins ***/
11837 static int helpcmd(int argc, char **argv)
11841 out1fmt("\nBuilt-in commands:\n-------------------\n");
11842 for (col = 0, i = 0; i < NUMBUILTINS; i++) {
11843 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11844 builtincmd[i].name + 1);
11850 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
11852 extern const struct BB_applet applets[];
11853 extern const size_t NUM_APPLETS;
11855 for (i = 0; i < NUM_APPLETS; i++) {
11857 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
11866 return EXIT_SUCCESS;
11868 #endif /* CONFIG_FEATURE_SH_EXTRA_QUIET */
11871 * Called to exit the shell.
11882 jmp = setjmp(loc.loc);
11883 status = exitstatus;
11884 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
11888 if ((p = trap[0]) != NULL && *p != '\0') {
11893 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
11894 if (iflag && rootshell) {
11895 const char *hp = lookupvar("HISTFILE");
11898 save_history ( hp );
11906 static int decode_signal(const char *string, int minsig)
11909 const char *name = u_signal_names(string, &signo, minsig);
11911 return name ? signo : -1;
11914 /* $NetBSD: var.c,v 1.32 2003/01/22 20:36:04 dsl Exp $ */
11916 static struct var *vartab[VTABSIZE];
11918 static int vpcmp(const void *, const void *);
11919 static struct var **findvar(struct var **, const char *);
11922 * Initialize the varable symbol tables and import the environment
11926 #ifdef CONFIG_ASH_GETOPTS
11928 * Safe version of setvar, returns 1 on success 0 on failure.
11932 setvarsafe(const char *name, const char *val, int flags)
11935 volatile int saveint;
11936 struct jmploc *volatile savehandler = handler;
11937 struct jmploc jmploc;
11940 if (setjmp(jmploc.loc))
11944 setvar(name, val, flags);
11947 handler = savehandler;
11948 RESTOREINT(saveint);
11954 * Set the value of a variable. The flags argument is ored with the
11955 * flags of the variable. If val is NULL, the variable is unset.
11959 setvar(const char *name, const char *val, int flags)
11966 q = endofname(name);
11967 p = strchrnul(q, '=');
11968 namelen = p - name;
11969 if (!namelen || p != q)
11970 error("%.*s: bad variable name", namelen, name);
11975 vallen = strlen(val);
11978 p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
11982 p = mempcpy(p, val, vallen);
11985 setvareq(nameeq, flags | VNOSAVE);
11991 * Same as setvar except that the variable and value are passed in
11992 * the first argument as name=value. Since the first argument will
11993 * be actually stored in the table, it should not be a string that
11995 * Called with interrupts off.
11999 setvareq(char *s, int flags)
12001 struct var *vp, **vpp;
12004 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
12005 vp = *findvar(vpp, s);
12007 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
12010 if (flags & VNOSAVE)
12013 error("%.*s: is read only", strchrnul(n, '=') - n, n);
12016 if (flags & VNOSET)
12019 if (vp->func && (flags & VNOFUNC) == 0)
12020 (*vp->func)(strchrnul(s, '=') + 1);
12022 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12025 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
12027 if (flags & VNOSET)
12030 vp = ckmalloc(sizeof (*vp));
12035 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
12043 * Process a linked list of variable assignments.
12047 listsetvar(struct strlist *list_set_var, int flags)
12049 struct strlist *lp = list_set_var;
12055 setvareq(lp->text, flags);
12056 } while ((lp = lp->next));
12062 * Find the value of a variable. Returns NULL if not set.
12066 lookupvar(const char *name)
12070 if ((v = *findvar(hashvar(name), name))) {
12073 * Dynamic variables are implemented roughly the same way they are
12074 * in bash. Namely, they're "special" so long as they aren't unset.
12075 * As soon as they're unset, they're no longer dynamic, and dynamic
12076 * lookup will no longer happen at that point. -- PFM.
12078 if((v->flags & VDYNAMIC))
12081 if(!(v->flags & VUNSET))
12082 return strchrnul(v->text, '=') + 1;
12090 * Search the environment of a builtin command.
12094 bltinlookup(const char *name)
12096 struct strlist *sp;
12098 for (sp = cmdenviron ; sp ; sp = sp->next) {
12099 if (varequal(sp->text, name))
12100 return strchrnul(sp->text, '=') + 1;
12102 return lookupvar(name);
12107 * Generate a list of variables satisfying the given conditions.
12111 listvars(int on, int off, char ***end)
12122 for (vp = *vpp ; vp ; vp = vp->next)
12123 if ((vp->flags & mask) == on) {
12124 if (ep == stackstrend())
12125 ep = growstackstr();
12126 *ep++ = (char *) vp->text;
12128 } while (++vpp < vartab + VTABSIZE);
12129 if (ep == stackstrend())
12130 ep = growstackstr();
12134 return grabstackstr(ep);
12139 * POSIX requires that 'set' (but not export or readonly) output the
12140 * variables in lexicographic order - by the locale's collating order (sigh).
12141 * Maybe we could keep them in an ordered balanced binary tree
12142 * instead of hashed lists.
12143 * For now just roll 'em through qsort for printing...
12147 showvars(const char *sep_prefix, int on, int off)
12150 char **ep, **epend;
12152 ep = listvars(on, off, &epend);
12153 qsort(ep, epend - ep, sizeof(char *), vpcmp);
12155 sep = *sep_prefix ? spcstr : sep_prefix;
12157 for (; ep < epend; ep++) {
12161 p = strchrnul(*ep, '=');
12164 q = single_quote(++p);
12166 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
12175 * The export and readonly commands.
12179 exportcmd(int argc, char **argv)
12185 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12188 notp = nextopt("p") - 'p';
12189 if (notp && ((name = *(aptr = argptr)))) {
12191 if ((p = strchr(name, '=')) != NULL) {
12194 if ((vp = *findvar(hashvar(name), name))) {
12199 setvar(name, p, flag);
12200 } while ((name = *++aptr) != NULL);
12202 showvars(argv[0], flag, 0);
12209 * Make a variable a local variable. When a variable is made local, it's
12210 * value and flags are saved in a localvar structure. The saved values
12211 * will be restored when the shell function returns. We handle the name
12212 * "-" as a special case.
12216 mklocal(char *name)
12218 struct localvar *lvp;
12223 lvp = ckmalloc(sizeof (struct localvar));
12224 if (name[0] == '-' && name[1] == '\0') {
12226 p = ckmalloc(sizeof(optlist));
12227 lvp->text = memcpy(p, optlist, sizeof(optlist));
12232 vpp = hashvar(name);
12233 vp = *findvar(vpp, name);
12234 eq = strchr(name, '=');
12237 setvareq(name, VSTRFIXED);
12239 setvar(name, NULL, VSTRFIXED);
12240 vp = *vpp; /* the new variable */
12241 lvp->flags = VUNSET;
12243 lvp->text = vp->text;
12244 lvp->flags = vp->flags;
12245 vp->flags |= VSTRFIXED|VTEXTFIXED;
12251 lvp->next = localvars;
12257 * The "local" command.
12261 localcmd(int argc, char **argv)
12266 while ((name = *argv++) != NULL) {
12274 * Called after a function returns.
12275 * Interrupts must be off.
12281 struct localvar *lvp;
12284 while ((lvp = localvars) != NULL) {
12285 localvars = lvp->next;
12287 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
12288 if (vp == NULL) { /* $- saved */
12289 memcpy(optlist, lvp->text, sizeof(optlist));
12292 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12293 unsetvar(vp->text);
12296 (*vp->func)(strchrnul(lvp->text, '=') + 1);
12297 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12299 vp->flags = lvp->flags;
12300 vp->text = lvp->text;
12308 * The unset builtin command. We unset the function before we unset the
12309 * variable to allow a function to be unset when there is a readonly variable
12310 * with the same name.
12314 unsetcmd(int argc, char **argv)
12321 while ((i = nextopt("vf")) != '\0') {
12325 for (ap = argptr; *ap ; ap++) {
12340 * Unset the specified variable.
12344 unsetvar(const char *s)
12350 vpp = findvar(hashvar(s), s);
12354 int flags = vp->flags;
12357 if (flags & VREADONLY)
12360 vp->flags &= ~VDYNAMIC;
12362 if (flags & VUNSET)
12364 if ((flags & VSTRFIXED) == 0) {
12366 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
12373 vp->flags &= ~VEXPORT;
12386 * Find the appropriate entry in the hash table from the name.
12389 static struct var **
12390 hashvar(const char *p)
12392 unsigned int hashval;
12394 hashval = ((unsigned char) *p) << 4;
12395 while (*p && *p != '=')
12396 hashval += (unsigned char) *p++;
12397 return &vartab[hashval % VTABSIZE];
12403 * Compares two strings up to the first = or '\0'. The first
12404 * string must be terminated by '='; the second may be terminated by
12405 * either '=' or '\0'.
12409 varcmp(const char *p, const char *q)
12413 while ((c = *p) == (d = *q)) {
12414 if (!c || c == '=')
12428 vpcmp(const void *a, const void *b)
12430 return varcmp(*(const char **)a, *(const char **)b);
12433 static struct var **
12434 findvar(struct var **vpp, const char *name)
12436 for (; *vpp; vpp = &(*vpp)->next) {
12437 if (varequal((*vpp)->text, name)) {
12443 /* $NetBSD: setmode.c,v 1.29 2003/01/15 23:58:03 kleink Exp $ */
12445 #include <sys/times.h>
12447 static const unsigned char timescmd_str[] = {
12448 ' ', offsetof(struct tms, tms_utime),
12449 '\n', offsetof(struct tms, tms_stime),
12450 ' ', offsetof(struct tms, tms_cutime),
12451 '\n', offsetof(struct tms, tms_cstime),
12455 static int timescmd(int ac, char **av)
12457 long int clk_tck, s, t;
12458 const unsigned char *p;
12461 clk_tck = sysconf(_SC_CLK_TCK);
12466 t = *(clock_t *)(((char *) &buf) + p[1]);
12468 out1fmt("%ldm%ld.%.3lds%c",
12470 ((t - s * clk_tck) * 1000) / clk_tck,
12472 } while (*(p += 2));
12477 #ifdef CONFIG_ASH_MATH_SUPPORT
12479 dash_arith(const char *s)
12485 result = arith(s, &errcode);
12488 error("exponent less than 0");
12489 else if (errcode == -2)
12490 error("divide by zero");
12491 else if (errcode == -5)
12492 error("expression recursion loop detected");
12503 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12504 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12506 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12510 letcmd(int argc, char **argv)
12517 error("expression expected");
12518 for (ap = argv + 1; *ap; ap++) {
12519 i = dash_arith(*ap);
12524 #endif /* CONFIG_ASH_MATH_SUPPORT */
12526 /* $NetBSD: miscbltin.c,v 1.31 2002/11/24 22:35:41 christos Exp $ */
12529 * Miscelaneous builtins.
12535 #if __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
12536 typedef enum __rlimit_resource rlim_t;
12542 * The read builtin. The -e option causes backslashes to escape the
12543 * following character.
12545 * This uses unbuffered input, which may be avoidable in some cases.
12549 readcmd(int argc, char **argv)
12564 while ((i = nextopt("p:r")) != '\0') {
12566 prompt = optionarg;
12570 if (prompt && isatty(0)) {
12573 if (*(ap = argptr) == NULL)
12574 error("arg count");
12575 if ((ifs = bltinlookup("IFS")) == NULL)
12582 if (read(0, &c, 1) != 1) {
12594 if (!rflag && c == '\\') {
12600 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12604 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12606 setvar(*ap, stackblock(), 0);
12616 /* Remove trailing blanks */
12617 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12619 setvar(*ap, stackblock(), 0);
12620 while (*++ap != NULL)
12621 setvar(*ap, nullstr, 0);
12626 static int umaskcmd(int argc, char **argv)
12628 static const char permuser[3] = "ugo";
12629 static const char permmode[3] = "rwx";
12630 static const short int permmask[] = {
12631 S_IRUSR, S_IWUSR, S_IXUSR,
12632 S_IRGRP, S_IWGRP, S_IXGRP,
12633 S_IROTH, S_IWOTH, S_IXOTH
12639 int symbolic_mode = 0;
12641 while (nextopt("S") != '\0') {
12650 if ((ap = *argptr) == NULL) {
12651 if (symbolic_mode) {
12655 for (i = 0; i < 3; i++) {
12658 *p++ = permuser[i];
12660 for (j = 0; j < 3; j++) {
12661 if ((mask & permmask[3 * i + j]) == 0) {
12662 *p++ = permmode[j];
12670 out1fmt("%.4o\n", mask);
12673 if (is_digit((unsigned char) *ap)) {
12676 if (*ap >= '8' || *ap < '0')
12677 error(illnum, argv[1]);
12678 mask = (mask << 3) + (*ap - '0');
12679 } while (*++ap != '\0');
12682 mask = ~mask & 0777;
12683 if (!bb_parse_mode(ap, &mask)) {
12684 error("Illegal mode: %s", ap);
12686 umask(~mask & 0777);
12695 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12696 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12697 * ash by J.T. Conklin.
12705 int factor; /* multiply by to get rlim_{cur,max} values */
12709 static const struct limits limits[] = {
12711 { "time(seconds)", RLIMIT_CPU, 1, 't' },
12713 #ifdef RLIMIT_FSIZE
12714 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
12717 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
12719 #ifdef RLIMIT_STACK
12720 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
12723 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
12726 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
12728 #ifdef RLIMIT_MEMLOCK
12729 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
12731 #ifdef RLIMIT_NPROC
12732 { "process", RLIMIT_NPROC, 1, 'p' },
12734 #ifdef RLIMIT_NOFILE
12735 { "nofiles", RLIMIT_NOFILE, 1, 'n' },
12738 { "vmemory(kbytes)", RLIMIT_AS, 1024, 'v' },
12740 #ifdef RLIMIT_LOCKS
12741 { "locks", RLIMIT_LOCKS, 1, 'w' },
12743 { (char *) 0, 0, 0, '\0' }
12746 enum limtype { SOFT = 0x1, HARD = 0x2 };
12748 static void printlim(enum limtype how, const struct rlimit *limit,
12749 const struct limits *l)
12753 val = limit->rlim_max;
12755 val = limit->rlim_cur;
12757 if (val == RLIM_INFINITY)
12758 out1fmt("unlimited\n");
12761 out1fmt("%lld\n", (long long) val);
12766 ulimitcmd(int argc, char **argv)
12770 enum limtype how = SOFT | HARD;
12771 const struct limits *l;
12774 struct rlimit limit;
12777 while ((optc = nextopt("HSa"
12781 #ifdef RLIMIT_FSIZE
12787 #ifdef RLIMIT_STACK
12796 #ifdef RLIMIT_MEMLOCK
12799 #ifdef RLIMIT_NPROC
12802 #ifdef RLIMIT_NOFILE
12808 #ifdef RLIMIT_LOCKS
12826 for (l = limits; l->option != what; l++)
12829 set = *argptr ? 1 : 0;
12833 if (all || argptr[1])
12834 error("too many arguments");
12835 if (strncmp(p, "unlimited\n", 9) == 0)
12836 val = RLIM_INFINITY;
12840 while ((c = *p++) >= '0' && c <= '9')
12842 val = (val * 10) + (long)(c - '0');
12843 if (val < (rlim_t) 0)
12847 error("bad number");
12852 for (l = limits; l->name; l++) {
12853 getrlimit(l->cmd, &limit);
12854 out1fmt("%-20s ", l->name);
12855 printlim(how, &limit, l);
12860 getrlimit(l->cmd, &limit);
12863 limit.rlim_max = val;
12865 limit.rlim_cur = val;
12866 if (setrlimit(l->cmd, &limit) < 0)
12867 error("error setting limit (%m)");
12869 printlim(how, &limit, l);
12875 #ifdef CONFIG_ASH_MATH_SUPPORT
12877 /* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
12879 Permission is hereby granted, free of charge, to any person obtaining
12880 a copy of this software and associated documentation files (the
12881 "Software"), to deal in the Software without restriction, including
12882 without limitation the rights to use, copy, modify, merge, publish,
12883 distribute, sublicense, and/or sell copies of the Software, and to
12884 permit persons to whom the Software is furnished to do so, subject to
12885 the following conditions:
12887 The above copyright notice and this permission notice shall be
12888 included in all copies or substantial portions of the Software.
12890 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12891 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12892 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
12893 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
12894 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
12895 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
12896 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12899 /* This is my infix parser/evaluator. It is optimized for size, intended
12900 * as a replacement for yacc-based parsers. However, it may well be faster
12901 * than a comparable parser writen in yacc. The supported operators are
12902 * listed in #defines below. Parens, order of operations, and error handling
12903 * are supported. This code is threadsafe. The exact expression format should
12904 * be that which POSIX specifies for shells. */
12906 /* The code uses a simple two-stack algorithm. See
12907 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
12908 * for a detailed explaination of the infix-to-postfix algorithm on which
12909 * this is based (this code differs in that it applies operators immediately
12910 * to the stack instead of adding them to a queue to end up with an
12913 /* To use the routine, call it with an expression string and error return
12917 * Aug 24, 2001 Manuel Novoa III
12919 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
12921 * 1) In arith_apply():
12922 * a) Cached values of *numptr and &(numptr[-1]).
12923 * b) Removed redundant test for zero denominator.
12926 * a) Eliminated redundant code for processing operator tokens by moving
12927 * to a table-based implementation. Also folded handling of parens
12929 * b) Combined all 3 loops which called arith_apply to reduce generated
12930 * code size at the cost of speed.
12932 * 3) The following expressions were treated as valid by the original code:
12933 * 1() , 0! , 1 ( *3 ) .
12934 * These bugs have been fixed by internally enclosing the expression in
12935 * parens and then checking that all binary ops and right parens are
12936 * preceded by a valid expression (NUM_TOKEN).
12938 * Note: It may be desireable to replace Aaron's test for whitespace with
12939 * ctype's isspace() if it is used by another busybox applet or if additional
12940 * whitespace chars should be considered. Look below the "#include"s for a
12941 * precompiler test.
12945 * Aug 26, 2001 Manuel Novoa III
12947 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
12949 * Merge in Aaron's comments previously posted to the busybox list,
12950 * modified slightly to take account of my changes to the code.
12955 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12957 * - allow access to variable,
12958 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
12959 * - realize assign syntax (VAR=expr, +=, *= etc)
12960 * - realize exponentiation (** operator)
12961 * - realize comma separated - expr, expr
12962 * - realise ++expr --expr expr++ expr--
12963 * - realise expr ? expr : expr (but, second expr calculate always)
12964 * - allow hexdecimal and octal numbers
12965 * - was restored loses XOR operator
12966 * - remove one goto label, added three ;-)
12967 * - protect $((num num)) as true zero expr (Manuel`s error)
12968 * - always use special isspace(), see comment from bash ;-)
12972 #define arith_isspace(arithval) \
12973 (arithval == ' ' || arithval == '\n' || arithval == '\t')
12976 typedef unsigned char operator;
12978 /* An operator's token id is a bit of a bitfield. The lower 5 bits are the
12979 * precedence, and 3 high bits are an ID unique accross operators of that
12980 * precedence. The ID portion is so that multiple operators can have the
12981 * same precedence, ensuring that the leftmost one is evaluated first.
12982 * Consider * and /. */
12984 #define tok_decl(prec,id) (((id)<<5)|(prec))
12985 #define PREC(op) ((op) & 0x1F)
12987 #define TOK_LPAREN tok_decl(0,0)
12989 #define TOK_COMMA tok_decl(1,0)
12991 #define TOK_ASSIGN tok_decl(2,0)
12992 #define TOK_AND_ASSIGN tok_decl(2,1)
12993 #define TOK_OR_ASSIGN tok_decl(2,2)
12994 #define TOK_XOR_ASSIGN tok_decl(2,3)
12995 #define TOK_PLUS_ASSIGN tok_decl(2,4)
12996 #define TOK_MINUS_ASSIGN tok_decl(2,5)
12997 #define TOK_LSHIFT_ASSIGN tok_decl(2,6)
12998 #define TOK_RSHIFT_ASSIGN tok_decl(2,7)
13000 #define TOK_MUL_ASSIGN tok_decl(3,0)
13001 #define TOK_DIV_ASSIGN tok_decl(3,1)
13002 #define TOK_REM_ASSIGN tok_decl(3,2)
13004 /* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
13005 #define convert_prec_is_assing(prec) do { if(prec == 3) prec = 2; } while(0)
13007 /* conditional is right associativity too */
13008 #define TOK_CONDITIONAL tok_decl(4,0)
13009 #define TOK_CONDITIONAL_SEP tok_decl(4,1)
13011 #define TOK_OR tok_decl(5,0)
13013 #define TOK_AND tok_decl(6,0)
13015 #define TOK_BOR tok_decl(7,0)
13017 #define TOK_BXOR tok_decl(8,0)
13019 #define TOK_BAND tok_decl(9,0)
13021 #define TOK_EQ tok_decl(10,0)
13022 #define TOK_NE tok_decl(10,1)
13024 #define TOK_LT tok_decl(11,0)
13025 #define TOK_GT tok_decl(11,1)
13026 #define TOK_GE tok_decl(11,2)
13027 #define TOK_LE tok_decl(11,3)
13029 #define TOK_LSHIFT tok_decl(12,0)
13030 #define TOK_RSHIFT tok_decl(12,1)
13032 #define TOK_ADD tok_decl(13,0)
13033 #define TOK_SUB tok_decl(13,1)
13035 #define TOK_MUL tok_decl(14,0)
13036 #define TOK_DIV tok_decl(14,1)
13037 #define TOK_REM tok_decl(14,2)
13039 /* exponent is right associativity */
13040 #define TOK_EXPONENT tok_decl(15,1)
13042 /* For now unary operators. */
13043 #define UNARYPREC 16
13044 #define TOK_BNOT tok_decl(UNARYPREC,0)
13045 #define TOK_NOT tok_decl(UNARYPREC,1)
13047 #define TOK_UMINUS tok_decl(UNARYPREC+1,0)
13048 #define TOK_UPLUS tok_decl(UNARYPREC+1,1)
13050 #define PREC_PRE (UNARYPREC+2)
13052 #define TOK_PRE_INC tok_decl(PREC_PRE, 0)
13053 #define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
13055 #define PREC_POST (UNARYPREC+3)
13057 #define TOK_POST_INC tok_decl(PREC_POST, 0)
13058 #define TOK_POST_DEC tok_decl(PREC_POST, 1)
13060 #define SPEC_PREC (UNARYPREC+4)
13062 #define TOK_NUM tok_decl(SPEC_PREC, 0)
13063 #define TOK_RPAREN tok_decl(SPEC_PREC, 1)
13065 #define NUMPTR (*numstackptr)
13067 static inline int tok_have_assign(operator op)
13069 operator prec = PREC(op);
13071 convert_prec_is_assing(prec);
13072 return (prec == PREC(TOK_ASSIGN) ||
13073 prec == PREC_PRE || prec == PREC_POST);
13076 static inline int is_right_associativity(operator prec)
13078 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) ||
13079 prec == PREC(TOK_CONDITIONAL));
13083 typedef struct ARITCH_VAR_NUM {
13085 long contidional_second_val;
13086 char contidional_second_val_initialized;
13087 char *var; /* if NULL then is regular number,
13088 else is varable name */
13092 typedef struct CHK_VAR_RECURSIVE_LOOPED {
13094 struct CHK_VAR_RECURSIVE_LOOPED *next;
13095 } chk_var_recursive_looped_t;
13097 static chk_var_recursive_looped_t *prev_chk_var_recursive;
13100 static int arith_lookup_val(v_n_t *t)
13103 const char * p = lookupvar(t->var);
13108 /* recursive try as expression */
13109 chk_var_recursive_looped_t *cur;
13110 chk_var_recursive_looped_t cur_save;
13112 for(cur = prev_chk_var_recursive; cur; cur = cur->next) {
13113 if(strcmp(cur->var, t->var) == 0) {
13114 /* expression recursion loop detected */
13118 /* save current lookuped var name */
13119 cur = prev_chk_var_recursive;
13120 cur_save.var = t->var;
13121 cur_save.next = cur;
13122 prev_chk_var_recursive = &cur_save;
13124 t->val = arith (p, &errcode);
13125 /* restore previous ptr after recursiving */
13126 prev_chk_var_recursive = cur;
13129 /* allow undefined var as 0 */
13136 /* "applying" a token means performing it on the top elements on the integer
13137 * stack. For a unary operator it will only change the top element, but a
13138 * binary operator will pop two arguments and push a result */
13140 arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
13145 int ret_arith_lookup_val;
13147 if (NUMPTR == numstack) goto err; /* There is no operator that can work
13148 without arguments */
13149 numptr_m1 = NUMPTR - 1;
13151 /* check operand is var with noninteger value */
13152 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13153 if(ret_arith_lookup_val)
13154 return ret_arith_lookup_val;
13156 rez = numptr_m1->val;
13157 if (op == TOK_UMINUS)
13159 else if (op == TOK_NOT)
13161 else if (op == TOK_BNOT)
13163 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
13165 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
13167 else if (op != TOK_UPLUS) {
13168 /* Binary operators */
13170 /* check and binary operators need two arguments */
13171 if (numptr_m1 == numstack) goto err;
13173 /* ... and they pop one */
13176 if (op == TOK_CONDITIONAL) {
13177 if(! numptr_m1->contidional_second_val_initialized) {
13178 /* protect $((expr1 ? expr2)) without ": expr" */
13181 rez = numptr_m1->contidional_second_val;
13182 } else if(numptr_m1->contidional_second_val_initialized) {
13183 /* protect $((expr1 : expr2)) without "expr ? " */
13186 numptr_m1 = NUMPTR - 1;
13187 if(op != TOK_ASSIGN) {
13188 /* check operand is var with noninteger value for not '=' */
13189 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13190 if(ret_arith_lookup_val)
13191 return ret_arith_lookup_val;
13193 if (op == TOK_CONDITIONAL) {
13194 numptr_m1->contidional_second_val = rez;
13196 rez = numptr_m1->val;
13197 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
13199 else if (op == TOK_OR)
13200 rez = numptr_val || rez;
13201 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
13203 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
13205 else if (op == TOK_AND)
13206 rez = rez && numptr_val;
13207 else if (op == TOK_EQ)
13208 rez = (rez == numptr_val);
13209 else if (op == TOK_NE)
13210 rez = (rez != numptr_val);
13211 else if (op == TOK_GE)
13212 rez = (rez >= numptr_val);
13213 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
13214 rez >>= numptr_val;
13215 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
13216 rez <<= numptr_val;
13217 else if (op == TOK_GT)
13218 rez = (rez > numptr_val);
13219 else if (op == TOK_LT)
13220 rez = (rez < numptr_val);
13221 else if (op == TOK_LE)
13222 rez = (rez <= numptr_val);
13223 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
13225 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
13227 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
13229 else if (op == TOK_ASSIGN || op == TOK_COMMA)
13231 else if (op == TOK_CONDITIONAL_SEP) {
13232 if (numptr_m1 == numstack) {
13233 /* protect $((expr : expr)) without "expr ? " */
13236 numptr_m1->contidional_second_val_initialized = op;
13237 numptr_m1->contidional_second_val = numptr_val;
13239 else if (op == TOK_CONDITIONAL) {
13241 numptr_val : numptr_m1->contidional_second_val;
13243 else if(op == TOK_EXPONENT) {
13245 return -3; /* exponent less than 0 */
13250 while(numptr_val--)
13255 else if(numptr_val==0) /* zero divisor check */
13257 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
13259 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
13262 if(tok_have_assign(op)) {
13265 if(numptr_m1->var == NULL) {
13269 /* save to shell variable */
13270 sprintf(buf, "%ld", rez);
13271 setvar(numptr_m1->var, buf, 0);
13272 /* after saving, make previous value for v++ or v-- */
13273 if(op == TOK_POST_INC)
13275 else if(op == TOK_POST_DEC)
13278 numptr_m1->val = rez;
13279 /* protect geting var value, is number now */
13280 numptr_m1->var = NULL;
13285 /* longest must first */
13286 static const char op_tokens[] = {
13287 '<','<','=',0, TOK_LSHIFT_ASSIGN,
13288 '>','>','=',0, TOK_RSHIFT_ASSIGN,
13289 '<','<', 0, TOK_LSHIFT,
13290 '>','>', 0, TOK_RSHIFT,
13291 '|','|', 0, TOK_OR,
13292 '&','&', 0, TOK_AND,
13293 '!','=', 0, TOK_NE,
13294 '<','=', 0, TOK_LE,
13295 '>','=', 0, TOK_GE,
13296 '=','=', 0, TOK_EQ,
13297 '|','=', 0, TOK_OR_ASSIGN,
13298 '&','=', 0, TOK_AND_ASSIGN,
13299 '*','=', 0, TOK_MUL_ASSIGN,
13300 '/','=', 0, TOK_DIV_ASSIGN,
13301 '%','=', 0, TOK_REM_ASSIGN,
13302 '+','=', 0, TOK_PLUS_ASSIGN,
13303 '-','=', 0, TOK_MINUS_ASSIGN,
13304 '-','-', 0, TOK_POST_DEC,
13305 '^','=', 0, TOK_XOR_ASSIGN,
13306 '+','+', 0, TOK_POST_INC,
13307 '*','*', 0, TOK_EXPONENT,
13311 '=', 0, TOK_ASSIGN,
13323 '?', 0, TOK_CONDITIONAL,
13324 ':', 0, TOK_CONDITIONAL_SEP,
13325 ')', 0, TOK_RPAREN,
13326 '(', 0, TOK_LPAREN,
13330 #define endexpression &op_tokens[sizeof(op_tokens)-7]
13333 extern long arith (const char *expr, int *perrcode)
13335 register char arithval; /* Current character under analysis */
13336 operator lasttok, op;
13339 const char *p = endexpression;
13342 size_t datasizes = strlen(expr) + 2;
13344 /* Stack of integers */
13345 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
13346 * in any given correct or incorrect expression is left as an excersize to
13348 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
13349 *numstackptr = numstack;
13350 /* Stack of operator tokens */
13351 operator *stack = alloca((datasizes) * sizeof(operator)),
13354 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
13355 *perrcode = errcode = 0;
13358 if ((arithval = *expr) == 0) {
13359 if (p == endexpression) {
13360 /* Null expression. */
13364 /* This is only reached after all tokens have been extracted from the
13365 * input stream. If there are still tokens on the operator stack, they
13366 * are to be applied in order. At the end, there should be a final
13367 * result on the integer stack */
13369 if (expr != endexpression + 1) {
13370 /* If we haven't done so already, */
13371 /* append a closing right paren */
13372 expr = endexpression;
13373 /* and let the loop process it. */
13376 /* At this point, we're done with the expression. */
13377 if (numstackptr != numstack+1) {
13378 /* ... but if there isn't, it's bad */
13380 return (*perrcode = -1);
13382 if(numstack->var) {
13383 /* expression is $((var)) only, lookup now */
13384 errcode = arith_lookup_val(numstack);
13387 *perrcode = errcode;
13388 return numstack->val;
13390 /* Continue processing the expression. */
13391 if (arith_isspace(arithval)) {
13392 /* Skip whitespace */
13395 if((p = endofname(expr)) != expr) {
13396 int var_name_size = (p-expr) + 1; /* trailing zero */
13398 numstackptr->var = alloca(var_name_size);
13399 safe_strncpy(numstackptr->var, expr, var_name_size);
13402 numstackptr->contidional_second_val_initialized = 0;
13406 } else if (is_digit(arithval)) {
13407 numstackptr->var = NULL;
13408 numstackptr->val = strtol(expr, (char **) &expr, 0);
13411 for(p = op_tokens; ; p++) {
13415 /* strange operator not found */
13418 for(o = expr; *p && *o == *p; p++)
13425 /* skip tail uncompared token */
13428 /* skip zero delim */
13433 /* post grammar: a++ reduce to num */
13434 if(lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13437 /* Plus and minus are binary (not unary) _only_ if the last
13438 * token was as number, or a right paren (which pretends to be
13439 * a number, since it evaluates to one). Think about it.
13440 * It makes sense. */
13441 if (lasttok != TOK_NUM) {
13457 /* We don't want a unary operator to cause recursive descent on the
13458 * stack, because there can be many in a row and it could cause an
13459 * operator to be evaluated before its argument is pushed onto the
13460 * integer stack. */
13461 /* But for binary operators, "apply" everything on the operator
13462 * stack until we find an operator with a lesser priority than the
13463 * one we have just extracted. */
13464 /* Left paren is given the lowest priority so it will never be
13465 * "applied" in this way.
13466 * if associativity is right and priority eq, applied also skip
13469 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13470 /* not left paren or unary */
13471 if (lasttok != TOK_NUM) {
13472 /* binary op must be preceded by a num */
13475 while (stackptr != stack) {
13476 if (op == TOK_RPAREN) {
13477 /* The algorithm employed here is simple: while we don't
13478 * hit an open paren nor the bottom of the stack, pop
13479 * tokens and apply them */
13480 if (stackptr[-1] == TOK_LPAREN) {
13482 /* Any operator directly after a */
13484 /* close paren should consider itself binary */
13488 operator prev_prec = PREC(stackptr[-1]);
13490 convert_prec_is_assing(prec);
13491 convert_prec_is_assing(prev_prec);
13492 if (prev_prec < prec)
13494 /* check right assoc */
13495 if(prev_prec == prec && is_right_associativity(prec))
13498 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13499 if(errcode) goto ret;
13501 if (op == TOK_RPAREN) {
13506 /* Push this operator to the stack and remember it. */
13507 *stackptr++ = lasttok = op;
13514 #endif /* CONFIG_ASH_MATH_SUPPORT */
13518 const char *bb_applet_name = "debug stuff usage";
13519 int main(int argc, char **argv)
13521 return ash_main(argc, argv);
13526 * Copyright (c) 1989, 1991, 1993, 1994
13527 * The Regents of the University of California. All rights reserved.
13529 * This code is derived from software contributed to Berkeley by
13530 * Kenneth Almquist.
13532 * Redistribution and use in source and binary forms, with or without
13533 * modification, are permitted provided that the following conditions
13535 * 1. Redistributions of source code must retain the above copyright
13536 * notice, this list of conditions and the following disclaimer.
13537 * 2. Redistributions in binary form must reproduce the above copyright
13538 * notice, this list of conditions and the following disclaimer in the
13539 * documentation and/or other materials provided with the distribution.
13541 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
13542 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
13544 * 4. Neither the name of the University nor the names of its contributors
13545 * may be used to endorse or promote products derived from this software
13546 * without specific prior written permission.
13548 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13549 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13550 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13551 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13552 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13553 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13554 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13555 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13556 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13557 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF