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-2005 Herbert Xu <herbert@gondor.apana.org.au>
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
108 #if JOBS || defined(CONFIG_ASH_READ_NCHARS)
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 */
279 /* $NetBSD: expand.h,v 1.13 2002/11/24 22:35:40 christos Exp $ */
282 struct strlist *next;
288 struct strlist *list;
289 struct strlist **lastp;
295 #define EXP_FULL 0x1 /* perform word splitting & file globbing */
296 #define EXP_TILDE 0x2 /* do normal tilde expansion */
297 #define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
298 #define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
299 #define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
300 #define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
301 #define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
302 #define EXP_WORD 0x80 /* expand word in parameter expansion */
303 #define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */
307 static void expandarg(union node *, struct arglist *, int);
308 #define rmescapes(p) _rmescapes((p), 0)
309 static char *_rmescapes(char *, int);
310 static int casematch(union node *, char *);
312 #ifdef CONFIG_ASH_MATH_SUPPORT
313 static void expari(int);
316 /* $NetBSD: eval.h,v 1.13 2002/11/24 22:35:39 christos Exp $ */
318 static char *commandname; /* currently executing command */
319 static struct strlist *cmdenviron; /* environment for builtin command */
320 static int exitstatus; /* exit status of last command */
321 static int back_exitstatus; /* exit status of backquoted command */
324 struct backcmd { /* result of evalbackcmd */
325 int fd; /* file descriptor to read from */
326 char *buf; /* buffer */
327 int nleft; /* number of chars in buffer */
328 struct job *jp; /* job structure for command */
332 * This file was generated by the mknodes program.
368 union node *redirect;
375 struct nodelist *cmdlist;
382 union node *redirect;
397 union node *elsepart;
428 struct nodelist *backquote;
468 struct nredir nredir;
469 struct nbinary nbinary;
473 struct nclist nclist;
483 struct nodelist *next;
494 static void freefunc(struct funcnode *);
495 /* $NetBSD: parser.h,v 1.15 2002/11/24 22:35:42 christos Exp $ */
497 /* control characters in argument strings */
498 #define CTL_FIRST '\201' /* first 'special' character */
499 #define CTLESC '\201' /* escape next character */
500 #define CTLVAR '\202' /* variable defn */
501 #define CTLENDVAR '\203'
502 #define CTLBACKQ '\204'
503 #define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
504 /* CTLBACKQ | CTLQUOTE == '\205' */
505 #define CTLARI '\206' /* arithmetic expression */
506 #define CTLENDARI '\207'
507 #define CTLQUOTEMARK '\210'
508 #define CTL_LAST '\210' /* last 'special' character */
510 /* variable substitution byte (follows CTLVAR) */
511 #define VSTYPE 0x0f /* type of variable substitution */
512 #define VSNUL 0x10 /* colon--treat the empty string as unset */
513 #define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
515 /* values of VSTYPE field */
516 #define VSNORMAL 0x1 /* normal variable: $var or ${var} */
517 #define VSMINUS 0x2 /* ${var-text} */
518 #define VSPLUS 0x3 /* ${var+text} */
519 #define VSQUESTION 0x4 /* ${var?message} */
520 #define VSASSIGN 0x5 /* ${var=text} */
521 #define VSTRIMRIGHT 0x6 /* ${var%pattern} */
522 #define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
523 #define VSTRIMLEFT 0x8 /* ${var#pattern} */
524 #define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
525 #define VSLENGTH 0xa /* ${#var} */
527 /* values of checkkwd variable */
532 #define IBUFSIZ (BUFSIZ + 1)
535 * NEOF is returned by parsecmd when it encounters an end of file. It
536 * must be distinct from NULL, so we use the address of a variable that
537 * happens to be handy.
539 static int plinno = 1; /* input line number */
541 /* number of characters left in input buffer */
542 static int parsenleft; /* copy of parsefile->nleft */
543 static int parselleft; /* copy of parsefile->lleft */
545 /* next character in input buffer */
546 static char *parsenextc; /* copy of parsefile->nextc */
549 struct strpush *prev; /* preceding string on stack */
552 #ifdef CONFIG_ASH_ALIAS
553 struct alias *ap; /* if push was associated with an alias */
555 char *string; /* remember the string since it may change */
559 struct parsefile *prev; /* preceding file on stack */
560 int linno; /* current line */
561 int fd; /* file descriptor (or -1 if string) */
562 int nleft; /* number of chars left in this line */
563 int lleft; /* number of chars left in this buffer */
564 char *nextc; /* next char in buffer */
565 char *buf; /* input buffer */
566 struct strpush *strpush; /* for pushing strings at this level */
567 struct strpush basestrpush; /* so pushing one is fast */
570 static struct parsefile basepf; /* top level input file */
571 #define basebuf bb_common_bufsiz1 /* buffer for top level input file */
572 static struct parsefile *parsefile = &basepf; /* current input file */
575 static int tokpushback; /* last token pushed back */
576 #define NEOF ((union node *)&tokpushback)
577 static int parsebackquote; /* nonzero if we are inside backquotes */
578 static int doprompt; /* if set, prompt the user */
579 static int needprompt; /* true if interactive and at start of line */
580 static int lasttoken; /* last token read */
581 static char *wordtext; /* text of last word returned by readtoken */
583 static struct nodelist *backquotelist;
584 static union node *redirnode;
585 static struct heredoc *heredoc;
586 static int quoteflag; /* set if (part of) last token was quoted */
587 static int startlinno; /* line # where last token started */
589 static union node *parsecmd(int);
590 static void fixredir(union node *, const char *, int);
591 static const char *const *findkwd(const char *);
592 static char *endofname(const char *);
594 /* $NetBSD: shell.h,v 1.16 2003/01/22 20:36:04 dsl Exp $ */
596 typedef void *pointer;
598 static char nullstr[1]; /* zero length string */
599 static const char spcstr[] = " ";
600 static const char snlfmt[] = "%s\n";
601 static const char dolatstr[] = { CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' };
602 static const char illnum[] = "Illegal number: %s";
603 static const char homestr[] = "HOME";
606 #define TRACE(param) trace param
607 #define TRACEV(param) tracev param
610 #define TRACEV(param)
613 #if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
614 #define __builtin_expect(x, expected_value) (x)
617 #define xlikely(x) __builtin_expect((x),1)
632 #define TENDBQUOTE 12
650 /* first char is indicating which tokens mark the end of a list */
651 static const char *const tokname_array[] = {
666 /* the following are keywords */
685 static const char *tokname(int tok)
691 sprintf(buf + (tok >= TSEMI), "%s%c",
692 tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));
696 /* $NetBSD: machdep.h,v 1.10 2002/10/07 14:26:08 christos Exp $ */
699 * Most machines require the value returned from malloc to be aligned
700 * in some way. The following macro will get this right on many machines.
703 #define SHELL_SIZE (sizeof(union {int i; char *cp; double d; }) - 1)
705 * It appears that grabstackstr() will barf with such alignments
706 * because stalloc() will return a string allocated in a new stackblock.
708 #define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
711 * This file was generated by the mksyntax program.
716 #define CWORD 0 /* character is nothing special */
717 #define CNL 1 /* newline character */
718 #define CBACK 2 /* a backslash character */
719 #define CSQUOTE 3 /* single quote */
720 #define CDQUOTE 4 /* double quote */
721 #define CENDQUOTE 5 /* a terminating quote */
722 #define CBQUOTE 6 /* backwards single quote */
723 #define CVAR 7 /* a dollar sign */
724 #define CENDVAR 8 /* a '}' character */
725 #define CLP 9 /* a left paren in arithmetic */
726 #define CRP 10 /* a right paren in arithmetic */
727 #define CENDFILE 11 /* end of file */
728 #define CCTL 12 /* like CWORD, except it must be escaped */
729 #define CSPCL 13 /* these terminate a word */
730 #define CIGN 14 /* character should be ignored */
732 #ifdef CONFIG_ASH_ALIAS
736 #define PEOA_OR_PEOF PEOA
740 #define PEOA_OR_PEOF PEOF
743 #define is_digit(c) ((unsigned)((c) - '0') <= 9)
744 #define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
745 #define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
748 * is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
749 * (assuming ascii char codes, as the original implementation did)
751 #define is_special(c) \
752 ( (((unsigned int)c) - 33 < 32) \
753 && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
755 #define digit_val(c) ((c) - '0')
758 * This file was generated by the mksyntax program.
761 #ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
762 #define USE_SIT_FUNCTION
765 /* number syntax index */
766 #define BASESYNTAX 0 /* not in quotes */
767 #define DQSYNTAX 1 /* in double quotes */
768 #define SQSYNTAX 2 /* in single quotes */
769 #define ARISYNTAX 3 /* in arithmetic */
771 #ifdef CONFIG_ASH_MATH_SUPPORT
772 static const char S_I_T[][4] = {
773 #ifdef CONFIG_ASH_ALIAS
774 {CSPCL, CIGN, CIGN, CIGN}, /* 0, PEOA */
776 {CSPCL, CWORD, CWORD, CWORD}, /* 1, ' ' */
777 {CNL, CNL, CNL, CNL}, /* 2, \n */
778 {CWORD, CCTL, CCTL, CWORD}, /* 3, !*-/:=?[]~ */
779 {CDQUOTE, CENDQUOTE, CWORD, CWORD}, /* 4, '"' */
780 {CVAR, CVAR, CWORD, CVAR}, /* 5, $ */
781 {CSQUOTE, CWORD, CENDQUOTE, CWORD}, /* 6, "'" */
782 {CSPCL, CWORD, CWORD, CLP}, /* 7, ( */
783 {CSPCL, CWORD, CWORD, CRP}, /* 8, ) */
784 {CBACK, CBACK, CCTL, CBACK}, /* 9, \ */
785 {CBQUOTE, CBQUOTE, CWORD, CBQUOTE}, /* 10, ` */
786 {CENDVAR, CENDVAR, CWORD, CENDVAR}, /* 11, } */
787 #ifndef USE_SIT_FUNCTION
788 {CENDFILE, CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */
789 {CWORD, CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */
790 {CCTL, CCTL, CCTL, CCTL} /* 14, CTLESC ... */
794 static const char S_I_T[][3] = {
795 #ifdef CONFIG_ASH_ALIAS
796 {CSPCL, CIGN, CIGN}, /* 0, PEOA */
798 {CSPCL, CWORD, CWORD}, /* 1, ' ' */
799 {CNL, CNL, CNL}, /* 2, \n */
800 {CWORD, CCTL, CCTL}, /* 3, !*-/:=?[]~ */
801 {CDQUOTE, CENDQUOTE, CWORD}, /* 4, '"' */
802 {CVAR, CVAR, CWORD}, /* 5, $ */
803 {CSQUOTE, CWORD, CENDQUOTE}, /* 6, "'" */
804 {CSPCL, CWORD, CWORD}, /* 7, ( */
805 {CSPCL, CWORD, CWORD}, /* 8, ) */
806 {CBACK, CBACK, CCTL}, /* 9, \ */
807 {CBQUOTE, CBQUOTE, CWORD}, /* 10, ` */
808 {CENDVAR, CENDVAR, CWORD}, /* 11, } */
809 #ifndef USE_SIT_FUNCTION
810 {CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */
811 {CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */
812 {CCTL, CCTL, CCTL} /* 14, CTLESC ... */
815 #endif /* CONFIG_ASH_MATH_SUPPORT */
817 #ifdef USE_SIT_FUNCTION
819 #define U_C(c) ((unsigned char)(c))
821 static int SIT(int c, int syntax)
823 static const char spec_symbls[] = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
824 #ifdef CONFIG_ASH_ALIAS
825 static const char syntax_index_table[] = {
826 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
827 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
828 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
832 static const char syntax_index_table[] = {
833 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
834 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */
835 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
842 if (c == PEOF) /* 2^8+2 */
844 #ifdef CONFIG_ASH_ALIAS
845 if (c == PEOA) /* 2^8+1 */
849 if (U_C(c) >= U_C(CTLESC) && U_C(c) <= U_C(CTLQUOTEMARK))
852 s = strchr(spec_symbls, c);
853 if (s == 0 || *s == 0)
855 indx = syntax_index_table[(s - spec_symbls)];
857 return S_I_T[indx][syntax];
860 #else /* USE_SIT_FUNCTION */
862 #define SIT(c, syntax) S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax]
864 #ifdef CONFIG_ASH_ALIAS
865 #define CSPCL_CIGN_CIGN_CIGN 0
866 #define CSPCL_CWORD_CWORD_CWORD 1
867 #define CNL_CNL_CNL_CNL 2
868 #define CWORD_CCTL_CCTL_CWORD 3
869 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 4
870 #define CVAR_CVAR_CWORD_CVAR 5
871 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 6
872 #define CSPCL_CWORD_CWORD_CLP 7
873 #define CSPCL_CWORD_CWORD_CRP 8
874 #define CBACK_CBACK_CCTL_CBACK 9
875 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10
876 #define CENDVAR_CENDVAR_CWORD_CENDVAR 11
877 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
878 #define CWORD_CWORD_CWORD_CWORD 13
879 #define CCTL_CCTL_CCTL_CCTL 14
881 #define CSPCL_CWORD_CWORD_CWORD 0
882 #define CNL_CNL_CNL_CNL 1
883 #define CWORD_CCTL_CCTL_CWORD 2
884 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 3
885 #define CVAR_CVAR_CWORD_CVAR 4
886 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 5
887 #define CSPCL_CWORD_CWORD_CLP 6
888 #define CSPCL_CWORD_CWORD_CRP 7
889 #define CBACK_CBACK_CCTL_CBACK 8
890 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 9
891 #define CENDVAR_CENDVAR_CWORD_CENDVAR 10
892 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 11
893 #define CWORD_CWORD_CWORD_CWORD 12
894 #define CCTL_CCTL_CCTL_CCTL 13
897 static const char syntax_index_table[258] = {
898 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
899 /* 0 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
900 #ifdef CONFIG_ASH_ALIAS
901 /* 1 PEOA */ CSPCL_CIGN_CIGN_CIGN,
903 /* 2 -128 0x80 */ CWORD_CWORD_CWORD_CWORD,
904 /* 3 -127 CTLESC */ CCTL_CCTL_CCTL_CCTL,
905 /* 4 -126 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
906 /* 5 -125 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
907 /* 6 -124 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
908 /* 7 -123 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
909 /* 8 -122 CTLARI */ CCTL_CCTL_CCTL_CCTL,
910 /* 9 -121 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
911 /* 10 -120 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
912 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD,
913 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD,
914 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD,
915 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD,
916 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD,
917 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD,
918 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD,
919 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD,
920 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,
921 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD,
922 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD,
923 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD,
924 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD,
925 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD,
926 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD,
927 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD,
928 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD,
929 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD,
930 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,
931 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD,
932 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD,
933 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD,
934 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD,
935 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD,
936 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD,
937 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD,
938 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD,
939 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,
940 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,
941 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD,
942 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD,
943 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD,
944 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD,
945 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD,
946 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD,
947 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD,
948 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD,
949 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD,
950 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD,
951 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD,
952 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD,
953 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD,
954 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD,
955 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD,
956 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD,
957 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD,
958 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD,
959 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,
960 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,
961 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD,
962 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD,
963 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD,
964 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD,
965 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD,
966 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD,
967 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD,
968 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD,
969 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD,
970 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD,
971 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD,
972 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD,
973 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD,
974 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD,
975 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD,
976 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD,
977 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD,
978 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD,
979 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD,
980 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD,
981 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD,
982 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD,
983 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD,
984 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD,
985 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD,
986 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD,
987 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD,
988 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD,
989 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD,
990 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,
991 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD,
992 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD,
993 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD,
994 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD,
995 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD,
996 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD,
997 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD,
998 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD,
999 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD,
1000 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD,
1001 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD,
1002 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD,
1003 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD,
1004 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD,
1005 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD,
1006 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD,
1007 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD,
1008 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD,
1009 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD,
1010 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD,
1011 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD,
1012 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD,
1013 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD,
1014 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD,
1015 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD,
1016 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD,
1017 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD,
1018 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD,
1019 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD,
1020 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD,
1021 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD,
1022 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD,
1023 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD,
1024 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD,
1025 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD,
1026 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD,
1027 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD,
1028 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD,
1029 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD,
1030 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD,
1031 /* 130 0 */ CWORD_CWORD_CWORD_CWORD,
1032 /* 131 1 */ CWORD_CWORD_CWORD_CWORD,
1033 /* 132 2 */ CWORD_CWORD_CWORD_CWORD,
1034 /* 133 3 */ CWORD_CWORD_CWORD_CWORD,
1035 /* 134 4 */ CWORD_CWORD_CWORD_CWORD,
1036 /* 135 5 */ CWORD_CWORD_CWORD_CWORD,
1037 /* 136 6 */ CWORD_CWORD_CWORD_CWORD,
1038 /* 137 7 */ CWORD_CWORD_CWORD_CWORD,
1039 /* 138 8 */ CWORD_CWORD_CWORD_CWORD,
1040 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
1041 /* 140 10 "\n" */ CNL_CNL_CNL_CNL,
1042 /* 141 11 */ CWORD_CWORD_CWORD_CWORD,
1043 /* 142 12 */ CWORD_CWORD_CWORD_CWORD,
1044 /* 143 13 */ CWORD_CWORD_CWORD_CWORD,
1045 /* 144 14 */ CWORD_CWORD_CWORD_CWORD,
1046 /* 145 15 */ CWORD_CWORD_CWORD_CWORD,
1047 /* 146 16 */ CWORD_CWORD_CWORD_CWORD,
1048 /* 147 17 */ CWORD_CWORD_CWORD_CWORD,
1049 /* 148 18 */ CWORD_CWORD_CWORD_CWORD,
1050 /* 149 19 */ CWORD_CWORD_CWORD_CWORD,
1051 /* 150 20 */ CWORD_CWORD_CWORD_CWORD,
1052 /* 151 21 */ CWORD_CWORD_CWORD_CWORD,
1053 /* 152 22 */ CWORD_CWORD_CWORD_CWORD,
1054 /* 153 23 */ CWORD_CWORD_CWORD_CWORD,
1055 /* 154 24 */ CWORD_CWORD_CWORD_CWORD,
1056 /* 155 25 */ CWORD_CWORD_CWORD_CWORD,
1057 /* 156 26 */ CWORD_CWORD_CWORD_CWORD,
1058 /* 157 27 */ CWORD_CWORD_CWORD_CWORD,
1059 /* 158 28 */ CWORD_CWORD_CWORD_CWORD,
1060 /* 159 29 */ CWORD_CWORD_CWORD_CWORD,
1061 /* 160 30 */ CWORD_CWORD_CWORD_CWORD,
1062 /* 161 31 */ CWORD_CWORD_CWORD_CWORD,
1063 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD,
1064 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD,
1065 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
1066 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD,
1067 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR,
1068 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD,
1069 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
1070 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
1071 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP,
1072 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP,
1073 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD,
1074 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD,
1075 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD,
1076 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD,
1077 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD,
1078 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD,
1079 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD,
1080 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD,
1081 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD,
1082 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD,
1083 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD,
1084 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD,
1085 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD,
1086 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD,
1087 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD,
1088 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD,
1089 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD,
1090 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
1091 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
1092 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD,
1093 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
1094 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD,
1095 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD,
1096 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD,
1097 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD,
1098 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD,
1099 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD,
1100 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD,
1101 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD,
1102 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD,
1103 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD,
1104 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD,
1105 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD,
1106 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD,
1107 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD,
1108 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD,
1109 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD,
1110 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD,
1111 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD,
1112 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
1113 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD,
1114 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD,
1115 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD,
1116 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD,
1117 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD,
1118 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD,
1119 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD,
1120 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
1121 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
1122 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD,
1123 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK,
1124 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD,
1125 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD,
1126 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD,
1127 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
1128 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD,
1129 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD,
1130 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD,
1131 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD,
1132 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD,
1133 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD,
1134 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD,
1135 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD,
1136 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD,
1137 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD,
1138 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD,
1139 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD,
1140 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD,
1141 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD,
1142 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD,
1143 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD,
1144 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD,
1145 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD,
1146 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD,
1147 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD,
1148 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD,
1149 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD,
1150 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD,
1151 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD,
1152 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD,
1153 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD,
1154 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD,
1155 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
1156 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
1157 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,
1158 /* 257 127 */ CWORD_CWORD_CWORD_CWORD,
1161 #endif /* USE_SIT_FUNCTION */
1163 /* $NetBSD: alias.c,v 1.11 2002/11/24 22:35:38 christos Exp $ */
1168 static int funcblocksize; /* size of structures in function */
1169 static int funcstringsize; /* size of strings in node */
1170 static pointer funcblock; /* block to allocate function from */
1171 static char *funcstring; /* block to allocate strings from */
1173 static const short nodesize[26] = {
1174 SHELL_ALIGN(sizeof (struct ncmd)),
1175 SHELL_ALIGN(sizeof (struct npipe)),
1176 SHELL_ALIGN(sizeof (struct nredir)),
1177 SHELL_ALIGN(sizeof (struct nredir)),
1178 SHELL_ALIGN(sizeof (struct nredir)),
1179 SHELL_ALIGN(sizeof (struct nbinary)),
1180 SHELL_ALIGN(sizeof (struct nbinary)),
1181 SHELL_ALIGN(sizeof (struct nbinary)),
1182 SHELL_ALIGN(sizeof (struct nif)),
1183 SHELL_ALIGN(sizeof (struct nbinary)),
1184 SHELL_ALIGN(sizeof (struct nbinary)),
1185 SHELL_ALIGN(sizeof (struct nfor)),
1186 SHELL_ALIGN(sizeof (struct ncase)),
1187 SHELL_ALIGN(sizeof (struct nclist)),
1188 SHELL_ALIGN(sizeof (struct narg)),
1189 SHELL_ALIGN(sizeof (struct narg)),
1190 SHELL_ALIGN(sizeof (struct nfile)),
1191 SHELL_ALIGN(sizeof (struct nfile)),
1192 SHELL_ALIGN(sizeof (struct nfile)),
1193 SHELL_ALIGN(sizeof (struct nfile)),
1194 SHELL_ALIGN(sizeof (struct nfile)),
1195 SHELL_ALIGN(sizeof (struct ndup)),
1196 SHELL_ALIGN(sizeof (struct ndup)),
1197 SHELL_ALIGN(sizeof (struct nhere)),
1198 SHELL_ALIGN(sizeof (struct nhere)),
1199 SHELL_ALIGN(sizeof (struct nnot)),
1203 static void calcsize(union node *);
1204 static void sizenodelist(struct nodelist *);
1205 static union node *copynode(union node *);
1206 static struct nodelist *copynodelist(struct nodelist *);
1207 static char *nodesavestr(char *);
1211 static void evalstring(char *);
1212 union node; /* BLETCH for ansi C */
1213 static void evaltree(union node *, int);
1214 static void evalbackcmd(union node *, struct backcmd *);
1216 /* in_function returns nonzero if we are currently evaluating a function */
1217 #define in_function() funcnest
1218 static int evalskip; /* set if we are skipping commands */
1219 static int skipcount; /* number of levels to skip */
1220 static int funcnest; /* depth of function calls */
1222 /* reasons for skipping commands (see comment on breakcmd routine) */
1229 * This file was generated by the mkbuiltins program.
1233 static int bgcmd(int, char **);
1235 static int breakcmd(int, char **);
1236 static int cdcmd(int, char **);
1237 #ifdef CONFIG_ASH_CMDCMD
1238 static int commandcmd(int, char **);
1240 static int dotcmd(int, char **);
1241 static int evalcmd(int, char **);
1242 #ifdef CONFIG_ASH_BUILTIN_ECHO
1243 static int echocmd(int, char **);
1245 static int execcmd(int, char **);
1246 static int exitcmd(int, char **);
1247 static int exportcmd(int, char **);
1248 static int falsecmd(int, char **);
1250 static int fgcmd(int, char **);
1252 #ifdef CONFIG_ASH_GETOPTS
1253 static int getoptscmd(int, char **);
1255 static int hashcmd(int, char **);
1256 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1257 static int helpcmd(int argc, char **argv);
1260 static int jobscmd(int, char **);
1262 #ifdef CONFIG_ASH_MATH_SUPPORT
1263 static int letcmd(int, char **);
1265 static int localcmd(int, char **);
1266 static int pwdcmd(int, char **);
1267 static int readcmd(int, char **);
1268 static int returncmd(int, char **);
1269 static int setcmd(int, char **);
1270 static int shiftcmd(int, char **);
1271 static int timescmd(int, char **);
1272 static int trapcmd(int, char **);
1273 static int truecmd(int, char **);
1274 static int typecmd(int, char **);
1275 static int umaskcmd(int, char **);
1276 static int unsetcmd(int, char **);
1277 static int waitcmd(int, char **);
1278 static int ulimitcmd(int, char **);
1280 static int killcmd(int, char **);
1283 /* $NetBSD: mail.h,v 1.9 2002/11/24 22:35:40 christos Exp $ */
1285 #ifdef CONFIG_ASH_MAIL
1286 static void chkmail(void);
1287 static void changemail(const char *);
1290 /* $NetBSD: exec.h,v 1.20 2003/01/22 20:36:04 dsl Exp $ */
1292 /* values of cmdtype */
1293 #define CMDUNKNOWN -1 /* no entry in table for command */
1294 #define CMDNORMAL 0 /* command is an executable program */
1295 #define CMDFUNCTION 1 /* command is a shell function */
1296 #define CMDBUILTIN 2 /* command is a shell builtin */
1300 int (*builtin)(int, char **);
1301 /* unsigned flags; */
1305 #define COMMANDCMD (builtincmd + 5 + \
1306 ENABLE_ASH_ALIAS + ENABLE_ASH_JOB_CONTROL)
1307 #define EXECCMD (builtincmd + 7 + \
1308 ENABLE_ASH_CMDCMD + ENABLE_ASH_ALIAS + \
1309 ENABLE_ASH_BUILTIN_ECHO + ENABLE_ASH_JOB_CONTROL)
1311 #define BUILTIN_NOSPEC "0"
1312 #define BUILTIN_SPECIAL "1"
1313 #define BUILTIN_REGULAR "2"
1314 #define BUILTIN_SPEC_REG "3"
1315 #define BUILTIN_ASSIGN "4"
1316 #define BUILTIN_SPEC_ASSG "5"
1317 #define BUILTIN_REG_ASSG "6"
1318 #define BUILTIN_SPEC_REG_ASSG "7"
1320 #define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1321 #define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
1322 #define IS_BUILTIN_ASSIGN(builtincmd) ((builtincmd)->name[0] & 4)
1324 static const struct builtincmd builtincmd[] = {
1325 { BUILTIN_SPEC_REG ".", dotcmd },
1326 { BUILTIN_SPEC_REG ":", truecmd },
1327 #ifdef CONFIG_ASH_ALIAS
1328 { BUILTIN_REG_ASSG "alias", aliascmd },
1331 { BUILTIN_REGULAR "bg", bgcmd },
1333 { BUILTIN_SPEC_REG "break", breakcmd },
1334 { BUILTIN_REGULAR "cd", cdcmd },
1335 { BUILTIN_NOSPEC "chdir", cdcmd },
1336 #ifdef CONFIG_ASH_CMDCMD
1337 { BUILTIN_REGULAR "command", commandcmd },
1339 { BUILTIN_SPEC_REG "continue", breakcmd },
1340 #ifdef CONFIG_ASH_BUILTIN_ECHO
1341 { BUILTIN_REGULAR "echo", echocmd },
1343 { BUILTIN_SPEC_REG "eval", evalcmd },
1344 { BUILTIN_SPEC_REG "exec", execcmd },
1345 { BUILTIN_SPEC_REG "exit", exitcmd },
1346 { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
1347 { BUILTIN_REGULAR "false", falsecmd },
1349 { BUILTIN_REGULAR "fg", fgcmd },
1351 #ifdef CONFIG_ASH_GETOPTS
1352 { BUILTIN_REGULAR "getopts", getoptscmd },
1354 { BUILTIN_NOSPEC "hash", hashcmd },
1355 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1356 { BUILTIN_NOSPEC "help", helpcmd },
1359 { BUILTIN_REGULAR "jobs", jobscmd },
1360 { BUILTIN_REGULAR "kill", killcmd },
1362 #ifdef CONFIG_ASH_MATH_SUPPORT
1363 { BUILTIN_NOSPEC "let", letcmd },
1365 { BUILTIN_ASSIGN "local", localcmd },
1366 { BUILTIN_NOSPEC "pwd", pwdcmd },
1367 { BUILTIN_REGULAR "read", readcmd },
1368 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
1369 { BUILTIN_SPEC_REG "return", returncmd },
1370 { BUILTIN_SPEC_REG "set", setcmd },
1371 { BUILTIN_SPEC_REG "shift", shiftcmd },
1372 { BUILTIN_SPEC_REG "times", timescmd },
1373 { BUILTIN_SPEC_REG "trap", trapcmd },
1374 { BUILTIN_REGULAR "true", truecmd },
1375 { BUILTIN_NOSPEC "type", typecmd },
1376 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
1377 { BUILTIN_REGULAR "umask", umaskcmd },
1378 #ifdef CONFIG_ASH_ALIAS
1379 { BUILTIN_REGULAR "unalias", unaliascmd },
1381 { BUILTIN_SPEC_REG "unset", unsetcmd },
1382 { BUILTIN_REGULAR "wait", waitcmd },
1385 #define NUMBUILTINS (sizeof (builtincmd) / sizeof (struct builtincmd) )
1393 const struct builtincmd *cmd;
1394 struct funcnode *func;
1399 /* action to find_command() */
1400 #define DO_ERR 0x01 /* prints errors */
1401 #define DO_ABS 0x02 /* checks absolute paths */
1402 #define DO_NOFUNC 0x04 /* don't return shell functions, for command */
1403 #define DO_ALTPATH 0x08 /* using alternate path */
1404 #define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
1406 static const char *pathopt; /* set by padvance */
1408 static void shellexec(char **, const char *, int)
1409 __attribute__((__noreturn__));
1410 static char *padvance(const char **, const char *);
1411 static void find_command(char *, struct cmdentry *, int, const char *);
1412 static struct builtincmd *find_builtin(const char *);
1413 static void hashcd(void);
1414 static void changepath(const char *);
1415 static void defun(char *, union node *);
1416 static void unsetfunc(const char *);
1418 #ifdef CONFIG_ASH_MATH_SUPPORT_64
1419 typedef int64_t arith_t;
1421 typedef long arith_t;
1424 #ifdef CONFIG_ASH_MATH_SUPPORT
1425 static arith_t dash_arith(const char *);
1426 static arith_t arith(const char *expr, int *perrcode);
1429 #ifdef CONFIG_ASH_RANDOM_SUPPORT
1430 static unsigned long rseed;
1431 static void change_random(const char *);
1432 # ifndef DYNAMIC_VAR
1433 # define DYNAMIC_VAR
1437 /* $NetBSD: init.h,v 1.9 2002/11/24 22:35:40 christos Exp $ */
1439 static void reset(void);
1441 /* $NetBSD: var.h,v 1.21 2003/01/22 20:36:04 dsl Exp $ */
1448 #define VEXPORT 0x01 /* variable is exported */
1449 #define VREADONLY 0x02 /* variable cannot be modified */
1450 #define VSTRFIXED 0x04 /* variable struct is statically allocated */
1451 #define VTEXTFIXED 0x08 /* text is statically allocated */
1452 #define VSTACK 0x10 /* text is allocated on the stack */
1453 #define VUNSET 0x20 /* the variable is not set */
1454 #define VNOFUNC 0x40 /* don't call the callback function */
1455 #define VNOSET 0x80 /* do not set variable - just readonly test */
1456 #define VNOSAVE 0x100 /* when text is on the heap before setvareq */
1458 # define VDYNAMIC 0x200 /* dynamic variable */
1464 struct var *next; /* next entry in hash list */
1465 int flags; /* flags are defined above */
1466 const char *text; /* name=value */
1467 void (*func)(const char *); /* function to be called when */
1468 /* the variable gets set/unset */
1472 struct localvar *next; /* next local variable in list */
1473 struct var *vp; /* the variable that was made local */
1474 int flags; /* saved flags */
1475 const char *text; /* saved text */
1479 static struct localvar *localvars;
1485 #ifdef CONFIG_ASH_GETOPTS
1486 static void getoptsreset(const char *);
1489 #ifdef CONFIG_LOCALE_SUPPORT
1491 static void change_lc_all(const char *value);
1492 static void change_lc_ctype(const char *value);
1498 static const char defpathvar[] = "PATH=/usr/local/bin:/usr/bin:/sbin:/bin";
1500 static const char defifsvar[] = "IFS= \t\n";
1501 #define defifs (defifsvar + 4)
1503 static const char defifs[] = " \t\n";
1507 static struct var varinit[] = {
1509 { 0, VSTRFIXED|VTEXTFIXED, defifsvar, 0 },
1511 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", 0 },
1514 #ifdef CONFIG_ASH_MAIL
1515 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail },
1516 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail },
1519 { 0, VSTRFIXED|VTEXTFIXED, defpathvar, changepath },
1520 { 0, VSTRFIXED|VTEXTFIXED, "PS1=$ ", 0 },
1521 { 0, VSTRFIXED|VTEXTFIXED, "PS2=> ", 0 },
1522 { 0, VSTRFIXED|VTEXTFIXED, "PS4=+ ", 0 },
1523 #ifdef CONFIG_ASH_GETOPTS
1524 { 0, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset },
1526 #ifdef CONFIG_ASH_RANDOM_SUPPORT
1527 {0, VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random },
1529 #ifdef CONFIG_LOCALE_SUPPORT
1530 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0", change_lc_all },
1531 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0", change_lc_ctype },
1533 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
1534 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0", NULL },
1538 #define vifs varinit[0]
1539 #ifdef CONFIG_ASH_MAIL
1540 #define vmail (&vifs)[1]
1541 #define vmpath (&vmail)[1]
1545 #define vpath (&vmpath)[1]
1546 #define vps1 (&vpath)[1]
1547 #define vps2 (&vps1)[1]
1548 #define vps4 (&vps2)[1]
1549 #define voptind (&vps4)[1]
1550 #ifdef CONFIG_ASH_GETOPTS
1551 #define vrandom (&voptind)[1]
1553 #define vrandom (&vps4)[1]
1555 #define defpath (defpathvar + 5)
1558 * The following macros access the values of the above variables.
1559 * They have to skip over the name. They return the null string
1560 * for unset variables.
1563 #define ifsval() (vifs.text + 4)
1564 #define ifsset() ((vifs.flags & VUNSET) == 0)
1565 #define mailval() (vmail.text + 5)
1566 #define mpathval() (vmpath.text + 9)
1567 #define pathval() (vpath.text + 5)
1568 #define ps1val() (vps1.text + 4)
1569 #define ps2val() (vps2.text + 4)
1570 #define ps4val() (vps4.text + 4)
1571 #define optindval() (voptind.text + 7)
1573 #define mpathset() ((vmpath.flags & VUNSET) == 0)
1575 static void setvar(const char *, const char *, int);
1576 static void setvareq(char *, int);
1577 static void listsetvar(struct strlist *, int);
1578 static char *lookupvar(const char *);
1579 static char *bltinlookup(const char *);
1580 static char **listvars(int, int, char ***);
1581 #define environment() listvars(VEXPORT, VUNSET, 0)
1582 static int showvars(const char *, int, int);
1583 static void poplocalvars(void);
1584 static int unsetvar(const char *);
1585 #ifdef CONFIG_ASH_GETOPTS
1586 static int setvarsafe(const char *, const char *, int);
1588 static int varcmp(const char *, const char *);
1589 static struct var **hashvar(const char *);
1592 static inline int varequal(const char *a, const char *b) {
1593 return !varcmp(a, b);
1597 static int loopnest; /* current loop nesting level */
1600 * The parsefile structure pointed to by the global variable parsefile
1601 * contains information about the current file being read.
1606 struct redirtab *next;
1611 static struct redirtab *redirlist;
1612 static int nullredirs;
1614 extern char **environ;
1616 /* $NetBSD: output.h,v 1.16 2002/11/24 22:35:42 christos Exp $ */
1619 static void outstr(const char *, FILE *);
1620 static void outcslow(int, FILE *);
1621 static void flushall(void);
1622 static void flusherr(void);
1623 static int out1fmt(const char *, ...)
1624 __attribute__((__format__(__printf__,1,2)));
1625 static int fmtstr(char *, size_t, const char *, ...)
1626 __attribute__((__format__(__printf__,3,4)));
1628 static int preverrout_fd; /* save fd2 before print debug if xflag is set. */
1631 static void out1str(const char *p)
1636 static void out2str(const char *p)
1643 * Initialization code.
1647 * This routine initializes the builtin variables.
1658 * PS1 depends on uid
1660 #if defined(CONFIG_FEATURE_COMMAND_EDITING) && defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
1661 vps1.text = "PS1=\\w \\$ ";
1664 vps1.text = "PS1=# ";
1667 end = vp + sizeof(varinit) / sizeof(varinit[0]);
1669 vpp = hashvar(vp->text);
1672 } while (++vp < end);
1681 basepf.nextc = basepf.buf = basebuf;
1686 signal(SIGCHLD, SIG_DFL);
1694 struct stat st1, st2;
1697 for (envp = environ ; envp && *envp ; envp++) {
1698 if (strchr(*envp, '=')) {
1699 setvareq(*envp, VEXPORT|VTEXTFIXED);
1703 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
1704 setvar("PPID", ppid, 0);
1706 p = lookupvar("PWD");
1708 if (*p != '/' || stat(p, &st1) || stat(".", &st2) ||
1709 st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
1715 /* PEOF (the end of file marker) */
1718 * The input line number. Input.c just defines this variable, and saves
1719 * and restores it when files are pushed and popped. The user of this
1720 * package must set its value.
1723 static int pgetc(void);
1724 static int pgetc2(void);
1725 static int preadbuffer(void);
1726 static void pungetc(void);
1727 static void pushstring(char *, void *);
1728 static void popstring(void);
1729 static void setinputfile(const char *, int);
1730 static void setinputfd(int, int);
1731 static void setinputstring(char *);
1732 static void popfile(void);
1733 static void popallfiles(void);
1734 static void closescript(void);
1737 /* $NetBSD: jobs.h,v 1.17 2003/01/22 20:36:04 dsl Exp $ */
1740 /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
1743 #define FORK_NOJOB 2
1745 /* mode flags for showjob(s) */
1746 #define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
1747 #define SHOW_PID 0x04 /* include process pid */
1748 #define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
1752 * A job structure contains information about a job. A job is either a
1753 * single process or a set of processes contained in a pipeline. In the
1754 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1759 pid_t pid; /* process id */
1760 int status; /* last process status from wait() */
1761 char *cmd; /* text of command being run */
1765 struct procstat ps0; /* status of process */
1766 struct procstat *ps; /* status or processes when more than one */
1768 int stopstatus; /* status of a stopped job */
1771 nprocs: 16, /* number of processes */
1773 #define JOBRUNNING 0 /* at least one proc running */
1774 #define JOBSTOPPED 1 /* all procs are stopped */
1775 #define JOBDONE 2 /* all procs are completed */
1777 sigint: 1, /* job was killed by SIGINT */
1778 jobctl: 1, /* job running under job control */
1780 waited: 1, /* true if this entry has been waited for */
1781 used: 1, /* true if this entry is in used */
1782 changed: 1; /* true if status has changed */
1783 struct job *prev_job; /* previous job */
1786 static pid_t backgndpid; /* pid of last background process */
1787 static int job_warning; /* user was warned about stopped jobs */
1789 static int jobctl; /* true if doing job control */
1792 static struct job *makejob(union node *, int);
1793 static int forkshell(struct job *, union node *, int);
1794 static int waitforjob(struct job *);
1795 static int stoppedjobs(void);
1798 #define setjobctl(on) /* do nothing */
1800 static void setjobctl(int);
1801 static void showjobs(FILE *, int);
1804 /* $NetBSD: main.h,v 1.9 2002/11/24 22:35:41 christos Exp $ */
1807 /* pid of main shell */
1809 /* true if we aren't a child of the main shell */
1810 static int rootshell;
1812 static void readcmdfile(char *);
1813 static void cmdloop(int);
1815 /* $NetBSD: memalloc.h,v 1.13 2003/01/22 20:36:04 dsl Exp $ */
1819 struct stack_block *stackp;
1822 struct stackmark *marknext;
1825 /* minimum size of a block */
1826 #define MINSIZE SHELL_ALIGN(504)
1828 struct stack_block {
1829 struct stack_block *prev;
1830 char space[MINSIZE];
1833 static struct stack_block stackbase;
1834 static struct stack_block *stackp = &stackbase;
1835 static struct stackmark *markp;
1836 static char *stacknxt = stackbase.space;
1837 static size_t stacknleft = MINSIZE;
1838 static char *sstrend = stackbase.space + MINSIZE;
1839 static int herefd = -1;
1842 static pointer ckmalloc(size_t);
1843 static pointer ckrealloc(pointer, size_t);
1844 static char *savestr(const char *);
1845 static pointer stalloc(size_t);
1846 static void stunalloc(pointer);
1847 static void setstackmark(struct stackmark *);
1848 static void popstackmark(struct stackmark *);
1849 static void growstackblock(void);
1850 static void *growstackstr(void);
1851 static char *makestrspace(size_t, char *);
1852 static char *stnputs(const char *, size_t, char *);
1853 static char *stputs(const char *, char *);
1856 static inline char *_STPUTC(char c, char *p) {
1863 #define stackblock() ((void *)stacknxt)
1864 #define stackblocksize() stacknleft
1865 #define STARTSTACKSTR(p) ((p) = stackblock())
1866 #define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1867 #define CHECKSTRSPACE(n, p) \
1871 size_t m = sstrend - q; \
1873 (p) = makestrspace(l, q); \
1876 #define USTPUTC(c, p) (*p++ = (c))
1877 #define STACKSTRNUL(p) ((p) == sstrend? (p = growstackstr(), *p = '\0') : (*p = '\0'))
1878 #define STUNPUTC(p) (--p)
1879 #define STTOPC(p) p[-1]
1880 #define STADJUST(amount, p) (p += (amount))
1882 #define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1883 #define ungrabstackstr(s, p) stunalloc((s))
1884 #define stackstrend() ((void *)sstrend)
1886 #define ckfree(p) free((pointer)(p))
1888 /* $NetBSD: mystring.h,v 1.10 2002/11/24 22:35:42 christos Exp $ */
1891 #define DOLATSTRLEN 4
1893 static char *prefix(const char *, const char *);
1894 static int number(const char *);
1895 static int is_number(const char *);
1896 static char *single_quote(const char *);
1897 static char *sstrdup(const char *);
1899 #define equal(s1, s2) (strcmp(s1, s2) == 0)
1900 #define scopy(s1, s2) ((void)strcpy(s2, s1))
1902 /* $NetBSD: options.h,v 1.16 2003/01/22 20:36:04 dsl Exp $ */
1905 int nparam; /* # of positional parameters (without $0) */
1906 unsigned char malloc; /* if parameter list dynamically allocated */
1907 char **p; /* parameter list */
1908 #ifdef CONFIG_ASH_GETOPTS
1909 int optind; /* next parameter to be processed by getopts */
1910 int optoff; /* used by getopts */
1915 #define eflag optlist[0]
1916 #define fflag optlist[1]
1917 #define Iflag optlist[2]
1918 #define iflag optlist[3]
1919 #define mflag optlist[4]
1920 #define nflag optlist[5]
1921 #define sflag optlist[6]
1922 #define xflag optlist[7]
1923 #define vflag optlist[8]
1924 #define Cflag optlist[9]
1925 #define aflag optlist[10]
1926 #define bflag optlist[11]
1927 #define uflag optlist[12]
1928 #define qflag optlist[13]
1929 #define viflag optlist[14]
1932 #define nolog optlist[15]
1933 #define debug optlist[16]
1936 #ifndef CONFIG_FEATURE_COMMAND_EDITING_VI
1937 #define setvimode(on) viflag = 0 /* forcibly keep the option off */
1940 /* $NetBSD: options.c,v 1.33 2003/01/22 20:36:04 dsl Exp $ */
1943 static const char *const optletters_optnames[] = {
1965 #define optletters(n) optletters_optnames[(n)][0]
1966 #define optnames(n) (&optletters_optnames[(n)][1])
1968 #define NOPTS (sizeof(optletters_optnames)/sizeof(optletters_optnames[0]))
1970 static char optlist[NOPTS];
1973 static char *arg0; /* value of $0 */
1974 static struct shparam shellparam; /* $@ current positional parameters */
1975 static char **argptr; /* argument list for builtin commands */
1976 static char *optionarg; /* set by nextopt (like getopt) */
1977 static char *optptr; /* used by nextopt */
1979 static char *minusc; /* argument to -c option */
1982 static void procargs(int, char **);
1983 static void optschanged(void);
1984 static void setparam(char **);
1985 static void freeparam(volatile struct shparam *);
1986 static int shiftcmd(int, char **);
1987 static int setcmd(int, char **);
1988 static int nextopt(const char *);
1990 /* $NetBSD: redir.h,v 1.14 2002/11/24 22:35:43 christos Exp $ */
1992 /* flags passed to redirect */
1993 #define REDIR_PUSH 01 /* save previous values of file descriptors */
1994 #define REDIR_SAVEFD2 03 /* set preverrout */
1997 static void redirect(union node *, int);
1998 static void popredir(int);
1999 static void clearredir(int);
2000 static int copyfd(int, int);
2001 static int redirectsafe(union node *, int);
2003 /* $NetBSD: show.h,v 1.6 2003/01/22 20:36:04 dsl Exp $ */
2007 static void showtree(union node *);
2008 static void trace(const char *, ...);
2009 static void tracev(const char *, va_list);
2010 static void trargs(char **);
2011 static void trputc(int);
2012 static void trputs(const char *);
2013 static void opentrace(void);
2016 /* $NetBSD: trap.h,v 1.16 2002/11/24 22:35:43 christos Exp $ */
2019 /* trap handler commands */
2020 static char *trap[NSIG];
2021 /* current value of signal */
2022 static char sigmode[NSIG - 1];
2023 /* indicates specified signal received */
2024 static char gotsig[NSIG - 1];
2026 static void clear_traps(void);
2027 static void setsignal(int);
2028 static void ignoresig(int);
2029 static void onsig(int);
2030 static void dotrap(void);
2031 static void setinteractive(int);
2032 static void exitshell(void) __attribute__((__noreturn__));
2033 static int decode_signal(const char *, int);
2036 * This routine is called when an error or an interrupt occurs in an
2037 * interactive shell and control is returned to the main command loop.
2052 parselleft = parsenleft = 0; /* clear input buffer */
2056 /* from parser.c: */
2069 #ifdef CONFIG_ASH_ALIAS
2070 static struct alias *atab[ATABSIZE];
2072 static void setalias(const char *, const char *);
2073 static struct alias *freealias(struct alias *);
2074 static struct alias **__lookupalias(const char *);
2077 setalias(const char *name, const char *val)
2079 struct alias *ap, **app;
2081 app = __lookupalias(name);
2085 if (!(ap->flag & ALIASINUSE)) {
2088 ap->val = savestr(val);
2089 ap->flag &= ~ALIASDEAD;
2092 ap = ckmalloc(sizeof (struct alias));
2093 ap->name = savestr(name);
2094 ap->val = savestr(val);
2103 unalias(const char *name)
2107 app = __lookupalias(name);
2111 *app = freealias(*app);
2122 struct alias *ap, **app;
2126 for (i = 0; i < ATABSIZE; i++) {
2128 for (ap = *app; ap; ap = *app) {
2129 *app = freealias(*app);
2138 static struct alias *
2139 lookupalias(const char *name, int check)
2141 struct alias *ap = *__lookupalias(name);
2143 if (check && ap && (ap->flag & ALIASINUSE))
2149 * TODO - sort output
2152 aliascmd(int argc, char **argv)
2161 for (i = 0; i < ATABSIZE; i++)
2162 for (ap = atab[i]; ap; ap = ap->next) {
2167 while ((n = *++argv) != NULL) {
2168 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
2169 if ((ap = *__lookupalias(n)) == NULL) {
2170 fprintf(stderr, "%s: %s not found\n", "alias", n);
2184 unaliascmd(int argc, char **argv)
2188 while ((i = nextopt("a")) != '\0') {
2194 for (i = 0; *argptr; argptr++) {
2195 if (unalias(*argptr)) {
2196 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
2204 static struct alias *
2205 freealias(struct alias *ap) {
2208 if (ap->flag & ALIASINUSE) {
2209 ap->flag |= ALIASDEAD;
2221 printalias(const struct alias *ap) {
2222 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
2225 static struct alias **
2226 __lookupalias(const char *name) {
2227 unsigned int hashval;
2234 ch = (unsigned char)*p;
2238 ch = (unsigned char)*++p;
2240 app = &atab[hashval % ATABSIZE];
2242 for (; *app; app = &(*app)->next) {
2243 if (equal(name, (*app)->name)) {
2250 #endif /* CONFIG_ASH_ALIAS */
2253 /* $NetBSD: cd.c,v 1.30 2003/01/22 20:36:03 dsl Exp $ */
2256 * The cd and pwd commands.
2259 #define CD_PHYSICAL 1
2262 static int docd(const char *, int);
2263 static int cdopt(void);
2265 static char *curdir = nullstr; /* current working directory */
2266 static char *physdir = nullstr; /* physical working directory */
2275 while ((i = nextopt("LP"))) {
2277 flags ^= CD_PHYSICAL;
2286 cdcmd(int argc, char **argv)
2298 dest = bltinlookup(homestr);
2299 else if (dest[0] == '-' && dest[1] == '\0') {
2300 dest = bltinlookup("OLDPWD");
2322 if (!(path = bltinlookup("CDPATH"))) {
2330 p = padvance(&path, dest);
2331 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2335 if (!docd(p, flags))
2340 error("can't cd to %s", dest);
2343 if (flags & CD_PRINT)
2344 out1fmt(snlfmt, curdir);
2350 * Update curdir (the name of the current directory) in response to a
2354 static inline const char *
2355 updatepwd(const char *dir)
2362 cdcomppath = sstrdup(dir);
2365 if (curdir == nullstr)
2367 new = stputs(curdir, new);
2369 new = makestrspace(strlen(dir) + 2, new);
2370 lim = stackblock() + 1;
2374 if (new > lim && *lim == '/')
2379 if (dir[1] == '/' && dir[2] != '/') {
2385 p = strtok(cdcomppath, "/");
2389 if (p[1] == '.' && p[2] == '\0') {
2396 } else if (p[1] == '\0')
2400 new = stputs(p, new);
2408 return stackblock();
2412 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2413 * know that the current directory has changed.
2417 docd(const char *dest, int flags)
2419 const char *dir = 0;
2422 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2425 if (!(flags & CD_PHYSICAL)) {
2426 dir = updatepwd(dest);
2441 * Find out what the current directory is. If we already know the current
2442 * directory, this routine returns immediately.
2444 static inline char *
2447 char *dir = getcwd(0, 0);
2448 return dir ? dir : nullstr;
2452 pwdcmd(int argc, char **argv)
2455 const char *dir = curdir;
2459 if (physdir == nullstr)
2463 out1fmt(snlfmt, dir);
2468 setpwd(const char *val, int setold)
2472 oldcur = dir = curdir;
2475 setvar("OLDPWD", oldcur, VEXPORT);
2478 if (physdir != nullstr) {
2479 if (physdir != oldcur)
2483 if (oldcur == val || !val) {
2490 if (oldcur != dir && oldcur != nullstr) {
2495 setvar("PWD", dir, VEXPORT);
2498 /* $NetBSD: error.c,v 1.30 2003/01/22 20:36:03 dsl Exp $ */
2501 * Errors and exceptions.
2505 * Code to handle exceptions in C.
2510 static void exverror(int, const char *, va_list)
2511 __attribute__((__noreturn__));
2514 * Called to raise an exception. Since C doesn't include exceptions, we
2515 * just do a longjmp to the exception handler. The type of exception is
2516 * stored in the global variable "exception".
2523 if (handler == NULL)
2529 longjmp(handler->loc, 1);
2534 * Called from trap.c when a SIGINT is received. (If the user specifies
2535 * that SIGINT is to be trapped or ignored using the trap builtin, then
2536 * this routine is not called.) Suppressint is nonzero when interrupts
2537 * are held using the INTOFF macro. (The test for iflag is just
2538 * defensive programming.)
2547 /* comment by vodz: its strange for me, this programm don`t use other
2552 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
2553 if (!(rootshell && iflag)) {
2554 signal(SIGINT, SIG_DFL);
2564 exvwarning(const char *msg, va_list ap)
2569 fprintf(errs, "%s: ", arg0);
2571 const char *fmt = (!iflag || parsefile->fd) ?
2572 "%s: %d: " : "%s: ";
2573 fprintf(errs, fmt, commandname, startlinno);
2575 vfprintf(errs, msg, ap);
2576 outcslow('\n', errs);
2580 * Exverror is called to raise the error exception. If the second argument
2581 * is not NULL then error prints an error message using printf style
2582 * formatting. It then raises the error exception.
2585 exverror(int cond, const char *msg, va_list ap)
2589 TRACE(("exverror(%d, \"", cond));
2591 TRACE(("\") pid=%d\n", getpid()));
2593 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
2596 exvwarning(msg, ap);
2605 error(const char *msg, ...)
2610 exverror(EXERROR, msg, ap);
2617 exerror(int cond, const char *msg, ...)
2622 exverror(cond, msg, ap);
2628 * error/warning routines for external builtins
2632 sh_warnx(const char *fmt, ...)
2637 exvwarning(fmt, ap);
2643 * Return a string describing an error. The returned string may be a
2644 * pointer to a static buffer that will be overwritten on the next call.
2645 * Action describes the operation that got the error.
2649 errmsg(int e, const char *em)
2651 if(e == ENOENT || e == ENOTDIR) {
2659 /* $NetBSD: eval.c,v 1.71 2003/01/23 03:33:16 rafal Exp $ */
2662 * Evaluate a command.
2665 /* flags in argument to evaltree */
2666 #define EV_EXIT 01 /* exit after evaluating tree */
2667 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2668 #define EV_BACKCMD 04 /* command executing within back quotes */
2671 static void evalloop(union node *, int);
2672 static void evalfor(union node *, int);
2673 static void evalcase(union node *, int);
2674 static void evalsubshell(union node *, int);
2675 static void expredir(union node *);
2676 static void evalpipe(union node *, int);
2677 static void evalcommand(union node *, int);
2678 static int evalbltin(const struct builtincmd *, int, char **);
2679 static int evalfun(struct funcnode *, int, char **, int);
2680 static void prehash(union node *);
2681 static int bltincmd(int, char **);
2684 static const struct builtincmd bltin = {
2690 * Called to reset things after an exception.
2698 evalcmd(int argc, char **argv)
2707 STARTSTACKSTR(concat);
2710 concat = stputs(p, concat);
2711 if ((p = *ap++) == NULL)
2713 STPUTC(' ', concat);
2715 STPUTC('\0', concat);
2716 p = grabstackstr(concat);
2725 * Execute a command or commands contained in a string.
2732 struct stackmark smark;
2734 setstackmark(&smark);
2737 while ((n = parsecmd(0)) != NEOF) {
2739 popstackmark(&smark);
2744 popstackmark(&smark);
2750 * Evaluate a parse tree. The value is left in the global variable
2755 evaltree(union node *n, int flags)
2758 void (*evalfn)(union node *, int);
2762 TRACE(("evaltree(NULL) called\n"));
2765 TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
2766 getpid(), n, n->type, flags));
2770 out1fmt("Node type = %d\n", n->type);
2775 evaltree(n->nnot.com, EV_TESTED);
2776 status = !exitstatus;
2779 expredir(n->nredir.redirect);
2780 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
2782 evaltree(n->nredir.n, flags & EV_TESTED);
2783 status = exitstatus;
2788 evalfn = evalcommand;
2790 if (eflag && !(flags & EV_TESTED))
2802 evalfn = evalsubshell;
2814 #error NAND + 1 != NOR
2816 #if NOR + 1 != NSEMI
2817 #error NOR + 1 != NSEMI
2819 isor = n->type - NAND;
2822 (flags | ((isor >> 1) - 1)) & EV_TESTED
2824 if (!exitstatus == isor)
2836 evaltree(n->nif.test, EV_TESTED);
2839 if (exitstatus == 0) {
2842 } else if (n->nif.elsepart) {
2843 n = n->nif.elsepart;
2848 defun(n->narg.text, n->narg.next);
2852 exitstatus = status;
2858 if (flags & EV_EXIT || checkexit & exitstatus)
2863 #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
2866 void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
2870 evalloop(union node *n, int flags)
2880 evaltree(n->nbinary.ch1, EV_TESTED);
2882 skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
2886 if (evalskip == SKIPBREAK && --skipcount <= 0)
2891 if (n->type != NWHILE)
2895 evaltree(n->nbinary.ch2, flags);
2896 status = exitstatus;
2901 exitstatus = status;
2907 evalfor(union node *n, int flags)
2909 struct arglist arglist;
2912 struct stackmark smark;
2914 setstackmark(&smark);
2915 arglist.lastp = &arglist.list;
2916 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
2917 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
2922 *arglist.lastp = NULL;
2927 for (sp = arglist.list ; sp ; sp = sp->next) {
2928 setvar(n->nfor.var, sp->text, 0);
2929 evaltree(n->nfor.body, flags);
2931 if (evalskip == SKIPCONT && --skipcount <= 0) {
2935 if (evalskip == SKIPBREAK && --skipcount <= 0)
2942 popstackmark(&smark);
2948 evalcase(union node *n, int flags)
2952 struct arglist arglist;
2953 struct stackmark smark;
2955 setstackmark(&smark);
2956 arglist.lastp = &arglist.list;
2957 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
2959 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2960 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
2961 if (casematch(patp, arglist.list->text)) {
2962 if (evalskip == 0) {
2963 evaltree(cp->nclist.body, flags);
2970 popstackmark(&smark);
2976 * Kick off a subshell to evaluate a tree.
2980 evalsubshell(union node *n, int flags)
2983 int backgnd = (n->type == NBACKGND);
2986 expredir(n->nredir.redirect);
2987 if (!backgnd && flags & EV_EXIT && !trap[0])
2991 if (forkshell(jp, n, backgnd) == 0) {
2995 flags &=~ EV_TESTED;
2997 redirect(n->nredir.redirect, 0);
2998 evaltreenr(n->nredir.n, flags);
3003 status = waitforjob(jp);
3004 exitstatus = status;
3011 * Compute the names of the files in a redirection list.
3015 expredir(union node *n)
3019 for (redir = n ; redir ; redir = redir->nfile.next) {
3021 fn.lastp = &fn.list;
3022 switch (redir->type) {
3028 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
3029 redir->nfile.expfname = fn.list->text;
3033 if (redir->ndup.vname) {
3034 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
3035 fixredir(redir, fn.list->text, 1);
3045 * Evaluate a pipeline. All the processes in the pipeline are children
3046 * of the process creating the pipeline. (This differs from some versions
3047 * of the shell, which make the last process in a pipeline the parent
3052 evalpipe(union node *n, int flags)
3055 struct nodelist *lp;
3060 TRACE(("evalpipe(0x%lx) called\n", (long)n));
3062 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
3066 jp = makejob(n, pipelen);
3068 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
3072 if (pipe(pip) < 0) {
3074 error("Pipe call failed");
3077 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
3090 evaltreenr(lp->n, flags);
3098 if (n->npipe.backgnd == 0) {
3099 exitstatus = waitforjob(jp);
3100 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
3108 * Execute a command inside back quotes. If it's a builtin command, we
3109 * want to save its output in a block obtained from malloc. Otherwise
3110 * we fork off a subprocess and get the output of the command via a pipe.
3111 * Should be called with interrupts off.
3115 evalbackcmd(union node *n, struct backcmd *result)
3127 saveherefd = herefd;
3135 error("Pipe call failed");
3137 if (forkshell(jp, n, FORK_NOJOB) == 0) {
3146 evaltreenr(n, EV_EXIT);
3150 result->fd = pip[0];
3153 herefd = saveherefd;
3155 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
3156 result->fd, result->buf, result->nleft, result->jp));
3159 #ifdef CONFIG_ASH_CMDCMD
3160 static inline char **
3161 parse_command_args(char **argv, const char **path)
3173 if (c == '-' && !*cp) {
3183 /* run 'typecmd' for other options */
3186 } while ((c = *cp++));
3193 isassignment(const char *p)
3195 const char *q = endofname(p);
3201 #ifdef CONFIG_ASH_EXPAND_PRMT
3202 static const char *expandstr(const char *ps);
3204 #define expandstr(s) s
3208 * Execute a simple command.
3212 evalcommand(union node *cmd, int flags)
3214 struct stackmark smark;
3216 struct arglist arglist;
3217 struct arglist varlist;
3220 const struct strlist *sp;
3221 struct cmdentry cmdentry;
3229 struct builtincmd *bcmd;
3230 int pseudovarflag = 0;
3232 /* First expand the arguments. */
3233 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
3234 setstackmark(&smark);
3235 back_exitstatus = 0;
3237 cmdentry.cmdtype = CMDBUILTIN;
3238 cmdentry.u.cmd = &bltin;
3239 varlist.lastp = &varlist.list;
3240 *varlist.lastp = NULL;
3241 arglist.lastp = &arglist.list;
3242 *arglist.lastp = NULL;
3247 bcmd = find_builtin(cmd->ncmd.args->narg.text);
3248 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
3251 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
3252 struct strlist **spp;
3254 spp = arglist.lastp;
3255 if (pseudovarflag && isassignment(argp->narg.text))
3256 expandarg(argp, &arglist, EXP_VARTILDE);
3258 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
3260 for (sp = *spp; sp; sp = sp->next)
3264 argv = nargv = stalloc(sizeof (char *) * (argc + 1));
3265 for (sp = arglist.list ; sp ; sp = sp->next) {
3266 TRACE(("evalcommand arg: %s\n", sp->text));
3267 *nargv++ = sp->text;
3272 if (iflag && funcnest == 0 && argc > 0)
3273 lastarg = nargv[-1];
3276 expredir(cmd->ncmd.redirect);
3277 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH|REDIR_SAVEFD2);
3280 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
3281 struct strlist **spp;
3284 spp = varlist.lastp;
3285 expandarg(argp, &varlist, EXP_VARTILDE);
3288 * Modify the command lookup path, if a PATH= assignment
3292 if (varequal(p, path))
3296 /* Print the command if xflag is set. */
3299 const char *p = " %s";
3302 dprintf(preverrout_fd, p, expandstr(ps4val()));
3305 for(n = 0; n < 2; n++) {
3307 dprintf(preverrout_fd, p, sp->text);
3315 bb_full_write(preverrout_fd, "\n", 1);
3321 /* Now locate the command. */
3323 const char *oldpath;
3324 int cmd_flag = DO_ERR;
3329 find_command(argv[0], &cmdentry, cmd_flag, path);
3330 if (cmdentry.cmdtype == CMDUNKNOWN) {
3336 /* implement bltin and command here */
3337 if (cmdentry.cmdtype != CMDBUILTIN)
3340 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
3341 if (cmdentry.u.cmd == EXECCMD)
3343 #ifdef CONFIG_ASH_CMDCMD
3344 if (cmdentry.u.cmd == COMMANDCMD) {
3347 nargv = parse_command_args(argv, &path);
3350 argc -= nargv - argv;
3352 cmd_flag |= DO_NOFUNC;
3360 /* We have a redirection error. */
3364 exitstatus = status;
3368 /* Execute the command. */
3369 switch (cmdentry.cmdtype) {
3371 /* Fork off a child process if necessary. */
3372 if (!(flags & EV_EXIT) || trap[0]) {
3374 jp = makejob(cmd, 1);
3375 if (forkshell(jp, cmd, FORK_FG) != 0) {
3376 exitstatus = waitforjob(jp);
3382 listsetvar(varlist.list, VEXPORT|VSTACK);
3383 shellexec(argv, path, cmdentry.u.index);
3387 cmdenviron = varlist.list;
3389 struct strlist *list = cmdenviron;
3391 if (spclbltin > 0 || argc == 0) {
3393 if (cmd_is_exec && argc > 1)
3396 listsetvar(list, i);
3398 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
3413 exit_status = j + 128;
3414 exitstatus = exit_status;
3416 if (i == EXINT || spclbltin > 0) {
3418 longjmp(handler->loc, 1);
3425 listsetvar(varlist.list, 0);
3426 if (evalfun(cmdentry.u.func, argc, argv, flags))
3432 popredir(cmd_is_exec);
3434 /* dsl: I think this is intended to be used to support
3435 * '_' in 'vi' command mode during line editing...
3436 * However I implemented that within libedit itself.
3438 setvar("_", lastarg, 0);
3439 popstackmark(&smark);
3443 evalbltin(const struct builtincmd *cmd, int argc, char **argv) {
3444 char *volatile savecmdname;
3445 struct jmploc *volatile savehandler;
3446 struct jmploc jmploc;
3449 savecmdname = commandname;
3450 if ((i = setjmp(jmploc.loc)))
3452 savehandler = handler;
3454 commandname = argv[0];
3456 optptr = NULL; /* initialize nextopt */
3457 exitstatus = (*cmd->builtin)(argc, argv);
3460 exitstatus |= ferror(stdout);
3461 commandname = savecmdname;
3463 handler = savehandler;
3469 evalfun(struct funcnode *func, int argc, char **argv, int flags)
3471 volatile struct shparam saveparam;
3472 struct localvar *volatile savelocalvars;
3473 struct jmploc *volatile savehandler;
3474 struct jmploc jmploc;
3477 saveparam = shellparam;
3478 savelocalvars = localvars;
3479 if ((e = setjmp(jmploc.loc))) {
3483 savehandler = handler;
3486 shellparam.malloc = 0;
3489 shellparam.nparam = argc - 1;
3490 shellparam.p = argv + 1;
3491 #ifdef CONFIG_ASH_GETOPTS
3492 shellparam.optind = 1;
3493 shellparam.optoff = -1;
3496 evaltree(&func->n, flags & EV_TESTED);
3502 localvars = savelocalvars;
3503 freeparam(&shellparam);
3504 shellparam = saveparam;
3505 handler = savehandler;
3507 if (evalskip == SKIPFUNC) {
3516 goodname(const char *p)
3518 return !*endofname(p);
3522 * Search for a command. This is called before we fork so that the
3523 * location of the command will be available in the parent as well as
3524 * the child. The check for "goodname" is an overly conservative
3525 * check that the name will not be subject to expansion.
3529 prehash(union node *n)
3531 struct cmdentry entry;
3533 if (n->type == NCMD && n->ncmd.args)
3534 if (goodname(n->ncmd.args->narg.text))
3535 find_command(n->ncmd.args->narg.text, &entry, 0,
3542 * Builtin commands. Builtin commands whose functions are closely
3543 * tied to evaluation are implemented here.
3551 bltincmd(int argc, char **argv)
3554 * Preserve exitstatus of a previous possible redirection
3557 return back_exitstatus;
3562 * Handle break and continue commands. Break, continue, and return are
3563 * all handled by setting the evalskip flag. The evaluation routines
3564 * above all check this flag, and if it is set they start skipping
3565 * commands rather than executing them. The variable skipcount is
3566 * the number of loops to break/continue, or the number of function
3567 * levels to return. (The latter is always 1.) It should probably
3568 * be an error to break out of more loops than exist, but it isn't
3569 * in the standard shell so we don't make it one here.
3573 breakcmd(int argc, char **argv)
3575 int n = argc > 1 ? number(argv[1]) : 1;
3578 error(illnum, argv[1]);
3582 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
3590 * The return command.
3594 returncmd(int argc, char **argv)
3596 int ret = argc > 1 ? number(argv[1]) : exitstatus;
3599 evalskip = SKIPFUNC;
3604 /* Do what ksh does; skip the rest of the file */
3605 evalskip = SKIPFILE;
3613 falsecmd(int argc, char **argv)
3620 truecmd(int argc, char **argv)
3627 execcmd(int argc, char **argv)
3630 iflag = 0; /* exit on error */
3633 shellexec(argv + 1, pathval(), 0);
3639 /* $NetBSD: exec.c,v 1.35 2003/01/22 20:36:04 dsl Exp $ */
3642 * When commands are first encountered, they are entered in a hash table.
3643 * This ensures that a full path search will not have to be done for them
3644 * on each invocation.
3646 * We should investigate converting to a linear search, even though that
3647 * would make the command name "hash" a misnomer.
3650 #define CMDTABLESIZE 31 /* should be prime */
3651 #define ARB 1 /* actual size determined at run time */
3656 struct tblentry *next; /* next entry in hash chain */
3657 union param param; /* definition of builtin function */
3658 short cmdtype; /* index identifying command */
3659 char rehash; /* if set, cd done since entry created */
3660 char cmdname[ARB]; /* name of command */
3664 static struct tblentry *cmdtable[CMDTABLESIZE];
3665 static int builtinloc = -1; /* index in path of %builtin, or -1 */
3668 static void tryexec(char *, char **, char **);
3669 static void clearcmdentry(int);
3670 static struct tblentry *cmdlookup(const char *, int);
3671 static void delete_cmd_entry(void);
3675 * Exec a program. Never returns. If you change this routine, you may
3676 * have to change the find_command routine as well.
3680 shellexec(char **argv, const char *path, int idx)
3687 envp = environment();
3688 if (strchr(argv[0], '/') != NULL
3689 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3690 || find_applet_by_name(argv[0])
3693 tryexec(argv[0], argv, envp);
3697 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3698 if (--idx < 0 && pathopt == NULL) {
3699 tryexec(cmdname, argv, envp);
3700 if (errno != ENOENT && errno != ENOTDIR)
3707 /* Map to POSIX errors */
3719 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
3720 argv[0], e, suppressint ));
3721 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3727 tryexec(char *cmd, char **argv, char **envp)
3730 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3731 if(find_applet_by_name(cmd) != NULL) {
3732 /* re-exec ourselves with the new arguments */
3733 execve("/proc/self/exe",argv,envp);
3734 /* If proc isn't mounted, try hardcoded path to busybox binary*/
3735 execve("/bin/busybox",argv,envp);
3736 /* If they called chroot or otherwise made the binary no longer
3737 * executable, fall through */
3744 execve(cmd, argv, envp);
3745 } while (errno == EINTR);
3747 execve(cmd, argv, envp);
3751 } else if (errno == ENOEXEC) {
3755 for (ap = argv; *ap; ap++)
3757 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
3759 *ap = cmd = (char *)DEFAULT_SHELL;
3762 while ((*ap++ = *argv++))
3772 * Do a path search. The variable path (passed by reference) should be
3773 * set to the start of the path before the first call; padvance will update
3774 * this value as it proceeds. Successive calls to padvance will return
3775 * the possible path expansions in sequence. If an option (indicated by
3776 * a percent sign) appears in the path entry then the global variable
3777 * pathopt will be set to point to it; otherwise pathopt will be set to
3782 padvance(const char **path, const char *name)
3792 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
3793 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
3794 while (stackblocksize() < len)
3798 memcpy(q, start, p - start);
3806 while (*p && *p != ':') p++;
3812 return stalloc(len);
3816 /*** Command hashing code ***/
3819 printentry(struct tblentry *cmdp)
3825 idx = cmdp->param.index;
3828 name = padvance(&path, cmdp->cmdname);
3830 } while (--idx >= 0);
3831 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
3836 hashcmd(int argc, char **argv)
3838 struct tblentry **pp;
3839 struct tblentry *cmdp;
3841 struct cmdentry entry;
3844 while ((c = nextopt("r")) != '\0') {
3848 if (*argptr == NULL) {
3849 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3850 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3851 if (cmdp->cmdtype == CMDNORMAL)
3858 while ((name = *argptr) != NULL) {
3859 if ((cmdp = cmdlookup(name, 0)) != NULL
3860 && (cmdp->cmdtype == CMDNORMAL
3861 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
3863 find_command(name, &entry, DO_ERR, pathval());
3864 if (entry.cmdtype == CMDUNKNOWN)
3873 * Resolve a command name. If you change this routine, you may have to
3874 * change the shellexec routine as well.
3878 find_command(char *name, struct cmdentry *entry, int act, const char *path)
3880 struct tblentry *cmdp;
3887 struct builtincmd *bcmd;
3889 /* If name contains a slash, don't use PATH or hash table */
3890 if (strchr(name, '/') != NULL) {
3891 entry->u.index = -1;
3893 while (stat(name, &statb) < 0) {
3898 entry->cmdtype = CMDUNKNOWN;
3902 entry->cmdtype = CMDNORMAL;
3906 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3907 if (find_applet_by_name(name)) {
3908 entry->cmdtype = CMDNORMAL;
3909 entry->u.index = -1;
3914 updatetbl = (path == pathval());
3917 if (strstr(path, "%builtin") != NULL)
3921 /* If name is in the table, check answer will be ok */
3922 if ((cmdp = cmdlookup(name, 0)) != NULL) {
3925 switch (cmdp->cmdtype) {
3943 } else if (cmdp->rehash == 0)
3944 /* if not invalidated by cd, we're done */
3948 /* If %builtin not in path, check for builtin next */
3949 bcmd = find_builtin(name);
3950 if (bcmd && (IS_BUILTIN_REGULAR(bcmd) || (
3951 act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0
3953 goto builtin_success;
3955 /* We have to search path. */
3956 prev = -1; /* where to start */
3957 if (cmdp && cmdp->rehash) { /* doing a rehash */
3958 if (cmdp->cmdtype == CMDBUILTIN)
3961 prev = cmdp->param.index;
3967 while ((fullname = padvance(&path, name)) != NULL) {
3968 stunalloc(fullname);
3971 if (prefix(pathopt, "builtin")) {
3973 goto builtin_success;
3975 } else if (!(act & DO_NOFUNC) &&
3976 prefix(pathopt, "func")) {
3979 /* ignore unimplemented options */
3983 /* if rehash, don't redo absolute path names */
3984 if (fullname[0] == '/' && idx <= prev) {
3987 TRACE(("searchexec \"%s\": no change\n", name));
3990 while (stat(fullname, &statb) < 0) {
3995 if (errno != ENOENT && errno != ENOTDIR)
3999 e = EACCES; /* if we fail, this will be the error */
4000 if (!S_ISREG(statb.st_mode))
4002 if (pathopt) { /* this is a %func directory */
4003 stalloc(strlen(fullname) + 1);
4004 readcmdfile(fullname);
4005 if ((cmdp = cmdlookup(name, 0)) == NULL ||
4006 cmdp->cmdtype != CMDFUNCTION)
4007 error("%s not defined in %s", name, fullname);
4008 stunalloc(fullname);
4011 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
4013 entry->cmdtype = CMDNORMAL;
4014 entry->u.index = idx;
4018 cmdp = cmdlookup(name, 1);
4019 cmdp->cmdtype = CMDNORMAL;
4020 cmdp->param.index = idx;
4025 /* We failed. If there was an entry for this command, delete it */
4026 if (cmdp && updatetbl)
4029 sh_warnx("%s: %s", name, errmsg(e, E_EXEC));
4030 entry->cmdtype = CMDUNKNOWN;
4035 entry->cmdtype = CMDBUILTIN;
4036 entry->u.cmd = bcmd;
4040 cmdp = cmdlookup(name, 1);
4041 cmdp->cmdtype = CMDBUILTIN;
4042 cmdp->param.cmd = bcmd;
4046 entry->cmdtype = cmdp->cmdtype;
4047 entry->u = cmdp->param;
4052 * Wrapper around strcmp for qsort/bsearch/...
4054 static int pstrcmp(const void *a, const void *b)
4056 return strcmp((const char *) a, (*(const char *const *) b) + 1);
4060 * Search the table of builtin commands.
4063 static struct builtincmd *
4064 find_builtin(const char *name)
4066 struct builtincmd *bp;
4069 name, builtincmd, NUMBUILTINS, sizeof(struct builtincmd),
4078 * Called when a cd is done. Marks all commands so the next time they
4079 * are executed they will be rehashed.
4085 struct tblentry **pp;
4086 struct tblentry *cmdp;
4088 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4089 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4090 if (cmdp->cmdtype == CMDNORMAL || (
4091 cmdp->cmdtype == CMDBUILTIN &&
4092 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) &&
4103 * Fix command hash table when PATH changed.
4104 * Called before PATH is changed. The argument is the new value of PATH;
4105 * pathval() still returns the old value at this point.
4106 * Called with interrupts off.
4110 changepath(const char *newval)
4112 const char *old, *new;
4119 firstchange = 9999; /* assume no change */
4125 if ((*old == '\0' && *new == ':')
4126 || (*old == ':' && *new == '\0'))
4128 old = new; /* ignore subsequent differences */
4132 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
4139 if (builtinloc < 0 && idx_bltin >= 0)
4140 builtinloc = idx_bltin; /* zap builtins */
4141 if (builtinloc >= 0 && idx_bltin < 0)
4143 clearcmdentry(firstchange);
4144 builtinloc = idx_bltin;
4149 * Clear out command entries. The argument specifies the first entry in
4150 * PATH which has changed.
4154 clearcmdentry(int firstchange)
4156 struct tblentry **tblp;
4157 struct tblentry **pp;
4158 struct tblentry *cmdp;
4161 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4163 while ((cmdp = *pp) != NULL) {
4164 if ((cmdp->cmdtype == CMDNORMAL &&
4165 cmdp->param.index >= firstchange)
4166 || (cmdp->cmdtype == CMDBUILTIN &&
4167 builtinloc >= firstchange)) {
4181 * Locate a command in the command hash table. If "add" is nonzero,
4182 * add the command to the table if it is not already present. The
4183 * variable "lastcmdentry" is set to point to the address of the link
4184 * pointing to the entry, so that delete_cmd_entry can delete the
4187 * Interrupts must be off if called with add != 0.
4190 static struct tblentry **lastcmdentry;
4193 static struct tblentry *
4194 cmdlookup(const char *name, int add)
4196 unsigned int hashval;
4198 struct tblentry *cmdp;
4199 struct tblentry **pp;
4202 hashval = (unsigned char)*p << 4;
4204 hashval += (unsigned char)*p++;
4206 pp = &cmdtable[hashval % CMDTABLESIZE];
4207 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4208 if (equal(cmdp->cmdname, name))
4212 if (add && cmdp == NULL) {
4213 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4214 + strlen(name) + 1);
4216 cmdp->cmdtype = CMDUNKNOWN;
4217 strcpy(cmdp->cmdname, name);
4224 * Delete the command entry returned on the last lookup.
4228 delete_cmd_entry(void)
4230 struct tblentry *cmdp;
4233 cmdp = *lastcmdentry;
4234 *lastcmdentry = cmdp->next;
4235 if (cmdp->cmdtype == CMDFUNCTION)
4236 freefunc(cmdp->param.func);
4243 * Add a new command entry, replacing any existing command entry for
4244 * the same name - except special builtins.
4248 addcmdentry(char *name, struct cmdentry *entry)
4250 struct tblentry *cmdp;
4252 cmdp = cmdlookup(name, 1);
4253 if (cmdp->cmdtype == CMDFUNCTION) {
4254 freefunc(cmdp->param.func);
4256 cmdp->cmdtype = entry->cmdtype;
4257 cmdp->param = entry->u;
4262 * Make a copy of a parse tree.
4265 static inline struct funcnode *
4266 copyfunc(union node *n)
4271 funcblocksize = offsetof(struct funcnode, n);
4274 blocksize = funcblocksize;
4275 f = ckmalloc(blocksize + funcstringsize);
4276 funcblock = (char *) f + offsetof(struct funcnode, n);
4277 funcstring = (char *) f + blocksize;
4284 * Define a shell function.
4288 defun(char *name, union node *func)
4290 struct cmdentry entry;
4293 entry.cmdtype = CMDFUNCTION;
4294 entry.u.func = copyfunc(func);
4295 addcmdentry(name, &entry);
4301 * Delete a function if it exists.
4305 unsetfunc(const char *name)
4307 struct tblentry *cmdp;
4309 if ((cmdp = cmdlookup(name, 0)) != NULL &&
4310 cmdp->cmdtype == CMDFUNCTION)
4315 * Locate and print what a word is...
4319 #ifdef CONFIG_ASH_CMDCMD
4321 describe_command(char *command, int describe_command_verbose)
4323 #define describe_command_verbose 1
4325 describe_command(char *command)
4328 struct cmdentry entry;
4329 struct tblentry *cmdp;
4330 #ifdef CONFIG_ASH_ALIAS
4331 const struct alias *ap;
4333 const char *path = pathval();
4335 if (describe_command_verbose) {
4339 /* First look at the keywords */
4340 if (findkwd(command)) {
4341 out1str(describe_command_verbose ? " is a shell keyword" : command);
4345 #ifdef CONFIG_ASH_ALIAS
4346 /* Then look at the aliases */
4347 if ((ap = lookupalias(command, 0)) != NULL) {
4348 if (describe_command_verbose) {
4349 out1fmt(" is an alias for %s", ap->val);
4358 /* Then check if it is a tracked alias */
4359 if ((cmdp = cmdlookup(command, 0)) != NULL) {
4360 entry.cmdtype = cmdp->cmdtype;
4361 entry.u = cmdp->param;
4363 /* Finally use brute force */
4364 find_command(command, &entry, DO_ABS, path);
4367 switch (entry.cmdtype) {
4369 int j = entry.u.index;
4375 p = padvance(&path, command);
4379 if (describe_command_verbose) {
4381 (cmdp ? " a tracked alias for" : nullstr), p
4390 if (describe_command_verbose) {
4391 out1str(" is a shell function");
4398 if (describe_command_verbose) {
4399 out1fmt(" is a %sshell builtin",
4400 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
4401 "special " : nullstr
4409 if (describe_command_verbose) {
4410 out1str(": not found\n");
4416 outstr("\n", stdout);
4421 typecmd(int argc, char **argv)
4426 for (i = 1; i < argc; i++) {
4427 #ifdef CONFIG_ASH_CMDCMD
4428 err |= describe_command(argv[i], 1);
4430 err |= describe_command(argv[i]);
4436 #ifdef CONFIG_ASH_CMDCMD
4438 commandcmd(int argc, char **argv)
4441 int default_path = 0;
4442 int verify_only = 0;
4443 int verbose_verify_only = 0;
4445 while ((c = nextopt("pvV")) != '\0')
4450 "command: nextopt returned character code 0%o\n", c);
4460 verbose_verify_only = 1;
4464 if (default_path + verify_only + verbose_verify_only > 1 ||
4467 "command [-p] command [arg ...]\n"
4468 "command {-v|-V} command\n");
4472 if (verify_only || verbose_verify_only) {
4473 return describe_command(*argptr, verbose_verify_only);
4480 /* $NetBSD: expand.c,v 1.56 2002/11/24 22:35:39 christos Exp $ */
4483 * Routines to expand arguments to commands. We have to deal with
4484 * backquotes, shell variables, and file metacharacters.
4490 #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4491 #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
4492 #define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
4493 #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
4494 #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
4497 * Structure specifying which parts of the string should be searched
4498 * for IFS characters.
4502 struct ifsregion *next; /* next region in list */
4503 int begoff; /* offset of start of region */
4504 int endoff; /* offset of end of region */
4505 int nulonly; /* search for nul bytes only */
4508 /* output of current string */
4509 static char *expdest;
4510 /* list of back quote expressions */
4511 static struct nodelist *argbackq;
4512 /* first struct in list of ifs regions */
4513 static struct ifsregion ifsfirst;
4514 /* last struct in list */
4515 static struct ifsregion *ifslastp;
4516 /* holds expanded arg list */
4517 static struct arglist exparg;
4519 static void argstr(char *, int);
4520 static char *exptilde(char *, char *, int);
4521 static void expbackq(union node *, int, int);
4522 static const char *subevalvar(char *, char *, int, int, int, int, int);
4523 static char *evalvar(char *, int);
4524 static void strtodest(const char *, int, int);
4525 static void memtodest(const char *p, size_t len, int syntax, int quotes);
4526 static ssize_t varvalue(char *, int, int);
4527 static void recordregion(int, int, int);
4528 static void removerecordregions(int);
4529 static void ifsbreakup(char *, struct arglist *);
4530 static void ifsfree(void);
4531 static void expandmeta(struct strlist *, int);
4532 static int patmatch(char *, const char *);
4534 static int cvtnum(arith_t);
4535 static size_t esclen(const char *, const char *);
4536 static char *scanleft(char *, char *, char *, char *, int, int);
4537 static char *scanright(char *, char *, char *, char *, int, int);
4538 static void varunset(const char *, const char *, const char *, int)
4539 __attribute__((__noreturn__));
4542 #define pmatch(a, b) !fnmatch((a), (b), 0)
4544 * Prepare a pattern for a expmeta (internal glob(3)) call.
4546 * Returns an stalloced string.
4549 static inline char *
4550 preglob(const char *pattern, int quoted, int flag) {
4551 flag |= RMESCAPE_GLOB;
4553 flag |= RMESCAPE_QUOTED;
4555 return _rmescapes((char *)pattern, flag);
4560 esclen(const char *start, const char *p) {
4563 while (p > start && *--p == CTLESC) {
4571 * Expand shell variables and backquotes inside a here document.
4575 expandhere(union node *arg, int fd)
4578 expandarg(arg, (struct arglist *)NULL, 0);
4579 bb_full_write(fd, stackblock(), expdest - (char *)stackblock());
4584 * Perform variable substitution and command substitution on an argument,
4585 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4586 * perform splitting and file name expansion. When arglist is NULL, perform
4587 * here document expansion.
4591 expandarg(union node *arg, struct arglist *arglist, int flag)
4596 argbackq = arg->narg.backquote;
4597 STARTSTACKSTR(expdest);
4598 ifsfirst.next = NULL;
4600 argstr(arg->narg.text, flag);
4601 p = _STPUTC('\0', expdest);
4603 if (arglist == NULL) {
4604 return; /* here document expanded */
4606 p = grabstackstr(p);
4607 exparg.lastp = &exparg.list;
4611 if (flag & EXP_FULL) {
4612 ifsbreakup(p, &exparg);
4613 *exparg.lastp = NULL;
4614 exparg.lastp = &exparg.list;
4615 expandmeta(exparg.list, flag);
4617 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
4619 sp = (struct strlist *)stalloc(sizeof (struct strlist));
4622 exparg.lastp = &sp->next;
4626 *exparg.lastp = NULL;
4628 *arglist->lastp = exparg.list;
4629 arglist->lastp = exparg.lastp;
4635 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4636 * characters to allow for further processing. Otherwise treat
4637 * $@ like $* since no splitting will be performed.
4641 argstr(char *p, int flag)
4643 static const char spclchars[] = {
4651 CTLBACKQ | CTLQUOTE,
4652 #ifdef CONFIG_ASH_MATH_SUPPORT
4657 const char *reject = spclchars;
4659 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
4660 int breakall = flag & EXP_WORD;
4665 if (!(flag & EXP_VARTILDE)) {
4667 } else if (flag & EXP_VARTILDE2) {
4672 if (flag & EXP_TILDE) {
4678 if (*q == CTLESC && (flag & EXP_QWORD))
4681 p = exptilde(p, q, flag);
4684 startloc = expdest - (char *)stackblock();
4686 length += strcspn(p + length, reject);
4688 if (c && (!(c & 0x80)
4689 #ifdef CONFIG_ASH_MATH_SUPPORT
4693 /* c == '=' || c == ':' || c == CTLENDARI */
4698 expdest = stnputs(p, length, expdest);
4699 newloc = expdest - (char *)stackblock();
4700 if (breakall && !inquotes && newloc > startloc) {
4701 recordregion(startloc, newloc, 0);
4712 if (flag & EXP_VARTILDE2) {
4716 flag |= EXP_VARTILDE2;
4721 * sort of a hack - expand tildes in variable
4722 * assignments (after the first '=' and after ':'s).
4731 case CTLENDVAR: /* ??? */
4734 /* "$@" syntax adherence hack */
4737 !memcmp(p, dolatstr, DOLATSTRLEN) &&
4738 (p[4] == CTLQUOTEMARK || (
4739 p[4] == CTLENDVAR &&
4740 p[5] == CTLQUOTEMARK
4743 p = evalvar(p + 1, flag) + 1;
4746 inquotes = !inquotes;
4759 p = evalvar(p, flag);
4763 case CTLBACKQ|CTLQUOTE:
4764 expbackq(argbackq->n, c, quotes);
4765 argbackq = argbackq->next;
4767 #ifdef CONFIG_ASH_MATH_SUPPORT
4780 exptilde(char *startp, char *p, int flag)
4786 int quotes = flag & (EXP_FULL | EXP_CASE);
4791 while ((c = *++p) != '\0') {
4798 if (flag & EXP_VARTILDE)
4808 if (*name == '\0') {
4809 if ((home = lookupvar(homestr)) == NULL)
4812 if ((pw = getpwnam(name)) == NULL)
4819 startloc = expdest - (char *)stackblock();
4820 strtodest(home, SQSYNTAX, quotes);
4821 recordregion(startloc, expdest - (char *)stackblock(), 0);
4830 removerecordregions(int endoff)
4832 if (ifslastp == NULL)
4835 if (ifsfirst.endoff > endoff) {
4836 while (ifsfirst.next != NULL) {
4837 struct ifsregion *ifsp;
4839 ifsp = ifsfirst.next->next;
4840 ckfree(ifsfirst.next);
4841 ifsfirst.next = ifsp;
4844 if (ifsfirst.begoff > endoff)
4847 ifslastp = &ifsfirst;
4848 ifsfirst.endoff = endoff;
4853 ifslastp = &ifsfirst;
4854 while (ifslastp->next && ifslastp->next->begoff < endoff)
4855 ifslastp=ifslastp->next;
4856 while (ifslastp->next != NULL) {
4857 struct ifsregion *ifsp;
4859 ifsp = ifslastp->next->next;
4860 ckfree(ifslastp->next);
4861 ifslastp->next = ifsp;
4864 if (ifslastp->endoff > endoff)
4865 ifslastp->endoff = endoff;
4869 #ifdef CONFIG_ASH_MATH_SUPPORT
4871 * Expand arithmetic expression. Backup to start of expression,
4872 * evaluate, place result in (backed up) result, adjust string position.
4885 * This routine is slightly over-complicated for
4886 * efficiency. Next we scan backwards looking for the
4887 * start of arithmetic.
4889 start = stackblock();
4896 while (*p != CTLARI) {
4900 error("missing CTLARI (shouldn't happen)");
4905 esc = esclen(start, p);
4915 removerecordregions(begoff);
4924 len = cvtnum(dash_arith(p + 2));
4927 recordregion(begoff, begoff + len, 0);
4932 * Expand stuff in backwards quotes.
4936 expbackq(union node *cmd, int quoted, int quotes)
4944 int syntax = quoted? DQSYNTAX : BASESYNTAX;
4945 struct stackmark smark;
4948 setstackmark(&smark);
4950 startloc = dest - (char *)stackblock();
4952 evalbackcmd(cmd, (struct backcmd *) &in);
4953 popstackmark(&smark);
4960 memtodest(p, i, syntax, quotes);
4964 i = safe_read(in.fd, buf, sizeof buf);
4965 TRACE(("expbackq: read returns %d\n", i));
4975 back_exitstatus = waitforjob(in.jp);
4979 /* Eat all trailing newlines */
4981 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
4986 recordregion(startloc, dest - (char *)stackblock(), 0);
4987 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4988 (dest - (char *)stackblock()) - startloc,
4989 (dest - (char *)stackblock()) - startloc,
4990 stackblock() + startloc));
4995 scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5006 const char *s = loc2;
5012 match = pmatch(str, s);
5016 if (quotes && *loc == CTLESC)
5026 scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5033 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5036 const char *s = loc2;
5041 match = pmatch(str, s);
5048 esc = esclen(startp, loc);
5060 subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
5064 int saveherefd = herefd;
5065 struct nodelist *saveargbackq = argbackq;
5067 char *rmesc, *rmescend;
5069 char *(*scan)(char *, char *, char *, char *, int , int);
5072 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
5073 STPUTC('\0', expdest);
5074 herefd = saveherefd;
5075 argbackq = saveargbackq;
5076 startp = stackblock() + startloc;
5080 setvar(str, startp, 0);
5081 amount = startp - expdest;
5082 STADJUST(amount, expdest);
5086 varunset(p, str, startp, varflags);
5090 subtype -= VSTRIMRIGHT;
5092 if (subtype < 0 || subtype > 3)
5097 rmescend = stackblock() + strloc;
5099 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5100 if (rmesc != startp) {
5102 startp = stackblock() + startloc;
5106 str = stackblock() + strloc;
5107 preglob(str, varflags & VSQUOTE, 0);
5109 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
5110 zero = subtype >> 1;
5111 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
5112 scan = (subtype & 1) ^ zero ? scanleft : scanright;
5114 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
5117 memmove(startp, loc, str - loc);
5118 loc = startp + (str - loc) - 1;
5121 amount = loc - expdest;
5122 STADJUST(amount, expdest);
5129 * Expand a variable, and return a pointer to the next character in the
5133 evalvar(char *p, int flag)
5146 quotes = flag & (EXP_FULL | EXP_CASE);
5148 subtype = varflags & VSTYPE;
5149 quoted = varflags & VSQUOTE;
5151 easy = (!quoted || (*var == '@' && shellparam.nparam));
5152 startloc = expdest - (char *)stackblock();
5153 p = strchr(p, '=') + 1;
5156 varlen = varvalue(var, varflags, flag);
5157 if (varflags & VSNUL)
5160 if (subtype == VSPLUS) {
5161 varlen = -1 - varlen;
5165 if (subtype == VSMINUS) {
5169 p, flag | EXP_TILDE |
5170 (quoted ? EXP_QWORD : EXP_WORD)
5179 if (subtype == VSASSIGN || subtype == VSQUESTION) {
5181 if (subevalvar(p, var, 0, subtype, startloc,
5185 * Remove any recorded regions beyond
5188 removerecordregions(startloc);
5198 if (varlen < 0 && uflag)
5199 varunset(p, var, 0, 0);
5201 if (subtype == VSLENGTH) {
5202 cvtnum(varlen > 0 ? varlen : 0);
5206 if (subtype == VSNORMAL) {
5210 recordregion(startloc, expdest - (char *)stackblock(), quoted);
5219 case VSTRIMRIGHTMAX:
5228 * Terminate the string and start recording the pattern
5231 STPUTC('\0', expdest);
5232 patloc = expdest - (char *)stackblock();
5233 if (subevalvar(p, NULL, patloc, subtype,
5234 startloc, varflags, quotes) == 0) {
5235 int amount = expdest - (
5236 (char *)stackblock() + patloc - 1
5238 STADJUST(-amount, expdest);
5240 /* Remove any recorded regions beyond start of variable */
5241 removerecordregions(startloc);
5246 if (subtype != VSNORMAL) { /* skip to end of alternative */
5249 if ((c = *p++) == CTLESC)
5251 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
5253 argbackq = argbackq->next;
5254 } else if (c == CTLVAR) {
5255 if ((*p++ & VSTYPE) != VSNORMAL)
5257 } else if (c == CTLENDVAR) {
5268 * Put a string on the stack.
5272 memtodest(const char *p, size_t len, int syntax, int quotes) {
5275 q = makestrspace(len * 2, q);
5281 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5291 strtodest(const char *p, int syntax, int quotes)
5293 memtodest(p, strlen(p), syntax, quotes);
5298 * Add the value of a specialized variable to the stack string.
5302 varvalue(char *name, int varflags, int flags)
5312 int quoted = varflags & VSQUOTE;
5313 int subtype = varflags & VSTYPE;
5314 int quotes = flags & (EXP_FULL | EXP_CASE);
5316 if (quoted && (flags & EXP_FULL))
5317 sep = 1 << CHAR_BIT;
5319 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5328 num = shellparam.nparam;
5338 p = makestrspace(NOPTS, expdest);
5339 for (i = NOPTS - 1; i >= 0; i--) {
5341 USTPUTC(optletters(i), p);
5352 sep = ifsset() ? ifsval()[0] : ' ';
5353 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
5356 if (!(ap = shellparam.p))
5358 while ((p = *ap++)) {
5361 partlen = strlen(p);
5364 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5365 memtodest(p, partlen, syntax, quotes);
5371 if (subtype == VSPLUS || subtype == VSLENGTH) {
5393 if (num < 0 || num > shellparam.nparam)
5395 p = num ? shellparam.p[num - 1] : arg0;
5398 p = lookupvar(name);
5404 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5405 memtodest(p, len, syntax, quotes);
5409 if (subtype == VSPLUS || subtype == VSLENGTH)
5410 STADJUST(-len, expdest);
5416 * Record the fact that we have to scan this region of the
5417 * string for IFS characters.
5421 recordregion(int start, int end, int nulonly)
5423 struct ifsregion *ifsp;
5425 if (ifslastp == NULL) {
5429 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
5431 ifslastp->next = ifsp;
5435 ifslastp->begoff = start;
5436 ifslastp->endoff = end;
5437 ifslastp->nulonly = nulonly;
5442 * Break the argument string into pieces based upon IFS and add the
5443 * strings to the argument list. The regions of the string to be
5444 * searched for IFS characters have been stored by recordregion.
5447 ifsbreakup(char *string, struct arglist *arglist)
5449 struct ifsregion *ifsp;
5454 const char *ifs, *realifs;
5460 if (ifslastp != NULL) {
5463 realifs = ifsset() ? ifsval() : defifs;
5466 p = string + ifsp->begoff;
5467 nulonly = ifsp->nulonly;
5468 ifs = nulonly ? nullstr : realifs;
5470 while (p < string + ifsp->endoff) {
5474 if (strchr(ifs, *p)) {
5476 ifsspc = (strchr(defifs, *p) != NULL);
5477 /* Ignore IFS whitespace at start */
5478 if (q == start && ifsspc) {
5484 sp = (struct strlist *)stalloc(sizeof *sp);
5486 *arglist->lastp = sp;
5487 arglist->lastp = &sp->next;
5491 if (p >= string + ifsp->endoff) {
5497 if (strchr(ifs, *p) == NULL ) {
5500 } else if (strchr(defifs, *p) == NULL) {
5516 } while ((ifsp = ifsp->next) != NULL);
5525 sp = (struct strlist *)stalloc(sizeof *sp);
5527 *arglist->lastp = sp;
5528 arglist->lastp = &sp->next;
5534 struct ifsregion *p;
5539 struct ifsregion *ifsp;
5545 ifsfirst.next = NULL;
5549 static void expmeta(char *, char *);
5550 static struct strlist *expsort(struct strlist *);
5551 static struct strlist *msort(struct strlist *, int);
5553 static char *expdir;
5557 expandmeta(struct strlist *str, int flag)
5559 static const char metachars[] = {
5562 /* TODO - EXP_REDIR */
5565 struct strlist **savelastp;
5571 if (!strpbrk(str->text, metachars))
5573 savelastp = exparg.lastp;
5576 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
5578 int i = strlen(str->text);
5579 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5587 if (exparg.lastp == savelastp) {
5592 *exparg.lastp = str;
5593 rmescapes(str->text);
5594 exparg.lastp = &str->next;
5596 *exparg.lastp = NULL;
5597 *savelastp = sp = expsort(*savelastp);
5598 while (sp->next != NULL)
5600 exparg.lastp = &sp->next;
5607 * Add a file name to the list.
5611 addfname(const char *name)
5615 sp = (struct strlist *)stalloc(sizeof *sp);
5616 sp->text = sstrdup(name);
5618 exparg.lastp = &sp->next;
5623 * Do metacharacter (i.e. *, ?, [...]) expansion.
5627 expmeta(char *enddir, char *name)
5642 for (p = name; *p; p++) {
5643 if (*p == '*' || *p == '?')
5645 else if (*p == '[') {
5652 if (*q == '/' || *q == '\0')
5659 } else if (*p == '\\')
5661 else if (*p == '/') {
5668 if (metaflag == 0) { /* we've reached the end of the file name */
5669 if (enddir != expdir)
5677 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
5688 } while (p < start);
5690 if (enddir == expdir) {
5692 } else if (enddir == expdir + 1 && *expdir == '/') {
5698 if ((dirp = opendir(cp)) == NULL)
5700 if (enddir != expdir)
5702 if (*endname == 0) {
5714 while (! intpending && (dp = readdir(dirp)) != NULL) {
5715 if (dp->d_name[0] == '.' && ! matchdot)
5717 if (pmatch(start, dp->d_name)) {
5719 scopy(dp->d_name, enddir);
5722 for (p = enddir, cp = dp->d_name;
5723 (*p++ = *cp++) != '\0';)
5726 expmeta(p, endname);
5736 * Sort the results of file name expansion. It calculates the number of
5737 * strings to sort and then calls msort (short for merge sort) to do the
5741 static struct strlist *
5742 expsort(struct strlist *str)
5748 for (sp = str ; sp ; sp = sp->next)
5750 return msort(str, len);
5754 static struct strlist *
5755 msort(struct strlist *list, int len)
5757 struct strlist *p, *q = NULL;
5758 struct strlist **lpp;
5766 for (n = half ; --n >= 0 ; ) {
5770 q->next = NULL; /* terminate first half of list */
5771 q = msort(list, half); /* sort first half of list */
5772 p = msort(p, len - half); /* sort second half */
5775 #ifdef CONFIG_LOCALE_SUPPORT
5776 if (strcoll(p->text, q->text) < 0)
5778 if (strcmp(p->text, q->text) < 0)
5783 if ((p = *lpp) == NULL) {
5790 if ((q = *lpp) == NULL) {
5801 * Returns true if the pattern matches the string.
5805 patmatch(char *pattern, const char *string)
5807 return pmatch(preglob(pattern, 0, 0), string);
5812 * Remove any CTLESC characters from a string.
5816 _rmescapes(char *str, int flag)
5819 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
5824 p = strpbrk(str, qchars);
5830 if (flag & RMESCAPE_ALLOC) {
5831 size_t len = p - str;
5832 size_t fulllen = len + strlen(p) + 1;
5834 if (flag & RMESCAPE_GROW) {
5835 r = makestrspace(fulllen, expdest);
5836 } else if (flag & RMESCAPE_HEAP) {
5837 r = ckmalloc(fulllen);
5839 r = stalloc(fulllen);
5843 q = mempcpy(q, str, len);
5846 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5847 globbing = flag & RMESCAPE_GLOB;
5848 notescaped = globbing;
5850 if (*p == CTLQUOTEMARK) {
5851 inquotes = ~inquotes;
5853 notescaped = globbing;
5857 /* naked back slash */
5863 if (notescaped && inquotes && *p != '/') {
5867 notescaped = globbing;
5872 if (flag & RMESCAPE_GROW) {
5874 STADJUST(q - r + 1, expdest);
5881 * See if a pattern matches in a case statement.
5885 casematch(union node *pattern, char *val)
5887 struct stackmark smark;
5890 setstackmark(&smark);
5891 argbackq = pattern->narg.backquote;
5892 STARTSTACKSTR(expdest);
5894 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
5895 STACKSTRNUL(expdest);
5896 result = patmatch(stackblock(), val);
5897 popstackmark(&smark);
5910 expdest = makestrspace(32, expdest);
5911 #ifdef CONFIG_ASH_MATH_SUPPORT_64
5912 len = fmtstr(expdest, 32, "%lld", (long long) num);
5914 len = fmtstr(expdest, 32, "%ld", num);
5916 STADJUST(len, expdest);
5921 varunset(const char *end, const char *var, const char *umsg, int varflags)
5927 msg = "parameter not set";
5929 if (*end == CTLENDVAR) {
5930 if (varflags & VSNUL)
5935 error("%.*s: %s%s", end - var - 1, var, msg, tail);
5939 /* $NetBSD: input.c,v 1.37 2002/11/24 22:35:40 christos Exp $ */
5942 * This implements the input routines used by the parser.
5945 #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
5947 static void pushfile(void);
5950 * Read a character from the script, returning PEOF on end of file.
5951 * Nul characters in the input are silently discarded.
5954 #define pgetc_as_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
5956 #ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
5957 #define pgetc_macro() pgetc()
5961 return pgetc_as_macro();
5964 #define pgetc_macro() pgetc_as_macro()
5968 return pgetc_macro();
5974 * Same as pgetc(), but ignores PEOA.
5976 #ifdef CONFIG_ASH_ALIAS
5977 static int pgetc2(void)
5983 } while (c == PEOA);
5987 static inline int pgetc2(void)
5989 return pgetc_macro();
5994 * Read a line from the script.
5997 static inline char *
5998 pfgets(char *line, int len)
6004 while (--nleft > 0) {
6021 #ifdef CONFIG_FEATURE_COMMAND_EDITING
6022 #ifdef CONFIG_ASH_EXPAND_PRMT
6023 static char *cmdedit_prompt;
6025 static const char *cmdedit_prompt;
6027 static inline void putprompt(const char *s)
6029 #ifdef CONFIG_ASH_EXPAND_PRMT
6030 free(cmdedit_prompt);
6031 cmdedit_prompt = bb_xstrdup(s);
6037 static inline void putprompt(const char *s)
6047 char *buf = parsefile->buf;
6051 #ifdef CONFIG_FEATURE_COMMAND_EDITING
6052 if (!iflag || parsefile->fd)
6053 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6055 #ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
6056 cmdedit_path_lookup = pathval();
6058 nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
6060 /* Ctrl+C presend */
6069 if(nr < 0 && errno == 0) {
6070 /* Ctrl+D presend */
6075 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6079 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6080 int flags = fcntl(0, F_GETFL, 0);
6081 if (flags >= 0 && flags & O_NONBLOCK) {
6082 flags &=~ O_NONBLOCK;
6083 if (fcntl(0, F_SETFL, flags) >= 0) {
6084 out2str("sh: turning off NDELAY mode\n");
6094 * Refill the input buffer and return the next input character:
6096 * 1) If a string was pushed back on the input, pop it;
6097 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6098 * from a string so we can't refill the buffer, return EOF.
6099 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6100 * 4) Process input up to the next newline, deleting nul characters.
6110 while (parsefile->strpush) {
6111 #ifdef CONFIG_ASH_ALIAS
6112 if (parsenleft == -1 && parsefile->strpush->ap &&
6113 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
6118 if (--parsenleft >= 0)
6119 return (*parsenextc++);
6121 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6126 if (parselleft <= 0) {
6127 if ((parselleft = preadfd()) <= 0) {
6128 parselleft = parsenleft = EOF_NLEFT;
6135 /* delete nul characters */
6136 for (more = 1; more;) {
6143 parsenleft = q - parsenextc;
6144 more = 0; /* Stop processing here */
6151 if (--parselleft <= 0 && more) {
6152 parsenleft = q - parsenextc - 1;
6163 out2str(parsenextc);
6168 return *parsenextc++;
6172 * Undo the last call to pgetc. Only one character may be pushed back.
6173 * PEOF may be pushed back.
6184 * Push a string back onto the input at this current parsefile level.
6185 * We handle aliases this way.
6188 pushstring(char *s, void *ap)
6195 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6196 if (parsefile->strpush) {
6197 sp = ckmalloc(sizeof (struct strpush));
6198 sp->prev = parsefile->strpush;
6199 parsefile->strpush = sp;
6201 sp = parsefile->strpush = &(parsefile->basestrpush);
6202 sp->prevstring = parsenextc;
6203 sp->prevnleft = parsenleft;
6204 #ifdef CONFIG_ASH_ALIAS
6205 sp->ap = (struct alias *)ap;
6207 ((struct alias *)ap)->flag |= ALIASINUSE;
6219 struct strpush *sp = parsefile->strpush;
6222 #ifdef CONFIG_ASH_ALIAS
6224 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6225 checkkwd |= CHKALIAS;
6227 if (sp->string != sp->ap->val) {
6230 sp->ap->flag &= ~ALIASINUSE;
6231 if (sp->ap->flag & ALIASDEAD) {
6232 unalias(sp->ap->name);
6236 parsenextc = sp->prevstring;
6237 parsenleft = sp->prevnleft;
6238 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6239 parsefile->strpush = sp->prev;
6240 if (sp != &(parsefile->basestrpush))
6246 * Set the input to take input from a file. If push is set, push the
6247 * old input onto the stack first.
6251 setinputfile(const char *fname, int push)
6257 if ((fd = open(fname, O_RDONLY)) < 0)
6258 error("Can't open %s", fname);
6260 fd2 = copyfd(fd, 10);
6263 error("Out of file descriptors");
6266 setinputfd(fd, push);
6272 * Like setinputfile, but takes an open file descriptor. Call this with
6277 setinputfd(int fd, int push)
6279 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
6285 if (parsefile->buf == NULL)
6286 parsefile->buf = ckmalloc(IBUFSIZ);
6287 parselleft = parsenleft = 0;
6293 * Like setinputfile, but takes input from a string.
6297 setinputstring(char *string)
6301 parsenextc = string;
6302 parsenleft = strlen(string);
6303 parsefile->buf = NULL;
6310 * To handle the "." command, a stack of input files is used. Pushfile
6311 * adds a new entry to the stack and popfile restores the previous level.
6317 struct parsefile *pf;
6319 parsefile->nleft = parsenleft;
6320 parsefile->lleft = parselleft;
6321 parsefile->nextc = parsenextc;
6322 parsefile->linno = plinno;
6323 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
6324 pf->prev = parsefile;
6327 pf->basestrpush.prev = NULL;
6335 struct parsefile *pf = parsefile;
6344 parsefile = pf->prev;
6346 parsenleft = parsefile->nleft;
6347 parselleft = parsefile->lleft;
6348 parsenextc = parsefile->nextc;
6349 plinno = parsefile->linno;
6355 * Return to top level.
6361 while (parsefile != &basepf)
6367 * Close the file(s) that the shell is reading commands from. Called
6368 * after a fork is done.
6375 if (parsefile->fd > 0) {
6376 close(parsefile->fd);
6381 /* $NetBSD: jobs.c,v 1.56 2002/11/25 12:13:03 agc Exp $ */
6383 /* mode flags for set_curjob */
6384 #define CUR_DELETE 2
6385 #define CUR_RUNNING 1
6386 #define CUR_STOPPED 0
6388 /* mode flags for dowait */
6389 #define DOWAIT_NORMAL 0
6390 #define DOWAIT_BLOCK 1
6393 static struct job *jobtab;
6395 static unsigned njobs;
6397 /* pgrp of shell on invocation */
6398 static int initialpgrp;
6399 static int ttyfd = -1;
6402 static struct job *curjob;
6403 /* number of presumed living untracked jobs */
6406 static void set_curjob(struct job *, unsigned);
6408 static int restartjob(struct job *, int);
6409 static void xtcsetpgrp(int, pid_t);
6410 static char *commandtext(union node *);
6411 static void cmdlist(union node *, int);
6412 static void cmdtxt(union node *);
6413 static void cmdputs(const char *);
6414 static void showpipe(struct job *, FILE *);
6416 static int sprint_status(char *, int, int);
6417 static void freejob(struct job *);
6418 static struct job *getjob(const char *, int);
6419 static struct job *growjobtab(void);
6420 static void forkchild(struct job *, union node *, int);
6421 static void forkparent(struct job *, union node *, int, pid_t);
6422 static int dowait(int, struct job *);
6423 static int getstatus(struct job *);
6426 set_curjob(struct job *jp, unsigned mode)
6429 struct job **jpp, **curp;
6431 /* first remove from list */
6432 jpp = curp = &curjob;
6437 jpp = &jp1->prev_job;
6439 *jpp = jp1->prev_job;
6441 /* Then re-insert in correct position */
6449 /* job being deleted */
6452 /* newly created job or backgrounded job,
6453 put after all stopped jobs. */
6457 if (!jp1 || jp1->state != JOBSTOPPED)
6460 jpp = &jp1->prev_job;
6466 /* newly stopped job - becomes curjob */
6467 jp->prev_job = *jpp;
6475 * Turn job control on and off.
6477 * Note: This code assumes that the third arg to ioctl is a character
6478 * pointer, which is true on Berkeley systems but not System V. Since
6479 * System V doesn't have job control yet, this isn't a problem now.
6481 * Called with interrupts off.
6490 if (on == jobctl || rootshell == 0)
6494 ofd = fd = open(_PATH_TTY, O_RDWR);
6497 while (!isatty(fd) && --fd >= 0)
6500 fd = fcntl(fd, F_DUPFD, 10);
6504 fcntl(fd, F_SETFD, FD_CLOEXEC);
6505 do { /* while we are in the background */
6506 if ((pgrp = tcgetpgrp(fd)) < 0) {
6508 sh_warnx("can't access tty; job control turned off");
6512 if (pgrp == getpgrp())
6523 xtcsetpgrp(fd, pgrp);
6525 /* turning job control off */
6528 xtcsetpgrp(fd, pgrp);
6542 killcmd(int argc, char **argv)
6553 "Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6554 "kill -l [exitstatus]"
6558 if (**++argv == '-') {
6559 signo = decode_signal(*argv + 1, 1);
6563 while ((c = nextopt("ls:")) != '\0')
6573 signo = decode_signal(optionarg, 1);
6576 "invalid signal number or name: %s",
6587 if (!list && signo < 0)
6590 if ((signo < 0 || !*argv) ^ list) {
6598 for (i = 1; i < NSIG; i++) {
6599 name = u_signal_names(0, &i, 1);
6601 out1fmt(snlfmt, name);
6605 name = u_signal_names(*argptr, &signo, -1);
6607 out1fmt(snlfmt, name);
6609 error("invalid signal number or exit status: %s", *argptr);
6615 if (**argv == '%') {
6616 jp = getjob(*argv, 0);
6617 pid = -jp->ps[0].pid;
6619 pid = **argv == '-' ?
6620 -number(*argv + 1) : number(*argv);
6622 if (kill(pid, signo) != 0) {
6623 sh_warnx("(%d) - %m", pid);
6632 #if defined(JOBS) || defined(DEBUG)
6634 jobno(const struct job *jp)
6636 return jp - jobtab + 1;
6642 fgcmd(int argc, char **argv)
6649 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
6654 jp = getjob(*argv, 1);
6655 if (mode == FORK_BG) {
6656 set_curjob(jp, CUR_RUNNING);
6657 fprintf(out, "[%d] ", jobno(jp));
6659 outstr(jp->ps->cmd, out);
6661 retval = restartjob(jp, mode);
6662 } while (*argv && *++argv);
6666 static int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
6670 restartjob(struct job *jp, int mode)
6672 struct procstat *ps;
6678 if (jp->state == JOBDONE)
6680 jp->state = JOBRUNNING;
6682 if (mode == FORK_FG)
6683 xtcsetpgrp(ttyfd, pgid);
6684 killpg(pgid, SIGCONT);
6688 if (WIFSTOPPED(ps->status)) {
6691 } while (ps++, --i);
6693 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
6700 sprint_status(char *s, int status, int sigonly)
6706 if (!WIFEXITED(status)) {
6708 if (WIFSTOPPED(status))
6709 st = WSTOPSIG(status);
6712 st = WTERMSIG(status);
6714 if (st == SIGINT || st == SIGPIPE)
6717 if (WIFSTOPPED(status))
6722 col = fmtstr(s, 32, strsignal(st));
6723 if (WCOREDUMP(status)) {
6724 col += fmtstr(s + col, 16, " (core dumped)");
6726 } else if (!sigonly) {
6727 st = WEXITSTATUS(status);
6729 col = fmtstr(s, 16, "Done(%d)", st);
6731 col = fmtstr(s, 16, "Done");
6740 showjob(FILE *out, struct job *jp, int mode)
6742 struct procstat *ps;
6743 struct procstat *psend;
6750 if (mode & SHOW_PGID) {
6751 /* just output process (group) id of pipeline */
6752 fprintf(out, "%d\n", ps->pid);
6756 col = fmtstr(s, 16, "[%d] ", jobno(jp));
6761 else if (curjob && jp == curjob->prev_job)
6764 if (mode & SHOW_PID)
6765 col += fmtstr(s + col, 16, "%d ", ps->pid);
6767 psend = ps + jp->nprocs;
6769 if (jp->state == JOBRUNNING) {
6770 scopy("Running", s + col);
6771 col += strlen("Running");
6773 int status = psend[-1].status;
6775 if (jp->state == JOBSTOPPED)
6776 status = jp->stopstatus;
6778 col += sprint_status(s + col, status, 0);
6784 /* for each process */
6785 col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
6788 fprintf(out, "%s%*c%s",
6789 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
6791 if (!(mode & SHOW_PID)) {
6795 if (++ps == psend) {
6796 outcslow('\n', out);
6803 if (jp->state == JOBDONE) {
6804 TRACE(("showjob: freeing job %d\n", jobno(jp)));
6811 jobscmd(int argc, char **argv)
6817 while ((m = nextopt("lp")))
6827 showjob(out, getjob(*argv,0), mode);
6830 showjobs(out, mode);
6837 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6838 * statuses have changed since the last call to showjobs.
6842 showjobs(FILE *out, int mode)
6846 TRACE(("showjobs(%x) called\n", mode));
6848 /* If not even one one job changed, there is nothing to do */
6849 while (dowait(DOWAIT_NORMAL, NULL) > 0)
6852 for (jp = curjob; jp; jp = jp->prev_job) {
6853 if (!(mode & SHOW_CHANGED) || jp->changed)
6854 showjob(out, jp, mode);
6860 * Mark a job structure as unused.
6864 freejob(struct job *jp)
6866 struct procstat *ps;
6870 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
6871 if (ps->cmd != nullstr)
6874 if (jp->ps != &jp->ps0)
6877 set_curjob(jp, CUR_DELETE);
6883 waitcmd(int argc, char **argv)
6896 /* wait for all jobs */
6901 /* no running procs */
6904 if (jp->state == JOBRUNNING)
6909 dowait(DOWAIT_BLOCK, 0);
6915 if (**argv != '%') {
6916 pid_t pid = number(*argv);
6920 if (job->ps[job->nprocs - 1].pid == pid)
6922 job = job->prev_job;
6928 job = getjob(*argv, 0);
6929 /* loop until process terminated or stopped */
6930 while (job->state == JOBRUNNING)
6931 dowait(DOWAIT_BLOCK, 0);
6933 retval = getstatus(job);
6944 * Convert a job name to a job structure.
6948 getjob(const char *name, int getctl)
6952 const char *err_msg = "No such job: %s";
6956 char *(*match)(const char *, const char *);
6971 if (c == '+' || c == '%') {
6973 err_msg = "No current job";
6975 } else if (c == '-') {
6978 err_msg = "No previous job";
6989 jp = jobtab + num - 1;
7006 if (match(jp->ps[0].cmd, p)) {
7010 err_msg = "%s: ambiguous";
7017 err_msg = "job %s not created under job control";
7018 if (getctl && jp->jobctl == 0)
7023 error(err_msg, name);
7028 * Return a new job structure.
7029 * Called with interrupts off.
7033 makejob(union node *node, int nprocs)
7038 for (i = njobs, jp = jobtab ; ; jp++) {
7045 if (jp->state != JOBDONE || !jp->waited)
7054 memset(jp, 0, sizeof(*jp));
7059 jp->prev_job = curjob;
7064 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
7066 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
7076 struct job *jp, *jq;
7078 len = njobs * sizeof(*jp);
7080 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
7082 offset = (char *)jp - (char *)jq;
7084 /* Relocate pointers */
7087 jq = (struct job *)((char *)jq + l);
7091 #define joff(p) ((struct job *)((char *)(p) + l))
7092 #define jmove(p) (p) = (void *)((char *)(p) + offset)
7093 if (xlikely(joff(jp)->ps == &jq->ps0))
7094 jmove(joff(jp)->ps);
7095 if (joff(jp)->prev_job)
7096 jmove(joff(jp)->prev_job);
7106 jp = (struct job *)((char *)jp + len);
7110 } while (--jq >= jp);
7116 * Fork off a subshell. If we are doing job control, give the subshell its
7117 * own process group. Jp is a job structure that the job is to be added to.
7118 * N is the command that will be evaluated by the child. Both jp and n may
7119 * be NULL. The mode parameter can be one of the following:
7120 * FORK_FG - Fork off a foreground process.
7121 * FORK_BG - Fork off a background process.
7122 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
7123 * process group even if job control is on.
7125 * When job control is turned off, background processes have their standard
7126 * input redirected to /dev/null (except for the second and later processes
7129 * Called with interrupts off.
7133 forkchild(struct job *jp, union node *n, int mode)
7137 TRACE(("Child shell %d\n", getpid()));
7138 wasroot = rootshell;
7144 /* do job control only in root shell */
7146 if (mode != FORK_NOJOB && jp->jobctl && wasroot) {
7149 if (jp->nprocs == 0)
7152 pgrp = jp->ps[0].pid;
7153 /* This can fail because we are doing it in the parent also */
7154 (void)setpgid(0, pgrp);
7155 if (mode == FORK_FG)
7156 xtcsetpgrp(ttyfd, pgrp);
7161 if (mode == FORK_BG) {
7164 if (jp->nprocs == 0) {
7166 if (open(_PATH_DEVNULL, O_RDONLY) != 0)
7167 error("Can't open %s", _PATH_DEVNULL);
7170 if (wasroot && iflag) {
7175 for (jp = curjob; jp; jp = jp->prev_job)
7181 forkparent(struct job *jp, union node *n, int mode, pid_t pid)
7183 TRACE(("In parent shell: child = %d\n", pid));
7185 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
7190 if (mode != FORK_NOJOB && jp->jobctl) {
7193 if (jp->nprocs == 0)
7196 pgrp = jp->ps[0].pid;
7197 /* This can fail because we are doing it in the child also */
7198 (void)setpgid(pid, pgrp);
7201 if (mode == FORK_BG) {
7202 backgndpid = pid; /* set $! */
7203 set_curjob(jp, CUR_RUNNING);
7206 struct procstat *ps = &jp->ps[jp->nprocs++];
7212 ps->cmd = commandtext(n);
7218 forkshell(struct job *jp, union node *n, int mode)
7222 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
7225 TRACE(("Fork failed, errno=%d", errno));
7228 error("Cannot fork");
7231 forkchild(jp, n, mode);
7233 forkparent(jp, n, mode, pid);
7238 * Wait for job to finish.
7240 * Under job control we have the problem that while a child process is
7241 * running interrupts generated by the user are sent to the child but not
7242 * to the shell. This means that an infinite loop started by an inter-
7243 * active user may be hard to kill. With job control turned off, an
7244 * interactive user may place an interactive program inside a loop. If
7245 * the interactive program catches interrupts, the user doesn't want
7246 * these interrupts to also abort the loop. The approach we take here
7247 * is to have the shell ignore interrupt signals while waiting for a
7248 * foreground process to terminate, and then send itself an interrupt
7249 * signal if the child process was terminated by an interrupt signal.
7250 * Unfortunately, some programs want to do a bit of cleanup and then
7251 * exit on interrupt; unless these processes terminate themselves by
7252 * sending a signal to themselves (instead of calling exit) they will
7253 * confuse this approach.
7255 * Called with interrupts off.
7259 waitforjob(struct job *jp)
7263 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
7264 while (jp->state == JOBRUNNING) {
7265 dowait(DOWAIT_BLOCK, jp);
7270 xtcsetpgrp(ttyfd, rootpid);
7272 * This is truly gross.
7273 * If we're doing job control, then we did a TIOCSPGRP which
7274 * caused us (the shell) to no longer be in the controlling
7275 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7276 * intuit from the subprocess exit status whether a SIGINT
7277 * occurred, and if so interrupt ourselves. Yuck. - mycroft
7282 if (jp->state == JOBDONE)
7290 * Do a wait system call. If job control is compiled in, we accept
7291 * stopped processes. If block is zero, we return a value of zero
7292 * rather than blocking.
7294 * System V doesn't have a non-blocking wait system call. It does
7295 * have a SIGCLD signal that is sent to a process when one of it's
7296 * children dies. The obvious way to use SIGCLD would be to install
7297 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7298 * was received, and have waitproc bump another counter when it got
7299 * the status of a process. Waitproc would then know that a wait
7300 * system call would not block if the two counters were different.
7301 * This approach doesn't work because if a process has children that
7302 * have not been waited for, System V will send it a SIGCLD when it
7303 * installs a signal handler for SIGCLD. What this means is that when
7304 * a child exits, the shell will be sent SIGCLD signals continuously
7305 * until is runs out of stack space, unless it does a wait call before
7306 * restoring the signal handler. The code below takes advantage of
7307 * this (mis)feature by installing a signal handler for SIGCLD and
7308 * then checking to see whether it was called. If there are any
7309 * children to be waited for, it will be.
7311 * If neither SYSV nor BSD is defined, we don't implement nonblocking
7312 * waits at all. In this case, the user will not be informed when
7313 * a background process until the next time she runs a real program
7314 * (as opposed to running a builtin command or just typing return),
7315 * and the jobs command may give out of date information.
7319 waitproc(int block, int *status)
7329 return wait3(status, flags, (struct rusage *)NULL);
7333 * Wait for a process to terminate.
7337 dowait(int block, struct job *job)
7342 struct job *thisjob;
7345 TRACE(("dowait(%d) called\n", block));
7346 pid = waitproc(block, &status);
7347 TRACE(("wait returns pid %d, status=%d\n", pid, status));
7352 for (jp = curjob; jp; jp = jp->prev_job) {
7353 struct procstat *sp;
7354 struct procstat *spend;
7355 if (jp->state == JOBDONE)
7358 spend = jp->ps + jp->nprocs;
7361 if (sp->pid == pid) {
7362 TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
7363 sp->status = status;
7366 if (sp->status == -1)
7369 if (state == JOBRUNNING)
7371 if (WIFSTOPPED(sp->status)) {
7372 jp->stopstatus = sp->status;
7376 } while (++sp < spend);
7381 if (!WIFSTOPPED(status))
7388 if (state != JOBRUNNING) {
7389 thisjob->changed = 1;
7391 if (thisjob->state != state) {
7392 TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
7393 thisjob->state = state;
7395 if (state == JOBSTOPPED) {
7396 set_curjob(thisjob, CUR_STOPPED);
7405 if (thisjob && thisjob == job) {
7409 len = sprint_status(s, status, 1);
7421 * return 1 if there are stopped jobs, otherwise 0
7434 if (jp && jp->state == JOBSTOPPED) {
7435 out2str("You have stopped jobs.\n");
7445 * Return a string identifying a command (to be printed by the
7450 static char *cmdnextc;
7453 commandtext(union node *n)
7457 STARTSTACKSTR(cmdnextc);
7459 name = stackblock();
7460 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
7461 name, cmdnextc, cmdnextc));
7462 return savestr(name);
7466 cmdtxt(union node *n)
7469 struct nodelist *lp;
7481 lp = n->npipe.cmdlist;
7499 cmdtxt(n->nbinary.ch1);
7515 cmdtxt(n->nif.test);
7518 if (n->nif.elsepart) {
7521 n = n->nif.elsepart;
7537 cmdtxt(n->nbinary.ch1);
7547 cmdputs(n->nfor.var);
7549 cmdlist(n->nfor.args, 1);
7554 cmdputs(n->narg.text);
7558 cmdlist(n->ncmd.args, 1);
7559 cmdlist(n->ncmd.redirect, 0);
7572 cmdputs(n->ncase.expr->narg.text);
7574 for (np = n->ncase.cases; np; np = np->nclist.next) {
7575 cmdtxt(np->nclist.pattern);
7577 cmdtxt(np->nclist.body);
7603 s[0] = n->nfile.fd + '0';
7607 if (n->type == NTOFD || n->type == NFROMFD) {
7608 s[0] = n->ndup.dupfd + '0';
7619 cmdlist(union node *np, int sep)
7621 for (; np; np = np->narg.next) {
7625 if (sep && np->narg.next)
7631 cmdputs(const char *s)
7633 const char *p, *str;
7634 char c, cc[2] = " ";
7638 static const char vstype[VSTYPE + 1][4] = {
7639 "", "}", "-", "+", "?", "=",
7640 "%", "%%", "#", "##"
7642 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
7644 while ((c = *p++) != 0) {
7652 if ((subtype & VSTYPE) == VSLENGTH)
7656 if (!(subtype & VSQUOTE) != !(quoted & 1)) {
7663 str = "\"}" + !(quoted & 1);
7670 case CTLBACKQ+CTLQUOTE:
7673 #ifdef CONFIG_ASH_MATH_SUPPORT
7688 if ((subtype & VSTYPE) != VSNORMAL)
7690 str = vstype[subtype & VSTYPE];
7691 if (subtype & VSNUL)
7700 /* 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 #ifdef CONFIG_ASH_BUILTIN_ECHO
8194 echocmd(int argc, char **argv)
8196 return bb_echo(argc, argv);
8199 /* $NetBSD: memalloc.c,v 1.27 2003/01/22 20:36:04 dsl Exp $ */
8202 * Same for malloc, realloc, but returns an error when out of space.
8206 ckrealloc(pointer p, size_t nbytes)
8208 p = realloc(p, nbytes);
8210 error(bb_msg_memory_exhausted);
8215 ckmalloc(size_t nbytes)
8217 return ckrealloc(NULL, nbytes);
8221 * Make a copy of a string in safe storage.
8225 savestr(const char *s)
8227 char *p = strdup(s);
8229 error(bb_msg_memory_exhausted);
8235 * Parse trees for commands are allocated in lifo order, so we use a stack
8236 * to make this more efficient, and also to avoid all sorts of exception
8237 * handling code to handle interrupts in the middle of a parse.
8239 * The size 504 was chosen because the Ultrix malloc handles that size
8245 stalloc(size_t nbytes)
8250 aligned = SHELL_ALIGN(nbytes);
8251 if (aligned > stacknleft) {
8254 struct stack_block *sp;
8256 blocksize = aligned;
8257 if (blocksize < MINSIZE)
8258 blocksize = MINSIZE;
8259 len = sizeof(struct stack_block) - MINSIZE + blocksize;
8260 if (len < blocksize)
8261 error(bb_msg_memory_exhausted);
8265 stacknxt = sp->space;
8266 stacknleft = blocksize;
8267 sstrend = stacknxt + blocksize;
8272 stacknxt += aligned;
8273 stacknleft -= aligned;
8279 stunalloc(pointer p)
8282 if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
8283 write(2, "stunalloc\n", 10);
8287 stacknleft += stacknxt - (char *)p;
8293 setstackmark(struct stackmark *mark)
8295 mark->stackp = stackp;
8296 mark->stacknxt = stacknxt;
8297 mark->stacknleft = stacknleft;
8298 mark->marknext = markp;
8304 popstackmark(struct stackmark *mark)
8306 struct stack_block *sp;
8309 markp = mark->marknext;
8310 while (stackp != mark->stackp) {
8315 stacknxt = mark->stacknxt;
8316 stacknleft = mark->stacknleft;
8317 sstrend = mark->stacknxt + mark->stacknleft;
8323 * When the parser reads in a string, it wants to stick the string on the
8324 * stack and only adjust the stack pointer when it knows how big the
8325 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8326 * of space on top of the stack and stackblocklen returns the length of
8327 * this block. Growstackblock will grow this space by at least one byte,
8328 * possibly moving it (like realloc). Grabstackblock actually allocates the
8329 * part of the block that has been used.
8333 growstackblock(void)
8337 newlen = stacknleft * 2;
8338 if (newlen < stacknleft)
8339 error(bb_msg_memory_exhausted);
8343 if (stacknxt == stackp->space && stackp != &stackbase) {
8344 struct stack_block *oldstackp;
8345 struct stackmark *xmark;
8346 struct stack_block *sp;
8347 struct stack_block *prevstackp;
8353 prevstackp = sp->prev;
8354 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
8355 sp = ckrealloc((pointer)sp, grosslen);
8356 sp->prev = prevstackp;
8358 stacknxt = sp->space;
8359 stacknleft = newlen;
8360 sstrend = sp->space + newlen;
8363 * Stack marks pointing to the start of the old block
8364 * must be relocated to point to the new block
8367 while (xmark != NULL && xmark->stackp == oldstackp) {
8368 xmark->stackp = stackp;
8369 xmark->stacknxt = stacknxt;
8370 xmark->stacknleft = stacknleft;
8371 xmark = xmark->marknext;
8375 char *oldspace = stacknxt;
8376 int oldlen = stacknleft;
8377 char *p = stalloc(newlen);
8379 /* free the space we just allocated */
8380 stacknxt = memcpy(p, oldspace, oldlen);
8381 stacknleft += newlen;
8386 grabstackblock(size_t len)
8388 len = SHELL_ALIGN(len);
8394 * The following routines are somewhat easier to use than the above.
8395 * The user declares a variable of type STACKSTR, which may be declared
8396 * to be a register. The macro STARTSTACKSTR initializes things. Then
8397 * the user uses the macro STPUTC to add characters to the string. In
8398 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8399 * grown as necessary. When the user is done, she can just leave the
8400 * string there and refer to it using stackblock(). Or she can allocate
8401 * the space for it using grabstackstr(). If it is necessary to allow
8402 * someone else to use the stack temporarily and then continue to grow
8403 * the string, the user should use grabstack to allocate the space, and
8404 * then call ungrabstr(p) to return to the previous mode of operation.
8406 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8407 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8408 * is space for at least one character.
8414 size_t len = stackblocksize();
8415 if (herefd >= 0 && len >= 1024) {
8416 bb_full_write(herefd, stackblock(), len);
8417 return stackblock();
8420 return stackblock() + len;
8424 * Called from CHECKSTRSPACE.
8428 makestrspace(size_t newlen, char *p)
8430 size_t len = p - stacknxt;
8431 size_t size = stackblocksize();
8436 size = stackblocksize();
8438 if (nleft >= newlen)
8442 return stackblock() + len;
8446 stnputs(const char *s, size_t n, char *p)
8448 p = makestrspace(n, p);
8449 p = mempcpy(p, s, n);
8454 stputs(const char *s, char *p)
8456 return stnputs(s, strlen(s), p);
8459 /* $NetBSD: mystring.c,v 1.15 2002/11/24 22:35:42 christos Exp $ */
8464 * number(s) Convert a string of digits to an integer.
8465 * is_number(s) Return true if s is a string of digits.
8469 * prefix -- see if pfx is a prefix of string.
8473 prefix(const char *string, const char *pfx)
8476 if (*pfx++ != *string++)
8479 return (char *) string;
8484 * Convert a string of digits to an integer, printing an error message on
8489 number(const char *s)
8499 * Check for a valid number. This should be elsewhere.
8503 is_number(const char *p)
8508 } while (*++p != '\0');
8514 * Produce a possibly single quoted string suitable as input to the shell.
8515 * The return string is allocated on the stack.
8519 single_quote(const char *s) {
8528 len = strchrnul(s, '\'') - s;
8530 q = p = makestrspace(len + 3, p);
8533 q = mempcpy(q, s, len);
8539 len = strspn(s, "'");
8543 q = p = makestrspace(len + 3, p);
8546 q = mempcpy(q, s, len);
8555 return stackblock();
8559 * Like strdup but works with the ash stack.
8563 sstrdup(const char *p)
8565 size_t len = strlen(p) + 1;
8566 return memcpy(stalloc(len), p, len);
8571 calcsize(union node *n)
8575 funcblocksize += nodesize[n->type];
8578 calcsize(n->ncmd.redirect);
8579 calcsize(n->ncmd.args);
8580 calcsize(n->ncmd.assign);
8583 sizenodelist(n->npipe.cmdlist);
8588 calcsize(n->nredir.redirect);
8589 calcsize(n->nredir.n);
8596 calcsize(n->nbinary.ch2);
8597 calcsize(n->nbinary.ch1);
8600 calcsize(n->nif.elsepart);
8601 calcsize(n->nif.ifpart);
8602 calcsize(n->nif.test);
8605 funcstringsize += strlen(n->nfor.var) + 1;
8606 calcsize(n->nfor.body);
8607 calcsize(n->nfor.args);
8610 calcsize(n->ncase.cases);
8611 calcsize(n->ncase.expr);
8614 calcsize(n->nclist.body);
8615 calcsize(n->nclist.pattern);
8616 calcsize(n->nclist.next);
8620 sizenodelist(n->narg.backquote);
8621 funcstringsize += strlen(n->narg.text) + 1;
8622 calcsize(n->narg.next);
8629 calcsize(n->nfile.fname);
8630 calcsize(n->nfile.next);
8634 calcsize(n->ndup.vname);
8635 calcsize(n->ndup.next);
8639 calcsize(n->nhere.doc);
8640 calcsize(n->nhere.next);
8643 calcsize(n->nnot.com);
8650 sizenodelist(struct nodelist *lp)
8653 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8661 copynode(union node *n)
8668 funcblock = (char *) funcblock + nodesize[n->type];
8671 new->ncmd.redirect = copynode(n->ncmd.redirect);
8672 new->ncmd.args = copynode(n->ncmd.args);
8673 new->ncmd.assign = copynode(n->ncmd.assign);
8676 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8677 new->npipe.backgnd = n->npipe.backgnd;
8682 new->nredir.redirect = copynode(n->nredir.redirect);
8683 new->nredir.n = copynode(n->nredir.n);
8690 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8691 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8694 new->nif.elsepart = copynode(n->nif.elsepart);
8695 new->nif.ifpart = copynode(n->nif.ifpart);
8696 new->nif.test = copynode(n->nif.test);
8699 new->nfor.var = nodesavestr(n->nfor.var);
8700 new->nfor.body = copynode(n->nfor.body);
8701 new->nfor.args = copynode(n->nfor.args);
8704 new->ncase.cases = copynode(n->ncase.cases);
8705 new->ncase.expr = copynode(n->ncase.expr);
8708 new->nclist.body = copynode(n->nclist.body);
8709 new->nclist.pattern = copynode(n->nclist.pattern);
8710 new->nclist.next = copynode(n->nclist.next);
8714 new->narg.backquote = copynodelist(n->narg.backquote);
8715 new->narg.text = nodesavestr(n->narg.text);
8716 new->narg.next = copynode(n->narg.next);
8723 new->nfile.fname = copynode(n->nfile.fname);
8724 new->nfile.fd = n->nfile.fd;
8725 new->nfile.next = copynode(n->nfile.next);
8729 new->ndup.vname = copynode(n->ndup.vname);
8730 new->ndup.dupfd = n->ndup.dupfd;
8731 new->ndup.fd = n->ndup.fd;
8732 new->ndup.next = copynode(n->ndup.next);
8736 new->nhere.doc = copynode(n->nhere.doc);
8737 new->nhere.fd = n->nhere.fd;
8738 new->nhere.next = copynode(n->nhere.next);
8741 new->nnot.com = copynode(n->nnot.com);
8744 new->type = n->type;
8749 static struct nodelist *
8750 copynodelist(struct nodelist *lp)
8752 struct nodelist *start;
8753 struct nodelist **lpp;
8758 funcblock = (char *) funcblock +
8759 SHELL_ALIGN(sizeof(struct nodelist));
8760 (*lpp)->n = copynode(lp->n);
8762 lpp = &(*lpp)->next;
8770 nodesavestr(char *s)
8772 char *rtn = funcstring;
8774 funcstring = stpcpy(funcstring, s) + 1;
8780 * Free a parse tree.
8784 freefunc(struct funcnode *f)
8786 if (f && --f->count < 0)
8791 static void options(int);
8792 static void setoption(int, int);
8796 * Process the shell command line arguments.
8800 procargs(int argc, char **argv)
8803 const char *xminusc;
8810 for (i = 0; i < NOPTS; i++)
8816 if (*xargv == NULL) {
8818 error("-c requires an argument");
8821 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8825 for (i = 0; i < NOPTS; i++)
8826 if (optlist[i] == 2)
8831 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8836 } else if (!sflag) {
8837 setinputfile(*xargv, 0);
8843 shellparam.p = xargv;
8844 #ifdef CONFIG_ASH_GETOPTS
8845 shellparam.optind = 1;
8846 shellparam.optoff = -1;
8848 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
8850 shellparam.nparam++;
8863 setinteractive(iflag);
8869 minus_o(char *name, int val)
8874 out1str("Current option settings\n");
8875 for (i = 0; i < NOPTS; i++)
8876 out1fmt("%-16s%s\n", optnames(i),
8877 optlist[i] ? "on" : "off");
8879 for (i = 0; i < NOPTS; i++)
8880 if (equal(name, optnames(i))) {
8884 error("Illegal option -o %s", name);
8889 * Process shell options. The global variable argptr contains a pointer
8890 * to the argument list; we advance it past the options.
8894 options(int cmdline)
8902 while ((p = *argptr) != NULL) {
8904 if ((c = *p++) == '-') {
8906 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8908 /* "-" means turn off -x and -v */
8911 /* "--" means reset params */
8912 else if (*argptr == NULL)
8915 break; /* "-" or "--" terminates options */
8917 } else if (c == '+') {
8923 while ((c = *p++) != '\0') {
8924 if (c == 'c' && cmdline) {
8925 minusc = p; /* command is after shell args*/
8926 } else if (c == 'o') {
8927 minus_o(*argptr, val);
8930 } else if (cmdline && (c == '-')) { // long options
8931 if (strcmp(p, "login") == 0)
8943 setoption(int flag, int val)
8947 for (i = 0; i < NOPTS; i++)
8948 if (optletters(i) == flag) {
8952 error("Illegal option -%c", flag);
8959 * Set the shell parameters.
8963 setparam(char **argv)
8969 for (nparam = 0 ; argv[nparam] ; nparam++);
8970 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
8972 *ap++ = savestr(*argv++);
8975 freeparam(&shellparam);
8976 shellparam.malloc = 1;
8977 shellparam.nparam = nparam;
8978 shellparam.p = newparam;
8979 #ifdef CONFIG_ASH_GETOPTS
8980 shellparam.optind = 1;
8981 shellparam.optoff = -1;
8987 * Free the list of positional parameters.
8991 freeparam(volatile struct shparam *param)
8995 if (param->malloc) {
8996 for (ap = param->p ; *ap ; ap++)
9005 * The shift builtin command.
9009 shiftcmd(int argc, char **argv)
9016 n = number(argv[1]);
9017 if (n > shellparam.nparam)
9018 error("can't shift that many");
9020 shellparam.nparam -= n;
9021 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
9022 if (shellparam.malloc)
9026 while ((*ap2++ = *ap1++) != NULL);
9027 #ifdef CONFIG_ASH_GETOPTS
9028 shellparam.optind = 1;
9029 shellparam.optoff = -1;
9038 * The set command builtin.
9042 setcmd(int argc, char **argv)
9045 return showvars(nullstr, 0, VUNSET);
9049 if (*argptr != NULL) {
9057 #ifdef CONFIG_ASH_GETOPTS
9062 shellparam.optind = number(value);
9063 shellparam.optoff = -1;
9067 #ifdef CONFIG_LOCALE_SUPPORT
9068 static void change_lc_all(const char *value)
9070 if (value != 0 && *value != 0)
9071 setlocale(LC_ALL, value);
9074 static void change_lc_ctype(const char *value)
9076 if (value != 0 && *value != 0)
9077 setlocale(LC_CTYPE, value);
9082 #ifdef CONFIG_ASH_RANDOM_SUPPORT
9083 /* Roughly copied from bash.. */
9084 static void change_random(const char *value)
9087 /* "get", generate */
9090 rseed = rseed * 1103515245 + 12345;
9091 sprintf(buf, "%d", (unsigned int)((rseed & 32767)));
9092 /* set without recursion */
9093 setvar(vrandom.text, buf, VNOFUNC);
9094 vrandom.flags &= ~VNOFUNC;
9097 rseed = strtoul(value, (char **)NULL, 10);
9103 #ifdef CONFIG_ASH_GETOPTS
9105 getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
9114 if(*param_optind < 1)
9116 optnext = optfirst + *param_optind - 1;
9118 if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff)
9121 p = optnext[-1] + *optoff;
9122 if (p == NULL || *p == '\0') {
9123 /* Current word is done, advance */
9125 if (p == NULL || *p != '-' || *++p == '\0') {
9132 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
9137 for (q = optstr; *q != c; ) {
9139 if (optstr[0] == ':') {
9142 err |= setvarsafe("OPTARG", s, 0);
9144 fprintf(stderr, "Illegal option -%c\n", c);
9145 (void) unsetvar("OPTARG");
9155 if (*p == '\0' && (p = *optnext) == NULL) {
9156 if (optstr[0] == ':') {
9159 err |= setvarsafe("OPTARG", s, 0);
9162 fprintf(stderr, "No arg for -%c option\n", c);
9163 (void) unsetvar("OPTARG");
9171 err |= setvarsafe("OPTARG", p, 0);
9174 err |= setvarsafe("OPTARG", nullstr, 0);
9177 *optoff = p ? p - *(optnext - 1) : -1;
9178 *param_optind = optnext - optfirst + 1;
9179 fmtstr(s, sizeof(s), "%d", *param_optind);
9180 err |= setvarsafe("OPTIND", s, VNOFUNC);
9183 err |= setvarsafe(optvar, s, 0);
9194 * The getopts builtin. Shellparam.optnext points to the next argument
9195 * to be processed. Shellparam.optptr points to the next character to
9196 * be processed in the current argument. If shellparam.optnext is NULL,
9197 * then it's the first time getopts has been called.
9201 getoptscmd(int argc, char **argv)
9206 error("Usage: getopts optstring var [arg]");
9207 else if (argc == 3) {
9208 optbase = shellparam.p;
9209 if (shellparam.optind > shellparam.nparam + 1) {
9210 shellparam.optind = 1;
9211 shellparam.optoff = -1;
9216 if (shellparam.optind > argc - 2) {
9217 shellparam.optind = 1;
9218 shellparam.optoff = -1;
9222 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9223 &shellparam.optoff);
9225 #endif /* CONFIG_ASH_GETOPTS */
9228 * XXX - should get rid of. have all builtins use getopt(3). the
9229 * library getopt must have the BSD extension static variable "optreset"
9230 * otherwise it can't be used within the shell safely.
9232 * Standard option processing (a la getopt) for builtin routines. The
9233 * only argument that is passed to nextopt is the option string; the
9234 * other arguments are unnecessary. It return the character, or '\0' on
9239 nextopt(const char *optstring)
9245 if ((p = optptr) == NULL || *p == '\0') {
9247 if (p == NULL || *p != '-' || *++p == '\0')
9250 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
9254 for (q = optstring ; *q != c ; ) {
9256 error("Illegal option -%c", c);
9261 if (*p == '\0' && (p = *argptr++) == NULL)
9262 error("No arg for -%c option", c);
9271 /* $NetBSD: output.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
9274 outstr(const char *p, FILE *file)
9299 outcslow(int c, FILE *dest)
9309 out1fmt(const char *fmt, ...)
9316 r = vprintf(fmt, ap);
9324 fmtstr(char *outbuf, size_t length, const char *fmt, ...)
9331 ret = vsnprintf(outbuf, length, fmt, ap);
9339 /* $NetBSD: parser.c,v 1.54 2002/11/24 22:35:42 christos Exp $ */
9343 * Shell command parser.
9346 #define EOFMARKLEN 79
9350 struct heredoc *next; /* next here document in list */
9351 union node *here; /* redirection node */
9352 char *eofmark; /* string indicating end of input */
9353 int striptabs; /* if set, strip leading tabs */
9358 static struct heredoc *heredoclist; /* list of here documents to read */
9361 static union node *list(int);
9362 static union node *andor(void);
9363 static union node *pipeline(void);
9364 static union node *command(void);
9365 static union node *simplecmd(void);
9366 static union node *makename(void);
9367 static void parsefname(void);
9368 static void parseheredoc(void);
9369 static char peektoken(void);
9370 static int readtoken(void);
9371 static int xxreadtoken(void);
9372 static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
9373 static int noexpand(char *);
9374 static void synexpect(int) __attribute__((__noreturn__));
9375 static void synerror(const char *) __attribute__((__noreturn__));
9376 static void setprompt(int);
9382 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9383 * valid parse tree indicating a blank line.)
9387 parsecmd(int interact)
9392 doprompt = interact;
9394 setprompt(doprompt);
9409 union node *n1, *n2, *n3;
9412 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9413 if (nlflag == 2 && peektoken())
9419 if (tok == TBACKGND) {
9420 if (n2->type == NPIPE) {
9421 n2->npipe.backgnd = 1;
9423 if (n2->type != NREDIR) {
9424 n3 = stalloc(sizeof(struct nredir));
9426 n3->nredir.redirect = NULL;
9429 n2->type = NBACKGND;
9436 n3 = (union node *)stalloc(sizeof (struct nbinary));
9438 n3->nbinary.ch1 = n1;
9439 n3->nbinary.ch2 = n2;
9455 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9463 pungetc(); /* push back EOF on input */
9479 union node *n1, *n2, *n3;
9484 if ((t = readtoken()) == TAND) {
9486 } else if (t == TOR) {
9492 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9494 n3 = (union node *)stalloc(sizeof (struct nbinary));
9496 n3->nbinary.ch1 = n1;
9497 n3->nbinary.ch2 = n2;
9507 union node *n1, *n2, *pipenode;
9508 struct nodelist *lp, *prev;
9512 TRACE(("pipeline: entered\n"));
9513 if (readtoken() == TNOT) {
9515 checkkwd = CHKKWD | CHKALIAS;
9519 if (readtoken() == TPIPE) {
9520 pipenode = (union node *)stalloc(sizeof (struct npipe));
9521 pipenode->type = NPIPE;
9522 pipenode->npipe.backgnd = 0;
9523 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9524 pipenode->npipe.cmdlist = lp;
9528 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9529 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9532 } while (readtoken() == TPIPE);
9538 n2 = (union node *)stalloc(sizeof (struct nnot));
9551 union node *n1, *n2;
9552 union node *ap, **app;
9553 union node *cp, **cpp;
9554 union node *redir, **rpp;
9561 switch (readtoken()) {
9566 n1 = (union node *)stalloc(sizeof (struct nif));
9568 n1->nif.test = list(0);
9569 if (readtoken() != TTHEN)
9571 n1->nif.ifpart = list(0);
9573 while (readtoken() == TELIF) {
9574 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
9575 n2 = n2->nif.elsepart;
9577 n2->nif.test = list(0);
9578 if (readtoken() != TTHEN)
9580 n2->nif.ifpart = list(0);
9582 if (lasttoken == TELSE)
9583 n2->nif.elsepart = list(0);
9585 n2->nif.elsepart = NULL;
9593 n1 = (union node *)stalloc(sizeof (struct nbinary));
9594 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
9595 n1->nbinary.ch1 = list(0);
9596 if ((got=readtoken()) != TDO) {
9597 TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
9600 n1->nbinary.ch2 = list(0);
9605 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9606 synerror("Bad for loop variable");
9607 n1 = (union node *)stalloc(sizeof (struct nfor));
9609 n1->nfor.var = wordtext;
9610 checkkwd = CHKKWD | CHKALIAS;
9611 if (readtoken() == TIN) {
9613 while (readtoken() == TWORD) {
9614 n2 = (union node *)stalloc(sizeof (struct narg));
9616 n2->narg.text = wordtext;
9617 n2->narg.backquote = backquotelist;
9619 app = &n2->narg.next;
9623 if (lasttoken != TNL && lasttoken != TSEMI)
9626 n2 = (union node *)stalloc(sizeof (struct narg));
9628 n2->narg.text = (char *)dolatstr;
9629 n2->narg.backquote = NULL;
9630 n2->narg.next = NULL;
9633 * Newline or semicolon here is optional (but note
9634 * that the original Bourne shell only allowed NL).
9636 if (lasttoken != TNL && lasttoken != TSEMI)
9639 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9640 if (readtoken() != TDO)
9642 n1->nfor.body = list(0);
9646 n1 = (union node *)stalloc(sizeof (struct ncase));
9648 if (readtoken() != TWORD)
9650 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
9652 n2->narg.text = wordtext;
9653 n2->narg.backquote = backquotelist;
9654 n2->narg.next = NULL;
9656 checkkwd = CHKKWD | CHKALIAS;
9657 } while (readtoken() == TNL);
9658 if (lasttoken != TIN)
9660 cpp = &n1->ncase.cases;
9662 checkkwd = CHKNL | CHKKWD;
9665 if (lasttoken == TLP)
9667 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
9669 app = &cp->nclist.pattern;
9671 *app = ap = (union node *)stalloc(sizeof (struct narg));
9673 ap->narg.text = wordtext;
9674 ap->narg.backquote = backquotelist;
9675 if (readtoken() != TPIPE)
9677 app = &ap->narg.next;
9680 ap->narg.next = NULL;
9681 if (lasttoken != TRP)
9683 cp->nclist.body = list(2);
9685 cpp = &cp->nclist.next;
9687 checkkwd = CHKNL | CHKKWD;
9688 if ((t = readtoken()) != TESAC) {
9690 synexpect(TENDCASE);
9698 n1 = (union node *)stalloc(sizeof (struct nredir));
9699 n1->type = NSUBSHELL;
9700 n1->nredir.n = list(0);
9701 n1->nredir.redirect = NULL;
9714 if (readtoken() != t)
9718 /* Now check for redirection which may follow command */
9719 checkkwd = CHKKWD | CHKALIAS;
9721 while (readtoken() == TREDIR) {
9722 *rpp = n2 = redirnode;
9723 rpp = &n2->nfile.next;
9729 if (n1->type != NSUBSHELL) {
9730 n2 = (union node *)stalloc(sizeof (struct nredir));
9735 n1->nredir.redirect = redir;
9744 union node *args, **app;
9745 union node *n = NULL;
9746 union node *vars, **vpp;
9747 union node **rpp, *redir;
9757 savecheckkwd = CHKALIAS;
9759 checkkwd = savecheckkwd;
9760 switch (readtoken()) {
9762 n = (union node *)stalloc(sizeof (struct narg));
9764 n->narg.text = wordtext;
9765 n->narg.backquote = backquotelist;
9766 if (savecheckkwd && isassignment(wordtext)) {
9768 vpp = &n->narg.next;
9771 app = &n->narg.next;
9776 *rpp = n = redirnode;
9777 rpp = &n->nfile.next;
9778 parsefname(); /* read name of redirection file */
9782 args && app == &args->narg.next &&
9785 struct builtincmd *bcmd;
9788 /* We have a function */
9789 if (readtoken() != TRP)
9791 name = n->narg.text;
9793 !goodname(name) || (
9794 (bcmd = find_builtin(name)) &&
9795 IS_BUILTIN_SPECIAL(bcmd)
9798 synerror("Bad function name");
9800 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9801 n->narg.next = command();
9814 n = (union node *)stalloc(sizeof (struct ncmd));
9816 n->ncmd.args = args;
9817 n->ncmd.assign = vars;
9818 n->ncmd.redirect = redir;
9827 n = (union node *)stalloc(sizeof (struct narg));
9829 n->narg.next = NULL;
9830 n->narg.text = wordtext;
9831 n->narg.backquote = backquotelist;
9835 void fixredir(union node *n, const char *text, int err)
9837 TRACE(("Fix redir %s %d\n", text, err));
9839 n->ndup.vname = NULL;
9841 if (is_digit(text[0]) && text[1] == '\0')
9842 n->ndup.dupfd = digit_val(text[0]);
9843 else if (text[0] == '-' && text[1] == '\0')
9848 synerror("Bad fd number");
9850 n->ndup.vname = makename();
9858 union node *n = redirnode;
9860 if (readtoken() != TWORD)
9862 if (n->type == NHERE) {
9863 struct heredoc *here = heredoc;
9869 TRACE(("Here document %d\n", n->type));
9870 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
9871 synerror("Illegal eof marker for << redirection");
9872 rmescapes(wordtext);
9873 here->eofmark = wordtext;
9875 if (heredoclist == NULL)
9878 for (p = heredoclist ; p->next ; p = p->next);
9881 } else if (n->type == NTOFD || n->type == NFROMFD) {
9882 fixredir(n, wordtext, 0);
9884 n->nfile.fname = makename();
9890 * Input any here documents.
9896 struct heredoc *here;
9906 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9907 here->eofmark, here->striptabs);
9908 n = (union node *)stalloc(sizeof (struct narg));
9909 n->narg.type = NARG;
9910 n->narg.next = NULL;
9911 n->narg.text = wordtext;
9912 n->narg.backquote = backquotelist;
9913 here->here->nhere.doc = n;
9918 static char peektoken(void)
9924 return tokname_array[t][0];
9932 int alreadyseen = tokpushback;
9935 #ifdef CONFIG_ASH_ALIAS
9944 if (checkkwd & CHKNL) {
9951 if (t != TWORD || quoteflag) {
9956 * check for keywords
9958 if (checkkwd & CHKKWD) {
9959 const char *const *pp;
9961 if ((pp = findkwd(wordtext))) {
9962 lasttoken = t = pp - tokname_array;
9963 TRACE(("keyword %s recognized\n", tokname(t)));
9968 if (checkkwd & CHKALIAS) {
9969 #ifdef CONFIG_ASH_ALIAS
9971 if ((ap = lookupalias(wordtext, 1)) != NULL) {
9973 pushstring(ap->val, ap);
9983 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
9985 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
9992 * Read the next input token.
9993 * If the token is a word, we set backquotelist to the list of cmds in
9994 * backquotes. We set quoteflag to true if any part of the word was
9996 * If the token is TREDIR, then we set redirnode to a structure containing
9998 * In all cases, the variable startlinno is set to the number of the line
9999 * on which the token starts.
10001 * [Change comment: here documents and internal procedures]
10002 * [Readtoken shouldn't have any arguments. Perhaps we should make the
10003 * word parsing code into a separate routine. In this case, readtoken
10004 * doesn't need to have any internal procedures, but parseword does.
10005 * We could also make parseoperator in essence the main routine, and
10006 * have parseword (readtoken1?) handle both words and redirection.]
10009 #define NEW_xxreadtoken
10010 #ifdef NEW_xxreadtoken
10012 /* singles must be first! */
10013 static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
10015 static const char xxreadtoken_tokens[] = {
10016 TNL, TLP, TRP, /* only single occurrence allowed */
10017 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
10018 TEOF, /* corresponds to trailing nul */
10019 TAND, TOR, TENDCASE, /* if double occurrence */
10022 #define xxreadtoken_doubles \
10023 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
10024 #define xxreadtoken_singles \
10025 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
10027 static int xxreadtoken()
10038 startlinno = plinno;
10039 for (;;) { /* until token or start of word found */
10042 if ((c != ' ') && (c != '\t')
10043 #ifdef CONFIG_ASH_ALIAS
10048 while ((c = pgetc()) != '\n' && c != PEOF);
10050 } else if (c == '\\') {
10051 if (pgetc() != '\n') {
10055 startlinno = ++plinno;
10060 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10065 needprompt = doprompt;
10068 p = strchr(xxreadtoken_chars, c);
10071 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
10074 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
10075 if (pgetc() == *p) { /* double occurrence? */
10076 p += xxreadtoken_doubles + 1;
10083 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
10091 #define RETURN(token) return lasttoken = token
10105 startlinno = plinno;
10106 for (;;) { /* until token or start of word found */
10109 case ' ': case '\t':
10110 #ifdef CONFIG_ASH_ALIAS
10115 while ((c = pgetc()) != '\n' && c != PEOF);
10119 if (pgetc() == '\n') {
10120 startlinno = ++plinno;
10129 needprompt = doprompt;
10134 if (pgetc() == '&')
10139 if (pgetc() == '|')
10144 if (pgetc() == ';')
10157 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10160 #endif /* NEW_xxreadtoken */
10164 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10165 * is not NULL, read a here document. In the latter case, eofmark is the
10166 * word which marks the end of the document and striptabs is true if
10167 * leading tabs should be stripped from the document. The argument firstc
10168 * is the first character of the input token or document.
10170 * Because C does not have internal subroutines, I have simulated them
10171 * using goto's to implement the subroutine linkage. The following macros
10172 * will run code that appears at the end of readtoken1.
10175 #define CHECKEND() {goto checkend; checkend_return:;}
10176 #define PARSEREDIR() {goto parseredir; parseredir_return:;}
10177 #define PARSESUB() {goto parsesub; parsesub_return:;}
10178 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10179 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10180 #define PARSEARITH() {goto parsearith; parsearith_return:;}
10183 readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
10188 char line[EOFMARKLEN + 1];
10189 struct nodelist *bqlist;
10192 int varnest; /* levels of variables expansion */
10193 int arinest; /* levels of arithmetic expansion */
10194 int parenlevel; /* levels of parens in arithmetic */
10195 int dqvarnest; /* levels of variables expansion within double quotes */
10197 int prevsyntax; /* syntax before arithmetic */
10199 /* Avoid longjmp clobbering */
10205 (void) &parenlevel;
10208 (void) &prevsyntax;
10212 startlinno = plinno;
10214 if (syntax == DQSYNTAX)
10223 STARTSTACKSTR(out);
10224 loop: { /* for each line, until end of word */
10225 CHECKEND(); /* set c to PEOF if at end of here document */
10226 for (;;) { /* until end of line or end of word */
10227 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10228 switch(SIT(c, syntax)) {
10229 case CNL: /* '\n' */
10230 if (syntax == BASESYNTAX)
10231 goto endword; /* exit outer loop */
10237 goto loop; /* continue outer loop */
10242 if (eofmark == NULL || dblquote)
10243 USTPUTC(CTLESC, out);
10246 case CBACK: /* backslash */
10249 USTPUTC(CTLESC, out);
10250 USTPUTC('\\', out);
10252 } else if (c == '\n') {
10258 c != '\\' && c != '`' &&
10264 USTPUTC(CTLESC, out);
10265 USTPUTC('\\', out);
10267 if (SIT(c, SQSYNTAX) == CCTL)
10268 USTPUTC(CTLESC, out);
10276 if (eofmark == NULL) {
10277 USTPUTC(CTLQUOTEMARK, out);
10285 if (eofmark != NULL && arinest == 0 &&
10289 if (dqvarnest == 0) {
10290 syntax = BASESYNTAX;
10297 case CVAR: /* '$' */
10298 PARSESUB(); /* parse substitution */
10300 case CENDVAR: /* '}' */
10303 if (dqvarnest > 0) {
10306 USTPUTC(CTLENDVAR, out);
10311 #ifdef CONFIG_ASH_MATH_SUPPORT
10312 case CLP: /* '(' in arithmetic */
10316 case CRP: /* ')' in arithmetic */
10317 if (parenlevel > 0) {
10321 if (pgetc() == ')') {
10322 if (--arinest == 0) {
10323 USTPUTC(CTLENDARI, out);
10324 syntax = prevsyntax;
10325 if (syntax == DQSYNTAX)
10333 * unbalanced parens
10334 * (don't 2nd guess - no error)
10342 case CBQUOTE: /* '`' */
10346 goto endword; /* exit outer loop */
10351 goto endword; /* exit outer loop */
10352 #ifdef CONFIG_ASH_ALIAS
10362 #ifdef CONFIG_ASH_MATH_SUPPORT
10363 if (syntax == ARISYNTAX)
10364 synerror("Missing '))'");
10366 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10367 synerror("Unterminated quoted string");
10368 if (varnest != 0) {
10369 startlinno = plinno;
10371 synerror("Missing '}'");
10373 USTPUTC('\0', out);
10374 len = out - (char *)stackblock();
10375 out = stackblock();
10376 if (eofmark == NULL) {
10377 if ((c == '>' || c == '<')
10380 && (*out == '\0' || is_digit(*out))) {
10382 return lasttoken = TREDIR;
10387 quoteflag = quotef;
10388 backquotelist = bqlist;
10389 grabstackblock(len);
10391 return lasttoken = TWORD;
10392 /* end of readtoken routine */
10397 * Check to see whether we are at the end of the here document. When this
10398 * is called, c is set to the first character of the next input line. If
10399 * we are at the end of the here document, this routine sets the c to PEOF.
10404 #ifdef CONFIG_ASH_ALIAS
10410 while (c == '\t') {
10414 if (c == *eofmark) {
10415 if (pfgets(line, sizeof line) != NULL) {
10419 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10420 if (*p == '\n' && *q == '\0') {
10423 needprompt = doprompt;
10425 pushstring(line, NULL);
10430 goto checkend_return;
10435 * Parse a redirection operator. The variable "out" points to a string
10436 * specifying the fd to be redirected. The variable "c" contains the
10437 * first character of the redirection operator.
10444 np = (union node *)stalloc(sizeof (struct nfile));
10449 np->type = NAPPEND;
10451 np->type = NCLOBBER;
10458 } else { /* c == '<' */
10460 switch (c = pgetc()) {
10462 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10463 np = (union node *)stalloc(sizeof (struct nhere));
10467 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10468 heredoc->here = np;
10469 if ((c = pgetc()) == '-') {
10470 heredoc->striptabs = 1;
10472 heredoc->striptabs = 0;
10478 np->type = NFROMFD;
10482 np->type = NFROMTO;
10492 np->nfile.fd = digit_val(fd);
10494 goto parseredir_return;
10499 * Parse a substitution. At this point, we have read the dollar sign
10500 * and nothing else.
10508 static const char types[] = "}-+?=";
10512 c <= PEOA_OR_PEOF ||
10513 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10517 } else if (c == '(') { /* $(command) or $((arith)) */
10518 if (pgetc() == '(') {
10519 #ifdef CONFIG_ASH_MATH_SUPPORT
10522 synerror("We unsupport $((arith))");
10529 USTPUTC(CTLVAR, out);
10530 typeloc = out - (char *)stackblock();
10531 USTPUTC(VSNORMAL, out);
10532 subtype = VSNORMAL;
10536 if ((c = pgetc()) == '}')
10539 subtype = VSLENGTH;
10544 if (c > PEOA_OR_PEOF && is_name(c)) {
10548 } while (c > PEOA_OR_PEOF && is_in_name(c));
10549 } else if (is_digit(c)) {
10553 } while (is_digit(c));
10555 else if (is_special(c)) {
10560 badsub: synerror("Bad substitution");
10564 if (subtype == 0) {
10571 p = strchr(types, c);
10574 subtype = p - types + VSNORMAL;
10580 subtype = c == '#' ? VSTRIMLEFT :
10593 if (dblquote || arinest)
10595 *((char *)stackblock() + typeloc) = subtype | flags;
10596 if (subtype != VSNORMAL) {
10598 if (dblquote || arinest) {
10603 goto parsesub_return;
10608 * Called to parse command substitutions. Newstyle is set if the command
10609 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10610 * list of commands (passed by reference), and savelen is the number of
10611 * characters on the top of the stack which must be preserved.
10615 struct nodelist **nlpp;
10618 char *volatile str;
10619 struct jmploc jmploc;
10620 struct jmploc *volatile savehandler;
10624 (void) &saveprompt;
10627 savepbq = parsebackquote;
10628 if (setjmp(jmploc.loc)) {
10631 parsebackquote = 0;
10632 handler = savehandler;
10633 longjmp(handler->loc, 1);
10637 savelen = out - (char *)stackblock();
10639 str = ckmalloc(savelen);
10640 memcpy(str, stackblock(), savelen);
10642 savehandler = handler;
10646 /* We must read until the closing backquote, giving special
10647 treatment to some slashes, and then push the string and
10648 reread it as input, interpreting it normally. */
10655 STARTSTACKSTR(pout);
10660 switch (pc = pgetc()) {
10665 if ((pc = pgetc()) == '\n') {
10670 * If eating a newline, avoid putting
10671 * the newline into the new character
10672 * stream (via the STPUTC after the
10677 if (pc != '\\' && pc != '`' && pc != '$'
10678 && (!dblquote || pc != '"'))
10679 STPUTC('\\', pout);
10680 if (pc > PEOA_OR_PEOF) {
10686 #ifdef CONFIG_ASH_ALIAS
10689 startlinno = plinno;
10690 synerror("EOF in backquote substitution");
10694 needprompt = doprompt;
10703 STPUTC('\0', pout);
10704 psavelen = pout - (char *)stackblock();
10705 if (psavelen > 0) {
10706 pstr = grabstackstr(pout);
10707 setinputstring(pstr);
10712 nlpp = &(*nlpp)->next;
10713 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10714 (*nlpp)->next = NULL;
10715 parsebackquote = oldstyle;
10718 saveprompt = doprompt;
10725 doprompt = saveprompt;
10727 if (readtoken() != TRP)
10734 * Start reading from old file again, ignoring any pushed back
10735 * tokens left from the backquote parsing
10740 while (stackblocksize() <= savelen)
10742 STARTSTACKSTR(out);
10744 memcpy(out, str, savelen);
10745 STADJUST(savelen, out);
10751 parsebackquote = savepbq;
10752 handler = savehandler;
10753 if (arinest || dblquote)
10754 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10756 USTPUTC(CTLBACKQ, out);
10758 goto parsebackq_oldreturn;
10760 goto parsebackq_newreturn;
10763 #ifdef CONFIG_ASH_MATH_SUPPORT
10765 * Parse an arithmetic expansion (indicate start of one and set state)
10769 if (++arinest == 1) {
10770 prevsyntax = syntax;
10771 syntax = ARISYNTAX;
10772 USTPUTC(CTLARI, out);
10779 * we collapse embedded arithmetic expansion to
10780 * parenthesis, which should be equivalent
10784 goto parsearith_return;
10788 } /* end of readtoken */
10793 * Returns true if the text contains nothing to expand (no dollar signs
10798 noexpand(char *text)
10804 while ((c = *p++) != '\0') {
10805 if (c == CTLQUOTEMARK)
10809 else if (SIT(c, BASESYNTAX) == CCTL)
10817 * Return of a legal variable name (a letter or underscore followed by zero or
10818 * more letters, underscores, and digits).
10822 endofname(const char *name)
10830 if (! is_in_name(*p))
10838 * Called when an unexpected token is read during the parse. The argument
10839 * is the token that is expected, or -1 if more than one type of token can
10840 * occur at this point.
10843 static void synexpect(int token)
10848 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10850 sprintf(msg + l, " (expecting %s)", tokname(token));
10856 synerror(const char *msg)
10858 error("Syntax error: %s", msg);
10864 * called by editline -- any expansions to the prompt
10865 * should be added here.
10868 #ifdef CONFIG_ASH_EXPAND_PRMT
10869 static const char *
10870 expandstr(const char *ps)
10874 /* XXX Fix (char *) cast. */
10875 setinputstring((char *)ps);
10876 readtoken1(pgetc(), DQSYNTAX, nullstr, 0);
10879 n.narg.type = NARG;
10880 n.narg.next = NULL;
10881 n.narg.text = wordtext;
10882 n.narg.backquote = backquotelist;
10884 expandarg(&n, NULL, 0);
10885 return stackblock();
10889 static void setprompt(int whichprompt)
10891 const char *prompt;
10892 #ifdef CONFIG_ASH_EXPAND_PRMT
10893 struct stackmark smark;
10898 switch (whichprompt) {
10908 #ifdef CONFIG_ASH_EXPAND_PRMT
10909 setstackmark(&smark);
10910 stalloc(stackblocksize());
10912 putprompt(expandstr(prompt));
10913 #ifdef CONFIG_ASH_EXPAND_PRMT
10914 popstackmark(&smark);
10919 static const char *const *findkwd(const char *s)
10921 return bsearch(s, tokname_array + KWDOFFSET,
10922 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
10923 sizeof(const char *), pstrcmp);
10926 /* $NetBSD: redir.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
10929 * Code for dealing with input/output redirection.
10932 #define EMPTY -2 /* marks an unused slot in redirtab */
10934 # define PIPESIZE 4096 /* amount of buffering in a pipe */
10936 # define PIPESIZE PIPE_BUF
10940 * Open a file in noclobber mode.
10941 * The code was copied from bash.
10944 noclobberopen(const char *fname)
10947 struct stat finfo, finfo2;
10950 * If the file exists and is a regular file, return an error
10953 r = stat(fname, &finfo);
10954 if (r == 0 && S_ISREG(finfo.st_mode)) {
10960 * If the file was not present (r != 0), make sure we open it
10961 * exclusively so that if it is created before we open it, our open
10962 * will fail. Make sure that we do not truncate an existing file.
10963 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10964 * file was not a regular file, we leave O_EXCL off.
10967 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10968 fd = open(fname, O_WRONLY|O_CREAT, 0666);
10970 /* If the open failed, return the file descriptor right away. */
10975 * OK, the open succeeded, but the file may have been changed from a
10976 * non-regular file to a regular file between the stat and the open.
10977 * We are assuming that the O_EXCL open handles the case where FILENAME
10978 * did not exist and is symlinked to an existing file between the stat
10983 * If we can open it and fstat the file descriptor, and neither check
10984 * revealed that it was a regular file, and the file has not been
10985 * replaced, return the file descriptor.
10987 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10988 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
10991 /* The file has been replaced. badness. */
10998 * Handle here documents. Normally we fork off a process to write the
10999 * data to a pipe. If the document is short, we can stuff the data in
11000 * the pipe without forking.
11004 openhere(union node *redir)
11010 error("Pipe call failed");
11011 if (redir->type == NHERE) {
11012 len = strlen(redir->nhere.doc->narg.text);
11013 if (len <= PIPESIZE) {
11014 bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
11018 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
11020 signal(SIGINT, SIG_IGN);
11021 signal(SIGQUIT, SIG_IGN);
11022 signal(SIGHUP, SIG_IGN);
11024 signal(SIGTSTP, SIG_IGN);
11026 signal(SIGPIPE, SIG_DFL);
11027 if (redir->type == NHERE)
11028 bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
11030 expandhere(redir->nhere.doc, pip[1]);
11039 openredirect(union node *redir)
11044 switch (redir->nfile.type) {
11046 fname = redir->nfile.expfname;
11047 if ((f = open(fname, O_RDONLY)) < 0)
11051 fname = redir->nfile.expfname;
11052 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
11056 /* Take care of noclobber mode. */
11058 fname = redir->nfile.expfname;
11059 if ((f = noclobberopen(fname)) < 0)
11065 fname = redir->nfile.expfname;
11066 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
11070 fname = redir->nfile.expfname;
11071 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
11078 /* Fall through to eliminate warning. */
11085 f = openhere(redir);
11091 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
11093 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11097 dupredirect(union node *redir, int f)
11099 int fd = redir->nfile.fd;
11101 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11102 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
11103 copyfd(redir->ndup.dupfd, fd);
11116 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11117 * old file descriptors are stashed away so that the redirection can be
11118 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11119 * standard output, and the standard error if it becomes a duplicate of
11120 * stdout, is saved in memory.
11124 redirect(union node *redir, int flags)
11127 struct redirtab *sv;
11138 if (flags & REDIR_PUSH) {
11139 struct redirtab *q;
11140 q = ckmalloc(sizeof (struct redirtab));
11141 q->next = redirlist;
11143 q->nullredirs = nullredirs - 1;
11144 for (i = 0 ; i < 10 ; i++)
11145 q->renamed[i] = EMPTY;
11152 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
11153 n->ndup.dupfd == fd)
11154 continue; /* redirect from/to same file descriptor */
11156 newfd = openredirect(n);
11159 if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
11160 i = fcntl(fd, F_DUPFD, 10);
11167 error("%d: %m", fd);
11177 dupredirect(n, newfd);
11178 } while ((n = n->nfile.next));
11180 if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
11181 preverrout_fd = sv->renamed[2];
11186 * Undo the effects of the last redirection.
11192 struct redirtab *rp;
11195 if (--nullredirs >= 0)
11199 for (i = 0 ; i < 10 ; i++) {
11200 if (rp->renamed[i] != EMPTY) {
11203 copyfd(rp->renamed[i], i);
11205 close(rp->renamed[i]);
11208 redirlist = rp->next;
11209 nullredirs = rp->nullredirs;
11215 * Undo all redirections. Called on error or interrupt.
11219 * Discard all saved file descriptors.
11223 clearredir(int drop)
11235 * Copy a file descriptor to be >= to. Returns -1
11236 * if the source file descriptor is closed, EMPTY if there are no unused
11237 * file descriptors left.
11241 copyfd(int from, int to)
11245 newfd = fcntl(from, F_DUPFD, to);
11247 if (errno == EMFILE)
11250 error("%d: %m", from);
11257 redirectsafe(union node *redir, int flags)
11260 volatile int saveint;
11261 struct jmploc *volatile savehandler = handler;
11262 struct jmploc jmploc;
11265 if (!(err = setjmp(jmploc.loc) * 2)) {
11267 redirect(redir, flags);
11269 handler = savehandler;
11270 if (err && exception != EXERROR)
11271 longjmp(handler->loc, 1);
11272 RESTOREINT(saveint);
11276 /* $NetBSD: show.c,v 1.24 2003/01/22 20:36:04 dsl Exp $ */
11279 static void shtree(union node *, int, char *, FILE*);
11280 static void shcmd(union node *, FILE *);
11281 static void sharg(union node *, FILE *);
11282 static void indent(int, char *, FILE *);
11283 static void trstring(char *);
11287 showtree(union node *n)
11289 trputs("showtree called\n");
11290 shtree(n, 1, NULL, stdout);
11295 shtree(union node *n, int ind, char *pfx, FILE *fp)
11297 struct nodelist *lp;
11303 indent(ind, pfx, fp);
11314 shtree(n->nbinary.ch1, ind, NULL, fp);
11317 shtree(n->nbinary.ch2, ind, NULL, fp);
11325 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
11330 if (n->npipe.backgnd)
11336 fprintf(fp, "<node type %d>", n->type);
11345 shcmd(union node *cmd, FILE *fp)
11353 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11359 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11362 switch (np->nfile.type) {
11363 case NTO: s = ">"; dftfd = 1; break;
11364 case NCLOBBER: s = ">|"; dftfd = 1; break;
11365 case NAPPEND: s = ">>"; dftfd = 1; break;
11366 case NTOFD: s = ">&"; dftfd = 1; break;
11367 case NFROM: s = "<"; dftfd = 0; break;
11368 case NFROMFD: s = "<&"; dftfd = 0; break;
11369 case NFROMTO: s = "<>"; dftfd = 0; break;
11370 default: s = "*error*"; dftfd = 0; break;
11372 if (np->nfile.fd != dftfd)
11373 fprintf(fp, "%d", np->nfile.fd);
11375 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11376 fprintf(fp, "%d", np->ndup.dupfd);
11378 sharg(np->nfile.fname, fp);
11387 sharg(union node *arg, FILE *fp)
11390 struct nodelist *bqlist;
11393 if (arg->type != NARG) {
11394 out1fmt("<node type %d>\n", arg->type);
11397 bqlist = arg->narg.backquote;
11398 for (p = arg->narg.text ; *p ; p++) {
11407 if (subtype == VSLENGTH)
11413 if (subtype & VSNUL)
11416 switch (subtype & VSTYPE) {
11435 case VSTRIMLEFTMAX:
11442 case VSTRIMRIGHTMAX:
11449 out1fmt("<subtype %d>", subtype);
11456 case CTLBACKQ|CTLQUOTE:
11459 shtree(bqlist->n, -1, NULL, fp);
11471 indent(int amount, char *pfx, FILE *fp)
11475 for (i = 0 ; i < amount ; i++) {
11476 if (pfx && i == amount - 1)
11497 putc(c, tracefile);
11501 trace(const char *fmt, ...)
11508 (void) vfprintf(tracefile, fmt, va);
11513 tracev(const char *fmt, va_list va)
11517 (void) vfprintf(tracefile, fmt, va);
11522 trputs(const char *s)
11526 fputs(s, tracefile);
11538 putc('"', tracefile);
11539 for (p = s ; *p ; p++) {
11541 case '\n': c = 'n'; goto backslash;
11542 case '\t': c = 't'; goto backslash;
11543 case '\r': c = 'r'; goto backslash;
11544 case '"': c = '"'; goto backslash;
11545 case '\\': c = '\\'; goto backslash;
11546 case CTLESC: c = 'e'; goto backslash;
11547 case CTLVAR: c = 'v'; goto backslash;
11548 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11549 case CTLBACKQ: c = 'q'; goto backslash;
11550 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
11551 backslash: putc('\\', tracefile);
11552 putc(c, tracefile);
11555 if (*p >= ' ' && *p <= '~')
11556 putc(*p, tracefile);
11558 putc('\\', tracefile);
11559 putc(*p >> 6 & 03, tracefile);
11560 putc(*p >> 3 & 07, tracefile);
11561 putc(*p & 07, tracefile);
11566 putc('"', tracefile);
11578 putc(' ', tracefile);
11580 putc('\n', tracefile);
11596 /* leave open because libedit might be using it */
11599 scopy("./trace", s);
11601 if (!freopen(s, "a", tracefile)) {
11602 fprintf(stderr, "Can't re-open %s\n", s);
11607 if ((tracefile = fopen(s, "a")) == NULL) {
11608 fprintf(stderr, "Can't open %s\n", s);
11614 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11615 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11617 setlinebuf(tracefile);
11618 fputs("\nTracing started.\n", tracefile);
11623 /* $NetBSD: trap.c,v 1.28 2002/11/24 22:35:43 christos Exp $ */
11626 * Sigmode records the current value of the signal handlers for the various
11627 * modes. A value of zero means that the current handler is not known.
11628 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
11631 #define S_DFL 1 /* default signal handling (SIG_DFL) */
11632 #define S_CATCH 2 /* signal is caught */
11633 #define S_IGN 3 /* signal is ignored (SIG_IGN) */
11634 #define S_HARD_IGN 4 /* signal is ignored permenantly */
11635 #define S_RESET 5 /* temporary - to reset a hard ignored sig */
11640 * The trap builtin.
11644 trapcmd(int argc, char **argv)
11653 for (signo = 0 ; signo < NSIG ; signo++) {
11654 if (trap[signo] != NULL) {
11657 sn = u_signal_names(0, &signo, 0);
11660 out1fmt("trap -- %s %s\n",
11661 single_quote(trap[signo]), sn);
11671 if ((signo = decode_signal(*ap, 0)) < 0)
11672 error("%s: bad trap", *ap);
11675 if (action[0] == '-' && action[1] == '\0')
11678 action = savestr(action);
11681 ckfree(trap[signo]);
11682 trap[signo] = action;
11693 * Clear traps on a fork.
11701 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
11702 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
11706 if (tp != &trap[0])
11707 setsignal(tp - trap);
11715 * Set the signal handler for the specified signal. The routine figures
11716 * out what it should be set to.
11720 setsignal(int signo)
11724 struct sigaction act;
11726 if ((t = trap[signo]) == NULL)
11728 else if (*t != '\0')
11732 if (rootshell && action == S_DFL) {
11735 if (iflag || minusc || sflag == 0)
11758 t = &sigmode[signo - 1];
11762 * current setting unknown
11764 if (sigaction(signo, 0, &act) == -1) {
11766 * Pretend it worked; maybe we should give a warning
11767 * here, but other shells don't. We don't alter
11768 * sigmode, so that we retry every time.
11772 if (act.sa_handler == SIG_IGN) {
11773 if (mflag && (signo == SIGTSTP ||
11774 signo == SIGTTIN || signo == SIGTTOU)) {
11775 tsig = S_IGN; /* don't hard ignore these */
11779 tsig = S_RESET; /* force to be set */
11782 if (tsig == S_HARD_IGN || tsig == action)
11786 act.sa_handler = onsig;
11789 act.sa_handler = SIG_IGN;
11792 act.sa_handler = SIG_DFL;
11796 sigfillset(&act.sa_mask);
11797 sigaction(signo, &act, 0);
11805 ignoresig(int signo)
11807 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11808 signal(signo, SIG_IGN);
11810 sigmode[signo - 1] = S_HARD_IGN;
11821 gotsig[signo - 1] = 1;
11822 pendingsigs = signo;
11824 if (exsig || (signo == SIGINT && !trap[SIGINT])) {
11833 * Called to execute a trap. Perhaps we should avoid entering new trap
11834 * handlers while we are executing a trap handler.
11844 savestatus = exitstatus;
11846 while (pendingsigs = 0, xbarrier(), (p = memchr(q, 1, NSIG - 1))) {
11848 p = trap[p - q + 1];
11852 exitstatus = savestatus;
11858 * Controls whether the shell is interactive or not.
11862 setinteractive(int on)
11864 static int is_interactive;
11866 if (++on == is_interactive)
11868 is_interactive = on;
11870 setsignal(SIGQUIT);
11871 setsignal(SIGTERM);
11872 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11873 if(is_interactive > 1) {
11874 /* Looks like they want an interactive shell */
11875 static int do_banner;
11879 "\n\n" BB_BANNER " Built-in shell (ash)\n"
11880 "Enter 'help' for a list of built-in commands.\n\n");
11888 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11889 /*** List the available builtins ***/
11891 static int helpcmd(int argc, char **argv)
11895 out1fmt("\nBuilt-in commands:\n-------------------\n");
11896 for (col = 0, i = 0; i < NUMBUILTINS; i++) {
11897 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11898 builtincmd[i].name + 1);
11904 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
11906 extern const struct BB_applet applets[];
11907 extern const size_t NUM_APPLETS;
11909 for (i = 0; i < NUM_APPLETS; i++) {
11911 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
11920 return EXIT_SUCCESS;
11922 #endif /* CONFIG_FEATURE_SH_EXTRA_QUIET */
11925 * Called to exit the shell.
11936 jmp = setjmp(loc.loc);
11937 status = exitstatus;
11938 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
11942 if ((p = trap[0]) != NULL && *p != '\0') {
11948 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
11949 if (iflag && rootshell) {
11950 const char *hp = lookupvar("HISTFILE");
11953 save_history ( hp );
11961 static int decode_signal(const char *string, int minsig)
11964 const char *name = u_signal_names(string, &signo, minsig);
11966 return name ? signo : -1;
11969 /* $NetBSD: var.c,v 1.32 2003/01/22 20:36:04 dsl Exp $ */
11971 static struct var *vartab[VTABSIZE];
11973 static int vpcmp(const void *, const void *);
11974 static struct var **findvar(struct var **, const char *);
11977 * Initialize the variable symbol tables and import the environment
11981 #ifdef CONFIG_ASH_GETOPTS
11983 * Safe version of setvar, returns 1 on success 0 on failure.
11987 setvarsafe(const char *name, const char *val, int flags)
11990 volatile int saveint;
11991 struct jmploc *volatile savehandler = handler;
11992 struct jmploc jmploc;
11995 if (setjmp(jmploc.loc))
11999 setvar(name, val, flags);
12002 handler = savehandler;
12003 RESTOREINT(saveint);
12009 * Set the value of a variable. The flags argument is ored with the
12010 * flags of the variable. If val is NULL, the variable is unset.
12014 setvar(const char *name, const char *val, int flags)
12021 q = endofname(name);
12022 p = strchrnul(q, '=');
12023 namelen = p - name;
12024 if (!namelen || p != q)
12025 error("%.*s: bad variable name", namelen, name);
12030 vallen = strlen(val);
12033 p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
12037 p = mempcpy(p, val, vallen);
12040 setvareq(nameeq, flags | VNOSAVE);
12046 * Same as setvar except that the variable and value are passed in
12047 * the first argument as name=value. Since the first argument will
12048 * be actually stored in the table, it should not be a string that
12050 * Called with interrupts off.
12054 setvareq(char *s, int flags)
12056 struct var *vp, **vpp;
12059 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
12060 vp = *findvar(vpp, s);
12062 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
12065 if (flags & VNOSAVE)
12068 error("%.*s: is read only", strchrnul(n, '=') - n, n);
12071 if (flags & VNOSET)
12074 if (vp->func && (flags & VNOFUNC) == 0)
12075 (*vp->func)(strchrnul(s, '=') + 1);
12077 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12080 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
12082 if (flags & VNOSET)
12085 vp = ckmalloc(sizeof (*vp));
12090 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
12098 * Process a linked list of variable assignments.
12102 listsetvar(struct strlist *list_set_var, int flags)
12104 struct strlist *lp = list_set_var;
12110 setvareq(lp->text, flags);
12111 } while ((lp = lp->next));
12117 * Find the value of a variable. Returns NULL if not set.
12121 lookupvar(const char *name)
12125 if ((v = *findvar(hashvar(name), name))) {
12128 * Dynamic variables are implemented roughly the same way they are
12129 * in bash. Namely, they're "special" so long as they aren't unset.
12130 * As soon as they're unset, they're no longer dynamic, and dynamic
12131 * lookup will no longer happen at that point. -- PFM.
12133 if((v->flags & VDYNAMIC))
12136 if(!(v->flags & VUNSET))
12137 return strchrnul(v->text, '=') + 1;
12145 * Search the environment of a builtin command.
12149 bltinlookup(const char *name)
12151 struct strlist *sp;
12153 for (sp = cmdenviron ; sp ; sp = sp->next) {
12154 if (varequal(sp->text, name))
12155 return strchrnul(sp->text, '=') + 1;
12157 return lookupvar(name);
12162 * Generate a list of variables satisfying the given conditions.
12166 listvars(int on, int off, char ***end)
12177 for (vp = *vpp ; vp ; vp = vp->next)
12178 if ((vp->flags & mask) == on) {
12179 if (ep == stackstrend())
12180 ep = growstackstr();
12181 *ep++ = (char *) vp->text;
12183 } while (++vpp < vartab + VTABSIZE);
12184 if (ep == stackstrend())
12185 ep = growstackstr();
12189 return grabstackstr(ep);
12194 * POSIX requires that 'set' (but not export or readonly) output the
12195 * variables in lexicographic order - by the locale's collating order (sigh).
12196 * Maybe we could keep them in an ordered balanced binary tree
12197 * instead of hashed lists.
12198 * For now just roll 'em through qsort for printing...
12202 showvars(const char *sep_prefix, int on, int off)
12205 char **ep, **epend;
12207 ep = listvars(on, off, &epend);
12208 qsort(ep, epend - ep, sizeof(char *), vpcmp);
12210 sep = *sep_prefix ? spcstr : sep_prefix;
12212 for (; ep < epend; ep++) {
12216 p = strchrnul(*ep, '=');
12219 q = single_quote(++p);
12221 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
12230 * The export and readonly commands.
12234 exportcmd(int argc, char **argv)
12240 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12243 notp = nextopt("p") - 'p';
12244 if (notp && ((name = *(aptr = argptr)))) {
12246 if ((p = strchr(name, '=')) != NULL) {
12249 if ((vp = *findvar(hashvar(name), name))) {
12254 setvar(name, p, flag);
12255 } while ((name = *++aptr) != NULL);
12257 showvars(argv[0], flag, 0);
12264 * Make a variable a local variable. When a variable is made local, it's
12265 * value and flags are saved in a localvar structure. The saved values
12266 * will be restored when the shell function returns. We handle the name
12267 * "-" as a special case.
12271 mklocal(char *name)
12273 struct localvar *lvp;
12278 lvp = ckmalloc(sizeof (struct localvar));
12279 if (name[0] == '-' && name[1] == '\0') {
12281 p = ckmalloc(sizeof(optlist));
12282 lvp->text = memcpy(p, optlist, sizeof(optlist));
12287 vpp = hashvar(name);
12288 vp = *findvar(vpp, name);
12289 eq = strchr(name, '=');
12292 setvareq(name, VSTRFIXED);
12294 setvar(name, NULL, VSTRFIXED);
12295 vp = *vpp; /* the new variable */
12296 lvp->flags = VUNSET;
12298 lvp->text = vp->text;
12299 lvp->flags = vp->flags;
12300 vp->flags |= VSTRFIXED|VTEXTFIXED;
12306 lvp->next = localvars;
12312 * The "local" command.
12316 localcmd(int argc, char **argv)
12321 while ((name = *argv++) != NULL) {
12329 * Called after a function returns.
12330 * Interrupts must be off.
12336 struct localvar *lvp;
12339 while ((lvp = localvars) != NULL) {
12340 localvars = lvp->next;
12342 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
12343 if (vp == NULL) { /* $- saved */
12344 memcpy(optlist, lvp->text, sizeof(optlist));
12347 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12348 unsetvar(vp->text);
12351 (*vp->func)(strchrnul(lvp->text, '=') + 1);
12352 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12354 vp->flags = lvp->flags;
12355 vp->text = lvp->text;
12363 * The unset builtin command. We unset the function before we unset the
12364 * variable to allow a function to be unset when there is a readonly variable
12365 * with the same name.
12369 unsetcmd(int argc, char **argv)
12376 while ((i = nextopt("vf")) != '\0') {
12380 for (ap = argptr; *ap ; ap++) {
12395 * Unset the specified variable.
12399 unsetvar(const char *s)
12405 vpp = findvar(hashvar(s), s);
12409 int flags = vp->flags;
12412 if (flags & VREADONLY)
12415 vp->flags &= ~VDYNAMIC;
12417 if (flags & VUNSET)
12419 if ((flags & VSTRFIXED) == 0) {
12421 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
12428 vp->flags &= ~VEXPORT;
12441 * Find the appropriate entry in the hash table from the name.
12444 static struct var **
12445 hashvar(const char *p)
12447 unsigned int hashval;
12449 hashval = ((unsigned char) *p) << 4;
12450 while (*p && *p != '=')
12451 hashval += (unsigned char) *p++;
12452 return &vartab[hashval % VTABSIZE];
12458 * Compares two strings up to the first = or '\0'. The first
12459 * string must be terminated by '='; the second may be terminated by
12460 * either '=' or '\0'.
12464 varcmp(const char *p, const char *q)
12468 while ((c = *p) == (d = *q)) {
12469 if (!c || c == '=')
12483 vpcmp(const void *a, const void *b)
12485 return varcmp(*(const char **)a, *(const char **)b);
12488 static struct var **
12489 findvar(struct var **vpp, const char *name)
12491 for (; *vpp; vpp = &(*vpp)->next) {
12492 if (varequal((*vpp)->text, name)) {
12498 /* $NetBSD: setmode.c,v 1.29 2003/01/15 23:58:03 kleink Exp $ */
12500 #include <sys/times.h>
12502 static const unsigned char timescmd_str[] = {
12503 ' ', offsetof(struct tms, tms_utime),
12504 '\n', offsetof(struct tms, tms_stime),
12505 ' ', offsetof(struct tms, tms_cutime),
12506 '\n', offsetof(struct tms, tms_cstime),
12510 static int timescmd(int ac, char **av)
12512 long int clk_tck, s, t;
12513 const unsigned char *p;
12516 clk_tck = sysconf(_SC_CLK_TCK);
12521 t = *(clock_t *)(((char *) &buf) + p[1]);
12523 out1fmt("%ldm%ld.%.3lds%c",
12525 ((t - s * clk_tck) * 1000) / clk_tck,
12527 } while (*(p += 2));
12532 #ifdef CONFIG_ASH_MATH_SUPPORT
12534 dash_arith(const char *s)
12540 result = arith(s, &errcode);
12543 error("exponent less than 0");
12544 else if (errcode == -2)
12545 error("divide by zero");
12546 else if (errcode == -5)
12547 error("expression recursion loop detected");
12558 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12559 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12561 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12565 letcmd(int argc, char **argv)
12572 error("expression expected");
12573 for (ap = argv + 1; *ap; ap++) {
12574 i = dash_arith(*ap);
12579 #endif /* CONFIG_ASH_MATH_SUPPORT */
12581 /* $NetBSD: miscbltin.c,v 1.31 2002/11/24 22:35:41 christos Exp $ */
12584 * Miscellaneous builtins.
12590 #if __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
12591 typedef enum __rlimit_resource rlim_t;
12597 * The read builtin. The -e option causes backslashes to escape the
12598 * following character.
12600 * This uses unbuffered input, which may be avoidable in some cases.
12604 readcmd(int argc, char **argv)
12616 #if defined(CONFIG_ASH_READ_NCHARS)
12620 struct termios tty, old_tty;
12622 #if defined(CONFIG_ASH_READ_TIMEOUT)
12626 ts.tv_sec = ts.tv_usec = 0;
12631 #if defined(CONFIG_ASH_READ_NCHARS) && defined(CONFIG_ASH_READ_TIMEOUT)
12632 while ((i = nextopt("p:rt:n:s")) != '\0')
12633 #elif defined(CONFIG_ASH_READ_NCHARS)
12634 while ((i = nextopt("p:rn:s")) != '\0')
12635 #elif defined(CONFIG_ASH_READ_TIMEOUT)
12636 while ((i = nextopt("p:rt:")) != '\0')
12638 while ((i = nextopt("p:r")) != '\0')
12643 prompt = optionarg;
12645 #if defined(CONFIG_ASH_READ_NCHARS)
12647 nchars = strtol(optionarg, &p, 10);
12649 error("invalid count");
12650 nch_flag = (nchars > 0);
12656 #if defined(CONFIG_ASH_READ_TIMEOUT)
12658 ts.tv_sec = strtol(optionarg, &p, 10);
12664 ts.tv_usec = strtol(p, &p2, 10);
12666 error("invalid timeout");
12668 /* normalize to usec */
12670 error("invalid timeout");
12671 while (scale++ < 6)
12675 error("invalid timeout");
12677 if ( ! ts.tv_sec && ! ts.tv_usec)
12678 error("invalid timeout");
12688 if (prompt && isatty(0)) {
12691 if (*(ap = argptr) == NULL)
12692 error("arg count");
12693 if ((ifs = bltinlookup("IFS")) == NULL)
12695 #if defined(CONFIG_ASH_READ_NCHARS)
12696 if (nch_flag || silent) {
12697 tcgetattr(0, &tty);
12700 tty.c_lflag &= ~ICANON;
12701 tty.c_cc[VMIN] = nchars;
12704 tty.c_lflag &= ~(ECHO|ECHOK|ECHONL);
12707 tcsetattr(0, TCSANOW, &tty);
12710 #if defined(CONFIG_ASH_READ_TIMEOUT)
12711 if (ts.tv_sec || ts.tv_usec) {
12715 i = select (FD_SETSIZE, &set, NULL, NULL, &ts);
12717 #if defined(CONFIG_ASH_READ_NCHARS)
12719 tcsetattr(0, TCSANOW, &old_tty);
12729 #if defined(CONFIG_ASH_READ_NCHARS)
12730 while (!nch_flag || nchars--)
12735 if (read(0, &c, 1) != 1) {
12747 if (!rflag && c == '\\') {
12753 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12757 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12759 setvar(*ap, stackblock(), 0);
12768 #if defined(CONFIG_ASH_READ_NCHARS)
12769 if (nch_flag || silent)
12770 tcsetattr(0, TCSANOW, &old_tty);
12774 /* Remove trailing blanks */
12775 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12777 setvar(*ap, stackblock(), 0);
12778 while (*++ap != NULL)
12779 setvar(*ap, nullstr, 0);
12784 static int umaskcmd(int argc, char **argv)
12786 static const char permuser[3] = "ugo";
12787 static const char permmode[3] = "rwx";
12788 static const short int permmask[] = {
12789 S_IRUSR, S_IWUSR, S_IXUSR,
12790 S_IRGRP, S_IWGRP, S_IXGRP,
12791 S_IROTH, S_IWOTH, S_IXOTH
12797 int symbolic_mode = 0;
12799 while (nextopt("S") != '\0') {
12808 if ((ap = *argptr) == NULL) {
12809 if (symbolic_mode) {
12813 for (i = 0; i < 3; i++) {
12816 *p++ = permuser[i];
12818 for (j = 0; j < 3; j++) {
12819 if ((mask & permmask[3 * i + j]) == 0) {
12820 *p++ = permmode[j];
12828 out1fmt("%.4o\n", mask);
12831 if (is_digit((unsigned char) *ap)) {
12834 if (*ap >= '8' || *ap < '0')
12835 error(illnum, argv[1]);
12836 mask = (mask << 3) + (*ap - '0');
12837 } while (*++ap != '\0');
12840 mask = ~mask & 0777;
12841 if (!bb_parse_mode(ap, &mask)) {
12842 error("Illegal mode: %s", ap);
12844 umask(~mask & 0777);
12853 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12854 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12855 * ash by J.T. Conklin.
12863 int factor; /* multiply by to get rlim_{cur,max} values */
12867 static const struct limits limits[] = {
12869 { "time(seconds)", RLIMIT_CPU, 1, 't' },
12871 #ifdef RLIMIT_FSIZE
12872 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
12875 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
12877 #ifdef RLIMIT_STACK
12878 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
12881 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
12884 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
12886 #ifdef RLIMIT_MEMLOCK
12887 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
12889 #ifdef RLIMIT_NPROC
12890 { "process", RLIMIT_NPROC, 1, 'p' },
12892 #ifdef RLIMIT_NOFILE
12893 { "nofiles", RLIMIT_NOFILE, 1, 'n' },
12896 { "vmemory(kbytes)", RLIMIT_AS, 1024, 'v' },
12898 #ifdef RLIMIT_LOCKS
12899 { "locks", RLIMIT_LOCKS, 1, 'w' },
12901 { (char *) 0, 0, 0, '\0' }
12904 enum limtype { SOFT = 0x1, HARD = 0x2 };
12906 static void printlim(enum limtype how, const struct rlimit *limit,
12907 const struct limits *l)
12911 val = limit->rlim_max;
12913 val = limit->rlim_cur;
12915 if (val == RLIM_INFINITY)
12916 out1fmt("unlimited\n");
12919 out1fmt("%lld\n", (long long) val);
12924 ulimitcmd(int argc, char **argv)
12928 enum limtype how = SOFT | HARD;
12929 const struct limits *l;
12932 struct rlimit limit;
12935 while ((optc = nextopt("HSa"
12939 #ifdef RLIMIT_FSIZE
12945 #ifdef RLIMIT_STACK
12954 #ifdef RLIMIT_MEMLOCK
12957 #ifdef RLIMIT_NPROC
12960 #ifdef RLIMIT_NOFILE
12966 #ifdef RLIMIT_LOCKS
12984 for (l = limits; l->option != what; l++)
12987 set = *argptr ? 1 : 0;
12991 if (all || argptr[1])
12992 error("too many arguments");
12993 if (strncmp(p, "unlimited\n", 9) == 0)
12994 val = RLIM_INFINITY;
12998 while ((c = *p++) >= '0' && c <= '9')
13000 val = (val * 10) + (long)(c - '0');
13001 if (val < (rlim_t) 0)
13005 error("bad number");
13010 for (l = limits; l->name; l++) {
13011 getrlimit(l->cmd, &limit);
13012 out1fmt("%-20s ", l->name);
13013 printlim(how, &limit, l);
13018 getrlimit(l->cmd, &limit);
13021 limit.rlim_max = val;
13023 limit.rlim_cur = val;
13024 if (setrlimit(l->cmd, &limit) < 0)
13025 error("error setting limit (%m)");
13027 printlim(how, &limit, l);
13033 #ifdef CONFIG_ASH_MATH_SUPPORT
13035 /* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
13037 Permission is hereby granted, free of charge, to any person obtaining
13038 a copy of this software and associated documentation files (the
13039 "Software"), to deal in the Software without restriction, including
13040 without limitation the rights to use, copy, modify, merge, publish,
13041 distribute, sublicense, and/or sell copies of the Software, and to
13042 permit persons to whom the Software is furnished to do so, subject to
13043 the following conditions:
13045 The above copyright notice and this permission notice shall be
13046 included in all copies or substantial portions of the Software.
13048 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13049 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
13050 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
13051 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
13052 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
13053 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
13054 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13057 /* This is my infix parser/evaluator. It is optimized for size, intended
13058 * as a replacement for yacc-based parsers. However, it may well be faster
13059 * than a comparable parser written in yacc. The supported operators are
13060 * listed in #defines below. Parens, order of operations, and error handling
13061 * are supported. This code is thread safe. The exact expression format should
13062 * be that which POSIX specifies for shells. */
13064 /* The code uses a simple two-stack algorithm. See
13065 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
13066 * for a detailed explanation of the infix-to-postfix algorithm on which
13067 * this is based (this code differs in that it applies operators immediately
13068 * to the stack instead of adding them to a queue to end up with an
13071 /* To use the routine, call it with an expression string and error return
13075 * Aug 24, 2001 Manuel Novoa III
13077 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
13079 * 1) In arith_apply():
13080 * a) Cached values of *numptr and &(numptr[-1]).
13081 * b) Removed redundant test for zero denominator.
13084 * a) Eliminated redundant code for processing operator tokens by moving
13085 * to a table-based implementation. Also folded handling of parens
13087 * b) Combined all 3 loops which called arith_apply to reduce generated
13088 * code size at the cost of speed.
13090 * 3) The following expressions were treated as valid by the original code:
13091 * 1() , 0! , 1 ( *3 ) .
13092 * These bugs have been fixed by internally enclosing the expression in
13093 * parens and then checking that all binary ops and right parens are
13094 * preceded by a valid expression (NUM_TOKEN).
13096 * Note: It may be desirable to replace Aaron's test for whitespace with
13097 * ctype's isspace() if it is used by another busybox applet or if additional
13098 * whitespace chars should be considered. Look below the "#include"s for a
13099 * precompiler test.
13103 * Aug 26, 2001 Manuel Novoa III
13105 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
13107 * Merge in Aaron's comments previously posted to the busybox list,
13108 * modified slightly to take account of my changes to the code.
13113 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
13115 * - allow access to variable,
13116 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
13117 * - realize assign syntax (VAR=expr, +=, *= etc)
13118 * - realize exponentiation (** operator)
13119 * - realize comma separated - expr, expr
13120 * - realise ++expr --expr expr++ expr--
13121 * - realise expr ? expr : expr (but, second expr calculate always)
13122 * - allow hexadecimal and octal numbers
13123 * - was restored loses XOR operator
13124 * - remove one goto label, added three ;-)
13125 * - protect $((num num)) as true zero expr (Manuel`s error)
13126 * - always use special isspace(), see comment from bash ;-)
13130 #define arith_isspace(arithval) \
13131 (arithval == ' ' || arithval == '\n' || arithval == '\t')
13134 typedef unsigned char operator;
13136 /* An operator's token id is a bit of a bitfield. The lower 5 bits are the
13137 * precedence, and 3 high bits are an ID unique across operators of that
13138 * precedence. The ID portion is so that multiple operators can have the
13139 * same precedence, ensuring that the leftmost one is evaluated first.
13140 * Consider * and /. */
13142 #define tok_decl(prec,id) (((id)<<5)|(prec))
13143 #define PREC(op) ((op) & 0x1F)
13145 #define TOK_LPAREN tok_decl(0,0)
13147 #define TOK_COMMA tok_decl(1,0)
13149 #define TOK_ASSIGN tok_decl(2,0)
13150 #define TOK_AND_ASSIGN tok_decl(2,1)
13151 #define TOK_OR_ASSIGN tok_decl(2,2)
13152 #define TOK_XOR_ASSIGN tok_decl(2,3)
13153 #define TOK_PLUS_ASSIGN tok_decl(2,4)
13154 #define TOK_MINUS_ASSIGN tok_decl(2,5)
13155 #define TOK_LSHIFT_ASSIGN tok_decl(2,6)
13156 #define TOK_RSHIFT_ASSIGN tok_decl(2,7)
13158 #define TOK_MUL_ASSIGN tok_decl(3,0)
13159 #define TOK_DIV_ASSIGN tok_decl(3,1)
13160 #define TOK_REM_ASSIGN tok_decl(3,2)
13162 /* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
13163 #define convert_prec_is_assing(prec) do { if(prec == 3) prec = 2; } while(0)
13165 /* conditional is right associativity too */
13166 #define TOK_CONDITIONAL tok_decl(4,0)
13167 #define TOK_CONDITIONAL_SEP tok_decl(4,1)
13169 #define TOK_OR tok_decl(5,0)
13171 #define TOK_AND tok_decl(6,0)
13173 #define TOK_BOR tok_decl(7,0)
13175 #define TOK_BXOR tok_decl(8,0)
13177 #define TOK_BAND tok_decl(9,0)
13179 #define TOK_EQ tok_decl(10,0)
13180 #define TOK_NE tok_decl(10,1)
13182 #define TOK_LT tok_decl(11,0)
13183 #define TOK_GT tok_decl(11,1)
13184 #define TOK_GE tok_decl(11,2)
13185 #define TOK_LE tok_decl(11,3)
13187 #define TOK_LSHIFT tok_decl(12,0)
13188 #define TOK_RSHIFT tok_decl(12,1)
13190 #define TOK_ADD tok_decl(13,0)
13191 #define TOK_SUB tok_decl(13,1)
13193 #define TOK_MUL tok_decl(14,0)
13194 #define TOK_DIV tok_decl(14,1)
13195 #define TOK_REM tok_decl(14,2)
13197 /* exponent is right associativity */
13198 #define TOK_EXPONENT tok_decl(15,1)
13200 /* For now unary operators. */
13201 #define UNARYPREC 16
13202 #define TOK_BNOT tok_decl(UNARYPREC,0)
13203 #define TOK_NOT tok_decl(UNARYPREC,1)
13205 #define TOK_UMINUS tok_decl(UNARYPREC+1,0)
13206 #define TOK_UPLUS tok_decl(UNARYPREC+1,1)
13208 #define PREC_PRE (UNARYPREC+2)
13210 #define TOK_PRE_INC tok_decl(PREC_PRE, 0)
13211 #define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
13213 #define PREC_POST (UNARYPREC+3)
13215 #define TOK_POST_INC tok_decl(PREC_POST, 0)
13216 #define TOK_POST_DEC tok_decl(PREC_POST, 1)
13218 #define SPEC_PREC (UNARYPREC+4)
13220 #define TOK_NUM tok_decl(SPEC_PREC, 0)
13221 #define TOK_RPAREN tok_decl(SPEC_PREC, 1)
13223 #define NUMPTR (*numstackptr)
13225 static inline int tok_have_assign(operator op)
13227 operator prec = PREC(op);
13229 convert_prec_is_assing(prec);
13230 return (prec == PREC(TOK_ASSIGN) ||
13231 prec == PREC_PRE || prec == PREC_POST);
13234 static inline int is_right_associativity(operator prec)
13236 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) ||
13237 prec == PREC(TOK_CONDITIONAL));
13241 typedef struct ARITCH_VAR_NUM {
13243 arith_t contidional_second_val;
13244 char contidional_second_val_initialized;
13245 char *var; /* if NULL then is regular number,
13246 else is variable name */
13250 typedef struct CHK_VAR_RECURSIVE_LOOPED {
13252 struct CHK_VAR_RECURSIVE_LOOPED *next;
13253 } chk_var_recursive_looped_t;
13255 static chk_var_recursive_looped_t *prev_chk_var_recursive;
13258 static int arith_lookup_val(v_n_t *t)
13261 const char * p = lookupvar(t->var);
13266 /* recursive try as expression */
13267 chk_var_recursive_looped_t *cur;
13268 chk_var_recursive_looped_t cur_save;
13270 for(cur = prev_chk_var_recursive; cur; cur = cur->next) {
13271 if(strcmp(cur->var, t->var) == 0) {
13272 /* expression recursion loop detected */
13276 /* save current lookuped var name */
13277 cur = prev_chk_var_recursive;
13278 cur_save.var = t->var;
13279 cur_save.next = cur;
13280 prev_chk_var_recursive = &cur_save;
13282 t->val = arith (p, &errcode);
13283 /* restore previous ptr after recursiving */
13284 prev_chk_var_recursive = cur;
13287 /* allow undefined var as 0 */
13294 /* "applying" a token means performing it on the top elements on the integer
13295 * stack. For a unary operator it will only change the top element, but a
13296 * binary operator will pop two arguments and push a result */
13298 arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
13301 arith_t numptr_val, rez;
13302 int ret_arith_lookup_val;
13304 if (NUMPTR == numstack) goto err; /* There is no operator that can work
13305 without arguments */
13306 numptr_m1 = NUMPTR - 1;
13308 /* check operand is var with noninteger value */
13309 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13310 if(ret_arith_lookup_val)
13311 return ret_arith_lookup_val;
13313 rez = numptr_m1->val;
13314 if (op == TOK_UMINUS)
13316 else if (op == TOK_NOT)
13318 else if (op == TOK_BNOT)
13320 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
13322 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
13324 else if (op != TOK_UPLUS) {
13325 /* Binary operators */
13327 /* check and binary operators need two arguments */
13328 if (numptr_m1 == numstack) goto err;
13330 /* ... and they pop one */
13333 if (op == TOK_CONDITIONAL) {
13334 if(! numptr_m1->contidional_second_val_initialized) {
13335 /* protect $((expr1 ? expr2)) without ": expr" */
13338 rez = numptr_m1->contidional_second_val;
13339 } else if(numptr_m1->contidional_second_val_initialized) {
13340 /* protect $((expr1 : expr2)) without "expr ? " */
13343 numptr_m1 = NUMPTR - 1;
13344 if(op != TOK_ASSIGN) {
13345 /* check operand is var with noninteger value for not '=' */
13346 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13347 if(ret_arith_lookup_val)
13348 return ret_arith_lookup_val;
13350 if (op == TOK_CONDITIONAL) {
13351 numptr_m1->contidional_second_val = rez;
13353 rez = numptr_m1->val;
13354 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
13356 else if (op == TOK_OR)
13357 rez = numptr_val || rez;
13358 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
13360 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
13362 else if (op == TOK_AND)
13363 rez = rez && numptr_val;
13364 else if (op == TOK_EQ)
13365 rez = (rez == numptr_val);
13366 else if (op == TOK_NE)
13367 rez = (rez != numptr_val);
13368 else if (op == TOK_GE)
13369 rez = (rez >= numptr_val);
13370 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
13371 rez >>= numptr_val;
13372 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
13373 rez <<= numptr_val;
13374 else if (op == TOK_GT)
13375 rez = (rez > numptr_val);
13376 else if (op == TOK_LT)
13377 rez = (rez < numptr_val);
13378 else if (op == TOK_LE)
13379 rez = (rez <= numptr_val);
13380 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
13382 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
13384 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
13386 else if (op == TOK_ASSIGN || op == TOK_COMMA)
13388 else if (op == TOK_CONDITIONAL_SEP) {
13389 if (numptr_m1 == numstack) {
13390 /* protect $((expr : expr)) without "expr ? " */
13393 numptr_m1->contidional_second_val_initialized = op;
13394 numptr_m1->contidional_second_val = numptr_val;
13396 else if (op == TOK_CONDITIONAL) {
13398 numptr_val : numptr_m1->contidional_second_val;
13400 else if(op == TOK_EXPONENT) {
13402 return -3; /* exponent less than 0 */
13407 while(numptr_val--)
13412 else if(numptr_val==0) /* zero divisor check */
13414 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
13416 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
13419 if(tok_have_assign(op)) {
13422 if(numptr_m1->var == NULL) {
13426 /* save to shell variable */
13427 #ifdef CONFIG_ASH_MATH_SUPPORT_64
13428 snprintf(buf, sizeof(buf), "%lld", rez);
13430 snprintf(buf, sizeof(buf), "%ld", rez);
13432 setvar(numptr_m1->var, buf, 0);
13433 /* after saving, make previous value for v++ or v-- */
13434 if(op == TOK_POST_INC)
13436 else if(op == TOK_POST_DEC)
13439 numptr_m1->val = rez;
13440 /* protect geting var value, is number now */
13441 numptr_m1->var = NULL;
13446 /* longest must first */
13447 static const char op_tokens[] = {
13448 '<','<','=',0, TOK_LSHIFT_ASSIGN,
13449 '>','>','=',0, TOK_RSHIFT_ASSIGN,
13450 '<','<', 0, TOK_LSHIFT,
13451 '>','>', 0, TOK_RSHIFT,
13452 '|','|', 0, TOK_OR,
13453 '&','&', 0, TOK_AND,
13454 '!','=', 0, TOK_NE,
13455 '<','=', 0, TOK_LE,
13456 '>','=', 0, TOK_GE,
13457 '=','=', 0, TOK_EQ,
13458 '|','=', 0, TOK_OR_ASSIGN,
13459 '&','=', 0, TOK_AND_ASSIGN,
13460 '*','=', 0, TOK_MUL_ASSIGN,
13461 '/','=', 0, TOK_DIV_ASSIGN,
13462 '%','=', 0, TOK_REM_ASSIGN,
13463 '+','=', 0, TOK_PLUS_ASSIGN,
13464 '-','=', 0, TOK_MINUS_ASSIGN,
13465 '-','-', 0, TOK_POST_DEC,
13466 '^','=', 0, TOK_XOR_ASSIGN,
13467 '+','+', 0, TOK_POST_INC,
13468 '*','*', 0, TOK_EXPONENT,
13472 '=', 0, TOK_ASSIGN,
13484 '?', 0, TOK_CONDITIONAL,
13485 ':', 0, TOK_CONDITIONAL_SEP,
13486 ')', 0, TOK_RPAREN,
13487 '(', 0, TOK_LPAREN,
13491 #define endexpression &op_tokens[sizeof(op_tokens)-7]
13494 static arith_t arith (const char *expr, int *perrcode)
13496 register char arithval; /* Current character under analysis */
13497 operator lasttok, op;
13500 const char *p = endexpression;
13503 size_t datasizes = strlen(expr) + 2;
13505 /* Stack of integers */
13506 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
13507 * in any given correct or incorrect expression is left as an exercise to
13509 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
13510 *numstackptr = numstack;
13511 /* Stack of operator tokens */
13512 operator *stack = alloca((datasizes) * sizeof(operator)),
13515 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
13516 *perrcode = errcode = 0;
13519 if ((arithval = *expr) == 0) {
13520 if (p == endexpression) {
13521 /* Null expression. */
13525 /* This is only reached after all tokens have been extracted from the
13526 * input stream. If there are still tokens on the operator stack, they
13527 * are to be applied in order. At the end, there should be a final
13528 * result on the integer stack */
13530 if (expr != endexpression + 1) {
13531 /* If we haven't done so already, */
13532 /* append a closing right paren */
13533 expr = endexpression;
13534 /* and let the loop process it. */
13537 /* At this point, we're done with the expression. */
13538 if (numstackptr != numstack+1) {
13539 /* ... but if there isn't, it's bad */
13541 return (*perrcode = -1);
13543 if(numstack->var) {
13544 /* expression is $((var)) only, lookup now */
13545 errcode = arith_lookup_val(numstack);
13548 *perrcode = errcode;
13549 return numstack->val;
13551 /* Continue processing the expression. */
13552 if (arith_isspace(arithval)) {
13553 /* Skip whitespace */
13556 if((p = endofname(expr)) != expr) {
13557 size_t var_name_size = (p-expr) + 1; /* trailing zero */
13559 numstackptr->var = alloca(var_name_size);
13560 safe_strncpy(numstackptr->var, expr, var_name_size);
13563 numstackptr->contidional_second_val_initialized = 0;
13567 } else if (is_digit(arithval)) {
13568 numstackptr->var = NULL;
13569 #ifdef CONFIG_ASH_MATH_SUPPORT_64
13570 numstackptr->val = strtoll(expr, (char **) &expr, 0);
13572 numstackptr->val = strtol(expr, (char **) &expr, 0);
13576 for(p = op_tokens; ; p++) {
13580 /* strange operator not found */
13583 for(o = expr; *p && *o == *p; p++)
13590 /* skip tail uncompared token */
13593 /* skip zero delim */
13598 /* post grammar: a++ reduce to num */
13599 if(lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13602 /* Plus and minus are binary (not unary) _only_ if the last
13603 * token was as number, or a right paren (which pretends to be
13604 * a number, since it evaluates to one). Think about it.
13605 * It makes sense. */
13606 if (lasttok != TOK_NUM) {
13622 /* We don't want a unary operator to cause recursive descent on the
13623 * stack, because there can be many in a row and it could cause an
13624 * operator to be evaluated before its argument is pushed onto the
13625 * integer stack. */
13626 /* But for binary operators, "apply" everything on the operator
13627 * stack until we find an operator with a lesser priority than the
13628 * one we have just extracted. */
13629 /* Left paren is given the lowest priority so it will never be
13630 * "applied" in this way.
13631 * if associativity is right and priority eq, applied also skip
13634 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13635 /* not left paren or unary */
13636 if (lasttok != TOK_NUM) {
13637 /* binary op must be preceded by a num */
13640 while (stackptr != stack) {
13641 if (op == TOK_RPAREN) {
13642 /* The algorithm employed here is simple: while we don't
13643 * hit an open paren nor the bottom of the stack, pop
13644 * tokens and apply them */
13645 if (stackptr[-1] == TOK_LPAREN) {
13647 /* Any operator directly after a */
13649 /* close paren should consider itself binary */
13653 operator prev_prec = PREC(stackptr[-1]);
13655 convert_prec_is_assing(prec);
13656 convert_prec_is_assing(prev_prec);
13657 if (prev_prec < prec)
13659 /* check right assoc */
13660 if(prev_prec == prec && is_right_associativity(prec))
13663 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13664 if(errcode) goto ret;
13666 if (op == TOK_RPAREN) {
13671 /* Push this operator to the stack and remember it. */
13672 *stackptr++ = lasttok = op;
13679 #endif /* CONFIG_ASH_MATH_SUPPORT */
13683 const char *bb_applet_name = "debug stuff usage";
13684 int main(int argc, char **argv)
13686 return ash_main(argc, argv);
13691 * Copyright (c) 1989, 1991, 1993, 1994
13692 * The Regents of the University of California. All rights reserved.
13694 * This code is derived from software contributed to Berkeley by
13695 * Kenneth Almquist.
13697 * Redistribution and use in source and binary forms, with or without
13698 * modification, are permitted provided that the following conditions
13700 * 1. Redistributions of source code must retain the above copyright
13701 * notice, this list of conditions and the following disclaimer.
13702 * 2. Redistributions in binary form must reproduce the above copyright
13703 * notice, this list of conditions and the following disclaimer in the
13704 * documentation and/or other materials provided with the distribution.
13705 * 3. Neither the name of the University nor the names of its contributors
13706 * may be used to endorse or promote products derived from this software
13707 * without specific prior written permission.
13709 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13710 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13711 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13712 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13713 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13714 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13715 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13716 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13717 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13718 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF