1 /* vi: set sw=4 ts=4: */
3 * ash shell port for busybox
5 * Copyright (c) 1989, 1991, 1993, 1994
6 * The Regents of the University of California. All rights reserved.
8 * Copyright (c) 1997-2003 Herbert Xu <herbert@debian.org>
9 * was re-ported from NetBSD and debianized.
12 * This code is derived from software contributed to Berkeley by
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 * Original BSD copyright notice is retained at the end of this file.
33 * rewrite arith.y to micro stack based cryptic algorithm by
34 * Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
36 * Modified by Paul Mundt <lethal@linux-sh.org> (c) 2004 to support
39 * Modified by Vladimir Oleynik <dzo@simtreas.ru> (c) 2001-2004 to be
40 * used in busybox and size optimizations,
41 * rewrote arith (see notes to this), added locale support,
42 * rewrote dynamic variables.
48 * The follow should be set to reflect the type of system you have:
49 * JOBS -> 1 if you have Berkeley job control, 0 otherwise.
50 * define SYSV if you are running under System V.
51 * define DEBUG=1 to compile in debugging ('set -o debug' to turn on)
52 * define DEBUG=2 to compile in and turn on debugging.
54 * When debugging is on, debugging info will be written to ./trace and
55 * a quit signal will generate a core dump.
68 #include <sys/types.h>
69 #include <sys/cdefs.h>
70 #include <sys/ioctl.h>
71 #include <sys/param.h>
72 #include <sys/resource.h>
102 #ifdef CONFIG_ASH_JOB_CONTROL
116 static int *dash_errno;
118 #define errno (*dash_errno)
121 #if defined(__uClinux__)
122 #error "Do not even bother, ash will not run on uClinux"
126 #define _DIAGASSERT(assert_expr) assert(assert_expr)
128 #define _DIAGASSERT(assert_expr)
132 #ifdef CONFIG_ASH_ALIAS
133 /* $NetBSD: alias.h,v 1.5 2002/11/24 22:35:38 christos Exp $ */
145 static struct alias *lookupalias(const char *, int);
146 static int aliascmd(int, char **);
147 static int unaliascmd(int, char **);
148 static void rmaliases(void);
149 static int unalias(const char *);
150 static void printalias(const struct alias *);
153 /* $NetBSD: cd.h,v 1.3 2002/11/24 22:35:39 christos Exp $ */
156 static void setpwd(const char *, int);
158 /* $NetBSD: error.h,v 1.15 2002/11/24 22:35:39 christos Exp $ */
162 * Types of operations (passed to the errmsg routine).
166 static const char not_found_msg[] = "%s: not found";
169 #define E_OPEN "No such file" /* opening a file */
170 #define E_CREAT "Directory nonexistent" /* creating a file */
171 #define E_EXEC not_found_msg+4 /* executing a program */
174 * We enclose jmp_buf in a structure so that we can declare pointers to
175 * jump locations. The global variable handler contains the location to
176 * jump to when an exception occurs, and the global variable exception
177 * contains a code identifying the exception. To implement nested
178 * exception handlers, the user should save the value of handler on entry
179 * to an inner scope, set handler to point to a jmploc structure for the
180 * inner scope, and restore handler on exit from the scope.
187 static struct jmploc *handler;
188 static int exception;
189 static volatile int suppressint;
190 static volatile sig_atomic_t intpending;
192 static int exerrno; /* Last exec error, error for EXEXEC */
195 #define EXINT 0 /* SIGINT received */
196 #define EXERROR 1 /* a generic error */
197 #define EXSHELLPROC 2 /* execute a shell procedure */
198 #define EXEXEC 3 /* command execution failed */
199 #define EXEXIT 4 /* exit the shell */
200 #define EXSIG 5 /* trapped signal in wait(1) */
203 /* do we generate EXSIG events */
205 /* last pending signal */
206 static volatile sig_atomic_t pendingsigs;
209 * These macros allow the user to suspend the handling of interrupt signals
210 * over a period of time. This is similar to SIGHOLD to or sigblock, but
211 * much more efficient and portable. (But hacking the kernel is so much
212 * more fun than worrying about efficiency and portability. :-))
215 #define xbarrier() ({ __asm__ __volatile__ ("": : :"memory"); })
222 #define SAVEINT(v) ((v) = suppressint)
223 #define RESTOREINT(v) \
226 if ((suppressint = (v)) == 0 && intpending) onint(); \
237 /* EXSIG is turned off by evalbltin(). */
240 static void exraise(int) __attribute__((__noreturn__));
241 static void onint(void) __attribute__((__noreturn__));
243 static void error(const char *, ...) __attribute__((__noreturn__));
244 static void exerror(int, const char *, ...) __attribute__((__noreturn__));
246 static void sh_warnx(const char *, ...);
248 #ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
251 if (--suppressint == 0 && intpending) {
255 #define INTON inton()
256 static void forceinton(void)
262 #define FORCEINTON forceinton()
267 if (--suppressint == 0 && intpending) onint(); \
274 if (intpending) onint(); \
277 #endif /* CONFIG_ASH_OPTIMIZE_FOR_SIZE */
280 * BSD setjmp saves the signal mask, which violates ANSI C and takes time,
281 * so we use _setjmp instead.
284 #if defined(BSD) && !defined(__SVR4) && !defined(__GLIBC__)
285 #define setjmp(jmploc) _setjmp(jmploc)
286 #define longjmp(jmploc, val) _longjmp(jmploc, val)
289 /* $NetBSD: expand.h,v 1.13 2002/11/24 22:35:40 christos Exp $ */
292 struct strlist *next;
298 struct strlist *list;
299 struct strlist **lastp;
305 #define EXP_FULL 0x1 /* perform word splitting & file globbing */
306 #define EXP_TILDE 0x2 /* do normal tilde expansion */
307 #define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
308 #define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
309 #define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
310 #define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
311 #define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
312 #define EXP_WORD 0x80 /* expand word in parameter expansion */
313 #define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */
317 static void expandarg(union node *, struct arglist *, int);
318 #define rmescapes(p) _rmescapes((p), 0)
319 static char *_rmescapes(char *, int);
320 static int casematch(union node *, char *);
322 #ifdef CONFIG_ASH_MATH_SUPPORT
323 static void expari(int);
326 /* $NetBSD: eval.h,v 1.13 2002/11/24 22:35:39 christos Exp $ */
328 static char *commandname; /* currently executing command */
329 static struct strlist *cmdenviron; /* environment for builtin command */
330 static int exitstatus; /* exit status of last command */
331 static int back_exitstatus; /* exit status of backquoted command */
334 struct backcmd { /* result of evalbackcmd */
335 int fd; /* file descriptor to read from */
336 char *buf; /* buffer */
337 int nleft; /* number of chars in buffer */
338 struct job *jp; /* job structure for command */
342 * This file was generated by the mknodes program.
378 union node *redirect;
385 struct nodelist *cmdlist;
392 union node *redirect;
407 union node *elsepart;
438 struct nodelist *backquote;
478 struct nredir nredir;
479 struct nbinary nbinary;
483 struct nclist nclist;
493 struct nodelist *next;
504 static void freefunc(struct funcnode *);
505 /* $NetBSD: parser.h,v 1.15 2002/11/24 22:35:42 christos Exp $ */
507 /* control characters in argument strings */
508 #define CTL_FIRST '\201' /* first 'special' character */
509 #define CTLESC '\201' /* escape next character */
510 #define CTLVAR '\202' /* variable defn */
511 #define CTLENDVAR '\203'
512 #define CTLBACKQ '\204'
513 #define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
514 /* CTLBACKQ | CTLQUOTE == '\205' */
515 #define CTLARI '\206' /* arithmetic expression */
516 #define CTLENDARI '\207'
517 #define CTLQUOTEMARK '\210'
518 #define CTL_LAST '\210' /* last 'special' character */
520 /* variable substitution byte (follows CTLVAR) */
521 #define VSTYPE 0x0f /* type of variable substitution */
522 #define VSNUL 0x10 /* colon--treat the empty string as unset */
523 #define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
525 /* values of VSTYPE field */
526 #define VSNORMAL 0x1 /* normal variable: $var or ${var} */
527 #define VSMINUS 0x2 /* ${var-text} */
528 #define VSPLUS 0x3 /* ${var+text} */
529 #define VSQUESTION 0x4 /* ${var?message} */
530 #define VSASSIGN 0x5 /* ${var=text} */
531 #define VSTRIMRIGHT 0x6 /* ${var%pattern} */
532 #define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
533 #define VSTRIMLEFT 0x8 /* ${var#pattern} */
534 #define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
535 #define VSLENGTH 0xa /* ${#var} */
537 /* values of checkkwd variable */
542 #define IBUFSIZ (BUFSIZ + 1)
545 * NEOF is returned by parsecmd when it encounters an end of file. It
546 * must be distinct from NULL, so we use the address of a variable that
547 * happens to be handy.
549 static int plinno = 1; /* input line number */
551 /* number of characters left in input buffer */
552 static int parsenleft; /* copy of parsefile->nleft */
553 static int parselleft; /* copy of parsefile->lleft */
555 /* next character in input buffer */
556 static char *parsenextc; /* copy of parsefile->nextc */
559 struct strpush *prev; /* preceding string on stack */
562 #ifdef CONFIG_ASH_ALIAS
563 struct alias *ap; /* if push was associated with an alias */
565 char *string; /* remember the string since it may change */
569 struct parsefile *prev; /* preceding file on stack */
570 int linno; /* current line */
571 int fd; /* file descriptor (or -1 if string) */
572 int nleft; /* number of chars left in this line */
573 int lleft; /* number of chars left in this buffer */
574 char *nextc; /* next char in buffer */
575 char *buf; /* input buffer */
576 struct strpush *strpush; /* for pushing strings at this level */
577 struct strpush basestrpush; /* so pushing one is fast */
580 static struct parsefile basepf; /* top level input file */
581 static char basebuf[IBUFSIZ]; /* buffer for top level input file */
582 static struct parsefile *parsefile = &basepf; /* current input file */
585 static int tokpushback; /* last token pushed back */
586 #define NEOF ((union node *)&tokpushback)
587 static int parsebackquote; /* nonzero if we are inside backquotes */
588 static int doprompt; /* if set, prompt the user */
589 static int needprompt; /* true if interactive and at start of line */
590 static int lasttoken; /* last token read */
591 static char *wordtext; /* text of last word returned by readtoken */
593 static struct nodelist *backquotelist;
594 static union node *redirnode;
595 static struct heredoc *heredoc;
596 static int quoteflag; /* set if (part of) last token was quoted */
597 static int startlinno; /* line # where last token started */
599 static union node *parsecmd(int);
600 static void fixredir(union node *, const char *, int);
601 static const char *const *findkwd(const char *);
602 static char *endofname(const char *);
604 /* $NetBSD: shell.h,v 1.16 2003/01/22 20:36:04 dsl Exp $ */
606 typedef void *pointer;
608 static char nullstr[1]; /* zero length string */
609 static const char spcstr[] = " ";
610 static const char snlfmt[] = "%s\n";
611 static const char dolatstr[] = { CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' };
612 static const char illnum[] = "Illegal number: %s";
613 static const char homestr[] = "HOME";
616 #define TRACE(param) trace param
617 #define TRACEV(param) tracev param
620 #define TRACEV(param)
623 #if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
624 #define __builtin_expect(x, expected_value) (x)
627 #define xlikely(x) __builtin_expect((x),1)
642 #define TENDBQUOTE 12
660 /* first char is indicating which tokens mark the end of a list */
661 static const char *const tokname_array[] = {
676 /* the following are keywords */
695 static const char *tokname(int tok)
701 sprintf(buf + (tok >= TSEMI), "%s%c",
702 tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));
706 /* $NetBSD: machdep.h,v 1.10 2002/10/07 14:26:08 christos Exp $ */
709 * Most machines require the value returned from malloc to be aligned
710 * in some way. The following macro will get this right on many machines.
713 #define SHELL_SIZE (sizeof(union {int i; char *cp; double d; }) - 1)
715 * It appears that grabstackstr() will barf with such alignments
716 * because stalloc() will return a string allocated in a new stackblock.
718 #define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
721 * This file was generated by the mksyntax program.
726 #define CWORD 0 /* character is nothing special */
727 #define CNL 1 /* newline character */
728 #define CBACK 2 /* a backslash character */
729 #define CSQUOTE 3 /* single quote */
730 #define CDQUOTE 4 /* double quote */
731 #define CENDQUOTE 5 /* a terminating quote */
732 #define CBQUOTE 6 /* backwards single quote */
733 #define CVAR 7 /* a dollar sign */
734 #define CENDVAR 8 /* a '}' character */
735 #define CLP 9 /* a left paren in arithmetic */
736 #define CRP 10 /* a right paren in arithmetic */
737 #define CENDFILE 11 /* end of file */
738 #define CCTL 12 /* like CWORD, except it must be escaped */
739 #define CSPCL 13 /* these terminate a word */
740 #define CIGN 14 /* character should be ignored */
742 #ifdef CONFIG_ASH_ALIAS
746 #define PEOA_OR_PEOF PEOA
750 #define PEOA_OR_PEOF PEOF
753 #define is_digit(c) ((unsigned)((c) - '0') <= 9)
754 #define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
755 #define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
758 * is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
759 * (assuming ascii char codes, as the original implementation did)
761 #define is_special(c) \
762 ( (((unsigned int)c) - 33 < 32) \
763 && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
765 #define digit_val(c) ((c) - '0')
768 * This file was generated by the mksyntax program.
771 #ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
772 #define USE_SIT_FUNCTION
775 /* number syntax index */
776 #define BASESYNTAX 0 /* not in quotes */
777 #define DQSYNTAX 1 /* in double quotes */
778 #define SQSYNTAX 2 /* in single quotes */
779 #define ARISYNTAX 3 /* in arithmetic */
781 #ifdef CONFIG_ASH_MATH_SUPPORT
782 static const char S_I_T[][4] = {
783 #ifdef CONFIG_ASH_ALIAS
784 {CSPCL, CIGN, CIGN, CIGN}, /* 0, PEOA */
786 {CSPCL, CWORD, CWORD, CWORD}, /* 1, ' ' */
787 {CNL, CNL, CNL, CNL}, /* 2, \n */
788 {CWORD, CCTL, CCTL, CWORD}, /* 3, !*-/:=?[]~ */
789 {CDQUOTE, CENDQUOTE, CWORD, CWORD}, /* 4, '"' */
790 {CVAR, CVAR, CWORD, CVAR}, /* 5, $ */
791 {CSQUOTE, CWORD, CENDQUOTE, CWORD}, /* 6, "'" */
792 {CSPCL, CWORD, CWORD, CLP}, /* 7, ( */
793 {CSPCL, CWORD, CWORD, CRP}, /* 8, ) */
794 {CBACK, CBACK, CCTL, CBACK}, /* 9, \ */
795 {CBQUOTE, CBQUOTE, CWORD, CBQUOTE}, /* 10, ` */
796 {CENDVAR, CENDVAR, CWORD, CENDVAR}, /* 11, } */
797 #ifndef USE_SIT_FUNCTION
798 {CENDFILE, CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */
799 {CWORD, CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */
800 {CCTL, CCTL, CCTL, CCTL} /* 14, CTLESC ... */
804 static const char S_I_T[][3] = {
805 #ifdef CONFIG_ASH_ALIAS
806 {CSPCL, CIGN, CIGN}, /* 0, PEOA */
808 {CSPCL, CWORD, CWORD}, /* 1, ' ' */
809 {CNL, CNL, CNL}, /* 2, \n */
810 {CWORD, CCTL, CCTL}, /* 3, !*-/:=?[]~ */
811 {CDQUOTE, CENDQUOTE, CWORD}, /* 4, '"' */
812 {CVAR, CVAR, CWORD}, /* 5, $ */
813 {CSQUOTE, CWORD, CENDQUOTE}, /* 6, "'" */
814 {CSPCL, CWORD, CWORD}, /* 7, ( */
815 {CSPCL, CWORD, CWORD}, /* 8, ) */
816 {CBACK, CBACK, CCTL}, /* 9, \ */
817 {CBQUOTE, CBQUOTE, CWORD}, /* 10, ` */
818 {CENDVAR, CENDVAR, CWORD}, /* 11, } */
819 #ifndef USE_SIT_FUNCTION
820 {CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */
821 {CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */
822 {CCTL, CCTL, CCTL} /* 14, CTLESC ... */
825 #endif /* CONFIG_ASH_MATH_SUPPORT */
827 #ifdef USE_SIT_FUNCTION
829 #define U_C(c) ((unsigned char)(c))
831 static int SIT(int c, int syntax)
833 static const char spec_symbls[] = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
834 #ifdef CONFIG_ASH_ALIAS
835 static const char syntax_index_table[] = {
836 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
837 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
838 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
842 static const char syntax_index_table[] = {
843 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
844 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */
845 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
852 if (c == PEOF) /* 2^8+2 */
854 #ifdef CONFIG_ASH_ALIAS
855 if (c == PEOA) /* 2^8+1 */
859 if (U_C(c) >= U_C(CTLESC) && U_C(c) <= U_C(CTLQUOTEMARK))
862 s = strchr(spec_symbls, c);
863 if (s == 0 || *s == 0)
865 indx = syntax_index_table[(s - spec_symbls)];
867 return S_I_T[indx][syntax];
870 #else /* USE_SIT_FUNCTION */
872 #define SIT(c, syntax) S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax]
874 #ifdef CONFIG_ASH_ALIAS
875 #define CSPCL_CIGN_CIGN_CIGN 0
876 #define CSPCL_CWORD_CWORD_CWORD 1
877 #define CNL_CNL_CNL_CNL 2
878 #define CWORD_CCTL_CCTL_CWORD 3
879 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 4
880 #define CVAR_CVAR_CWORD_CVAR 5
881 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 6
882 #define CSPCL_CWORD_CWORD_CLP 7
883 #define CSPCL_CWORD_CWORD_CRP 8
884 #define CBACK_CBACK_CCTL_CBACK 9
885 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10
886 #define CENDVAR_CENDVAR_CWORD_CENDVAR 11
887 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
888 #define CWORD_CWORD_CWORD_CWORD 13
889 #define CCTL_CCTL_CCTL_CCTL 14
891 #define CSPCL_CWORD_CWORD_CWORD 0
892 #define CNL_CNL_CNL_CNL 1
893 #define CWORD_CCTL_CCTL_CWORD 2
894 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 3
895 #define CVAR_CVAR_CWORD_CVAR 4
896 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 5
897 #define CSPCL_CWORD_CWORD_CLP 6
898 #define CSPCL_CWORD_CWORD_CRP 7
899 #define CBACK_CBACK_CCTL_CBACK 8
900 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 9
901 #define CENDVAR_CENDVAR_CWORD_CENDVAR 10
902 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 11
903 #define CWORD_CWORD_CWORD_CWORD 12
904 #define CCTL_CCTL_CCTL_CCTL 13
907 static const char syntax_index_table[258] = {
908 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
909 /* 0 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
910 #ifdef CONFIG_ASH_ALIAS
911 /* 1 PEOA */ CSPCL_CIGN_CIGN_CIGN,
913 /* 2 -128 0x80 */ CWORD_CWORD_CWORD_CWORD,
914 /* 3 -127 CTLESC */ CCTL_CCTL_CCTL_CCTL,
915 /* 4 -126 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
916 /* 5 -125 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
917 /* 6 -124 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
918 /* 7 -123 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
919 /* 8 -122 CTLARI */ CCTL_CCTL_CCTL_CCTL,
920 /* 9 -121 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
921 /* 10 -120 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
922 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD,
923 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD,
924 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD,
925 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD,
926 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD,
927 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD,
928 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD,
929 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD,
930 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,
931 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD,
932 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD,
933 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD,
934 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD,
935 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD,
936 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD,
937 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD,
938 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD,
939 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD,
940 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,
941 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD,
942 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD,
943 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD,
944 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD,
945 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD,
946 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD,
947 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD,
948 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD,
949 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,
950 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,
951 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD,
952 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD,
953 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD,
954 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD,
955 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD,
956 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD,
957 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD,
958 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD,
959 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD,
960 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD,
961 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD,
962 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD,
963 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD,
964 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD,
965 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD,
966 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD,
967 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD,
968 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD,
969 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,
970 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,
971 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD,
972 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD,
973 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD,
974 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD,
975 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD,
976 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD,
977 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD,
978 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD,
979 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD,
980 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD,
981 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD,
982 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD,
983 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD,
984 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD,
985 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD,
986 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD,
987 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD,
988 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD,
989 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD,
990 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD,
991 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD,
992 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD,
993 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD,
994 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD,
995 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD,
996 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD,
997 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD,
998 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD,
999 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD,
1000 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,
1001 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD,
1002 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD,
1003 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD,
1004 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD,
1005 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD,
1006 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD,
1007 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD,
1008 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD,
1009 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD,
1010 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD,
1011 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD,
1012 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD,
1013 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD,
1014 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD,
1015 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD,
1016 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD,
1017 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD,
1018 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD,
1019 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD,
1020 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD,
1021 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD,
1022 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD,
1023 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD,
1024 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD,
1025 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD,
1026 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD,
1027 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD,
1028 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD,
1029 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD,
1030 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD,
1031 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD,
1032 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD,
1033 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD,
1034 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD,
1035 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD,
1036 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD,
1037 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD,
1038 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD,
1039 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD,
1040 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD,
1041 /* 130 0 */ CWORD_CWORD_CWORD_CWORD,
1042 /* 131 1 */ CWORD_CWORD_CWORD_CWORD,
1043 /* 132 2 */ CWORD_CWORD_CWORD_CWORD,
1044 /* 133 3 */ CWORD_CWORD_CWORD_CWORD,
1045 /* 134 4 */ CWORD_CWORD_CWORD_CWORD,
1046 /* 135 5 */ CWORD_CWORD_CWORD_CWORD,
1047 /* 136 6 */ CWORD_CWORD_CWORD_CWORD,
1048 /* 137 7 */ CWORD_CWORD_CWORD_CWORD,
1049 /* 138 8 */ CWORD_CWORD_CWORD_CWORD,
1050 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
1051 /* 140 10 "\n" */ CNL_CNL_CNL_CNL,
1052 /* 141 11 */ CWORD_CWORD_CWORD_CWORD,
1053 /* 142 12 */ CWORD_CWORD_CWORD_CWORD,
1054 /* 143 13 */ CWORD_CWORD_CWORD_CWORD,
1055 /* 144 14 */ CWORD_CWORD_CWORD_CWORD,
1056 /* 145 15 */ CWORD_CWORD_CWORD_CWORD,
1057 /* 146 16 */ CWORD_CWORD_CWORD_CWORD,
1058 /* 147 17 */ CWORD_CWORD_CWORD_CWORD,
1059 /* 148 18 */ CWORD_CWORD_CWORD_CWORD,
1060 /* 149 19 */ CWORD_CWORD_CWORD_CWORD,
1061 /* 150 20 */ CWORD_CWORD_CWORD_CWORD,
1062 /* 151 21 */ CWORD_CWORD_CWORD_CWORD,
1063 /* 152 22 */ CWORD_CWORD_CWORD_CWORD,
1064 /* 153 23 */ CWORD_CWORD_CWORD_CWORD,
1065 /* 154 24 */ CWORD_CWORD_CWORD_CWORD,
1066 /* 155 25 */ CWORD_CWORD_CWORD_CWORD,
1067 /* 156 26 */ CWORD_CWORD_CWORD_CWORD,
1068 /* 157 27 */ CWORD_CWORD_CWORD_CWORD,
1069 /* 158 28 */ CWORD_CWORD_CWORD_CWORD,
1070 /* 159 29 */ CWORD_CWORD_CWORD_CWORD,
1071 /* 160 30 */ CWORD_CWORD_CWORD_CWORD,
1072 /* 161 31 */ CWORD_CWORD_CWORD_CWORD,
1073 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD,
1074 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD,
1075 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
1076 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD,
1077 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR,
1078 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD,
1079 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
1080 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
1081 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP,
1082 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP,
1083 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD,
1084 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD,
1085 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD,
1086 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD,
1087 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD,
1088 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD,
1089 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD,
1090 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD,
1091 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD,
1092 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD,
1093 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD,
1094 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD,
1095 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD,
1096 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD,
1097 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD,
1098 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD,
1099 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD,
1100 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
1101 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
1102 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD,
1103 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
1104 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD,
1105 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD,
1106 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD,
1107 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD,
1108 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD,
1109 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD,
1110 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD,
1111 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD,
1112 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD,
1113 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD,
1114 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD,
1115 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD,
1116 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD,
1117 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD,
1118 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD,
1119 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD,
1120 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD,
1121 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD,
1122 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
1123 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD,
1124 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD,
1125 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD,
1126 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD,
1127 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD,
1128 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD,
1129 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD,
1130 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
1131 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
1132 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD,
1133 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK,
1134 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD,
1135 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD,
1136 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD,
1137 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
1138 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD,
1139 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD,
1140 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD,
1141 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD,
1142 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD,
1143 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD,
1144 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD,
1145 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD,
1146 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD,
1147 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD,
1148 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD,
1149 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD,
1150 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD,
1151 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD,
1152 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD,
1153 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD,
1154 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD,
1155 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD,
1156 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD,
1157 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD,
1158 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD,
1159 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD,
1160 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD,
1161 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD,
1162 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD,
1163 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD,
1164 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD,
1165 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
1166 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
1167 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,
1168 /* 257 127 */ CWORD_CWORD_CWORD_CWORD,
1171 #endif /* USE_SIT_FUNCTION */
1173 /* $NetBSD: alias.c,v 1.11 2002/11/24 22:35:38 christos Exp $ */
1178 static int funcblocksize; /* size of structures in function */
1179 static int funcstringsize; /* size of strings in node */
1180 static pointer funcblock; /* block to allocate function from */
1181 static char *funcstring; /* block to allocate strings from */
1183 static const short nodesize[26] = {
1184 SHELL_ALIGN(sizeof (struct ncmd)),
1185 SHELL_ALIGN(sizeof (struct npipe)),
1186 SHELL_ALIGN(sizeof (struct nredir)),
1187 SHELL_ALIGN(sizeof (struct nredir)),
1188 SHELL_ALIGN(sizeof (struct nredir)),
1189 SHELL_ALIGN(sizeof (struct nbinary)),
1190 SHELL_ALIGN(sizeof (struct nbinary)),
1191 SHELL_ALIGN(sizeof (struct nbinary)),
1192 SHELL_ALIGN(sizeof (struct nif)),
1193 SHELL_ALIGN(sizeof (struct nbinary)),
1194 SHELL_ALIGN(sizeof (struct nbinary)),
1195 SHELL_ALIGN(sizeof (struct nfor)),
1196 SHELL_ALIGN(sizeof (struct ncase)),
1197 SHELL_ALIGN(sizeof (struct nclist)),
1198 SHELL_ALIGN(sizeof (struct narg)),
1199 SHELL_ALIGN(sizeof (struct narg)),
1200 SHELL_ALIGN(sizeof (struct nfile)),
1201 SHELL_ALIGN(sizeof (struct nfile)),
1202 SHELL_ALIGN(sizeof (struct nfile)),
1203 SHELL_ALIGN(sizeof (struct nfile)),
1204 SHELL_ALIGN(sizeof (struct nfile)),
1205 SHELL_ALIGN(sizeof (struct ndup)),
1206 SHELL_ALIGN(sizeof (struct ndup)),
1207 SHELL_ALIGN(sizeof (struct nhere)),
1208 SHELL_ALIGN(sizeof (struct nhere)),
1209 SHELL_ALIGN(sizeof (struct nnot)),
1213 static void calcsize(union node *);
1214 static void sizenodelist(struct nodelist *);
1215 static union node *copynode(union node *);
1216 static struct nodelist *copynodelist(struct nodelist *);
1217 static char *nodesavestr(char *);
1221 static void evalstring(char *);
1222 union node; /* BLETCH for ansi C */
1223 static void evaltree(union node *, int);
1224 static void evalbackcmd(union node *, struct backcmd *);
1226 /* in_function returns nonzero if we are currently evaluating a function */
1227 #define in_function() funcnest
1228 static int evalskip; /* set if we are skipping commands */
1229 static int skipcount; /* number of levels to skip */
1230 static int funcnest; /* depth of function calls */
1232 /* reasons for skipping commands (see comment on breakcmd routine) */
1239 * This file was generated by the mkbuiltins program.
1243 static int bgcmd(int, char **);
1245 static int breakcmd(int, char **);
1246 static int cdcmd(int, char **);
1247 #ifdef CONFIG_ASH_CMDCMD
1248 static int commandcmd(int, char **);
1250 static int dotcmd(int, char **);
1251 static int evalcmd(int, char **);
1252 static int execcmd(int, char **);
1253 static int exitcmd(int, char **);
1254 static int exportcmd(int, char **);
1255 static int falsecmd(int, char **);
1257 static int fgcmd(int, char **);
1259 #ifdef CONFIG_ASH_GETOPTS
1260 static int getoptscmd(int, char **);
1262 static int hashcmd(int, char **);
1263 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1264 static int helpcmd(int argc, char **argv);
1267 static int jobscmd(int, char **);
1269 #ifdef CONFIG_ASH_MATH_SUPPORT
1270 static int letcmd(int, char **);
1272 static int localcmd(int, char **);
1273 static int pwdcmd(int, char **);
1274 static int readcmd(int, char **);
1275 static int returncmd(int, char **);
1276 static int setcmd(int, char **);
1277 static int shiftcmd(int, char **);
1278 static int timescmd(int, char **);
1279 static int trapcmd(int, char **);
1280 static int truecmd(int, char **);
1281 static int typecmd(int, char **);
1282 static int umaskcmd(int, char **);
1283 static int unsetcmd(int, char **);
1284 static int waitcmd(int, char **);
1285 static int ulimitcmd(int, char **);
1287 static int killcmd(int, char **);
1290 /* $NetBSD: mail.h,v 1.9 2002/11/24 22:35:40 christos Exp $ */
1292 #ifdef CONFIG_ASH_MAIL
1293 static void chkmail(void);
1294 static void changemail(const char *);
1297 /* $NetBSD: exec.h,v 1.20 2003/01/22 20:36:04 dsl Exp $ */
1299 /* values of cmdtype */
1300 #define CMDUNKNOWN -1 /* no entry in table for command */
1301 #define CMDNORMAL 0 /* command is an executable program */
1302 #define CMDFUNCTION 1 /* command is a shell function */
1303 #define CMDBUILTIN 2 /* command is a shell builtin */
1307 int (*builtin)(int, char **);
1308 /* unsigned flags; */
1311 #ifdef CONFIG_ASH_CMDCMD
1313 # ifdef CONFIG_ASH_ALIAS
1314 # define COMMANDCMD (builtincmd + 7)
1315 # define EXECCMD (builtincmd + 10)
1317 # define COMMANDCMD (builtincmd + 6)
1318 # define EXECCMD (builtincmd + 9)
1321 # ifdef CONFIG_ASH_ALIAS
1322 # define COMMANDCMD (builtincmd + 6)
1323 # define EXECCMD (builtincmd + 9)
1325 # define COMMANDCMD (builtincmd + 5)
1326 # define EXECCMD (builtincmd + 8)
1329 #else /* ! CONFIG_ASH_CMDCMD */
1331 # ifdef CONFIG_ASH_ALIAS
1332 # define EXECCMD (builtincmd + 9)
1334 # define EXECCMD (builtincmd + 8)
1337 # ifdef CONFIG_ASH_ALIAS
1338 # define EXECCMD (builtincmd + 8)
1340 # define EXECCMD (builtincmd + 7)
1343 #endif /* CONFIG_ASH_CMDCMD */
1345 #define BUILTIN_NOSPEC "0"
1346 #define BUILTIN_SPECIAL "1"
1347 #define BUILTIN_REGULAR "2"
1348 #define BUILTIN_SPEC_REG "3"
1349 #define BUILTIN_ASSIGN "4"
1350 #define BUILTIN_SPEC_ASSG "5"
1351 #define BUILTIN_REG_ASSG "6"
1352 #define BUILTIN_SPEC_REG_ASSG "7"
1354 #define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1355 #define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
1357 static const struct builtincmd builtincmd[] = {
1358 { BUILTIN_SPEC_REG ".", dotcmd },
1359 { BUILTIN_SPEC_REG ":", truecmd },
1360 #ifdef CONFIG_ASH_ALIAS
1361 { BUILTIN_REG_ASSG "alias", aliascmd },
1364 { BUILTIN_REGULAR "bg", bgcmd },
1366 { BUILTIN_SPEC_REG "break", breakcmd },
1367 { BUILTIN_REGULAR "cd", cdcmd },
1368 { BUILTIN_NOSPEC "chdir", cdcmd },
1369 #ifdef CONFIG_ASH_CMDCMD
1370 { BUILTIN_REGULAR "command", commandcmd },
1372 { BUILTIN_SPEC_REG "continue", breakcmd },
1373 { BUILTIN_SPEC_REG "eval", evalcmd },
1374 { BUILTIN_SPEC_REG "exec", execcmd },
1375 { BUILTIN_SPEC_REG "exit", exitcmd },
1376 { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
1377 { BUILTIN_REGULAR "false", falsecmd },
1379 { BUILTIN_REGULAR "fg", fgcmd },
1381 #ifdef CONFIG_ASH_GETOPTS
1382 { BUILTIN_REGULAR "getopts", getoptscmd },
1384 { BUILTIN_NOSPEC "hash", hashcmd },
1385 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1386 { BUILTIN_NOSPEC "help", helpcmd },
1389 { BUILTIN_REGULAR "jobs", jobscmd },
1390 { BUILTIN_REGULAR "kill", killcmd },
1392 #ifdef CONFIG_ASH_MATH_SUPPORT
1393 { BUILTIN_NOSPEC "let", letcmd },
1395 { BUILTIN_ASSIGN "local", localcmd },
1396 { BUILTIN_NOSPEC "pwd", pwdcmd },
1397 { BUILTIN_REGULAR "read", readcmd },
1398 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
1399 { BUILTIN_SPEC_REG "return", returncmd },
1400 { BUILTIN_SPEC_REG "set", setcmd },
1401 { BUILTIN_SPEC_REG "shift", shiftcmd },
1402 { BUILTIN_SPEC_REG "times", timescmd },
1403 { BUILTIN_SPEC_REG "trap", trapcmd },
1404 { BUILTIN_REGULAR "true", truecmd },
1405 { BUILTIN_NOSPEC "type", typecmd },
1406 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
1407 { BUILTIN_REGULAR "umask", umaskcmd },
1408 #ifdef CONFIG_ASH_ALIAS
1409 { BUILTIN_REGULAR "unalias", unaliascmd },
1411 { BUILTIN_SPEC_REG "unset", unsetcmd },
1412 { BUILTIN_REGULAR "wait", waitcmd },
1415 #define NUMBUILTINS (sizeof (builtincmd) / sizeof (struct builtincmd) )
1423 const struct builtincmd *cmd;
1424 struct funcnode *func;
1429 /* action to find_command() */
1430 #define DO_ERR 0x01 /* prints errors */
1431 #define DO_ABS 0x02 /* checks absolute paths */
1432 #define DO_NOFUNC 0x04 /* don't return shell functions, for command */
1433 #define DO_ALTPATH 0x08 /* using alternate path */
1434 #define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
1436 static const char *pathopt; /* set by padvance */
1438 static void shellexec(char **, const char *, int)
1439 __attribute__((__noreturn__));
1440 static char *padvance(const char **, const char *);
1441 static void find_command(char *, struct cmdentry *, int, const char *);
1442 static struct builtincmd *find_builtin(const char *);
1443 static void hashcd(void);
1444 static void changepath(const char *);
1445 static void defun(char *, union node *);
1446 static void unsetfunc(const char *);
1448 #ifdef CONFIG_ASH_MATH_SUPPORT_64
1449 typedef int64_t arith_t;
1451 typedef long arith_t;
1454 #ifdef CONFIG_ASH_MATH_SUPPORT
1455 static arith_t dash_arith(const char *);
1456 static arith_t arith(const char *expr, int *perrcode);
1459 #ifdef CONFIG_ASH_RANDOM_SUPPORT
1460 static unsigned long rseed;
1461 static void change_random(const char *);
1462 # ifndef DYNAMIC_VAR
1463 # define DYNAMIC_VAR
1467 /* $NetBSD: init.h,v 1.9 2002/11/24 22:35:40 christos Exp $ */
1469 static void reset(void);
1471 /* $NetBSD: var.h,v 1.21 2003/01/22 20:36:04 dsl Exp $ */
1478 #define VEXPORT 0x01 /* variable is exported */
1479 #define VREADONLY 0x02 /* variable cannot be modified */
1480 #define VSTRFIXED 0x04 /* variable struct is statically allocated */
1481 #define VTEXTFIXED 0x08 /* text is statically allocated */
1482 #define VSTACK 0x10 /* text is allocated on the stack */
1483 #define VUNSET 0x20 /* the variable is not set */
1484 #define VNOFUNC 0x40 /* don't call the callback function */
1485 #define VNOSET 0x80 /* do not set variable - just readonly test */
1486 #define VNOSAVE 0x100 /* when text is on the heap before setvareq */
1488 # define VDYNAMIC 0x200 /* dynamic variable */
1494 struct var *next; /* next entry in hash list */
1495 int flags; /* flags are defined above */
1496 const char *text; /* name=value */
1497 void (*func)(const char *); /* function to be called when */
1498 /* the variable gets set/unset */
1502 struct localvar *next; /* next local variable in list */
1503 struct var *vp; /* the variable that was made local */
1504 int flags; /* saved flags */
1505 const char *text; /* saved text */
1509 static struct localvar *localvars;
1515 #ifdef CONFIG_ASH_GETOPTS
1516 static void getoptsreset(const char *);
1519 #ifdef CONFIG_LOCALE_SUPPORT
1521 static void change_lc_all(const char *value);
1522 static void change_lc_ctype(const char *value);
1528 static const char defpathvar[] = "PATH=/usr/local/bin:/usr/bin:/sbin:/bin";
1530 static const char defifsvar[] = "IFS= \t\n";
1531 #define defifs (defifsvar + 4)
1533 static const char defifs[] = " \t\n";
1537 static struct var varinit[] = {
1539 { 0, VSTRFIXED|VTEXTFIXED, defifsvar, 0 },
1541 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", 0 },
1544 #ifdef CONFIG_ASH_MAIL
1545 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail },
1546 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail },
1549 { 0, VSTRFIXED|VTEXTFIXED, defpathvar, changepath },
1550 { 0, VSTRFIXED|VTEXTFIXED, "PS1=$ ", 0 },
1551 { 0, VSTRFIXED|VTEXTFIXED, "PS2=> ", 0 },
1552 { 0, VSTRFIXED|VTEXTFIXED, "PS4=+ ", 0 },
1553 #ifdef CONFIG_ASH_GETOPTS
1554 { 0, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset },
1556 #ifdef CONFIG_ASH_RANDOM_SUPPORT
1557 {0, VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random },
1559 #ifdef CONFIG_LOCALE_SUPPORT
1560 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0", change_lc_all },
1561 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0", change_lc_ctype },
1563 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
1564 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0", NULL },
1568 #define vifs varinit[0]
1569 #ifdef CONFIG_ASH_MAIL
1570 #define vmail (&vifs)[1]
1571 #define vmpath (&vmail)[1]
1575 #define vpath (&vmpath)[1]
1576 #define vps1 (&vpath)[1]
1577 #define vps2 (&vps1)[1]
1578 #define vps4 (&vps2)[1]
1579 #define voptind (&vps4)[1]
1580 #ifdef CONFIG_ASH_GETOPTS
1581 #define vrandom (&voptind)[1]
1583 #define vrandom (&vps4)[1]
1585 #define defpath (defpathvar + 5)
1588 * The following macros access the values of the above variables.
1589 * They have to skip over the name. They return the null string
1590 * for unset variables.
1593 #define ifsval() (vifs.text + 4)
1594 #define ifsset() ((vifs.flags & VUNSET) == 0)
1595 #define mailval() (vmail.text + 5)
1596 #define mpathval() (vmpath.text + 9)
1597 #define pathval() (vpath.text + 5)
1598 #define ps1val() (vps1.text + 4)
1599 #define ps2val() (vps2.text + 4)
1600 #define ps4val() (vps4.text + 4)
1601 #define optindval() (voptind.text + 7)
1603 #define mpathset() ((vmpath.flags & VUNSET) == 0)
1605 static void setvar(const char *, const char *, int);
1606 static void setvareq(char *, int);
1607 static void listsetvar(struct strlist *, int);
1608 static char *lookupvar(const char *);
1609 static char *bltinlookup(const char *);
1610 static char **listvars(int, int, char ***);
1611 #define environment() listvars(VEXPORT, VUNSET, 0)
1612 static int showvars(const char *, int, int);
1613 static void poplocalvars(void);
1614 static int unsetvar(const char *);
1615 #ifdef CONFIG_ASH_GETOPTS
1616 static int setvarsafe(const char *, const char *, int);
1618 static int varcmp(const char *, const char *);
1619 static struct var **hashvar(const char *);
1622 static inline int varequal(const char *a, const char *b) {
1623 return !varcmp(a, b);
1627 static int loopnest; /* current loop nesting level */
1630 * The parsefile structure pointed to by the global variable parsefile
1631 * contains information about the current file being read.
1636 struct redirtab *next;
1641 static struct redirtab *redirlist;
1642 static int nullredirs;
1644 extern char **environ;
1646 /* $NetBSD: output.h,v 1.16 2002/11/24 22:35:42 christos Exp $ */
1649 static void outstr(const char *, FILE *);
1650 static void outcslow(int, FILE *);
1651 static void flushall(void);
1652 static void flusherr(void);
1653 static int out1fmt(const char *, ...)
1654 __attribute__((__format__(__printf__,1,2)));
1655 static int fmtstr(char *, size_t, const char *, ...)
1656 __attribute__((__format__(__printf__,3,4)));
1658 static int preverrout_fd; /* save fd2 before print debug if xflag is set. */
1661 static void out1str(const char *p)
1666 static void out2str(const char *p)
1673 * Initialization code.
1677 * This routine initializes the builtin variables.
1688 * PS1 depends on uid
1690 #if defined(CONFIG_FEATURE_COMMAND_EDITING) && defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
1691 vps1.text = "PS1=\\w \\$ ";
1694 vps1.text = "PS1=# ";
1697 end = vp + sizeof(varinit) / sizeof(varinit[0]);
1699 vpp = hashvar(vp->text);
1702 } while (++vp < end);
1711 basepf.nextc = basepf.buf = basebuf;
1716 signal(SIGCHLD, SIG_DFL);
1725 for (envp = environ ; *envp ; envp++) {
1726 if (strchr(*envp, '=')) {
1727 setvareq(*envp, VEXPORT|VTEXTFIXED);
1731 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
1732 setvar("PPID", ppid, 0);
1737 /* PEOF (the end of file marker) */
1740 * The input line number. Input.c just defines this variable, and saves
1741 * and restores it when files are pushed and popped. The user of this
1742 * package must set its value.
1745 static int pgetc(void);
1746 static int pgetc2(void);
1747 static int preadbuffer(void);
1748 static void pungetc(void);
1749 static void pushstring(char *, void *);
1750 static void popstring(void);
1751 static void setinputfile(const char *, int);
1752 static void setinputfd(int, int);
1753 static void setinputstring(char *);
1754 static void popfile(void);
1755 static void popallfiles(void);
1756 static void closescript(void);
1759 /* $NetBSD: jobs.h,v 1.17 2003/01/22 20:36:04 dsl Exp $ */
1762 /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
1765 #define FORK_NOJOB 2
1767 /* mode flags for showjob(s) */
1768 #define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
1769 #define SHOW_PID 0x04 /* include process pid */
1770 #define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
1774 * A job structure contains information about a job. A job is either a
1775 * single process or a set of processes contained in a pipeline. In the
1776 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1781 pid_t pid; /* process id */
1782 int status; /* last process status from wait() */
1783 char *cmd; /* text of command being run */
1787 struct procstat ps0; /* status of process */
1788 struct procstat *ps; /* status or processes when more than one */
1790 int stopstatus; /* status of a stopped job */
1793 nprocs: 16, /* number of processes */
1795 #define JOBRUNNING 0 /* at least one proc running */
1796 #define JOBSTOPPED 1 /* all procs are stopped */
1797 #define JOBDONE 2 /* all procs are completed */
1799 sigint: 1, /* job was killed by SIGINT */
1800 jobctl: 1, /* job running under job control */
1802 waited: 1, /* true if this entry has been waited for */
1803 used: 1, /* true if this entry is in used */
1804 changed: 1; /* true if status has changed */
1805 struct job *prev_job; /* previous job */
1808 static pid_t backgndpid; /* pid of last background process */
1809 static int job_warning; /* user was warned about stopped jobs */
1811 static int jobctl; /* true if doing job control */
1814 static struct job *makejob(union node *, int);
1815 static int forkshell(struct job *, union node *, int);
1816 static int waitforjob(struct job *);
1817 static int stoppedjobs(void);
1820 #define setjobctl(on) /* do nothing */
1822 static void setjobctl(int);
1823 static void showjobs(FILE *, int);
1826 /* $NetBSD: main.h,v 1.9 2002/11/24 22:35:41 christos Exp $ */
1829 /* pid of main shell */
1831 /* true if we aren't a child of the main shell */
1832 static int rootshell;
1834 static void readcmdfile(char *);
1835 static void cmdloop(int);
1837 /* $NetBSD: memalloc.h,v 1.13 2003/01/22 20:36:04 dsl Exp $ */
1841 struct stack_block *stackp;
1844 struct stackmark *marknext;
1847 /* minimum size of a block */
1848 #define MINSIZE SHELL_ALIGN(504)
1850 struct stack_block {
1851 struct stack_block *prev;
1852 char space[MINSIZE];
1855 static struct stack_block stackbase;
1856 static struct stack_block *stackp = &stackbase;
1857 static struct stackmark *markp;
1858 static char *stacknxt = stackbase.space;
1859 static size_t stacknleft = MINSIZE;
1860 static char *sstrend = stackbase.space + MINSIZE;
1861 static int herefd = -1;
1864 static pointer ckmalloc(size_t);
1865 static pointer ckrealloc(pointer, size_t);
1866 static char *savestr(const char *);
1867 static pointer stalloc(size_t);
1868 static void stunalloc(pointer);
1869 static void setstackmark(struct stackmark *);
1870 static void popstackmark(struct stackmark *);
1871 static void growstackblock(void);
1872 static void *growstackstr(void);
1873 static char *makestrspace(size_t, char *);
1874 static char *stnputs(const char *, size_t, char *);
1875 static char *stputs(const char *, char *);
1878 static inline char *_STPUTC(char c, char *p) {
1885 #define stackblock() ((void *)stacknxt)
1886 #define stackblocksize() stacknleft
1887 #define STARTSTACKSTR(p) ((p) = stackblock())
1888 #define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1889 #define CHECKSTRSPACE(n, p) \
1893 size_t m = sstrend - q; \
1895 (p) = makestrspace(l, q); \
1898 #define USTPUTC(c, p) (*p++ = (c))
1899 #define STACKSTRNUL(p) ((p) == sstrend? (p = growstackstr(), *p = '\0') : (*p = '\0'))
1900 #define STUNPUTC(p) (--p)
1901 #define STTOPC(p) p[-1]
1902 #define STADJUST(amount, p) (p += (amount))
1904 #define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1905 #define ungrabstackstr(s, p) stunalloc((s))
1906 #define stackstrend() ((void *)sstrend)
1908 #define ckfree(p) free((pointer)(p))
1910 /* $NetBSD: mystring.h,v 1.10 2002/11/24 22:35:42 christos Exp $ */
1913 #define DOLATSTRLEN 4
1915 static char *prefix(const char *, const char *);
1916 static int number(const char *);
1917 static int is_number(const char *);
1918 static char *single_quote(const char *);
1919 static char *sstrdup(const char *);
1921 #define equal(s1, s2) (strcmp(s1, s2) == 0)
1922 #define scopy(s1, s2) ((void)strcpy(s2, s1))
1924 /* $NetBSD: options.h,v 1.16 2003/01/22 20:36:04 dsl Exp $ */
1927 int nparam; /* # of positional parameters (without $0) */
1928 unsigned char malloc; /* if parameter list dynamically allocated */
1929 char **p; /* parameter list */
1930 #ifdef CONFIG_ASH_GETOPTS
1931 int optind; /* next parameter to be processed by getopts */
1932 int optoff; /* used by getopts */
1937 #define eflag optlist[0]
1938 #define fflag optlist[1]
1939 #define Iflag optlist[2]
1940 #define iflag optlist[3]
1941 #define mflag optlist[4]
1942 #define nflag optlist[5]
1943 #define sflag optlist[6]
1944 #define xflag optlist[7]
1945 #define vflag optlist[8]
1946 #define Cflag optlist[9]
1947 #define aflag optlist[10]
1948 #define bflag optlist[11]
1949 #define uflag optlist[12]
1950 #define qflag optlist[13]
1953 #define nolog optlist[14]
1954 #define debug optlist[15]
1960 /* $NetBSD: options.c,v 1.33 2003/01/22 20:36:04 dsl Exp $ */
1963 static const char *const optletters_optnames[NOPTS] = {
1984 #define optletters(n) optletters_optnames[(n)][0]
1985 #define optnames(n) (&optletters_optnames[(n)][1])
1988 static char optlist[NOPTS];
1991 static char *arg0; /* value of $0 */
1992 static struct shparam shellparam; /* $@ current positional parameters */
1993 static char **argptr; /* argument list for builtin commands */
1994 static char *optionarg; /* set by nextopt (like getopt) */
1995 static char *optptr; /* used by nextopt */
1997 static char *minusc; /* argument to -c option */
2000 static void procargs(int, char **);
2001 static void optschanged(void);
2002 static void setparam(char **);
2003 static void freeparam(volatile struct shparam *);
2004 static int shiftcmd(int, char **);
2005 static int setcmd(int, char **);
2006 static int nextopt(const char *);
2008 /* $NetBSD: redir.h,v 1.14 2002/11/24 22:35:43 christos Exp $ */
2010 /* flags passed to redirect */
2011 #define REDIR_PUSH 01 /* save previous values of file descriptors */
2012 #define REDIR_SAVEFD2 03 /* set preverrout */
2015 static void redirect(union node *, int);
2016 static void popredir(int);
2017 static void clearredir(int);
2018 static int copyfd(int, int);
2019 static int redirectsafe(union node *, int);
2021 /* $NetBSD: show.h,v 1.6 2003/01/22 20:36:04 dsl Exp $ */
2025 static void showtree(union node *);
2026 static void trace(const char *, ...);
2027 static void tracev(const char *, va_list);
2028 static void trargs(char **);
2029 static void trputc(int);
2030 static void trputs(const char *);
2031 static void opentrace(void);
2034 /* $NetBSD: trap.h,v 1.16 2002/11/24 22:35:43 christos Exp $ */
2037 /* trap handler commands */
2038 static char *trap[NSIG];
2039 /* current value of signal */
2040 static char sigmode[NSIG - 1];
2041 /* indicates specified signal received */
2042 static char gotsig[NSIG - 1];
2044 static void clear_traps(void);
2045 static void setsignal(int);
2046 static void ignoresig(int);
2047 static void onsig(int);
2048 static void dotrap(void);
2049 static void setinteractive(int);
2050 static void exitshell(void) __attribute__((__noreturn__));
2051 static int decode_signal(const char *, int);
2054 * This routine is called when an error or an interrupt occurs in an
2055 * interactive shell and control is returned to the main command loop.
2070 parselleft = parsenleft = 0; /* clear input buffer */
2074 /* from parser.c: */
2087 #ifdef CONFIG_ASH_ALIAS
2088 static struct alias *atab[ATABSIZE];
2090 static void setalias(const char *, const char *);
2091 static struct alias *freealias(struct alias *);
2092 static struct alias **__lookupalias(const char *);
2095 setalias(const char *name, const char *val)
2097 struct alias *ap, **app;
2099 app = __lookupalias(name);
2103 if (!(ap->flag & ALIASINUSE)) {
2106 ap->val = savestr(val);
2107 ap->flag &= ~ALIASDEAD;
2110 ap = ckmalloc(sizeof (struct alias));
2111 ap->name = savestr(name);
2112 ap->val = savestr(val);
2121 unalias(const char *name)
2125 app = __lookupalias(name);
2129 *app = freealias(*app);
2140 struct alias *ap, **app;
2144 for (i = 0; i < ATABSIZE; i++) {
2146 for (ap = *app; ap; ap = *app) {
2147 *app = freealias(*app);
2156 static struct alias *
2157 lookupalias(const char *name, int check)
2159 struct alias *ap = *__lookupalias(name);
2161 if (check && ap && (ap->flag & ALIASINUSE))
2167 * TODO - sort output
2170 aliascmd(int argc, char **argv)
2179 for (i = 0; i < ATABSIZE; i++)
2180 for (ap = atab[i]; ap; ap = ap->next) {
2185 while ((n = *++argv) != NULL) {
2186 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
2187 if ((ap = *__lookupalias(n)) == NULL) {
2188 fprintf(stderr, "%s: %s not found\n", "alias", n);
2202 unaliascmd(int argc, char **argv)
2206 while ((i = nextopt("a")) != '\0') {
2212 for (i = 0; *argptr; argptr++) {
2213 if (unalias(*argptr)) {
2214 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
2222 static struct alias *
2223 freealias(struct alias *ap) {
2226 if (ap->flag & ALIASINUSE) {
2227 ap->flag |= ALIASDEAD;
2239 printalias(const struct alias *ap) {
2240 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
2243 static struct alias **
2244 __lookupalias(const char *name) {
2245 unsigned int hashval;
2252 ch = (unsigned char)*p;
2256 ch = (unsigned char)*++p;
2258 app = &atab[hashval % ATABSIZE];
2260 for (; *app; app = &(*app)->next) {
2261 if (equal(name, (*app)->name)) {
2268 #endif /* CONFIG_ASH_ALIAS */
2271 /* $NetBSD: cd.c,v 1.30 2003/01/22 20:36:03 dsl Exp $ */
2274 * The cd and pwd commands.
2277 #define CD_PHYSICAL 1
2280 static int docd(const char *, int);
2281 static int cdopt(void);
2283 static char *curdir = nullstr; /* current working directory */
2284 static char *physdir = nullstr; /* physical working directory */
2293 while ((i = nextopt("LP"))) {
2295 flags ^= CD_PHYSICAL;
2304 cdcmd(int argc, char **argv)
2316 dest = bltinlookup(homestr);
2317 else if (dest[0] == '-' && dest[1] == '\0') {
2318 dest = bltinlookup("OLDPWD");
2341 if (!(path = bltinlookup("CDPATH"))) {
2349 p = padvance(&path, dest);
2350 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2354 if (!docd(p, flags))
2359 error("can't cd to %s", dest);
2362 if (flags & CD_PRINT)
2363 out1fmt(snlfmt, curdir);
2369 * Update curdir (the name of the current directory) in response to a
2373 static inline const char *
2374 updatepwd(const char *dir)
2381 cdcomppath = sstrdup(dir);
2384 if (curdir == nullstr)
2386 new = stputs(curdir, new);
2388 new = makestrspace(strlen(dir) + 2, new);
2389 lim = stackblock() + 1;
2393 if (new > lim && *lim == '/')
2398 if (dir[1] == '/' && dir[2] != '/') {
2404 p = strtok(cdcomppath, "/");
2408 if (p[1] == '.' && p[2] == '\0') {
2415 } else if (p[1] == '\0')
2419 new = stputs(p, new);
2427 return stackblock();
2431 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2432 * know that the current directory has changed.
2436 docd(const char *dest, int flags)
2438 const char *dir = 0;
2441 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2444 if (!(flags & CD_PHYSICAL)) {
2445 dir = updatepwd(dest);
2460 * Find out what the current directory is. If we already know the current
2461 * directory, this routine returns immediately.
2463 static inline char *
2466 char *dir = getcwd(0, 0);
2467 return dir ? dir : nullstr;
2471 pwdcmd(int argc, char **argv)
2474 const char *dir = curdir;
2478 if (physdir == nullstr)
2482 out1fmt(snlfmt, dir);
2487 setpwd(const char *val, int setold)
2491 oldcur = dir = curdir;
2494 setvar("OLDPWD", oldcur, VEXPORT);
2497 if (physdir != nullstr) {
2498 if (physdir != oldcur)
2502 if (oldcur == val || !val) {
2509 if (oldcur != dir && oldcur != nullstr) {
2514 setvar("PWD", dir, VEXPORT);
2517 /* $NetBSD: error.c,v 1.30 2003/01/22 20:36:03 dsl Exp $ */
2520 * Errors and exceptions.
2524 * Code to handle exceptions in C.
2529 static void exverror(int, const char *, va_list)
2530 __attribute__((__noreturn__));
2533 * Called to raise an exception. Since C doesn't include exceptions, we
2534 * just do a longjmp to the exception handler. The type of exception is
2535 * stored in the global variable "exception".
2542 if (handler == NULL)
2548 longjmp(handler->loc, 1);
2553 * Called from trap.c when a SIGINT is received. (If the user specifies
2554 * that SIGINT is to be trapped or ignored using the trap builtin, then
2555 * this routine is not called.) Suppressint is nonzero when interrupts
2556 * are held using the INTOFF macro. (The test for iflag is just
2557 * defensive programming.)
2567 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
2568 if (!(rootshell && iflag)) {
2569 signal(SIGINT, SIG_DFL);
2579 exvwarning(const char *msg, va_list ap)
2592 fprintf(errs, fmt, name, startlinno);
2593 vfprintf(errs, msg, ap);
2594 outcslow('\n', errs);
2598 * Exverror is called to raise the error exception. If the second argument
2599 * is not NULL then error prints an error message using printf style
2600 * formatting. It then raises the error exception.
2603 exverror(int cond, const char *msg, va_list ap)
2607 TRACE(("exverror(%d, \"", cond));
2609 TRACE(("\") pid=%d\n", getpid()));
2611 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
2614 exvwarning(msg, ap);
2623 error(const char *msg, ...)
2628 exverror(EXERROR, msg, ap);
2635 exerror(int cond, const char *msg, ...)
2640 exverror(cond, msg, ap);
2646 * error/warning routines for external builtins
2650 sh_warnx(const char *fmt, ...)
2655 exvwarning(fmt, ap);
2661 * Return a string describing an error. The returned string may be a
2662 * pointer to a static buffer that will be overwritten on the next call.
2663 * Action describes the operation that got the error.
2667 errmsg(int e, const char *em)
2669 if(e == ENOENT || e == ENOTDIR) {
2677 /* $NetBSD: eval.c,v 1.71 2003/01/23 03:33:16 rafal Exp $ */
2680 * Evaluate a command.
2683 /* flags in argument to evaltree */
2684 #define EV_EXIT 01 /* exit after evaluating tree */
2685 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2686 #define EV_BACKCMD 04 /* command executing within back quotes */
2689 static void evalloop(union node *, int);
2690 static void evalfor(union node *, int);
2691 static void evalcase(union node *, int);
2692 static void evalsubshell(union node *, int);
2693 static void expredir(union node *);
2694 static void evalpipe(union node *, int);
2695 static void evalcommand(union node *, int);
2696 static int evalbltin(const struct builtincmd *, int, char **);
2697 static int evalfun(struct funcnode *, int, char **, int);
2698 static void prehash(union node *);
2699 static int bltincmd(int, char **);
2702 static const struct builtincmd bltin = {
2708 * Called to reset things after an exception.
2716 evalcmd(int argc, char **argv)
2725 STARTSTACKSTR(concat);
2728 concat = stputs(p, concat);
2729 if ((p = *ap++) == NULL)
2731 STPUTC(' ', concat);
2733 STPUTC('\0', concat);
2734 p = grabstackstr(concat);
2743 * Execute a command or commands contained in a string.
2750 struct stackmark smark;
2752 setstackmark(&smark);
2755 while ((n = parsecmd(0)) != NEOF) {
2757 popstackmark(&smark);
2762 popstackmark(&smark);
2768 * Evaluate a parse tree. The value is left in the global variable
2773 evaltree(union node *n, int flags)
2776 void (*evalfn)(union node *, int);
2780 TRACE(("evaltree(NULL) called\n"));
2783 TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
2784 getpid(), n, n->type, flags));
2788 out1fmt("Node type = %d\n", n->type);
2793 evaltree(n->nnot.com, EV_TESTED);
2794 status = !exitstatus;
2797 expredir(n->nredir.redirect);
2798 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
2800 evaltree(n->nredir.n, flags & EV_TESTED);
2801 status = exitstatus;
2806 evalfn = evalcommand;
2808 if (eflag && !(flags & EV_TESTED))
2820 evalfn = evalsubshell;
2832 #error NAND + 1 != NOR
2834 #if NOR + 1 != NSEMI
2835 #error NOR + 1 != NSEMI
2837 isor = n->type - NAND;
2840 (flags | ((isor >> 1) - 1)) & EV_TESTED
2842 if (!exitstatus == isor)
2854 evaltree(n->nif.test, EV_TESTED);
2857 if (exitstatus == 0) {
2860 } else if (n->nif.elsepart) {
2861 n = n->nif.elsepart;
2866 defun(n->narg.text, n->narg.next);
2870 exitstatus = status;
2876 if (flags & EV_EXIT || checkexit & exitstatus)
2881 #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
2884 void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
2888 evalloop(union node *n, int flags)
2898 evaltree(n->nbinary.ch1, EV_TESTED);
2900 skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
2904 if (evalskip == SKIPBREAK && --skipcount <= 0)
2909 if (n->type != NWHILE)
2913 evaltree(n->nbinary.ch2, flags);
2914 status = exitstatus;
2919 exitstatus = status;
2925 evalfor(union node *n, int flags)
2927 struct arglist arglist;
2930 struct stackmark smark;
2932 setstackmark(&smark);
2933 arglist.lastp = &arglist.list;
2934 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
2935 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
2940 *arglist.lastp = NULL;
2945 for (sp = arglist.list ; sp ; sp = sp->next) {
2946 setvar(n->nfor.var, sp->text, 0);
2947 evaltree(n->nfor.body, flags);
2949 if (evalskip == SKIPCONT && --skipcount <= 0) {
2953 if (evalskip == SKIPBREAK && --skipcount <= 0)
2960 popstackmark(&smark);
2966 evalcase(union node *n, int flags)
2970 struct arglist arglist;
2971 struct stackmark smark;
2973 setstackmark(&smark);
2974 arglist.lastp = &arglist.list;
2975 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
2977 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2978 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
2979 if (casematch(patp, arglist.list->text)) {
2980 if (evalskip == 0) {
2981 evaltree(cp->nclist.body, flags);
2988 popstackmark(&smark);
2994 * Kick off a subshell to evaluate a tree.
2998 evalsubshell(union node *n, int flags)
3001 int backgnd = (n->type == NBACKGND);
3004 expredir(n->nredir.redirect);
3005 if (!backgnd && flags & EV_EXIT && !trap[0])
3009 if (forkshell(jp, n, backgnd) == 0) {
3013 flags &=~ EV_TESTED;
3015 redirect(n->nredir.redirect, 0);
3016 evaltreenr(n->nredir.n, flags);
3021 status = waitforjob(jp);
3022 exitstatus = status;
3029 * Compute the names of the files in a redirection list.
3033 expredir(union node *n)
3037 for (redir = n ; redir ; redir = redir->nfile.next) {
3039 fn.lastp = &fn.list;
3040 switch (redir->type) {
3046 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
3047 redir->nfile.expfname = fn.list->text;
3051 if (redir->ndup.vname) {
3052 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
3053 fixredir(redir, fn.list->text, 1);
3063 * Evaluate a pipeline. All the processes in the pipeline are children
3064 * of the process creating the pipeline. (This differs from some versions
3065 * of the shell, which make the last process in a pipeline the parent
3070 evalpipe(union node *n, int flags)
3073 struct nodelist *lp;
3078 TRACE(("evalpipe(0x%lx) called\n", (long)n));
3080 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
3084 jp = makejob(n, pipelen);
3086 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
3090 if (pipe(pip) < 0) {
3092 error("Pipe call failed");
3095 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
3108 evaltreenr(lp->n, flags);
3116 if (n->npipe.backgnd == 0) {
3117 exitstatus = waitforjob(jp);
3118 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
3126 * Execute a command inside back quotes. If it's a builtin command, we
3127 * want to save its output in a block obtained from malloc. Otherwise
3128 * we fork off a subprocess and get the output of the command via a pipe.
3129 * Should be called with interrupts off.
3133 evalbackcmd(union node *n, struct backcmd *result)
3145 saveherefd = herefd;
3153 error("Pipe call failed");
3155 if (forkshell(jp, n, FORK_NOJOB) == 0) {
3164 evaltreenr(n, EV_EXIT);
3168 result->fd = pip[0];
3171 herefd = saveherefd;
3173 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
3174 result->fd, result->buf, result->nleft, result->jp));
3177 #ifdef CONFIG_ASH_CMDCMD
3178 static inline char **
3179 parse_command_args(char **argv, const char **path)
3191 if (c == '-' && !*cp) {
3201 /* run 'typecmd' for other options */
3204 } while ((c = *cp++));
3213 * Execute a simple command.
3217 evalcommand(union node *cmd, int flags)
3219 struct stackmark smark;
3221 struct arglist arglist;
3222 struct arglist varlist;
3225 const struct strlist *sp;
3226 struct cmdentry cmdentry;
3235 /* First expand the arguments. */
3236 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
3237 setstackmark(&smark);
3238 back_exitstatus = 0;
3240 cmdentry.cmdtype = CMDBUILTIN;
3241 cmdentry.u.cmd = &bltin;
3242 varlist.lastp = &varlist.list;
3243 *varlist.lastp = NULL;
3244 arglist.lastp = &arglist.list;
3245 *arglist.lastp = NULL;
3248 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
3249 struct strlist **spp;
3251 spp = arglist.lastp;
3252 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
3253 for (sp = *spp; sp; sp = sp->next)
3257 argv = nargv = stalloc(sizeof (char *) * (argc + 1));
3258 for (sp = arglist.list ; sp ; sp = sp->next) {
3259 TRACE(("evalcommand arg: %s\n", sp->text));
3260 *nargv++ = sp->text;
3265 if (iflag && funcnest == 0 && argc > 0)
3266 lastarg = nargv[-1];
3269 expredir(cmd->ncmd.redirect);
3270 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH|REDIR_SAVEFD2);
3273 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
3274 struct strlist **spp;
3277 spp = varlist.lastp;
3278 expandarg(argp, &varlist, EXP_VARTILDE);
3281 * Modify the command lookup path, if a PATH= assignment
3285 if (varequal(p, path))
3289 /* Print the command if xflag is set. */
3292 const char *p = " %s";
3295 dprintf(preverrout_fd, p, ps4val());
3298 for(n = 0; n < 2; n++) {
3300 dprintf(preverrout_fd, p, sp->text);
3308 bb_full_write(preverrout_fd, "\n", 1);
3314 /* Now locate the command. */
3316 const char *oldpath;
3317 int cmd_flag = DO_ERR;
3322 find_command(argv[0], &cmdentry, cmd_flag, path);
3323 if (cmdentry.cmdtype == CMDUNKNOWN) {
3329 /* implement bltin and command here */
3330 if (cmdentry.cmdtype != CMDBUILTIN)
3333 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
3334 if (cmdentry.u.cmd == EXECCMD)
3336 #ifdef CONFIG_ASH_CMDCMD
3337 if (cmdentry.u.cmd == COMMANDCMD) {
3340 nargv = parse_command_args(argv, &path);
3343 argc -= nargv - argv;
3345 cmd_flag |= DO_NOFUNC;
3353 /* We have a redirection error. */
3357 exitstatus = status;
3361 /* Execute the command. */
3362 switch (cmdentry.cmdtype) {
3364 /* Fork off a child process if necessary. */
3365 if (!(flags & EV_EXIT) || trap[0]) {
3367 jp = makejob(cmd, 1);
3368 if (forkshell(jp, cmd, FORK_FG) != 0) {
3369 exitstatus = waitforjob(jp);
3375 listsetvar(varlist.list, VEXPORT|VSTACK);
3376 shellexec(argv, path, cmdentry.u.index);
3380 cmdenviron = varlist.list;
3382 struct strlist *list = cmdenviron;
3384 if (spclbltin > 0 || argc == 0) {
3386 if (cmd_is_exec && argc > 1)
3389 listsetvar(list, i);
3391 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
3406 exit_status = j + 128;
3407 exitstatus = exit_status;
3409 if (i == EXINT || spclbltin > 0) {
3411 longjmp(handler->loc, 1);
3418 listsetvar(varlist.list, 0);
3419 if (evalfun(cmdentry.u.func, argc, argv, flags))
3425 popredir(cmd_is_exec);
3427 /* dsl: I think this is intended to be used to support
3428 * '_' in 'vi' command mode during line editing...
3429 * However I implemented that within libedit itself.
3431 setvar("_", lastarg, 0);
3432 popstackmark(&smark);
3436 evalbltin(const struct builtincmd *cmd, int argc, char **argv) {
3437 char *volatile savecmdname;
3438 struct jmploc *volatile savehandler;
3439 struct jmploc jmploc;
3442 savecmdname = commandname;
3443 if ((i = setjmp(jmploc.loc)))
3445 savehandler = handler;
3447 commandname = argv[0];
3449 optptr = NULL; /* initialize nextopt */
3450 exitstatus = (*cmd->builtin)(argc, argv);
3453 exitstatus |= ferror(stdout);
3454 commandname = savecmdname;
3456 handler = savehandler;
3462 evalfun(struct funcnode *func, int argc, char **argv, int flags)
3464 volatile struct shparam saveparam;
3465 struct localvar *volatile savelocalvars;
3466 struct jmploc *volatile savehandler;
3467 struct jmploc jmploc;
3470 saveparam = shellparam;
3471 savelocalvars = localvars;
3472 if ((e = setjmp(jmploc.loc))) {
3476 savehandler = handler;
3479 shellparam.malloc = 0;
3482 shellparam.nparam = argc - 1;
3483 shellparam.p = argv + 1;
3484 #ifdef CONFIG_ASH_GETOPTS
3485 shellparam.optind = 1;
3486 shellparam.optoff = -1;
3489 evaltree(&func->n, flags & EV_TESTED);
3495 localvars = savelocalvars;
3496 freeparam(&shellparam);
3497 shellparam = saveparam;
3498 handler = savehandler;
3500 if (evalskip == SKIPFUNC) {
3509 goodname(const char *p)
3511 return !*endofname(p);
3515 * Search for a command. This is called before we fork so that the
3516 * location of the command will be available in the parent as well as
3517 * the child. The check for "goodname" is an overly conservative
3518 * check that the name will not be subject to expansion.
3522 prehash(union node *n)
3524 struct cmdentry entry;
3526 if (n->type == NCMD && n->ncmd.args)
3527 if (goodname(n->ncmd.args->narg.text))
3528 find_command(n->ncmd.args->narg.text, &entry, 0,
3535 * Builtin commands. Builtin commands whose functions are closely
3536 * tied to evaluation are implemented here.
3544 bltincmd(int argc, char **argv)
3547 * Preserve exitstatus of a previous possible redirection
3550 return back_exitstatus;
3555 * Handle break and continue commands. Break, continue, and return are
3556 * all handled by setting the evalskip flag. The evaluation routines
3557 * above all check this flag, and if it is set they start skipping
3558 * commands rather than executing them. The variable skipcount is
3559 * the number of loops to break/continue, or the number of function
3560 * levels to return. (The latter is always 1.) It should probably
3561 * be an error to break out of more loops than exist, but it isn't
3562 * in the standard shell so we don't make it one here.
3566 breakcmd(int argc, char **argv)
3568 int n = argc > 1 ? number(argv[1]) : 1;
3571 error(illnum, argv[1]);
3575 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
3583 * The return command.
3587 returncmd(int argc, char **argv)
3589 int ret = argc > 1 ? number(argv[1]) : exitstatus;
3592 evalskip = SKIPFUNC;
3597 /* Do what ksh does; skip the rest of the file */
3598 evalskip = SKIPFILE;
3606 falsecmd(int argc, char **argv)
3613 truecmd(int argc, char **argv)
3620 execcmd(int argc, char **argv)
3623 iflag = 0; /* exit on error */
3626 shellexec(argv + 1, pathval(), 0);
3632 /* $NetBSD: exec.c,v 1.35 2003/01/22 20:36:04 dsl Exp $ */
3635 * When commands are first encountered, they are entered in a hash table.
3636 * This ensures that a full path search will not have to be done for them
3637 * on each invocation.
3639 * We should investigate converting to a linear search, even though that
3640 * would make the command name "hash" a misnomer.
3643 #define CMDTABLESIZE 31 /* should be prime */
3644 #define ARB 1 /* actual size determined at run time */
3649 struct tblentry *next; /* next entry in hash chain */
3650 union param param; /* definition of builtin function */
3651 short cmdtype; /* index identifying command */
3652 char rehash; /* if set, cd done since entry created */
3653 char cmdname[ARB]; /* name of command */
3657 static struct tblentry *cmdtable[CMDTABLESIZE];
3658 static int builtinloc = -1; /* index in path of %builtin, or -1 */
3661 static void tryexec(char *, char **, char **);
3662 static void clearcmdentry(int);
3663 static struct tblentry *cmdlookup(const char *, int);
3664 static void delete_cmd_entry(void);
3668 * Exec a program. Never returns. If you change this routine, you may
3669 * have to change the find_command routine as well.
3673 shellexec(char **argv, const char *path, int idx)
3680 envp = environment();
3681 if (strchr(argv[0], '/') != NULL
3682 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3683 || find_applet_by_name(argv[0])
3686 tryexec(argv[0], argv, envp);
3690 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3691 if (--idx < 0 && pathopt == NULL) {
3692 tryexec(cmdname, argv, envp);
3693 if (errno != ENOENT && errno != ENOTDIR)
3700 /* Map to POSIX errors */
3712 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
3713 argv[0], e, suppressint ));
3714 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3720 tryexec(char *cmd, char **argv, char **envp)
3723 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3727 if(strchr(name, '/') == NULL && find_applet_by_name(name) != NULL) {
3735 if(strcmp(name, "busybox")) {
3736 for (ap = argv; *ap; ap++);
3737 ap = new = xmalloc((ap - argv + 2) * sizeof(char *));
3738 *ap++ = cmd = "/bin/busybox";
3739 while ((*ap++ = *argv++));
3743 cmd = "/bin/busybox";
3751 execve(cmd, argv, envp);
3752 } while (errno == EINTR);
3754 execve(cmd, argv, envp);
3758 } else if (errno == ENOEXEC) {
3762 for (ap = argv; *ap; ap++)
3764 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
3766 *ap = cmd = (char *)DEFAULT_SHELL;
3769 while ((*ap++ = *argv++))
3779 * Do a path search. The variable path (passed by reference) should be
3780 * set to the start of the path before the first call; padvance will update
3781 * this value as it proceeds. Successive calls to padvance will return
3782 * the possible path expansions in sequence. If an option (indicated by
3783 * a percent sign) appears in the path entry then the global variable
3784 * pathopt will be set to point to it; otherwise pathopt will be set to
3789 padvance(const char **path, const char *name)
3799 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
3800 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
3801 while (stackblocksize() < len)
3805 memcpy(q, start, p - start);
3813 while (*p && *p != ':') p++;
3819 return stalloc(len);
3823 /*** Command hashing code ***/
3826 printentry(struct tblentry *cmdp)
3832 idx = cmdp->param.index;
3835 name = padvance(&path, cmdp->cmdname);
3837 } while (--idx >= 0);
3838 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
3843 hashcmd(int argc, char **argv)
3845 struct tblentry **pp;
3846 struct tblentry *cmdp;
3848 struct cmdentry entry;
3851 while ((c = nextopt("r")) != '\0') {
3855 if (*argptr == NULL) {
3856 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3857 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3858 if (cmdp->cmdtype == CMDNORMAL)
3865 while ((name = *argptr) != NULL) {
3866 if ((cmdp = cmdlookup(name, 0)) != NULL
3867 && (cmdp->cmdtype == CMDNORMAL
3868 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
3870 find_command(name, &entry, DO_ERR, pathval());
3871 if (entry.cmdtype == CMDUNKNOWN)
3880 * Resolve a command name. If you change this routine, you may have to
3881 * change the shellexec routine as well.
3885 find_command(char *name, struct cmdentry *entry, int act, const char *path)
3887 struct tblentry *cmdp;
3894 struct builtincmd *bcmd;
3896 /* If name contains a slash, don't use PATH or hash table */
3897 if (strchr(name, '/') != NULL) {
3898 entry->u.index = -1;
3900 while (stat(name, &statb) < 0) {
3905 entry->cmdtype = CMDUNKNOWN;
3909 entry->cmdtype = CMDNORMAL;
3913 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3914 if (find_applet_by_name(name)) {
3915 entry->cmdtype = CMDNORMAL;
3916 entry->u.index = -1;
3921 updatetbl = (path == pathval());
3924 if (strstr(path, "%builtin") != NULL)
3928 /* If name is in the table, check answer will be ok */
3929 if ((cmdp = cmdlookup(name, 0)) != NULL) {
3932 switch (cmdp->cmdtype) {
3950 } else if (cmdp->rehash == 0)
3951 /* if not invalidated by cd, we're done */
3955 /* If %builtin not in path, check for builtin next */
3956 bcmd = find_builtin(name);
3957 if (bcmd && (IS_BUILTIN_REGULAR(bcmd) || (
3958 act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0
3960 goto builtin_success;
3962 /* We have to search path. */
3963 prev = -1; /* where to start */
3964 if (cmdp && cmdp->rehash) { /* doing a rehash */
3965 if (cmdp->cmdtype == CMDBUILTIN)
3968 prev = cmdp->param.index;
3974 while ((fullname = padvance(&path, name)) != NULL) {
3975 stunalloc(fullname);
3978 if (prefix(pathopt, "builtin")) {
3980 goto builtin_success;
3982 } else if (!(act & DO_NOFUNC) &&
3983 prefix(pathopt, "func")) {
3986 /* ignore unimplemented options */
3990 /* if rehash, don't redo absolute path names */
3991 if (fullname[0] == '/' && idx <= prev) {
3994 TRACE(("searchexec \"%s\": no change\n", name));
3997 while (stat(fullname, &statb) < 0) {
4002 if (errno != ENOENT && errno != ENOTDIR)
4006 e = EACCES; /* if we fail, this will be the error */
4007 if (!S_ISREG(statb.st_mode))
4009 if (pathopt) { /* this is a %func directory */
4010 stalloc(strlen(fullname) + 1);
4011 readcmdfile(fullname);
4012 if ((cmdp = cmdlookup(name, 0)) == NULL ||
4013 cmdp->cmdtype != CMDFUNCTION)
4014 error("%s not defined in %s", name, fullname);
4015 stunalloc(fullname);
4018 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
4020 entry->cmdtype = CMDNORMAL;
4021 entry->u.index = idx;
4025 cmdp = cmdlookup(name, 1);
4026 cmdp->cmdtype = CMDNORMAL;
4027 cmdp->param.index = idx;
4032 /* We failed. If there was an entry for this command, delete it */
4033 if (cmdp && updatetbl)
4036 sh_warnx("%s: %s", name, errmsg(e, E_EXEC));
4037 entry->cmdtype = CMDUNKNOWN;
4042 entry->cmdtype = CMDBUILTIN;
4043 entry->u.cmd = bcmd;
4047 cmdp = cmdlookup(name, 1);
4048 cmdp->cmdtype = CMDBUILTIN;
4049 cmdp->param.cmd = bcmd;
4053 entry->cmdtype = cmdp->cmdtype;
4054 entry->u = cmdp->param;
4059 * Wrapper around strcmp for qsort/bsearch/...
4061 static int pstrcmp(const void *a, const void *b)
4063 return strcmp((const char *) a, (*(const char *const *) b) + 1);
4067 * Search the table of builtin commands.
4070 static struct builtincmd *
4071 find_builtin(const char *name)
4073 struct builtincmd *bp;
4076 name, builtincmd, NUMBUILTINS, sizeof(struct builtincmd),
4085 * Called when a cd is done. Marks all commands so the next time they
4086 * are executed they will be rehashed.
4092 struct tblentry **pp;
4093 struct tblentry *cmdp;
4095 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4096 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4097 if (cmdp->cmdtype == CMDNORMAL || (
4098 cmdp->cmdtype == CMDBUILTIN &&
4099 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) &&
4110 * Fix command hash table when PATH changed.
4111 * Called before PATH is changed. The argument is the new value of PATH;
4112 * pathval() still returns the old value at this point.
4113 * Called with interrupts off.
4117 changepath(const char *newval)
4119 const char *old, *new;
4126 firstchange = 9999; /* assume no change */
4132 if ((*old == '\0' && *new == ':')
4133 || (*old == ':' && *new == '\0'))
4135 old = new; /* ignore subsequent differences */
4139 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
4146 if (builtinloc < 0 && idx_bltin >= 0)
4147 builtinloc = idx_bltin; /* zap builtins */
4148 if (builtinloc >= 0 && idx_bltin < 0)
4150 clearcmdentry(firstchange);
4151 builtinloc = idx_bltin;
4156 * Clear out command entries. The argument specifies the first entry in
4157 * PATH which has changed.
4161 clearcmdentry(int firstchange)
4163 struct tblentry **tblp;
4164 struct tblentry **pp;
4165 struct tblentry *cmdp;
4168 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4170 while ((cmdp = *pp) != NULL) {
4171 if ((cmdp->cmdtype == CMDNORMAL &&
4172 cmdp->param.index >= firstchange)
4173 || (cmdp->cmdtype == CMDBUILTIN &&
4174 builtinloc >= firstchange)) {
4188 * Locate a command in the command hash table. If "add" is nonzero,
4189 * add the command to the table if it is not already present. The
4190 * variable "lastcmdentry" is set to point to the address of the link
4191 * pointing to the entry, so that delete_cmd_entry can delete the
4194 * Interrupts must be off if called with add != 0.
4197 static struct tblentry **lastcmdentry;
4200 static struct tblentry *
4201 cmdlookup(const char *name, int add)
4203 unsigned int hashval;
4205 struct tblentry *cmdp;
4206 struct tblentry **pp;
4209 hashval = (unsigned char)*p << 4;
4211 hashval += (unsigned char)*p++;
4213 pp = &cmdtable[hashval % CMDTABLESIZE];
4214 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4215 if (equal(cmdp->cmdname, name))
4219 if (add && cmdp == NULL) {
4220 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4221 + strlen(name) + 1);
4223 cmdp->cmdtype = CMDUNKNOWN;
4224 strcpy(cmdp->cmdname, name);
4231 * Delete the command entry returned on the last lookup.
4235 delete_cmd_entry(void)
4237 struct tblentry *cmdp;
4240 cmdp = *lastcmdentry;
4241 *lastcmdentry = cmdp->next;
4242 if (cmdp->cmdtype == CMDFUNCTION)
4243 freefunc(cmdp->param.func);
4250 * Add a new command entry, replacing any existing command entry for
4251 * the same name - except special builtins.
4255 addcmdentry(char *name, struct cmdentry *entry)
4257 struct tblentry *cmdp;
4259 cmdp = cmdlookup(name, 1);
4260 if (cmdp->cmdtype == CMDFUNCTION) {
4261 freefunc(cmdp->param.func);
4263 cmdp->cmdtype = entry->cmdtype;
4264 cmdp->param = entry->u;
4269 * Make a copy of a parse tree.
4272 static inline struct funcnode *
4273 copyfunc(union node *n)
4278 funcblocksize = offsetof(struct funcnode, n);
4281 blocksize = funcblocksize;
4282 f = ckmalloc(blocksize + funcstringsize);
4283 funcblock = (char *) f + offsetof(struct funcnode, n);
4284 funcstring = (char *) f + blocksize;
4291 * Define a shell function.
4295 defun(char *name, union node *func)
4297 struct cmdentry entry;
4300 entry.cmdtype = CMDFUNCTION;
4301 entry.u.func = copyfunc(func);
4302 addcmdentry(name, &entry);
4308 * Delete a function if it exists.
4312 unsetfunc(const char *name)
4314 struct tblentry *cmdp;
4316 if ((cmdp = cmdlookup(name, 0)) != NULL &&
4317 cmdp->cmdtype == CMDFUNCTION)
4322 * Locate and print what a word is...
4326 #ifdef CONFIG_ASH_CMDCMD
4328 describe_command(char *command, int describe_command_verbose)
4330 #define describe_command_verbose 1
4332 describe_command(char *command)
4335 struct cmdentry entry;
4336 struct tblentry *cmdp;
4337 #ifdef CONFIG_ASH_ALIAS
4338 const struct alias *ap;
4340 const char *path = pathval();
4342 if (describe_command_verbose) {
4346 /* First look at the keywords */
4347 if (findkwd(command)) {
4348 out1str(describe_command_verbose ? " is a shell keyword" : command);
4352 #ifdef CONFIG_ASH_ALIAS
4353 /* Then look at the aliases */
4354 if ((ap = lookupalias(command, 0)) != NULL) {
4355 if (describe_command_verbose) {
4356 out1fmt(" is an alias for %s", ap->val);
4365 /* Then check if it is a tracked alias */
4366 if ((cmdp = cmdlookup(command, 0)) != NULL) {
4367 entry.cmdtype = cmdp->cmdtype;
4368 entry.u = cmdp->param;
4370 /* Finally use brute force */
4371 find_command(command, &entry, DO_ABS, path);
4374 switch (entry.cmdtype) {
4376 int j = entry.u.index;
4382 p = padvance(&path, command);
4386 if (describe_command_verbose) {
4388 (cmdp ? " a tracked alias for" : nullstr), p
4397 if (describe_command_verbose) {
4398 out1str(" is a shell function");
4405 if (describe_command_verbose) {
4406 out1fmt(" is a %sshell builtin",
4407 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
4408 "special " : nullstr
4416 if (describe_command_verbose) {
4417 out1str(": not found\n");
4423 outstr("\n", stdout);
4428 typecmd(int argc, char **argv)
4433 for (i = 1; i < argc; i++) {
4434 #ifdef CONFIG_ASH_CMDCMD
4435 err |= describe_command(argv[i], 1);
4437 err |= describe_command(argv[i]);
4443 #ifdef CONFIG_ASH_CMDCMD
4445 commandcmd(int argc, char **argv)
4448 int default_path = 0;
4449 int verify_only = 0;
4450 int verbose_verify_only = 0;
4452 while ((c = nextopt("pvV")) != '\0')
4457 "command: nextopt returned character code 0%o\n", c);
4467 verbose_verify_only = 1;
4471 if (default_path + verify_only + verbose_verify_only > 1 ||
4474 "command [-p] command [arg ...]\n"
4475 "command {-v|-V} command\n");
4479 if (verify_only || verbose_verify_only) {
4480 return describe_command(*argptr, verbose_verify_only);
4487 /* $NetBSD: expand.c,v 1.56 2002/11/24 22:35:39 christos Exp $ */
4490 * Routines to expand arguments to commands. We have to deal with
4491 * backquotes, shell variables, and file metacharacters.
4497 #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4498 #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
4499 #define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
4500 #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
4501 #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
4504 * Structure specifying which parts of the string should be searched
4505 * for IFS characters.
4509 struct ifsregion *next; /* next region in list */
4510 int begoff; /* offset of start of region */
4511 int endoff; /* offset of end of region */
4512 int nulonly; /* search for nul bytes only */
4515 /* output of current string */
4516 static char *expdest;
4517 /* list of back quote expressions */
4518 static struct nodelist *argbackq;
4519 /* first struct in list of ifs regions */
4520 static struct ifsregion ifsfirst;
4521 /* last struct in list */
4522 static struct ifsregion *ifslastp;
4523 /* holds expanded arg list */
4524 static struct arglist exparg;
4526 static void argstr(char *, int);
4527 static char *exptilde(char *, char *, int);
4528 static void expbackq(union node *, int, int);
4529 static const char *subevalvar(char *, char *, int, int, int, int, int);
4530 static char *evalvar(char *, int);
4531 static void strtodest(const char *, int, int);
4532 static void memtodest(const char *p, size_t len, int syntax, int quotes);
4533 static ssize_t varvalue(char *, int, int);
4534 static void recordregion(int, int, int);
4535 static void removerecordregions(int);
4536 static void ifsbreakup(char *, struct arglist *);
4537 static void ifsfree(void);
4538 static void expandmeta(struct strlist *, int);
4539 static int patmatch(char *, const char *);
4541 static int cvtnum(arith_t);
4542 static size_t esclen(const char *, const char *);
4543 static char *scanleft(char *, char *, char *, char *, int, int);
4544 static char *scanright(char *, char *, char *, char *, int, int);
4545 static void varunset(const char *, const char *, const char *, int)
4546 __attribute__((__noreturn__));
4549 #define pmatch(a, b) !fnmatch((a), (b), 0)
4551 * Prepare a pattern for a expmeta (internal glob(3)) call.
4553 * Returns an stalloced string.
4556 static inline char *
4557 preglob(const char *pattern, int quoted, int flag) {
4558 flag |= RMESCAPE_GLOB;
4560 flag |= RMESCAPE_QUOTED;
4562 return _rmescapes((char *)pattern, flag);
4567 esclen(const char *start, const char *p) {
4570 while (p > start && *--p == CTLESC) {
4578 * Expand shell variables and backquotes inside a here document.
4582 expandhere(union node *arg, int fd)
4585 expandarg(arg, (struct arglist *)NULL, 0);
4586 bb_full_write(fd, stackblock(), expdest - (char *)stackblock());
4591 * Perform variable substitution and command substitution on an argument,
4592 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4593 * perform splitting and file name expansion. When arglist is NULL, perform
4594 * here document expansion.
4598 expandarg(union node *arg, struct arglist *arglist, int flag)
4603 argbackq = arg->narg.backquote;
4604 STARTSTACKSTR(expdest);
4605 ifsfirst.next = NULL;
4607 argstr(arg->narg.text, flag);
4608 if (arglist == NULL) {
4609 return; /* here document expanded */
4611 STPUTC('\0', expdest);
4612 p = grabstackstr(expdest);
4613 exparg.lastp = &exparg.list;
4617 if (flag & EXP_FULL) {
4618 ifsbreakup(p, &exparg);
4619 *exparg.lastp = NULL;
4620 exparg.lastp = &exparg.list;
4621 expandmeta(exparg.list, flag);
4623 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
4625 sp = (struct strlist *)stalloc(sizeof (struct strlist));
4628 exparg.lastp = &sp->next;
4632 *exparg.lastp = NULL;
4634 *arglist->lastp = exparg.list;
4635 arglist->lastp = exparg.lastp;
4641 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4642 * characters to allow for further processing. Otherwise treat
4643 * $@ like $* since no splitting will be performed.
4647 argstr(char *p, int flag)
4649 static const char spclchars[] = {
4657 CTLBACKQ | CTLQUOTE,
4658 #ifdef CONFIG_ASH_MATH_SUPPORT
4663 const char *reject = spclchars;
4665 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
4666 int breakall = flag & EXP_WORD;
4671 if (!(flag & EXP_VARTILDE)) {
4673 } else if (flag & EXP_VARTILDE2) {
4678 if (flag & EXP_TILDE) {
4684 if (*q == CTLESC && (flag & EXP_QWORD))
4687 p = exptilde(p, q, flag);
4690 startloc = expdest - (char *)stackblock();
4692 length += strcspn(p + length, reject);
4694 if (c && (!(c & 0x80)
4695 #ifdef CONFIG_ASH_MATH_SUPPORT
4699 /* c == '=' || c == ':' || c == CTLENDARI */
4704 expdest = stnputs(p, length, expdest);
4705 newloc = expdest - (char *)stackblock();
4706 if (breakall && !inquotes && newloc > startloc) {
4707 recordregion(startloc, newloc, 0);
4718 if (flag & EXP_VARTILDE2) {
4722 flag |= EXP_VARTILDE2;
4727 * sort of a hack - expand tildes in variable
4728 * assignments (after the first '=' and after ':'s).
4737 case CTLENDVAR: /* ??? */
4740 /* "$@" syntax adherence hack */
4743 !memcmp(p, dolatstr, DOLATSTRLEN) &&
4744 (p[4] == CTLQUOTEMARK || (
4745 p[4] == CTLENDVAR &&
4746 p[5] == CTLQUOTEMARK
4749 p = evalvar(p + 1, flag) + 1;
4752 inquotes = !inquotes;
4765 p = evalvar(p, flag);
4769 case CTLBACKQ|CTLQUOTE:
4770 expbackq(argbackq->n, c, quotes);
4771 argbackq = argbackq->next;
4773 #ifdef CONFIG_ASH_MATH_SUPPORT
4786 exptilde(char *startp, char *p, int flag)
4792 int quotes = flag & (EXP_FULL | EXP_CASE);
4797 while ((c = *++p) != '\0') {
4804 if (flag & EXP_VARTILDE)
4814 if (*name == '\0') {
4815 if ((home = lookupvar(homestr)) == NULL)
4818 if ((pw = getpwnam(name)) == NULL)
4825 startloc = expdest - (char *)stackblock();
4826 strtodest(home, SQSYNTAX, quotes);
4827 recordregion(startloc, expdest - (char *)stackblock(), 0);
4836 removerecordregions(int endoff)
4838 if (ifslastp == NULL)
4841 if (ifsfirst.endoff > endoff) {
4842 while (ifsfirst.next != NULL) {
4843 struct ifsregion *ifsp;
4845 ifsp = ifsfirst.next->next;
4846 ckfree(ifsfirst.next);
4847 ifsfirst.next = ifsp;
4850 if (ifsfirst.begoff > endoff)
4853 ifslastp = &ifsfirst;
4854 ifsfirst.endoff = endoff;
4859 ifslastp = &ifsfirst;
4860 while (ifslastp->next && ifslastp->next->begoff < endoff)
4861 ifslastp=ifslastp->next;
4862 while (ifslastp->next != NULL) {
4863 struct ifsregion *ifsp;
4865 ifsp = ifslastp->next->next;
4866 ckfree(ifslastp->next);
4867 ifslastp->next = ifsp;
4870 if (ifslastp->endoff > endoff)
4871 ifslastp->endoff = endoff;
4875 #ifdef CONFIG_ASH_MATH_SUPPORT
4877 * Expand arithmetic expression. Backup to start of expression,
4878 * evaluate, place result in (backed up) result, adjust string position.
4891 * This routine is slightly over-complicated for
4892 * efficiency. Next we scan backwards looking for the
4893 * start of arithmetic.
4895 start = stackblock();
4902 while (*p != CTLARI) {
4906 error("missing CTLARI (shouldn't happen)");
4911 esc = esclen(start, p);
4921 removerecordregions(begoff);
4930 len = cvtnum(dash_arith(p + 2));
4933 recordregion(begoff, begoff + len, 0);
4938 * Expand stuff in backwards quotes.
4942 expbackq(union node *cmd, int quoted, int quotes)
4950 int syntax = quoted? DQSYNTAX : BASESYNTAX;
4951 struct stackmark smark;
4954 setstackmark(&smark);
4956 startloc = dest - (char *)stackblock();
4958 evalbackcmd(cmd, (struct backcmd *) &in);
4959 popstackmark(&smark);
4966 memtodest(p, i, syntax, quotes);
4970 i = safe_read(in.fd, buf, sizeof buf);
4971 TRACE(("expbackq: read returns %d\n", i));
4981 back_exitstatus = waitforjob(in.jp);
4985 /* Eat all trailing newlines */
4987 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
4992 recordregion(startloc, dest - (char *)stackblock(), 0);
4993 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4994 (dest - (char *)stackblock()) - startloc,
4995 (dest - (char *)stackblock()) - startloc,
4996 stackblock() + startloc));
5001 scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5012 const char *s = loc2;
5018 match = pmatch(str, s);
5022 if (quotes && *loc == CTLESC)
5032 scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5039 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5042 const char *s = loc2;
5047 match = pmatch(str, s);
5054 esc = esclen(startp, loc);
5066 subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
5070 int saveherefd = herefd;
5071 struct nodelist *saveargbackq = argbackq;
5073 char *rmesc, *rmescend;
5075 char *(*scan)(char *, char *, char *, char *, int , int);
5078 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
5079 STPUTC('\0', expdest);
5080 herefd = saveherefd;
5081 argbackq = saveargbackq;
5082 startp = stackblock() + startloc;
5086 setvar(str, startp, 0);
5087 amount = startp - expdest;
5088 STADJUST(amount, expdest);
5092 varunset(p, str, startp, varflags);
5096 subtype -= VSTRIMRIGHT;
5098 if (subtype < 0 || subtype > 3)
5103 rmescend = stackblock() + strloc;
5105 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5106 if (rmesc != startp) {
5108 startp = stackblock() + startloc;
5112 str = stackblock() + strloc;
5113 preglob(str, varflags & VSQUOTE, 0);
5115 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
5116 zero = subtype >> 1;
5117 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
5118 scan = (subtype & 1) ^ zero ? scanleft : scanright;
5120 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
5123 memmove(startp, loc, str - loc);
5124 loc = startp + (str - loc) - 1;
5127 amount = loc - expdest;
5128 STADJUST(amount, expdest);
5135 * Expand a variable, and return a pointer to the next character in the
5139 evalvar(char *p, int flag)
5152 quotes = flag & (EXP_FULL | EXP_CASE);
5154 subtype = varflags & VSTYPE;
5155 quoted = varflags & VSQUOTE;
5157 easy = (!quoted || (*var == '@' && shellparam.nparam));
5158 startloc = expdest - (char *)stackblock();
5159 p = strchr(p, '=') + 1;
5162 varlen = varvalue(var, varflags, flag);
5163 if (varflags & VSNUL)
5166 if (subtype == VSPLUS) {
5167 varlen = -1 - varlen;
5171 if (subtype == VSMINUS) {
5175 p, flag | EXP_TILDE |
5176 (quoted ? EXP_QWORD : EXP_WORD)
5185 if (subtype == VSASSIGN || subtype == VSQUESTION) {
5187 if (subevalvar(p, var, 0, subtype, startloc,
5191 * Remove any recorded regions beyond
5194 removerecordregions(startloc);
5204 if (varlen < 0 && uflag)
5205 varunset(p, var, 0, 0);
5207 if (subtype == VSLENGTH) {
5208 cvtnum(varlen > 0 ? varlen : 0);
5212 if (subtype == VSNORMAL) {
5216 recordregion(startloc, expdest - (char *)stackblock(), quoted);
5225 case VSTRIMRIGHTMAX:
5234 * Terminate the string and start recording the pattern
5237 STPUTC('\0', expdest);
5238 patloc = expdest - (char *)stackblock();
5239 if (subevalvar(p, NULL, patloc, subtype,
5240 startloc, varflags, quotes) == 0) {
5241 int amount = expdest - (
5242 (char *)stackblock() + patloc - 1
5244 STADJUST(-amount, expdest);
5246 /* Remove any recorded regions beyond start of variable */
5247 removerecordregions(startloc);
5252 if (subtype != VSNORMAL) { /* skip to end of alternative */
5255 if ((c = *p++) == CTLESC)
5257 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
5259 argbackq = argbackq->next;
5260 } else if (c == CTLVAR) {
5261 if ((*p++ & VSTYPE) != VSNORMAL)
5263 } else if (c == CTLENDVAR) {
5274 * Put a string on the stack.
5278 memtodest(const char *p, size_t len, int syntax, int quotes) {
5281 q = makestrspace(len * 2, q);
5287 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5297 strtodest(const char *p, int syntax, int quotes)
5299 memtodest(p, strlen(p), syntax, quotes);
5304 * Add the value of a specialized variable to the stack string.
5308 varvalue(char *name, int varflags, int flags)
5318 int quoted = varflags & VSQUOTE;
5319 int subtype = varflags & VSTYPE;
5320 int quotes = flags & (EXP_FULL | EXP_CASE);
5322 if (quoted && (flags & EXP_FULL))
5323 sep = 1 << CHAR_BIT;
5325 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5334 num = shellparam.nparam;
5344 p = makestrspace(NOPTS, expdest);
5345 for (i = NOPTS - 1; i >= 0; i--) {
5347 USTPUTC(optletters(i), p);
5358 sep = ifsset() ? ifsval()[0] : ' ';
5359 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
5362 if (!(ap = shellparam.p))
5364 while ((p = *ap++)) {
5367 partlen = strlen(p);
5370 if (len > partlen && sep) {
5374 if (subtype == VSPLUS || subtype == VSLENGTH) {
5384 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5385 memtodest(p, partlen, syntax, quotes);
5399 if (num < 0 || num > shellparam.nparam)
5401 p = num ? shellparam.p[num - 1] : arg0;
5404 p = lookupvar(name);
5410 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5411 memtodest(p, len, syntax, quotes);
5415 if (subtype == VSPLUS || subtype == VSLENGTH)
5416 STADJUST(-len, expdest);
5422 * Record the fact that we have to scan this region of the
5423 * string for IFS characters.
5427 recordregion(int start, int end, int nulonly)
5429 struct ifsregion *ifsp;
5431 if (ifslastp == NULL) {
5435 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
5437 ifslastp->next = ifsp;
5441 ifslastp->begoff = start;
5442 ifslastp->endoff = end;
5443 ifslastp->nulonly = nulonly;
5448 * Break the argument string into pieces based upon IFS and add the
5449 * strings to the argument list. The regions of the string to be
5450 * searched for IFS characters have been stored by recordregion.
5453 ifsbreakup(char *string, struct arglist *arglist)
5455 struct ifsregion *ifsp;
5460 const char *ifs, *realifs;
5466 if (ifslastp != NULL) {
5469 realifs = ifsset() ? ifsval() : defifs;
5472 p = string + ifsp->begoff;
5473 nulonly = ifsp->nulonly;
5474 ifs = nulonly ? nullstr : realifs;
5476 while (p < string + ifsp->endoff) {
5480 if (strchr(ifs, *p)) {
5482 ifsspc = (strchr(defifs, *p) != NULL);
5483 /* Ignore IFS whitespace at start */
5484 if (q == start && ifsspc) {
5490 sp = (struct strlist *)stalloc(sizeof *sp);
5492 *arglist->lastp = sp;
5493 arglist->lastp = &sp->next;
5497 if (p >= string + ifsp->endoff) {
5503 if (strchr(ifs, *p) == NULL ) {
5506 } else if (strchr(defifs, *p) == NULL) {
5522 } while ((ifsp = ifsp->next) != NULL);
5531 sp = (struct strlist *)stalloc(sizeof *sp);
5533 *arglist->lastp = sp;
5534 arglist->lastp = &sp->next;
5540 struct ifsregion *p;
5545 struct ifsregion *ifsp;
5551 ifsfirst.next = NULL;
5555 static void expmeta(char *, char *);
5556 static struct strlist *expsort(struct strlist *);
5557 static struct strlist *msort(struct strlist *, int);
5559 static char *expdir;
5563 expandmeta(struct strlist *str, int flag)
5565 static const char metachars[] = {
5568 /* TODO - EXP_REDIR */
5571 struct strlist **savelastp;
5577 if (!strpbrk(str->text, metachars))
5579 savelastp = exparg.lastp;
5582 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
5584 int i = strlen(str->text);
5585 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5593 if (exparg.lastp == savelastp) {
5598 *exparg.lastp = str;
5599 rmescapes(str->text);
5600 exparg.lastp = &str->next;
5602 *exparg.lastp = NULL;
5603 *savelastp = sp = expsort(*savelastp);
5604 while (sp->next != NULL)
5606 exparg.lastp = &sp->next;
5613 * Add a file name to the list.
5617 addfname(const char *name)
5621 sp = (struct strlist *)stalloc(sizeof *sp);
5622 sp->text = sstrdup(name);
5624 exparg.lastp = &sp->next;
5629 * Do metacharacter (i.e. *, ?, [...]) expansion.
5633 expmeta(char *enddir, char *name)
5648 for (p = name; *p; p++) {
5649 if (*p == '*' || *p == '?')
5651 else if (*p == '[') {
5658 if (*q == '/' || *q == '\0')
5665 } else if (*p == '\\')
5667 else if (*p == '/') {
5674 if (metaflag == 0) { /* we've reached the end of the file name */
5675 if (enddir != expdir)
5683 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
5694 } while (p < start);
5696 if (enddir == expdir) {
5698 } else if (enddir == expdir + 1 && *expdir == '/') {
5704 if ((dirp = opendir(cp)) == NULL)
5706 if (enddir != expdir)
5708 if (*endname == 0) {
5720 while (! intpending && (dp = readdir(dirp)) != NULL) {
5721 if (dp->d_name[0] == '.' && ! matchdot)
5723 if (pmatch(start, dp->d_name)) {
5725 scopy(dp->d_name, enddir);
5728 for (p = enddir, cp = dp->d_name;
5729 (*p++ = *cp++) != '\0';)
5732 expmeta(p, endname);
5742 * Sort the results of file name expansion. It calculates the number of
5743 * strings to sort and then calls msort (short for merge sort) to do the
5747 static struct strlist *
5748 expsort(struct strlist *str)
5754 for (sp = str ; sp ; sp = sp->next)
5756 return msort(str, len);
5760 static struct strlist *
5761 msort(struct strlist *list, int len)
5763 struct strlist *p, *q = NULL;
5764 struct strlist **lpp;
5772 for (n = half ; --n >= 0 ; ) {
5776 q->next = NULL; /* terminate first half of list */
5777 q = msort(list, half); /* sort first half of list */
5778 p = msort(p, len - half); /* sort second half */
5781 #ifdef CONFIG_LOCALE_SUPPORT
5782 if (strcoll(p->text, q->text) < 0)
5784 if (strcmp(p->text, q->text) < 0)
5789 if ((p = *lpp) == NULL) {
5796 if ((q = *lpp) == NULL) {
5807 * Returns true if the pattern matches the string.
5811 patmatch(char *pattern, const char *string)
5813 return pmatch(preglob(pattern, 0, 0), string);
5818 * Remove any CTLESC characters from a string.
5822 _rmescapes(char *str, int flag)
5825 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
5830 p = strpbrk(str, qchars);
5836 if (flag & RMESCAPE_ALLOC) {
5837 size_t len = p - str;
5838 size_t fulllen = len + strlen(p) + 1;
5840 if (flag & RMESCAPE_GROW) {
5841 r = makestrspace(fulllen, expdest);
5842 } else if (flag & RMESCAPE_HEAP) {
5843 r = ckmalloc(fulllen);
5845 r = stalloc(fulllen);
5849 q = mempcpy(q, str, len);
5852 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5853 globbing = flag & RMESCAPE_GLOB;
5854 notescaped = globbing;
5856 if (*p == CTLQUOTEMARK) {
5857 inquotes = ~inquotes;
5859 notescaped = globbing;
5863 /* naked back slash */
5869 if (notescaped && inquotes && *p != '/') {
5873 notescaped = globbing;
5878 if (flag & RMESCAPE_GROW) {
5880 STADJUST(q - r + 1, expdest);
5887 * See if a pattern matches in a case statement.
5891 casematch(union node *pattern, char *val)
5893 struct stackmark smark;
5896 setstackmark(&smark);
5897 argbackq = pattern->narg.backquote;
5898 STARTSTACKSTR(expdest);
5900 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
5901 STACKSTRNUL(expdest);
5902 result = patmatch(stackblock(), val);
5903 popstackmark(&smark);
5916 expdest = makestrspace(32, expdest);
5917 #ifdef CONFIG_ASH_MATH_SUPPORT_64
5918 len = fmtstr(expdest, 32, "%lld", (long long) num);
5920 len = fmtstr(expdest, 32, "%ld", num);
5922 STADJUST(len, expdest);
5927 varunset(const char *end, const char *var, const char *umsg, int varflags)
5933 msg = "parameter not set";
5935 if (*end == CTLENDVAR) {
5936 if (varflags & VSNUL)
5941 error("%.*s: %s%s", end - var - 1, var, msg, tail);
5945 /* $NetBSD: input.c,v 1.37 2002/11/24 22:35:40 christos Exp $ */
5948 * This implements the input routines used by the parser.
5951 #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
5952 #define IBUFSIZ (BUFSIZ + 1)
5954 static void pushfile(void);
5957 * Read a character from the script, returning PEOF on end of file.
5958 * Nul characters in the input are silently discarded.
5961 #define pgetc_as_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
5963 #ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
5964 #define pgetc_macro() pgetc()
5968 return pgetc_as_macro();
5971 #define pgetc_macro() pgetc_as_macro()
5975 return pgetc_macro();
5981 * Same as pgetc(), but ignores PEOA.
5983 #ifdef CONFIG_ASH_ALIAS
5984 static int pgetc2(void)
5990 } while (c == PEOA);
5994 static inline int pgetc2(void)
5996 return pgetc_macro();
6001 * Read a line from the script.
6004 static inline char *
6005 pfgets(char *line, int len)
6011 while (--nleft > 0) {
6028 #ifdef CONFIG_FEATURE_COMMAND_EDITING
6029 static const char *cmdedit_prompt;
6030 static inline void putprompt(const char *s)
6035 static inline void putprompt(const char *s)
6045 char *buf = parsefile->buf;
6049 #ifdef CONFIG_FEATURE_COMMAND_EDITING
6050 if (!iflag || parsefile->fd)
6051 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6053 #ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
6054 cmdedit_path_lookup = pathval();
6056 nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
6058 /* Ctrl+C presend */
6067 if(nr < 0 && errno == 0) {
6068 /* Ctrl+D presend */
6073 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6077 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6078 int flags = fcntl(0, F_GETFL, 0);
6079 if (flags >= 0 && flags & O_NONBLOCK) {
6080 flags &=~ O_NONBLOCK;
6081 if (fcntl(0, F_SETFL, flags) >= 0) {
6082 out2str("sh: turning off NDELAY mode\n");
6092 * Refill the input buffer and return the next input character:
6094 * 1) If a string was pushed back on the input, pop it;
6095 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6096 * from a string so we can't refill the buffer, return EOF.
6097 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6098 * 4) Process input up to the next newline, deleting nul characters.
6108 while (parsefile->strpush) {
6109 #ifdef CONFIG_ASH_ALIAS
6110 if (parsenleft == -1 && parsefile->strpush->ap &&
6111 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
6116 if (--parsenleft >= 0)
6117 return (*parsenextc++);
6119 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6124 if (parselleft <= 0) {
6125 if ((parselleft = preadfd()) <= 0) {
6126 parselleft = parsenleft = EOF_NLEFT;
6133 /* delete nul characters */
6134 for (more = 1; more;) {
6141 parsenleft = q - parsenextc;
6142 more = 0; /* Stop processing here */
6149 if (--parselleft <= 0 && more) {
6150 parsenleft = q - parsenextc - 1;
6161 out2str(parsenextc);
6166 return *parsenextc++;
6170 * Undo the last call to pgetc. Only one character may be pushed back.
6171 * PEOF may be pushed back.
6182 * Push a string back onto the input at this current parsefile level.
6183 * We handle aliases this way.
6186 pushstring(char *s, void *ap)
6193 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6194 if (parsefile->strpush) {
6195 sp = ckmalloc(sizeof (struct strpush));
6196 sp->prev = parsefile->strpush;
6197 parsefile->strpush = sp;
6199 sp = parsefile->strpush = &(parsefile->basestrpush);
6200 sp->prevstring = parsenextc;
6201 sp->prevnleft = parsenleft;
6202 #ifdef CONFIG_ASH_ALIAS
6203 sp->ap = (struct alias *)ap;
6205 ((struct alias *)ap)->flag |= ALIASINUSE;
6217 struct strpush *sp = parsefile->strpush;
6220 #ifdef CONFIG_ASH_ALIAS
6222 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6223 checkkwd |= CHKALIAS;
6225 if (sp->string != sp->ap->val) {
6228 sp->ap->flag &= ~ALIASINUSE;
6229 if (sp->ap->flag & ALIASDEAD) {
6230 unalias(sp->ap->name);
6234 parsenextc = sp->prevstring;
6235 parsenleft = sp->prevnleft;
6236 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6237 parsefile->strpush = sp->prev;
6238 if (sp != &(parsefile->basestrpush))
6244 * Set the input to take input from a file. If push is set, push the
6245 * old input onto the stack first.
6249 setinputfile(const char *fname, int push)
6255 if ((fd = open(fname, O_RDONLY)) < 0)
6256 error("Can't open %s", fname);
6258 fd2 = copyfd(fd, 10);
6261 error("Out of file descriptors");
6264 setinputfd(fd, push);
6270 * Like setinputfile, but takes an open file descriptor. Call this with
6275 setinputfd(int fd, int push)
6277 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
6283 if (parsefile->buf == NULL)
6284 parsefile->buf = ckmalloc(IBUFSIZ);
6285 parselleft = parsenleft = 0;
6291 * Like setinputfile, but takes input from a string.
6295 setinputstring(char *string)
6299 parsenextc = string;
6300 parsenleft = strlen(string);
6301 parsefile->buf = NULL;
6308 * To handle the "." command, a stack of input files is used. Pushfile
6309 * adds a new entry to the stack and popfile restores the previous level.
6315 struct parsefile *pf;
6317 parsefile->nleft = parsenleft;
6318 parsefile->lleft = parselleft;
6319 parsefile->nextc = parsenextc;
6320 parsefile->linno = plinno;
6321 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
6322 pf->prev = parsefile;
6325 pf->basestrpush.prev = NULL;
6333 struct parsefile *pf = parsefile;
6342 parsefile = pf->prev;
6344 parsenleft = parsefile->nleft;
6345 parselleft = parsefile->lleft;
6346 parsenextc = parsefile->nextc;
6347 plinno = parsefile->linno;
6353 * Return to top level.
6359 while (parsefile != &basepf)
6365 * Close the file(s) that the shell is reading commands from. Called
6366 * after a fork is done.
6373 if (parsefile->fd > 0) {
6374 close(parsefile->fd);
6379 /* $NetBSD: jobs.c,v 1.56 2002/11/25 12:13:03 agc Exp $ */
6381 /* mode flags for set_curjob */
6382 #define CUR_DELETE 2
6383 #define CUR_RUNNING 1
6384 #define CUR_STOPPED 0
6386 /* mode flags for dowait */
6387 #define DOWAIT_NORMAL 0
6388 #define DOWAIT_BLOCK 1
6391 static struct job *jobtab;
6393 static unsigned njobs;
6395 /* pgrp of shell on invocation */
6396 static int initialpgrp;
6397 static int ttyfd = -1;
6400 static struct job *curjob;
6401 /* number of presumed living untracked jobs */
6404 static void set_curjob(struct job *, unsigned);
6406 static int restartjob(struct job *, int);
6407 static void xtcsetpgrp(int, pid_t);
6408 static char *commandtext(union node *);
6409 static void cmdlist(union node *, int);
6410 static void cmdtxt(union node *);
6411 static void cmdputs(const char *);
6412 static void showpipe(struct job *, FILE *);
6414 static int sprint_status(char *, int, int);
6415 static void freejob(struct job *);
6416 static struct job *getjob(const char *, int);
6417 static struct job *growjobtab(void);
6418 static void forkchild(struct job *, union node *, int);
6419 static void forkparent(struct job *, union node *, int, pid_t);
6420 static int dowait(int, struct job *);
6421 static int getstatus(struct job *);
6424 set_curjob(struct job *jp, unsigned mode)
6427 struct job **jpp, **curp;
6429 /* first remove from list */
6430 jpp = curp = &curjob;
6435 jpp = &jp1->prev_job;
6437 *jpp = jp1->prev_job;
6439 /* Then re-insert in correct position */
6447 /* job being deleted */
6450 /* newly created job or backgrounded job,
6451 put after all stopped jobs. */
6455 if (!jp1 || jp1->state != JOBSTOPPED)
6458 jpp = &jp1->prev_job;
6464 /* newly stopped job - becomes curjob */
6465 jp->prev_job = *jpp;
6473 * Turn job control on and off.
6475 * Note: This code assumes that the third arg to ioctl is a character
6476 * pointer, which is true on Berkeley systems but not System V. Since
6477 * System V doesn't have job control yet, this isn't a problem now.
6479 * Called with interrupts off.
6488 if (on == jobctl || rootshell == 0)
6492 ofd = fd = open(_PATH_TTY, O_RDWR);
6495 while (!isatty(fd) && --fd >= 0)
6498 fd = fcntl(fd, F_DUPFD, 10);
6502 fcntl(fd, F_SETFD, FD_CLOEXEC);
6503 do { /* while we are in the background */
6504 if ((pgrp = tcgetpgrp(fd)) < 0) {
6506 sh_warnx("can't access tty; job control turned off");
6510 if (pgrp == getpgrp())
6521 xtcsetpgrp(fd, pgrp);
6523 /* turning job control off */
6526 xtcsetpgrp(fd, pgrp);
6540 killcmd(int argc, char **argv)
6551 "Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6552 "kill -l [exitstatus]"
6556 if (**++argv == '-') {
6557 signo = decode_signal(*argv + 1, 1);
6561 while ((c = nextopt("ls:")) != '\0')
6571 signo = decode_signal(optionarg, 1);
6574 "invalid signal number or name: %s",
6585 if (!list && signo < 0)
6588 if ((signo < 0 || !*argv) ^ list) {
6596 for (i = 1; i < NSIG; i++) {
6597 name = u_signal_names(0, &i, 1);
6599 out1fmt(snlfmt, name);
6603 name = u_signal_names(*argptr, &signo, -1);
6605 out1fmt(snlfmt, name);
6607 error("invalid signal number or exit status: %s", *argptr);
6613 if (**argv == '%') {
6614 jp = getjob(*argv, 0);
6615 pid = -jp->ps[0].pid;
6617 pid = number(*argv);
6618 if (kill(pid, signo) != 0) {
6628 #if defined(JOBS) || defined(DEBUG)
6630 jobno(const struct job *jp)
6632 return jp - jobtab + 1;
6638 fgcmd(int argc, char **argv)
6645 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
6650 jp = getjob(*argv, 1);
6651 if (mode == FORK_BG) {
6652 set_curjob(jp, CUR_RUNNING);
6653 fprintf(out, "[%d] ", jobno(jp));
6655 outstr(jp->ps->cmd, out);
6657 retval = restartjob(jp, mode);
6658 } while (*argv && *++argv);
6662 static int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
6666 restartjob(struct job *jp, int mode)
6668 struct procstat *ps;
6674 if (jp->state == JOBDONE)
6676 jp->state = JOBRUNNING;
6678 if (mode == FORK_FG)
6679 xtcsetpgrp(ttyfd, pgid);
6680 killpg(pgid, SIGCONT);
6684 if (WIFSTOPPED(ps->status)) {
6687 } while (ps++, --i);
6689 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
6696 sprint_status(char *s, int status, int sigonly)
6702 if (!WIFEXITED(status)) {
6704 if (WIFSTOPPED(status))
6705 st = WSTOPSIG(status);
6708 st = WTERMSIG(status);
6710 if (st == SIGINT || st == SIGPIPE)
6713 if (WIFSTOPPED(status))
6718 col = fmtstr(s, 32, strsignal(st));
6719 if (WCOREDUMP(status)) {
6720 col += fmtstr(s + col, 16, " (core dumped)");
6722 } else if (!sigonly) {
6723 st = WEXITSTATUS(status);
6725 col = fmtstr(s, 16, "Done(%d)", st);
6727 col = fmtstr(s, 16, "Done");
6736 showjob(FILE *out, struct job *jp, int mode)
6738 struct procstat *ps;
6739 struct procstat *psend;
6746 if (mode & SHOW_PGID) {
6747 /* just output process (group) id of pipeline */
6748 fprintf(out, "%d\n", ps->pid);
6752 col = fmtstr(s, 16, "[%d] ", jobno(jp));
6757 else if (curjob && jp == curjob->prev_job)
6760 if (mode & SHOW_PID)
6761 col += fmtstr(s + col, 16, "%d ", ps->pid);
6763 psend = ps + jp->nprocs;
6765 if (jp->state == JOBRUNNING) {
6766 scopy("Running", s + col);
6767 col += strlen("Running");
6769 int status = psend[-1].status;
6771 if (jp->state == JOBSTOPPED)
6772 status = jp->stopstatus;
6774 col += sprint_status(s + col, status, 0);
6780 /* for each process */
6781 col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
6784 fprintf(out, "%s%*c%s",
6785 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
6787 if (!(mode & SHOW_PID)) {
6791 if (++ps == psend) {
6792 outcslow('\n', out);
6799 if (jp->state == JOBDONE) {
6800 TRACE(("showjob: freeing job %d\n", jobno(jp)));
6807 jobscmd(int argc, char **argv)
6813 while ((m = nextopt("lp")))
6823 showjob(out, getjob(*argv,0), mode);
6826 showjobs(out, mode);
6833 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6834 * statuses have changed since the last call to showjobs.
6838 showjobs(FILE *out, int mode)
6842 TRACE(("showjobs(%x) called\n", mode));
6844 /* If not even one one job changed, there is nothing to do */
6845 while (dowait(DOWAIT_NORMAL, NULL) > 0)
6848 for (jp = curjob; jp; jp = jp->prev_job) {
6849 if (!(mode & SHOW_CHANGED) || jp->changed)
6850 showjob(out, jp, mode);
6856 * Mark a job structure as unused.
6860 freejob(struct job *jp)
6862 struct procstat *ps;
6866 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
6867 if (ps->cmd != nullstr)
6870 if (jp->ps != &jp->ps0)
6873 set_curjob(jp, CUR_DELETE);
6879 waitcmd(int argc, char **argv)
6892 /* wait for all jobs */
6897 /* no running procs */
6900 if (jp->state == JOBRUNNING)
6905 dowait(DOWAIT_BLOCK, 0);
6911 if (**argv != '%') {
6912 pid_t pid = number(*argv);
6916 if (job->ps[job->nprocs - 1].pid == pid)
6918 job = job->prev_job;
6924 job = getjob(*argv, 0);
6925 /* loop until process terminated or stopped */
6926 while (job->state == JOBRUNNING)
6927 dowait(DOWAIT_BLOCK, 0);
6929 retval = getstatus(job);
6940 * Convert a job name to a job structure.
6944 getjob(const char *name, int getctl)
6948 const char *err_msg = "No such job: %s";
6952 char *(*match)(const char *, const char *);
6967 if (c == '+' || c == '%') {
6969 err_msg = "No current job";
6971 } else if (c == '-') {
6974 err_msg = "No previous job";
6985 jp = jobtab + num - 1;
7002 if (match(jp->ps[0].cmd, p)) {
7006 err_msg = "%s: ambiguous";
7013 err_msg = "job %s not created under job control";
7014 if (getctl && jp->jobctl == 0)
7019 error(err_msg, name);
7024 * Return a new job structure.
7025 * Called with interrupts off.
7029 makejob(union node *node, int nprocs)
7034 for (i = njobs, jp = jobtab ; ; jp++) {
7041 if (jp->state != JOBDONE || !jp->waited)
7050 memset(jp, 0, sizeof(*jp));
7055 jp->prev_job = curjob;
7060 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
7062 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
7072 struct job *jp, *jq;
7074 len = njobs * sizeof(*jp);
7076 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
7078 offset = (char *)jp - (char *)jq;
7080 /* Relocate pointers */
7083 jq = (struct job *)((char *)jq + l);
7087 #define joff(p) ((struct job *)((char *)(p) + l))
7088 #define jmove(p) (p) = (void *)((char *)(p) + offset)
7089 if (xlikely(joff(jp)->ps == &jq->ps0))
7090 jmove(joff(jp)->ps);
7091 if (joff(jp)->prev_job)
7092 jmove(joff(jp)->prev_job);
7102 jp = (struct job *)((char *)jp + len);
7106 } while (--jq >= jp);
7112 * Fork off a subshell. If we are doing job control, give the subshell its
7113 * own process group. Jp is a job structure that the job is to be added to.
7114 * N is the command that will be evaluated by the child. Both jp and n may
7115 * be NULL. The mode parameter can be one of the following:
7116 * FORK_FG - Fork off a foreground process.
7117 * FORK_BG - Fork off a background process.
7118 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
7119 * process group even if job control is on.
7121 * When job control is turned off, background processes have their standard
7122 * input redirected to /dev/null (except for the second and later processes
7125 * Called with interrupts off.
7129 forkchild(struct job *jp, union node *n, int mode)
7133 TRACE(("Child shell %d\n", getpid()));
7134 wasroot = rootshell;
7140 /* do job control only in root shell */
7142 if (mode != FORK_NOJOB && jp->jobctl && wasroot) {
7145 if (jp->nprocs == 0)
7148 pgrp = jp->ps[0].pid;
7149 /* This can fail because we are doing it in the parent also */
7150 (void)setpgid(0, pgrp);
7151 if (mode == FORK_FG)
7152 xtcsetpgrp(ttyfd, pgrp);
7157 if (mode == FORK_BG) {
7160 if (jp->nprocs == 0) {
7162 if (open(_PATH_DEVNULL, O_RDONLY) != 0)
7163 error("Can't open %s", _PATH_DEVNULL);
7166 if (wasroot && iflag) {
7171 for (jp = curjob; jp; jp = jp->prev_job)
7177 forkparent(struct job *jp, union node *n, int mode, pid_t pid)
7179 TRACE(("In parent shell: child = %d\n", pid));
7181 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
7186 if (mode != FORK_NOJOB && jp->jobctl) {
7189 if (jp->nprocs == 0)
7192 pgrp = jp->ps[0].pid;
7193 /* This can fail because we are doing it in the child also */
7194 (void)setpgid(pid, pgrp);
7197 if (mode == FORK_BG) {
7198 backgndpid = pid; /* set $! */
7199 set_curjob(jp, CUR_RUNNING);
7202 struct procstat *ps = &jp->ps[jp->nprocs++];
7208 ps->cmd = commandtext(n);
7214 forkshell(struct job *jp, union node *n, int mode)
7218 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
7221 TRACE(("Fork failed, errno=%d", errno));
7224 error("Cannot fork");
7227 forkchild(jp, n, mode);
7229 forkparent(jp, n, mode, pid);
7234 * Wait for job to finish.
7236 * Under job control we have the problem that while a child process is
7237 * running interrupts generated by the user are sent to the child but not
7238 * to the shell. This means that an infinite loop started by an inter-
7239 * active user may be hard to kill. With job control turned off, an
7240 * interactive user may place an interactive program inside a loop. If
7241 * the interactive program catches interrupts, the user doesn't want
7242 * these interrupts to also abort the loop. The approach we take here
7243 * is to have the shell ignore interrupt signals while waiting for a
7244 * foreground process to terminate, and then send itself an interrupt
7245 * signal if the child process was terminated by an interrupt signal.
7246 * Unfortunately, some programs want to do a bit of cleanup and then
7247 * exit on interrupt; unless these processes terminate themselves by
7248 * sending a signal to themselves (instead of calling exit) they will
7249 * confuse this approach.
7251 * Called with interrupts off.
7255 waitforjob(struct job *jp)
7259 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
7260 while (jp->state == JOBRUNNING) {
7261 dowait(DOWAIT_BLOCK, jp);
7266 xtcsetpgrp(ttyfd, rootpid);
7268 * This is truly gross.
7269 * If we're doing job control, then we did a TIOCSPGRP which
7270 * caused us (the shell) to no longer be in the controlling
7271 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7272 * intuit from the subprocess exit status whether a SIGINT
7273 * occurred, and if so interrupt ourselves. Yuck. - mycroft
7278 if (jp->state == JOBDONE)
7286 * Do a wait system call. If job control is compiled in, we accept
7287 * stopped processes. If block is zero, we return a value of zero
7288 * rather than blocking.
7290 * System V doesn't have a non-blocking wait system call. It does
7291 * have a SIGCLD signal that is sent to a process when one of it's
7292 * children dies. The obvious way to use SIGCLD would be to install
7293 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7294 * was received, and have waitproc bump another counter when it got
7295 * the status of a process. Waitproc would then know that a wait
7296 * system call would not block if the two counters were different.
7297 * This approach doesn't work because if a process has children that
7298 * have not been waited for, System V will send it a SIGCLD when it
7299 * installs a signal handler for SIGCLD. What this means is that when
7300 * a child exits, the shell will be sent SIGCLD signals continuously
7301 * until is runs out of stack space, unless it does a wait call before
7302 * restoring the signal handler. The code below takes advantage of
7303 * this (mis)feature by installing a signal handler for SIGCLD and
7304 * then checking to see whether it was called. If there are any
7305 * children to be waited for, it will be.
7307 * If neither SYSV nor BSD is defined, we don't implement nonblocking
7308 * waits at all. In this case, the user will not be informed when
7309 * a background process until the next time she runs a real program
7310 * (as opposed to running a builtin command or just typing return),
7311 * and the jobs command may give out of date information.
7315 waitproc(int block, int *status)
7325 return wait3(status, flags, (struct rusage *)NULL);
7329 * Wait for a process to terminate.
7333 dowait(int block, struct job *job)
7338 struct job *thisjob;
7341 TRACE(("dowait(%d) called\n", block));
7342 pid = waitproc(block, &status);
7343 TRACE(("wait returns pid %d, status=%d\n", pid, status));
7348 for (jp = curjob; jp; jp = jp->prev_job) {
7349 struct procstat *sp;
7350 struct procstat *spend;
7351 if (jp->state == JOBDONE)
7354 spend = jp->ps + jp->nprocs;
7357 if (sp->pid == pid) {
7358 TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
7359 sp->status = status;
7362 if (sp->status == -1)
7365 if (state == JOBRUNNING)
7367 if (WIFSTOPPED(sp->status)) {
7368 jp->stopstatus = sp->status;
7372 } while (++sp < spend);
7377 if (!WIFSTOPPED(status))
7384 if (state != JOBRUNNING) {
7385 thisjob->changed = 1;
7387 if (thisjob->state != state) {
7388 TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
7389 thisjob->state = state;
7391 if (state == JOBSTOPPED) {
7392 set_curjob(thisjob, CUR_STOPPED);
7401 if (thisjob && thisjob == job) {
7405 len = sprint_status(s, status, 1);
7417 * return 1 if there are stopped jobs, otherwise 0
7430 if (jp && jp->state == JOBSTOPPED) {
7431 out2str("You have stopped jobs.\n");
7441 * Return a string identifying a command (to be printed by the
7446 static char *cmdnextc;
7449 commandtext(union node *n)
7453 STARTSTACKSTR(cmdnextc);
7455 name = stackblock();
7456 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
7457 name, cmdnextc, cmdnextc));
7458 return savestr(name);
7462 cmdtxt(union node *n)
7465 struct nodelist *lp;
7477 lp = n->npipe.cmdlist;
7495 cmdtxt(n->nbinary.ch1);
7511 cmdtxt(n->nif.test);
7514 if (n->nif.elsepart) {
7517 n = n->nif.elsepart;
7533 cmdtxt(n->nbinary.ch1);
7543 cmdputs(n->nfor.var);
7545 cmdlist(n->nfor.args, 1);
7550 cmdputs(n->narg.text);
7554 cmdlist(n->ncmd.args, 1);
7555 cmdlist(n->ncmd.redirect, 0);
7568 cmdputs(n->ncase.expr->narg.text);
7570 for (np = n->ncase.cases; np; np = np->nclist.next) {
7571 cmdtxt(np->nclist.pattern);
7573 cmdtxt(np->nclist.body);
7599 s[0] = n->nfile.fd + '0';
7603 if (n->type == NTOFD || n->type == NFROMFD) {
7604 s[0] = n->ndup.dupfd + '0';
7615 cmdlist(union node *np, int sep)
7617 for (; np; np = np->narg.next) {
7621 if (sep && np->narg.next)
7627 cmdputs(const char *s)
7629 const char *p, *str;
7630 char c, cc[2] = " ";
7634 static const char *const vstype[16] = {
7635 nullstr, "}", "-", "+", "?", "=",
7636 "%", "%%", "#", "##", nullstr
7639 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
7641 while ((c = *p++) != 0) {
7649 if ((subtype & VSTYPE) == VSLENGTH)
7653 if (!(subtype & VSQUOTE) != !(quoted & 1)) {
7671 case CTLBACKQ+CTLQUOTE:
7674 #ifdef CONFIG_ASH_MATH_SUPPORT
7689 str = vstype[subtype & VSTYPE];
7690 if (subtype & VSNUL)
7701 /* These can only happen inside quotes */
7713 while ((c = *str++)) {
7718 USTPUTC('"', nextc);
7726 showpipe(struct job *jp, FILE *out)
7728 struct procstat *sp;
7729 struct procstat *spend;
7731 spend = jp->ps + jp->nprocs;
7732 for (sp = jp->ps + 1; sp < spend; sp++)
7733 fprintf(out, " | %s", sp->cmd);
7734 outcslow('\n', out);
7739 xtcsetpgrp(int fd, pid_t pgrp)
7741 if (tcsetpgrp(fd, pgrp))
7742 error("Cannot set tty process group (%m)");
7747 getstatus(struct job *job) {
7751 status = job->ps[job->nprocs - 1].status;
7752 retval = WEXITSTATUS(status);
7753 if (!WIFEXITED(status)) {
7755 retval = WSTOPSIG(status);
7756 if (!WIFSTOPPED(status))
7759 /* XXX: limits number of signals */
7760 retval = WTERMSIG(status);
7762 if (retval == SIGINT)
7768 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
7769 jobno(job), job->nprocs, status, retval));
7773 #ifdef CONFIG_ASH_MAIL
7774 /* $NetBSD: mail.c,v 1.15 2002/11/24 22:35:40 christos Exp $ */
7777 * Routines to check for mail. (Perhaps make part of main.c?)
7780 #define MAXMBOXES 10
7782 /* times of mailboxes */
7783 static time_t mailtime[MAXMBOXES];
7784 /* Set if MAIL or MAILPATH is changed. */
7785 static int mail_var_path_changed;
7790 * Print appropriate message(s) if mail has arrived.
7791 * If mail_var_path_changed is set,
7792 * then the value of MAIL has mail_var_path_changed,
7793 * so we just update the values.
7803 struct stackmark smark;
7806 setstackmark(&smark);
7807 mpath = mpathset() ? mpathval() : mailval();
7808 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
7809 p = padvance(&mpath, nullstr);
7814 for (q = p ; *q ; q++);
7819 q[-1] = '\0'; /* delete trailing '/' */
7820 if (stat(p, &statb) < 0) {
7824 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
7827 pathopt ? pathopt : "you have mail"
7830 *mtp = statb.st_mtime;
7832 mail_var_path_changed = 0;
7833 popstackmark(&smark);
7838 changemail(const char *val)
7840 mail_var_path_changed++;
7843 #endif /* CONFIG_ASH_MAIL */
7845 /* $NetBSD: main.c,v 1.46 2002/12/11 19:12:18 christos Exp $ */
7849 static short profile_buf[16384];
7853 static int isloginsh;
7855 static void read_profile(const char *);
7858 * Main routine. We initialize things, parse the arguments, execute
7859 * profiles if we're a login shell, and then call cmdloop to execute
7860 * commands. The setjmp call sets up the location to jump to when an
7861 * exception occurs. When an exception occurs the variable "state"
7862 * is used to figure out how far we had gotten.
7866 ash_main(int argc, char **argv)
7870 struct jmploc jmploc;
7871 struct stackmark smark;
7874 dash_errno = __errno_location();
7878 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7881 if (setjmp(jmploc.loc)) {
7888 switch (exception) {
7898 status = exitstatus;
7901 exitstatus = status;
7903 if (e == EXEXIT || state == 0 || iflag == 0 || ! rootshell)
7907 outcslow('\n', stderr);
7909 popstackmark(&smark);
7910 FORCEINTON; /* enable interrupts */
7913 else if (state == 2)
7915 else if (state == 3)
7923 trputs("Shell args: "); trargs(argv);
7927 #ifdef CONFIG_ASH_RANDOM_SUPPORT
7928 rseed = rootpid + ((time_t)time((time_t *)0));
7932 setstackmark(&smark);
7933 procargs(argc, argv);
7934 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7936 const char *hp = lookupvar("HISTFILE");
7939 hp = lookupvar("HOME");
7941 char *defhp = concat_path_file(hp, ".ash_history");
7942 setvar("HISTFILE", defhp, 0);
7948 if (argv[0] && argv[0][0] == '-')
7952 read_profile("/etc/profile");
7955 read_profile(".profile");
7961 getuid() == geteuid() && getgid() == getegid() &&
7965 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
7966 read_profile(shinit);
7974 if (sflag || minusc == NULL) {
7975 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7977 const char *hp = lookupvar("HISTFILE");
7980 load_history ( hp );
7983 state4: /* XXX ??? - why isn't this before the "if" statement */
7991 extern void _mcleanup(void);
8001 * Read and execute commands. "Top" is nonzero for the top level command
8002 * loop; it turns on prompting if the shell is interactive.
8009 struct stackmark smark;
8013 TRACE(("cmdloop(%d) called\n", top));
8015 setstackmark(&smark);
8020 showjobs(stderr, SHOW_CHANGED);
8025 #ifdef CONFIG_ASH_MAIL
8029 n = parsecmd(inter);
8030 /* showtree(n); DEBUG */
8032 if (!top || numeof >= 50)
8034 if (!stoppedjobs()) {
8037 out2str("\nUse \"exit\" to leave shell.\n");
8040 } else if (n != NULL && nflag == 0) {
8041 job_warning = (job_warning == 2) ? 1 : 0;
8045 popstackmark(&smark);
8055 * Read /etc/profile or .profile. Return on error.
8059 read_profile(const char *name)
8066 if ((fd = open(name, O_RDONLY)) >= 0)
8071 /* -q turns off -x and -v just when executing init files */
8074 xflag = 0, xflag_set = 1;
8076 vflag = 0, vflag_set = 1;
8090 * Read a file containing shell functions.
8094 readcmdfile(char *name)
8099 if ((fd = open(name, O_RDONLY)) >= 0)
8102 error("Can't open %s", name);
8110 * Take commands from a file. To be compatible we should do a path
8111 * search for the file, which is necessary to find sub-commands.
8114 static inline char *
8115 find_dot_file(char *name)
8118 const char *path = pathval();
8121 /* don't try this for absolute or relative paths */
8122 if (strchr(name, '/'))
8125 while ((fullname = padvance(&path, name)) != NULL) {
8126 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
8128 * Don't bother freeing here, since it will
8129 * be freed by the caller.
8133 stunalloc(fullname);
8136 /* not found in the PATH */
8137 error(not_found_msg, name);
8141 static int dotcmd(int argc, char **argv)
8144 volatile struct shparam saveparam;
8148 for (sp = cmdenviron; sp; sp = sp->next)
8149 setvareq(bb_xstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
8151 if (argc >= 2) { /* That's what SVR2 does */
8153 struct stackmark smark;
8155 setstackmark(&smark);
8156 fullname = find_dot_file(argv[1]);
8159 saveparam = shellparam;
8160 shellparam.malloc = 0;
8161 shellparam.nparam = argc - 2;
8162 shellparam.p = argv + 2;
8165 setinputfile(fullname, 1);
8166 commandname = fullname;
8171 freeparam(&shellparam);
8172 shellparam = saveparam;
8175 popstackmark(&smark);
8182 exitcmd(int argc, char **argv)
8187 exitstatus = number(argv[1]);
8192 /* $NetBSD: memalloc.c,v 1.27 2003/01/22 20:36:04 dsl Exp $ */
8195 * Same for malloc, realloc, but returns an error when out of space.
8199 ckrealloc(pointer p, size_t nbytes)
8201 p = realloc(p, nbytes);
8203 error(bb_msg_memory_exhausted);
8208 ckmalloc(size_t nbytes)
8210 return ckrealloc(NULL, nbytes);
8214 * Make a copy of a string in safe storage.
8218 savestr(const char *s)
8220 char *p = strdup(s);
8222 error(bb_msg_memory_exhausted);
8228 * Parse trees for commands are allocated in lifo order, so we use a stack
8229 * to make this more efficient, and also to avoid all sorts of exception
8230 * handling code to handle interrupts in the middle of a parse.
8232 * The size 504 was chosen because the Ultrix malloc handles that size
8238 stalloc(size_t nbytes)
8243 aligned = SHELL_ALIGN(nbytes);
8244 if (aligned > stacknleft) {
8247 struct stack_block *sp;
8249 blocksize = aligned;
8250 if (blocksize < MINSIZE)
8251 blocksize = MINSIZE;
8252 len = sizeof(struct stack_block) - MINSIZE + blocksize;
8253 if (len < blocksize)
8254 error(bb_msg_memory_exhausted);
8258 stacknxt = sp->space;
8259 stacknleft = blocksize;
8260 sstrend = stacknxt + blocksize;
8265 stacknxt += aligned;
8266 stacknleft -= aligned;
8272 stunalloc(pointer p)
8275 if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
8276 write(2, "stunalloc\n", 10);
8280 stacknleft += stacknxt - (char *)p;
8286 setstackmark(struct stackmark *mark)
8288 mark->stackp = stackp;
8289 mark->stacknxt = stacknxt;
8290 mark->stacknleft = stacknleft;
8291 mark->marknext = markp;
8297 popstackmark(struct stackmark *mark)
8299 struct stack_block *sp;
8302 markp = mark->marknext;
8303 while (stackp != mark->stackp) {
8308 stacknxt = mark->stacknxt;
8309 stacknleft = mark->stacknleft;
8310 sstrend = mark->stacknxt + mark->stacknleft;
8316 * When the parser reads in a string, it wants to stick the string on the
8317 * stack and only adjust the stack pointer when it knows how big the
8318 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8319 * of space on top of the stack and stackblocklen returns the length of
8320 * this block. Growstackblock will grow this space by at least one byte,
8321 * possibly moving it (like realloc). Grabstackblock actually allocates the
8322 * part of the block that has been used.
8326 growstackblock(void)
8330 newlen = stacknleft * 2;
8331 if (newlen < stacknleft)
8332 error(bb_msg_memory_exhausted);
8336 if (stacknxt == stackp->space && stackp != &stackbase) {
8337 struct stack_block *oldstackp;
8338 struct stackmark *xmark;
8339 struct stack_block *sp;
8340 struct stack_block *prevstackp;
8346 prevstackp = sp->prev;
8347 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
8348 sp = ckrealloc((pointer)sp, grosslen);
8349 sp->prev = prevstackp;
8351 stacknxt = sp->space;
8352 stacknleft = newlen;
8353 sstrend = sp->space + newlen;
8356 * Stack marks pointing to the start of the old block
8357 * must be relocated to point to the new block
8360 while (xmark != NULL && xmark->stackp == oldstackp) {
8361 xmark->stackp = stackp;
8362 xmark->stacknxt = stacknxt;
8363 xmark->stacknleft = stacknleft;
8364 xmark = xmark->marknext;
8368 char *oldspace = stacknxt;
8369 int oldlen = stacknleft;
8370 char *p = stalloc(newlen);
8372 /* free the space we just allocated */
8373 stacknxt = memcpy(p, oldspace, oldlen);
8374 stacknleft += newlen;
8379 grabstackblock(size_t len)
8381 len = SHELL_ALIGN(len);
8387 * The following routines are somewhat easier to use than the above.
8388 * The user declares a variable of type STACKSTR, which may be declared
8389 * to be a register. The macro STARTSTACKSTR initializes things. Then
8390 * the user uses the macro STPUTC to add characters to the string. In
8391 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8392 * grown as necessary. When the user is done, she can just leave the
8393 * string there and refer to it using stackblock(). Or she can allocate
8394 * the space for it using grabstackstr(). If it is necessary to allow
8395 * someone else to use the stack temporarily and then continue to grow
8396 * the string, the user should use grabstack to allocate the space, and
8397 * then call ungrabstr(p) to return to the previous mode of operation.
8399 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8400 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8401 * is space for at least one character.
8407 size_t len = stackblocksize();
8408 if (herefd >= 0 && len >= 1024) {
8409 bb_full_write(herefd, stackblock(), len);
8410 return stackblock();
8413 return stackblock() + len;
8417 * Called from CHECKSTRSPACE.
8421 makestrspace(size_t newlen, char *p)
8423 size_t len = p - stacknxt;
8424 size_t size = stackblocksize();
8429 size = stackblocksize();
8431 if (nleft >= newlen)
8435 return stackblock() + len;
8439 stnputs(const char *s, size_t n, char *p)
8441 p = makestrspace(n, p);
8442 p = mempcpy(p, s, n);
8447 stputs(const char *s, char *p)
8449 return stnputs(s, strlen(s), p);
8452 /* $NetBSD: mystring.c,v 1.15 2002/11/24 22:35:42 christos Exp $ */
8457 * number(s) Convert a string of digits to an integer.
8458 * is_number(s) Return true if s is a string of digits.
8462 * prefix -- see if pfx is a prefix of string.
8466 prefix(const char *string, const char *pfx)
8469 if (*pfx++ != *string++)
8472 return (char *) string;
8477 * Convert a string of digits to an integer, printing an error message on
8482 number(const char *s)
8492 * Check for a valid number. This should be elsewhere.
8496 is_number(const char *p)
8501 } while (*++p != '\0');
8507 * Produce a possibly single quoted string suitable as input to the shell.
8508 * The return string is allocated on the stack.
8512 single_quote(const char *s) {
8521 len = strchrnul(s, '\'') - s;
8523 q = p = makestrspace(len + 3, p);
8526 q = mempcpy(q, s, len);
8532 len = strspn(s, "'");
8536 q = p = makestrspace(len + 3, p);
8539 q = mempcpy(q, s, len);
8548 return stackblock();
8552 * Like strdup but works with the ash stack.
8556 sstrdup(const char *p)
8558 size_t len = strlen(p) + 1;
8559 return memcpy(stalloc(len), p, len);
8564 calcsize(union node *n)
8568 funcblocksize += nodesize[n->type];
8571 calcsize(n->ncmd.redirect);
8572 calcsize(n->ncmd.args);
8573 calcsize(n->ncmd.assign);
8576 sizenodelist(n->npipe.cmdlist);
8581 calcsize(n->nredir.redirect);
8582 calcsize(n->nredir.n);
8589 calcsize(n->nbinary.ch2);
8590 calcsize(n->nbinary.ch1);
8593 calcsize(n->nif.elsepart);
8594 calcsize(n->nif.ifpart);
8595 calcsize(n->nif.test);
8598 funcstringsize += strlen(n->nfor.var) + 1;
8599 calcsize(n->nfor.body);
8600 calcsize(n->nfor.args);
8603 calcsize(n->ncase.cases);
8604 calcsize(n->ncase.expr);
8607 calcsize(n->nclist.body);
8608 calcsize(n->nclist.pattern);
8609 calcsize(n->nclist.next);
8613 sizenodelist(n->narg.backquote);
8614 funcstringsize += strlen(n->narg.text) + 1;
8615 calcsize(n->narg.next);
8622 calcsize(n->nfile.fname);
8623 calcsize(n->nfile.next);
8627 calcsize(n->ndup.vname);
8628 calcsize(n->ndup.next);
8632 calcsize(n->nhere.doc);
8633 calcsize(n->nhere.next);
8636 calcsize(n->nnot.com);
8643 sizenodelist(struct nodelist *lp)
8646 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8654 copynode(union node *n)
8661 funcblock = (char *) funcblock + nodesize[n->type];
8664 new->ncmd.redirect = copynode(n->ncmd.redirect);
8665 new->ncmd.args = copynode(n->ncmd.args);
8666 new->ncmd.assign = copynode(n->ncmd.assign);
8669 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8670 new->npipe.backgnd = n->npipe.backgnd;
8675 new->nredir.redirect = copynode(n->nredir.redirect);
8676 new->nredir.n = copynode(n->nredir.n);
8683 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8684 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8687 new->nif.elsepart = copynode(n->nif.elsepart);
8688 new->nif.ifpart = copynode(n->nif.ifpart);
8689 new->nif.test = copynode(n->nif.test);
8692 new->nfor.var = nodesavestr(n->nfor.var);
8693 new->nfor.body = copynode(n->nfor.body);
8694 new->nfor.args = copynode(n->nfor.args);
8697 new->ncase.cases = copynode(n->ncase.cases);
8698 new->ncase.expr = copynode(n->ncase.expr);
8701 new->nclist.body = copynode(n->nclist.body);
8702 new->nclist.pattern = copynode(n->nclist.pattern);
8703 new->nclist.next = copynode(n->nclist.next);
8707 new->narg.backquote = copynodelist(n->narg.backquote);
8708 new->narg.text = nodesavestr(n->narg.text);
8709 new->narg.next = copynode(n->narg.next);
8716 new->nfile.fname = copynode(n->nfile.fname);
8717 new->nfile.fd = n->nfile.fd;
8718 new->nfile.next = copynode(n->nfile.next);
8722 new->ndup.vname = copynode(n->ndup.vname);
8723 new->ndup.dupfd = n->ndup.dupfd;
8724 new->ndup.fd = n->ndup.fd;
8725 new->ndup.next = copynode(n->ndup.next);
8729 new->nhere.doc = copynode(n->nhere.doc);
8730 new->nhere.fd = n->nhere.fd;
8731 new->nhere.next = copynode(n->nhere.next);
8734 new->nnot.com = copynode(n->nnot.com);
8737 new->type = n->type;
8742 static struct nodelist *
8743 copynodelist(struct nodelist *lp)
8745 struct nodelist *start;
8746 struct nodelist **lpp;
8751 funcblock = (char *) funcblock +
8752 SHELL_ALIGN(sizeof(struct nodelist));
8753 (*lpp)->n = copynode(lp->n);
8755 lpp = &(*lpp)->next;
8763 nodesavestr(char *s)
8765 char *rtn = funcstring;
8767 funcstring = stpcpy(funcstring, s) + 1;
8773 * Free a parse tree.
8777 freefunc(struct funcnode *f)
8779 if (f && --f->count < 0)
8784 static void options(int);
8785 static void setoption(int, int);
8789 * Process the shell command line arguments.
8793 procargs(int argc, char **argv)
8796 const char *xminusc;
8803 for (i = 0; i < NOPTS; i++)
8809 if (*xargv == NULL) {
8811 error("-c requires an argument");
8814 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8818 for (i = 0; i < NOPTS; i++)
8819 if (optlist[i] == 2)
8824 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8829 } else if (!sflag) {
8830 setinputfile(*xargv, 0);
8836 shellparam.p = xargv;
8837 #ifdef CONFIG_ASH_GETOPTS
8838 shellparam.optind = 1;
8839 shellparam.optoff = -1;
8841 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
8843 shellparam.nparam++;
8856 setinteractive(iflag);
8861 minus_o(char *name, int val)
8866 out1str("Current option settings\n");
8867 for (i = 0; i < NOPTS; i++)
8868 out1fmt("%-16s%s\n", optnames(i),
8869 optlist[i] ? "on" : "off");
8871 for (i = 0; i < NOPTS; i++)
8872 if (equal(name, optnames(i))) {
8876 error("Illegal option -o %s", name);
8881 * Process shell options. The global variable argptr contains a pointer
8882 * to the argument list; we advance it past the options.
8886 options(int cmdline)
8894 while ((p = *argptr) != NULL) {
8896 if ((c = *p++) == '-') {
8898 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8900 /* "-" means turn off -x and -v */
8903 /* "--" means reset params */
8904 else if (*argptr == NULL)
8907 break; /* "-" or "--" terminates options */
8909 } else if (c == '+') {
8915 while ((c = *p++) != '\0') {
8916 if (c == 'c' && cmdline) {
8917 minusc = p; /* command is after shell args*/
8918 } else if (c == 'o') {
8919 minus_o(*argptr, val);
8922 } else if (cmdline && (c == '-')) { // long options
8923 if (strcmp(p, "login") == 0)
8935 setoption(int flag, int val)
8939 for (i = 0; i < NOPTS; i++)
8940 if (optletters(i) == flag) {
8944 error("Illegal option -%c", flag);
8951 * Set the shell parameters.
8955 setparam(char **argv)
8961 for (nparam = 0 ; argv[nparam] ; nparam++);
8962 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
8964 *ap++ = savestr(*argv++);
8967 freeparam(&shellparam);
8968 shellparam.malloc = 1;
8969 shellparam.nparam = nparam;
8970 shellparam.p = newparam;
8971 #ifdef CONFIG_ASH_GETOPTS
8972 shellparam.optind = 1;
8973 shellparam.optoff = -1;
8979 * Free the list of positional parameters.
8983 freeparam(volatile struct shparam *param)
8987 if (param->malloc) {
8988 for (ap = param->p ; *ap ; ap++)
8997 * The shift builtin command.
9001 shiftcmd(int argc, char **argv)
9008 n = number(argv[1]);
9009 if (n > shellparam.nparam)
9010 error("can't shift that many");
9012 shellparam.nparam -= n;
9013 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
9014 if (shellparam.malloc)
9018 while ((*ap2++ = *ap1++) != NULL);
9019 #ifdef CONFIG_ASH_GETOPTS
9020 shellparam.optind = 1;
9021 shellparam.optoff = -1;
9030 * The set command builtin.
9034 setcmd(int argc, char **argv)
9037 return showvars(nullstr, 0, VUNSET);
9041 if (*argptr != NULL) {
9049 #ifdef CONFIG_ASH_GETOPTS
9054 shellparam.optind = number(value);
9055 shellparam.optoff = -1;
9059 #ifdef CONFIG_LOCALE_SUPPORT
9060 static void change_lc_all(const char *value)
9062 if (value != 0 && *value != 0)
9063 setlocale(LC_ALL, value);
9066 static void change_lc_ctype(const char *value)
9068 if (value != 0 && *value != 0)
9069 setlocale(LC_CTYPE, value);
9074 #ifdef CONFIG_ASH_RANDOM_SUPPORT
9075 /* Roughly copied from bash.. */
9076 static void change_random(const char *value)
9079 /* "get", generate */
9082 rseed = rseed * 1103515245 + 12345;
9083 sprintf(buf, "%d", (unsigned int)((rseed & 32767)));
9084 /* set without recursion */
9085 setvar(vrandom.text, buf, VNOFUNC);
9086 vrandom.flags &= ~VNOFUNC;
9089 rseed = strtoul(value, (char **)NULL, 10);
9095 #ifdef CONFIG_ASH_GETOPTS
9097 getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
9106 if(*param_optind < 1)
9108 optnext = optfirst + *param_optind - 1;
9110 if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff)
9113 p = optnext[-1] + *optoff;
9114 if (p == NULL || *p == '\0') {
9115 /* Current word is done, advance */
9117 if (p == NULL || *p != '-' || *++p == '\0') {
9124 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
9129 for (q = optstr; *q != c; ) {
9131 if (optstr[0] == ':') {
9134 err |= setvarsafe("OPTARG", s, 0);
9136 fprintf(stderr, "Illegal option -%c\n", c);
9137 (void) unsetvar("OPTARG");
9147 if (*p == '\0' && (p = *optnext) == NULL) {
9148 if (optstr[0] == ':') {
9151 err |= setvarsafe("OPTARG", s, 0);
9154 fprintf(stderr, "No arg for -%c option\n", c);
9155 (void) unsetvar("OPTARG");
9163 err |= setvarsafe("OPTARG", p, 0);
9166 err |= setvarsafe("OPTARG", nullstr, 0);
9169 *optoff = p ? p - *(optnext - 1) : -1;
9170 *param_optind = optnext - optfirst + 1;
9171 fmtstr(s, sizeof(s), "%d", *param_optind);
9172 err |= setvarsafe("OPTIND", s, VNOFUNC);
9175 err |= setvarsafe(optvar, s, 0);
9186 * The getopts builtin. Shellparam.optnext points to the next argument
9187 * to be processed. Shellparam.optptr points to the next character to
9188 * be processed in the current argument. If shellparam.optnext is NULL,
9189 * then it's the first time getopts has been called.
9193 getoptscmd(int argc, char **argv)
9198 error("Usage: getopts optstring var [arg]");
9199 else if (argc == 3) {
9200 optbase = shellparam.p;
9201 if (shellparam.optind > shellparam.nparam + 1) {
9202 shellparam.optind = 1;
9203 shellparam.optoff = -1;
9208 if (shellparam.optind > argc - 2) {
9209 shellparam.optind = 1;
9210 shellparam.optoff = -1;
9214 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9215 &shellparam.optoff);
9217 #endif /* CONFIG_ASH_GETOPTS */
9220 * XXX - should get rid of. have all builtins use getopt(3). the
9221 * library getopt must have the BSD extension static variable "optreset"
9222 * otherwise it can't be used within the shell safely.
9224 * Standard option processing (a la getopt) for builtin routines. The
9225 * only argument that is passed to nextopt is the option string; the
9226 * other arguments are unnecessary. It return the character, or '\0' on
9231 nextopt(const char *optstring)
9237 if ((p = optptr) == NULL || *p == '\0') {
9239 if (p == NULL || *p != '-' || *++p == '\0')
9242 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
9246 for (q = optstring ; *q != c ; ) {
9248 error("Illegal option -%c", c);
9253 if (*p == '\0' && (p = *argptr++) == NULL)
9254 error("No arg for -%c option", c);
9263 /* $NetBSD: output.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
9266 outstr(const char *p, FILE *file)
9291 outcslow(int c, FILE *dest)
9301 out1fmt(const char *fmt, ...)
9308 r = vprintf(fmt, ap);
9316 fmtstr(char *outbuf, size_t length, const char *fmt, ...)
9323 ret = vsnprintf(outbuf, length, fmt, ap);
9331 /* $NetBSD: parser.c,v 1.54 2002/11/24 22:35:42 christos Exp $ */
9335 * Shell command parser.
9338 #define EOFMARKLEN 79
9342 struct heredoc *next; /* next here document in list */
9343 union node *here; /* redirection node */
9344 char *eofmark; /* string indicating end of input */
9345 int striptabs; /* if set, strip leading tabs */
9350 static struct heredoc *heredoclist; /* list of here documents to read */
9353 static union node *list(int);
9354 static union node *andor(void);
9355 static union node *pipeline(void);
9356 static union node *command(void);
9357 static union node *simplecmd(void);
9358 static union node *makename(void);
9359 static void parsefname(void);
9360 static void parseheredoc(void);
9361 static char peektoken(void);
9362 static int readtoken(void);
9363 static int xxreadtoken(void);
9364 static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
9365 static int noexpand(char *);
9366 static void synexpect(int) __attribute__((__noreturn__));
9367 static void synerror(const char *) __attribute__((__noreturn__));
9368 static void setprompt(int);
9373 isassignment(const char *p)
9375 const char *q = endofname(p);
9383 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9384 * valid parse tree indicating a blank line.)
9388 parsecmd(int interact)
9393 doprompt = interact;
9395 setprompt(doprompt);
9410 union node *n1, *n2, *n3;
9413 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9414 if (nlflag == 2 && peektoken())
9420 if (tok == TBACKGND) {
9421 if (n2->type == NPIPE) {
9422 n2->npipe.backgnd = 1;
9424 if (n2->type != NREDIR) {
9425 n3 = stalloc(sizeof(struct nredir));
9427 n3->nredir.redirect = NULL;
9430 n2->type = NBACKGND;
9437 n3 = (union node *)stalloc(sizeof (struct nbinary));
9439 n3->nbinary.ch1 = n1;
9440 n3->nbinary.ch2 = n2;
9456 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9464 pungetc(); /* push back EOF on input */
9480 union node *n1, *n2, *n3;
9485 if ((t = readtoken()) == TAND) {
9487 } else if (t == TOR) {
9493 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9495 n3 = (union node *)stalloc(sizeof (struct nbinary));
9497 n3->nbinary.ch1 = n1;
9498 n3->nbinary.ch2 = n2;
9508 union node *n1, *n2, *pipenode;
9509 struct nodelist *lp, *prev;
9513 TRACE(("pipeline: entered\n"));
9514 if (readtoken() == TNOT) {
9516 checkkwd = CHKKWD | CHKALIAS;
9520 if (readtoken() == TPIPE) {
9521 pipenode = (union node *)stalloc(sizeof (struct npipe));
9522 pipenode->type = NPIPE;
9523 pipenode->npipe.backgnd = 0;
9524 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9525 pipenode->npipe.cmdlist = lp;
9529 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9530 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9533 } while (readtoken() == TPIPE);
9539 n2 = (union node *)stalloc(sizeof (struct nnot));
9552 union node *n1, *n2;
9553 union node *ap, **app;
9554 union node *cp, **cpp;
9555 union node *redir, **rpp;
9562 switch (readtoken()) {
9567 n1 = (union node *)stalloc(sizeof (struct nif));
9569 n1->nif.test = list(0);
9570 if (readtoken() != TTHEN)
9572 n1->nif.ifpart = list(0);
9574 while (readtoken() == TELIF) {
9575 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
9576 n2 = n2->nif.elsepart;
9578 n2->nif.test = list(0);
9579 if (readtoken() != TTHEN)
9581 n2->nif.ifpart = list(0);
9583 if (lasttoken == TELSE)
9584 n2->nif.elsepart = list(0);
9586 n2->nif.elsepart = NULL;
9594 n1 = (union node *)stalloc(sizeof (struct nbinary));
9595 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
9596 n1->nbinary.ch1 = list(0);
9597 if ((got=readtoken()) != TDO) {
9598 TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
9601 n1->nbinary.ch2 = list(0);
9606 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9607 synerror("Bad for loop variable");
9608 n1 = (union node *)stalloc(sizeof (struct nfor));
9610 n1->nfor.var = wordtext;
9611 checkkwd = CHKKWD | CHKALIAS;
9612 if (readtoken() == TIN) {
9614 while (readtoken() == TWORD) {
9615 n2 = (union node *)stalloc(sizeof (struct narg));
9617 n2->narg.text = wordtext;
9618 n2->narg.backquote = backquotelist;
9620 app = &n2->narg.next;
9624 if (lasttoken != TNL && lasttoken != TSEMI)
9627 n2 = (union node *)stalloc(sizeof (struct narg));
9629 n2->narg.text = (char *)dolatstr;
9630 n2->narg.backquote = NULL;
9631 n2->narg.next = NULL;
9634 * Newline or semicolon here is optional (but note
9635 * that the original Bourne shell only allowed NL).
9637 if (lasttoken != TNL && lasttoken != TSEMI)
9640 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9641 if (readtoken() != TDO)
9643 n1->nfor.body = list(0);
9647 n1 = (union node *)stalloc(sizeof (struct ncase));
9649 if (readtoken() != TWORD)
9651 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
9653 n2->narg.text = wordtext;
9654 n2->narg.backquote = backquotelist;
9655 n2->narg.next = NULL;
9657 checkkwd = CHKKWD | CHKALIAS;
9658 } while (readtoken() == TNL);
9659 if (lasttoken != TIN)
9661 cpp = &n1->ncase.cases;
9663 checkkwd = CHKNL | CHKKWD;
9666 if (lasttoken == TLP)
9668 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
9670 app = &cp->nclist.pattern;
9672 *app = ap = (union node *)stalloc(sizeof (struct narg));
9674 ap->narg.text = wordtext;
9675 ap->narg.backquote = backquotelist;
9676 if (readtoken() != TPIPE)
9678 app = &ap->narg.next;
9681 ap->narg.next = NULL;
9682 if (lasttoken != TRP)
9684 cp->nclist.body = list(2);
9686 cpp = &cp->nclist.next;
9688 checkkwd = CHKNL | CHKKWD;
9689 if ((t = readtoken()) != TESAC) {
9691 synexpect(TENDCASE);
9699 n1 = (union node *)stalloc(sizeof (struct nredir));
9700 n1->type = NSUBSHELL;
9701 n1->nredir.n = list(0);
9702 n1->nredir.redirect = NULL;
9715 if (readtoken() != t)
9719 /* Now check for redirection which may follow command */
9720 checkkwd = CHKKWD | CHKALIAS;
9722 while (readtoken() == TREDIR) {
9723 *rpp = n2 = redirnode;
9724 rpp = &n2->nfile.next;
9730 if (n1->type != NSUBSHELL) {
9731 n2 = (union node *)stalloc(sizeof (struct nredir));
9736 n1->nredir.redirect = redir;
9745 union node *args, **app;
9746 union node *n = NULL;
9747 union node *vars, **vpp;
9748 union node **rpp, *redir;
9758 savecheckkwd = CHKALIAS;
9760 checkkwd = savecheckkwd;
9761 switch (readtoken()) {
9763 n = (union node *)stalloc(sizeof (struct narg));
9765 n->narg.text = wordtext;
9766 n->narg.backquote = backquotelist;
9767 if (savecheckkwd && isassignment(wordtext)) {
9769 vpp = &n->narg.next;
9772 app = &n->narg.next;
9777 *rpp = n = redirnode;
9778 rpp = &n->nfile.next;
9779 parsefname(); /* read name of redirection file */
9783 args && app == &args->narg.next &&
9786 struct builtincmd *bcmd;
9789 /* We have a function */
9790 if (readtoken() != TRP)
9792 name = n->narg.text;
9794 !goodname(name) || (
9795 (bcmd = find_builtin(name)) &&
9796 IS_BUILTIN_SPECIAL(bcmd)
9799 synerror("Bad function name");
9801 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9802 n->narg.next = command();
9815 n = (union node *)stalloc(sizeof (struct ncmd));
9817 n->ncmd.args = args;
9818 n->ncmd.assign = vars;
9819 n->ncmd.redirect = redir;
9828 n = (union node *)stalloc(sizeof (struct narg));
9830 n->narg.next = NULL;
9831 n->narg.text = wordtext;
9832 n->narg.backquote = backquotelist;
9836 void fixredir(union node *n, const char *text, int err)
9838 TRACE(("Fix redir %s %d\n", text, err));
9840 n->ndup.vname = NULL;
9842 if (is_digit(text[0]) && text[1] == '\0')
9843 n->ndup.dupfd = digit_val(text[0]);
9844 else if (text[0] == '-' && text[1] == '\0')
9849 synerror("Bad fd number");
9851 n->ndup.vname = makename();
9859 union node *n = redirnode;
9861 if (readtoken() != TWORD)
9863 if (n->type == NHERE) {
9864 struct heredoc *here = heredoc;
9870 TRACE(("Here document %d\n", n->type));
9871 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
9872 synerror("Illegal eof marker for << redirection");
9873 rmescapes(wordtext);
9874 here->eofmark = wordtext;
9876 if (heredoclist == NULL)
9879 for (p = heredoclist ; p->next ; p = p->next);
9882 } else if (n->type == NTOFD || n->type == NFROMFD) {
9883 fixredir(n, wordtext, 0);
9885 n->nfile.fname = makename();
9891 * Input any here documents.
9897 struct heredoc *here;
9908 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9909 here->eofmark, here->striptabs);
9910 n = (union node *)stalloc(sizeof (struct narg));
9911 n->narg.type = NARG;
9912 n->narg.next = NULL;
9913 n->narg.text = wordtext;
9914 n->narg.backquote = backquotelist;
9915 here->here->nhere.doc = n;
9920 static char peektoken(void)
9926 return tokname_array[t][0];
9934 int alreadyseen = tokpushback;
9937 #ifdef CONFIG_ASH_ALIAS
9946 if (checkkwd & CHKNL) {
9953 if (t != TWORD || quoteflag) {
9958 * check for keywords
9960 if (checkkwd & CHKKWD) {
9961 const char *const *pp;
9963 if ((pp = findkwd(wordtext))) {
9964 lasttoken = t = pp - tokname_array;
9965 TRACE(("keyword %s recognized\n", tokname(t)));
9970 if (checkkwd & CHKALIAS) {
9971 #ifdef CONFIG_ASH_ALIAS
9973 if ((ap = lookupalias(wordtext, 1)) != NULL) {
9975 pushstring(ap->val, ap);
9985 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
9987 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
9994 * Read the next input token.
9995 * If the token is a word, we set backquotelist to the list of cmds in
9996 * backquotes. We set quoteflag to true if any part of the word was
9998 * If the token is TREDIR, then we set redirnode to a structure containing
10000 * In all cases, the variable startlinno is set to the number of the line
10001 * on which the token starts.
10003 * [Change comment: here documents and internal procedures]
10004 * [Readtoken shouldn't have any arguments. Perhaps we should make the
10005 * word parsing code into a separate routine. In this case, readtoken
10006 * doesn't need to have any internal procedures, but parseword does.
10007 * We could also make parseoperator in essence the main routine, and
10008 * have parseword (readtoken1?) handle both words and redirection.]
10011 #define NEW_xxreadtoken
10012 #ifdef NEW_xxreadtoken
10014 /* singles must be first! */
10015 static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
10017 static const char xxreadtoken_tokens[] = {
10018 TNL, TLP, TRP, /* only single occurrence allowed */
10019 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
10020 TEOF, /* corresponds to trailing nul */
10021 TAND, TOR, TENDCASE, /* if double occurrence */
10024 #define xxreadtoken_doubles \
10025 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
10026 #define xxreadtoken_singles \
10027 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
10029 static int xxreadtoken()
10041 startlinno = plinno;
10042 for (;;) { /* until token or start of word found */
10045 if ((c != ' ') && (c != '\t')
10046 #ifdef CONFIG_ASH_ALIAS
10051 while ((c = pgetc()) != '\n' && c != PEOF);
10053 } else if (c == '\\') {
10054 if (pgetc() != '\n') {
10058 startlinno = ++plinno;
10063 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10068 needprompt = doprompt;
10071 p = strchr(xxreadtoken_chars, c);
10074 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
10077 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
10078 if (pgetc() == *p) { /* double occurrence? */
10079 p += xxreadtoken_doubles + 1;
10086 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
10094 #define RETURN(token) return lasttoken = token
10109 startlinno = plinno;
10110 for (;;) { /* until token or start of word found */
10113 case ' ': case '\t':
10114 #ifdef CONFIG_ASH_ALIAS
10119 while ((c = pgetc()) != '\n' && c != PEOF);
10123 if (pgetc() == '\n') {
10124 startlinno = ++plinno;
10133 needprompt = doprompt;
10138 if (pgetc() == '&')
10143 if (pgetc() == '|')
10148 if (pgetc() == ';')
10161 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10164 #endif /* NEW_xxreadtoken */
10168 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10169 * is not NULL, read a here document. In the latter case, eofmark is the
10170 * word which marks the end of the document and striptabs is true if
10171 * leading tabs should be stripped from the document. The argument firstc
10172 * is the first character of the input token or document.
10174 * Because C does not have internal subroutines, I have simulated them
10175 * using goto's to implement the subroutine linkage. The following macros
10176 * will run code that appears at the end of readtoken1.
10179 #define CHECKEND() {goto checkend; checkend_return:;}
10180 #define PARSEREDIR() {goto parseredir; parseredir_return:;}
10181 #define PARSESUB() {goto parsesub; parsesub_return:;}
10182 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10183 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10184 #define PARSEARITH() {goto parsearith; parsearith_return:;}
10187 readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
10192 char line[EOFMARKLEN + 1];
10193 struct nodelist *bqlist;
10196 int varnest; /* levels of variables expansion */
10197 int arinest; /* levels of arithmetic expansion */
10198 int parenlevel; /* levels of parens in arithmetic */
10199 int dqvarnest; /* levels of variables expansion within double quotes */
10201 int prevsyntax; /* syntax before arithmetic */
10203 /* Avoid longjmp clobbering */
10209 (void) &parenlevel;
10212 (void) &prevsyntax;
10216 startlinno = plinno;
10218 if (syntax == DQSYNTAX)
10227 STARTSTACKSTR(out);
10228 loop: { /* for each line, until end of word */
10229 CHECKEND(); /* set c to PEOF if at end of here document */
10230 for (;;) { /* until end of line or end of word */
10231 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10232 switch(SIT(c, syntax)) {
10233 case CNL: /* '\n' */
10234 if (syntax == BASESYNTAX)
10235 goto endword; /* exit outer loop */
10241 goto loop; /* continue outer loop */
10246 if (eofmark == NULL || dblquote)
10247 USTPUTC(CTLESC, out);
10250 case CBACK: /* backslash */
10253 USTPUTC(CTLESC, out);
10254 USTPUTC('\\', out);
10256 } else if (c == '\n') {
10262 c != '\\' && c != '`' &&
10268 USTPUTC(CTLESC, out);
10269 USTPUTC('\\', out);
10271 if (SIT(c, SQSYNTAX) == CCTL)
10272 USTPUTC(CTLESC, out);
10280 if (eofmark == NULL) {
10281 USTPUTC(CTLQUOTEMARK, out);
10289 if (eofmark != NULL && arinest == 0 &&
10293 if (dqvarnest == 0) {
10294 syntax = BASESYNTAX;
10301 case CVAR: /* '$' */
10302 PARSESUB(); /* parse substitution */
10304 case CENDVAR: /* '}' */
10307 if (dqvarnest > 0) {
10310 USTPUTC(CTLENDVAR, out);
10315 #ifdef CONFIG_ASH_MATH_SUPPORT
10316 case CLP: /* '(' in arithmetic */
10320 case CRP: /* ')' in arithmetic */
10321 if (parenlevel > 0) {
10325 if (pgetc() == ')') {
10326 if (--arinest == 0) {
10327 USTPUTC(CTLENDARI, out);
10328 syntax = prevsyntax;
10329 if (syntax == DQSYNTAX)
10337 * unbalanced parens
10338 * (don't 2nd guess - no error)
10346 case CBQUOTE: /* '`' */
10350 goto endword; /* exit outer loop */
10355 goto endword; /* exit outer loop */
10356 #ifdef CONFIG_ASH_ALIAS
10366 #ifdef CONFIG_ASH_MATH_SUPPORT
10367 if (syntax == ARISYNTAX)
10368 synerror("Missing '))'");
10370 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10371 synerror("Unterminated quoted string");
10372 if (varnest != 0) {
10373 startlinno = plinno;
10375 synerror("Missing '}'");
10377 USTPUTC('\0', out);
10378 len = out - (char *)stackblock();
10379 out = stackblock();
10380 if (eofmark == NULL) {
10381 if ((c == '>' || c == '<')
10384 && (*out == '\0' || is_digit(*out))) {
10386 return lasttoken = TREDIR;
10391 quoteflag = quotef;
10392 backquotelist = bqlist;
10393 grabstackblock(len);
10395 return lasttoken = TWORD;
10396 /* end of readtoken routine */
10401 * Check to see whether we are at the end of the here document. When this
10402 * is called, c is set to the first character of the next input line. If
10403 * we are at the end of the here document, this routine sets the c to PEOF.
10408 #ifdef CONFIG_ASH_ALIAS
10414 while (c == '\t') {
10418 if (c == *eofmark) {
10419 if (pfgets(line, sizeof line) != NULL) {
10423 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10424 if (*p == '\n' && *q == '\0') {
10427 needprompt = doprompt;
10429 pushstring(line, NULL);
10434 goto checkend_return;
10439 * Parse a redirection operator. The variable "out" points to a string
10440 * specifying the fd to be redirected. The variable "c" contains the
10441 * first character of the redirection operator.
10448 np = (union node *)stalloc(sizeof (struct nfile));
10453 np->type = NAPPEND;
10455 np->type = NCLOBBER;
10462 } else { /* c == '<' */
10464 switch (c = pgetc()) {
10466 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10467 np = (union node *)stalloc(sizeof (struct nhere));
10471 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10472 heredoc->here = np;
10473 if ((c = pgetc()) == '-') {
10474 heredoc->striptabs = 1;
10476 heredoc->striptabs = 0;
10482 np->type = NFROMFD;
10486 np->type = NFROMTO;
10496 np->nfile.fd = digit_val(fd);
10498 goto parseredir_return;
10503 * Parse a substitution. At this point, we have read the dollar sign
10504 * and nothing else.
10512 static const char types[] = "}-+?=";
10516 c <= PEOA_OR_PEOF ||
10517 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10521 } else if (c == '(') { /* $(command) or $((arith)) */
10522 if (pgetc() == '(') {
10523 #ifdef CONFIG_ASH_MATH_SUPPORT
10526 synerror("We unsupport $((arith))");
10533 USTPUTC(CTLVAR, out);
10534 typeloc = out - (char *)stackblock();
10535 USTPUTC(VSNORMAL, out);
10536 subtype = VSNORMAL;
10540 if ((c = pgetc()) == '}')
10543 subtype = VSLENGTH;
10548 if (c > PEOA_OR_PEOF && is_name(c)) {
10552 } while (c > PEOA_OR_PEOF && is_in_name(c));
10553 } else if (is_digit(c)) {
10557 } while (is_digit(c));
10559 else if (is_special(c)) {
10564 badsub: synerror("Bad substitution");
10568 if (subtype == 0) {
10575 p = strchr(types, c);
10578 subtype = p - types + VSNORMAL;
10584 subtype = c == '#' ? VSTRIMLEFT :
10597 if (dblquote || arinest)
10599 *((char *)stackblock() + typeloc) = subtype | flags;
10600 if (subtype != VSNORMAL) {
10602 if (dblquote || arinest) {
10607 goto parsesub_return;
10612 * Called to parse command substitutions. Newstyle is set if the command
10613 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10614 * list of commands (passed by reference), and savelen is the number of
10615 * characters on the top of the stack which must be preserved.
10619 struct nodelist **nlpp;
10622 char *volatile str;
10623 struct jmploc jmploc;
10624 struct jmploc *volatile savehandler;
10628 (void) &saveprompt;
10631 savepbq = parsebackquote;
10632 if (setjmp(jmploc.loc)) {
10635 parsebackquote = 0;
10636 handler = savehandler;
10637 longjmp(handler->loc, 1);
10641 savelen = out - (char *)stackblock();
10643 str = ckmalloc(savelen);
10644 memcpy(str, stackblock(), savelen);
10646 savehandler = handler;
10650 /* We must read until the closing backquote, giving special
10651 treatment to some slashes, and then push the string and
10652 reread it as input, interpreting it normally. */
10659 STARTSTACKSTR(pout);
10665 switch (pc = pgetc()) {
10670 if ((pc = pgetc()) == '\n') {
10675 * If eating a newline, avoid putting
10676 * the newline into the new character
10677 * stream (via the STPUTC after the
10682 if (pc != '\\' && pc != '`' && pc != '$'
10683 && (!dblquote || pc != '"'))
10684 STPUTC('\\', pout);
10685 if (pc > PEOA_OR_PEOF) {
10691 #ifdef CONFIG_ASH_ALIAS
10694 startlinno = plinno;
10695 synerror("EOF in backquote substitution");
10699 needprompt = doprompt;
10708 STPUTC('\0', pout);
10709 psavelen = pout - (char *)stackblock();
10710 if (psavelen > 0) {
10711 pstr = grabstackstr(pout);
10712 setinputstring(pstr);
10717 nlpp = &(*nlpp)->next;
10718 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10719 (*nlpp)->next = NULL;
10720 parsebackquote = oldstyle;
10723 saveprompt = doprompt;
10730 doprompt = saveprompt;
10732 if (readtoken() != TRP)
10739 * Start reading from old file again, ignoring any pushed back
10740 * tokens left from the backquote parsing
10745 while (stackblocksize() <= savelen)
10747 STARTSTACKSTR(out);
10749 memcpy(out, str, savelen);
10750 STADJUST(savelen, out);
10756 parsebackquote = savepbq;
10757 handler = savehandler;
10758 if (arinest || dblquote)
10759 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10761 USTPUTC(CTLBACKQ, out);
10763 goto parsebackq_oldreturn;
10765 goto parsebackq_newreturn;
10768 #ifdef CONFIG_ASH_MATH_SUPPORT
10770 * Parse an arithmetic expansion (indicate start of one and set state)
10774 if (++arinest == 1) {
10775 prevsyntax = syntax;
10776 syntax = ARISYNTAX;
10777 USTPUTC(CTLARI, out);
10784 * we collapse embedded arithmetic expansion to
10785 * parenthesis, which should be equivalent
10789 goto parsearith_return;
10793 } /* end of readtoken */
10798 * Returns true if the text contains nothing to expand (no dollar signs
10803 noexpand(char *text)
10809 while ((c = *p++) != '\0') {
10810 if (c == CTLQUOTEMARK)
10814 else if (SIT(c, BASESYNTAX) == CCTL)
10822 * Return of a legal variable name (a letter or underscore followed by zero or
10823 * more letters, underscores, and digits).
10827 endofname(const char *name)
10835 if (! is_in_name(*p))
10843 * Called when an unexpected token is read during the parse. The argument
10844 * is the token that is expected, or -1 if more than one type of token can
10845 * occur at this point.
10848 static void synexpect(int token)
10853 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10855 sprintf(msg + l, " (expecting %s)", tokname(token));
10861 synerror(const char *msg)
10863 error("Syntax error: %s", msg);
10869 * called by editline -- any expansions to the prompt
10870 * should be added here.
10873 static void setprompt(int whichprompt)
10875 const char *prompt;
10877 switch (whichprompt) {
10891 static const char *const *findkwd(const char *s)
10893 return bsearch(s, tokname_array + KWDOFFSET,
10894 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
10895 sizeof(const char *), pstrcmp);
10898 /* $NetBSD: redir.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
10901 * Code for dealing with input/output redirection.
10904 #define EMPTY -2 /* marks an unused slot in redirtab */
10906 # define PIPESIZE 4096 /* amount of buffering in a pipe */
10908 # define PIPESIZE PIPE_BUF
10912 * Open a file in noclobber mode.
10913 * The code was copied from bash.
10916 noclobberopen(const char *fname)
10919 struct stat finfo, finfo2;
10922 * If the file exists and is a regular file, return an error
10925 r = stat(fname, &finfo);
10926 if (r == 0 && S_ISREG(finfo.st_mode)) {
10932 * If the file was not present (r != 0), make sure we open it
10933 * exclusively so that if it is created before we open it, our open
10934 * will fail. Make sure that we do not truncate an existing file.
10935 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10936 * file was not a regular file, we leave O_EXCL off.
10939 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10940 fd = open(fname, O_WRONLY|O_CREAT, 0666);
10942 /* If the open failed, return the file descriptor right away. */
10947 * OK, the open succeeded, but the file may have been changed from a
10948 * non-regular file to a regular file between the stat and the open.
10949 * We are assuming that the O_EXCL open handles the case where FILENAME
10950 * did not exist and is symlinked to an existing file between the stat
10955 * If we can open it and fstat the file descriptor, and neither check
10956 * revealed that it was a regular file, and the file has not been
10957 * replaced, return the file descriptor.
10959 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10960 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
10963 /* The file has been replaced. badness. */
10970 * Handle here documents. Normally we fork off a process to write the
10971 * data to a pipe. If the document is short, we can stuff the data in
10972 * the pipe without forking.
10976 openhere(union node *redir)
10982 error("Pipe call failed");
10983 if (redir->type == NHERE) {
10984 len = strlen(redir->nhere.doc->narg.text);
10985 if (len <= PIPESIZE) {
10986 bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
10990 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
10992 signal(SIGINT, SIG_IGN);
10993 signal(SIGQUIT, SIG_IGN);
10994 signal(SIGHUP, SIG_IGN);
10996 signal(SIGTSTP, SIG_IGN);
10998 signal(SIGPIPE, SIG_DFL);
10999 if (redir->type == NHERE)
11000 bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
11002 expandhere(redir->nhere.doc, pip[1]);
11011 openredirect(union node *redir)
11016 switch (redir->nfile.type) {
11018 fname = redir->nfile.expfname;
11019 if ((f = open(fname, O_RDONLY)) < 0)
11023 fname = redir->nfile.expfname;
11024 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
11028 /* Take care of noclobber mode. */
11030 fname = redir->nfile.expfname;
11031 if ((f = noclobberopen(fname)) < 0)
11037 fname = redir->nfile.expfname;
11038 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
11042 fname = redir->nfile.expfname;
11043 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
11050 /* Fall through to eliminate warning. */
11057 f = openhere(redir);
11063 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
11065 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11069 dupredirect(union node *redir, int f)
11071 int fd = redir->nfile.fd;
11073 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11074 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
11075 copyfd(redir->ndup.dupfd, fd);
11088 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11089 * old file descriptors are stashed away so that the redirection can be
11090 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11091 * standard output, and the standard error if it becomes a duplicate of
11092 * stdout, is saved in memory.
11096 redirect(union node *redir, int flags)
11099 struct redirtab *sv;
11110 if (flags & REDIR_PUSH) {
11111 struct redirtab *q;
11112 q = ckmalloc(sizeof (struct redirtab));
11113 q->next = redirlist;
11115 q->nullredirs = nullredirs - 1;
11116 for (i = 0 ; i < 10 ; i++)
11117 q->renamed[i] = EMPTY;
11124 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
11125 n->ndup.dupfd == fd)
11126 continue; /* redirect from/to same file descriptor */
11128 newfd = openredirect(n);
11131 if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
11132 i = fcntl(fd, F_DUPFD, 10);
11139 error("%d: %m", fd);
11149 dupredirect(n, newfd);
11150 } while ((n = n->nfile.next));
11152 if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
11153 preverrout_fd = sv->renamed[2];
11158 * Undo the effects of the last redirection.
11164 struct redirtab *rp;
11167 if (--nullredirs >= 0)
11171 for (i = 0 ; i < 10 ; i++) {
11172 if (rp->renamed[i] != EMPTY) {
11175 copyfd(rp->renamed[i], i);
11177 close(rp->renamed[i]);
11180 redirlist = rp->next;
11181 nullredirs = rp->nullredirs;
11187 * Undo all redirections. Called on error or interrupt.
11191 * Discard all saved file descriptors.
11195 clearredir(int drop)
11207 * Copy a file descriptor to be >= to. Returns -1
11208 * if the source file descriptor is closed, EMPTY if there are no unused
11209 * file descriptors left.
11213 copyfd(int from, int to)
11217 newfd = fcntl(from, F_DUPFD, to);
11219 if (errno == EMFILE)
11222 error("%d: %m", from);
11229 redirectsafe(union node *redir, int flags)
11232 volatile int saveint;
11233 struct jmploc *volatile savehandler = handler;
11234 struct jmploc jmploc;
11237 if (!(err = setjmp(jmploc.loc) * 2)) {
11239 redirect(redir, flags);
11241 handler = savehandler;
11242 if (err && exception != EXERROR)
11243 longjmp(handler->loc, 1);
11244 RESTOREINT(saveint);
11248 /* $NetBSD: show.c,v 1.24 2003/01/22 20:36:04 dsl Exp $ */
11251 static void shtree(union node *, int, char *, FILE*);
11252 static void shcmd(union node *, FILE *);
11253 static void sharg(union node *, FILE *);
11254 static void indent(int, char *, FILE *);
11255 static void trstring(char *);
11259 showtree(union node *n)
11261 trputs("showtree called\n");
11262 shtree(n, 1, NULL, stdout);
11267 shtree(union node *n, int ind, char *pfx, FILE *fp)
11269 struct nodelist *lp;
11275 indent(ind, pfx, fp);
11286 shtree(n->nbinary.ch1, ind, NULL, fp);
11289 shtree(n->nbinary.ch2, ind, NULL, fp);
11297 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
11302 if (n->npipe.backgnd)
11308 fprintf(fp, "<node type %d>", n->type);
11317 shcmd(union node *cmd, FILE *fp)
11325 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11331 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11334 switch (np->nfile.type) {
11335 case NTO: s = ">"; dftfd = 1; break;
11336 case NCLOBBER: s = ">|"; dftfd = 1; break;
11337 case NAPPEND: s = ">>"; dftfd = 1; break;
11338 case NTOFD: s = ">&"; dftfd = 1; break;
11339 case NFROM: s = "<"; dftfd = 0; break;
11340 case NFROMFD: s = "<&"; dftfd = 0; break;
11341 case NFROMTO: s = "<>"; dftfd = 0; break;
11342 default: s = "*error*"; dftfd = 0; break;
11344 if (np->nfile.fd != dftfd)
11345 fprintf(fp, "%d", np->nfile.fd);
11347 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11348 fprintf(fp, "%d", np->ndup.dupfd);
11350 sharg(np->nfile.fname, fp);
11359 sharg(union node *arg, FILE *fp)
11362 struct nodelist *bqlist;
11365 if (arg->type != NARG) {
11366 out1fmt("<node type %d>\n", arg->type);
11369 bqlist = arg->narg.backquote;
11370 for (p = arg->narg.text ; *p ; p++) {
11379 if (subtype == VSLENGTH)
11385 if (subtype & VSNUL)
11388 switch (subtype & VSTYPE) {
11407 case VSTRIMLEFTMAX:
11414 case VSTRIMRIGHTMAX:
11421 out1fmt("<subtype %d>", subtype);
11428 case CTLBACKQ|CTLQUOTE:
11431 shtree(bqlist->n, -1, NULL, fp);
11443 indent(int amount, char *pfx, FILE *fp)
11447 for (i = 0 ; i < amount ; i++) {
11448 if (pfx && i == amount - 1)
11469 putc(c, tracefile);
11473 trace(const char *fmt, ...)
11480 (void) vfprintf(tracefile, fmt, va);
11485 tracev(const char *fmt, va_list va)
11489 (void) vfprintf(tracefile, fmt, va);
11494 trputs(const char *s)
11498 fputs(s, tracefile);
11510 putc('"', tracefile);
11511 for (p = s ; *p ; p++) {
11513 case '\n': c = 'n'; goto backslash;
11514 case '\t': c = 't'; goto backslash;
11515 case '\r': c = 'r'; goto backslash;
11516 case '"': c = '"'; goto backslash;
11517 case '\\': c = '\\'; goto backslash;
11518 case CTLESC: c = 'e'; goto backslash;
11519 case CTLVAR: c = 'v'; goto backslash;
11520 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11521 case CTLBACKQ: c = 'q'; goto backslash;
11522 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
11523 backslash: putc('\\', tracefile);
11524 putc(c, tracefile);
11527 if (*p >= ' ' && *p <= '~')
11528 putc(*p, tracefile);
11530 putc('\\', tracefile);
11531 putc(*p >> 6 & 03, tracefile);
11532 putc(*p >> 3 & 07, tracefile);
11533 putc(*p & 07, tracefile);
11538 putc('"', tracefile);
11550 putc(' ', tracefile);
11552 putc('\n', tracefile);
11568 /* leave open because libedit might be using it */
11571 scopy("./trace", s);
11573 if (!freopen(s, "a", tracefile)) {
11574 fprintf(stderr, "Can't re-open %s\n", s);
11579 if ((tracefile = fopen(s, "a")) == NULL) {
11580 fprintf(stderr, "Can't open %s\n", s);
11586 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11587 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11589 setlinebuf(tracefile);
11590 fputs("\nTracing started.\n", tracefile);
11595 /* $NetBSD: trap.c,v 1.28 2002/11/24 22:35:43 christos Exp $ */
11598 * Sigmode records the current value of the signal handlers for the various
11599 * modes. A value of zero means that the current handler is not known.
11600 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
11603 #define S_DFL 1 /* default signal handling (SIG_DFL) */
11604 #define S_CATCH 2 /* signal is caught */
11605 #define S_IGN 3 /* signal is ignored (SIG_IGN) */
11606 #define S_HARD_IGN 4 /* signal is ignored permenantly */
11607 #define S_RESET 5 /* temporary - to reset a hard ignored sig */
11612 * The trap builtin.
11616 trapcmd(int argc, char **argv)
11625 for (signo = 0 ; signo < NSIG ; signo++) {
11626 if (trap[signo] != NULL) {
11629 sn = u_signal_names(0, &signo, 0);
11632 out1fmt("trap -- %s %s\n",
11633 single_quote(trap[signo]), sn);
11643 if ((signo = decode_signal(*ap, 0)) < 0)
11644 error("%s: bad trap", *ap);
11647 if (action[0] == '-' && action[1] == '\0')
11650 action = savestr(action);
11653 ckfree(trap[signo]);
11654 trap[signo] = action;
11665 * Clear traps on a fork.
11673 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
11674 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
11678 if (tp != &trap[0])
11679 setsignal(tp - trap);
11687 * Set the signal handler for the specified signal. The routine figures
11688 * out what it should be set to.
11692 setsignal(int signo)
11696 struct sigaction act;
11698 if ((t = trap[signo]) == NULL)
11700 else if (*t != '\0')
11704 if (rootshell && action == S_DFL) {
11707 if (iflag || minusc || sflag == 0)
11730 t = &sigmode[signo - 1];
11734 * current setting unknown
11736 if (sigaction(signo, 0, &act) == -1) {
11738 * Pretend it worked; maybe we should give a warning
11739 * here, but other shells don't. We don't alter
11740 * sigmode, so that we retry every time.
11744 if (act.sa_handler == SIG_IGN) {
11745 if (mflag && (signo == SIGTSTP ||
11746 signo == SIGTTIN || signo == SIGTTOU)) {
11747 tsig = S_IGN; /* don't hard ignore these */
11751 tsig = S_RESET; /* force to be set */
11754 if (tsig == S_HARD_IGN || tsig == action)
11758 act.sa_handler = onsig;
11761 act.sa_handler = SIG_IGN;
11764 act.sa_handler = SIG_DFL;
11768 sigfillset(&act.sa_mask);
11769 sigaction(signo, &act, 0);
11777 ignoresig(int signo)
11779 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11780 signal(signo, SIG_IGN);
11782 sigmode[signo - 1] = S_HARD_IGN;
11793 gotsig[signo - 1] = 1;
11794 pendingsigs = signo;
11796 if (exsig || (signo == SIGINT && !trap[SIGINT])) {
11805 * Called to execute a trap. Perhaps we should avoid entering new trap
11806 * handlers while we are executing a trap handler.
11816 savestatus = exitstatus;
11818 while (pendingsigs = 0, xbarrier(), (p = memchr(q, 1, NSIG - 1))) {
11820 p = trap[p - q + 1];
11824 exitstatus = savestatus;
11830 * Controls whether the shell is interactive or not.
11834 setinteractive(int on)
11836 static int is_interactive;
11838 if (++on == is_interactive)
11840 is_interactive = on;
11842 setsignal(SIGQUIT);
11843 setsignal(SIGTERM);
11844 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11845 if(is_interactive > 1) {
11846 /* Looks like they want an interactive shell */
11847 static int do_banner;
11851 "\n\n" BB_BANNER " Built-in shell (ash)\n"
11852 "Enter 'help' for a list of built-in commands.\n\n");
11860 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11861 /*** List the available builtins ***/
11863 static int helpcmd(int argc, char **argv)
11867 out1fmt("\nBuilt-in commands:\n-------------------\n");
11868 for (col = 0, i = 0; i < NUMBUILTINS; i++) {
11869 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11870 builtincmd[i].name + 1);
11876 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
11878 extern const struct BB_applet applets[];
11879 extern const size_t NUM_APPLETS;
11881 for (i = 0; i < NUM_APPLETS; i++) {
11883 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
11892 return EXIT_SUCCESS;
11894 #endif /* CONFIG_FEATURE_SH_EXTRA_QUIET */
11897 * Called to exit the shell.
11908 jmp = setjmp(loc.loc);
11909 status = exitstatus;
11910 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
11914 if ((p = trap[0]) != NULL && *p != '\0') {
11920 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
11921 if (iflag && rootshell) {
11922 const char *hp = lookupvar("HISTFILE");
11925 save_history ( hp );
11933 static int decode_signal(const char *string, int minsig)
11936 const char *name = u_signal_names(string, &signo, minsig);
11938 return name ? signo : -1;
11941 /* $NetBSD: var.c,v 1.32 2003/01/22 20:36:04 dsl Exp $ */
11943 static struct var *vartab[VTABSIZE];
11945 static int vpcmp(const void *, const void *);
11946 static struct var **findvar(struct var **, const char *);
11949 * Initialize the variable symbol tables and import the environment
11953 #ifdef CONFIG_ASH_GETOPTS
11955 * Safe version of setvar, returns 1 on success 0 on failure.
11959 setvarsafe(const char *name, const char *val, int flags)
11962 volatile int saveint;
11963 struct jmploc *volatile savehandler = handler;
11964 struct jmploc jmploc;
11967 if (setjmp(jmploc.loc))
11971 setvar(name, val, flags);
11974 handler = savehandler;
11975 RESTOREINT(saveint);
11981 * Set the value of a variable. The flags argument is ored with the
11982 * flags of the variable. If val is NULL, the variable is unset.
11986 setvar(const char *name, const char *val, int flags)
11993 q = endofname(name);
11994 p = strchrnul(q, '=');
11995 namelen = p - name;
11996 if (!namelen || p != q)
11997 error("%.*s: bad variable name", namelen, name);
12002 vallen = strlen(val);
12005 p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
12009 p = mempcpy(p, val, vallen);
12012 setvareq(nameeq, flags | VNOSAVE);
12018 * Same as setvar except that the variable and value are passed in
12019 * the first argument as name=value. Since the first argument will
12020 * be actually stored in the table, it should not be a string that
12022 * Called with interrupts off.
12026 setvareq(char *s, int flags)
12028 struct var *vp, **vpp;
12031 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
12032 vp = *findvar(vpp, s);
12034 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
12037 if (flags & VNOSAVE)
12040 error("%.*s: is read only", strchrnul(n, '=') - n, n);
12043 if (flags & VNOSET)
12046 if (vp->func && (flags & VNOFUNC) == 0)
12047 (*vp->func)(strchrnul(s, '=') + 1);
12049 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12052 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
12054 if (flags & VNOSET)
12057 vp = ckmalloc(sizeof (*vp));
12062 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
12070 * Process a linked list of variable assignments.
12074 listsetvar(struct strlist *list_set_var, int flags)
12076 struct strlist *lp = list_set_var;
12082 setvareq(lp->text, flags);
12083 } while ((lp = lp->next));
12089 * Find the value of a variable. Returns NULL if not set.
12093 lookupvar(const char *name)
12097 if ((v = *findvar(hashvar(name), name))) {
12100 * Dynamic variables are implemented roughly the same way they are
12101 * in bash. Namely, they're "special" so long as they aren't unset.
12102 * As soon as they're unset, they're no longer dynamic, and dynamic
12103 * lookup will no longer happen at that point. -- PFM.
12105 if((v->flags & VDYNAMIC))
12108 if(!(v->flags & VUNSET))
12109 return strchrnul(v->text, '=') + 1;
12117 * Search the environment of a builtin command.
12121 bltinlookup(const char *name)
12123 struct strlist *sp;
12125 for (sp = cmdenviron ; sp ; sp = sp->next) {
12126 if (varequal(sp->text, name))
12127 return strchrnul(sp->text, '=') + 1;
12129 return lookupvar(name);
12134 * Generate a list of variables satisfying the given conditions.
12138 listvars(int on, int off, char ***end)
12149 for (vp = *vpp ; vp ; vp = vp->next)
12150 if ((vp->flags & mask) == on) {
12151 if (ep == stackstrend())
12152 ep = growstackstr();
12153 *ep++ = (char *) vp->text;
12155 } while (++vpp < vartab + VTABSIZE);
12156 if (ep == stackstrend())
12157 ep = growstackstr();
12161 return grabstackstr(ep);
12166 * POSIX requires that 'set' (but not export or readonly) output the
12167 * variables in lexicographic order - by the locale's collating order (sigh).
12168 * Maybe we could keep them in an ordered balanced binary tree
12169 * instead of hashed lists.
12170 * For now just roll 'em through qsort for printing...
12174 showvars(const char *sep_prefix, int on, int off)
12177 char **ep, **epend;
12179 ep = listvars(on, off, &epend);
12180 qsort(ep, epend - ep, sizeof(char *), vpcmp);
12182 sep = *sep_prefix ? spcstr : sep_prefix;
12184 for (; ep < epend; ep++) {
12188 p = strchrnul(*ep, '=');
12191 q = single_quote(++p);
12193 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
12202 * The export and readonly commands.
12206 exportcmd(int argc, char **argv)
12212 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12215 notp = nextopt("p") - 'p';
12216 if (notp && ((name = *(aptr = argptr)))) {
12218 if ((p = strchr(name, '=')) != NULL) {
12221 if ((vp = *findvar(hashvar(name), name))) {
12226 setvar(name, p, flag);
12227 } while ((name = *++aptr) != NULL);
12229 showvars(argv[0], flag, 0);
12236 * Make a variable a local variable. When a variable is made local, it's
12237 * value and flags are saved in a localvar structure. The saved values
12238 * will be restored when the shell function returns. We handle the name
12239 * "-" as a special case.
12243 mklocal(char *name)
12245 struct localvar *lvp;
12250 lvp = ckmalloc(sizeof (struct localvar));
12251 if (name[0] == '-' && name[1] == '\0') {
12253 p = ckmalloc(sizeof(optlist));
12254 lvp->text = memcpy(p, optlist, sizeof(optlist));
12259 vpp = hashvar(name);
12260 vp = *findvar(vpp, name);
12261 eq = strchr(name, '=');
12264 setvareq(name, VSTRFIXED);
12266 setvar(name, NULL, VSTRFIXED);
12267 vp = *vpp; /* the new variable */
12268 lvp->flags = VUNSET;
12270 lvp->text = vp->text;
12271 lvp->flags = vp->flags;
12272 vp->flags |= VSTRFIXED|VTEXTFIXED;
12278 lvp->next = localvars;
12284 * The "local" command.
12288 localcmd(int argc, char **argv)
12293 while ((name = *argv++) != NULL) {
12301 * Called after a function returns.
12302 * Interrupts must be off.
12308 struct localvar *lvp;
12311 while ((lvp = localvars) != NULL) {
12312 localvars = lvp->next;
12314 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
12315 if (vp == NULL) { /* $- saved */
12316 memcpy(optlist, lvp->text, sizeof(optlist));
12319 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12320 unsetvar(vp->text);
12323 (*vp->func)(strchrnul(lvp->text, '=') + 1);
12324 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12326 vp->flags = lvp->flags;
12327 vp->text = lvp->text;
12335 * The unset builtin command. We unset the function before we unset the
12336 * variable to allow a function to be unset when there is a readonly variable
12337 * with the same name.
12341 unsetcmd(int argc, char **argv)
12348 while ((i = nextopt("vf")) != '\0') {
12352 for (ap = argptr; *ap ; ap++) {
12367 * Unset the specified variable.
12371 unsetvar(const char *s)
12377 vpp = findvar(hashvar(s), s);
12381 int flags = vp->flags;
12384 if (flags & VREADONLY)
12387 vp->flags &= ~VDYNAMIC;
12389 if (flags & VUNSET)
12391 if ((flags & VSTRFIXED) == 0) {
12393 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
12400 vp->flags &= ~VEXPORT;
12413 * Find the appropriate entry in the hash table from the name.
12416 static struct var **
12417 hashvar(const char *p)
12419 unsigned int hashval;
12421 hashval = ((unsigned char) *p) << 4;
12422 while (*p && *p != '=')
12423 hashval += (unsigned char) *p++;
12424 return &vartab[hashval % VTABSIZE];
12430 * Compares two strings up to the first = or '\0'. The first
12431 * string must be terminated by '='; the second may be terminated by
12432 * either '=' or '\0'.
12436 varcmp(const char *p, const char *q)
12440 while ((c = *p) == (d = *q)) {
12441 if (!c || c == '=')
12455 vpcmp(const void *a, const void *b)
12457 return varcmp(*(const char **)a, *(const char **)b);
12460 static struct var **
12461 findvar(struct var **vpp, const char *name)
12463 for (; *vpp; vpp = &(*vpp)->next) {
12464 if (varequal((*vpp)->text, name)) {
12470 /* $NetBSD: setmode.c,v 1.29 2003/01/15 23:58:03 kleink Exp $ */
12472 #include <sys/times.h>
12474 static const unsigned char timescmd_str[] = {
12475 ' ', offsetof(struct tms, tms_utime),
12476 '\n', offsetof(struct tms, tms_stime),
12477 ' ', offsetof(struct tms, tms_cutime),
12478 '\n', offsetof(struct tms, tms_cstime),
12482 static int timescmd(int ac, char **av)
12484 long int clk_tck, s, t;
12485 const unsigned char *p;
12488 clk_tck = sysconf(_SC_CLK_TCK);
12493 t = *(clock_t *)(((char *) &buf) + p[1]);
12495 out1fmt("%ldm%ld.%.3lds%c",
12497 ((t - s * clk_tck) * 1000) / clk_tck,
12499 } while (*(p += 2));
12504 #ifdef CONFIG_ASH_MATH_SUPPORT
12506 dash_arith(const char *s)
12512 result = arith(s, &errcode);
12515 error("exponent less than 0");
12516 else if (errcode == -2)
12517 error("divide by zero");
12518 else if (errcode == -5)
12519 error("expression recursion loop detected");
12530 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12531 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12533 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12537 letcmd(int argc, char **argv)
12544 error("expression expected");
12545 for (ap = argv + 1; *ap; ap++) {
12546 i = dash_arith(*ap);
12551 #endif /* CONFIG_ASH_MATH_SUPPORT */
12553 /* $NetBSD: miscbltin.c,v 1.31 2002/11/24 22:35:41 christos Exp $ */
12556 * Miscellaneous builtins.
12562 #if __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
12563 typedef enum __rlimit_resource rlim_t;
12569 * The read builtin. The -e option causes backslashes to escape the
12570 * following character.
12572 * This uses unbuffered input, which may be avoidable in some cases.
12576 readcmd(int argc, char **argv)
12591 while ((i = nextopt("p:r")) != '\0') {
12593 prompt = optionarg;
12597 if (prompt && isatty(0)) {
12600 if (*(ap = argptr) == NULL)
12601 error("arg count");
12602 if ((ifs = bltinlookup("IFS")) == NULL)
12609 if (read(0, &c, 1) != 1) {
12621 if (!rflag && c == '\\') {
12627 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12631 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12633 setvar(*ap, stackblock(), 0);
12643 /* Remove trailing blanks */
12644 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12646 setvar(*ap, stackblock(), 0);
12647 while (*++ap != NULL)
12648 setvar(*ap, nullstr, 0);
12653 static int umaskcmd(int argc, char **argv)
12655 static const char permuser[3] = "ugo";
12656 static const char permmode[3] = "rwx";
12657 static const short int permmask[] = {
12658 S_IRUSR, S_IWUSR, S_IXUSR,
12659 S_IRGRP, S_IWGRP, S_IXGRP,
12660 S_IROTH, S_IWOTH, S_IXOTH
12666 int symbolic_mode = 0;
12668 while (nextopt("S") != '\0') {
12677 if ((ap = *argptr) == NULL) {
12678 if (symbolic_mode) {
12682 for (i = 0; i < 3; i++) {
12685 *p++ = permuser[i];
12687 for (j = 0; j < 3; j++) {
12688 if ((mask & permmask[3 * i + j]) == 0) {
12689 *p++ = permmode[j];
12697 out1fmt("%.4o\n", mask);
12700 if (is_digit((unsigned char) *ap)) {
12703 if (*ap >= '8' || *ap < '0')
12704 error(illnum, argv[1]);
12705 mask = (mask << 3) + (*ap - '0');
12706 } while (*++ap != '\0');
12709 mask = ~mask & 0777;
12710 if (!bb_parse_mode(ap, &mask)) {
12711 error("Illegal mode: %s", ap);
12713 umask(~mask & 0777);
12722 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12723 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12724 * ash by J.T. Conklin.
12732 int factor; /* multiply by to get rlim_{cur,max} values */
12736 static const struct limits limits[] = {
12738 { "time(seconds)", RLIMIT_CPU, 1, 't' },
12740 #ifdef RLIMIT_FSIZE
12741 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
12744 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
12746 #ifdef RLIMIT_STACK
12747 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
12750 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
12753 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
12755 #ifdef RLIMIT_MEMLOCK
12756 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
12758 #ifdef RLIMIT_NPROC
12759 { "process", RLIMIT_NPROC, 1, 'p' },
12761 #ifdef RLIMIT_NOFILE
12762 { "nofiles", RLIMIT_NOFILE, 1, 'n' },
12765 { "vmemory(kbytes)", RLIMIT_AS, 1024, 'v' },
12767 #ifdef RLIMIT_LOCKS
12768 { "locks", RLIMIT_LOCKS, 1, 'w' },
12770 { (char *) 0, 0, 0, '\0' }
12773 enum limtype { SOFT = 0x1, HARD = 0x2 };
12775 static void printlim(enum limtype how, const struct rlimit *limit,
12776 const struct limits *l)
12780 val = limit->rlim_max;
12782 val = limit->rlim_cur;
12784 if (val == RLIM_INFINITY)
12785 out1fmt("unlimited\n");
12788 out1fmt("%lld\n", (long long) val);
12793 ulimitcmd(int argc, char **argv)
12797 enum limtype how = SOFT | HARD;
12798 const struct limits *l;
12801 struct rlimit limit;
12804 while ((optc = nextopt("HSa"
12808 #ifdef RLIMIT_FSIZE
12814 #ifdef RLIMIT_STACK
12823 #ifdef RLIMIT_MEMLOCK
12826 #ifdef RLIMIT_NPROC
12829 #ifdef RLIMIT_NOFILE
12835 #ifdef RLIMIT_LOCKS
12853 for (l = limits; l->option != what; l++)
12856 set = *argptr ? 1 : 0;
12860 if (all || argptr[1])
12861 error("too many arguments");
12862 if (strncmp(p, "unlimited\n", 9) == 0)
12863 val = RLIM_INFINITY;
12867 while ((c = *p++) >= '0' && c <= '9')
12869 val = (val * 10) + (long)(c - '0');
12870 if (val < (rlim_t) 0)
12874 error("bad number");
12879 for (l = limits; l->name; l++) {
12880 getrlimit(l->cmd, &limit);
12881 out1fmt("%-20s ", l->name);
12882 printlim(how, &limit, l);
12887 getrlimit(l->cmd, &limit);
12890 limit.rlim_max = val;
12892 limit.rlim_cur = val;
12893 if (setrlimit(l->cmd, &limit) < 0)
12894 error("error setting limit (%m)");
12896 printlim(how, &limit, l);
12902 #ifdef CONFIG_ASH_MATH_SUPPORT
12904 /* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
12906 Permission is hereby granted, free of charge, to any person obtaining
12907 a copy of this software and associated documentation files (the
12908 "Software"), to deal in the Software without restriction, including
12909 without limitation the rights to use, copy, modify, merge, publish,
12910 distribute, sublicense, and/or sell copies of the Software, and to
12911 permit persons to whom the Software is furnished to do so, subject to
12912 the following conditions:
12914 The above copyright notice and this permission notice shall be
12915 included in all copies or substantial portions of the Software.
12917 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12918 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12919 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
12920 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
12921 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
12922 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
12923 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12926 /* This is my infix parser/evaluator. It is optimized for size, intended
12927 * as a replacement for yacc-based parsers. However, it may well be faster
12928 * than a comparable parser written in yacc. The supported operators are
12929 * listed in #defines below. Parens, order of operations, and error handling
12930 * are supported. This code is thread safe. The exact expression format should
12931 * be that which POSIX specifies for shells. */
12933 /* The code uses a simple two-stack algorithm. See
12934 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
12935 * for a detailed explanation of the infix-to-postfix algorithm on which
12936 * this is based (this code differs in that it applies operators immediately
12937 * to the stack instead of adding them to a queue to end up with an
12940 /* To use the routine, call it with an expression string and error return
12944 * Aug 24, 2001 Manuel Novoa III
12946 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
12948 * 1) In arith_apply():
12949 * a) Cached values of *numptr and &(numptr[-1]).
12950 * b) Removed redundant test for zero denominator.
12953 * a) Eliminated redundant code for processing operator tokens by moving
12954 * to a table-based implementation. Also folded handling of parens
12956 * b) Combined all 3 loops which called arith_apply to reduce generated
12957 * code size at the cost of speed.
12959 * 3) The following expressions were treated as valid by the original code:
12960 * 1() , 0! , 1 ( *3 ) .
12961 * These bugs have been fixed by internally enclosing the expression in
12962 * parens and then checking that all binary ops and right parens are
12963 * preceded by a valid expression (NUM_TOKEN).
12965 * Note: It may be desirable to replace Aaron's test for whitespace with
12966 * ctype's isspace() if it is used by another busybox applet or if additional
12967 * whitespace chars should be considered. Look below the "#include"s for a
12968 * precompiler test.
12972 * Aug 26, 2001 Manuel Novoa III
12974 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
12976 * Merge in Aaron's comments previously posted to the busybox list,
12977 * modified slightly to take account of my changes to the code.
12982 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12984 * - allow access to variable,
12985 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
12986 * - realize assign syntax (VAR=expr, +=, *= etc)
12987 * - realize exponentiation (** operator)
12988 * - realize comma separated - expr, expr
12989 * - realise ++expr --expr expr++ expr--
12990 * - realise expr ? expr : expr (but, second expr calculate always)
12991 * - allow hexadecimal and octal numbers
12992 * - was restored loses XOR operator
12993 * - remove one goto label, added three ;-)
12994 * - protect $((num num)) as true zero expr (Manuel`s error)
12995 * - always use special isspace(), see comment from bash ;-)
12999 #define arith_isspace(arithval) \
13000 (arithval == ' ' || arithval == '\n' || arithval == '\t')
13003 typedef unsigned char operator;
13005 /* An operator's token id is a bit of a bitfield. The lower 5 bits are the
13006 * precedence, and 3 high bits are an ID unique across operators of that
13007 * precedence. The ID portion is so that multiple operators can have the
13008 * same precedence, ensuring that the leftmost one is evaluated first.
13009 * Consider * and /. */
13011 #define tok_decl(prec,id) (((id)<<5)|(prec))
13012 #define PREC(op) ((op) & 0x1F)
13014 #define TOK_LPAREN tok_decl(0,0)
13016 #define TOK_COMMA tok_decl(1,0)
13018 #define TOK_ASSIGN tok_decl(2,0)
13019 #define TOK_AND_ASSIGN tok_decl(2,1)
13020 #define TOK_OR_ASSIGN tok_decl(2,2)
13021 #define TOK_XOR_ASSIGN tok_decl(2,3)
13022 #define TOK_PLUS_ASSIGN tok_decl(2,4)
13023 #define TOK_MINUS_ASSIGN tok_decl(2,5)
13024 #define TOK_LSHIFT_ASSIGN tok_decl(2,6)
13025 #define TOK_RSHIFT_ASSIGN tok_decl(2,7)
13027 #define TOK_MUL_ASSIGN tok_decl(3,0)
13028 #define TOK_DIV_ASSIGN tok_decl(3,1)
13029 #define TOK_REM_ASSIGN tok_decl(3,2)
13031 /* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
13032 #define convert_prec_is_assing(prec) do { if(prec == 3) prec = 2; } while(0)
13034 /* conditional is right associativity too */
13035 #define TOK_CONDITIONAL tok_decl(4,0)
13036 #define TOK_CONDITIONAL_SEP tok_decl(4,1)
13038 #define TOK_OR tok_decl(5,0)
13040 #define TOK_AND tok_decl(6,0)
13042 #define TOK_BOR tok_decl(7,0)
13044 #define TOK_BXOR tok_decl(8,0)
13046 #define TOK_BAND tok_decl(9,0)
13048 #define TOK_EQ tok_decl(10,0)
13049 #define TOK_NE tok_decl(10,1)
13051 #define TOK_LT tok_decl(11,0)
13052 #define TOK_GT tok_decl(11,1)
13053 #define TOK_GE tok_decl(11,2)
13054 #define TOK_LE tok_decl(11,3)
13056 #define TOK_LSHIFT tok_decl(12,0)
13057 #define TOK_RSHIFT tok_decl(12,1)
13059 #define TOK_ADD tok_decl(13,0)
13060 #define TOK_SUB tok_decl(13,1)
13062 #define TOK_MUL tok_decl(14,0)
13063 #define TOK_DIV tok_decl(14,1)
13064 #define TOK_REM tok_decl(14,2)
13066 /* exponent is right associativity */
13067 #define TOK_EXPONENT tok_decl(15,1)
13069 /* For now unary operators. */
13070 #define UNARYPREC 16
13071 #define TOK_BNOT tok_decl(UNARYPREC,0)
13072 #define TOK_NOT tok_decl(UNARYPREC,1)
13074 #define TOK_UMINUS tok_decl(UNARYPREC+1,0)
13075 #define TOK_UPLUS tok_decl(UNARYPREC+1,1)
13077 #define PREC_PRE (UNARYPREC+2)
13079 #define TOK_PRE_INC tok_decl(PREC_PRE, 0)
13080 #define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
13082 #define PREC_POST (UNARYPREC+3)
13084 #define TOK_POST_INC tok_decl(PREC_POST, 0)
13085 #define TOK_POST_DEC tok_decl(PREC_POST, 1)
13087 #define SPEC_PREC (UNARYPREC+4)
13089 #define TOK_NUM tok_decl(SPEC_PREC, 0)
13090 #define TOK_RPAREN tok_decl(SPEC_PREC, 1)
13092 #define NUMPTR (*numstackptr)
13094 static inline int tok_have_assign(operator op)
13096 operator prec = PREC(op);
13098 convert_prec_is_assing(prec);
13099 return (prec == PREC(TOK_ASSIGN) ||
13100 prec == PREC_PRE || prec == PREC_POST);
13103 static inline int is_right_associativity(operator prec)
13105 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) ||
13106 prec == PREC(TOK_CONDITIONAL));
13110 typedef struct ARITCH_VAR_NUM {
13112 arith_t contidional_second_val;
13113 char contidional_second_val_initialized;
13114 char *var; /* if NULL then is regular number,
13115 else is variable name */
13119 typedef struct CHK_VAR_RECURSIVE_LOOPED {
13121 struct CHK_VAR_RECURSIVE_LOOPED *next;
13122 } chk_var_recursive_looped_t;
13124 static chk_var_recursive_looped_t *prev_chk_var_recursive;
13127 static int arith_lookup_val(v_n_t *t)
13130 const char * p = lookupvar(t->var);
13135 /* recursive try as expression */
13136 chk_var_recursive_looped_t *cur;
13137 chk_var_recursive_looped_t cur_save;
13139 for(cur = prev_chk_var_recursive; cur; cur = cur->next) {
13140 if(strcmp(cur->var, t->var) == 0) {
13141 /* expression recursion loop detected */
13145 /* save current lookuped var name */
13146 cur = prev_chk_var_recursive;
13147 cur_save.var = t->var;
13148 cur_save.next = cur;
13149 prev_chk_var_recursive = &cur_save;
13151 t->val = arith (p, &errcode);
13152 /* restore previous ptr after recursiving */
13153 prev_chk_var_recursive = cur;
13156 /* allow undefined var as 0 */
13163 /* "applying" a token means performing it on the top elements on the integer
13164 * stack. For a unary operator it will only change the top element, but a
13165 * binary operator will pop two arguments and push a result */
13167 arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
13170 arith_t numptr_val, rez;
13171 int ret_arith_lookup_val;
13173 if (NUMPTR == numstack) goto err; /* There is no operator that can work
13174 without arguments */
13175 numptr_m1 = NUMPTR - 1;
13177 /* check operand is var with noninteger value */
13178 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13179 if(ret_arith_lookup_val)
13180 return ret_arith_lookup_val;
13182 rez = numptr_m1->val;
13183 if (op == TOK_UMINUS)
13185 else if (op == TOK_NOT)
13187 else if (op == TOK_BNOT)
13189 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
13191 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
13193 else if (op != TOK_UPLUS) {
13194 /* Binary operators */
13196 /* check and binary operators need two arguments */
13197 if (numptr_m1 == numstack) goto err;
13199 /* ... and they pop one */
13202 if (op == TOK_CONDITIONAL) {
13203 if(! numptr_m1->contidional_second_val_initialized) {
13204 /* protect $((expr1 ? expr2)) without ": expr" */
13207 rez = numptr_m1->contidional_second_val;
13208 } else if(numptr_m1->contidional_second_val_initialized) {
13209 /* protect $((expr1 : expr2)) without "expr ? " */
13212 numptr_m1 = NUMPTR - 1;
13213 if(op != TOK_ASSIGN) {
13214 /* check operand is var with noninteger value for not '=' */
13215 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13216 if(ret_arith_lookup_val)
13217 return ret_arith_lookup_val;
13219 if (op == TOK_CONDITIONAL) {
13220 numptr_m1->contidional_second_val = rez;
13222 rez = numptr_m1->val;
13223 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
13225 else if (op == TOK_OR)
13226 rez = numptr_val || rez;
13227 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
13229 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
13231 else if (op == TOK_AND)
13232 rez = rez && numptr_val;
13233 else if (op == TOK_EQ)
13234 rez = (rez == numptr_val);
13235 else if (op == TOK_NE)
13236 rez = (rez != numptr_val);
13237 else if (op == TOK_GE)
13238 rez = (rez >= numptr_val);
13239 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
13240 rez >>= numptr_val;
13241 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
13242 rez <<= numptr_val;
13243 else if (op == TOK_GT)
13244 rez = (rez > numptr_val);
13245 else if (op == TOK_LT)
13246 rez = (rez < numptr_val);
13247 else if (op == TOK_LE)
13248 rez = (rez <= numptr_val);
13249 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
13251 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
13253 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
13255 else if (op == TOK_ASSIGN || op == TOK_COMMA)
13257 else if (op == TOK_CONDITIONAL_SEP) {
13258 if (numptr_m1 == numstack) {
13259 /* protect $((expr : expr)) without "expr ? " */
13262 numptr_m1->contidional_second_val_initialized = op;
13263 numptr_m1->contidional_second_val = numptr_val;
13265 else if (op == TOK_CONDITIONAL) {
13267 numptr_val : numptr_m1->contidional_second_val;
13269 else if(op == TOK_EXPONENT) {
13271 return -3; /* exponent less than 0 */
13276 while(numptr_val--)
13281 else if(numptr_val==0) /* zero divisor check */
13283 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
13285 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
13288 if(tok_have_assign(op)) {
13291 if(numptr_m1->var == NULL) {
13295 /* save to shell variable */
13296 sprintf(buf, "%lld", (long long) rez);
13297 setvar(numptr_m1->var, buf, 0);
13298 /* after saving, make previous value for v++ or v-- */
13299 if(op == TOK_POST_INC)
13301 else if(op == TOK_POST_DEC)
13304 numptr_m1->val = rez;
13305 /* protect geting var value, is number now */
13306 numptr_m1->var = NULL;
13311 /* longest must first */
13312 static const char op_tokens[] = {
13313 '<','<','=',0, TOK_LSHIFT_ASSIGN,
13314 '>','>','=',0, TOK_RSHIFT_ASSIGN,
13315 '<','<', 0, TOK_LSHIFT,
13316 '>','>', 0, TOK_RSHIFT,
13317 '|','|', 0, TOK_OR,
13318 '&','&', 0, TOK_AND,
13319 '!','=', 0, TOK_NE,
13320 '<','=', 0, TOK_LE,
13321 '>','=', 0, TOK_GE,
13322 '=','=', 0, TOK_EQ,
13323 '|','=', 0, TOK_OR_ASSIGN,
13324 '&','=', 0, TOK_AND_ASSIGN,
13325 '*','=', 0, TOK_MUL_ASSIGN,
13326 '/','=', 0, TOK_DIV_ASSIGN,
13327 '%','=', 0, TOK_REM_ASSIGN,
13328 '+','=', 0, TOK_PLUS_ASSIGN,
13329 '-','=', 0, TOK_MINUS_ASSIGN,
13330 '-','-', 0, TOK_POST_DEC,
13331 '^','=', 0, TOK_XOR_ASSIGN,
13332 '+','+', 0, TOK_POST_INC,
13333 '*','*', 0, TOK_EXPONENT,
13337 '=', 0, TOK_ASSIGN,
13349 '?', 0, TOK_CONDITIONAL,
13350 ':', 0, TOK_CONDITIONAL_SEP,
13351 ')', 0, TOK_RPAREN,
13352 '(', 0, TOK_LPAREN,
13356 #define endexpression &op_tokens[sizeof(op_tokens)-7]
13359 static arith_t arith (const char *expr, int *perrcode)
13361 register char arithval; /* Current character under analysis */
13362 operator lasttok, op;
13365 const char *p = endexpression;
13368 size_t datasizes = strlen(expr) + 2;
13370 /* Stack of integers */
13371 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
13372 * in any given correct or incorrect expression is left as an exercise to
13374 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
13375 *numstackptr = numstack;
13376 /* Stack of operator tokens */
13377 operator *stack = alloca((datasizes) * sizeof(operator)),
13380 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
13381 *perrcode = errcode = 0;
13384 if ((arithval = *expr) == 0) {
13385 if (p == endexpression) {
13386 /* Null expression. */
13390 /* This is only reached after all tokens have been extracted from the
13391 * input stream. If there are still tokens on the operator stack, they
13392 * are to be applied in order. At the end, there should be a final
13393 * result on the integer stack */
13395 if (expr != endexpression + 1) {
13396 /* If we haven't done so already, */
13397 /* append a closing right paren */
13398 expr = endexpression;
13399 /* and let the loop process it. */
13402 /* At this point, we're done with the expression. */
13403 if (numstackptr != numstack+1) {
13404 /* ... but if there isn't, it's bad */
13406 return (*perrcode = -1);
13408 if(numstack->var) {
13409 /* expression is $((var)) only, lookup now */
13410 errcode = arith_lookup_val(numstack);
13413 *perrcode = errcode;
13414 return numstack->val;
13416 /* Continue processing the expression. */
13417 if (arith_isspace(arithval)) {
13418 /* Skip whitespace */
13421 if((p = endofname(expr)) != expr) {
13422 int var_name_size = (p-expr) + 1; /* trailing zero */
13424 numstackptr->var = alloca(var_name_size);
13425 safe_strncpy(numstackptr->var, expr, var_name_size);
13428 numstackptr->contidional_second_val_initialized = 0;
13432 } else if (is_digit(arithval)) {
13433 numstackptr->var = NULL;
13434 numstackptr->val = strtol(expr, (char **) &expr, 0);
13437 for(p = op_tokens; ; p++) {
13441 /* strange operator not found */
13444 for(o = expr; *p && *o == *p; p++)
13451 /* skip tail uncompared token */
13454 /* skip zero delim */
13459 /* post grammar: a++ reduce to num */
13460 if(lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13463 /* Plus and minus are binary (not unary) _only_ if the last
13464 * token was as number, or a right paren (which pretends to be
13465 * a number, since it evaluates to one). Think about it.
13466 * It makes sense. */
13467 if (lasttok != TOK_NUM) {
13483 /* We don't want a unary operator to cause recursive descent on the
13484 * stack, because there can be many in a row and it could cause an
13485 * operator to be evaluated before its argument is pushed onto the
13486 * integer stack. */
13487 /* But for binary operators, "apply" everything on the operator
13488 * stack until we find an operator with a lesser priority than the
13489 * one we have just extracted. */
13490 /* Left paren is given the lowest priority so it will never be
13491 * "applied" in this way.
13492 * if associativity is right and priority eq, applied also skip
13495 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13496 /* not left paren or unary */
13497 if (lasttok != TOK_NUM) {
13498 /* binary op must be preceded by a num */
13501 while (stackptr != stack) {
13502 if (op == TOK_RPAREN) {
13503 /* The algorithm employed here is simple: while we don't
13504 * hit an open paren nor the bottom of the stack, pop
13505 * tokens and apply them */
13506 if (stackptr[-1] == TOK_LPAREN) {
13508 /* Any operator directly after a */
13510 /* close paren should consider itself binary */
13514 operator prev_prec = PREC(stackptr[-1]);
13516 convert_prec_is_assing(prec);
13517 convert_prec_is_assing(prev_prec);
13518 if (prev_prec < prec)
13520 /* check right assoc */
13521 if(prev_prec == prec && is_right_associativity(prec))
13524 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13525 if(errcode) goto ret;
13527 if (op == TOK_RPAREN) {
13532 /* Push this operator to the stack and remember it. */
13533 *stackptr++ = lasttok = op;
13540 #endif /* CONFIG_ASH_MATH_SUPPORT */
13544 const char *bb_applet_name = "debug stuff usage";
13545 int main(int argc, char **argv)
13547 return ash_main(argc, argv);
13552 * Copyright (c) 1989, 1991, 1993, 1994
13553 * The Regents of the University of California. All rights reserved.
13555 * This code is derived from software contributed to Berkeley by
13556 * Kenneth Almquist.
13558 * Redistribution and use in source and binary forms, with or without
13559 * modification, are permitted provided that the following conditions
13561 * 1. Redistributions of source code must retain the above copyright
13562 * notice, this list of conditions and the following disclaimer.
13563 * 2. Redistributions in binary form must reproduce the above copyright
13564 * notice, this list of conditions and the following disclaimer in the
13565 * documentation and/or other materials provided with the distribution.
13567 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
13568 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
13570 * 4. Neither the name of the University nor the names of its contributors
13571 * may be used to endorse or promote products derived from this software
13572 * without specific prior written permission.
13574 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13575 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13576 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13577 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13578 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13579 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13580 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13581 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13582 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13583 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF