1 /* vi: set sw=4 ts=4: */
3 * ash shell port for busybox
5 * Copyright (c) 1989, 1991, 1993, 1994
6 * The Regents of the University of California. All rights reserved.
8 * Copyright (c) 1997-2003 Herbert Xu <herbert@debian.org>
9 * was re-ported from NetBSD and debianized.
12 * This code is derived from software contributed to Berkeley by
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 * Original BSD copyright notice is retained at the end of this file.
33 * rewrite arith.y to micro stack based cryptic algorithm by
34 * Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
36 * Modified by Paul Mundt <lethal@linux-sh.org> (c) 2004 to support
39 * Modified by Vladimir Oleynik <dzo@simtreas.ru> (c) 2001-2004 to be
40 * used in busybox and size optimizations,
41 * rewrote arith (see notes to this), added locale support,
42 * rewrote dynamic variables.
48 * The follow should be set to reflect the type of system you have:
49 * JOBS -> 1 if you have Berkeley job control, 0 otherwise.
50 * define SYSV if you are running under System V.
51 * define DEBUG=1 to compile in debugging ('set -o debug' to turn on)
52 * define DEBUG=2 to compile in and turn on debugging.
54 * When debugging is on, debugging info will be written to ./trace and
55 * a quit signal will generate a core dump.
68 #include <sys/types.h>
69 #include <sys/cdefs.h>
70 #include <sys/ioctl.h>
71 #include <sys/param.h>
72 #include <sys/resource.h>
102 #ifdef CONFIG_ASH_JOB_CONTROL
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 static char basebuf[IBUFSIZ]; /* 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.)
2548 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
2549 if (!(rootshell && iflag)) {
2550 signal(SIGINT, SIG_DFL);
2560 exvwarning(const char *msg, va_list ap)
2565 fprintf(errs, "%s: ", arg0);
2567 const char *fmt = (!iflag || parsefile->fd) ?
2568 "%s: %d: " : "%s: ";
2569 fprintf(errs, fmt, commandname, startlinno);
2571 vfprintf(errs, msg, ap);
2572 outcslow('\n', errs);
2576 * Exverror is called to raise the error exception. If the second argument
2577 * is not NULL then error prints an error message using printf style
2578 * formatting. It then raises the error exception.
2581 exverror(int cond, const char *msg, va_list ap)
2585 TRACE(("exverror(%d, \"", cond));
2587 TRACE(("\") pid=%d\n", getpid()));
2589 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
2592 exvwarning(msg, ap);
2601 error(const char *msg, ...)
2606 exverror(EXERROR, msg, ap);
2613 exerror(int cond, const char *msg, ...)
2618 exverror(cond, msg, ap);
2624 * error/warning routines for external builtins
2628 sh_warnx(const char *fmt, ...)
2633 exvwarning(fmt, ap);
2639 * Return a string describing an error. The returned string may be a
2640 * pointer to a static buffer that will be overwritten on the next call.
2641 * Action describes the operation that got the error.
2645 errmsg(int e, const char *em)
2647 if(e == ENOENT || e == ENOTDIR) {
2655 /* $NetBSD: eval.c,v 1.71 2003/01/23 03:33:16 rafal Exp $ */
2658 * Evaluate a command.
2661 /* flags in argument to evaltree */
2662 #define EV_EXIT 01 /* exit after evaluating tree */
2663 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2664 #define EV_BACKCMD 04 /* command executing within back quotes */
2667 static void evalloop(union node *, int);
2668 static void evalfor(union node *, int);
2669 static void evalcase(union node *, int);
2670 static void evalsubshell(union node *, int);
2671 static void expredir(union node *);
2672 static void evalpipe(union node *, int);
2673 static void evalcommand(union node *, int);
2674 static int evalbltin(const struct builtincmd *, int, char **);
2675 static int evalfun(struct funcnode *, int, char **, int);
2676 static void prehash(union node *);
2677 static int bltincmd(int, char **);
2680 static const struct builtincmd bltin = {
2686 * Called to reset things after an exception.
2694 evalcmd(int argc, char **argv)
2703 STARTSTACKSTR(concat);
2706 concat = stputs(p, concat);
2707 if ((p = *ap++) == NULL)
2709 STPUTC(' ', concat);
2711 STPUTC('\0', concat);
2712 p = grabstackstr(concat);
2721 * Execute a command or commands contained in a string.
2728 struct stackmark smark;
2730 setstackmark(&smark);
2733 while ((n = parsecmd(0)) != NEOF) {
2735 popstackmark(&smark);
2740 popstackmark(&smark);
2746 * Evaluate a parse tree. The value is left in the global variable
2751 evaltree(union node *n, int flags)
2754 void (*evalfn)(union node *, int);
2758 TRACE(("evaltree(NULL) called\n"));
2761 TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
2762 getpid(), n, n->type, flags));
2766 out1fmt("Node type = %d\n", n->type);
2771 evaltree(n->nnot.com, EV_TESTED);
2772 status = !exitstatus;
2775 expredir(n->nredir.redirect);
2776 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
2778 evaltree(n->nredir.n, flags & EV_TESTED);
2779 status = exitstatus;
2784 evalfn = evalcommand;
2786 if (eflag && !(flags & EV_TESTED))
2798 evalfn = evalsubshell;
2810 #error NAND + 1 != NOR
2812 #if NOR + 1 != NSEMI
2813 #error NOR + 1 != NSEMI
2815 isor = n->type - NAND;
2818 (flags | ((isor >> 1) - 1)) & EV_TESTED
2820 if (!exitstatus == isor)
2832 evaltree(n->nif.test, EV_TESTED);
2835 if (exitstatus == 0) {
2838 } else if (n->nif.elsepart) {
2839 n = n->nif.elsepart;
2844 defun(n->narg.text, n->narg.next);
2848 exitstatus = status;
2854 if (flags & EV_EXIT || checkexit & exitstatus)
2859 #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
2862 void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
2866 evalloop(union node *n, int flags)
2876 evaltree(n->nbinary.ch1, EV_TESTED);
2878 skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
2882 if (evalskip == SKIPBREAK && --skipcount <= 0)
2887 if (n->type != NWHILE)
2891 evaltree(n->nbinary.ch2, flags);
2892 status = exitstatus;
2897 exitstatus = status;
2903 evalfor(union node *n, int flags)
2905 struct arglist arglist;
2908 struct stackmark smark;
2910 setstackmark(&smark);
2911 arglist.lastp = &arglist.list;
2912 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
2913 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
2918 *arglist.lastp = NULL;
2923 for (sp = arglist.list ; sp ; sp = sp->next) {
2924 setvar(n->nfor.var, sp->text, 0);
2925 evaltree(n->nfor.body, flags);
2927 if (evalskip == SKIPCONT && --skipcount <= 0) {
2931 if (evalskip == SKIPBREAK && --skipcount <= 0)
2938 popstackmark(&smark);
2944 evalcase(union node *n, int flags)
2948 struct arglist arglist;
2949 struct stackmark smark;
2951 setstackmark(&smark);
2952 arglist.lastp = &arglist.list;
2953 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
2955 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2956 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
2957 if (casematch(patp, arglist.list->text)) {
2958 if (evalskip == 0) {
2959 evaltree(cp->nclist.body, flags);
2966 popstackmark(&smark);
2972 * Kick off a subshell to evaluate a tree.
2976 evalsubshell(union node *n, int flags)
2979 int backgnd = (n->type == NBACKGND);
2982 expredir(n->nredir.redirect);
2983 if (!backgnd && flags & EV_EXIT && !trap[0])
2987 if (forkshell(jp, n, backgnd) == 0) {
2991 flags &=~ EV_TESTED;
2993 redirect(n->nredir.redirect, 0);
2994 evaltreenr(n->nredir.n, flags);
2999 status = waitforjob(jp);
3000 exitstatus = status;
3007 * Compute the names of the files in a redirection list.
3011 expredir(union node *n)
3015 for (redir = n ; redir ; redir = redir->nfile.next) {
3017 fn.lastp = &fn.list;
3018 switch (redir->type) {
3024 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
3025 redir->nfile.expfname = fn.list->text;
3029 if (redir->ndup.vname) {
3030 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
3031 fixredir(redir, fn.list->text, 1);
3041 * Evaluate a pipeline. All the processes in the pipeline are children
3042 * of the process creating the pipeline. (This differs from some versions
3043 * of the shell, which make the last process in a pipeline the parent
3048 evalpipe(union node *n, int flags)
3051 struct nodelist *lp;
3056 TRACE(("evalpipe(0x%lx) called\n", (long)n));
3058 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
3062 jp = makejob(n, pipelen);
3064 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
3068 if (pipe(pip) < 0) {
3070 error("Pipe call failed");
3073 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
3086 evaltreenr(lp->n, flags);
3094 if (n->npipe.backgnd == 0) {
3095 exitstatus = waitforjob(jp);
3096 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
3104 * Execute a command inside back quotes. If it's a builtin command, we
3105 * want to save its output in a block obtained from malloc. Otherwise
3106 * we fork off a subprocess and get the output of the command via a pipe.
3107 * Should be called with interrupts off.
3111 evalbackcmd(union node *n, struct backcmd *result)
3123 saveherefd = herefd;
3131 error("Pipe call failed");
3133 if (forkshell(jp, n, FORK_NOJOB) == 0) {
3142 evaltreenr(n, EV_EXIT);
3146 result->fd = pip[0];
3149 herefd = saveherefd;
3151 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
3152 result->fd, result->buf, result->nleft, result->jp));
3155 #ifdef CONFIG_ASH_CMDCMD
3156 static inline char **
3157 parse_command_args(char **argv, const char **path)
3169 if (c == '-' && !*cp) {
3179 /* run 'typecmd' for other options */
3182 } while ((c = *cp++));
3189 isassignment(const char *p)
3191 const char *q = endofname(p);
3197 #ifdef CONFIG_ASH_EXPAND_PRMT
3198 static const char *expandstr(const char *ps);
3200 #define expandstr(s) s
3204 * Execute a simple command.
3208 evalcommand(union node *cmd, int flags)
3210 struct stackmark smark;
3212 struct arglist arglist;
3213 struct arglist varlist;
3216 const struct strlist *sp;
3217 struct cmdentry cmdentry;
3225 struct builtincmd *bcmd;
3226 int pseudovarflag = 0;
3228 /* First expand the arguments. */
3229 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
3230 setstackmark(&smark);
3231 back_exitstatus = 0;
3233 cmdentry.cmdtype = CMDBUILTIN;
3234 cmdentry.u.cmd = &bltin;
3235 varlist.lastp = &varlist.list;
3236 *varlist.lastp = NULL;
3237 arglist.lastp = &arglist.list;
3238 *arglist.lastp = NULL;
3243 bcmd = find_builtin(cmd->ncmd.args->narg.text);
3244 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
3247 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
3248 struct strlist **spp;
3250 spp = arglist.lastp;
3251 if (pseudovarflag && isassignment(argp->narg.text))
3252 expandarg(argp, &arglist, EXP_VARTILDE);
3254 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
3256 for (sp = *spp; sp; sp = sp->next)
3260 argv = nargv = stalloc(sizeof (char *) * (argc + 1));
3261 for (sp = arglist.list ; sp ; sp = sp->next) {
3262 TRACE(("evalcommand arg: %s\n", sp->text));
3263 *nargv++ = sp->text;
3268 if (iflag && funcnest == 0 && argc > 0)
3269 lastarg = nargv[-1];
3272 expredir(cmd->ncmd.redirect);
3273 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH|REDIR_SAVEFD2);
3276 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
3277 struct strlist **spp;
3280 spp = varlist.lastp;
3281 expandarg(argp, &varlist, EXP_VARTILDE);
3284 * Modify the command lookup path, if a PATH= assignment
3288 if (varequal(p, path))
3292 /* Print the command if xflag is set. */
3295 const char *p = " %s";
3298 dprintf(preverrout_fd, p, expandstr(ps4val()));
3301 for(n = 0; n < 2; n++) {
3303 dprintf(preverrout_fd, p, sp->text);
3311 bb_full_write(preverrout_fd, "\n", 1);
3317 /* Now locate the command. */
3319 const char *oldpath;
3320 int cmd_flag = DO_ERR;
3325 find_command(argv[0], &cmdentry, cmd_flag, path);
3326 if (cmdentry.cmdtype == CMDUNKNOWN) {
3332 /* implement bltin and command here */
3333 if (cmdentry.cmdtype != CMDBUILTIN)
3336 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
3337 if (cmdentry.u.cmd == EXECCMD)
3339 #ifdef CONFIG_ASH_CMDCMD
3340 if (cmdentry.u.cmd == COMMANDCMD) {
3343 nargv = parse_command_args(argv, &path);
3346 argc -= nargv - argv;
3348 cmd_flag |= DO_NOFUNC;
3356 /* We have a redirection error. */
3360 exitstatus = status;
3364 /* Execute the command. */
3365 switch (cmdentry.cmdtype) {
3367 /* Fork off a child process if necessary. */
3368 if (!(flags & EV_EXIT) || trap[0]) {
3370 jp = makejob(cmd, 1);
3371 if (forkshell(jp, cmd, FORK_FG) != 0) {
3372 exitstatus = waitforjob(jp);
3378 listsetvar(varlist.list, VEXPORT|VSTACK);
3379 shellexec(argv, path, cmdentry.u.index);
3383 cmdenviron = varlist.list;
3385 struct strlist *list = cmdenviron;
3387 if (spclbltin > 0 || argc == 0) {
3389 if (cmd_is_exec && argc > 1)
3392 listsetvar(list, i);
3394 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
3409 exit_status = j + 128;
3410 exitstatus = exit_status;
3412 if (i == EXINT || spclbltin > 0) {
3414 longjmp(handler->loc, 1);
3421 listsetvar(varlist.list, 0);
3422 if (evalfun(cmdentry.u.func, argc, argv, flags))
3428 popredir(cmd_is_exec);
3430 /* dsl: I think this is intended to be used to support
3431 * '_' in 'vi' command mode during line editing...
3432 * However I implemented that within libedit itself.
3434 setvar("_", lastarg, 0);
3435 popstackmark(&smark);
3439 evalbltin(const struct builtincmd *cmd, int argc, char **argv) {
3440 char *volatile savecmdname;
3441 struct jmploc *volatile savehandler;
3442 struct jmploc jmploc;
3445 savecmdname = commandname;
3446 if ((i = setjmp(jmploc.loc)))
3448 savehandler = handler;
3450 commandname = argv[0];
3452 optptr = NULL; /* initialize nextopt */
3453 exitstatus = (*cmd->builtin)(argc, argv);
3456 exitstatus |= ferror(stdout);
3457 commandname = savecmdname;
3459 handler = savehandler;
3465 evalfun(struct funcnode *func, int argc, char **argv, int flags)
3467 volatile struct shparam saveparam;
3468 struct localvar *volatile savelocalvars;
3469 struct jmploc *volatile savehandler;
3470 struct jmploc jmploc;
3473 saveparam = shellparam;
3474 savelocalvars = localvars;
3475 if ((e = setjmp(jmploc.loc))) {
3479 savehandler = handler;
3482 shellparam.malloc = 0;
3485 shellparam.nparam = argc - 1;
3486 shellparam.p = argv + 1;
3487 #ifdef CONFIG_ASH_GETOPTS
3488 shellparam.optind = 1;
3489 shellparam.optoff = -1;
3492 evaltree(&func->n, flags & EV_TESTED);
3498 localvars = savelocalvars;
3499 freeparam(&shellparam);
3500 shellparam = saveparam;
3501 handler = savehandler;
3503 if (evalskip == SKIPFUNC) {
3512 goodname(const char *p)
3514 return !*endofname(p);
3518 * Search for a command. This is called before we fork so that the
3519 * location of the command will be available in the parent as well as
3520 * the child. The check for "goodname" is an overly conservative
3521 * check that the name will not be subject to expansion.
3525 prehash(union node *n)
3527 struct cmdentry entry;
3529 if (n->type == NCMD && n->ncmd.args)
3530 if (goodname(n->ncmd.args->narg.text))
3531 find_command(n->ncmd.args->narg.text, &entry, 0,
3538 * Builtin commands. Builtin commands whose functions are closely
3539 * tied to evaluation are implemented here.
3547 bltincmd(int argc, char **argv)
3550 * Preserve exitstatus of a previous possible redirection
3553 return back_exitstatus;
3558 * Handle break and continue commands. Break, continue, and return are
3559 * all handled by setting the evalskip flag. The evaluation routines
3560 * above all check this flag, and if it is set they start skipping
3561 * commands rather than executing them. The variable skipcount is
3562 * the number of loops to break/continue, or the number of function
3563 * levels to return. (The latter is always 1.) It should probably
3564 * be an error to break out of more loops than exist, but it isn't
3565 * in the standard shell so we don't make it one here.
3569 breakcmd(int argc, char **argv)
3571 int n = argc > 1 ? number(argv[1]) : 1;
3574 error(illnum, argv[1]);
3578 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
3586 * The return command.
3590 returncmd(int argc, char **argv)
3592 int ret = argc > 1 ? number(argv[1]) : exitstatus;
3595 evalskip = SKIPFUNC;
3600 /* Do what ksh does; skip the rest of the file */
3601 evalskip = SKIPFILE;
3609 falsecmd(int argc, char **argv)
3616 truecmd(int argc, char **argv)
3623 execcmd(int argc, char **argv)
3626 iflag = 0; /* exit on error */
3629 shellexec(argv + 1, pathval(), 0);
3635 /* $NetBSD: exec.c,v 1.35 2003/01/22 20:36:04 dsl Exp $ */
3638 * When commands are first encountered, they are entered in a hash table.
3639 * This ensures that a full path search will not have to be done for them
3640 * on each invocation.
3642 * We should investigate converting to a linear search, even though that
3643 * would make the command name "hash" a misnomer.
3646 #define CMDTABLESIZE 31 /* should be prime */
3647 #define ARB 1 /* actual size determined at run time */
3652 struct tblentry *next; /* next entry in hash chain */
3653 union param param; /* definition of builtin function */
3654 short cmdtype; /* index identifying command */
3655 char rehash; /* if set, cd done since entry created */
3656 char cmdname[ARB]; /* name of command */
3660 static struct tblentry *cmdtable[CMDTABLESIZE];
3661 static int builtinloc = -1; /* index in path of %builtin, or -1 */
3664 static void tryexec(char *, char **, char **);
3665 static void clearcmdentry(int);
3666 static struct tblentry *cmdlookup(const char *, int);
3667 static void delete_cmd_entry(void);
3671 * Exec a program. Never returns. If you change this routine, you may
3672 * have to change the find_command routine as well.
3676 shellexec(char **argv, const char *path, int idx)
3683 envp = environment();
3684 if (strchr(argv[0], '/') != NULL
3685 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3686 || find_applet_by_name(argv[0])
3689 tryexec(argv[0], argv, envp);
3693 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3694 if (--idx < 0 && pathopt == NULL) {
3695 tryexec(cmdname, argv, envp);
3696 if (errno != ENOENT && errno != ENOTDIR)
3703 /* Map to POSIX errors */
3715 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
3716 argv[0], e, suppressint ));
3717 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3723 tryexec(char *cmd, char **argv, char **envp)
3726 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3727 if(find_applet_by_name(cmd) != NULL) {
3728 /* re-exec ourselves with the new arguments */
3729 execve("/proc/self/exe",argv,envp);
3730 /* If proc isn't mounted, try hardcoded path to busybox binary*/
3731 execve("/bin/busybox",argv,envp);
3732 /* If they called chroot or otherwise made the binary no longer
3733 * executable, fall through */
3740 execve(cmd, argv, envp);
3741 } while (errno == EINTR);
3743 execve(cmd, argv, envp);
3747 } else if (errno == ENOEXEC) {
3751 for (ap = argv; *ap; ap++)
3753 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
3755 *ap = cmd = (char *)DEFAULT_SHELL;
3758 while ((*ap++ = *argv++))
3768 * Do a path search. The variable path (passed by reference) should be
3769 * set to the start of the path before the first call; padvance will update
3770 * this value as it proceeds. Successive calls to padvance will return
3771 * the possible path expansions in sequence. If an option (indicated by
3772 * a percent sign) appears in the path entry then the global variable
3773 * pathopt will be set to point to it; otherwise pathopt will be set to
3778 padvance(const char **path, const char *name)
3788 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
3789 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
3790 while (stackblocksize() < len)
3794 memcpy(q, start, p - start);
3802 while (*p && *p != ':') p++;
3808 return stalloc(len);
3812 /*** Command hashing code ***/
3815 printentry(struct tblentry *cmdp)
3821 idx = cmdp->param.index;
3824 name = padvance(&path, cmdp->cmdname);
3826 } while (--idx >= 0);
3827 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
3832 hashcmd(int argc, char **argv)
3834 struct tblentry **pp;
3835 struct tblentry *cmdp;
3837 struct cmdentry entry;
3840 while ((c = nextopt("r")) != '\0') {
3844 if (*argptr == NULL) {
3845 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3846 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3847 if (cmdp->cmdtype == CMDNORMAL)
3854 while ((name = *argptr) != NULL) {
3855 if ((cmdp = cmdlookup(name, 0)) != NULL
3856 && (cmdp->cmdtype == CMDNORMAL
3857 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
3859 find_command(name, &entry, DO_ERR, pathval());
3860 if (entry.cmdtype == CMDUNKNOWN)
3869 * Resolve a command name. If you change this routine, you may have to
3870 * change the shellexec routine as well.
3874 find_command(char *name, struct cmdentry *entry, int act, const char *path)
3876 struct tblentry *cmdp;
3883 struct builtincmd *bcmd;
3885 /* If name contains a slash, don't use PATH or hash table */
3886 if (strchr(name, '/') != NULL) {
3887 entry->u.index = -1;
3889 while (stat(name, &statb) < 0) {
3894 entry->cmdtype = CMDUNKNOWN;
3898 entry->cmdtype = CMDNORMAL;
3902 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3903 if (find_applet_by_name(name)) {
3904 entry->cmdtype = CMDNORMAL;
3905 entry->u.index = -1;
3910 updatetbl = (path == pathval());
3913 if (strstr(path, "%builtin") != NULL)
3917 /* If name is in the table, check answer will be ok */
3918 if ((cmdp = cmdlookup(name, 0)) != NULL) {
3921 switch (cmdp->cmdtype) {
3939 } else if (cmdp->rehash == 0)
3940 /* if not invalidated by cd, we're done */
3944 /* If %builtin not in path, check for builtin next */
3945 bcmd = find_builtin(name);
3946 if (bcmd && (IS_BUILTIN_REGULAR(bcmd) || (
3947 act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0
3949 goto builtin_success;
3951 /* We have to search path. */
3952 prev = -1; /* where to start */
3953 if (cmdp && cmdp->rehash) { /* doing a rehash */
3954 if (cmdp->cmdtype == CMDBUILTIN)
3957 prev = cmdp->param.index;
3963 while ((fullname = padvance(&path, name)) != NULL) {
3964 stunalloc(fullname);
3967 if (prefix(pathopt, "builtin")) {
3969 goto builtin_success;
3971 } else if (!(act & DO_NOFUNC) &&
3972 prefix(pathopt, "func")) {
3975 /* ignore unimplemented options */
3979 /* if rehash, don't redo absolute path names */
3980 if (fullname[0] == '/' && idx <= prev) {
3983 TRACE(("searchexec \"%s\": no change\n", name));
3986 while (stat(fullname, &statb) < 0) {
3991 if (errno != ENOENT && errno != ENOTDIR)
3995 e = EACCES; /* if we fail, this will be the error */
3996 if (!S_ISREG(statb.st_mode))
3998 if (pathopt) { /* this is a %func directory */
3999 stalloc(strlen(fullname) + 1);
4000 readcmdfile(fullname);
4001 if ((cmdp = cmdlookup(name, 0)) == NULL ||
4002 cmdp->cmdtype != CMDFUNCTION)
4003 error("%s not defined in %s", name, fullname);
4004 stunalloc(fullname);
4007 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
4009 entry->cmdtype = CMDNORMAL;
4010 entry->u.index = idx;
4014 cmdp = cmdlookup(name, 1);
4015 cmdp->cmdtype = CMDNORMAL;
4016 cmdp->param.index = idx;
4021 /* We failed. If there was an entry for this command, delete it */
4022 if (cmdp && updatetbl)
4025 sh_warnx("%s: %s", name, errmsg(e, E_EXEC));
4026 entry->cmdtype = CMDUNKNOWN;
4031 entry->cmdtype = CMDBUILTIN;
4032 entry->u.cmd = bcmd;
4036 cmdp = cmdlookup(name, 1);
4037 cmdp->cmdtype = CMDBUILTIN;
4038 cmdp->param.cmd = bcmd;
4042 entry->cmdtype = cmdp->cmdtype;
4043 entry->u = cmdp->param;
4048 * Wrapper around strcmp for qsort/bsearch/...
4050 static int pstrcmp(const void *a, const void *b)
4052 return strcmp((const char *) a, (*(const char *const *) b) + 1);
4056 * Search the table of builtin commands.
4059 static struct builtincmd *
4060 find_builtin(const char *name)
4062 struct builtincmd *bp;
4065 name, builtincmd, NUMBUILTINS, sizeof(struct builtincmd),
4074 * Called when a cd is done. Marks all commands so the next time they
4075 * are executed they will be rehashed.
4081 struct tblentry **pp;
4082 struct tblentry *cmdp;
4084 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4085 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4086 if (cmdp->cmdtype == CMDNORMAL || (
4087 cmdp->cmdtype == CMDBUILTIN &&
4088 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) &&
4099 * Fix command hash table when PATH changed.
4100 * Called before PATH is changed. The argument is the new value of PATH;
4101 * pathval() still returns the old value at this point.
4102 * Called with interrupts off.
4106 changepath(const char *newval)
4108 const char *old, *new;
4115 firstchange = 9999; /* assume no change */
4121 if ((*old == '\0' && *new == ':')
4122 || (*old == ':' && *new == '\0'))
4124 old = new; /* ignore subsequent differences */
4128 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
4135 if (builtinloc < 0 && idx_bltin >= 0)
4136 builtinloc = idx_bltin; /* zap builtins */
4137 if (builtinloc >= 0 && idx_bltin < 0)
4139 clearcmdentry(firstchange);
4140 builtinloc = idx_bltin;
4145 * Clear out command entries. The argument specifies the first entry in
4146 * PATH which has changed.
4150 clearcmdentry(int firstchange)
4152 struct tblentry **tblp;
4153 struct tblentry **pp;
4154 struct tblentry *cmdp;
4157 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4159 while ((cmdp = *pp) != NULL) {
4160 if ((cmdp->cmdtype == CMDNORMAL &&
4161 cmdp->param.index >= firstchange)
4162 || (cmdp->cmdtype == CMDBUILTIN &&
4163 builtinloc >= firstchange)) {
4177 * Locate a command in the command hash table. If "add" is nonzero,
4178 * add the command to the table if it is not already present. The
4179 * variable "lastcmdentry" is set to point to the address of the link
4180 * pointing to the entry, so that delete_cmd_entry can delete the
4183 * Interrupts must be off if called with add != 0.
4186 static struct tblentry **lastcmdentry;
4189 static struct tblentry *
4190 cmdlookup(const char *name, int add)
4192 unsigned int hashval;
4194 struct tblentry *cmdp;
4195 struct tblentry **pp;
4198 hashval = (unsigned char)*p << 4;
4200 hashval += (unsigned char)*p++;
4202 pp = &cmdtable[hashval % CMDTABLESIZE];
4203 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4204 if (equal(cmdp->cmdname, name))
4208 if (add && cmdp == NULL) {
4209 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4210 + strlen(name) + 1);
4212 cmdp->cmdtype = CMDUNKNOWN;
4213 strcpy(cmdp->cmdname, name);
4220 * Delete the command entry returned on the last lookup.
4224 delete_cmd_entry(void)
4226 struct tblentry *cmdp;
4229 cmdp = *lastcmdentry;
4230 *lastcmdentry = cmdp->next;
4231 if (cmdp->cmdtype == CMDFUNCTION)
4232 freefunc(cmdp->param.func);
4239 * Add a new command entry, replacing any existing command entry for
4240 * the same name - except special builtins.
4244 addcmdentry(char *name, struct cmdentry *entry)
4246 struct tblentry *cmdp;
4248 cmdp = cmdlookup(name, 1);
4249 if (cmdp->cmdtype == CMDFUNCTION) {
4250 freefunc(cmdp->param.func);
4252 cmdp->cmdtype = entry->cmdtype;
4253 cmdp->param = entry->u;
4258 * Make a copy of a parse tree.
4261 static inline struct funcnode *
4262 copyfunc(union node *n)
4267 funcblocksize = offsetof(struct funcnode, n);
4270 blocksize = funcblocksize;
4271 f = ckmalloc(blocksize + funcstringsize);
4272 funcblock = (char *) f + offsetof(struct funcnode, n);
4273 funcstring = (char *) f + blocksize;
4280 * Define a shell function.
4284 defun(char *name, union node *func)
4286 struct cmdentry entry;
4289 entry.cmdtype = CMDFUNCTION;
4290 entry.u.func = copyfunc(func);
4291 addcmdentry(name, &entry);
4297 * Delete a function if it exists.
4301 unsetfunc(const char *name)
4303 struct tblentry *cmdp;
4305 if ((cmdp = cmdlookup(name, 0)) != NULL &&
4306 cmdp->cmdtype == CMDFUNCTION)
4311 * Locate and print what a word is...
4315 #ifdef CONFIG_ASH_CMDCMD
4317 describe_command(char *command, int describe_command_verbose)
4319 #define describe_command_verbose 1
4321 describe_command(char *command)
4324 struct cmdentry entry;
4325 struct tblentry *cmdp;
4326 #ifdef CONFIG_ASH_ALIAS
4327 const struct alias *ap;
4329 const char *path = pathval();
4331 if (describe_command_verbose) {
4335 /* First look at the keywords */
4336 if (findkwd(command)) {
4337 out1str(describe_command_verbose ? " is a shell keyword" : command);
4341 #ifdef CONFIG_ASH_ALIAS
4342 /* Then look at the aliases */
4343 if ((ap = lookupalias(command, 0)) != NULL) {
4344 if (describe_command_verbose) {
4345 out1fmt(" is an alias for %s", ap->val);
4354 /* Then check if it is a tracked alias */
4355 if ((cmdp = cmdlookup(command, 0)) != NULL) {
4356 entry.cmdtype = cmdp->cmdtype;
4357 entry.u = cmdp->param;
4359 /* Finally use brute force */
4360 find_command(command, &entry, DO_ABS, path);
4363 switch (entry.cmdtype) {
4365 int j = entry.u.index;
4371 p = padvance(&path, command);
4375 if (describe_command_verbose) {
4377 (cmdp ? " a tracked alias for" : nullstr), p
4386 if (describe_command_verbose) {
4387 out1str(" is a shell function");
4394 if (describe_command_verbose) {
4395 out1fmt(" is a %sshell builtin",
4396 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
4397 "special " : nullstr
4405 if (describe_command_verbose) {
4406 out1str(": not found\n");
4412 outstr("\n", stdout);
4417 typecmd(int argc, char **argv)
4422 for (i = 1; i < argc; i++) {
4423 #ifdef CONFIG_ASH_CMDCMD
4424 err |= describe_command(argv[i], 1);
4426 err |= describe_command(argv[i]);
4432 #ifdef CONFIG_ASH_CMDCMD
4434 commandcmd(int argc, char **argv)
4437 int default_path = 0;
4438 int verify_only = 0;
4439 int verbose_verify_only = 0;
4441 while ((c = nextopt("pvV")) != '\0')
4446 "command: nextopt returned character code 0%o\n", c);
4456 verbose_verify_only = 1;
4460 if (default_path + verify_only + verbose_verify_only > 1 ||
4463 "command [-p] command [arg ...]\n"
4464 "command {-v|-V} command\n");
4468 if (verify_only || verbose_verify_only) {
4469 return describe_command(*argptr, verbose_verify_only);
4476 /* $NetBSD: expand.c,v 1.56 2002/11/24 22:35:39 christos Exp $ */
4479 * Routines to expand arguments to commands. We have to deal with
4480 * backquotes, shell variables, and file metacharacters.
4486 #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4487 #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
4488 #define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
4489 #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
4490 #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
4493 * Structure specifying which parts of the string should be searched
4494 * for IFS characters.
4498 struct ifsregion *next; /* next region in list */
4499 int begoff; /* offset of start of region */
4500 int endoff; /* offset of end of region */
4501 int nulonly; /* search for nul bytes only */
4504 /* output of current string */
4505 static char *expdest;
4506 /* list of back quote expressions */
4507 static struct nodelist *argbackq;
4508 /* first struct in list of ifs regions */
4509 static struct ifsregion ifsfirst;
4510 /* last struct in list */
4511 static struct ifsregion *ifslastp;
4512 /* holds expanded arg list */
4513 static struct arglist exparg;
4515 static void argstr(char *, int);
4516 static char *exptilde(char *, char *, int);
4517 static void expbackq(union node *, int, int);
4518 static const char *subevalvar(char *, char *, int, int, int, int, int);
4519 static char *evalvar(char *, int);
4520 static void strtodest(const char *, int, int);
4521 static void memtodest(const char *p, size_t len, int syntax, int quotes);
4522 static ssize_t varvalue(char *, int, int);
4523 static void recordregion(int, int, int);
4524 static void removerecordregions(int);
4525 static void ifsbreakup(char *, struct arglist *);
4526 static void ifsfree(void);
4527 static void expandmeta(struct strlist *, int);
4528 static int patmatch(char *, const char *);
4530 static int cvtnum(arith_t);
4531 static size_t esclen(const char *, const char *);
4532 static char *scanleft(char *, char *, char *, char *, int, int);
4533 static char *scanright(char *, char *, char *, char *, int, int);
4534 static void varunset(const char *, const char *, const char *, int)
4535 __attribute__((__noreturn__));
4538 #define pmatch(a, b) !fnmatch((a), (b), 0)
4540 * Prepare a pattern for a expmeta (internal glob(3)) call.
4542 * Returns an stalloced string.
4545 static inline char *
4546 preglob(const char *pattern, int quoted, int flag) {
4547 flag |= RMESCAPE_GLOB;
4549 flag |= RMESCAPE_QUOTED;
4551 return _rmescapes((char *)pattern, flag);
4556 esclen(const char *start, const char *p) {
4559 while (p > start && *--p == CTLESC) {
4567 * Expand shell variables and backquotes inside a here document.
4571 expandhere(union node *arg, int fd)
4574 expandarg(arg, (struct arglist *)NULL, 0);
4575 bb_full_write(fd, stackblock(), expdest - (char *)stackblock());
4580 * Perform variable substitution and command substitution on an argument,
4581 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4582 * perform splitting and file name expansion. When arglist is NULL, perform
4583 * here document expansion.
4587 expandarg(union node *arg, struct arglist *arglist, int flag)
4592 argbackq = arg->narg.backquote;
4593 STARTSTACKSTR(expdest);
4594 ifsfirst.next = NULL;
4596 argstr(arg->narg.text, flag);
4597 p = _STPUTC('\0', expdest);
4599 if (arglist == NULL) {
4600 return; /* here document expanded */
4602 p = grabstackstr(p);
4603 exparg.lastp = &exparg.list;
4607 if (flag & EXP_FULL) {
4608 ifsbreakup(p, &exparg);
4609 *exparg.lastp = NULL;
4610 exparg.lastp = &exparg.list;
4611 expandmeta(exparg.list, flag);
4613 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
4615 sp = (struct strlist *)stalloc(sizeof (struct strlist));
4618 exparg.lastp = &sp->next;
4622 *exparg.lastp = NULL;
4624 *arglist->lastp = exparg.list;
4625 arglist->lastp = exparg.lastp;
4631 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4632 * characters to allow for further processing. Otherwise treat
4633 * $@ like $* since no splitting will be performed.
4637 argstr(char *p, int flag)
4639 static const char spclchars[] = {
4647 CTLBACKQ | CTLQUOTE,
4648 #ifdef CONFIG_ASH_MATH_SUPPORT
4653 const char *reject = spclchars;
4655 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
4656 int breakall = flag & EXP_WORD;
4661 if (!(flag & EXP_VARTILDE)) {
4663 } else if (flag & EXP_VARTILDE2) {
4668 if (flag & EXP_TILDE) {
4674 if (*q == CTLESC && (flag & EXP_QWORD))
4677 p = exptilde(p, q, flag);
4680 startloc = expdest - (char *)stackblock();
4682 length += strcspn(p + length, reject);
4684 if (c && (!(c & 0x80)
4685 #ifdef CONFIG_ASH_MATH_SUPPORT
4689 /* c == '=' || c == ':' || c == CTLENDARI */
4694 expdest = stnputs(p, length, expdest);
4695 newloc = expdest - (char *)stackblock();
4696 if (breakall && !inquotes && newloc > startloc) {
4697 recordregion(startloc, newloc, 0);
4708 if (flag & EXP_VARTILDE2) {
4712 flag |= EXP_VARTILDE2;
4717 * sort of a hack - expand tildes in variable
4718 * assignments (after the first '=' and after ':'s).
4727 case CTLENDVAR: /* ??? */
4730 /* "$@" syntax adherence hack */
4733 !memcmp(p, dolatstr, DOLATSTRLEN) &&
4734 (p[4] == CTLQUOTEMARK || (
4735 p[4] == CTLENDVAR &&
4736 p[5] == CTLQUOTEMARK
4739 p = evalvar(p + 1, flag) + 1;
4742 inquotes = !inquotes;
4755 p = evalvar(p, flag);
4759 case CTLBACKQ|CTLQUOTE:
4760 expbackq(argbackq->n, c, quotes);
4761 argbackq = argbackq->next;
4763 #ifdef CONFIG_ASH_MATH_SUPPORT
4776 exptilde(char *startp, char *p, int flag)
4782 int quotes = flag & (EXP_FULL | EXP_CASE);
4787 while ((c = *++p) != '\0') {
4794 if (flag & EXP_VARTILDE)
4804 if (*name == '\0') {
4805 if ((home = lookupvar(homestr)) == NULL)
4808 if ((pw = getpwnam(name)) == NULL)
4815 startloc = expdest - (char *)stackblock();
4816 strtodest(home, SQSYNTAX, quotes);
4817 recordregion(startloc, expdest - (char *)stackblock(), 0);
4826 removerecordregions(int endoff)
4828 if (ifslastp == NULL)
4831 if (ifsfirst.endoff > endoff) {
4832 while (ifsfirst.next != NULL) {
4833 struct ifsregion *ifsp;
4835 ifsp = ifsfirst.next->next;
4836 ckfree(ifsfirst.next);
4837 ifsfirst.next = ifsp;
4840 if (ifsfirst.begoff > endoff)
4843 ifslastp = &ifsfirst;
4844 ifsfirst.endoff = endoff;
4849 ifslastp = &ifsfirst;
4850 while (ifslastp->next && ifslastp->next->begoff < endoff)
4851 ifslastp=ifslastp->next;
4852 while (ifslastp->next != NULL) {
4853 struct ifsregion *ifsp;
4855 ifsp = ifslastp->next->next;
4856 ckfree(ifslastp->next);
4857 ifslastp->next = ifsp;
4860 if (ifslastp->endoff > endoff)
4861 ifslastp->endoff = endoff;
4865 #ifdef CONFIG_ASH_MATH_SUPPORT
4867 * Expand arithmetic expression. Backup to start of expression,
4868 * evaluate, place result in (backed up) result, adjust string position.
4881 * This routine is slightly over-complicated for
4882 * efficiency. Next we scan backwards looking for the
4883 * start of arithmetic.
4885 start = stackblock();
4892 while (*p != CTLARI) {
4896 error("missing CTLARI (shouldn't happen)");
4901 esc = esclen(start, p);
4911 removerecordregions(begoff);
4920 len = cvtnum(dash_arith(p + 2));
4923 recordregion(begoff, begoff + len, 0);
4928 * Expand stuff in backwards quotes.
4932 expbackq(union node *cmd, int quoted, int quotes)
4940 int syntax = quoted? DQSYNTAX : BASESYNTAX;
4941 struct stackmark smark;
4944 setstackmark(&smark);
4946 startloc = dest - (char *)stackblock();
4948 evalbackcmd(cmd, (struct backcmd *) &in);
4949 popstackmark(&smark);
4956 memtodest(p, i, syntax, quotes);
4960 i = safe_read(in.fd, buf, sizeof buf);
4961 TRACE(("expbackq: read returns %d\n", i));
4971 back_exitstatus = waitforjob(in.jp);
4975 /* Eat all trailing newlines */
4977 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
4982 recordregion(startloc, dest - (char *)stackblock(), 0);
4983 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4984 (dest - (char *)stackblock()) - startloc,
4985 (dest - (char *)stackblock()) - startloc,
4986 stackblock() + startloc));
4991 scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5002 const char *s = loc2;
5008 match = pmatch(str, s);
5012 if (quotes && *loc == CTLESC)
5022 scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5029 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5032 const char *s = loc2;
5037 match = pmatch(str, s);
5044 esc = esclen(startp, loc);
5056 subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
5060 int saveherefd = herefd;
5061 struct nodelist *saveargbackq = argbackq;
5063 char *rmesc, *rmescend;
5065 char *(*scan)(char *, char *, char *, char *, int , int);
5068 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
5069 STPUTC('\0', expdest);
5070 herefd = saveherefd;
5071 argbackq = saveargbackq;
5072 startp = stackblock() + startloc;
5076 setvar(str, startp, 0);
5077 amount = startp - expdest;
5078 STADJUST(amount, expdest);
5082 varunset(p, str, startp, varflags);
5086 subtype -= VSTRIMRIGHT;
5088 if (subtype < 0 || subtype > 3)
5093 rmescend = stackblock() + strloc;
5095 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5096 if (rmesc != startp) {
5098 startp = stackblock() + startloc;
5102 str = stackblock() + strloc;
5103 preglob(str, varflags & VSQUOTE, 0);
5105 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
5106 zero = subtype >> 1;
5107 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
5108 scan = (subtype & 1) ^ zero ? scanleft : scanright;
5110 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
5113 memmove(startp, loc, str - loc);
5114 loc = startp + (str - loc) - 1;
5117 amount = loc - expdest;
5118 STADJUST(amount, expdest);
5125 * Expand a variable, and return a pointer to the next character in the
5129 evalvar(char *p, int flag)
5142 quotes = flag & (EXP_FULL | EXP_CASE);
5144 subtype = varflags & VSTYPE;
5145 quoted = varflags & VSQUOTE;
5147 easy = (!quoted || (*var == '@' && shellparam.nparam));
5148 startloc = expdest - (char *)stackblock();
5149 p = strchr(p, '=') + 1;
5152 varlen = varvalue(var, varflags, flag);
5153 if (varflags & VSNUL)
5156 if (subtype == VSPLUS) {
5157 varlen = -1 - varlen;
5161 if (subtype == VSMINUS) {
5165 p, flag | EXP_TILDE |
5166 (quoted ? EXP_QWORD : EXP_WORD)
5175 if (subtype == VSASSIGN || subtype == VSQUESTION) {
5177 if (subevalvar(p, var, 0, subtype, startloc,
5181 * Remove any recorded regions beyond
5184 removerecordregions(startloc);
5194 if (varlen < 0 && uflag)
5195 varunset(p, var, 0, 0);
5197 if (subtype == VSLENGTH) {
5198 cvtnum(varlen > 0 ? varlen : 0);
5202 if (subtype == VSNORMAL) {
5206 recordregion(startloc, expdest - (char *)stackblock(), quoted);
5215 case VSTRIMRIGHTMAX:
5224 * Terminate the string and start recording the pattern
5227 STPUTC('\0', expdest);
5228 patloc = expdest - (char *)stackblock();
5229 if (subevalvar(p, NULL, patloc, subtype,
5230 startloc, varflags, quotes) == 0) {
5231 int amount = expdest - (
5232 (char *)stackblock() + patloc - 1
5234 STADJUST(-amount, expdest);
5236 /* Remove any recorded regions beyond start of variable */
5237 removerecordregions(startloc);
5242 if (subtype != VSNORMAL) { /* skip to end of alternative */
5245 if ((c = *p++) == CTLESC)
5247 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
5249 argbackq = argbackq->next;
5250 } else if (c == CTLVAR) {
5251 if ((*p++ & VSTYPE) != VSNORMAL)
5253 } else if (c == CTLENDVAR) {
5264 * Put a string on the stack.
5268 memtodest(const char *p, size_t len, int syntax, int quotes) {
5271 q = makestrspace(len * 2, q);
5277 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5287 strtodest(const char *p, int syntax, int quotes)
5289 memtodest(p, strlen(p), syntax, quotes);
5294 * Add the value of a specialized variable to the stack string.
5298 varvalue(char *name, int varflags, int flags)
5308 int quoted = varflags & VSQUOTE;
5309 int subtype = varflags & VSTYPE;
5310 int quotes = flags & (EXP_FULL | EXP_CASE);
5312 if (quoted && (flags & EXP_FULL))
5313 sep = 1 << CHAR_BIT;
5315 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5324 num = shellparam.nparam;
5334 p = makestrspace(NOPTS, expdest);
5335 for (i = NOPTS - 1; i >= 0; i--) {
5337 USTPUTC(optletters(i), p);
5348 sep = ifsset() ? ifsval()[0] : ' ';
5349 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
5352 if (!(ap = shellparam.p))
5354 while ((p = *ap++)) {
5357 partlen = strlen(p);
5360 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5361 memtodest(p, partlen, syntax, quotes);
5367 if (subtype == VSPLUS || subtype == VSLENGTH) {
5389 if (num < 0 || num > shellparam.nparam)
5391 p = num ? shellparam.p[num - 1] : arg0;
5394 p = lookupvar(name);
5400 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5401 memtodest(p, len, syntax, quotes);
5405 if (subtype == VSPLUS || subtype == VSLENGTH)
5406 STADJUST(-len, expdest);
5412 * Record the fact that we have to scan this region of the
5413 * string for IFS characters.
5417 recordregion(int start, int end, int nulonly)
5419 struct ifsregion *ifsp;
5421 if (ifslastp == NULL) {
5425 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
5427 ifslastp->next = ifsp;
5431 ifslastp->begoff = start;
5432 ifslastp->endoff = end;
5433 ifslastp->nulonly = nulonly;
5438 * Break the argument string into pieces based upon IFS and add the
5439 * strings to the argument list. The regions of the string to be
5440 * searched for IFS characters have been stored by recordregion.
5443 ifsbreakup(char *string, struct arglist *arglist)
5445 struct ifsregion *ifsp;
5450 const char *ifs, *realifs;
5456 if (ifslastp != NULL) {
5459 realifs = ifsset() ? ifsval() : defifs;
5462 p = string + ifsp->begoff;
5463 nulonly = ifsp->nulonly;
5464 ifs = nulonly ? nullstr : realifs;
5466 while (p < string + ifsp->endoff) {
5470 if (strchr(ifs, *p)) {
5472 ifsspc = (strchr(defifs, *p) != NULL);
5473 /* Ignore IFS whitespace at start */
5474 if (q == start && ifsspc) {
5480 sp = (struct strlist *)stalloc(sizeof *sp);
5482 *arglist->lastp = sp;
5483 arglist->lastp = &sp->next;
5487 if (p >= string + ifsp->endoff) {
5493 if (strchr(ifs, *p) == NULL ) {
5496 } else if (strchr(defifs, *p) == NULL) {
5512 } while ((ifsp = ifsp->next) != NULL);
5521 sp = (struct strlist *)stalloc(sizeof *sp);
5523 *arglist->lastp = sp;
5524 arglist->lastp = &sp->next;
5530 struct ifsregion *p;
5535 struct ifsregion *ifsp;
5541 ifsfirst.next = NULL;
5545 static void expmeta(char *, char *);
5546 static struct strlist *expsort(struct strlist *);
5547 static struct strlist *msort(struct strlist *, int);
5549 static char *expdir;
5553 expandmeta(struct strlist *str, int flag)
5555 static const char metachars[] = {
5558 /* TODO - EXP_REDIR */
5561 struct strlist **savelastp;
5567 if (!strpbrk(str->text, metachars))
5569 savelastp = exparg.lastp;
5572 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
5574 int i = strlen(str->text);
5575 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5583 if (exparg.lastp == savelastp) {
5588 *exparg.lastp = str;
5589 rmescapes(str->text);
5590 exparg.lastp = &str->next;
5592 *exparg.lastp = NULL;
5593 *savelastp = sp = expsort(*savelastp);
5594 while (sp->next != NULL)
5596 exparg.lastp = &sp->next;
5603 * Add a file name to the list.
5607 addfname(const char *name)
5611 sp = (struct strlist *)stalloc(sizeof *sp);
5612 sp->text = sstrdup(name);
5614 exparg.lastp = &sp->next;
5619 * Do metacharacter (i.e. *, ?, [...]) expansion.
5623 expmeta(char *enddir, char *name)
5638 for (p = name; *p; p++) {
5639 if (*p == '*' || *p == '?')
5641 else if (*p == '[') {
5648 if (*q == '/' || *q == '\0')
5655 } else if (*p == '\\')
5657 else if (*p == '/') {
5664 if (metaflag == 0) { /* we've reached the end of the file name */
5665 if (enddir != expdir)
5673 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
5684 } while (p < start);
5686 if (enddir == expdir) {
5688 } else if (enddir == expdir + 1 && *expdir == '/') {
5694 if ((dirp = opendir(cp)) == NULL)
5696 if (enddir != expdir)
5698 if (*endname == 0) {
5710 while (! intpending && (dp = readdir(dirp)) != NULL) {
5711 if (dp->d_name[0] == '.' && ! matchdot)
5713 if (pmatch(start, dp->d_name)) {
5715 scopy(dp->d_name, enddir);
5718 for (p = enddir, cp = dp->d_name;
5719 (*p++ = *cp++) != '\0';)
5722 expmeta(p, endname);
5732 * Sort the results of file name expansion. It calculates the number of
5733 * strings to sort and then calls msort (short for merge sort) to do the
5737 static struct strlist *
5738 expsort(struct strlist *str)
5744 for (sp = str ; sp ; sp = sp->next)
5746 return msort(str, len);
5750 static struct strlist *
5751 msort(struct strlist *list, int len)
5753 struct strlist *p, *q = NULL;
5754 struct strlist **lpp;
5762 for (n = half ; --n >= 0 ; ) {
5766 q->next = NULL; /* terminate first half of list */
5767 q = msort(list, half); /* sort first half of list */
5768 p = msort(p, len - half); /* sort second half */
5771 #ifdef CONFIG_LOCALE_SUPPORT
5772 if (strcoll(p->text, q->text) < 0)
5774 if (strcmp(p->text, q->text) < 0)
5779 if ((p = *lpp) == NULL) {
5786 if ((q = *lpp) == NULL) {
5797 * Returns true if the pattern matches the string.
5801 patmatch(char *pattern, const char *string)
5803 return pmatch(preglob(pattern, 0, 0), string);
5808 * Remove any CTLESC characters from a string.
5812 _rmescapes(char *str, int flag)
5815 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
5820 p = strpbrk(str, qchars);
5826 if (flag & RMESCAPE_ALLOC) {
5827 size_t len = p - str;
5828 size_t fulllen = len + strlen(p) + 1;
5830 if (flag & RMESCAPE_GROW) {
5831 r = makestrspace(fulllen, expdest);
5832 } else if (flag & RMESCAPE_HEAP) {
5833 r = ckmalloc(fulllen);
5835 r = stalloc(fulllen);
5839 q = mempcpy(q, str, len);
5842 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5843 globbing = flag & RMESCAPE_GLOB;
5844 notescaped = globbing;
5846 if (*p == CTLQUOTEMARK) {
5847 inquotes = ~inquotes;
5849 notescaped = globbing;
5853 /* naked back slash */
5859 if (notescaped && inquotes && *p != '/') {
5863 notescaped = globbing;
5868 if (flag & RMESCAPE_GROW) {
5870 STADJUST(q - r + 1, expdest);
5877 * See if a pattern matches in a case statement.
5881 casematch(union node *pattern, char *val)
5883 struct stackmark smark;
5886 setstackmark(&smark);
5887 argbackq = pattern->narg.backquote;
5888 STARTSTACKSTR(expdest);
5890 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
5891 STACKSTRNUL(expdest);
5892 result = patmatch(stackblock(), val);
5893 popstackmark(&smark);
5906 expdest = makestrspace(32, expdest);
5907 #ifdef CONFIG_ASH_MATH_SUPPORT_64
5908 len = fmtstr(expdest, 32, "%lld", (long long) num);
5910 len = fmtstr(expdest, 32, "%ld", num);
5912 STADJUST(len, expdest);
5917 varunset(const char *end, const char *var, const char *umsg, int varflags)
5923 msg = "parameter not set";
5925 if (*end == CTLENDVAR) {
5926 if (varflags & VSNUL)
5931 error("%.*s: %s%s", end - var - 1, var, msg, tail);
5935 /* $NetBSD: input.c,v 1.37 2002/11/24 22:35:40 christos Exp $ */
5938 * This implements the input routines used by the parser.
5941 #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
5942 #define IBUFSIZ (BUFSIZ + 1)
5944 static void pushfile(void);
5947 * Read a character from the script, returning PEOF on end of file.
5948 * Nul characters in the input are silently discarded.
5951 #define pgetc_as_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
5953 #ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
5954 #define pgetc_macro() pgetc()
5958 return pgetc_as_macro();
5961 #define pgetc_macro() pgetc_as_macro()
5965 return pgetc_macro();
5971 * Same as pgetc(), but ignores PEOA.
5973 #ifdef CONFIG_ASH_ALIAS
5974 static int pgetc2(void)
5980 } while (c == PEOA);
5984 static inline int pgetc2(void)
5986 return pgetc_macro();
5991 * Read a line from the script.
5994 static inline char *
5995 pfgets(char *line, int len)
6001 while (--nleft > 0) {
6018 #ifdef CONFIG_FEATURE_COMMAND_EDITING
6019 #ifdef CONFIG_ASH_EXPAND_PRMT
6020 static char *cmdedit_prompt;
6022 static const char *cmdedit_prompt;
6024 static inline void putprompt(const char *s)
6026 #ifdef CONFIG_ASH_EXPAND_PRMT
6027 free(cmdedit_prompt);
6028 cmdedit_prompt = bb_xstrdup(s);
6034 static inline void putprompt(const char *s)
6044 char *buf = parsefile->buf;
6048 #ifdef CONFIG_FEATURE_COMMAND_EDITING
6049 if (!iflag || parsefile->fd)
6050 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6052 #ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
6053 cmdedit_path_lookup = pathval();
6055 nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
6057 /* Ctrl+C presend */
6066 if(nr < 0 && errno == 0) {
6067 /* Ctrl+D presend */
6072 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6076 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6077 int flags = fcntl(0, F_GETFL, 0);
6078 if (flags >= 0 && flags & O_NONBLOCK) {
6079 flags &=~ O_NONBLOCK;
6080 if (fcntl(0, F_SETFL, flags) >= 0) {
6081 out2str("sh: turning off NDELAY mode\n");
6091 * Refill the input buffer and return the next input character:
6093 * 1) If a string was pushed back on the input, pop it;
6094 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6095 * from a string so we can't refill the buffer, return EOF.
6096 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6097 * 4) Process input up to the next newline, deleting nul characters.
6107 while (parsefile->strpush) {
6108 #ifdef CONFIG_ASH_ALIAS
6109 if (parsenleft == -1 && parsefile->strpush->ap &&
6110 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
6115 if (--parsenleft >= 0)
6116 return (*parsenextc++);
6118 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6123 if (parselleft <= 0) {
6124 if ((parselleft = preadfd()) <= 0) {
6125 parselleft = parsenleft = EOF_NLEFT;
6132 /* delete nul characters */
6133 for (more = 1; more;) {
6140 parsenleft = q - parsenextc;
6141 more = 0; /* Stop processing here */
6148 if (--parselleft <= 0 && more) {
6149 parsenleft = q - parsenextc - 1;
6160 out2str(parsenextc);
6165 return *parsenextc++;
6169 * Undo the last call to pgetc. Only one character may be pushed back.
6170 * PEOF may be pushed back.
6181 * Push a string back onto the input at this current parsefile level.
6182 * We handle aliases this way.
6185 pushstring(char *s, void *ap)
6192 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6193 if (parsefile->strpush) {
6194 sp = ckmalloc(sizeof (struct strpush));
6195 sp->prev = parsefile->strpush;
6196 parsefile->strpush = sp;
6198 sp = parsefile->strpush = &(parsefile->basestrpush);
6199 sp->prevstring = parsenextc;
6200 sp->prevnleft = parsenleft;
6201 #ifdef CONFIG_ASH_ALIAS
6202 sp->ap = (struct alias *)ap;
6204 ((struct alias *)ap)->flag |= ALIASINUSE;
6216 struct strpush *sp = parsefile->strpush;
6219 #ifdef CONFIG_ASH_ALIAS
6221 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6222 checkkwd |= CHKALIAS;
6224 if (sp->string != sp->ap->val) {
6227 sp->ap->flag &= ~ALIASINUSE;
6228 if (sp->ap->flag & ALIASDEAD) {
6229 unalias(sp->ap->name);
6233 parsenextc = sp->prevstring;
6234 parsenleft = sp->prevnleft;
6235 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6236 parsefile->strpush = sp->prev;
6237 if (sp != &(parsefile->basestrpush))
6243 * Set the input to take input from a file. If push is set, push the
6244 * old input onto the stack first.
6248 setinputfile(const char *fname, int push)
6254 if ((fd = open(fname, O_RDONLY)) < 0)
6255 error("Can't open %s", fname);
6257 fd2 = copyfd(fd, 10);
6260 error("Out of file descriptors");
6263 setinputfd(fd, push);
6269 * Like setinputfile, but takes an open file descriptor. Call this with
6274 setinputfd(int fd, int push)
6276 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
6282 if (parsefile->buf == NULL)
6283 parsefile->buf = ckmalloc(IBUFSIZ);
6284 parselleft = parsenleft = 0;
6290 * Like setinputfile, but takes input from a string.
6294 setinputstring(char *string)
6298 parsenextc = string;
6299 parsenleft = strlen(string);
6300 parsefile->buf = NULL;
6307 * To handle the "." command, a stack of input files is used. Pushfile
6308 * adds a new entry to the stack and popfile restores the previous level.
6314 struct parsefile *pf;
6316 parsefile->nleft = parsenleft;
6317 parsefile->lleft = parselleft;
6318 parsefile->nextc = parsenextc;
6319 parsefile->linno = plinno;
6320 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
6321 pf->prev = parsefile;
6324 pf->basestrpush.prev = NULL;
6332 struct parsefile *pf = parsefile;
6341 parsefile = pf->prev;
6343 parsenleft = parsefile->nleft;
6344 parselleft = parsefile->lleft;
6345 parsenextc = parsefile->nextc;
6346 plinno = parsefile->linno;
6352 * Return to top level.
6358 while (parsefile != &basepf)
6364 * Close the file(s) that the shell is reading commands from. Called
6365 * after a fork is done.
6372 if (parsefile->fd > 0) {
6373 close(parsefile->fd);
6378 /* $NetBSD: jobs.c,v 1.56 2002/11/25 12:13:03 agc Exp $ */
6380 /* mode flags for set_curjob */
6381 #define CUR_DELETE 2
6382 #define CUR_RUNNING 1
6383 #define CUR_STOPPED 0
6385 /* mode flags for dowait */
6386 #define DOWAIT_NORMAL 0
6387 #define DOWAIT_BLOCK 1
6390 static struct job *jobtab;
6392 static unsigned njobs;
6394 /* pgrp of shell on invocation */
6395 static int initialpgrp;
6396 static int ttyfd = -1;
6399 static struct job *curjob;
6400 /* number of presumed living untracked jobs */
6403 static void set_curjob(struct job *, unsigned);
6405 static int restartjob(struct job *, int);
6406 static void xtcsetpgrp(int, pid_t);
6407 static char *commandtext(union node *);
6408 static void cmdlist(union node *, int);
6409 static void cmdtxt(union node *);
6410 static void cmdputs(const char *);
6411 static void showpipe(struct job *, FILE *);
6413 static int sprint_status(char *, int, int);
6414 static void freejob(struct job *);
6415 static struct job *getjob(const char *, int);
6416 static struct job *growjobtab(void);
6417 static void forkchild(struct job *, union node *, int);
6418 static void forkparent(struct job *, union node *, int, pid_t);
6419 static int dowait(int, struct job *);
6420 static int getstatus(struct job *);
6423 set_curjob(struct job *jp, unsigned mode)
6426 struct job **jpp, **curp;
6428 /* first remove from list */
6429 jpp = curp = &curjob;
6434 jpp = &jp1->prev_job;
6436 *jpp = jp1->prev_job;
6438 /* Then re-insert in correct position */
6446 /* job being deleted */
6449 /* newly created job or backgrounded job,
6450 put after all stopped jobs. */
6454 if (!jp1 || jp1->state != JOBSTOPPED)
6457 jpp = &jp1->prev_job;
6463 /* newly stopped job - becomes curjob */
6464 jp->prev_job = *jpp;
6472 * Turn job control on and off.
6474 * Note: This code assumes that the third arg to ioctl is a character
6475 * pointer, which is true on Berkeley systems but not System V. Since
6476 * System V doesn't have job control yet, this isn't a problem now.
6478 * Called with interrupts off.
6487 if (on == jobctl || rootshell == 0)
6491 ofd = fd = open(_PATH_TTY, O_RDWR);
6494 while (!isatty(fd) && --fd >= 0)
6497 fd = fcntl(fd, F_DUPFD, 10);
6501 fcntl(fd, F_SETFD, FD_CLOEXEC);
6502 do { /* while we are in the background */
6503 if ((pgrp = tcgetpgrp(fd)) < 0) {
6505 sh_warnx("can't access tty; job control turned off");
6509 if (pgrp == getpgrp())
6520 xtcsetpgrp(fd, pgrp);
6522 /* turning job control off */
6525 xtcsetpgrp(fd, pgrp);
6539 killcmd(int argc, char **argv)
6550 "Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6551 "kill -l [exitstatus]"
6555 if (**++argv == '-') {
6556 signo = decode_signal(*argv + 1, 1);
6560 while ((c = nextopt("ls:")) != '\0')
6570 signo = decode_signal(optionarg, 1);
6573 "invalid signal number or name: %s",
6584 if (!list && signo < 0)
6587 if ((signo < 0 || !*argv) ^ list) {
6595 for (i = 1; i < NSIG; i++) {
6596 name = u_signal_names(0, &i, 1);
6598 out1fmt(snlfmt, name);
6602 name = u_signal_names(*argptr, &signo, -1);
6604 out1fmt(snlfmt, name);
6606 error("invalid signal number or exit status: %s", *argptr);
6612 if (**argv == '%') {
6613 jp = getjob(*argv, 0);
6614 pid = -jp->ps[0].pid;
6616 pid = **argv == '-' ?
6617 -number(*argv + 1) : number(*argv);
6619 if (kill(pid, signo) != 0) {
6620 sh_warnx("(%d) - %m", pid);
6629 #if defined(JOBS) || defined(DEBUG)
6631 jobno(const struct job *jp)
6633 return jp - jobtab + 1;
6639 fgcmd(int argc, char **argv)
6646 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
6651 jp = getjob(*argv, 1);
6652 if (mode == FORK_BG) {
6653 set_curjob(jp, CUR_RUNNING);
6654 fprintf(out, "[%d] ", jobno(jp));
6656 outstr(jp->ps->cmd, out);
6658 retval = restartjob(jp, mode);
6659 } while (*argv && *++argv);
6663 static int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
6667 restartjob(struct job *jp, int mode)
6669 struct procstat *ps;
6675 if (jp->state == JOBDONE)
6677 jp->state = JOBRUNNING;
6679 if (mode == FORK_FG)
6680 xtcsetpgrp(ttyfd, pgid);
6681 killpg(pgid, SIGCONT);
6685 if (WIFSTOPPED(ps->status)) {
6688 } while (ps++, --i);
6690 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
6697 sprint_status(char *s, int status, int sigonly)
6703 if (!WIFEXITED(status)) {
6705 if (WIFSTOPPED(status))
6706 st = WSTOPSIG(status);
6709 st = WTERMSIG(status);
6711 if (st == SIGINT || st == SIGPIPE)
6714 if (WIFSTOPPED(status))
6719 col = fmtstr(s, 32, strsignal(st));
6720 if (WCOREDUMP(status)) {
6721 col += fmtstr(s + col, 16, " (core dumped)");
6723 } else if (!sigonly) {
6724 st = WEXITSTATUS(status);
6726 col = fmtstr(s, 16, "Done(%d)", st);
6728 col = fmtstr(s, 16, "Done");
6737 showjob(FILE *out, struct job *jp, int mode)
6739 struct procstat *ps;
6740 struct procstat *psend;
6747 if (mode & SHOW_PGID) {
6748 /* just output process (group) id of pipeline */
6749 fprintf(out, "%d\n", ps->pid);
6753 col = fmtstr(s, 16, "[%d] ", jobno(jp));
6758 else if (curjob && jp == curjob->prev_job)
6761 if (mode & SHOW_PID)
6762 col += fmtstr(s + col, 16, "%d ", ps->pid);
6764 psend = ps + jp->nprocs;
6766 if (jp->state == JOBRUNNING) {
6767 scopy("Running", s + col);
6768 col += strlen("Running");
6770 int status = psend[-1].status;
6772 if (jp->state == JOBSTOPPED)
6773 status = jp->stopstatus;
6775 col += sprint_status(s + col, status, 0);
6781 /* for each process */
6782 col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
6785 fprintf(out, "%s%*c%s",
6786 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
6788 if (!(mode & SHOW_PID)) {
6792 if (++ps == psend) {
6793 outcslow('\n', out);
6800 if (jp->state == JOBDONE) {
6801 TRACE(("showjob: freeing job %d\n", jobno(jp)));
6808 jobscmd(int argc, char **argv)
6814 while ((m = nextopt("lp")))
6824 showjob(out, getjob(*argv,0), mode);
6827 showjobs(out, mode);
6834 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6835 * statuses have changed since the last call to showjobs.
6839 showjobs(FILE *out, int mode)
6843 TRACE(("showjobs(%x) called\n", mode));
6845 /* If not even one one job changed, there is nothing to do */
6846 while (dowait(DOWAIT_NORMAL, NULL) > 0)
6849 for (jp = curjob; jp; jp = jp->prev_job) {
6850 if (!(mode & SHOW_CHANGED) || jp->changed)
6851 showjob(out, jp, mode);
6857 * Mark a job structure as unused.
6861 freejob(struct job *jp)
6863 struct procstat *ps;
6867 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
6868 if (ps->cmd != nullstr)
6871 if (jp->ps != &jp->ps0)
6874 set_curjob(jp, CUR_DELETE);
6880 waitcmd(int argc, char **argv)
6893 /* wait for all jobs */
6898 /* no running procs */
6901 if (jp->state == JOBRUNNING)
6906 dowait(DOWAIT_BLOCK, 0);
6912 if (**argv != '%') {
6913 pid_t pid = number(*argv);
6917 if (job->ps[job->nprocs - 1].pid == pid)
6919 job = job->prev_job;
6925 job = getjob(*argv, 0);
6926 /* loop until process terminated or stopped */
6927 while (job->state == JOBRUNNING)
6928 dowait(DOWAIT_BLOCK, 0);
6930 retval = getstatus(job);
6941 * Convert a job name to a job structure.
6945 getjob(const char *name, int getctl)
6949 const char *err_msg = "No such job: %s";
6953 char *(*match)(const char *, const char *);
6968 if (c == '+' || c == '%') {
6970 err_msg = "No current job";
6972 } else if (c == '-') {
6975 err_msg = "No previous job";
6986 jp = jobtab + num - 1;
7003 if (match(jp->ps[0].cmd, p)) {
7007 err_msg = "%s: ambiguous";
7014 err_msg = "job %s not created under job control";
7015 if (getctl && jp->jobctl == 0)
7020 error(err_msg, name);
7025 * Return a new job structure.
7026 * Called with interrupts off.
7030 makejob(union node *node, int nprocs)
7035 for (i = njobs, jp = jobtab ; ; jp++) {
7042 if (jp->state != JOBDONE || !jp->waited)
7051 memset(jp, 0, sizeof(*jp));
7056 jp->prev_job = curjob;
7061 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
7063 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
7073 struct job *jp, *jq;
7075 len = njobs * sizeof(*jp);
7077 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
7079 offset = (char *)jp - (char *)jq;
7081 /* Relocate pointers */
7084 jq = (struct job *)((char *)jq + l);
7088 #define joff(p) ((struct job *)((char *)(p) + l))
7089 #define jmove(p) (p) = (void *)((char *)(p) + offset)
7090 if (xlikely(joff(jp)->ps == &jq->ps0))
7091 jmove(joff(jp)->ps);
7092 if (joff(jp)->prev_job)
7093 jmove(joff(jp)->prev_job);
7103 jp = (struct job *)((char *)jp + len);
7107 } while (--jq >= jp);
7113 * Fork off a subshell. If we are doing job control, give the subshell its
7114 * own process group. Jp is a job structure that the job is to be added to.
7115 * N is the command that will be evaluated by the child. Both jp and n may
7116 * be NULL. The mode parameter can be one of the following:
7117 * FORK_FG - Fork off a foreground process.
7118 * FORK_BG - Fork off a background process.
7119 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
7120 * process group even if job control is on.
7122 * When job control is turned off, background processes have their standard
7123 * input redirected to /dev/null (except for the second and later processes
7126 * Called with interrupts off.
7130 forkchild(struct job *jp, union node *n, int mode)
7134 TRACE(("Child shell %d\n", getpid()));
7135 wasroot = rootshell;
7141 /* do job control only in root shell */
7143 if (mode != FORK_NOJOB && jp->jobctl && wasroot) {
7146 if (jp->nprocs == 0)
7149 pgrp = jp->ps[0].pid;
7150 /* This can fail because we are doing it in the parent also */
7151 (void)setpgid(0, pgrp);
7152 if (mode == FORK_FG)
7153 xtcsetpgrp(ttyfd, pgrp);
7158 if (mode == FORK_BG) {
7161 if (jp->nprocs == 0) {
7163 if (open(_PATH_DEVNULL, O_RDONLY) != 0)
7164 error("Can't open %s", _PATH_DEVNULL);
7167 if (wasroot && iflag) {
7172 for (jp = curjob; jp; jp = jp->prev_job)
7178 forkparent(struct job *jp, union node *n, int mode, pid_t pid)
7180 TRACE(("In parent shell: child = %d\n", pid));
7182 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
7187 if (mode != FORK_NOJOB && jp->jobctl) {
7190 if (jp->nprocs == 0)
7193 pgrp = jp->ps[0].pid;
7194 /* This can fail because we are doing it in the child also */
7195 (void)setpgid(pid, pgrp);
7198 if (mode == FORK_BG) {
7199 backgndpid = pid; /* set $! */
7200 set_curjob(jp, CUR_RUNNING);
7203 struct procstat *ps = &jp->ps[jp->nprocs++];
7209 ps->cmd = commandtext(n);
7215 forkshell(struct job *jp, union node *n, int mode)
7219 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
7222 TRACE(("Fork failed, errno=%d", errno));
7225 error("Cannot fork");
7228 forkchild(jp, n, mode);
7230 forkparent(jp, n, mode, pid);
7235 * Wait for job to finish.
7237 * Under job control we have the problem that while a child process is
7238 * running interrupts generated by the user are sent to the child but not
7239 * to the shell. This means that an infinite loop started by an inter-
7240 * active user may be hard to kill. With job control turned off, an
7241 * interactive user may place an interactive program inside a loop. If
7242 * the interactive program catches interrupts, the user doesn't want
7243 * these interrupts to also abort the loop. The approach we take here
7244 * is to have the shell ignore interrupt signals while waiting for a
7245 * foreground process to terminate, and then send itself an interrupt
7246 * signal if the child process was terminated by an interrupt signal.
7247 * Unfortunately, some programs want to do a bit of cleanup and then
7248 * exit on interrupt; unless these processes terminate themselves by
7249 * sending a signal to themselves (instead of calling exit) they will
7250 * confuse this approach.
7252 * Called with interrupts off.
7256 waitforjob(struct job *jp)
7260 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
7261 while (jp->state == JOBRUNNING) {
7262 dowait(DOWAIT_BLOCK, jp);
7267 xtcsetpgrp(ttyfd, rootpid);
7269 * This is truly gross.
7270 * If we're doing job control, then we did a TIOCSPGRP which
7271 * caused us (the shell) to no longer be in the controlling
7272 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7273 * intuit from the subprocess exit status whether a SIGINT
7274 * occurred, and if so interrupt ourselves. Yuck. - mycroft
7279 if (jp->state == JOBDONE)
7287 * Do a wait system call. If job control is compiled in, we accept
7288 * stopped processes. If block is zero, we return a value of zero
7289 * rather than blocking.
7291 * System V doesn't have a non-blocking wait system call. It does
7292 * have a SIGCLD signal that is sent to a process when one of it's
7293 * children dies. The obvious way to use SIGCLD would be to install
7294 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7295 * was received, and have waitproc bump another counter when it got
7296 * the status of a process. Waitproc would then know that a wait
7297 * system call would not block if the two counters were different.
7298 * This approach doesn't work because if a process has children that
7299 * have not been waited for, System V will send it a SIGCLD when it
7300 * installs a signal handler for SIGCLD. What this means is that when
7301 * a child exits, the shell will be sent SIGCLD signals continuously
7302 * until is runs out of stack space, unless it does a wait call before
7303 * restoring the signal handler. The code below takes advantage of
7304 * this (mis)feature by installing a signal handler for SIGCLD and
7305 * then checking to see whether it was called. If there are any
7306 * children to be waited for, it will be.
7308 * If neither SYSV nor BSD is defined, we don't implement nonblocking
7309 * waits at all. In this case, the user will not be informed when
7310 * a background process until the next time she runs a real program
7311 * (as opposed to running a builtin command or just typing return),
7312 * and the jobs command may give out of date information.
7316 waitproc(int block, int *status)
7326 return wait3(status, flags, (struct rusage *)NULL);
7330 * Wait for a process to terminate.
7334 dowait(int block, struct job *job)
7339 struct job *thisjob;
7342 TRACE(("dowait(%d) called\n", block));
7343 pid = waitproc(block, &status);
7344 TRACE(("wait returns pid %d, status=%d\n", pid, status));
7349 for (jp = curjob; jp; jp = jp->prev_job) {
7350 struct procstat *sp;
7351 struct procstat *spend;
7352 if (jp->state == JOBDONE)
7355 spend = jp->ps + jp->nprocs;
7358 if (sp->pid == pid) {
7359 TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
7360 sp->status = status;
7363 if (sp->status == -1)
7366 if (state == JOBRUNNING)
7368 if (WIFSTOPPED(sp->status)) {
7369 jp->stopstatus = sp->status;
7373 } while (++sp < spend);
7378 if (!WIFSTOPPED(status))
7385 if (state != JOBRUNNING) {
7386 thisjob->changed = 1;
7388 if (thisjob->state != state) {
7389 TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
7390 thisjob->state = state;
7392 if (state == JOBSTOPPED) {
7393 set_curjob(thisjob, CUR_STOPPED);
7402 if (thisjob && thisjob == job) {
7406 len = sprint_status(s, status, 1);
7418 * return 1 if there are stopped jobs, otherwise 0
7431 if (jp && jp->state == JOBSTOPPED) {
7432 out2str("You have stopped jobs.\n");
7442 * Return a string identifying a command (to be printed by the
7447 static char *cmdnextc;
7450 commandtext(union node *n)
7454 STARTSTACKSTR(cmdnextc);
7456 name = stackblock();
7457 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
7458 name, cmdnextc, cmdnextc));
7459 return savestr(name);
7463 cmdtxt(union node *n)
7466 struct nodelist *lp;
7478 lp = n->npipe.cmdlist;
7496 cmdtxt(n->nbinary.ch1);
7512 cmdtxt(n->nif.test);
7515 if (n->nif.elsepart) {
7518 n = n->nif.elsepart;
7534 cmdtxt(n->nbinary.ch1);
7544 cmdputs(n->nfor.var);
7546 cmdlist(n->nfor.args, 1);
7551 cmdputs(n->narg.text);
7555 cmdlist(n->ncmd.args, 1);
7556 cmdlist(n->ncmd.redirect, 0);
7569 cmdputs(n->ncase.expr->narg.text);
7571 for (np = n->ncase.cases; np; np = np->nclist.next) {
7572 cmdtxt(np->nclist.pattern);
7574 cmdtxt(np->nclist.body);
7600 s[0] = n->nfile.fd + '0';
7604 if (n->type == NTOFD || n->type == NFROMFD) {
7605 s[0] = n->ndup.dupfd + '0';
7616 cmdlist(union node *np, int sep)
7618 for (; np; np = np->narg.next) {
7622 if (sep && np->narg.next)
7628 cmdputs(const char *s)
7630 const char *p, *str;
7631 char c, cc[2] = " ";
7635 static const char vstype[VSTYPE + 1][4] = {
7636 "", "}", "-", "+", "?", "=",
7637 "%", "%%", "#", "##"
7639 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
7641 while ((c = *p++) != 0) {
7649 if ((subtype & VSTYPE) == VSLENGTH)
7653 if (!(subtype & VSQUOTE) != !(quoted & 1)) {
7660 str = "\"}" + !(quoted & 1);
7667 case CTLBACKQ+CTLQUOTE:
7670 #ifdef CONFIG_ASH_MATH_SUPPORT
7685 if ((subtype & VSTYPE) != VSNORMAL)
7687 str = vstype[subtype & VSTYPE];
7688 if (subtype & VSNUL)
7697 /* These can only happen inside quotes */
7710 while ((c = *str++)) {
7715 USTPUTC('"', nextc);
7723 showpipe(struct job *jp, FILE *out)
7725 struct procstat *sp;
7726 struct procstat *spend;
7728 spend = jp->ps + jp->nprocs;
7729 for (sp = jp->ps + 1; sp < spend; sp++)
7730 fprintf(out, " | %s", sp->cmd);
7731 outcslow('\n', out);
7736 xtcsetpgrp(int fd, pid_t pgrp)
7738 if (tcsetpgrp(fd, pgrp))
7739 error("Cannot set tty process group (%m)");
7744 getstatus(struct job *job) {
7748 status = job->ps[job->nprocs - 1].status;
7749 retval = WEXITSTATUS(status);
7750 if (!WIFEXITED(status)) {
7752 retval = WSTOPSIG(status);
7753 if (!WIFSTOPPED(status))
7756 /* XXX: limits number of signals */
7757 retval = WTERMSIG(status);
7759 if (retval == SIGINT)
7765 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
7766 jobno(job), job->nprocs, status, retval));
7770 #ifdef CONFIG_ASH_MAIL
7771 /* $NetBSD: mail.c,v 1.15 2002/11/24 22:35:40 christos Exp $ */
7774 * Routines to check for mail. (Perhaps make part of main.c?)
7777 #define MAXMBOXES 10
7779 /* times of mailboxes */
7780 static time_t mailtime[MAXMBOXES];
7781 /* Set if MAIL or MAILPATH is changed. */
7782 static int mail_var_path_changed;
7787 * Print appropriate message(s) if mail has arrived.
7788 * If mail_var_path_changed is set,
7789 * then the value of MAIL has mail_var_path_changed,
7790 * so we just update the values.
7800 struct stackmark smark;
7803 setstackmark(&smark);
7804 mpath = mpathset() ? mpathval() : mailval();
7805 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
7806 p = padvance(&mpath, nullstr);
7811 for (q = p ; *q ; q++);
7816 q[-1] = '\0'; /* delete trailing '/' */
7817 if (stat(p, &statb) < 0) {
7821 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
7824 pathopt ? pathopt : "you have mail"
7827 *mtp = statb.st_mtime;
7829 mail_var_path_changed = 0;
7830 popstackmark(&smark);
7835 changemail(const char *val)
7837 mail_var_path_changed++;
7840 #endif /* CONFIG_ASH_MAIL */
7842 /* $NetBSD: main.c,v 1.46 2002/12/11 19:12:18 christos Exp $ */
7846 static short profile_buf[16384];
7850 static int isloginsh;
7852 static void read_profile(const char *);
7855 * Main routine. We initialize things, parse the arguments, execute
7856 * profiles if we're a login shell, and then call cmdloop to execute
7857 * commands. The setjmp call sets up the location to jump to when an
7858 * exception occurs. When an exception occurs the variable "state"
7859 * is used to figure out how far we had gotten.
7863 ash_main(int argc, char **argv)
7867 struct jmploc jmploc;
7868 struct stackmark smark;
7871 dash_errno = __errno_location();
7875 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7878 if (setjmp(jmploc.loc)) {
7885 switch (exception) {
7895 status = exitstatus;
7898 exitstatus = status;
7900 if (e == EXEXIT || state == 0 || iflag == 0 || ! rootshell)
7904 outcslow('\n', stderr);
7906 popstackmark(&smark);
7907 FORCEINTON; /* enable interrupts */
7910 else if (state == 2)
7912 else if (state == 3)
7920 trputs("Shell args: "); trargs(argv);
7924 #ifdef CONFIG_ASH_RANDOM_SUPPORT
7925 rseed = rootpid + ((time_t)time((time_t *)0));
7929 setstackmark(&smark);
7930 procargs(argc, argv);
7931 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7933 const char *hp = lookupvar("HISTFILE");
7936 hp = lookupvar("HOME");
7938 char *defhp = concat_path_file(hp, ".ash_history");
7939 setvar("HISTFILE", defhp, 0);
7945 if (argv[0] && argv[0][0] == '-')
7949 read_profile("/etc/profile");
7952 read_profile(".profile");
7958 getuid() == geteuid() && getgid() == getegid() &&
7962 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
7963 read_profile(shinit);
7971 if (sflag || minusc == NULL) {
7972 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7974 const char *hp = lookupvar("HISTFILE");
7977 load_history ( hp );
7980 state4: /* XXX ??? - why isn't this before the "if" statement */
7988 extern void _mcleanup(void);
7998 * Read and execute commands. "Top" is nonzero for the top level command
7999 * loop; it turns on prompting if the shell is interactive.
8006 struct stackmark smark;
8010 TRACE(("cmdloop(%d) called\n", top));
8012 setstackmark(&smark);
8017 showjobs(stderr, SHOW_CHANGED);
8022 #ifdef CONFIG_ASH_MAIL
8026 n = parsecmd(inter);
8027 /* showtree(n); DEBUG */
8029 if (!top || numeof >= 50)
8031 if (!stoppedjobs()) {
8034 out2str("\nUse \"exit\" to leave shell.\n");
8037 } else if (n != NULL && nflag == 0) {
8038 job_warning = (job_warning == 2) ? 1 : 0;
8042 popstackmark(&smark);
8052 * Read /etc/profile or .profile. Return on error.
8056 read_profile(const char *name)
8063 if ((fd = open(name, O_RDONLY)) >= 0)
8068 /* -q turns off -x and -v just when executing init files */
8071 xflag = 0, xflag_set = 1;
8073 vflag = 0, vflag_set = 1;
8087 * Read a file containing shell functions.
8091 readcmdfile(char *name)
8096 if ((fd = open(name, O_RDONLY)) >= 0)
8099 error("Can't open %s", name);
8107 * Take commands from a file. To be compatible we should do a path
8108 * search for the file, which is necessary to find sub-commands.
8111 static inline char *
8112 find_dot_file(char *name)
8115 const char *path = pathval();
8118 /* don't try this for absolute or relative paths */
8119 if (strchr(name, '/'))
8122 while ((fullname = padvance(&path, name)) != NULL) {
8123 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
8125 * Don't bother freeing here, since it will
8126 * be freed by the caller.
8130 stunalloc(fullname);
8133 /* not found in the PATH */
8134 error(not_found_msg, name);
8138 static int dotcmd(int argc, char **argv)
8141 volatile struct shparam saveparam;
8145 for (sp = cmdenviron; sp; sp = sp->next)
8146 setvareq(bb_xstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
8148 if (argc >= 2) { /* That's what SVR2 does */
8150 struct stackmark smark;
8152 setstackmark(&smark);
8153 fullname = find_dot_file(argv[1]);
8156 saveparam = shellparam;
8157 shellparam.malloc = 0;
8158 shellparam.nparam = argc - 2;
8159 shellparam.p = argv + 2;
8162 setinputfile(fullname, 1);
8163 commandname = fullname;
8168 freeparam(&shellparam);
8169 shellparam = saveparam;
8172 popstackmark(&smark);
8179 exitcmd(int argc, char **argv)
8184 exitstatus = number(argv[1]);
8189 #ifdef CONFIG_ASH_BUILTIN_ECHO
8191 echocmd(int argc, char **argv)
8193 return bb_echo(argc, argv);
8196 /* $NetBSD: memalloc.c,v 1.27 2003/01/22 20:36:04 dsl Exp $ */
8199 * Same for malloc, realloc, but returns an error when out of space.
8203 ckrealloc(pointer p, size_t nbytes)
8205 p = realloc(p, nbytes);
8207 error(bb_msg_memory_exhausted);
8212 ckmalloc(size_t nbytes)
8214 return ckrealloc(NULL, nbytes);
8218 * Make a copy of a string in safe storage.
8222 savestr(const char *s)
8224 char *p = strdup(s);
8226 error(bb_msg_memory_exhausted);
8232 * Parse trees for commands are allocated in lifo order, so we use a stack
8233 * to make this more efficient, and also to avoid all sorts of exception
8234 * handling code to handle interrupts in the middle of a parse.
8236 * The size 504 was chosen because the Ultrix malloc handles that size
8242 stalloc(size_t nbytes)
8247 aligned = SHELL_ALIGN(nbytes);
8248 if (aligned > stacknleft) {
8251 struct stack_block *sp;
8253 blocksize = aligned;
8254 if (blocksize < MINSIZE)
8255 blocksize = MINSIZE;
8256 len = sizeof(struct stack_block) - MINSIZE + blocksize;
8257 if (len < blocksize)
8258 error(bb_msg_memory_exhausted);
8262 stacknxt = sp->space;
8263 stacknleft = blocksize;
8264 sstrend = stacknxt + blocksize;
8269 stacknxt += aligned;
8270 stacknleft -= aligned;
8276 stunalloc(pointer p)
8279 if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
8280 write(2, "stunalloc\n", 10);
8284 stacknleft += stacknxt - (char *)p;
8290 setstackmark(struct stackmark *mark)
8292 mark->stackp = stackp;
8293 mark->stacknxt = stacknxt;
8294 mark->stacknleft = stacknleft;
8295 mark->marknext = markp;
8301 popstackmark(struct stackmark *mark)
8303 struct stack_block *sp;
8306 markp = mark->marknext;
8307 while (stackp != mark->stackp) {
8312 stacknxt = mark->stacknxt;
8313 stacknleft = mark->stacknleft;
8314 sstrend = mark->stacknxt + mark->stacknleft;
8320 * When the parser reads in a string, it wants to stick the string on the
8321 * stack and only adjust the stack pointer when it knows how big the
8322 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8323 * of space on top of the stack and stackblocklen returns the length of
8324 * this block. Growstackblock will grow this space by at least one byte,
8325 * possibly moving it (like realloc). Grabstackblock actually allocates the
8326 * part of the block that has been used.
8330 growstackblock(void)
8334 newlen = stacknleft * 2;
8335 if (newlen < stacknleft)
8336 error(bb_msg_memory_exhausted);
8340 if (stacknxt == stackp->space && stackp != &stackbase) {
8341 struct stack_block *oldstackp;
8342 struct stackmark *xmark;
8343 struct stack_block *sp;
8344 struct stack_block *prevstackp;
8350 prevstackp = sp->prev;
8351 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
8352 sp = ckrealloc((pointer)sp, grosslen);
8353 sp->prev = prevstackp;
8355 stacknxt = sp->space;
8356 stacknleft = newlen;
8357 sstrend = sp->space + newlen;
8360 * Stack marks pointing to the start of the old block
8361 * must be relocated to point to the new block
8364 while (xmark != NULL && xmark->stackp == oldstackp) {
8365 xmark->stackp = stackp;
8366 xmark->stacknxt = stacknxt;
8367 xmark->stacknleft = stacknleft;
8368 xmark = xmark->marknext;
8372 char *oldspace = stacknxt;
8373 int oldlen = stacknleft;
8374 char *p = stalloc(newlen);
8376 /* free the space we just allocated */
8377 stacknxt = memcpy(p, oldspace, oldlen);
8378 stacknleft += newlen;
8383 grabstackblock(size_t len)
8385 len = SHELL_ALIGN(len);
8391 * The following routines are somewhat easier to use than the above.
8392 * The user declares a variable of type STACKSTR, which may be declared
8393 * to be a register. The macro STARTSTACKSTR initializes things. Then
8394 * the user uses the macro STPUTC to add characters to the string. In
8395 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8396 * grown as necessary. When the user is done, she can just leave the
8397 * string there and refer to it using stackblock(). Or she can allocate
8398 * the space for it using grabstackstr(). If it is necessary to allow
8399 * someone else to use the stack temporarily and then continue to grow
8400 * the string, the user should use grabstack to allocate the space, and
8401 * then call ungrabstr(p) to return to the previous mode of operation.
8403 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8404 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8405 * is space for at least one character.
8411 size_t len = stackblocksize();
8412 if (herefd >= 0 && len >= 1024) {
8413 bb_full_write(herefd, stackblock(), len);
8414 return stackblock();
8417 return stackblock() + len;
8421 * Called from CHECKSTRSPACE.
8425 makestrspace(size_t newlen, char *p)
8427 size_t len = p - stacknxt;
8428 size_t size = stackblocksize();
8433 size = stackblocksize();
8435 if (nleft >= newlen)
8439 return stackblock() + len;
8443 stnputs(const char *s, size_t n, char *p)
8445 p = makestrspace(n, p);
8446 p = mempcpy(p, s, n);
8451 stputs(const char *s, char *p)
8453 return stnputs(s, strlen(s), p);
8456 /* $NetBSD: mystring.c,v 1.15 2002/11/24 22:35:42 christos Exp $ */
8461 * number(s) Convert a string of digits to an integer.
8462 * is_number(s) Return true if s is a string of digits.
8466 * prefix -- see if pfx is a prefix of string.
8470 prefix(const char *string, const char *pfx)
8473 if (*pfx++ != *string++)
8476 return (char *) string;
8481 * Convert a string of digits to an integer, printing an error message on
8486 number(const char *s)
8496 * Check for a valid number. This should be elsewhere.
8500 is_number(const char *p)
8505 } while (*++p != '\0');
8511 * Produce a possibly single quoted string suitable as input to the shell.
8512 * The return string is allocated on the stack.
8516 single_quote(const char *s) {
8525 len = strchrnul(s, '\'') - s;
8527 q = p = makestrspace(len + 3, p);
8530 q = mempcpy(q, s, len);
8536 len = strspn(s, "'");
8540 q = p = makestrspace(len + 3, p);
8543 q = mempcpy(q, s, len);
8552 return stackblock();
8556 * Like strdup but works with the ash stack.
8560 sstrdup(const char *p)
8562 size_t len = strlen(p) + 1;
8563 return memcpy(stalloc(len), p, len);
8568 calcsize(union node *n)
8572 funcblocksize += nodesize[n->type];
8575 calcsize(n->ncmd.redirect);
8576 calcsize(n->ncmd.args);
8577 calcsize(n->ncmd.assign);
8580 sizenodelist(n->npipe.cmdlist);
8585 calcsize(n->nredir.redirect);
8586 calcsize(n->nredir.n);
8593 calcsize(n->nbinary.ch2);
8594 calcsize(n->nbinary.ch1);
8597 calcsize(n->nif.elsepart);
8598 calcsize(n->nif.ifpart);
8599 calcsize(n->nif.test);
8602 funcstringsize += strlen(n->nfor.var) + 1;
8603 calcsize(n->nfor.body);
8604 calcsize(n->nfor.args);
8607 calcsize(n->ncase.cases);
8608 calcsize(n->ncase.expr);
8611 calcsize(n->nclist.body);
8612 calcsize(n->nclist.pattern);
8613 calcsize(n->nclist.next);
8617 sizenodelist(n->narg.backquote);
8618 funcstringsize += strlen(n->narg.text) + 1;
8619 calcsize(n->narg.next);
8626 calcsize(n->nfile.fname);
8627 calcsize(n->nfile.next);
8631 calcsize(n->ndup.vname);
8632 calcsize(n->ndup.next);
8636 calcsize(n->nhere.doc);
8637 calcsize(n->nhere.next);
8640 calcsize(n->nnot.com);
8647 sizenodelist(struct nodelist *lp)
8650 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8658 copynode(union node *n)
8665 funcblock = (char *) funcblock + nodesize[n->type];
8668 new->ncmd.redirect = copynode(n->ncmd.redirect);
8669 new->ncmd.args = copynode(n->ncmd.args);
8670 new->ncmd.assign = copynode(n->ncmd.assign);
8673 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8674 new->npipe.backgnd = n->npipe.backgnd;
8679 new->nredir.redirect = copynode(n->nredir.redirect);
8680 new->nredir.n = copynode(n->nredir.n);
8687 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8688 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8691 new->nif.elsepart = copynode(n->nif.elsepart);
8692 new->nif.ifpart = copynode(n->nif.ifpart);
8693 new->nif.test = copynode(n->nif.test);
8696 new->nfor.var = nodesavestr(n->nfor.var);
8697 new->nfor.body = copynode(n->nfor.body);
8698 new->nfor.args = copynode(n->nfor.args);
8701 new->ncase.cases = copynode(n->ncase.cases);
8702 new->ncase.expr = copynode(n->ncase.expr);
8705 new->nclist.body = copynode(n->nclist.body);
8706 new->nclist.pattern = copynode(n->nclist.pattern);
8707 new->nclist.next = copynode(n->nclist.next);
8711 new->narg.backquote = copynodelist(n->narg.backquote);
8712 new->narg.text = nodesavestr(n->narg.text);
8713 new->narg.next = copynode(n->narg.next);
8720 new->nfile.fname = copynode(n->nfile.fname);
8721 new->nfile.fd = n->nfile.fd;
8722 new->nfile.next = copynode(n->nfile.next);
8726 new->ndup.vname = copynode(n->ndup.vname);
8727 new->ndup.dupfd = n->ndup.dupfd;
8728 new->ndup.fd = n->ndup.fd;
8729 new->ndup.next = copynode(n->ndup.next);
8733 new->nhere.doc = copynode(n->nhere.doc);
8734 new->nhere.fd = n->nhere.fd;
8735 new->nhere.next = copynode(n->nhere.next);
8738 new->nnot.com = copynode(n->nnot.com);
8741 new->type = n->type;
8746 static struct nodelist *
8747 copynodelist(struct nodelist *lp)
8749 struct nodelist *start;
8750 struct nodelist **lpp;
8755 funcblock = (char *) funcblock +
8756 SHELL_ALIGN(sizeof(struct nodelist));
8757 (*lpp)->n = copynode(lp->n);
8759 lpp = &(*lpp)->next;
8767 nodesavestr(char *s)
8769 char *rtn = funcstring;
8771 funcstring = stpcpy(funcstring, s) + 1;
8777 * Free a parse tree.
8781 freefunc(struct funcnode *f)
8783 if (f && --f->count < 0)
8788 static void options(int);
8789 static void setoption(int, int);
8793 * Process the shell command line arguments.
8797 procargs(int argc, char **argv)
8800 const char *xminusc;
8807 for (i = 0; i < NOPTS; i++)
8813 if (*xargv == NULL) {
8815 error("-c requires an argument");
8818 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8822 for (i = 0; i < NOPTS; i++)
8823 if (optlist[i] == 2)
8828 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8833 } else if (!sflag) {
8834 setinputfile(*xargv, 0);
8840 shellparam.p = xargv;
8841 #ifdef CONFIG_ASH_GETOPTS
8842 shellparam.optind = 1;
8843 shellparam.optoff = -1;
8845 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
8847 shellparam.nparam++;
8860 setinteractive(iflag);
8866 minus_o(char *name, int val)
8871 out1str("Current option settings\n");
8872 for (i = 0; i < NOPTS; i++)
8873 out1fmt("%-16s%s\n", optnames(i),
8874 optlist[i] ? "on" : "off");
8876 for (i = 0; i < NOPTS; i++)
8877 if (equal(name, optnames(i))) {
8881 error("Illegal option -o %s", name);
8886 * Process shell options. The global variable argptr contains a pointer
8887 * to the argument list; we advance it past the options.
8891 options(int cmdline)
8899 while ((p = *argptr) != NULL) {
8901 if ((c = *p++) == '-') {
8903 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8905 /* "-" means turn off -x and -v */
8908 /* "--" means reset params */
8909 else if (*argptr == NULL)
8912 break; /* "-" or "--" terminates options */
8914 } else if (c == '+') {
8920 while ((c = *p++) != '\0') {
8921 if (c == 'c' && cmdline) {
8922 minusc = p; /* command is after shell args*/
8923 } else if (c == 'o') {
8924 minus_o(*argptr, val);
8927 } else if (cmdline && (c == '-')) { // long options
8928 if (strcmp(p, "login") == 0)
8940 setoption(int flag, int val)
8944 for (i = 0; i < NOPTS; i++)
8945 if (optletters(i) == flag) {
8949 error("Illegal option -%c", flag);
8956 * Set the shell parameters.
8960 setparam(char **argv)
8966 for (nparam = 0 ; argv[nparam] ; nparam++);
8967 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
8969 *ap++ = savestr(*argv++);
8972 freeparam(&shellparam);
8973 shellparam.malloc = 1;
8974 shellparam.nparam = nparam;
8975 shellparam.p = newparam;
8976 #ifdef CONFIG_ASH_GETOPTS
8977 shellparam.optind = 1;
8978 shellparam.optoff = -1;
8984 * Free the list of positional parameters.
8988 freeparam(volatile struct shparam *param)
8992 if (param->malloc) {
8993 for (ap = param->p ; *ap ; ap++)
9002 * The shift builtin command.
9006 shiftcmd(int argc, char **argv)
9013 n = number(argv[1]);
9014 if (n > shellparam.nparam)
9015 error("can't shift that many");
9017 shellparam.nparam -= n;
9018 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
9019 if (shellparam.malloc)
9023 while ((*ap2++ = *ap1++) != NULL);
9024 #ifdef CONFIG_ASH_GETOPTS
9025 shellparam.optind = 1;
9026 shellparam.optoff = -1;
9035 * The set command builtin.
9039 setcmd(int argc, char **argv)
9042 return showvars(nullstr, 0, VUNSET);
9046 if (*argptr != NULL) {
9054 #ifdef CONFIG_ASH_GETOPTS
9059 shellparam.optind = number(value);
9060 shellparam.optoff = -1;
9064 #ifdef CONFIG_LOCALE_SUPPORT
9065 static void change_lc_all(const char *value)
9067 if (value != 0 && *value != 0)
9068 setlocale(LC_ALL, value);
9071 static void change_lc_ctype(const char *value)
9073 if (value != 0 && *value != 0)
9074 setlocale(LC_CTYPE, value);
9079 #ifdef CONFIG_ASH_RANDOM_SUPPORT
9080 /* Roughly copied from bash.. */
9081 static void change_random(const char *value)
9084 /* "get", generate */
9087 rseed = rseed * 1103515245 + 12345;
9088 sprintf(buf, "%d", (unsigned int)((rseed & 32767)));
9089 /* set without recursion */
9090 setvar(vrandom.text, buf, VNOFUNC);
9091 vrandom.flags &= ~VNOFUNC;
9094 rseed = strtoul(value, (char **)NULL, 10);
9100 #ifdef CONFIG_ASH_GETOPTS
9102 getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
9111 if(*param_optind < 1)
9113 optnext = optfirst + *param_optind - 1;
9115 if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff)
9118 p = optnext[-1] + *optoff;
9119 if (p == NULL || *p == '\0') {
9120 /* Current word is done, advance */
9122 if (p == NULL || *p != '-' || *++p == '\0') {
9129 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
9134 for (q = optstr; *q != c; ) {
9136 if (optstr[0] == ':') {
9139 err |= setvarsafe("OPTARG", s, 0);
9141 fprintf(stderr, "Illegal option -%c\n", c);
9142 (void) unsetvar("OPTARG");
9152 if (*p == '\0' && (p = *optnext) == NULL) {
9153 if (optstr[0] == ':') {
9156 err |= setvarsafe("OPTARG", s, 0);
9159 fprintf(stderr, "No arg for -%c option\n", c);
9160 (void) unsetvar("OPTARG");
9168 err |= setvarsafe("OPTARG", p, 0);
9171 err |= setvarsafe("OPTARG", nullstr, 0);
9174 *optoff = p ? p - *(optnext - 1) : -1;
9175 *param_optind = optnext - optfirst + 1;
9176 fmtstr(s, sizeof(s), "%d", *param_optind);
9177 err |= setvarsafe("OPTIND", s, VNOFUNC);
9180 err |= setvarsafe(optvar, s, 0);
9191 * The getopts builtin. Shellparam.optnext points to the next argument
9192 * to be processed. Shellparam.optptr points to the next character to
9193 * be processed in the current argument. If shellparam.optnext is NULL,
9194 * then it's the first time getopts has been called.
9198 getoptscmd(int argc, char **argv)
9203 error("Usage: getopts optstring var [arg]");
9204 else if (argc == 3) {
9205 optbase = shellparam.p;
9206 if (shellparam.optind > shellparam.nparam + 1) {
9207 shellparam.optind = 1;
9208 shellparam.optoff = -1;
9213 if (shellparam.optind > argc - 2) {
9214 shellparam.optind = 1;
9215 shellparam.optoff = -1;
9219 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9220 &shellparam.optoff);
9222 #endif /* CONFIG_ASH_GETOPTS */
9225 * XXX - should get rid of. have all builtins use getopt(3). the
9226 * library getopt must have the BSD extension static variable "optreset"
9227 * otherwise it can't be used within the shell safely.
9229 * Standard option processing (a la getopt) for builtin routines. The
9230 * only argument that is passed to nextopt is the option string; the
9231 * other arguments are unnecessary. It return the character, or '\0' on
9236 nextopt(const char *optstring)
9242 if ((p = optptr) == NULL || *p == '\0') {
9244 if (p == NULL || *p != '-' || *++p == '\0')
9247 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
9251 for (q = optstring ; *q != c ; ) {
9253 error("Illegal option -%c", c);
9258 if (*p == '\0' && (p = *argptr++) == NULL)
9259 error("No arg for -%c option", c);
9268 /* $NetBSD: output.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
9271 outstr(const char *p, FILE *file)
9296 outcslow(int c, FILE *dest)
9306 out1fmt(const char *fmt, ...)
9313 r = vprintf(fmt, ap);
9321 fmtstr(char *outbuf, size_t length, const char *fmt, ...)
9328 ret = vsnprintf(outbuf, length, fmt, ap);
9336 /* $NetBSD: parser.c,v 1.54 2002/11/24 22:35:42 christos Exp $ */
9340 * Shell command parser.
9343 #define EOFMARKLEN 79
9347 struct heredoc *next; /* next here document in list */
9348 union node *here; /* redirection node */
9349 char *eofmark; /* string indicating end of input */
9350 int striptabs; /* if set, strip leading tabs */
9355 static struct heredoc *heredoclist; /* list of here documents to read */
9358 static union node *list(int);
9359 static union node *andor(void);
9360 static union node *pipeline(void);
9361 static union node *command(void);
9362 static union node *simplecmd(void);
9363 static union node *makename(void);
9364 static void parsefname(void);
9365 static void parseheredoc(void);
9366 static char peektoken(void);
9367 static int readtoken(void);
9368 static int xxreadtoken(void);
9369 static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
9370 static int noexpand(char *);
9371 static void synexpect(int) __attribute__((__noreturn__));
9372 static void synerror(const char *) __attribute__((__noreturn__));
9373 static void setprompt(int);
9379 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9380 * valid parse tree indicating a blank line.)
9384 parsecmd(int interact)
9389 doprompt = interact;
9391 setprompt(doprompt);
9406 union node *n1, *n2, *n3;
9409 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9410 if (nlflag == 2 && peektoken())
9416 if (tok == TBACKGND) {
9417 if (n2->type == NPIPE) {
9418 n2->npipe.backgnd = 1;
9420 if (n2->type != NREDIR) {
9421 n3 = stalloc(sizeof(struct nredir));
9423 n3->nredir.redirect = NULL;
9426 n2->type = NBACKGND;
9433 n3 = (union node *)stalloc(sizeof (struct nbinary));
9435 n3->nbinary.ch1 = n1;
9436 n3->nbinary.ch2 = n2;
9452 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9460 pungetc(); /* push back EOF on input */
9476 union node *n1, *n2, *n3;
9481 if ((t = readtoken()) == TAND) {
9483 } else if (t == TOR) {
9489 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9491 n3 = (union node *)stalloc(sizeof (struct nbinary));
9493 n3->nbinary.ch1 = n1;
9494 n3->nbinary.ch2 = n2;
9504 union node *n1, *n2, *pipenode;
9505 struct nodelist *lp, *prev;
9509 TRACE(("pipeline: entered\n"));
9510 if (readtoken() == TNOT) {
9512 checkkwd = CHKKWD | CHKALIAS;
9516 if (readtoken() == TPIPE) {
9517 pipenode = (union node *)stalloc(sizeof (struct npipe));
9518 pipenode->type = NPIPE;
9519 pipenode->npipe.backgnd = 0;
9520 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9521 pipenode->npipe.cmdlist = lp;
9525 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9526 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9529 } while (readtoken() == TPIPE);
9535 n2 = (union node *)stalloc(sizeof (struct nnot));
9548 union node *n1, *n2;
9549 union node *ap, **app;
9550 union node *cp, **cpp;
9551 union node *redir, **rpp;
9558 switch (readtoken()) {
9563 n1 = (union node *)stalloc(sizeof (struct nif));
9565 n1->nif.test = list(0);
9566 if (readtoken() != TTHEN)
9568 n1->nif.ifpart = list(0);
9570 while (readtoken() == TELIF) {
9571 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
9572 n2 = n2->nif.elsepart;
9574 n2->nif.test = list(0);
9575 if (readtoken() != TTHEN)
9577 n2->nif.ifpart = list(0);
9579 if (lasttoken == TELSE)
9580 n2->nif.elsepart = list(0);
9582 n2->nif.elsepart = NULL;
9590 n1 = (union node *)stalloc(sizeof (struct nbinary));
9591 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
9592 n1->nbinary.ch1 = list(0);
9593 if ((got=readtoken()) != TDO) {
9594 TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
9597 n1->nbinary.ch2 = list(0);
9602 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9603 synerror("Bad for loop variable");
9604 n1 = (union node *)stalloc(sizeof (struct nfor));
9606 n1->nfor.var = wordtext;
9607 checkkwd = CHKKWD | CHKALIAS;
9608 if (readtoken() == TIN) {
9610 while (readtoken() == TWORD) {
9611 n2 = (union node *)stalloc(sizeof (struct narg));
9613 n2->narg.text = wordtext;
9614 n2->narg.backquote = backquotelist;
9616 app = &n2->narg.next;
9620 if (lasttoken != TNL && lasttoken != TSEMI)
9623 n2 = (union node *)stalloc(sizeof (struct narg));
9625 n2->narg.text = (char *)dolatstr;
9626 n2->narg.backquote = NULL;
9627 n2->narg.next = NULL;
9630 * Newline or semicolon here is optional (but note
9631 * that the original Bourne shell only allowed NL).
9633 if (lasttoken != TNL && lasttoken != TSEMI)
9636 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9637 if (readtoken() != TDO)
9639 n1->nfor.body = list(0);
9643 n1 = (union node *)stalloc(sizeof (struct ncase));
9645 if (readtoken() != TWORD)
9647 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
9649 n2->narg.text = wordtext;
9650 n2->narg.backquote = backquotelist;
9651 n2->narg.next = NULL;
9653 checkkwd = CHKKWD | CHKALIAS;
9654 } while (readtoken() == TNL);
9655 if (lasttoken != TIN)
9657 cpp = &n1->ncase.cases;
9659 checkkwd = CHKNL | CHKKWD;
9662 if (lasttoken == TLP)
9664 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
9666 app = &cp->nclist.pattern;
9668 *app = ap = (union node *)stalloc(sizeof (struct narg));
9670 ap->narg.text = wordtext;
9671 ap->narg.backquote = backquotelist;
9672 if (readtoken() != TPIPE)
9674 app = &ap->narg.next;
9677 ap->narg.next = NULL;
9678 if (lasttoken != TRP)
9680 cp->nclist.body = list(2);
9682 cpp = &cp->nclist.next;
9684 checkkwd = CHKNL | CHKKWD;
9685 if ((t = readtoken()) != TESAC) {
9687 synexpect(TENDCASE);
9695 n1 = (union node *)stalloc(sizeof (struct nredir));
9696 n1->type = NSUBSHELL;
9697 n1->nredir.n = list(0);
9698 n1->nredir.redirect = NULL;
9711 if (readtoken() != t)
9715 /* Now check for redirection which may follow command */
9716 checkkwd = CHKKWD | CHKALIAS;
9718 while (readtoken() == TREDIR) {
9719 *rpp = n2 = redirnode;
9720 rpp = &n2->nfile.next;
9726 if (n1->type != NSUBSHELL) {
9727 n2 = (union node *)stalloc(sizeof (struct nredir));
9732 n1->nredir.redirect = redir;
9741 union node *args, **app;
9742 union node *n = NULL;
9743 union node *vars, **vpp;
9744 union node **rpp, *redir;
9754 savecheckkwd = CHKALIAS;
9756 checkkwd = savecheckkwd;
9757 switch (readtoken()) {
9759 n = (union node *)stalloc(sizeof (struct narg));
9761 n->narg.text = wordtext;
9762 n->narg.backquote = backquotelist;
9763 if (savecheckkwd && isassignment(wordtext)) {
9765 vpp = &n->narg.next;
9768 app = &n->narg.next;
9773 *rpp = n = redirnode;
9774 rpp = &n->nfile.next;
9775 parsefname(); /* read name of redirection file */
9779 args && app == &args->narg.next &&
9782 struct builtincmd *bcmd;
9785 /* We have a function */
9786 if (readtoken() != TRP)
9788 name = n->narg.text;
9790 !goodname(name) || (
9791 (bcmd = find_builtin(name)) &&
9792 IS_BUILTIN_SPECIAL(bcmd)
9795 synerror("Bad function name");
9797 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9798 n->narg.next = command();
9811 n = (union node *)stalloc(sizeof (struct ncmd));
9813 n->ncmd.args = args;
9814 n->ncmd.assign = vars;
9815 n->ncmd.redirect = redir;
9824 n = (union node *)stalloc(sizeof (struct narg));
9826 n->narg.next = NULL;
9827 n->narg.text = wordtext;
9828 n->narg.backquote = backquotelist;
9832 void fixredir(union node *n, const char *text, int err)
9834 TRACE(("Fix redir %s %d\n", text, err));
9836 n->ndup.vname = NULL;
9838 if (is_digit(text[0]) && text[1] == '\0')
9839 n->ndup.dupfd = digit_val(text[0]);
9840 else if (text[0] == '-' && text[1] == '\0')
9845 synerror("Bad fd number");
9847 n->ndup.vname = makename();
9855 union node *n = redirnode;
9857 if (readtoken() != TWORD)
9859 if (n->type == NHERE) {
9860 struct heredoc *here = heredoc;
9866 TRACE(("Here document %d\n", n->type));
9867 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
9868 synerror("Illegal eof marker for << redirection");
9869 rmescapes(wordtext);
9870 here->eofmark = wordtext;
9872 if (heredoclist == NULL)
9875 for (p = heredoclist ; p->next ; p = p->next);
9878 } else if (n->type == NTOFD || n->type == NFROMFD) {
9879 fixredir(n, wordtext, 0);
9881 n->nfile.fname = makename();
9887 * Input any here documents.
9893 struct heredoc *here;
9903 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9904 here->eofmark, here->striptabs);
9905 n = (union node *)stalloc(sizeof (struct narg));
9906 n->narg.type = NARG;
9907 n->narg.next = NULL;
9908 n->narg.text = wordtext;
9909 n->narg.backquote = backquotelist;
9910 here->here->nhere.doc = n;
9915 static char peektoken(void)
9921 return tokname_array[t][0];
9929 int alreadyseen = tokpushback;
9932 #ifdef CONFIG_ASH_ALIAS
9941 if (checkkwd & CHKNL) {
9948 if (t != TWORD || quoteflag) {
9953 * check for keywords
9955 if (checkkwd & CHKKWD) {
9956 const char *const *pp;
9958 if ((pp = findkwd(wordtext))) {
9959 lasttoken = t = pp - tokname_array;
9960 TRACE(("keyword %s recognized\n", tokname(t)));
9965 if (checkkwd & CHKALIAS) {
9966 #ifdef CONFIG_ASH_ALIAS
9968 if ((ap = lookupalias(wordtext, 1)) != NULL) {
9970 pushstring(ap->val, ap);
9980 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
9982 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
9989 * Read the next input token.
9990 * If the token is a word, we set backquotelist to the list of cmds in
9991 * backquotes. We set quoteflag to true if any part of the word was
9993 * If the token is TREDIR, then we set redirnode to a structure containing
9995 * In all cases, the variable startlinno is set to the number of the line
9996 * on which the token starts.
9998 * [Change comment: here documents and internal procedures]
9999 * [Readtoken shouldn't have any arguments. Perhaps we should make the
10000 * word parsing code into a separate routine. In this case, readtoken
10001 * doesn't need to have any internal procedures, but parseword does.
10002 * We could also make parseoperator in essence the main routine, and
10003 * have parseword (readtoken1?) handle both words and redirection.]
10006 #define NEW_xxreadtoken
10007 #ifdef NEW_xxreadtoken
10009 /* singles must be first! */
10010 static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
10012 static const char xxreadtoken_tokens[] = {
10013 TNL, TLP, TRP, /* only single occurrence allowed */
10014 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
10015 TEOF, /* corresponds to trailing nul */
10016 TAND, TOR, TENDCASE, /* if double occurrence */
10019 #define xxreadtoken_doubles \
10020 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
10021 #define xxreadtoken_singles \
10022 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
10024 static int xxreadtoken()
10035 startlinno = plinno;
10036 for (;;) { /* until token or start of word found */
10039 if ((c != ' ') && (c != '\t')
10040 #ifdef CONFIG_ASH_ALIAS
10045 while ((c = pgetc()) != '\n' && c != PEOF);
10047 } else if (c == '\\') {
10048 if (pgetc() != '\n') {
10052 startlinno = ++plinno;
10057 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10062 needprompt = doprompt;
10065 p = strchr(xxreadtoken_chars, c);
10068 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
10071 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
10072 if (pgetc() == *p) { /* double occurrence? */
10073 p += xxreadtoken_doubles + 1;
10080 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
10088 #define RETURN(token) return lasttoken = token
10102 startlinno = plinno;
10103 for (;;) { /* until token or start of word found */
10106 case ' ': case '\t':
10107 #ifdef CONFIG_ASH_ALIAS
10112 while ((c = pgetc()) != '\n' && c != PEOF);
10116 if (pgetc() == '\n') {
10117 startlinno = ++plinno;
10126 needprompt = doprompt;
10131 if (pgetc() == '&')
10136 if (pgetc() == '|')
10141 if (pgetc() == ';')
10154 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10157 #endif /* NEW_xxreadtoken */
10161 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10162 * is not NULL, read a here document. In the latter case, eofmark is the
10163 * word which marks the end of the document and striptabs is true if
10164 * leading tabs should be stripped from the document. The argument firstc
10165 * is the first character of the input token or document.
10167 * Because C does not have internal subroutines, I have simulated them
10168 * using goto's to implement the subroutine linkage. The following macros
10169 * will run code that appears at the end of readtoken1.
10172 #define CHECKEND() {goto checkend; checkend_return:;}
10173 #define PARSEREDIR() {goto parseredir; parseredir_return:;}
10174 #define PARSESUB() {goto parsesub; parsesub_return:;}
10175 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10176 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10177 #define PARSEARITH() {goto parsearith; parsearith_return:;}
10180 readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
10185 char line[EOFMARKLEN + 1];
10186 struct nodelist *bqlist;
10189 int varnest; /* levels of variables expansion */
10190 int arinest; /* levels of arithmetic expansion */
10191 int parenlevel; /* levels of parens in arithmetic */
10192 int dqvarnest; /* levels of variables expansion within double quotes */
10194 int prevsyntax; /* syntax before arithmetic */
10196 /* Avoid longjmp clobbering */
10202 (void) &parenlevel;
10205 (void) &prevsyntax;
10209 startlinno = plinno;
10211 if (syntax == DQSYNTAX)
10220 STARTSTACKSTR(out);
10221 loop: { /* for each line, until end of word */
10222 CHECKEND(); /* set c to PEOF if at end of here document */
10223 for (;;) { /* until end of line or end of word */
10224 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10225 switch(SIT(c, syntax)) {
10226 case CNL: /* '\n' */
10227 if (syntax == BASESYNTAX)
10228 goto endword; /* exit outer loop */
10234 goto loop; /* continue outer loop */
10239 if (eofmark == NULL || dblquote)
10240 USTPUTC(CTLESC, out);
10243 case CBACK: /* backslash */
10246 USTPUTC(CTLESC, out);
10247 USTPUTC('\\', out);
10249 } else if (c == '\n') {
10255 c != '\\' && c != '`' &&
10261 USTPUTC(CTLESC, out);
10262 USTPUTC('\\', out);
10264 if (SIT(c, SQSYNTAX) == CCTL)
10265 USTPUTC(CTLESC, out);
10273 if (eofmark == NULL) {
10274 USTPUTC(CTLQUOTEMARK, out);
10282 if (eofmark != NULL && arinest == 0 &&
10286 if (dqvarnest == 0) {
10287 syntax = BASESYNTAX;
10294 case CVAR: /* '$' */
10295 PARSESUB(); /* parse substitution */
10297 case CENDVAR: /* '}' */
10300 if (dqvarnest > 0) {
10303 USTPUTC(CTLENDVAR, out);
10308 #ifdef CONFIG_ASH_MATH_SUPPORT
10309 case CLP: /* '(' in arithmetic */
10313 case CRP: /* ')' in arithmetic */
10314 if (parenlevel > 0) {
10318 if (pgetc() == ')') {
10319 if (--arinest == 0) {
10320 USTPUTC(CTLENDARI, out);
10321 syntax = prevsyntax;
10322 if (syntax == DQSYNTAX)
10330 * unbalanced parens
10331 * (don't 2nd guess - no error)
10339 case CBQUOTE: /* '`' */
10343 goto endword; /* exit outer loop */
10348 goto endword; /* exit outer loop */
10349 #ifdef CONFIG_ASH_ALIAS
10359 #ifdef CONFIG_ASH_MATH_SUPPORT
10360 if (syntax == ARISYNTAX)
10361 synerror("Missing '))'");
10363 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10364 synerror("Unterminated quoted string");
10365 if (varnest != 0) {
10366 startlinno = plinno;
10368 synerror("Missing '}'");
10370 USTPUTC('\0', out);
10371 len = out - (char *)stackblock();
10372 out = stackblock();
10373 if (eofmark == NULL) {
10374 if ((c == '>' || c == '<')
10377 && (*out == '\0' || is_digit(*out))) {
10379 return lasttoken = TREDIR;
10384 quoteflag = quotef;
10385 backquotelist = bqlist;
10386 grabstackblock(len);
10388 return lasttoken = TWORD;
10389 /* end of readtoken routine */
10394 * Check to see whether we are at the end of the here document. When this
10395 * is called, c is set to the first character of the next input line. If
10396 * we are at the end of the here document, this routine sets the c to PEOF.
10401 #ifdef CONFIG_ASH_ALIAS
10407 while (c == '\t') {
10411 if (c == *eofmark) {
10412 if (pfgets(line, sizeof line) != NULL) {
10416 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10417 if (*p == '\n' && *q == '\0') {
10420 needprompt = doprompt;
10422 pushstring(line, NULL);
10427 goto checkend_return;
10432 * Parse a redirection operator. The variable "out" points to a string
10433 * specifying the fd to be redirected. The variable "c" contains the
10434 * first character of the redirection operator.
10441 np = (union node *)stalloc(sizeof (struct nfile));
10446 np->type = NAPPEND;
10448 np->type = NCLOBBER;
10455 } else { /* c == '<' */
10457 switch (c = pgetc()) {
10459 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10460 np = (union node *)stalloc(sizeof (struct nhere));
10464 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10465 heredoc->here = np;
10466 if ((c = pgetc()) == '-') {
10467 heredoc->striptabs = 1;
10469 heredoc->striptabs = 0;
10475 np->type = NFROMFD;
10479 np->type = NFROMTO;
10489 np->nfile.fd = digit_val(fd);
10491 goto parseredir_return;
10496 * Parse a substitution. At this point, we have read the dollar sign
10497 * and nothing else.
10505 static const char types[] = "}-+?=";
10509 c <= PEOA_OR_PEOF ||
10510 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10514 } else if (c == '(') { /* $(command) or $((arith)) */
10515 if (pgetc() == '(') {
10516 #ifdef CONFIG_ASH_MATH_SUPPORT
10519 synerror("We unsupport $((arith))");
10526 USTPUTC(CTLVAR, out);
10527 typeloc = out - (char *)stackblock();
10528 USTPUTC(VSNORMAL, out);
10529 subtype = VSNORMAL;
10533 if ((c = pgetc()) == '}')
10536 subtype = VSLENGTH;
10541 if (c > PEOA_OR_PEOF && is_name(c)) {
10545 } while (c > PEOA_OR_PEOF && is_in_name(c));
10546 } else if (is_digit(c)) {
10550 } while (is_digit(c));
10552 else if (is_special(c)) {
10557 badsub: synerror("Bad substitution");
10561 if (subtype == 0) {
10568 p = strchr(types, c);
10571 subtype = p - types + VSNORMAL;
10577 subtype = c == '#' ? VSTRIMLEFT :
10590 if (dblquote || arinest)
10592 *((char *)stackblock() + typeloc) = subtype | flags;
10593 if (subtype != VSNORMAL) {
10595 if (dblquote || arinest) {
10600 goto parsesub_return;
10605 * Called to parse command substitutions. Newstyle is set if the command
10606 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10607 * list of commands (passed by reference), and savelen is the number of
10608 * characters on the top of the stack which must be preserved.
10612 struct nodelist **nlpp;
10615 char *volatile str;
10616 struct jmploc jmploc;
10617 struct jmploc *volatile savehandler;
10621 (void) &saveprompt;
10624 savepbq = parsebackquote;
10625 if (setjmp(jmploc.loc)) {
10628 parsebackquote = 0;
10629 handler = savehandler;
10630 longjmp(handler->loc, 1);
10634 savelen = out - (char *)stackblock();
10636 str = ckmalloc(savelen);
10637 memcpy(str, stackblock(), savelen);
10639 savehandler = handler;
10643 /* We must read until the closing backquote, giving special
10644 treatment to some slashes, and then push the string and
10645 reread it as input, interpreting it normally. */
10652 STARTSTACKSTR(pout);
10657 switch (pc = pgetc()) {
10662 if ((pc = pgetc()) == '\n') {
10667 * If eating a newline, avoid putting
10668 * the newline into the new character
10669 * stream (via the STPUTC after the
10674 if (pc != '\\' && pc != '`' && pc != '$'
10675 && (!dblquote || pc != '"'))
10676 STPUTC('\\', pout);
10677 if (pc > PEOA_OR_PEOF) {
10683 #ifdef CONFIG_ASH_ALIAS
10686 startlinno = plinno;
10687 synerror("EOF in backquote substitution");
10691 needprompt = doprompt;
10700 STPUTC('\0', pout);
10701 psavelen = pout - (char *)stackblock();
10702 if (psavelen > 0) {
10703 pstr = grabstackstr(pout);
10704 setinputstring(pstr);
10709 nlpp = &(*nlpp)->next;
10710 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10711 (*nlpp)->next = NULL;
10712 parsebackquote = oldstyle;
10715 saveprompt = doprompt;
10722 doprompt = saveprompt;
10724 if (readtoken() != TRP)
10731 * Start reading from old file again, ignoring any pushed back
10732 * tokens left from the backquote parsing
10737 while (stackblocksize() <= savelen)
10739 STARTSTACKSTR(out);
10741 memcpy(out, str, savelen);
10742 STADJUST(savelen, out);
10748 parsebackquote = savepbq;
10749 handler = savehandler;
10750 if (arinest || dblquote)
10751 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10753 USTPUTC(CTLBACKQ, out);
10755 goto parsebackq_oldreturn;
10757 goto parsebackq_newreturn;
10760 #ifdef CONFIG_ASH_MATH_SUPPORT
10762 * Parse an arithmetic expansion (indicate start of one and set state)
10766 if (++arinest == 1) {
10767 prevsyntax = syntax;
10768 syntax = ARISYNTAX;
10769 USTPUTC(CTLARI, out);
10776 * we collapse embedded arithmetic expansion to
10777 * parenthesis, which should be equivalent
10781 goto parsearith_return;
10785 } /* end of readtoken */
10790 * Returns true if the text contains nothing to expand (no dollar signs
10795 noexpand(char *text)
10801 while ((c = *p++) != '\0') {
10802 if (c == CTLQUOTEMARK)
10806 else if (SIT(c, BASESYNTAX) == CCTL)
10814 * Return of a legal variable name (a letter or underscore followed by zero or
10815 * more letters, underscores, and digits).
10819 endofname(const char *name)
10827 if (! is_in_name(*p))
10835 * Called when an unexpected token is read during the parse. The argument
10836 * is the token that is expected, or -1 if more than one type of token can
10837 * occur at this point.
10840 static void synexpect(int token)
10845 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10847 sprintf(msg + l, " (expecting %s)", tokname(token));
10853 synerror(const char *msg)
10855 error("Syntax error: %s", msg);
10861 * called by editline -- any expansions to the prompt
10862 * should be added here.
10865 #ifdef CONFIG_ASH_EXPAND_PRMT
10866 static const char *
10867 expandstr(const char *ps)
10871 /* XXX Fix (char *) cast. */
10872 setinputstring((char *)ps);
10873 readtoken1(pgetc(), DQSYNTAX, nullstr, 0);
10876 n.narg.type = NARG;
10877 n.narg.next = NULL;
10878 n.narg.text = wordtext;
10879 n.narg.backquote = backquotelist;
10881 expandarg(&n, NULL, 0);
10882 return stackblock();
10886 static void setprompt(int whichprompt)
10888 const char *prompt;
10889 #ifdef CONFIG_ASH_EXPAND_PRMT
10890 struct stackmark smark;
10895 switch (whichprompt) {
10905 #ifdef CONFIG_ASH_EXPAND_PRMT
10906 setstackmark(&smark);
10907 stalloc(stackblocksize());
10909 putprompt(expandstr(prompt));
10910 #ifdef CONFIG_ASH_EXPAND_PRMT
10911 popstackmark(&smark);
10916 static const char *const *findkwd(const char *s)
10918 return bsearch(s, tokname_array + KWDOFFSET,
10919 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
10920 sizeof(const char *), pstrcmp);
10923 /* $NetBSD: redir.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
10926 * Code for dealing with input/output redirection.
10929 #define EMPTY -2 /* marks an unused slot in redirtab */
10931 # define PIPESIZE 4096 /* amount of buffering in a pipe */
10933 # define PIPESIZE PIPE_BUF
10937 * Open a file in noclobber mode.
10938 * The code was copied from bash.
10941 noclobberopen(const char *fname)
10944 struct stat finfo, finfo2;
10947 * If the file exists and is a regular file, return an error
10950 r = stat(fname, &finfo);
10951 if (r == 0 && S_ISREG(finfo.st_mode)) {
10957 * If the file was not present (r != 0), make sure we open it
10958 * exclusively so that if it is created before we open it, our open
10959 * will fail. Make sure that we do not truncate an existing file.
10960 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10961 * file was not a regular file, we leave O_EXCL off.
10964 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10965 fd = open(fname, O_WRONLY|O_CREAT, 0666);
10967 /* If the open failed, return the file descriptor right away. */
10972 * OK, the open succeeded, but the file may have been changed from a
10973 * non-regular file to a regular file between the stat and the open.
10974 * We are assuming that the O_EXCL open handles the case where FILENAME
10975 * did not exist and is symlinked to an existing file between the stat
10980 * If we can open it and fstat the file descriptor, and neither check
10981 * revealed that it was a regular file, and the file has not been
10982 * replaced, return the file descriptor.
10984 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10985 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
10988 /* The file has been replaced. badness. */
10995 * Handle here documents. Normally we fork off a process to write the
10996 * data to a pipe. If the document is short, we can stuff the data in
10997 * the pipe without forking.
11001 openhere(union node *redir)
11007 error("Pipe call failed");
11008 if (redir->type == NHERE) {
11009 len = strlen(redir->nhere.doc->narg.text);
11010 if (len <= PIPESIZE) {
11011 bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
11015 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
11017 signal(SIGINT, SIG_IGN);
11018 signal(SIGQUIT, SIG_IGN);
11019 signal(SIGHUP, SIG_IGN);
11021 signal(SIGTSTP, SIG_IGN);
11023 signal(SIGPIPE, SIG_DFL);
11024 if (redir->type == NHERE)
11025 bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
11027 expandhere(redir->nhere.doc, pip[1]);
11036 openredirect(union node *redir)
11041 switch (redir->nfile.type) {
11043 fname = redir->nfile.expfname;
11044 if ((f = open(fname, O_RDONLY)) < 0)
11048 fname = redir->nfile.expfname;
11049 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
11053 /* Take care of noclobber mode. */
11055 fname = redir->nfile.expfname;
11056 if ((f = noclobberopen(fname)) < 0)
11062 fname = redir->nfile.expfname;
11063 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
11067 fname = redir->nfile.expfname;
11068 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
11075 /* Fall through to eliminate warning. */
11082 f = openhere(redir);
11088 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
11090 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11094 dupredirect(union node *redir, int f)
11096 int fd = redir->nfile.fd;
11098 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11099 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
11100 copyfd(redir->ndup.dupfd, fd);
11113 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11114 * old file descriptors are stashed away so that the redirection can be
11115 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11116 * standard output, and the standard error if it becomes a duplicate of
11117 * stdout, is saved in memory.
11121 redirect(union node *redir, int flags)
11124 struct redirtab *sv;
11135 if (flags & REDIR_PUSH) {
11136 struct redirtab *q;
11137 q = ckmalloc(sizeof (struct redirtab));
11138 q->next = redirlist;
11140 q->nullredirs = nullredirs - 1;
11141 for (i = 0 ; i < 10 ; i++)
11142 q->renamed[i] = EMPTY;
11149 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
11150 n->ndup.dupfd == fd)
11151 continue; /* redirect from/to same file descriptor */
11153 newfd = openredirect(n);
11156 if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
11157 i = fcntl(fd, F_DUPFD, 10);
11164 error("%d: %m", fd);
11174 dupredirect(n, newfd);
11175 } while ((n = n->nfile.next));
11177 if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
11178 preverrout_fd = sv->renamed[2];
11183 * Undo the effects of the last redirection.
11189 struct redirtab *rp;
11192 if (--nullredirs >= 0)
11196 for (i = 0 ; i < 10 ; i++) {
11197 if (rp->renamed[i] != EMPTY) {
11200 copyfd(rp->renamed[i], i);
11202 close(rp->renamed[i]);
11205 redirlist = rp->next;
11206 nullredirs = rp->nullredirs;
11212 * Undo all redirections. Called on error or interrupt.
11216 * Discard all saved file descriptors.
11220 clearredir(int drop)
11232 * Copy a file descriptor to be >= to. Returns -1
11233 * if the source file descriptor is closed, EMPTY if there are no unused
11234 * file descriptors left.
11238 copyfd(int from, int to)
11242 newfd = fcntl(from, F_DUPFD, to);
11244 if (errno == EMFILE)
11247 error("%d: %m", from);
11254 redirectsafe(union node *redir, int flags)
11257 volatile int saveint;
11258 struct jmploc *volatile savehandler = handler;
11259 struct jmploc jmploc;
11262 if (!(err = setjmp(jmploc.loc) * 2)) {
11264 redirect(redir, flags);
11266 handler = savehandler;
11267 if (err && exception != EXERROR)
11268 longjmp(handler->loc, 1);
11269 RESTOREINT(saveint);
11273 /* $NetBSD: show.c,v 1.24 2003/01/22 20:36:04 dsl Exp $ */
11276 static void shtree(union node *, int, char *, FILE*);
11277 static void shcmd(union node *, FILE *);
11278 static void sharg(union node *, FILE *);
11279 static void indent(int, char *, FILE *);
11280 static void trstring(char *);
11284 showtree(union node *n)
11286 trputs("showtree called\n");
11287 shtree(n, 1, NULL, stdout);
11292 shtree(union node *n, int ind, char *pfx, FILE *fp)
11294 struct nodelist *lp;
11300 indent(ind, pfx, fp);
11311 shtree(n->nbinary.ch1, ind, NULL, fp);
11314 shtree(n->nbinary.ch2, ind, NULL, fp);
11322 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
11327 if (n->npipe.backgnd)
11333 fprintf(fp, "<node type %d>", n->type);
11342 shcmd(union node *cmd, FILE *fp)
11350 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11356 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11359 switch (np->nfile.type) {
11360 case NTO: s = ">"; dftfd = 1; break;
11361 case NCLOBBER: s = ">|"; dftfd = 1; break;
11362 case NAPPEND: s = ">>"; dftfd = 1; break;
11363 case NTOFD: s = ">&"; dftfd = 1; break;
11364 case NFROM: s = "<"; dftfd = 0; break;
11365 case NFROMFD: s = "<&"; dftfd = 0; break;
11366 case NFROMTO: s = "<>"; dftfd = 0; break;
11367 default: s = "*error*"; dftfd = 0; break;
11369 if (np->nfile.fd != dftfd)
11370 fprintf(fp, "%d", np->nfile.fd);
11372 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11373 fprintf(fp, "%d", np->ndup.dupfd);
11375 sharg(np->nfile.fname, fp);
11384 sharg(union node *arg, FILE *fp)
11387 struct nodelist *bqlist;
11390 if (arg->type != NARG) {
11391 out1fmt("<node type %d>\n", arg->type);
11394 bqlist = arg->narg.backquote;
11395 for (p = arg->narg.text ; *p ; p++) {
11404 if (subtype == VSLENGTH)
11410 if (subtype & VSNUL)
11413 switch (subtype & VSTYPE) {
11432 case VSTRIMLEFTMAX:
11439 case VSTRIMRIGHTMAX:
11446 out1fmt("<subtype %d>", subtype);
11453 case CTLBACKQ|CTLQUOTE:
11456 shtree(bqlist->n, -1, NULL, fp);
11468 indent(int amount, char *pfx, FILE *fp)
11472 for (i = 0 ; i < amount ; i++) {
11473 if (pfx && i == amount - 1)
11494 putc(c, tracefile);
11498 trace(const char *fmt, ...)
11505 (void) vfprintf(tracefile, fmt, va);
11510 tracev(const char *fmt, va_list va)
11514 (void) vfprintf(tracefile, fmt, va);
11519 trputs(const char *s)
11523 fputs(s, tracefile);
11535 putc('"', tracefile);
11536 for (p = s ; *p ; p++) {
11538 case '\n': c = 'n'; goto backslash;
11539 case '\t': c = 't'; goto backslash;
11540 case '\r': c = 'r'; goto backslash;
11541 case '"': c = '"'; goto backslash;
11542 case '\\': c = '\\'; goto backslash;
11543 case CTLESC: c = 'e'; goto backslash;
11544 case CTLVAR: c = 'v'; goto backslash;
11545 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11546 case CTLBACKQ: c = 'q'; goto backslash;
11547 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
11548 backslash: putc('\\', tracefile);
11549 putc(c, tracefile);
11552 if (*p >= ' ' && *p <= '~')
11553 putc(*p, tracefile);
11555 putc('\\', tracefile);
11556 putc(*p >> 6 & 03, tracefile);
11557 putc(*p >> 3 & 07, tracefile);
11558 putc(*p & 07, tracefile);
11563 putc('"', tracefile);
11575 putc(' ', tracefile);
11577 putc('\n', tracefile);
11593 /* leave open because libedit might be using it */
11596 scopy("./trace", s);
11598 if (!freopen(s, "a", tracefile)) {
11599 fprintf(stderr, "Can't re-open %s\n", s);
11604 if ((tracefile = fopen(s, "a")) == NULL) {
11605 fprintf(stderr, "Can't open %s\n", s);
11611 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11612 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11614 setlinebuf(tracefile);
11615 fputs("\nTracing started.\n", tracefile);
11620 /* $NetBSD: trap.c,v 1.28 2002/11/24 22:35:43 christos Exp $ */
11623 * Sigmode records the current value of the signal handlers for the various
11624 * modes. A value of zero means that the current handler is not known.
11625 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
11628 #define S_DFL 1 /* default signal handling (SIG_DFL) */
11629 #define S_CATCH 2 /* signal is caught */
11630 #define S_IGN 3 /* signal is ignored (SIG_IGN) */
11631 #define S_HARD_IGN 4 /* signal is ignored permenantly */
11632 #define S_RESET 5 /* temporary - to reset a hard ignored sig */
11637 * The trap builtin.
11641 trapcmd(int argc, char **argv)
11650 for (signo = 0 ; signo < NSIG ; signo++) {
11651 if (trap[signo] != NULL) {
11654 sn = u_signal_names(0, &signo, 0);
11657 out1fmt("trap -- %s %s\n",
11658 single_quote(trap[signo]), sn);
11668 if ((signo = decode_signal(*ap, 0)) < 0)
11669 error("%s: bad trap", *ap);
11672 if (action[0] == '-' && action[1] == '\0')
11675 action = savestr(action);
11678 ckfree(trap[signo]);
11679 trap[signo] = action;
11690 * Clear traps on a fork.
11698 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
11699 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
11703 if (tp != &trap[0])
11704 setsignal(tp - trap);
11712 * Set the signal handler for the specified signal. The routine figures
11713 * out what it should be set to.
11717 setsignal(int signo)
11721 struct sigaction act;
11723 if ((t = trap[signo]) == NULL)
11725 else if (*t != '\0')
11729 if (rootshell && action == S_DFL) {
11732 if (iflag || minusc || sflag == 0)
11755 t = &sigmode[signo - 1];
11759 * current setting unknown
11761 if (sigaction(signo, 0, &act) == -1) {
11763 * Pretend it worked; maybe we should give a warning
11764 * here, but other shells don't. We don't alter
11765 * sigmode, so that we retry every time.
11769 if (act.sa_handler == SIG_IGN) {
11770 if (mflag && (signo == SIGTSTP ||
11771 signo == SIGTTIN || signo == SIGTTOU)) {
11772 tsig = S_IGN; /* don't hard ignore these */
11776 tsig = S_RESET; /* force to be set */
11779 if (tsig == S_HARD_IGN || tsig == action)
11783 act.sa_handler = onsig;
11786 act.sa_handler = SIG_IGN;
11789 act.sa_handler = SIG_DFL;
11793 sigfillset(&act.sa_mask);
11794 sigaction(signo, &act, 0);
11802 ignoresig(int signo)
11804 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11805 signal(signo, SIG_IGN);
11807 sigmode[signo - 1] = S_HARD_IGN;
11818 gotsig[signo - 1] = 1;
11819 pendingsigs = signo;
11821 if (exsig || (signo == SIGINT && !trap[SIGINT])) {
11830 * Called to execute a trap. Perhaps we should avoid entering new trap
11831 * handlers while we are executing a trap handler.
11841 savestatus = exitstatus;
11843 while (pendingsigs = 0, xbarrier(), (p = memchr(q, 1, NSIG - 1))) {
11845 p = trap[p - q + 1];
11849 exitstatus = savestatus;
11855 * Controls whether the shell is interactive or not.
11859 setinteractive(int on)
11861 static int is_interactive;
11863 if (++on == is_interactive)
11865 is_interactive = on;
11867 setsignal(SIGQUIT);
11868 setsignal(SIGTERM);
11869 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11870 if(is_interactive > 1) {
11871 /* Looks like they want an interactive shell */
11872 static int do_banner;
11876 "\n\n" BB_BANNER " Built-in shell (ash)\n"
11877 "Enter 'help' for a list of built-in commands.\n\n");
11885 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11886 /*** List the available builtins ***/
11888 static int helpcmd(int argc, char **argv)
11892 out1fmt("\nBuilt-in commands:\n-------------------\n");
11893 for (col = 0, i = 0; i < NUMBUILTINS; i++) {
11894 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11895 builtincmd[i].name + 1);
11901 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
11903 extern const struct BB_applet applets[];
11904 extern const size_t NUM_APPLETS;
11906 for (i = 0; i < NUM_APPLETS; i++) {
11908 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
11917 return EXIT_SUCCESS;
11919 #endif /* CONFIG_FEATURE_SH_EXTRA_QUIET */
11922 * Called to exit the shell.
11933 jmp = setjmp(loc.loc);
11934 status = exitstatus;
11935 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
11939 if ((p = trap[0]) != NULL && *p != '\0') {
11945 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
11946 if (iflag && rootshell) {
11947 const char *hp = lookupvar("HISTFILE");
11950 save_history ( hp );
11958 static int decode_signal(const char *string, int minsig)
11961 const char *name = u_signal_names(string, &signo, minsig);
11963 return name ? signo : -1;
11966 /* $NetBSD: var.c,v 1.32 2003/01/22 20:36:04 dsl Exp $ */
11968 static struct var *vartab[VTABSIZE];
11970 static int vpcmp(const void *, const void *);
11971 static struct var **findvar(struct var **, const char *);
11974 * Initialize the variable symbol tables and import the environment
11978 #ifdef CONFIG_ASH_GETOPTS
11980 * Safe version of setvar, returns 1 on success 0 on failure.
11984 setvarsafe(const char *name, const char *val, int flags)
11987 volatile int saveint;
11988 struct jmploc *volatile savehandler = handler;
11989 struct jmploc jmploc;
11992 if (setjmp(jmploc.loc))
11996 setvar(name, val, flags);
11999 handler = savehandler;
12000 RESTOREINT(saveint);
12006 * Set the value of a variable. The flags argument is ored with the
12007 * flags of the variable. If val is NULL, the variable is unset.
12011 setvar(const char *name, const char *val, int flags)
12018 q = endofname(name);
12019 p = strchrnul(q, '=');
12020 namelen = p - name;
12021 if (!namelen || p != q)
12022 error("%.*s: bad variable name", namelen, name);
12027 vallen = strlen(val);
12030 p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
12034 p = mempcpy(p, val, vallen);
12037 setvareq(nameeq, flags | VNOSAVE);
12043 * Same as setvar except that the variable and value are passed in
12044 * the first argument as name=value. Since the first argument will
12045 * be actually stored in the table, it should not be a string that
12047 * Called with interrupts off.
12051 setvareq(char *s, int flags)
12053 struct var *vp, **vpp;
12056 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
12057 vp = *findvar(vpp, s);
12059 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
12062 if (flags & VNOSAVE)
12065 error("%.*s: is read only", strchrnul(n, '=') - n, n);
12068 if (flags & VNOSET)
12071 if (vp->func && (flags & VNOFUNC) == 0)
12072 (*vp->func)(strchrnul(s, '=') + 1);
12074 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12077 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
12079 if (flags & VNOSET)
12082 vp = ckmalloc(sizeof (*vp));
12087 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
12095 * Process a linked list of variable assignments.
12099 listsetvar(struct strlist *list_set_var, int flags)
12101 struct strlist *lp = list_set_var;
12107 setvareq(lp->text, flags);
12108 } while ((lp = lp->next));
12114 * Find the value of a variable. Returns NULL if not set.
12118 lookupvar(const char *name)
12122 if ((v = *findvar(hashvar(name), name))) {
12125 * Dynamic variables are implemented roughly the same way they are
12126 * in bash. Namely, they're "special" so long as they aren't unset.
12127 * As soon as they're unset, they're no longer dynamic, and dynamic
12128 * lookup will no longer happen at that point. -- PFM.
12130 if((v->flags & VDYNAMIC))
12133 if(!(v->flags & VUNSET))
12134 return strchrnul(v->text, '=') + 1;
12142 * Search the environment of a builtin command.
12146 bltinlookup(const char *name)
12148 struct strlist *sp;
12150 for (sp = cmdenviron ; sp ; sp = sp->next) {
12151 if (varequal(sp->text, name))
12152 return strchrnul(sp->text, '=') + 1;
12154 return lookupvar(name);
12159 * Generate a list of variables satisfying the given conditions.
12163 listvars(int on, int off, char ***end)
12174 for (vp = *vpp ; vp ; vp = vp->next)
12175 if ((vp->flags & mask) == on) {
12176 if (ep == stackstrend())
12177 ep = growstackstr();
12178 *ep++ = (char *) vp->text;
12180 } while (++vpp < vartab + VTABSIZE);
12181 if (ep == stackstrend())
12182 ep = growstackstr();
12186 return grabstackstr(ep);
12191 * POSIX requires that 'set' (but not export or readonly) output the
12192 * variables in lexicographic order - by the locale's collating order (sigh).
12193 * Maybe we could keep them in an ordered balanced binary tree
12194 * instead of hashed lists.
12195 * For now just roll 'em through qsort for printing...
12199 showvars(const char *sep_prefix, int on, int off)
12202 char **ep, **epend;
12204 ep = listvars(on, off, &epend);
12205 qsort(ep, epend - ep, sizeof(char *), vpcmp);
12207 sep = *sep_prefix ? spcstr : sep_prefix;
12209 for (; ep < epend; ep++) {
12213 p = strchrnul(*ep, '=');
12216 q = single_quote(++p);
12218 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
12227 * The export and readonly commands.
12231 exportcmd(int argc, char **argv)
12237 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12240 notp = nextopt("p") - 'p';
12241 if (notp && ((name = *(aptr = argptr)))) {
12243 if ((p = strchr(name, '=')) != NULL) {
12246 if ((vp = *findvar(hashvar(name), name))) {
12251 setvar(name, p, flag);
12252 } while ((name = *++aptr) != NULL);
12254 showvars(argv[0], flag, 0);
12261 * Make a variable a local variable. When a variable is made local, it's
12262 * value and flags are saved in a localvar structure. The saved values
12263 * will be restored when the shell function returns. We handle the name
12264 * "-" as a special case.
12268 mklocal(char *name)
12270 struct localvar *lvp;
12275 lvp = ckmalloc(sizeof (struct localvar));
12276 if (name[0] == '-' && name[1] == '\0') {
12278 p = ckmalloc(sizeof(optlist));
12279 lvp->text = memcpy(p, optlist, sizeof(optlist));
12284 vpp = hashvar(name);
12285 vp = *findvar(vpp, name);
12286 eq = strchr(name, '=');
12289 setvareq(name, VSTRFIXED);
12291 setvar(name, NULL, VSTRFIXED);
12292 vp = *vpp; /* the new variable */
12293 lvp->flags = VUNSET;
12295 lvp->text = vp->text;
12296 lvp->flags = vp->flags;
12297 vp->flags |= VSTRFIXED|VTEXTFIXED;
12303 lvp->next = localvars;
12309 * The "local" command.
12313 localcmd(int argc, char **argv)
12318 while ((name = *argv++) != NULL) {
12326 * Called after a function returns.
12327 * Interrupts must be off.
12333 struct localvar *lvp;
12336 while ((lvp = localvars) != NULL) {
12337 localvars = lvp->next;
12339 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
12340 if (vp == NULL) { /* $- saved */
12341 memcpy(optlist, lvp->text, sizeof(optlist));
12344 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12345 unsetvar(vp->text);
12348 (*vp->func)(strchrnul(lvp->text, '=') + 1);
12349 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12351 vp->flags = lvp->flags;
12352 vp->text = lvp->text;
12360 * The unset builtin command. We unset the function before we unset the
12361 * variable to allow a function to be unset when there is a readonly variable
12362 * with the same name.
12366 unsetcmd(int argc, char **argv)
12373 while ((i = nextopt("vf")) != '\0') {
12377 for (ap = argptr; *ap ; ap++) {
12392 * Unset the specified variable.
12396 unsetvar(const char *s)
12402 vpp = findvar(hashvar(s), s);
12406 int flags = vp->flags;
12409 if (flags & VREADONLY)
12412 vp->flags &= ~VDYNAMIC;
12414 if (flags & VUNSET)
12416 if ((flags & VSTRFIXED) == 0) {
12418 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
12425 vp->flags &= ~VEXPORT;
12438 * Find the appropriate entry in the hash table from the name.
12441 static struct var **
12442 hashvar(const char *p)
12444 unsigned int hashval;
12446 hashval = ((unsigned char) *p) << 4;
12447 while (*p && *p != '=')
12448 hashval += (unsigned char) *p++;
12449 return &vartab[hashval % VTABSIZE];
12455 * Compares two strings up to the first = or '\0'. The first
12456 * string must be terminated by '='; the second may be terminated by
12457 * either '=' or '\0'.
12461 varcmp(const char *p, const char *q)
12465 while ((c = *p) == (d = *q)) {
12466 if (!c || c == '=')
12480 vpcmp(const void *a, const void *b)
12482 return varcmp(*(const char **)a, *(const char **)b);
12485 static struct var **
12486 findvar(struct var **vpp, const char *name)
12488 for (; *vpp; vpp = &(*vpp)->next) {
12489 if (varequal((*vpp)->text, name)) {
12495 /* $NetBSD: setmode.c,v 1.29 2003/01/15 23:58:03 kleink Exp $ */
12497 #include <sys/times.h>
12499 static const unsigned char timescmd_str[] = {
12500 ' ', offsetof(struct tms, tms_utime),
12501 '\n', offsetof(struct tms, tms_stime),
12502 ' ', offsetof(struct tms, tms_cutime),
12503 '\n', offsetof(struct tms, tms_cstime),
12507 static int timescmd(int ac, char **av)
12509 long int clk_tck, s, t;
12510 const unsigned char *p;
12513 clk_tck = sysconf(_SC_CLK_TCK);
12518 t = *(clock_t *)(((char *) &buf) + p[1]);
12520 out1fmt("%ldm%ld.%.3lds%c",
12522 ((t - s * clk_tck) * 1000) / clk_tck,
12524 } while (*(p += 2));
12529 #ifdef CONFIG_ASH_MATH_SUPPORT
12531 dash_arith(const char *s)
12537 result = arith(s, &errcode);
12540 error("exponent less than 0");
12541 else if (errcode == -2)
12542 error("divide by zero");
12543 else if (errcode == -5)
12544 error("expression recursion loop detected");
12555 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12556 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12558 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12562 letcmd(int argc, char **argv)
12569 error("expression expected");
12570 for (ap = argv + 1; *ap; ap++) {
12571 i = dash_arith(*ap);
12576 #endif /* CONFIG_ASH_MATH_SUPPORT */
12578 /* $NetBSD: miscbltin.c,v 1.31 2002/11/24 22:35:41 christos Exp $ */
12581 * Miscellaneous builtins.
12587 #if __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
12588 typedef enum __rlimit_resource rlim_t;
12594 * The read builtin. The -e option causes backslashes to escape the
12595 * following character.
12597 * This uses unbuffered input, which may be avoidable in some cases.
12601 readcmd(int argc, char **argv)
12613 #if defined(CONFIG_ASH_READ_NCHARS)
12617 struct termios tty, old_tty;
12619 #if defined(CONFIG_ASH_READ_TIMEOUT)
12623 ts.tv_sec = ts.tv_usec = 0;
12628 #if defined(CONFIG_ASH_READ_NCHARS) && defined(CONFIG_ASH_READ_TIMEOUT)
12629 while ((i = nextopt("p:rt:n:s")) != '\0')
12630 #elif defined(CONFIG_ASH_READ_NCHARS)
12631 while ((i = nextopt("p:rn:s")) != '\0')
12632 #elif defined(CONFIG_ASH_READ_TIMEOUT)
12633 while ((i = nextopt("p:rt:")) != '\0')
12635 while ((i = nextopt("p:r")) != '\0')
12640 prompt = optionarg;
12642 #if defined(CONFIG_ASH_READ_NCHARS)
12644 nchars = strtol(optionarg, &p, 10);
12646 error("invalid count");
12647 nch_flag = (nchars > 0);
12653 #if defined(CONFIG_ASH_READ_TIMEOUT)
12655 ts.tv_sec = strtol(optionarg, &p, 10);
12661 ts.tv_usec = strtol(p, &p2, 10);
12663 error("invalid timeout");
12665 /* normalize to usec */
12667 error("invalid timeout");
12668 while (scale++ < 6)
12672 error("invalid timeout");
12674 if ( ! ts.tv_sec && ! ts.tv_usec)
12675 error("invalid timeout");
12685 if (prompt && isatty(0)) {
12688 if (*(ap = argptr) == NULL)
12689 error("arg count");
12690 if ((ifs = bltinlookup("IFS")) == NULL)
12692 #if defined(CONFIG_ASH_READ_NCHARS)
12693 if (nch_flag || silent) {
12694 tcgetattr(0, &tty);
12697 tty.c_lflag &= ~ICANON;
12698 tty.c_cc[VMIN] = nchars;
12701 tty.c_lflag &= ~(ECHO|ECHOK|ECHONL);
12704 tcsetattr(0, TCSANOW, &tty);
12707 #if defined(CONFIG_ASH_READ_TIMEOUT)
12708 if (ts.tv_sec || ts.tv_usec) {
12712 i = select (FD_SETSIZE, &set, NULL, NULL, &ts);
12714 #if defined(CONFIG_ASH_READ_NCHARS)
12716 tcsetattr(0, TCSANOW, &old_tty);
12726 #if defined(CONFIG_ASH_READ_NCHARS)
12727 while (!nch_flag || nchars--)
12732 if (read(0, &c, 1) != 1) {
12744 if (!rflag && c == '\\') {
12750 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12754 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12756 setvar(*ap, stackblock(), 0);
12765 #if defined(CONFIG_ASH_READ_NCHARS)
12766 if (nch_flag || silent)
12767 tcsetattr(0, TCSANOW, &old_tty);
12771 /* Remove trailing blanks */
12772 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12774 setvar(*ap, stackblock(), 0);
12775 while (*++ap != NULL)
12776 setvar(*ap, nullstr, 0);
12781 static int umaskcmd(int argc, char **argv)
12783 static const char permuser[3] = "ugo";
12784 static const char permmode[3] = "rwx";
12785 static const short int permmask[] = {
12786 S_IRUSR, S_IWUSR, S_IXUSR,
12787 S_IRGRP, S_IWGRP, S_IXGRP,
12788 S_IROTH, S_IWOTH, S_IXOTH
12794 int symbolic_mode = 0;
12796 while (nextopt("S") != '\0') {
12805 if ((ap = *argptr) == NULL) {
12806 if (symbolic_mode) {
12810 for (i = 0; i < 3; i++) {
12813 *p++ = permuser[i];
12815 for (j = 0; j < 3; j++) {
12816 if ((mask & permmask[3 * i + j]) == 0) {
12817 *p++ = permmode[j];
12825 out1fmt("%.4o\n", mask);
12828 if (is_digit((unsigned char) *ap)) {
12831 if (*ap >= '8' || *ap < '0')
12832 error(illnum, argv[1]);
12833 mask = (mask << 3) + (*ap - '0');
12834 } while (*++ap != '\0');
12837 mask = ~mask & 0777;
12838 if (!bb_parse_mode(ap, &mask)) {
12839 error("Illegal mode: %s", ap);
12841 umask(~mask & 0777);
12850 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12851 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12852 * ash by J.T. Conklin.
12860 int factor; /* multiply by to get rlim_{cur,max} values */
12864 static const struct limits limits[] = {
12866 { "time(seconds)", RLIMIT_CPU, 1, 't' },
12868 #ifdef RLIMIT_FSIZE
12869 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
12872 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
12874 #ifdef RLIMIT_STACK
12875 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
12878 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
12881 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
12883 #ifdef RLIMIT_MEMLOCK
12884 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
12886 #ifdef RLIMIT_NPROC
12887 { "process", RLIMIT_NPROC, 1, 'p' },
12889 #ifdef RLIMIT_NOFILE
12890 { "nofiles", RLIMIT_NOFILE, 1, 'n' },
12893 { "vmemory(kbytes)", RLIMIT_AS, 1024, 'v' },
12895 #ifdef RLIMIT_LOCKS
12896 { "locks", RLIMIT_LOCKS, 1, 'w' },
12898 { (char *) 0, 0, 0, '\0' }
12901 enum limtype { SOFT = 0x1, HARD = 0x2 };
12903 static void printlim(enum limtype how, const struct rlimit *limit,
12904 const struct limits *l)
12908 val = limit->rlim_max;
12910 val = limit->rlim_cur;
12912 if (val == RLIM_INFINITY)
12913 out1fmt("unlimited\n");
12916 out1fmt("%lld\n", (long long) val);
12921 ulimitcmd(int argc, char **argv)
12925 enum limtype how = SOFT | HARD;
12926 const struct limits *l;
12929 struct rlimit limit;
12932 while ((optc = nextopt("HSa"
12936 #ifdef RLIMIT_FSIZE
12942 #ifdef RLIMIT_STACK
12951 #ifdef RLIMIT_MEMLOCK
12954 #ifdef RLIMIT_NPROC
12957 #ifdef RLIMIT_NOFILE
12963 #ifdef RLIMIT_LOCKS
12981 for (l = limits; l->option != what; l++)
12984 set = *argptr ? 1 : 0;
12988 if (all || argptr[1])
12989 error("too many arguments");
12990 if (strncmp(p, "unlimited\n", 9) == 0)
12991 val = RLIM_INFINITY;
12995 while ((c = *p++) >= '0' && c <= '9')
12997 val = (val * 10) + (long)(c - '0');
12998 if (val < (rlim_t) 0)
13002 error("bad number");
13007 for (l = limits; l->name; l++) {
13008 getrlimit(l->cmd, &limit);
13009 out1fmt("%-20s ", l->name);
13010 printlim(how, &limit, l);
13015 getrlimit(l->cmd, &limit);
13018 limit.rlim_max = val;
13020 limit.rlim_cur = val;
13021 if (setrlimit(l->cmd, &limit) < 0)
13022 error("error setting limit (%m)");
13024 printlim(how, &limit, l);
13030 #ifdef CONFIG_ASH_MATH_SUPPORT
13032 /* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
13034 Permission is hereby granted, free of charge, to any person obtaining
13035 a copy of this software and associated documentation files (the
13036 "Software"), to deal in the Software without restriction, including
13037 without limitation the rights to use, copy, modify, merge, publish,
13038 distribute, sublicense, and/or sell copies of the Software, and to
13039 permit persons to whom the Software is furnished to do so, subject to
13040 the following conditions:
13042 The above copyright notice and this permission notice shall be
13043 included in all copies or substantial portions of the Software.
13045 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13046 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
13047 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
13048 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
13049 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
13050 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
13051 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13054 /* This is my infix parser/evaluator. It is optimized for size, intended
13055 * as a replacement for yacc-based parsers. However, it may well be faster
13056 * than a comparable parser written in yacc. The supported operators are
13057 * listed in #defines below. Parens, order of operations, and error handling
13058 * are supported. This code is thread safe. The exact expression format should
13059 * be that which POSIX specifies for shells. */
13061 /* The code uses a simple two-stack algorithm. See
13062 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
13063 * for a detailed explanation of the infix-to-postfix algorithm on which
13064 * this is based (this code differs in that it applies operators immediately
13065 * to the stack instead of adding them to a queue to end up with an
13068 /* To use the routine, call it with an expression string and error return
13072 * Aug 24, 2001 Manuel Novoa III
13074 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
13076 * 1) In arith_apply():
13077 * a) Cached values of *numptr and &(numptr[-1]).
13078 * b) Removed redundant test for zero denominator.
13081 * a) Eliminated redundant code for processing operator tokens by moving
13082 * to a table-based implementation. Also folded handling of parens
13084 * b) Combined all 3 loops which called arith_apply to reduce generated
13085 * code size at the cost of speed.
13087 * 3) The following expressions were treated as valid by the original code:
13088 * 1() , 0! , 1 ( *3 ) .
13089 * These bugs have been fixed by internally enclosing the expression in
13090 * parens and then checking that all binary ops and right parens are
13091 * preceded by a valid expression (NUM_TOKEN).
13093 * Note: It may be desirable to replace Aaron's test for whitespace with
13094 * ctype's isspace() if it is used by another busybox applet or if additional
13095 * whitespace chars should be considered. Look below the "#include"s for a
13096 * precompiler test.
13100 * Aug 26, 2001 Manuel Novoa III
13102 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
13104 * Merge in Aaron's comments previously posted to the busybox list,
13105 * modified slightly to take account of my changes to the code.
13110 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
13112 * - allow access to variable,
13113 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
13114 * - realize assign syntax (VAR=expr, +=, *= etc)
13115 * - realize exponentiation (** operator)
13116 * - realize comma separated - expr, expr
13117 * - realise ++expr --expr expr++ expr--
13118 * - realise expr ? expr : expr (but, second expr calculate always)
13119 * - allow hexadecimal and octal numbers
13120 * - was restored loses XOR operator
13121 * - remove one goto label, added three ;-)
13122 * - protect $((num num)) as true zero expr (Manuel`s error)
13123 * - always use special isspace(), see comment from bash ;-)
13127 #define arith_isspace(arithval) \
13128 (arithval == ' ' || arithval == '\n' || arithval == '\t')
13131 typedef unsigned char operator;
13133 /* An operator's token id is a bit of a bitfield. The lower 5 bits are the
13134 * precedence, and 3 high bits are an ID unique across operators of that
13135 * precedence. The ID portion is so that multiple operators can have the
13136 * same precedence, ensuring that the leftmost one is evaluated first.
13137 * Consider * and /. */
13139 #define tok_decl(prec,id) (((id)<<5)|(prec))
13140 #define PREC(op) ((op) & 0x1F)
13142 #define TOK_LPAREN tok_decl(0,0)
13144 #define TOK_COMMA tok_decl(1,0)
13146 #define TOK_ASSIGN tok_decl(2,0)
13147 #define TOK_AND_ASSIGN tok_decl(2,1)
13148 #define TOK_OR_ASSIGN tok_decl(2,2)
13149 #define TOK_XOR_ASSIGN tok_decl(2,3)
13150 #define TOK_PLUS_ASSIGN tok_decl(2,4)
13151 #define TOK_MINUS_ASSIGN tok_decl(2,5)
13152 #define TOK_LSHIFT_ASSIGN tok_decl(2,6)
13153 #define TOK_RSHIFT_ASSIGN tok_decl(2,7)
13155 #define TOK_MUL_ASSIGN tok_decl(3,0)
13156 #define TOK_DIV_ASSIGN tok_decl(3,1)
13157 #define TOK_REM_ASSIGN tok_decl(3,2)
13159 /* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
13160 #define convert_prec_is_assing(prec) do { if(prec == 3) prec = 2; } while(0)
13162 /* conditional is right associativity too */
13163 #define TOK_CONDITIONAL tok_decl(4,0)
13164 #define TOK_CONDITIONAL_SEP tok_decl(4,1)
13166 #define TOK_OR tok_decl(5,0)
13168 #define TOK_AND tok_decl(6,0)
13170 #define TOK_BOR tok_decl(7,0)
13172 #define TOK_BXOR tok_decl(8,0)
13174 #define TOK_BAND tok_decl(9,0)
13176 #define TOK_EQ tok_decl(10,0)
13177 #define TOK_NE tok_decl(10,1)
13179 #define TOK_LT tok_decl(11,0)
13180 #define TOK_GT tok_decl(11,1)
13181 #define TOK_GE tok_decl(11,2)
13182 #define TOK_LE tok_decl(11,3)
13184 #define TOK_LSHIFT tok_decl(12,0)
13185 #define TOK_RSHIFT tok_decl(12,1)
13187 #define TOK_ADD tok_decl(13,0)
13188 #define TOK_SUB tok_decl(13,1)
13190 #define TOK_MUL tok_decl(14,0)
13191 #define TOK_DIV tok_decl(14,1)
13192 #define TOK_REM tok_decl(14,2)
13194 /* exponent is right associativity */
13195 #define TOK_EXPONENT tok_decl(15,1)
13197 /* For now unary operators. */
13198 #define UNARYPREC 16
13199 #define TOK_BNOT tok_decl(UNARYPREC,0)
13200 #define TOK_NOT tok_decl(UNARYPREC,1)
13202 #define TOK_UMINUS tok_decl(UNARYPREC+1,0)
13203 #define TOK_UPLUS tok_decl(UNARYPREC+1,1)
13205 #define PREC_PRE (UNARYPREC+2)
13207 #define TOK_PRE_INC tok_decl(PREC_PRE, 0)
13208 #define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
13210 #define PREC_POST (UNARYPREC+3)
13212 #define TOK_POST_INC tok_decl(PREC_POST, 0)
13213 #define TOK_POST_DEC tok_decl(PREC_POST, 1)
13215 #define SPEC_PREC (UNARYPREC+4)
13217 #define TOK_NUM tok_decl(SPEC_PREC, 0)
13218 #define TOK_RPAREN tok_decl(SPEC_PREC, 1)
13220 #define NUMPTR (*numstackptr)
13222 static inline int tok_have_assign(operator op)
13224 operator prec = PREC(op);
13226 convert_prec_is_assing(prec);
13227 return (prec == PREC(TOK_ASSIGN) ||
13228 prec == PREC_PRE || prec == PREC_POST);
13231 static inline int is_right_associativity(operator prec)
13233 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) ||
13234 prec == PREC(TOK_CONDITIONAL));
13238 typedef struct ARITCH_VAR_NUM {
13240 arith_t contidional_second_val;
13241 char contidional_second_val_initialized;
13242 char *var; /* if NULL then is regular number,
13243 else is variable name */
13247 typedef struct CHK_VAR_RECURSIVE_LOOPED {
13249 struct CHK_VAR_RECURSIVE_LOOPED *next;
13250 } chk_var_recursive_looped_t;
13252 static chk_var_recursive_looped_t *prev_chk_var_recursive;
13255 static int arith_lookup_val(v_n_t *t)
13258 const char * p = lookupvar(t->var);
13263 /* recursive try as expression */
13264 chk_var_recursive_looped_t *cur;
13265 chk_var_recursive_looped_t cur_save;
13267 for(cur = prev_chk_var_recursive; cur; cur = cur->next) {
13268 if(strcmp(cur->var, t->var) == 0) {
13269 /* expression recursion loop detected */
13273 /* save current lookuped var name */
13274 cur = prev_chk_var_recursive;
13275 cur_save.var = t->var;
13276 cur_save.next = cur;
13277 prev_chk_var_recursive = &cur_save;
13279 t->val = arith (p, &errcode);
13280 /* restore previous ptr after recursiving */
13281 prev_chk_var_recursive = cur;
13284 /* allow undefined var as 0 */
13291 /* "applying" a token means performing it on the top elements on the integer
13292 * stack. For a unary operator it will only change the top element, but a
13293 * binary operator will pop two arguments and push a result */
13295 arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
13298 arith_t numptr_val, rez;
13299 int ret_arith_lookup_val;
13301 if (NUMPTR == numstack) goto err; /* There is no operator that can work
13302 without arguments */
13303 numptr_m1 = NUMPTR - 1;
13305 /* check operand is var with noninteger value */
13306 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13307 if(ret_arith_lookup_val)
13308 return ret_arith_lookup_val;
13310 rez = numptr_m1->val;
13311 if (op == TOK_UMINUS)
13313 else if (op == TOK_NOT)
13315 else if (op == TOK_BNOT)
13317 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
13319 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
13321 else if (op != TOK_UPLUS) {
13322 /* Binary operators */
13324 /* check and binary operators need two arguments */
13325 if (numptr_m1 == numstack) goto err;
13327 /* ... and they pop one */
13330 if (op == TOK_CONDITIONAL) {
13331 if(! numptr_m1->contidional_second_val_initialized) {
13332 /* protect $((expr1 ? expr2)) without ": expr" */
13335 rez = numptr_m1->contidional_second_val;
13336 } else if(numptr_m1->contidional_second_val_initialized) {
13337 /* protect $((expr1 : expr2)) without "expr ? " */
13340 numptr_m1 = NUMPTR - 1;
13341 if(op != TOK_ASSIGN) {
13342 /* check operand is var with noninteger value for not '=' */
13343 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13344 if(ret_arith_lookup_val)
13345 return ret_arith_lookup_val;
13347 if (op == TOK_CONDITIONAL) {
13348 numptr_m1->contidional_second_val = rez;
13350 rez = numptr_m1->val;
13351 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
13353 else if (op == TOK_OR)
13354 rez = numptr_val || rez;
13355 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
13357 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
13359 else if (op == TOK_AND)
13360 rez = rez && numptr_val;
13361 else if (op == TOK_EQ)
13362 rez = (rez == numptr_val);
13363 else if (op == TOK_NE)
13364 rez = (rez != numptr_val);
13365 else if (op == TOK_GE)
13366 rez = (rez >= numptr_val);
13367 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
13368 rez >>= numptr_val;
13369 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
13370 rez <<= numptr_val;
13371 else if (op == TOK_GT)
13372 rez = (rez > numptr_val);
13373 else if (op == TOK_LT)
13374 rez = (rez < numptr_val);
13375 else if (op == TOK_LE)
13376 rez = (rez <= numptr_val);
13377 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
13379 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
13381 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
13383 else if (op == TOK_ASSIGN || op == TOK_COMMA)
13385 else if (op == TOK_CONDITIONAL_SEP) {
13386 if (numptr_m1 == numstack) {
13387 /* protect $((expr : expr)) without "expr ? " */
13390 numptr_m1->contidional_second_val_initialized = op;
13391 numptr_m1->contidional_second_val = numptr_val;
13393 else if (op == TOK_CONDITIONAL) {
13395 numptr_val : numptr_m1->contidional_second_val;
13397 else if(op == TOK_EXPONENT) {
13399 return -3; /* exponent less than 0 */
13404 while(numptr_val--)
13409 else if(numptr_val==0) /* zero divisor check */
13411 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
13413 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
13416 if(tok_have_assign(op)) {
13419 if(numptr_m1->var == NULL) {
13423 /* save to shell variable */
13424 #ifdef CONFIG_ASH_MATH_SUPPORT_64
13425 snprintf(buf, sizeof(buf), "%lld", rez);
13427 snprintf(buf, sizeof(buf), "%ld", rez);
13429 setvar(numptr_m1->var, buf, 0);
13430 /* after saving, make previous value for v++ or v-- */
13431 if(op == TOK_POST_INC)
13433 else if(op == TOK_POST_DEC)
13436 numptr_m1->val = rez;
13437 /* protect geting var value, is number now */
13438 numptr_m1->var = NULL;
13443 /* longest must first */
13444 static const char op_tokens[] = {
13445 '<','<','=',0, TOK_LSHIFT_ASSIGN,
13446 '>','>','=',0, TOK_RSHIFT_ASSIGN,
13447 '<','<', 0, TOK_LSHIFT,
13448 '>','>', 0, TOK_RSHIFT,
13449 '|','|', 0, TOK_OR,
13450 '&','&', 0, TOK_AND,
13451 '!','=', 0, TOK_NE,
13452 '<','=', 0, TOK_LE,
13453 '>','=', 0, TOK_GE,
13454 '=','=', 0, TOK_EQ,
13455 '|','=', 0, TOK_OR_ASSIGN,
13456 '&','=', 0, TOK_AND_ASSIGN,
13457 '*','=', 0, TOK_MUL_ASSIGN,
13458 '/','=', 0, TOK_DIV_ASSIGN,
13459 '%','=', 0, TOK_REM_ASSIGN,
13460 '+','=', 0, TOK_PLUS_ASSIGN,
13461 '-','=', 0, TOK_MINUS_ASSIGN,
13462 '-','-', 0, TOK_POST_DEC,
13463 '^','=', 0, TOK_XOR_ASSIGN,
13464 '+','+', 0, TOK_POST_INC,
13465 '*','*', 0, TOK_EXPONENT,
13469 '=', 0, TOK_ASSIGN,
13481 '?', 0, TOK_CONDITIONAL,
13482 ':', 0, TOK_CONDITIONAL_SEP,
13483 ')', 0, TOK_RPAREN,
13484 '(', 0, TOK_LPAREN,
13488 #define endexpression &op_tokens[sizeof(op_tokens)-7]
13491 static arith_t arith (const char *expr, int *perrcode)
13493 register char arithval; /* Current character under analysis */
13494 operator lasttok, op;
13497 const char *p = endexpression;
13500 size_t datasizes = strlen(expr) + 2;
13502 /* Stack of integers */
13503 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
13504 * in any given correct or incorrect expression is left as an exercise to
13506 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
13507 *numstackptr = numstack;
13508 /* Stack of operator tokens */
13509 operator *stack = alloca((datasizes) * sizeof(operator)),
13512 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
13513 *perrcode = errcode = 0;
13516 if ((arithval = *expr) == 0) {
13517 if (p == endexpression) {
13518 /* Null expression. */
13522 /* This is only reached after all tokens have been extracted from the
13523 * input stream. If there are still tokens on the operator stack, they
13524 * are to be applied in order. At the end, there should be a final
13525 * result on the integer stack */
13527 if (expr != endexpression + 1) {
13528 /* If we haven't done so already, */
13529 /* append a closing right paren */
13530 expr = endexpression;
13531 /* and let the loop process it. */
13534 /* At this point, we're done with the expression. */
13535 if (numstackptr != numstack+1) {
13536 /* ... but if there isn't, it's bad */
13538 return (*perrcode = -1);
13540 if(numstack->var) {
13541 /* expression is $((var)) only, lookup now */
13542 errcode = arith_lookup_val(numstack);
13545 *perrcode = errcode;
13546 return numstack->val;
13548 /* Continue processing the expression. */
13549 if (arith_isspace(arithval)) {
13550 /* Skip whitespace */
13553 if((p = endofname(expr)) != expr) {
13554 size_t var_name_size = (p-expr) + 1; /* trailing zero */
13556 numstackptr->var = alloca(var_name_size);
13557 safe_strncpy(numstackptr->var, expr, var_name_size);
13560 numstackptr->contidional_second_val_initialized = 0;
13564 } else if (is_digit(arithval)) {
13565 numstackptr->var = NULL;
13566 #ifdef CONFIG_ASH_MATH_SUPPORT_64
13567 numstackptr->val = strtoll(expr, (char **) &expr, 0);
13569 numstackptr->val = strtol(expr, (char **) &expr, 0);
13573 for(p = op_tokens; ; p++) {
13577 /* strange operator not found */
13580 for(o = expr; *p && *o == *p; p++)
13587 /* skip tail uncompared token */
13590 /* skip zero delim */
13595 /* post grammar: a++ reduce to num */
13596 if(lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13599 /* Plus and minus are binary (not unary) _only_ if the last
13600 * token was as number, or a right paren (which pretends to be
13601 * a number, since it evaluates to one). Think about it.
13602 * It makes sense. */
13603 if (lasttok != TOK_NUM) {
13619 /* We don't want a unary operator to cause recursive descent on the
13620 * stack, because there can be many in a row and it could cause an
13621 * operator to be evaluated before its argument is pushed onto the
13622 * integer stack. */
13623 /* But for binary operators, "apply" everything on the operator
13624 * stack until we find an operator with a lesser priority than the
13625 * one we have just extracted. */
13626 /* Left paren is given the lowest priority so it will never be
13627 * "applied" in this way.
13628 * if associativity is right and priority eq, applied also skip
13631 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13632 /* not left paren or unary */
13633 if (lasttok != TOK_NUM) {
13634 /* binary op must be preceded by a num */
13637 while (stackptr != stack) {
13638 if (op == TOK_RPAREN) {
13639 /* The algorithm employed here is simple: while we don't
13640 * hit an open paren nor the bottom of the stack, pop
13641 * tokens and apply them */
13642 if (stackptr[-1] == TOK_LPAREN) {
13644 /* Any operator directly after a */
13646 /* close paren should consider itself binary */
13650 operator prev_prec = PREC(stackptr[-1]);
13652 convert_prec_is_assing(prec);
13653 convert_prec_is_assing(prev_prec);
13654 if (prev_prec < prec)
13656 /* check right assoc */
13657 if(prev_prec == prec && is_right_associativity(prec))
13660 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13661 if(errcode) goto ret;
13663 if (op == TOK_RPAREN) {
13668 /* Push this operator to the stack and remember it. */
13669 *stackptr++ = lasttok = op;
13676 #endif /* CONFIG_ASH_MATH_SUPPORT */
13680 const char *bb_applet_name = "debug stuff usage";
13681 int main(int argc, char **argv)
13683 return ash_main(argc, argv);
13688 * Copyright (c) 1989, 1991, 1993, 1994
13689 * The Regents of the University of California. All rights reserved.
13691 * This code is derived from software contributed to Berkeley by
13692 * Kenneth Almquist.
13694 * Redistribution and use in source and binary forms, with or without
13695 * modification, are permitted provided that the following conditions
13697 * 1. Redistributions of source code must retain the above copyright
13698 * notice, this list of conditions and the following disclaimer.
13699 * 2. Redistributions in binary form must reproduce the above copyright
13700 * notice, this list of conditions and the following disclaimer in the
13701 * documentation and/or other materials provided with the distribution.
13703 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
13704 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
13706 * 4. Neither the name of the University nor the names of its contributors
13707 * may be used to endorse or promote products derived from this software
13708 * without specific prior written permission.
13710 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13711 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13712 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13713 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13714 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13715 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13716 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13717 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13718 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13719 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF