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
30 * Modified by Vladimir Oleynik <dzo@simtreas.ru> to be used in busybox
33 * Original BSD copyright notice is retained at the end of this file.
37 * The follow should be set to reflect the type of system you have:
38 * JOBS -> 1 if you have Berkeley job control, 0 otherwise.
39 * define SYSV if you are running under System V.
40 * define DEBUG=1 to compile in debugging ('set -o debug' to turn on)
41 * define DEBUG=2 to compile in and turn on debugging.
43 * When debugging is on, debugging info will be written to ./trace and
44 * a quit signal will generate a core dump.
57 #include <sys/types.h>
58 #include <sys/cdefs.h>
59 #include <sys/ioctl.h>
60 #include <sys/param.h>
61 #include <sys/resource.h>
93 #ifdef CONFIG_ASH_JOB_CONTROL
107 static int *dash_errno;
109 #define errno (*dash_errno)
112 #if defined(__uClinux__)
113 #error "Do not even bother, ash will not run on uClinux"
117 #define _DIAGASSERT(assert_expr) assert(assert_expr)
119 #define _DIAGASSERT(assert_expr)
123 #ifdef CONFIG_ASH_ALIAS
124 /* $NetBSD: alias.h,v 1.5 2002/11/24 22:35:38 christos Exp $ */
136 static struct alias *lookupalias(const char *, int);
137 static int aliascmd(int, char **);
138 static int unaliascmd(int, char **);
139 static void rmaliases(void);
140 static int unalias(const char *);
141 static void printalias(const struct alias *);
144 /* $NetBSD: cd.h,v 1.3 2002/11/24 22:35:39 christos Exp $ */
147 static void setpwd(const char *, int);
149 /* $NetBSD: error.h,v 1.15 2002/11/24 22:35:39 christos Exp $ */
153 * Types of operations (passed to the errmsg routine).
157 static const char not_found_msg[] = "%s: not found";
160 #define E_OPEN "No such file" /* opening a file */
161 #define E_CREAT "Directory nonexistent" /* creating a file */
162 #define E_EXEC not_found_msg+4 /* executing a program */
165 * We enclose jmp_buf in a structure so that we can declare pointers to
166 * jump locations. The global variable handler contains the location to
167 * jump to when an exception occurs, and the global variable exception
168 * contains a code identifying the exeception. To implement nested
169 * exception handlers, the user should save the value of handler on entry
170 * to an inner scope, set handler to point to a jmploc structure for the
171 * inner scope, and restore handler on exit from the scope.
178 static struct jmploc *handler;
179 static int exception;
180 static volatile int suppressint;
181 static volatile sig_atomic_t intpending;
183 static int exerrno; /* Last exec error, error for EXEXEC */
186 #define EXINT 0 /* SIGINT received */
187 #define EXERROR 1 /* a generic error */
188 #define EXSHELLPROC 2 /* execute a shell procedure */
189 #define EXEXEC 3 /* command execution failed */
190 #define EXEXIT 4 /* exit the shell */
191 #define EXSIG 5 /* trapped signal in wait(1) */
194 /* do we generate EXSIG events */
196 /* last pending signal */
197 static volatile sig_atomic_t pendingsigs;
200 * These macros allow the user to suspend the handling of interrupt signals
201 * over a period of time. This is similar to SIGHOLD to or sigblock, but
202 * much more efficient and portable. (But hacking the kernel is so much
203 * more fun than worrying about efficiency and portability. :-))
206 #define barrier() ({ __asm__ __volatile__ ("": : :"memory"); })
213 #define SAVEINT(v) ((v) = suppressint)
214 #define RESTOREINT(v) \
217 if ((suppressint = (v)) == 0 && intpending) onint(); \
228 /* EXSIG is turned off by evalbltin(). */
231 static void exraise(int) __attribute__((__noreturn__));
232 static void onint(void) __attribute__((__noreturn__));
234 static void error(const char *, ...) __attribute__((__noreturn__));
235 static void exerror(int, const char *, ...) __attribute__((__noreturn__));
237 static void sh_warnx(const char *, ...);
239 #ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
242 if (--suppressint == 0 && intpending) {
246 #define INTON inton()
247 static void forceinton(void)
253 #define FORCEINTON forceinton()
258 if (--suppressint == 0 && intpending) onint(); \
265 if (intpending) onint(); \
268 #endif /* CONFIG_ASH_OPTIMIZE_FOR_SIZE */
271 * BSD setjmp saves the signal mask, which violates ANSI C and takes time,
272 * so we use _setjmp instead.
275 #if defined(BSD) && !defined(__SVR4) && !defined(__GLIBC__)
276 #define setjmp(jmploc) _setjmp(jmploc)
277 #define longjmp(jmploc, val) _longjmp(jmploc, val)
280 /* $NetBSD: expand.h,v 1.13 2002/11/24 22:35:40 christos Exp $ */
283 struct strlist *next;
289 struct strlist *list;
290 struct strlist **lastp;
296 #define EXP_FULL 0x1 /* perform word splitting & file globbing */
297 #define EXP_TILDE 0x2 /* do normal tilde expansion */
298 #define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
299 #define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
300 #define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
301 #define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
302 #define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
303 #define EXP_WORD 0x80 /* expand word in parameter expansion */
304 #define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */
308 static void expandarg(union node *, struct arglist *, int);
309 #define rmescapes(p) _rmescapes((p), 0)
310 static char *_rmescapes(char *, int);
311 static int casematch(union node *, char *);
313 #ifdef CONFIG_ASH_MATH_SUPPORT
314 static void expari(int);
317 /* $NetBSD: eval.h,v 1.13 2002/11/24 22:35:39 christos Exp $ */
319 static char *commandname; /* currently executing command */
320 static struct strlist *cmdenviron; /* environment for builtin command */
321 static int exitstatus; /* exit status of last command */
322 static int back_exitstatus; /* exit status of backquoted command */
325 struct backcmd { /* result of evalbackcmd */
326 int fd; /* file descriptor to read from */
327 char *buf; /* buffer */
328 int nleft; /* number of chars in buffer */
329 struct job *jp; /* job structure for command */
333 * This file was generated by the mknodes program.
369 union node *redirect;
376 struct nodelist *cmdlist;
383 union node *redirect;
398 union node *elsepart;
429 struct nodelist *backquote;
469 struct nredir nredir;
470 struct nbinary nbinary;
474 struct nclist nclist;
484 struct nodelist *next;
495 static void freefunc(struct funcnode *);
496 /* $NetBSD: parser.h,v 1.15 2002/11/24 22:35:42 christos Exp $ */
498 /* control characters in argument strings */
499 #define CTL_FIRST '\201' /* first 'special' character */
500 #define CTLESC '\201' /* escape next character */
501 #define CTLVAR '\202' /* variable defn */
502 #define CTLENDVAR '\203'
503 #define CTLBACKQ '\204'
504 #define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
505 /* CTLBACKQ | CTLQUOTE == '\205' */
506 #define CTLARI '\206' /* arithmetic expression */
507 #define CTLENDARI '\207'
508 #define CTLQUOTEMARK '\210'
509 #define CTL_LAST '\210' /* last 'special' character */
511 /* variable substitution byte (follows CTLVAR) */
512 #define VSTYPE 0x0f /* type of variable substitution */
513 #define VSNUL 0x10 /* colon--treat the empty string as unset */
514 #define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
516 /* values of VSTYPE field */
517 #define VSNORMAL 0x1 /* normal variable: $var or ${var} */
518 #define VSMINUS 0x2 /* ${var-text} */
519 #define VSPLUS 0x3 /* ${var+text} */
520 #define VSQUESTION 0x4 /* ${var?message} */
521 #define VSASSIGN 0x5 /* ${var=text} */
522 #define VSTRIMRIGHT 0x6 /* ${var%pattern} */
523 #define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
524 #define VSTRIMLEFT 0x8 /* ${var#pattern} */
525 #define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
526 #define VSLENGTH 0xa /* ${#var} */
528 /* values of checkkwd variable */
533 #define IBUFSIZ (BUFSIZ + 1)
536 * NEOF is returned by parsecmd when it encounters an end of file. It
537 * must be distinct from NULL, so we use the address of a variable that
538 * happens to be handy.
540 static int plinno = 1; /* input line number */
542 /* number of characters left in input buffer */
543 static int parsenleft; /* copy of parsefile->nleft */
544 static int parselleft; /* copy of parsefile->lleft */
546 /* next character in input buffer */
547 static char *parsenextc; /* copy of parsefile->nextc */
548 static struct parsefile basepf; /* top level input file */
549 static char basebuf[IBUFSIZ]; /* buffer for top level input file */
550 static struct parsefile *parsefile = &basepf; /* current input file */
553 static int tokpushback; /* last token pushed back */
554 #define NEOF ((union node *)&tokpushback)
555 static int parsebackquote; /* nonzero if we are inside backquotes */
556 static int doprompt; /* if set, prompt the user */
557 static int needprompt; /* true if interactive and at start of line */
558 static int lasttoken; /* last token read */
559 static char *wordtext; /* text of last word returned by readtoken */
561 static struct nodelist *backquotelist;
562 static union node *redirnode;
563 static struct heredoc *heredoc;
564 static int quoteflag; /* set if (part of) last token was quoted */
565 static int startlinno; /* line # where last token started */
567 static union node *parsecmd(int);
568 static void fixredir(union node *, const char *, int);
569 static const char *const *findkwd(const char *);
570 static char *endofname(const char *);
572 /* $NetBSD: shell.h,v 1.16 2003/01/22 20:36:04 dsl Exp $ */
574 typedef void *pointer;
576 static char nullstr[1]; /* zero length string */
577 static const char spcstr[] = " ";
578 static const char snlfmt[] = "%s\n";
579 static const char dolatstr[] = { CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' };
580 static const char illnum[] = "Illegal number: %s";
581 static const char homestr[] = "HOME";
584 #define TRACE(param) trace param
585 #define TRACEV(param) tracev param
588 #define TRACEV(param)
591 #if defined(__GNUC__) && __GNUC__ < 3
592 #define va_copy __va_copy
595 #if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
596 #define __builtin_expect(x, expected_value) (x)
599 #define likely(x) __builtin_expect((x),1)
600 #define unlikely(x) __builtin_expect((x),0)
614 #define TENDBQUOTE 12
632 /* first char is indicating which tokens mark the end of a list */
633 static const char *const tokname_array[] = {
648 /* the following are keywords */
667 static const char *tokname(int tok)
673 sprintf(buf + (tok >= TSEMI), "%s%c",
674 tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));
678 /* $NetBSD: machdep.h,v 1.10 2002/10/07 14:26:08 christos Exp $ */
681 * Most machines require the value returned from malloc to be aligned
682 * in some way. The following macro will get this right on many machines.
685 #define SHELL_SIZE (sizeof(union {int i; char *cp; double d; }) - 1)
687 * It appears that grabstackstr() will barf with such alignments
688 * because stalloc() will return a string allocated in a new stackblock.
690 #define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
693 * This file was generated by the mksyntax program.
698 #define CWORD 0 /* character is nothing special */
699 #define CNL 1 /* newline character */
700 #define CBACK 2 /* a backslash character */
701 #define CSQUOTE 3 /* single quote */
702 #define CDQUOTE 4 /* double quote */
703 #define CENDQUOTE 5 /* a terminating quote */
704 #define CBQUOTE 6 /* backwards single quote */
705 #define CVAR 7 /* a dollar sign */
706 #define CENDVAR 8 /* a '}' character */
707 #define CLP 9 /* a left paren in arithmetic */
708 #define CRP 10 /* a right paren in arithmetic */
709 #define CENDFILE 11 /* end of file */
710 #define CCTL 12 /* like CWORD, except it must be escaped */
711 #define CSPCL 13 /* these terminate a word */
712 #define CIGN 14 /* character should be ignored */
714 #ifdef CONFIG_ASH_ALIAS
718 #define PEOA_OR_PEOF PEOA
722 #define PEOA_OR_PEOF PEOF
725 #define is_digit(c) ((unsigned)((c) - '0') <= 9)
726 #define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
727 #define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
730 * is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
731 * (assuming ascii char codes, as the original implementation did)
733 #define is_special(c) \
734 ( (((unsigned int)c) - 33 < 32) \
735 && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
737 #define digit_val(c) ((c) - '0')
740 * This file was generated by the mksyntax program.
743 #ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
744 #define USE_SIT_FUNCTION
747 /* number syntax index */
748 #define BASESYNTAX 0 /* not in quotes */
749 #define DQSYNTAX 1 /* in double quotes */
750 #define SQSYNTAX 2 /* in single quotes */
751 #define ARISYNTAX 3 /* in arithmetic */
753 #ifdef CONFIG_ASH_MATH_SUPPORT
754 static const char S_I_T[][4] = {
755 #ifdef CONFIG_ASH_ALIAS
756 {CSPCL, CIGN, CIGN, CIGN}, /* 0, PEOA */
758 {CSPCL, CWORD, CWORD, CWORD}, /* 1, ' ' */
759 {CNL, CNL, CNL, CNL}, /* 2, \n */
760 {CWORD, CCTL, CCTL, CWORD}, /* 3, !*-/:=?[]~ */
761 {CDQUOTE, CENDQUOTE, CWORD, CWORD}, /* 4, '"' */
762 {CVAR, CVAR, CWORD, CVAR}, /* 5, $ */
763 {CSQUOTE, CWORD, CENDQUOTE, CWORD}, /* 6, "'" */
764 {CSPCL, CWORD, CWORD, CLP}, /* 7, ( */
765 {CSPCL, CWORD, CWORD, CRP}, /* 8, ) */
766 {CBACK, CBACK, CCTL, CBACK}, /* 9, \ */
767 {CBQUOTE, CBQUOTE, CWORD, CBQUOTE}, /* 10, ` */
768 {CENDVAR, CENDVAR, CWORD, CENDVAR}, /* 11, } */
769 #ifndef USE_SIT_FUNCTION
770 {CENDFILE, CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */
771 {CWORD, CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */
772 {CCTL, CCTL, CCTL, CCTL} /* 14, CTLESC ... */
776 static const char S_I_T[][3] = {
777 #ifdef CONFIG_ASH_ALIAS
778 {CSPCL, CIGN, CIGN}, /* 0, PEOA */
780 {CSPCL, CWORD, CWORD}, /* 1, ' ' */
781 {CNL, CNL, CNL}, /* 2, \n */
782 {CWORD, CCTL, CCTL}, /* 3, !*-/:=?[]~ */
783 {CDQUOTE, CENDQUOTE, CWORD}, /* 4, '"' */
784 {CVAR, CVAR, CWORD}, /* 5, $ */
785 {CSQUOTE, CWORD, CENDQUOTE}, /* 6, "'" */
786 {CSPCL, CWORD, CWORD}, /* 7, ( */
787 {CSPCL, CWORD, CWORD}, /* 8, ) */
788 {CBACK, CBACK, CCTL}, /* 9, \ */
789 {CBQUOTE, CBQUOTE, CWORD}, /* 10, ` */
790 {CENDVAR, CENDVAR, CWORD}, /* 11, } */
791 #ifndef USE_SIT_FUNCTION
792 {CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */
793 {CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */
794 {CCTL, CCTL, CCTL} /* 14, CTLESC ... */
797 #endif /* CONFIG_ASH_MATH_SUPPORT */
799 #ifdef USE_SIT_FUNCTION
801 #define U_C(c) ((unsigned char)(c))
803 static int SIT(int c, int syntax)
805 static const char spec_symbls[] = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
806 #ifdef CONFIG_ASH_ALIAS
807 static const char syntax_index_table[] = {
808 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
809 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
810 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
814 static const char syntax_index_table[] = {
815 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
816 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */
817 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
824 if (c == PEOF) /* 2^8+2 */
826 #ifdef CONFIG_ASH_ALIAS
827 if (c == PEOA) /* 2^8+1 */
831 if (U_C(c) >= U_C(CTLESC) && U_C(c) <= U_C(CTLQUOTEMARK))
834 s = strchr(spec_symbls, c);
835 if (s == 0 || *s == 0)
837 indx = syntax_index_table[(s - spec_symbls)];
839 return S_I_T[indx][syntax];
842 #else /* USE_SIT_FUNCTION */
844 #define SIT(c, syntax) S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax]
846 #ifdef CONFIG_ASH_ALIAS
847 #define CSPCL_CIGN_CIGN_CIGN 0
848 #define CSPCL_CWORD_CWORD_CWORD 1
849 #define CNL_CNL_CNL_CNL 2
850 #define CWORD_CCTL_CCTL_CWORD 3
851 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 4
852 #define CVAR_CVAR_CWORD_CVAR 5
853 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 6
854 #define CSPCL_CWORD_CWORD_CLP 7
855 #define CSPCL_CWORD_CWORD_CRP 8
856 #define CBACK_CBACK_CCTL_CBACK 9
857 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10
858 #define CENDVAR_CENDVAR_CWORD_CENDVAR 11
859 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
860 #define CWORD_CWORD_CWORD_CWORD 13
861 #define CCTL_CCTL_CCTL_CCTL 14
863 #define CSPCL_CWORD_CWORD_CWORD 0
864 #define CNL_CNL_CNL_CNL 1
865 #define CWORD_CCTL_CCTL_CWORD 2
866 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 3
867 #define CVAR_CVAR_CWORD_CVAR 4
868 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 5
869 #define CSPCL_CWORD_CWORD_CLP 6
870 #define CSPCL_CWORD_CWORD_CRP 7
871 #define CBACK_CBACK_CCTL_CBACK 8
872 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 9
873 #define CENDVAR_CENDVAR_CWORD_CENDVAR 10
874 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 11
875 #define CWORD_CWORD_CWORD_CWORD 12
876 #define CCTL_CCTL_CCTL_CCTL 13
879 static const char syntax_index_table[258] = {
880 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
881 /* 0 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
882 #ifdef CONFIG_ASH_ALIAS
883 /* 1 PEOA */ CSPCL_CIGN_CIGN_CIGN,
885 /* 2 -128 0x80 */ CWORD_CWORD_CWORD_CWORD,
886 /* 3 -127 CTLESC */ CCTL_CCTL_CCTL_CCTL,
887 /* 4 -126 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
888 /* 5 -125 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
889 /* 6 -124 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
890 /* 7 -123 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
891 /* 8 -122 CTLARI */ CCTL_CCTL_CCTL_CCTL,
892 /* 9 -121 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
893 /* 10 -120 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
894 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD,
895 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD,
896 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD,
897 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD,
898 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD,
899 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD,
900 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD,
901 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD,
902 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,
903 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD,
904 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD,
905 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD,
906 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD,
907 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD,
908 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD,
909 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD,
910 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD,
911 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD,
912 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,
913 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD,
914 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD,
915 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD,
916 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD,
917 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD,
918 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD,
919 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD,
920 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD,
921 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,
922 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,
923 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD,
924 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD,
925 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD,
926 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD,
927 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD,
928 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD,
929 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD,
930 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD,
931 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD,
932 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD,
933 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD,
934 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD,
935 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD,
936 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD,
937 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD,
938 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD,
939 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD,
940 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD,
941 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,
942 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,
943 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD,
944 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD,
945 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD,
946 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD,
947 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD,
948 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD,
949 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD,
950 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD,
951 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD,
952 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD,
953 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD,
954 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD,
955 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD,
956 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD,
957 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD,
958 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD,
959 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD,
960 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD,
961 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD,
962 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD,
963 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD,
964 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD,
965 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD,
966 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD,
967 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD,
968 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD,
969 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD,
970 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD,
971 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD,
972 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,
973 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD,
974 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD,
975 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD,
976 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD,
977 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD,
978 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD,
979 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD,
980 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD,
981 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD,
982 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD,
983 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD,
984 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD,
985 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD,
986 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD,
987 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD,
988 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD,
989 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD,
990 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD,
991 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD,
992 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD,
993 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD,
994 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD,
995 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD,
996 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD,
997 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD,
998 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD,
999 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD,
1000 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD,
1001 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD,
1002 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD,
1003 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD,
1004 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD,
1005 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD,
1006 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD,
1007 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD,
1008 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD,
1009 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD,
1010 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD,
1011 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD,
1012 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD,
1013 /* 130 0 */ CWORD_CWORD_CWORD_CWORD,
1014 /* 131 1 */ CWORD_CWORD_CWORD_CWORD,
1015 /* 132 2 */ CWORD_CWORD_CWORD_CWORD,
1016 /* 133 3 */ CWORD_CWORD_CWORD_CWORD,
1017 /* 134 4 */ CWORD_CWORD_CWORD_CWORD,
1018 /* 135 5 */ CWORD_CWORD_CWORD_CWORD,
1019 /* 136 6 */ CWORD_CWORD_CWORD_CWORD,
1020 /* 137 7 */ CWORD_CWORD_CWORD_CWORD,
1021 /* 138 8 */ CWORD_CWORD_CWORD_CWORD,
1022 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
1023 /* 140 10 "\n" */ CNL_CNL_CNL_CNL,
1024 /* 141 11 */ CWORD_CWORD_CWORD_CWORD,
1025 /* 142 12 */ CWORD_CWORD_CWORD_CWORD,
1026 /* 143 13 */ CWORD_CWORD_CWORD_CWORD,
1027 /* 144 14 */ CWORD_CWORD_CWORD_CWORD,
1028 /* 145 15 */ CWORD_CWORD_CWORD_CWORD,
1029 /* 146 16 */ CWORD_CWORD_CWORD_CWORD,
1030 /* 147 17 */ CWORD_CWORD_CWORD_CWORD,
1031 /* 148 18 */ CWORD_CWORD_CWORD_CWORD,
1032 /* 149 19 */ CWORD_CWORD_CWORD_CWORD,
1033 /* 150 20 */ CWORD_CWORD_CWORD_CWORD,
1034 /* 151 21 */ CWORD_CWORD_CWORD_CWORD,
1035 /* 152 22 */ CWORD_CWORD_CWORD_CWORD,
1036 /* 153 23 */ CWORD_CWORD_CWORD_CWORD,
1037 /* 154 24 */ CWORD_CWORD_CWORD_CWORD,
1038 /* 155 25 */ CWORD_CWORD_CWORD_CWORD,
1039 /* 156 26 */ CWORD_CWORD_CWORD_CWORD,
1040 /* 157 27 */ CWORD_CWORD_CWORD_CWORD,
1041 /* 158 28 */ CWORD_CWORD_CWORD_CWORD,
1042 /* 159 29 */ CWORD_CWORD_CWORD_CWORD,
1043 /* 160 30 */ CWORD_CWORD_CWORD_CWORD,
1044 /* 161 31 */ CWORD_CWORD_CWORD_CWORD,
1045 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD,
1046 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD,
1047 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
1048 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD,
1049 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR,
1050 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD,
1051 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
1052 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
1053 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP,
1054 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP,
1055 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD,
1056 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD,
1057 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD,
1058 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD,
1059 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD,
1060 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD,
1061 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD,
1062 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD,
1063 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD,
1064 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD,
1065 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD,
1066 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD,
1067 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD,
1068 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD,
1069 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD,
1070 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD,
1071 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD,
1072 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
1073 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
1074 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD,
1075 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
1076 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD,
1077 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD,
1078 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD,
1079 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD,
1080 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD,
1081 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD,
1082 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD,
1083 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD,
1084 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD,
1085 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD,
1086 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD,
1087 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD,
1088 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD,
1089 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD,
1090 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD,
1091 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD,
1092 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD,
1093 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD,
1094 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
1095 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD,
1096 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD,
1097 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD,
1098 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD,
1099 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD,
1100 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD,
1101 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD,
1102 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
1103 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
1104 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD,
1105 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK,
1106 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD,
1107 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD,
1108 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD,
1109 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
1110 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD,
1111 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD,
1112 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD,
1113 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD,
1114 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD,
1115 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD,
1116 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD,
1117 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD,
1118 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD,
1119 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD,
1120 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD,
1121 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD,
1122 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD,
1123 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD,
1124 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD,
1125 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD,
1126 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD,
1127 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD,
1128 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD,
1129 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD,
1130 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD,
1131 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD,
1132 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD,
1133 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD,
1134 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD,
1135 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD,
1136 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD,
1137 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
1138 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
1139 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,
1140 /* 257 127 */ CWORD_CWORD_CWORD_CWORD,
1143 #endif /* USE_SIT_FUNCTION */
1145 /* $NetBSD: alias.c,v 1.11 2002/11/24 22:35:38 christos Exp $ */
1150 static int funcblocksize; /* size of structures in function */
1151 static int funcstringsize; /* size of strings in node */
1152 static pointer funcblock; /* block to allocate function from */
1153 static char *funcstring; /* block to allocate strings from */
1155 static const short nodesize[26] = {
1156 SHELL_ALIGN(sizeof (struct ncmd)),
1157 SHELL_ALIGN(sizeof (struct npipe)),
1158 SHELL_ALIGN(sizeof (struct nredir)),
1159 SHELL_ALIGN(sizeof (struct nredir)),
1160 SHELL_ALIGN(sizeof (struct nredir)),
1161 SHELL_ALIGN(sizeof (struct nbinary)),
1162 SHELL_ALIGN(sizeof (struct nbinary)),
1163 SHELL_ALIGN(sizeof (struct nbinary)),
1164 SHELL_ALIGN(sizeof (struct nif)),
1165 SHELL_ALIGN(sizeof (struct nbinary)),
1166 SHELL_ALIGN(sizeof (struct nbinary)),
1167 SHELL_ALIGN(sizeof (struct nfor)),
1168 SHELL_ALIGN(sizeof (struct ncase)),
1169 SHELL_ALIGN(sizeof (struct nclist)),
1170 SHELL_ALIGN(sizeof (struct narg)),
1171 SHELL_ALIGN(sizeof (struct narg)),
1172 SHELL_ALIGN(sizeof (struct nfile)),
1173 SHELL_ALIGN(sizeof (struct nfile)),
1174 SHELL_ALIGN(sizeof (struct nfile)),
1175 SHELL_ALIGN(sizeof (struct nfile)),
1176 SHELL_ALIGN(sizeof (struct nfile)),
1177 SHELL_ALIGN(sizeof (struct ndup)),
1178 SHELL_ALIGN(sizeof (struct ndup)),
1179 SHELL_ALIGN(sizeof (struct nhere)),
1180 SHELL_ALIGN(sizeof (struct nhere)),
1181 SHELL_ALIGN(sizeof (struct nnot)),
1185 static void calcsize(union node *);
1186 static void sizenodelist(struct nodelist *);
1187 static union node *copynode(union node *);
1188 static struct nodelist *copynodelist(struct nodelist *);
1189 static char *nodesavestr(char *);
1193 static void evalstring(char *, int);
1194 union node; /* BLETCH for ansi C */
1195 static void evaltree(union node *, int);
1196 static void evalbackcmd(union node *, struct backcmd *);
1198 /* in_function returns nonzero if we are currently evaluating a function */
1199 #define in_function() funcnest
1200 static int evalskip; /* set if we are skipping commands */
1201 static int skipcount; /* number of levels to skip */
1202 static int funcnest; /* depth of function calls */
1204 /* reasons for skipping commands (see comment on breakcmd routine) */
1211 * This file was generated by the mkbuiltins program.
1215 static int bgcmd(int, char **);
1217 static int breakcmd(int, char **);
1218 static int cdcmd(int, char **);
1219 #ifdef CONFIG_ASH_CMDCMD
1220 static int commandcmd(int, char **);
1222 static int dotcmd(int, char **);
1223 static int evalcmd(int, char **);
1224 static int execcmd(int, char **);
1225 static int exitcmd(int, char **);
1226 #ifdef CONFIG_ASH_MATH_SUPPORT
1227 static int expcmd(int, char **);
1229 static int exportcmd(int, char **);
1230 static int falsecmd(int, char **);
1232 static int fgcmd(int, char **);
1234 #ifdef CONFIG_ASH_GETOPTS
1235 static int getoptscmd(int, char **);
1237 static int hashcmd(int, char **);
1238 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1239 static int helpcmd(int argc, char **argv);
1242 static int jobscmd(int, char **);
1244 static int localcmd(int, char **);
1245 static int pwdcmd(int, char **);
1246 static int readcmd(int, char **);
1247 static int returncmd(int, char **);
1248 static int setcmd(int, char **);
1249 static int shiftcmd(int, char **);
1250 static int timescmd(int, char **);
1251 static int trapcmd(int, char **);
1252 static int truecmd(int, char **);
1253 static int typecmd(int, char **);
1254 static int umaskcmd(int, char **);
1255 static int unsetcmd(int, char **);
1256 static int waitcmd(int, char **);
1257 static int ulimitcmd(int, char **);
1259 static int killcmd(int, char **);
1262 /* $NetBSD: mail.h,v 1.9 2002/11/24 22:35:40 christos Exp $ */
1264 #ifdef CONFIG_ASH_MAIL
1265 static void chkmail(void);
1266 static void changemail(const char *);
1269 /* $NetBSD: exec.h,v 1.20 2003/01/22 20:36:04 dsl Exp $ */
1271 /* values of cmdtype */
1272 #define CMDUNKNOWN -1 /* no entry in table for command */
1273 #define CMDNORMAL 0 /* command is an executable program */
1274 #define CMDFUNCTION 1 /* command is a shell function */
1275 #define CMDBUILTIN 2 /* command is a shell builtin */
1279 int (*builtin)(int, char **);
1280 /* unsigned flags; */
1283 #ifdef CONFIG_ASH_CMDCMD
1285 # ifdef CONFIG_ASH_ALIAS
1286 # define COMMANDCMD (builtincmd + 7)
1287 # define EXECCMD (builtincmd + 10)
1289 # define COMMANDCMD (builtincmd + 6)
1290 # define EXECCMD (builtincmd + 9)
1293 # ifdef CONFIG_ASH_ALIAS
1294 # define COMMANDCMD (builtincmd + 6)
1295 # define EXECCMD (builtincmd + 9)
1297 # define COMMANDCMD (builtincmd + 5)
1298 # define EXECCMD (builtincmd + 8)
1301 #else /* ! CONFIG_ASH_CMDCMD */
1303 # ifdef CONFIG_ASH_ALIAS
1304 # define EXECCMD (builtincmd + 9)
1306 # define EXECCMD (builtincmd + 8)
1309 # ifdef CONFIG_ASH_ALIAS
1310 # define EXECCMD (builtincmd + 8)
1312 # define EXECCMD (builtincmd + 7)
1315 #endif /* CONFIG_ASH_CMDCMD */
1317 #define BUILTIN_NOSPEC "0"
1318 #define BUILTIN_SPECIAL "1"
1319 #define BUILTIN_REGULAR "2"
1320 #define BUILTIN_SPEC_REG "3"
1321 #define BUILTIN_ASSIGN "4"
1322 #define BUILTIN_SPEC_ASSG "5"
1323 #define BUILTIN_REG_ASSG "6"
1324 #define BUILTIN_SPEC_REG_ASSG "7"
1326 #define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1327 #define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
1329 static const struct builtincmd builtincmd[] = {
1330 { BUILTIN_SPEC_REG ".", dotcmd },
1331 { BUILTIN_SPEC_REG ":", truecmd },
1332 #ifdef CONFIG_ASH_ALIAS
1333 { BUILTIN_REG_ASSG "alias", aliascmd },
1336 { BUILTIN_REGULAR "bg", bgcmd },
1338 { BUILTIN_SPEC_REG "break", breakcmd },
1339 { BUILTIN_REGULAR "cd", cdcmd },
1340 { BUILTIN_NOSPEC "chdir", cdcmd },
1341 #ifdef CONFIG_ASH_CMDCMD
1342 { BUILTIN_REGULAR "command", commandcmd },
1344 { BUILTIN_SPEC_REG "continue", breakcmd },
1345 { BUILTIN_SPEC_REG "eval", evalcmd },
1346 { BUILTIN_SPEC_REG "exec", execcmd },
1347 { BUILTIN_SPEC_REG "exit", exitcmd },
1348 #ifdef CONFIG_ASH_MATH_SUPPORT
1349 { BUILTIN_NOSPEC "exp", expcmd },
1351 { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
1352 { BUILTIN_REGULAR "false", falsecmd },
1354 { BUILTIN_REGULAR "fg", fgcmd },
1356 #ifdef CONFIG_ASH_GETOPTS
1357 { BUILTIN_REGULAR "getopts", getoptscmd },
1359 { BUILTIN_NOSPEC "hash", hashcmd },
1360 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1361 { BUILTIN_NOSPEC "help", helpcmd },
1364 { BUILTIN_REGULAR "jobs", jobscmd },
1365 { BUILTIN_REGULAR "kill", killcmd },
1367 #ifdef CONFIG_ASH_MATH_SUPPORT
1368 { BUILTIN_NOSPEC "let", expcmd },
1370 { BUILTIN_ASSIGN "local", localcmd },
1371 { BUILTIN_NOSPEC "pwd", pwdcmd },
1372 { BUILTIN_REGULAR "read", readcmd },
1373 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
1374 { BUILTIN_SPEC_REG "return", returncmd },
1375 { BUILTIN_SPEC_REG "set", setcmd },
1376 { BUILTIN_SPEC_REG "shift", shiftcmd },
1377 { BUILTIN_SPEC_REG "times", timescmd },
1378 { BUILTIN_SPEC_REG "trap", trapcmd },
1379 { BUILTIN_REGULAR "true", truecmd },
1380 { BUILTIN_NOSPEC "type", typecmd },
1381 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
1382 { BUILTIN_REGULAR "umask", umaskcmd },
1383 #ifdef CONFIG_ASH_ALIAS
1384 { BUILTIN_REGULAR "unalias", unaliascmd },
1386 { BUILTIN_SPEC_REG "unset", unsetcmd },
1387 { BUILTIN_REGULAR "wait", waitcmd },
1390 #define NUMBUILTINS (sizeof (builtincmd) / sizeof (struct builtincmd) )
1398 const struct builtincmd *cmd;
1399 struct funcnode *func;
1404 /* action to find_command() */
1405 #define DO_ERR 0x01 /* prints errors */
1406 #define DO_ABS 0x02 /* checks absolute paths */
1407 #define DO_NOFUNC 0x04 /* don't return shell functions, for command */
1408 #define DO_ALTPATH 0x08 /* using alternate path */
1409 #define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
1411 static const char *pathopt; /* set by padvance */
1413 static void shellexec(char **, const char *, int)
1414 __attribute__((__noreturn__));
1415 static char *padvance(const char **, const char *);
1416 static void find_command(char *, struct cmdentry *, int, const char *);
1417 static struct builtincmd *find_builtin(const char *);
1418 static void hashcd(void);
1419 static void changepath(const char *);
1420 static void defun(char *, union node *);
1421 static void unsetfunc(const char *);
1423 #ifdef CONFIG_ASH_MATH_SUPPORT
1425 static int dash_arith(const char *);
1428 /* $NetBSD: init.h,v 1.9 2002/11/24 22:35:40 christos Exp $ */
1430 static void reset(void);
1432 /* $NetBSD: var.h,v 1.21 2003/01/22 20:36:04 dsl Exp $ */
1439 #define VEXPORT 0x01 /* variable is exported */
1440 #define VREADONLY 0x02 /* variable cannot be modified */
1441 #define VSTRFIXED 0x04 /* variable struct is statically allocated */
1442 #define VTEXTFIXED 0x08 /* text is statically allocated */
1443 #define VSTACK 0x10 /* text is allocated on the stack */
1444 #define VUNSET 0x20 /* the variable is not set */
1445 #define VNOFUNC 0x40 /* don't call the callback function */
1446 #define VNOSET 0x80 /* do not set variable - just readonly test */
1447 #define VNOSAVE 0x100 /* when text is on the heap before setvareq */
1451 struct var *next; /* next entry in hash list */
1452 int flags; /* flags are defined above */
1453 const char *text; /* name=value */
1454 void (*func)(const char *);
1455 /* function to be called when */
1456 /* the variable gets set/unset */
1460 struct localvar *next; /* next local variable in list */
1461 struct var *vp; /* the variable that was made local */
1462 int flags; /* saved flags */
1463 const char *text; /* saved text */
1467 static struct localvar *localvars;
1473 #ifdef CONFIG_ASH_GETOPTS
1474 static void getoptsreset(const char *);
1477 #ifdef CONFIG_LOCALE_SUPPORT
1479 static void change_lc_all(const char *value);
1480 static void change_lc_ctype(const char *value);
1485 static const char defpathvar[] =
1486 "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
1488 static const char defifsvar[] = "IFS= \t\n";
1489 #define defifs (defifsvar + 4)
1491 static const char defifs[] = " \t\n";
1495 static struct var varinit[] = {
1497 { 0, VSTRFIXED|VTEXTFIXED, defifsvar, 0 },
1499 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", 0 },
1502 #ifdef CONFIG_ASH_MAIL
1503 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail },
1504 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail },
1507 { 0, VSTRFIXED|VTEXTFIXED, defpathvar, changepath },
1508 { 0, VSTRFIXED|VTEXTFIXED, "PS1=$ ", 0 },
1509 { 0, VSTRFIXED|VTEXTFIXED, "PS2=> ", 0 },
1510 { 0, VSTRFIXED|VTEXTFIXED, "PS4=+ ", 0 },
1511 #ifdef CONFIG_ASH_GETOPTS
1512 { 0, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset },
1514 #ifdef CONFIG_LOCALE_SUPPORT
1515 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL=", change_lc_all},
1516 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE=", change_lc_ctype},
1518 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
1519 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE=", NULL},
1523 #define vifs varinit[0]
1524 #ifdef CONFIG_ASH_MAIL
1525 #define vmail (&vifs)[1]
1526 #define vmpath (&vmail)[1]
1530 #define vpath (&vmpath)[1]
1531 #define vps1 (&vpath)[1]
1532 #define vps2 (&vps1)[1]
1533 #define vps4 (&vps2)[1]
1534 #define voptind (&vps4)[1]
1536 #define defpath (defpathvar + 5)
1539 * The following macros access the values of the above variables.
1540 * They have to skip over the name. They return the null string
1541 * for unset variables.
1544 #define ifsval() (vifs.text + 4)
1545 #define ifsset() ((vifs.flags & VUNSET) == 0)
1546 #define mailval() (vmail.text + 5)
1547 #define mpathval() (vmpath.text + 9)
1548 #define pathval() (vpath.text + 5)
1549 #define ps1val() (vps1.text + 4)
1550 #define ps2val() (vps2.text + 4)
1551 #define ps4val() (vps4.text + 4)
1552 #define optindval() (voptind.text + 7)
1554 #define mpathset() ((vmpath.flags & VUNSET) == 0)
1556 static void setvar(const char *, const char *, int);
1557 static void setvareq(char *, int);
1558 static void listsetvar(struct strlist *, int);
1559 static char *lookupvar(const char *);
1560 static char *bltinlookup(const char *);
1561 static char **listvars(int, int, char ***);
1562 #define environment() listvars(VEXPORT, VUNSET, 0)
1563 static int showvars(const char *, int, int);
1564 static void poplocalvars(void);
1565 static int unsetvar(const char *);
1566 #ifdef CONFIG_ASH_GETOPTS
1567 static int setvarsafe(const char *, const char *, int);
1569 static int varcmp(const char *, const char *);
1570 static struct var **hashvar(const char *);
1573 static inline int varequal(const char *a, const char *b) {
1574 return !varcmp(a, b);
1578 static int loopnest; /* current loop nesting level */
1581 struct strpush *prev; /* preceding string on stack */
1584 #ifdef CONFIG_ASH_ALIAS
1585 struct alias *ap; /* if push was associated with an alias */
1587 char *string; /* remember the string since it may change */
1591 struct parsefile *prev; /* preceding file on stack */
1592 int linno; /* current line */
1593 int fd; /* file descriptor (or -1 if string) */
1594 int nleft; /* number of chars left in this line */
1595 int lleft; /* number of chars left in this buffer */
1596 char *nextc; /* next char in buffer */
1597 char *buf; /* input buffer */
1598 struct strpush *strpush; /* for pushing strings at this level */
1599 struct strpush basestrpush; /* so pushing one is fast */
1603 * The parsefile structure pointed to by the global variable parsefile
1604 * contains information about the current file being read.
1609 struct redirtab *next;
1614 static struct redirtab *redirlist;
1615 static int nullredirs;
1617 extern char **environ;
1619 /* $NetBSD: output.h,v 1.16 2002/11/24 22:35:42 christos Exp $ */
1622 static void outstr(const char *, FILE *);
1623 static void outcslow(int, FILE *);
1624 static void flushall(void);
1625 static void flushout(FILE *);
1626 static int out1fmt(const char *, ...)
1627 __attribute__((__format__(__printf__,1,2)));
1628 static int fmtstr(char *, size_t, const char *, ...)
1629 __attribute__((__format__(__printf__,3,4)));
1630 static void xwrite(int, const void *, size_t);
1633 #define outerr(f) ferror(f)
1634 #define out2c(c) outcslow((c), stderr)
1636 static void out1str(const char *p)
1641 static void out2str(const char *p)
1646 static void out1c(char c)
1656 * Initialization code.
1660 * This routine initializes the builtin variables.
1671 * PS1 depends on uid
1673 #if defined(CONFIG_FEATURE_COMMAND_EDITING) && defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
1674 vps1.text = "PS1=\\w \\$ ";
1677 vps1.text = "PS1=# ";
1680 end = vp + sizeof(varinit) / sizeof(varinit[0]);
1682 vpp = hashvar(vp->text);
1685 } while (++vp < end);
1694 basepf.nextc = basepf.buf = basebuf;
1699 signal(SIGCHLD, SIG_DFL);
1708 for (envp = environ ; *envp ; envp++) {
1709 if (strchr(*envp, '=')) {
1710 setvareq(*envp, VEXPORT|VTEXTFIXED);
1714 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
1715 setvar("PPID", ppid, 0);
1720 /* PEOF (the end of file marker) */
1723 * The input line number. Input.c just defines this variable, and saves
1724 * and restores it when files are pushed and popped. The user of this
1725 * package must set its value.
1728 static int pgetc(void);
1729 static int pgetc2(void);
1730 static int preadbuffer(void);
1731 static void pungetc(void);
1732 static void pushstring(char *, void *);
1733 static void popstring(void);
1734 static void setinputfile(const char *, int);
1735 static void setinputfd(int, int);
1736 static void setinputstring(char *);
1737 static void popfile(void);
1738 static void popallfiles(void);
1739 static void closescript(void);
1742 /* $NetBSD: jobs.h,v 1.17 2003/01/22 20:36:04 dsl Exp $ */
1745 /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
1748 #define FORK_NOJOB 2
1750 /* mode flags for showjob(s) */
1751 #define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
1752 #define SHOW_PID 0x04 /* include process pid */
1753 #define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
1757 * A job structure contains information about a job. A job is either a
1758 * single process or a set of processes contained in a pipeline. In the
1759 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1764 pid_t pid; /* process id */
1765 int status; /* last process status from wait() */
1766 char *cmd; /* text of command being run */
1770 struct procstat ps0; /* status of process */
1771 struct procstat *ps; /* status or processes when more than one */
1773 int stopstatus; /* status of a stopped job */
1776 nprocs: 16, /* number of processes */
1778 #define JOBRUNNING 0 /* at least one proc running */
1779 #define JOBSTOPPED 1 /* all procs are stopped */
1780 #define JOBDONE 2 /* all procs are completed */
1782 sigint: 1, /* job was killed by SIGINT */
1783 jobctl: 1, /* job running under job control */
1785 waited: 1, /* true if this entry has been waited for */
1786 used: 1, /* true if this entry is in used */
1787 changed: 1; /* true if status has changed */
1788 struct job *prev_job; /* previous job */
1791 static pid_t backgndpid; /* pid of last background process */
1792 static int job_warning; /* user was warned about stopped jobs */
1794 static int jobctl; /* true if doing job control */
1797 static struct job *makejob(union node *, int);
1798 static int forkshell(struct job *, union node *, int);
1799 static int waitforjob(struct job *);
1800 static int stoppedjobs(void);
1803 #define setjobctl(on) /* do nothing */
1805 static void setjobctl(int);
1806 static void showjobs(FILE *, int);
1809 /* $NetBSD: main.h,v 1.9 2002/11/24 22:35:41 christos Exp $ */
1812 /* pid of main shell */
1814 /* true if we aren't a child of the main shell */
1815 static int rootshell;
1817 static void readcmdfile(char *);
1818 static void cmdloop(int);
1820 /* $NetBSD: memalloc.h,v 1.13 2003/01/22 20:36:04 dsl Exp $ */
1824 struct stack_block *stackp;
1827 struct stackmark *marknext;
1830 /* minimum size of a block */
1831 #define MINSIZE SHELL_ALIGN(504)
1833 struct stack_block {
1834 struct stack_block *prev;
1835 char space[MINSIZE];
1838 static struct stack_block stackbase;
1839 static struct stack_block *stackp = &stackbase;
1840 static struct stackmark *markp;
1841 static char *stacknxt = stackbase.space;
1842 static size_t stacknleft = MINSIZE;
1843 static char *sstrend = stackbase.space + MINSIZE;
1844 static int herefd = -1;
1847 static pointer ckmalloc(size_t);
1848 static pointer ckrealloc(pointer, size_t);
1849 static char *savestr(const char *);
1850 static pointer stalloc(size_t);
1851 static void stunalloc(pointer);
1852 static void setstackmark(struct stackmark *);
1853 static void popstackmark(struct stackmark *);
1854 static void growstackblock(void);
1855 static void *growstackstr(void);
1856 static char *makestrspace(size_t, char *);
1857 static char *stnputs(const char *, size_t, char *);
1858 static char *stputs(const char *, char *);
1861 static inline char *_STPUTC(char c, char *p) {
1868 #define stackblock() ((void *)stacknxt)
1869 #define stackblocksize() stacknleft
1870 #define STARTSTACKSTR(p) ((p) = stackblock())
1871 #define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1872 #define CHECKSTRSPACE(n, p) \
1876 size_t m = sstrend - q; \
1878 (p) = makestrspace(l, q); \
1881 #define USTPUTC(c, p) (*p++ = (c))
1882 #define STACKSTRNUL(p) ((p) == sstrend? (p = growstackstr(), *p = '\0') : (*p = '\0'))
1883 #define STUNPUTC(p) (--p)
1884 #define STTOPC(p) p[-1]
1885 #define STADJUST(amount, p) (p += (amount))
1887 #define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1888 #define ungrabstackstr(s, p) stunalloc((s))
1889 #define stackstrend() ((void *)sstrend)
1891 #define ckfree(p) free((pointer)(p))
1893 /* $NetBSD: mystring.h,v 1.10 2002/11/24 22:35:42 christos Exp $ */
1896 #define DOLATSTRLEN 4
1898 static char *prefix(const char *, const char *);
1899 static int number(const char *);
1900 static int is_number(const char *);
1901 static char *single_quote(const char *);
1902 static char *sstrdup(const char *);
1904 #define equal(s1, s2) (strcmp(s1, s2) == 0)
1905 #define scopy(s1, s2) ((void)strcpy(s2, s1))
1907 /* $NetBSD: options.h,v 1.16 2003/01/22 20:36:04 dsl Exp $ */
1910 int nparam; /* # of positional parameters (without $0) */
1911 unsigned char malloc; /* if parameter list dynamically allocated */
1912 char **p; /* parameter list */
1913 #ifdef CONFIG_ASH_GETOPTS
1914 int optind; /* next parameter to be processed by getopts */
1915 int optoff; /* used by getopts */
1920 #define eflag optlist[0]
1921 #define fflag optlist[1]
1922 #define Iflag optlist[2]
1923 #define iflag optlist[3]
1924 #define mflag optlist[4]
1925 #define nflag optlist[5]
1926 #define sflag optlist[6]
1927 #define xflag optlist[7]
1928 #define vflag optlist[8]
1929 #define Cflag optlist[9]
1930 #define aflag optlist[10]
1931 #define bflag optlist[11]
1932 #define uflag optlist[12]
1933 #define qflag optlist[13]
1936 #define nolog optlist[14]
1937 #define debug optlist[15]
1943 /* $NetBSD: options.c,v 1.33 2003/01/22 20:36:04 dsl Exp $ */
1946 static const char *const optletters_optnames[NOPTS] = {
1967 #define optletters(n) optletters_optnames[(n)][0]
1968 #define optnames(n) (&optletters_optnames[(n)][1])
1971 static char optlist[NOPTS];
1974 static char *arg0; /* value of $0 */
1975 static struct shparam shellparam; /* $@ current positional parameters */
1976 static char **argptr; /* argument list for builtin commands */
1977 static char *optionarg; /* set by nextopt (like getopt) */
1978 static char *optptr; /* used by nextopt */
1980 static char *minusc; /* argument to -c option */
1983 static void procargs(int, char **);
1984 static void optschanged(void);
1985 static void setparam(char **);
1986 static void freeparam(volatile struct shparam *);
1987 static int shiftcmd(int, char **);
1988 static int setcmd(int, char **);
1989 static int nextopt(const char *);
1991 /* $NetBSD: redir.h,v 1.14 2002/11/24 22:35:43 christos Exp $ */
1993 /* flags passed to redirect */
1994 #define REDIR_PUSH 01 /* save previous values of file descriptors */
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");
2323 if (!(path = bltinlookup("CDPATH"))) {
2331 p = padvance(&path, dest);
2332 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2336 if (!docd(p, flags))
2341 error("can't cd to %s", dest);
2344 if (flags & CD_PRINT)
2345 out1fmt(snlfmt, curdir);
2351 * Update curdir (the name of the current directory) in response to a
2355 static inline const char *
2356 updatepwd(const char *dir)
2363 cdcomppath = sstrdup(dir);
2366 if (curdir == nullstr)
2368 new = stputs(curdir, new);
2370 new = makestrspace(strlen(dir) + 2, new);
2371 lim = stackblock() + 1;
2375 if (new > lim && *lim == '/')
2380 if (dir[1] == '/' && dir[2] != '/') {
2386 p = strtok(cdcomppath, "/");
2390 if (p[1] == '.' && p[2] == '\0') {
2397 } else if (p[1] == '\0')
2401 new = stputs(p, new);
2409 return stackblock();
2413 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2414 * know that the current directory has changed.
2418 docd(const char *dest, int flags)
2420 const char *dir = 0;
2423 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2426 if (!(flags & CD_PHYSICAL)) {
2427 dir = updatepwd(dest);
2442 * Find out what the current directory is. If we already know the current
2443 * directory, this routine returns immediately.
2445 static inline char *
2448 char *dir = getcwd(0, 0);
2449 return dir ? dir : nullstr;
2453 pwdcmd(int argc, char **argv)
2456 const char *dir = curdir;
2460 if (physdir == nullstr)
2464 out1fmt(snlfmt, dir);
2469 setpwd(const char *val, int setold)
2473 oldcur = dir = curdir;
2476 setvar("OLDPWD", oldcur, VEXPORT);
2479 if (physdir != nullstr) {
2480 if (physdir != oldcur)
2484 if (oldcur == val || !val) {
2491 if (oldcur != dir && oldcur != nullstr) {
2496 setvar("PWD", dir, VEXPORT);
2499 /* $NetBSD: error.c,v 1.30 2003/01/22 20:36:03 dsl Exp $ */
2502 * Errors and exceptions.
2506 * Code to handle exceptions in C.
2511 static void exverror(int, const char *, va_list)
2512 __attribute__((__noreturn__));
2515 * Called to raise an exception. Since C doesn't include exceptions, we
2516 * just do a longjmp to the exception handler. The type of exception is
2517 * stored in the global variable "exception".
2524 if (handler == NULL)
2530 longjmp(handler->loc, 1);
2535 * Called from trap.c when a SIGINT is received. (If the user specifies
2536 * that SIGINT is to be trapped or ignored using the trap builtin, then
2537 * this routine is not called.) Suppressint is nonzero when interrupts
2538 * are held using the INTOFF macro. (The test for iflag is just
2539 * defensive programming.)
2549 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
2550 if (!(rootshell && iflag)) {
2551 signal(SIGINT, SIG_DFL);
2561 exvwarning(const char *msg, va_list ap)
2574 fprintf(errs, fmt, name, startlinno);
2575 vfprintf(errs, msg, ap);
2576 outcslow('\n', errs);
2580 * Exverror is called to raise the error exception. If the second argument
2581 * is not NULL then error prints an error message using printf style
2582 * formatting. It then raises the error exception.
2585 exverror(int cond, const char *msg, va_list ap)
2589 TRACE(("exverror(%d, \"", cond));
2591 TRACE(("\") pid=%d\n", getpid()));
2593 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
2596 exvwarning(msg, ap);
2605 error(const char *msg, ...)
2610 exverror(EXERROR, msg, ap);
2617 exerror(int cond, const char *msg, ...)
2622 exverror(cond, msg, ap);
2628 * error/warning routines for external builtins
2632 sh_warnx(const char *fmt, ...)
2637 exvwarning(fmt, ap);
2643 * Return a string describing an error. The returned string may be a
2644 * pointer to a static buffer that will be overwritten on the next call.
2645 * Action describes the operation that got the error.
2649 errmsg(int e, const char *em)
2651 if(e == ENOENT || e == ENOTDIR) {
2659 /* $NetBSD: eval.c,v 1.71 2003/01/23 03:33:16 rafal Exp $ */
2662 * Evaluate a command.
2665 /* flags in argument to evaltree */
2666 #define EV_EXIT 01 /* exit after evaluating tree */
2667 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2668 #define EV_BACKCMD 04 /* command executing within back quotes */
2671 static void evalloop(union node *, int);
2672 static void evalfor(union node *, int);
2673 static void evalcase(union node *, int);
2674 static void evalsubshell(union node *, int);
2675 static void expredir(union node *);
2676 static void evalpipe(union node *, int);
2677 static void evalcommand(union node *, int);
2678 static int evalbltin(const struct builtincmd *, int, char **);
2679 static int evalfun(struct funcnode *, int, char **, int);
2680 static void prehash(union node *);
2681 static int eprintlist(struct strlist *, int);
2682 static int bltincmd(int, char **);
2685 static const struct builtincmd bltin = {
2691 * Called to reset things after an exception.
2695 * The eval commmand.
2699 evalcmd(int argc, char **argv)
2708 STARTSTACKSTR(concat);
2711 concat = stputs(p, concat);
2712 if ((p = *ap++) == NULL)
2714 STPUTC(' ', concat);
2716 STPUTC('\0', concat);
2717 p = grabstackstr(concat);
2719 evalstring(p, EV_TESTED);
2726 * Execute a command or commands contained in a string.
2730 evalstring(char *s, int flag)
2733 struct stackmark smark;
2735 setstackmark(&smark);
2738 while ((n = parsecmd(0)) != NEOF) {
2740 popstackmark(&smark);
2745 popstackmark(&smark);
2751 * Evaluate a parse tree. The value is left in the global variable
2756 evaltree(union node *n, int flags)
2759 void (*evalfn)(union node *, int);
2763 TRACE(("evaltree(NULL) called\n"));
2766 TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
2767 getpid(), n, n->type, flags));
2771 out1fmt("Node type = %d\n", n->type);
2776 evaltree(n->nnot.com, EV_TESTED);
2777 status = !exitstatus;
2780 expredir(n->nredir.redirect);
2781 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
2783 evaltree(n->nredir.n, flags & EV_TESTED);
2784 status = exitstatus;
2789 evalfn = evalcommand;
2791 if (eflag && !(flags & EV_TESTED))
2803 evalfn = evalsubshell;
2815 #error NAND + 1 != NOR
2817 #if NOR + 1 != NSEMI
2818 #error NOR + 1 != NSEMI
2820 isor = n->type - NAND;
2823 (flags | ((isor >> 1) - 1)) & EV_TESTED
2825 if (!exitstatus == isor)
2837 evaltree(n->nif.test, EV_TESTED);
2840 if (exitstatus == 0) {
2843 } else if (n->nif.elsepart) {
2844 n = n->nif.elsepart;
2849 defun(n->narg.text, n->narg.next);
2853 exitstatus = status;
2859 if (flags & EV_EXIT || checkexit & exitstatus)
2864 #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
2867 void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
2871 evalloop(union node *n, int flags)
2881 evaltree(n->nbinary.ch1, EV_TESTED);
2883 skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
2887 if (evalskip == SKIPBREAK && --skipcount <= 0)
2892 if (n->type != NWHILE)
2896 evaltree(n->nbinary.ch2, flags);
2897 status = exitstatus;
2902 exitstatus = status;
2908 evalfor(union node *n, int flags)
2910 struct arglist arglist;
2913 struct stackmark smark;
2915 setstackmark(&smark);
2916 arglist.lastp = &arglist.list;
2917 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
2918 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
2923 *arglist.lastp = NULL;
2928 for (sp = arglist.list ; sp ; sp = sp->next) {
2929 setvar(n->nfor.var, sp->text, 0);
2930 evaltree(n->nfor.body, flags);
2932 if (evalskip == SKIPCONT && --skipcount <= 0) {
2936 if (evalskip == SKIPBREAK && --skipcount <= 0)
2943 popstackmark(&smark);
2949 evalcase(union node *n, int flags)
2953 struct arglist arglist;
2954 struct stackmark smark;
2956 setstackmark(&smark);
2957 arglist.lastp = &arglist.list;
2958 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
2960 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2961 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
2962 if (casematch(patp, arglist.list->text)) {
2963 if (evalskip == 0) {
2964 evaltree(cp->nclist.body, flags);
2971 popstackmark(&smark);
2977 * Kick off a subshell to evaluate a tree.
2981 evalsubshell(union node *n, int flags)
2984 int backgnd = (n->type == NBACKGND);
2987 expredir(n->nredir.redirect);
2988 if (!backgnd && flags & EV_EXIT && !trap[0])
2992 if (forkshell(jp, n, backgnd) == 0) {
2996 flags &=~ EV_TESTED;
2998 redirect(n->nredir.redirect, 0);
2999 evaltreenr(n->nredir.n, flags);
3004 status = waitforjob(jp);
3005 exitstatus = status;
3012 * Compute the names of the files in a redirection list.
3016 expredir(union node *n)
3020 for (redir = n ; redir ; redir = redir->nfile.next) {
3022 fn.lastp = &fn.list;
3023 switch (redir->type) {
3029 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
3030 redir->nfile.expfname = fn.list->text;
3034 if (redir->ndup.vname) {
3035 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
3036 fixredir(redir, fn.list->text, 1);
3046 * Evaluate a pipeline. All the processes in the pipeline are children
3047 * of the process creating the pipeline. (This differs from some versions
3048 * of the shell, which make the last process in a pipeline the parent
3053 evalpipe(union node *n, int flags)
3056 struct nodelist *lp;
3061 TRACE(("evalpipe(0x%lx) called\n", (long)n));
3063 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
3067 jp = makejob(n, pipelen);
3069 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
3073 if (pipe(pip) < 0) {
3075 error("Pipe call failed");
3078 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
3091 evaltreenr(lp->n, flags);
3099 if (n->npipe.backgnd == 0) {
3100 exitstatus = waitforjob(jp);
3101 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
3109 * Execute a command inside back quotes. If it's a builtin command, we
3110 * want to save its output in a block obtained from malloc. Otherwise
3111 * we fork off a subprocess and get the output of the command via a pipe.
3112 * Should be called with interrupts off.
3116 evalbackcmd(union node *n, struct backcmd *result)
3128 saveherefd = herefd;
3136 error("Pipe call failed");
3138 if (forkshell(jp, n, FORK_NOJOB) == 0) {
3147 evaltreenr(n, EV_EXIT);
3151 result->fd = pip[0];
3154 herefd = saveherefd;
3156 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
3157 result->fd, result->buf, result->nleft, result->jp));
3160 #ifdef CONFIG_ASH_CMDCMD
3161 static inline char **
3162 parse_command_args(char **argv, const char **path)
3174 if (c == '-' && !*cp) {
3184 /* run 'typecmd' for other options */
3187 } while ((c = *cp++));
3196 * Execute a simple command.
3200 evalcommand(union node *cmd, int flags)
3202 struct stackmark smark;
3204 struct arglist arglist;
3205 struct arglist varlist;
3209 struct cmdentry cmdentry;
3218 /* First expand the arguments. */
3219 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
3220 setstackmark(&smark);
3221 back_exitstatus = 0;
3223 cmdentry.cmdtype = CMDBUILTIN;
3224 cmdentry.u.cmd = &bltin;
3225 varlist.lastp = &varlist.list;
3226 *varlist.lastp = NULL;
3227 arglist.lastp = &arglist.list;
3228 *arglist.lastp = NULL;
3231 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
3232 struct strlist **spp;
3234 spp = arglist.lastp;
3235 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
3236 for (sp = *spp; sp; sp = sp->next)
3240 argv = nargv = stalloc(sizeof (char *) * (argc + 1));
3241 for (sp = arglist.list ; sp ; sp = sp->next) {
3242 TRACE(("evalcommand arg: %s\n", sp->text));
3243 *nargv++ = sp->text;
3248 if (iflag && funcnest == 0 && argc > 0)
3249 lastarg = nargv[-1];
3251 expredir(cmd->ncmd.redirect);
3252 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH);
3255 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
3256 struct strlist **spp;
3259 spp = varlist.lastp;
3260 expandarg(argp, &varlist, EXP_VARTILDE);
3263 * Modify the command lookup path, if a PATH= assignment
3267 if (varequal(p, path))
3271 /* Print the command if xflag is set. */
3277 sep = eprintlist(varlist.list, sep);
3278 eprintlist(arglist.list, sep);
3286 /* Now locate the command. */
3288 const char *oldpath;
3289 int cmd_flag = DO_ERR;
3294 find_command(argv[0], &cmdentry, cmd_flag, path);
3295 if (cmdentry.cmdtype == CMDUNKNOWN) {
3301 /* implement bltin and command here */
3302 if (cmdentry.cmdtype != CMDBUILTIN)
3305 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
3306 if (cmdentry.u.cmd == EXECCMD)
3308 #ifdef CONFIG_ASH_CMDCMD
3309 if (cmdentry.u.cmd == COMMANDCMD) {
3312 nargv = parse_command_args(argv, &path);
3315 argc -= nargv - argv;
3317 cmd_flag |= DO_NOFUNC;
3325 /* We have a redirection error. */
3329 exitstatus = status;
3333 /* Execute the command. */
3334 switch (cmdentry.cmdtype) {
3336 /* Fork off a child process if necessary. */
3337 if (!(flags & EV_EXIT) || trap[0]) {
3339 jp = makejob(cmd, 1);
3340 if (forkshell(jp, cmd, FORK_FG) != 0) {
3341 exitstatus = waitforjob(jp);
3347 listsetvar(varlist.list, VEXPORT|VSTACK);
3348 shellexec(argv, path, cmdentry.u.index);
3352 cmdenviron = varlist.list;
3354 struct strlist *list = cmdenviron;
3356 if (spclbltin > 0 || argc == 0) {
3358 if (cmd_is_exec && argc > 1)
3361 listsetvar(list, i);
3363 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
3378 exit_status = j + 128;
3379 exitstatus = exit_status;
3381 if (i == EXINT || spclbltin > 0) {
3383 longjmp(handler->loc, 1);
3390 listsetvar(varlist.list, 0);
3391 if (evalfun(cmdentry.u.func, argc, argv, flags))
3397 popredir(cmd_is_exec);
3399 /* dsl: I think this is intended to be used to support
3400 * '_' in 'vi' command mode during line editing...
3401 * However I implemented that within libedit itself.
3403 setvar("_", lastarg, 0);
3404 popstackmark(&smark);
3408 evalbltin(const struct builtincmd *cmd, int argc, char **argv) {
3409 char *volatile savecmdname;
3410 struct jmploc *volatile savehandler;
3411 struct jmploc jmploc;
3414 savecmdname = commandname;
3415 if ((i = setjmp(jmploc.loc)))
3417 savehandler = handler;
3419 commandname = argv[0];
3421 optptr = NULL; /* initialize nextopt */
3422 exitstatus = (*cmd->builtin)(argc, argv);
3425 exitstatus |= outerr(stdout);
3426 commandname = savecmdname;
3428 handler = savehandler;
3434 evalfun(struct funcnode *func, int argc, char **argv, int flags)
3436 volatile struct shparam saveparam;
3437 struct localvar *volatile savelocalvars;
3438 struct jmploc *volatile savehandler;
3439 struct jmploc jmploc;
3442 saveparam = shellparam;
3443 savelocalvars = localvars;
3444 if ((e = setjmp(jmploc.loc))) {
3448 savehandler = handler;
3451 shellparam.malloc = 0;
3454 shellparam.nparam = argc - 1;
3455 shellparam.p = argv + 1;
3456 #ifdef CONFIG_ASH_GETOPTS
3457 shellparam.optind = 1;
3458 shellparam.optoff = -1;
3461 evaltree(&func->n, flags & EV_TESTED);
3467 localvars = savelocalvars;
3468 freeparam(&shellparam);
3469 shellparam = saveparam;
3470 handler = savehandler;
3472 if (evalskip == SKIPFUNC) {
3481 * Search for a command. This is called before we fork so that the
3482 * location of the command will be available in the parent as well as
3487 prehash(union node *n)
3489 struct cmdentry entry;
3491 if (n->type == NCMD && n->ncmd.args)
3492 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
3498 * Builtin commands. Builtin commands whose functions are closely
3499 * tied to evaluation are implemented here.
3507 bltincmd(int argc, char **argv)
3510 * Preserve exitstatus of a previous possible redirection
3513 return back_exitstatus;
3518 * Handle break and continue commands. Break, continue, and return are
3519 * all handled by setting the evalskip flag. The evaluation routines
3520 * above all check this flag, and if it is set they start skipping
3521 * commands rather than executing them. The variable skipcount is
3522 * the number of loops to break/continue, or the number of function
3523 * levels to return. (The latter is always 1.) It should probably
3524 * be an error to break out of more loops than exist, but it isn't
3525 * in the standard shell so we don't make it one here.
3529 breakcmd(int argc, char **argv)
3531 int n = argc > 1 ? number(argv[1]) : 1;
3534 error(illnum, argv[1]);
3538 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
3546 * The return command.
3550 returncmd(int argc, char **argv)
3552 int ret = argc > 1 ? number(argv[1]) : exitstatus;
3555 evalskip = SKIPFUNC;
3560 /* Do what ksh does; skip the rest of the file */
3561 evalskip = SKIPFILE;
3569 falsecmd(int argc, char **argv)
3576 truecmd(int argc, char **argv)
3583 execcmd(int argc, char **argv)
3586 iflag = 0; /* exit on error */
3589 shellexec(argv + 1, pathval(), 0);
3596 eprintlist(struct strlist *sp, int sep)
3601 p = " %s" + (1 - sep);
3603 fprintf(stderr, p, sp->text);
3609 /* $NetBSD: exec.c,v 1.35 2003/01/22 20:36:04 dsl Exp $ */
3612 * When commands are first encountered, they are entered in a hash table.
3613 * This ensures that a full path search will not have to be done for them
3614 * on each invocation.
3616 * We should investigate converting to a linear search, even though that
3617 * would make the command name "hash" a misnomer.
3620 #define CMDTABLESIZE 31 /* should be prime */
3621 #define ARB 1 /* actual size determined at run time */
3626 struct tblentry *next; /* next entry in hash chain */
3627 union param param; /* definition of builtin function */
3628 short cmdtype; /* index identifying command */
3629 char rehash; /* if set, cd done since entry created */
3630 char cmdname[ARB]; /* name of command */
3634 static struct tblentry *cmdtable[CMDTABLESIZE];
3635 static int builtinloc = -1; /* index in path of %builtin, or -1 */
3638 static void tryexec(char *, char **, char **);
3639 static void printentry(struct tblentry *);
3640 static void clearcmdentry(int);
3641 static struct tblentry *cmdlookup(const char *, int);
3642 static void delete_cmd_entry(void);
3646 * Exec a program. Never returns. If you change this routine, you may
3647 * have to change the find_command routine as well.
3651 shellexec(char **argv, const char *path, int idx)
3658 envp = environment();
3659 if (strchr(argv[0], '/') != NULL
3660 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3661 || find_applet_by_name(argv[0])
3664 tryexec(argv[0], argv, envp);
3668 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3669 if (--idx < 0 && pathopt == NULL) {
3670 tryexec(cmdname, argv, envp);
3671 if (errno != ENOENT && errno != ENOTDIR)
3678 /* Map to POSIX errors */
3690 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
3691 argv[0], e, suppressint ));
3692 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3698 tryexec(char *cmd, char **argv, char **envp)
3701 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3705 #ifdef CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN
3706 name = bb_get_last_path_component(name);
3707 if(find_applet_by_name(name) != NULL)
3710 if(strchr(name, '/') == NULL && find_applet_by_name(name) != NULL) {
3719 if(strcmp(name, "busybox")) {
3720 for (ap = argv; *ap; ap++);
3721 ap = new = xmalloc((ap - argv + 2) * sizeof(char *));
3722 *ap++ = cmd = "/bin/busybox";
3723 while ((*ap++ = *argv++));
3727 cmd = "/bin/busybox";
3735 execve(cmd, argv, envp);
3736 } while (errno == EINTR);
3738 execve(cmd, argv, envp);
3742 } else if (errno == ENOEXEC) {
3746 for (ap = argv; *ap; ap++)
3748 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
3749 *ap++ = cmd = "/bin/sh";
3750 while ((*ap++ = *argv++))
3760 * Do a path search. The variable path (passed by reference) should be
3761 * set to the start of the path before the first call; padvance will update
3762 * this value as it proceeds. Successive calls to padvance will return
3763 * the possible path expansions in sequence. If an option (indicated by
3764 * a percent sign) appears in the path entry then the global variable
3765 * pathopt will be set to point to it; otherwise pathopt will be set to
3770 padvance(const char **path, const char *name)
3780 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
3781 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
3782 while (stackblocksize() < len)
3786 memcpy(q, start, p - start);
3794 while (*p && *p != ':') p++;
3800 return stalloc(len);
3805 /*** Command hashing code ***/
3809 hashcmd(int argc, char **argv)
3811 struct tblentry **pp;
3812 struct tblentry *cmdp;
3814 struct cmdentry entry;
3817 while ((c = nextopt("r")) != '\0') {
3821 if (*argptr == NULL) {
3822 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3823 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3824 if (cmdp->cmdtype == CMDNORMAL)
3831 while ((name = *argptr) != NULL) {
3832 if ((cmdp = cmdlookup(name, 0)) != NULL
3833 && (cmdp->cmdtype == CMDNORMAL
3834 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
3836 find_command(name, &entry, DO_ERR, pathval());
3837 if (entry.cmdtype == CMDUNKNOWN)
3846 printentry(struct tblentry *cmdp)
3852 idx = cmdp->param.index;
3855 name = padvance(&path, cmdp->cmdname);
3857 } while (--idx >= 0);
3859 out1fmt(snlfmt, cmdp->rehash ? "*" : nullstr);
3865 * Resolve a command name. If you change this routine, you may have to
3866 * change the shellexec routine as well.
3870 find_command(char *name, struct cmdentry *entry, int act, const char *path)
3872 struct tblentry *cmdp;
3879 struct builtincmd *bcmd;
3881 /* If name contains a slash, don't use PATH or hash table */
3882 if (strchr(name, '/') != NULL) {
3883 entry->u.index = -1;
3885 while (stat(name, &statb) < 0) {
3890 entry->cmdtype = CMDUNKNOWN;
3894 entry->cmdtype = CMDNORMAL;
3898 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3899 if (find_applet_by_name(name)) {
3900 entry->cmdtype = CMDNORMAL;
3901 entry->u.index = -1;
3906 updatetbl = (path == pathval());
3909 if (strstr(path, "%builtin") != NULL)
3913 /* If name is in the table, check answer will be ok */
3914 if ((cmdp = cmdlookup(name, 0)) != NULL) {
3917 switch (cmdp->cmdtype) {
3935 } else if (cmdp->rehash == 0)
3936 /* if not invalidated by cd, we're done */
3940 /* If %builtin not in path, check for builtin next */
3941 bcmd = find_builtin(name);
3942 if (bcmd && (IS_BUILTIN_REGULAR(bcmd) || (
3943 act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0
3945 goto builtin_success;
3947 /* We have to search path. */
3948 prev = -1; /* where to start */
3949 if (cmdp && cmdp->rehash) { /* doing a rehash */
3950 if (cmdp->cmdtype == CMDBUILTIN)
3953 prev = cmdp->param.index;
3959 while ((fullname = padvance(&path, name)) != NULL) {
3960 stunalloc(fullname);
3963 if (prefix(pathopt, "builtin")) {
3965 goto builtin_success;
3967 } else if (!(act & DO_NOFUNC) &&
3968 prefix(pathopt, "func")) {
3971 /* ignore unimplemented options */
3975 /* if rehash, don't redo absolute path names */
3976 if (fullname[0] == '/' && idx <= prev) {
3979 TRACE(("searchexec \"%s\": no change\n", name));
3982 while (stat(fullname, &statb) < 0) {
3987 if (errno != ENOENT && errno != ENOTDIR)
3991 e = EACCES; /* if we fail, this will be the error */
3992 if (!S_ISREG(statb.st_mode))
3994 if (pathopt) { /* this is a %func directory */
3995 stalloc(strlen(fullname) + 1);
3996 readcmdfile(fullname);
3997 if ((cmdp = cmdlookup(name, 0)) == NULL ||
3998 cmdp->cmdtype != CMDFUNCTION)
3999 error("%s not defined in %s", name, fullname);
4000 stunalloc(fullname);
4003 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
4005 entry->cmdtype = CMDNORMAL;
4006 entry->u.index = idx;
4010 cmdp = cmdlookup(name, 1);
4011 cmdp->cmdtype = CMDNORMAL;
4012 cmdp->param.index = idx;
4017 /* We failed. If there was an entry for this command, delete it */
4018 if (cmdp && updatetbl)
4021 sh_warnx("%s: %s", name, errmsg(e, E_EXEC));
4022 entry->cmdtype = CMDUNKNOWN;
4027 entry->cmdtype = CMDBUILTIN;
4028 entry->u.cmd = bcmd;
4032 cmdp = cmdlookup(name, 1);
4033 cmdp->cmdtype = CMDBUILTIN;
4034 cmdp->param.cmd = bcmd;
4038 entry->cmdtype = cmdp->cmdtype;
4039 entry->u = cmdp->param;
4044 * Wrapper around strcmp for qsort/bsearch/...
4046 static int pstrcmp(const void *a, const void *b)
4048 return strcmp((const char *) a, (*(const char *const *) b) + 1);
4052 * Search the table of builtin commands.
4055 static struct builtincmd *
4056 find_builtin(const char *name)
4058 struct builtincmd *bp;
4061 name, builtincmd, NUMBUILTINS, sizeof(struct builtincmd),
4070 * Called when a cd is done. Marks all commands so the next time they
4071 * are executed they will be rehashed.
4077 struct tblentry **pp;
4078 struct tblentry *cmdp;
4080 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4081 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4082 if (cmdp->cmdtype == CMDNORMAL || (
4083 cmdp->cmdtype == CMDBUILTIN &&
4084 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) &&
4095 * Fix command hash table when PATH changed.
4096 * Called before PATH is changed. The argument is the new value of PATH;
4097 * pathval() still returns the old value at this point.
4098 * Called with interrupts off.
4102 changepath(const char *newval)
4104 const char *old, *new;
4111 firstchange = 9999; /* assume no change */
4117 if ((*old == '\0' && *new == ':')
4118 || (*old == ':' && *new == '\0'))
4120 old = new; /* ignore subsequent differences */
4124 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
4131 if (builtinloc < 0 && idx_bltin >= 0)
4132 builtinloc = idx_bltin; /* zap builtins */
4133 if (builtinloc >= 0 && idx_bltin < 0)
4135 clearcmdentry(firstchange);
4136 builtinloc = idx_bltin;
4141 * Clear out command entries. The argument specifies the first entry in
4142 * PATH which has changed.
4146 clearcmdentry(int firstchange)
4148 struct tblentry **tblp;
4149 struct tblentry **pp;
4150 struct tblentry *cmdp;
4153 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4155 while ((cmdp = *pp) != NULL) {
4156 if ((cmdp->cmdtype == CMDNORMAL &&
4157 cmdp->param.index >= firstchange)
4158 || (cmdp->cmdtype == CMDBUILTIN &&
4159 builtinloc >= firstchange)) {
4173 * Locate a command in the command hash table. If "add" is nonzero,
4174 * add the command to the table if it is not already present. The
4175 * variable "lastcmdentry" is set to point to the address of the link
4176 * pointing to the entry, so that delete_cmd_entry can delete the
4179 * Interrupts must be off if called with add != 0.
4182 static struct tblentry **lastcmdentry;
4185 static struct tblentry *
4186 cmdlookup(const char *name, int add)
4188 unsigned int hashval;
4190 struct tblentry *cmdp;
4191 struct tblentry **pp;
4194 hashval = (unsigned char)*p << 4;
4196 hashval += (unsigned char)*p++;
4198 pp = &cmdtable[hashval % CMDTABLESIZE];
4199 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4200 if (equal(cmdp->cmdname, name))
4204 if (add && cmdp == NULL) {
4205 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4206 + strlen(name) + 1);
4208 cmdp->cmdtype = CMDUNKNOWN;
4209 strcpy(cmdp->cmdname, name);
4216 * Delete the command entry returned on the last lookup.
4220 delete_cmd_entry(void)
4222 struct tblentry *cmdp;
4225 cmdp = *lastcmdentry;
4226 *lastcmdentry = cmdp->next;
4227 if (cmdp->cmdtype == CMDFUNCTION)
4228 freefunc(cmdp->param.func);
4235 * Add a new command entry, replacing any existing command entry for
4236 * the same name - except special builtins.
4240 addcmdentry(char *name, struct cmdentry *entry)
4242 struct tblentry *cmdp;
4244 cmdp = cmdlookup(name, 1);
4245 if (cmdp->cmdtype == CMDFUNCTION) {
4246 freefunc(cmdp->param.func);
4248 cmdp->cmdtype = entry->cmdtype;
4249 cmdp->param = entry->u;
4254 * Make a copy of a parse tree.
4257 static inline struct funcnode *
4258 copyfunc(union node *n)
4263 funcblocksize = offsetof(struct funcnode, n);
4266 blocksize = funcblocksize;
4267 f = ckmalloc(blocksize + funcstringsize);
4268 funcblock = (char *) f + offsetof(struct funcnode, n);
4269 funcstring = (char *) f + blocksize;
4276 * Define a shell function.
4280 defun(char *name, union node *func)
4282 struct cmdentry entry;
4285 entry.cmdtype = CMDFUNCTION;
4286 entry.u.func = copyfunc(func);
4287 addcmdentry(name, &entry);
4293 * Delete a function if it exists.
4297 unsetfunc(const char *name)
4299 struct tblentry *cmdp;
4301 if ((cmdp = cmdlookup(name, 0)) != NULL &&
4302 cmdp->cmdtype == CMDFUNCTION)
4307 * Locate and print what a word is...
4311 #ifdef CONFIG_ASH_CMDCMD
4313 describe_command(char *command, int describe_command_verbose)
4315 #define describe_command_verbose 1
4317 describe_command(char *command)
4320 struct cmdentry entry;
4321 struct tblentry *cmdp;
4322 #ifdef CONFIG_ASH_ALIAS
4323 const struct alias *ap;
4325 const char *path = pathval();
4327 if (describe_command_verbose) {
4331 /* First look at the keywords */
4332 if (findkwd(command)) {
4333 out1str(describe_command_verbose ? " is a shell keyword" : command);
4337 #ifdef CONFIG_ASH_ALIAS
4338 /* Then look at the aliases */
4339 if ((ap = lookupalias(command, 0)) != NULL) {
4340 if (describe_command_verbose) {
4341 out1fmt(" is an alias for %s", ap->val);
4350 /* Then check if it is a tracked alias */
4351 if ((cmdp = cmdlookup(command, 0)) != NULL) {
4352 entry.cmdtype = cmdp->cmdtype;
4353 entry.u = cmdp->param;
4355 /* Finally use brute force */
4356 find_command(command, &entry, DO_ABS, path);
4359 switch (entry.cmdtype) {
4361 int j = entry.u.index;
4367 p = padvance(&path, command);
4371 if (describe_command_verbose) {
4373 (cmdp ? " a tracked alias for" : nullstr), p
4382 if (describe_command_verbose) {
4383 out1str(" is a shell function");
4390 if (describe_command_verbose) {
4391 out1fmt(" is a %sshell builtin",
4392 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
4393 "special " : nullstr
4401 if (describe_command_verbose) {
4402 out1str(": not found\n");
4413 typecmd(int argc, char **argv)
4418 for (i = 1; i < argc; i++) {
4419 #ifdef CONFIG_ASH_CMDCMD
4420 err |= describe_command(argv[i], 1);
4422 err |= describe_command(argv[i]);
4428 #ifdef CONFIG_ASH_CMDCMD
4430 commandcmd(int argc, char **argv)
4433 int default_path = 0;
4434 int verify_only = 0;
4435 int verbose_verify_only = 0;
4437 while ((c = nextopt("pvV")) != '\0')
4442 "command: nextopt returned character code 0%o\n", c);
4452 verbose_verify_only = 1;
4456 if (default_path + verify_only + verbose_verify_only > 1 ||
4459 "command [-p] command [arg ...]\n"
4460 "command {-v|-V} command\n");
4464 if (verify_only || verbose_verify_only) {
4465 return describe_command(*argptr, verbose_verify_only);
4472 /* $NetBSD: expand.c,v 1.56 2002/11/24 22:35:39 christos Exp $ */
4475 * Routines to expand arguments to commands. We have to deal with
4476 * backquotes, shell variables, and file metacharacters.
4482 #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4483 #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
4484 #define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
4485 #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
4486 #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
4489 * Structure specifying which parts of the string should be searched
4490 * for IFS characters.
4494 struct ifsregion *next; /* next region in list */
4495 int begoff; /* offset of start of region */
4496 int endoff; /* offset of end of region */
4497 int nulonly; /* search for nul bytes only */
4500 /* output of current string */
4501 static char *expdest;
4502 /* list of back quote expressions */
4503 static struct nodelist *argbackq;
4504 /* first struct in list of ifs regions */
4505 static struct ifsregion ifsfirst;
4506 /* last struct in list */
4507 static struct ifsregion *ifslastp;
4508 /* holds expanded arg list */
4509 static struct arglist exparg;
4511 static void argstr(char *, int);
4512 static char *exptilde(char *, char *, int);
4513 static void expbackq(union node *, int, int);
4514 static const char *subevalvar(char *, char *, int, int, int, int, int);
4515 static char *evalvar(char *, int);
4516 static int varisset(char *, int);
4517 static void strtodest(const char *, int, int);
4518 static void memtodest(const char *p, size_t len, int syntax, int quotes);
4519 static void varvalue(char *, int, int);
4520 static void recordregion(int, int, int);
4521 static void removerecordregions(int);
4522 static void ifsbreakup(char *, struct arglist *);
4523 static void ifsfree(void);
4524 static void expandmeta(struct strlist *, int);
4525 static void addglob(const glob_t *);
4526 static void addfname(char *);
4527 static int patmatch(char *, const char *);
4529 static int cvtnum(long);
4530 static size_t esclen(const char *, const char *);
4531 static char *scanleft(char *, char *, char *, char *, int, int);
4532 static char *scanright(char *, char *, char *, char *, int, int);
4533 static void varunset(const char *, const char *, const char *, int)
4534 __attribute__((__noreturn__));
4537 #define pmatch(a, b) !fnmatch((a), (b), 0)
4539 * Prepare a pattern for a glob(3) call.
4541 * Returns an stalloced string.
4544 static inline char *
4545 preglob(const char *pattern, int quoted, int flag) {
4546 flag |= RMESCAPE_GLOB;
4548 flag |= RMESCAPE_QUOTED;
4550 return _rmescapes((char *)pattern, flag);
4555 esclen(const char *start, const char *p) {
4558 while (p > start && *--p == CTLESC) {
4566 * Expand shell variables and backquotes inside a here document.
4570 expandhere(union node *arg, int fd)
4573 expandarg(arg, (struct arglist *)NULL, 0);
4574 xwrite(fd, stackblock(), expdest - (char *)stackblock());
4579 * Perform variable substitution and command substitution on an argument,
4580 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4581 * perform splitting and file name expansion. When arglist is NULL, perform
4582 * here document expansion.
4586 expandarg(union node *arg, struct arglist *arglist, int flag)
4591 argbackq = arg->narg.backquote;
4592 STARTSTACKSTR(expdest);
4593 ifsfirst.next = NULL;
4595 argstr(arg->narg.text, flag);
4596 if (arglist == NULL) {
4597 return; /* here document expanded */
4599 STPUTC('\0', expdest);
4600 p = grabstackstr(expdest);
4601 exparg.lastp = &exparg.list;
4605 if (flag & EXP_FULL) {
4606 ifsbreakup(p, &exparg);
4607 *exparg.lastp = NULL;
4608 exparg.lastp = &exparg.list;
4609 expandmeta(exparg.list, flag);
4611 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
4613 sp = (struct strlist *)stalloc(sizeof (struct strlist));
4616 exparg.lastp = &sp->next;
4620 *exparg.lastp = NULL;
4622 *arglist->lastp = exparg.list;
4623 arglist->lastp = exparg.lastp;
4630 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4631 * characters to allow for further processing. Otherwise treat
4632 * $@ like $* since no splitting will be performed.
4636 argstr(char *p, int flag)
4638 static const char spclchars[] = {
4646 CTLBACKQ | CTLQUOTE,
4647 #ifdef CONFIG_ASH_MATH_SUPPORT
4652 const char *reject = spclchars;
4654 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
4655 int breakall = flag & EXP_WORD;
4660 if (!(flag & EXP_VARTILDE)) {
4662 } else if (flag & EXP_VARTILDE2) {
4667 if (flag & EXP_TILDE) {
4673 if (*q == CTLESC && (flag & EXP_QWORD))
4676 p = exptilde(p, q, flag);
4679 startloc = expdest - (char *)stackblock();
4681 length += strcspn(p + length, reject);
4683 if (c && (!(c & 0x80)
4684 #ifdef CONFIG_ASH_MATH_SUPPORT
4688 /* c == '=' || c == ':' || c == CTLENDARI */
4693 expdest = stnputs(p, length, expdest);
4694 newloc = expdest - (char *)stackblock();
4695 if (breakall && !inquotes && newloc > startloc) {
4696 recordregion(startloc, newloc, 0);
4707 if (flag & EXP_VARTILDE2) {
4711 flag |= EXP_VARTILDE2;
4716 * sort of a hack - expand tildes in variable
4717 * assignments (after the first '=' and after ':'s).
4726 case CTLENDVAR: /* ??? */
4729 /* "$@" syntax adherence hack */
4732 !memcmp(p, dolatstr, DOLATSTRLEN) &&
4733 (p[4] == CTLQUOTEMARK || (
4734 p[4] == CTLENDVAR &&
4735 p[5] == CTLQUOTEMARK
4738 p = evalvar(p + 1, flag) + 1;
4741 inquotes = !inquotes;
4754 p = evalvar(p, flag);
4758 case CTLBACKQ|CTLQUOTE:
4759 expbackq(argbackq->n, c, quotes);
4760 argbackq = argbackq->next;
4762 #ifdef CONFIG_ASH_MATH_SUPPORT
4775 exptilde(char *startp, char *p, int flag)
4781 int quotes = flag & (EXP_FULL | EXP_CASE);
4786 while ((c = *++p) != '\0') {
4793 if (flag & EXP_VARTILDE)
4803 if (*name == '\0') {
4804 if ((home = lookupvar(homestr)) == NULL)
4807 if ((pw = getpwnam(name)) == NULL)
4814 startloc = expdest - (char *)stackblock();
4815 strtodest(home, SQSYNTAX, quotes);
4816 recordregion(startloc, expdest - (char *)stackblock(), 0);
4825 removerecordregions(int endoff)
4827 if (ifslastp == NULL)
4830 if (ifsfirst.endoff > endoff) {
4831 while (ifsfirst.next != NULL) {
4832 struct ifsregion *ifsp;
4834 ifsp = ifsfirst.next->next;
4835 ckfree(ifsfirst.next);
4836 ifsfirst.next = ifsp;
4839 if (ifsfirst.begoff > endoff)
4842 ifslastp = &ifsfirst;
4843 ifsfirst.endoff = endoff;
4848 ifslastp = &ifsfirst;
4849 while (ifslastp->next && ifslastp->next->begoff < endoff)
4850 ifslastp=ifslastp->next;
4851 while (ifslastp->next != NULL) {
4852 struct ifsregion *ifsp;
4854 ifsp = ifslastp->next->next;
4855 ckfree(ifslastp->next);
4856 ifslastp->next = ifsp;
4859 if (ifslastp->endoff > endoff)
4860 ifslastp->endoff = endoff;
4864 #ifdef CONFIG_ASH_MATH_SUPPORT
4866 * Expand arithmetic expression. Backup to start of expression,
4867 * evaluate, place result in (backed up) result, adjust string position.
4880 * This routine is slightly over-complicated for
4881 * efficiency. Next we scan backwards looking for the
4882 * start of arithmetic.
4884 start = stackblock();
4891 while (*p != CTLARI) {
4895 error("missing CTLARI (shouldn't happen)");
4900 esc = esclen(start, p);
4910 removerecordregions(begoff);
4919 len = cvtnum(dash_arith(p + 2));
4922 recordregion(begoff, begoff + len, 0);
4927 * Expand stuff in backwards quotes.
4931 expbackq(union node *cmd, int quoted, int quotes)
4939 int syntax = quoted? DQSYNTAX : BASESYNTAX;
4940 struct stackmark smark;
4943 setstackmark(&smark);
4945 startloc = dest - (char *)stackblock();
4947 evalbackcmd(cmd, (struct backcmd *) &in);
4948 popstackmark(&smark);
4955 memtodest(p, i, syntax, quotes);
4959 i = safe_read(in.fd, buf, sizeof buf);
4960 TRACE(("expbackq: read returns %d\n", i));
4970 back_exitstatus = waitforjob(in.jp);
4974 /* Eat all trailing newlines */
4976 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
4981 recordregion(startloc, dest - (char *)stackblock(), 0);
4982 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4983 (dest - (char *)stackblock()) - startloc,
4984 (dest - (char *)stackblock()) - startloc,
4985 stackblock() + startloc));
4991 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)
5023 char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5030 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5033 const char *s = loc2;
5038 match = pmatch(str, s);
5045 esc = esclen(startp, loc);
5057 subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
5061 int saveherefd = herefd;
5062 struct nodelist *saveargbackq = argbackq;
5064 char *rmesc, *rmescend;
5066 char *(*scan)(char *, char *, char *, char *, int , int);
5069 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
5070 STPUTC('\0', expdest);
5071 herefd = saveherefd;
5072 argbackq = saveargbackq;
5073 startp = stackblock() + startloc;
5077 setvar(str, startp, 0);
5078 amount = startp - expdest;
5079 STADJUST(amount, expdest);
5083 varunset(p, str, startp, varflags);
5087 subtype -= VSTRIMRIGHT;
5089 if (subtype < 0 || subtype > 3)
5094 rmescend = stackblock() + strloc;
5096 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5097 if (rmesc != startp) {
5099 startp = stackblock() + startloc;
5103 str = stackblock() + strloc;
5104 preglob(str, varflags & VSQUOTE, 0);
5106 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
5107 zero = subtype >> 1;
5108 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
5109 scan = (subtype & 1) ^ zero ? scanleft : scanright;
5111 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
5114 memmove(startp, loc, str - loc);
5115 loc = startp + (str - loc) - 1;
5118 amount = loc - expdest;
5119 STADJUST(amount, expdest);
5126 * Expand a variable, and return a pointer to the next character in the
5130 evalvar(char *p, int flag)
5144 quotes = flag & (EXP_FULL | EXP_CASE);
5146 subtype = varflags & VSTYPE;
5147 quoted = varflags & VSQUOTE;
5149 easy = (!quoted || (*var == '@' && shellparam.nparam));
5151 startloc = expdest - (char *)stackblock();
5152 p = strchr(p, '=') + 1;
5154 if (!is_name(*var)) {
5155 set = varisset(var, varflags & VSNUL);
5157 if (subtype == VSPLUS)
5160 varvalue(var, quoted, flag);
5161 if (subtype == VSLENGTH) {
5163 expdest - (char *)stackblock() -
5165 STADJUST(-varlen, expdest);
5172 /* jump here after setting a variable with ${var=text} */
5173 val = lookupvar(var);
5174 set = !val || ((varflags & VSNUL) && !*val);
5175 if (subtype == VSPLUS)
5178 varlen = strlen(val);
5179 if (subtype == VSLENGTH)
5182 val, varlen, quoted ? DQSYNTAX : BASESYNTAX,
5189 if (subtype == VSMINUS) {
5193 p, flag | EXP_TILDE |
5194 (quoted ? EXP_QWORD : EXP_WORD)
5203 if (subtype == VSASSIGN || subtype == VSQUESTION) {
5205 if (subevalvar(p, var, 0, subtype, startloc,
5209 * Remove any recorded regions beyond
5212 removerecordregions(startloc);
5223 varunset(p, var, 0, 0);
5225 if (subtype == VSLENGTH) {
5231 if (subtype == VSNORMAL) {
5235 recordregion(startloc, expdest - (char *)stackblock(), quoted);
5244 case VSTRIMRIGHTMAX:
5253 * Terminate the string and start recording the pattern
5256 STPUTC('\0', expdest);
5257 patloc = expdest - (char *)stackblock();
5258 if (subevalvar(p, NULL, patloc, subtype,
5259 startloc, varflags, quotes) == 0) {
5260 int amount = expdest - (
5261 (char *)stackblock() + patloc - 1
5263 STADJUST(-amount, expdest);
5265 /* Remove any recorded regions beyond start of variable */
5266 removerecordregions(startloc);
5271 if (subtype != VSNORMAL) { /* skip to end of alternative */
5274 if ((c = *p++) == CTLESC)
5276 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
5278 argbackq = argbackq->next;
5279 } else if (c == CTLVAR) {
5280 if ((*p++ & VSTYPE) != VSNORMAL)
5282 } else if (c == CTLENDVAR) {
5294 * Test whether a specialized variable is set.
5298 varisset(char *name, int nulok)
5301 return backgndpid != 0;
5302 else if (*name == '@' || *name == '*') {
5303 if (*shellparam.p == NULL)
5309 for (av = shellparam.p; *av; av++)
5314 } else if (is_digit(*name)) {
5316 int num = atoi(name);
5318 if (num > shellparam.nparam)
5324 ap = shellparam.p[num - 1];
5326 if (nulok && (ap == NULL || *ap == '\0'))
5335 * Put a string on the stack.
5339 memtodest(const char *p, size_t len, int syntax, int quotes) {
5342 q = makestrspace(len * 2, q);
5348 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5358 strtodest(const char *p, int syntax, int quotes)
5360 memtodest(p, strlen(p), syntax, quotes);
5366 * Add the value of a specialized variable to the stack string.
5370 varvalue(char *name, int quoted, int flags)
5379 int allow_split = flags & EXP_FULL;
5380 int quotes = flags & (EXP_FULL | EXP_CASE);
5382 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5391 num = shellparam.nparam;
5399 for (i = 0 ; i < NOPTS ; i++) {
5401 STPUTC(optletters(i), expdest);
5405 if (allow_split && quoted) {
5406 sep = 1 << CHAR_BIT;
5411 sep = ifsset() ? ifsval()[0] : ' ';
5413 sepq = (SIT(sep, syntax) == CCTL) || (SIT(sep, syntax) == CBACK);
5416 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
5417 strtodest(p, syntax, quotes);
5428 strtodest(arg0, syntax, quotes);
5432 if (num > 0 && num <= shellparam.nparam) {
5433 strtodest(shellparam.p[num - 1], syntax, quotes);
5442 * Record the fact that we have to scan this region of the
5443 * string for IFS characters.
5447 recordregion(int start, int end, int nulonly)
5449 struct ifsregion *ifsp;
5451 if (ifslastp == NULL) {
5455 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
5457 ifslastp->next = ifsp;
5461 ifslastp->begoff = start;
5462 ifslastp->endoff = end;
5463 ifslastp->nulonly = nulonly;
5469 * Break the argument string into pieces based upon IFS and add the
5470 * strings to the argument list. The regions of the string to be
5471 * searched for IFS characters have been stored by recordregion.
5474 ifsbreakup(char *string, struct arglist *arglist)
5476 struct ifsregion *ifsp;
5481 const char *ifs, *realifs;
5487 if (ifslastp != NULL) {
5490 realifs = ifsset() ? ifsval() : defifs;
5493 p = string + ifsp->begoff;
5494 nulonly = ifsp->nulonly;
5495 ifs = nulonly ? nullstr : realifs;
5497 while (p < string + ifsp->endoff) {
5501 if (strchr(ifs, *p)) {
5503 ifsspc = (strchr(defifs, *p) != NULL);
5504 /* Ignore IFS whitespace at start */
5505 if (q == start && ifsspc) {
5511 sp = (struct strlist *)stalloc(sizeof *sp);
5513 *arglist->lastp = sp;
5514 arglist->lastp = &sp->next;
5518 if (p >= string + ifsp->endoff) {
5524 if (strchr(ifs, *p) == NULL ) {
5527 } else if (strchr(defifs, *p) == NULL) {
5543 } while ((ifsp = ifsp->next) != NULL);
5552 sp = (struct strlist *)stalloc(sizeof *sp);
5554 *arglist->lastp = sp;
5555 arglist->lastp = &sp->next;
5561 struct ifsregion *p;
5566 struct ifsregion *ifsp;
5572 ifsfirst.next = NULL;
5579 * Expand shell metacharacters. At this point, the only control characters
5580 * should be escapes. The results are stored in the list exparg.
5584 expandmeta(str, flag)
5585 struct strlist *str;
5588 /* TODO - EXP_REDIR */
5598 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
5599 i = glob(p, GLOB_NOMAGIC, 0, &pglob);
5604 if (!(pglob.gl_flags & GLOB_MAGCHAR))
5615 *exparg.lastp = str;
5616 rmescapes(str->text);
5617 exparg.lastp = &str->next;
5619 default: /* GLOB_NOSPACE */
5620 error(bb_msg_memory_exhausted);
5628 * Add the result of glob(3) to the list.
5633 const glob_t *pglob;
5635 char **p = pglob->gl_pathv;
5644 * Add a file name to the list.
5648 addfname(char *name)
5652 sp = (struct strlist *)stalloc(sizeof *sp);
5653 sp->text = sstrdup(name);
5655 exparg.lastp = &sp->next;
5660 * Returns true if the pattern matches the string.
5664 patmatch(char *pattern, const char *string)
5666 return pmatch(preglob(pattern, 0, 0), string);
5671 * Remove any CTLESC characters from a string.
5675 _rmescapes(char *str, int flag)
5678 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
5683 p = strpbrk(str, qchars);
5689 if (flag & RMESCAPE_ALLOC) {
5690 size_t len = p - str;
5691 size_t fulllen = len + strlen(p) + 1;
5693 if (flag & RMESCAPE_GROW) {
5694 r = makestrspace(fulllen, expdest);
5695 } else if (flag & RMESCAPE_HEAP) {
5696 r = ckmalloc(fulllen);
5698 r = stalloc(fulllen);
5702 q = mempcpy(q, str, len);
5705 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5706 globbing = flag & RMESCAPE_GLOB;
5707 notescaped = globbing;
5709 if (*p == CTLQUOTEMARK) {
5710 inquotes = ~inquotes;
5712 notescaped = globbing;
5716 /* naked back slash */
5722 if (notescaped && inquotes && *p != '/') {
5726 notescaped = globbing;
5731 if (flag & RMESCAPE_GROW) {
5733 STADJUST(q - r + 1, expdest);
5741 * See if a pattern matches in a case statement.
5745 casematch(union node *pattern, char *val)
5747 struct stackmark smark;
5750 setstackmark(&smark);
5751 argbackq = pattern->narg.backquote;
5752 STARTSTACKSTR(expdest);
5754 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
5755 STACKSTRNUL(expdest);
5756 result = patmatch(stackblock(), val);
5757 popstackmark(&smark);
5770 expdest = makestrspace(32, expdest);
5771 len = fmtstr(expdest, 32, "%ld", num);
5772 STADJUST(len, expdest);
5777 varunset(const char *end, const char *var, const char *umsg, int varflags)
5783 msg = "parameter not set";
5785 if (*end == CTLENDVAR) {
5786 if (varflags & VSNUL)
5791 error("%.*s: %s%s", end - var - 1, var, msg, tail);
5793 /* $NetBSD: input.c,v 1.37 2002/11/24 22:35:40 christos Exp $ */
5798 * This file implements the input routines used by the parser.
5801 #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
5802 #define IBUFSIZ (BUFSIZ + 1)
5804 static void pushfile(void);
5807 * Read a line from the script.
5810 static inline char *
5811 pfgets(char *line, int len)
5817 while (--nleft > 0) {
5834 * Read a character from the script, returning PEOF on end of file.
5835 * Nul characters in the input are silently discarded.
5838 #define pgetc_as_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
5840 #ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
5841 #define pgetc_macro() pgetc()
5845 return pgetc_as_macro();
5848 #define pgetc_macro() pgetc_as_macro()
5852 return pgetc_macro();
5858 * Same as pgetc(), but ignores PEOA.
5860 #ifdef CONFIG_ASH_ALIAS
5861 static int pgetc2(void)
5867 } while (c == PEOA);
5871 static inline int pgetc2(void)
5873 return pgetc_macro();
5878 #ifdef CONFIG_FEATURE_COMMAND_EDITING
5879 static const char *cmdedit_prompt;
5880 static inline void putprompt(const char *s)
5885 static inline void putprompt(const char *s)
5895 char *buf = parsefile->buf;
5899 #ifdef CONFIG_FEATURE_COMMAND_EDITING
5900 if (!iflag || parsefile->fd)
5901 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
5903 nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
5905 /* Ctrl+C presend */
5910 /* Ctrl+D presend */
5915 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
5919 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
5920 int flags = fcntl(0, F_GETFL, 0);
5921 if (flags >= 0 && flags & O_NONBLOCK) {
5922 flags &=~ O_NONBLOCK;
5923 if (fcntl(0, F_SETFL, flags) >= 0) {
5924 out2str("sh: turning off NDELAY mode\n");
5934 * Refill the input buffer and return the next input character:
5936 * 1) If a string was pushed back on the input, pop it;
5937 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
5938 * from a string so we can't refill the buffer, return EOF.
5939 * 3) If the is more stuff in this buffer, use it else call read to fill it.
5940 * 4) Process input up to the next newline, deleting nul characters.
5950 while (parsefile->strpush) {
5951 #ifdef CONFIG_ASH_ALIAS
5952 if (parsenleft == -1 && parsefile->strpush->ap &&
5953 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
5958 if (--parsenleft >= 0)
5959 return (*parsenextc++);
5961 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
5966 if (parselleft <= 0) {
5967 if ((parselleft = preadfd()) <= 0) {
5968 parselleft = parsenleft = EOF_NLEFT;
5975 /* delete nul characters */
5976 for (more = 1; more;) {
5983 parsenleft = q - parsenextc;
5984 more = 0; /* Stop processing here */
5991 if (--parselleft <= 0 && more) {
5992 parsenleft = q - parsenextc - 1;
6003 out2str(parsenextc);
6009 return *parsenextc++;
6013 * Undo the last call to pgetc. Only one character may be pushed back.
6014 * PEOF may be pushed back.
6025 * Push a string back onto the input at this current parsefile level.
6026 * We handle aliases this way.
6029 pushstring(char *s, void *ap)
6036 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6037 if (parsefile->strpush) {
6038 sp = ckmalloc(sizeof (struct strpush));
6039 sp->prev = parsefile->strpush;
6040 parsefile->strpush = sp;
6042 sp = parsefile->strpush = &(parsefile->basestrpush);
6043 sp->prevstring = parsenextc;
6044 sp->prevnleft = parsenleft;
6045 #ifdef CONFIG_ASH_ALIAS
6046 sp->ap = (struct alias *)ap;
6048 ((struct alias *)ap)->flag |= ALIASINUSE;
6060 struct strpush *sp = parsefile->strpush;
6063 #ifdef CONFIG_ASH_ALIAS
6065 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6066 checkkwd |= CHKALIAS;
6068 if (sp->string != sp->ap->val) {
6071 sp->ap->flag &= ~ALIASINUSE;
6072 if (sp->ap->flag & ALIASDEAD) {
6073 unalias(sp->ap->name);
6077 parsenextc = sp->prevstring;
6078 parsenleft = sp->prevnleft;
6079 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6080 parsefile->strpush = sp->prev;
6081 if (sp != &(parsefile->basestrpush))
6087 * Set the input to take input from a file. If push is set, push the
6088 * old input onto the stack first.
6092 setinputfile(const char *fname, int push)
6098 if ((fd = open(fname, O_RDONLY)) < 0)
6099 error("Can't open %s", fname);
6101 fd2 = copyfd(fd, 10);
6104 error("Out of file descriptors");
6107 setinputfd(fd, push);
6113 * Like setinputfile, but takes an open file descriptor. Call this with
6118 setinputfd(int fd, int push)
6120 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
6126 if (parsefile->buf == NULL)
6127 parsefile->buf = ckmalloc(IBUFSIZ);
6128 parselleft = parsenleft = 0;
6134 * Like setinputfile, but takes input from a string.
6138 setinputstring(char *string)
6142 parsenextc = string;
6143 parsenleft = strlen(string);
6144 parsefile->buf = NULL;
6152 * To handle the "." command, a stack of input files is used. Pushfile
6153 * adds a new entry to the stack and popfile restores the previous level.
6159 struct parsefile *pf;
6161 parsefile->nleft = parsenleft;
6162 parsefile->lleft = parselleft;
6163 parsefile->nextc = parsenextc;
6164 parsefile->linno = plinno;
6165 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
6166 pf->prev = parsefile;
6169 pf->basestrpush.prev = NULL;
6177 struct parsefile *pf = parsefile;
6186 parsefile = pf->prev;
6188 parsenleft = parsefile->nleft;
6189 parselleft = parsefile->lleft;
6190 parsenextc = parsefile->nextc;
6191 plinno = parsefile->linno;
6197 * Return to top level.
6203 while (parsefile != &basepf)
6210 * Close the file(s) that the shell is reading commands from. Called
6211 * after a fork is done.
6218 if (parsefile->fd > 0) {
6219 close(parsefile->fd);
6223 /* $NetBSD: jobs.c,v 1.56 2002/11/25 12:13:03 agc Exp $ */
6226 /* mode flags for set_curjob */
6227 #define CUR_DELETE 2
6228 #define CUR_RUNNING 1
6229 #define CUR_STOPPED 0
6231 /* mode flags for dowait */
6232 #define DOWAIT_NORMAL 0
6233 #define DOWAIT_BLOCK 1
6236 static struct job *jobtab;
6238 static unsigned njobs;
6240 /* pgrp of shell on invocation */
6241 static int initialpgrp;
6242 static int ttyfd = -1;
6245 static struct job *curjob;
6246 /* number of presumed living untracked jobs */
6249 static void set_curjob(struct job *, unsigned);
6251 static int restartjob(struct job *, int);
6252 static void xtcsetpgrp(int, pid_t);
6253 static char *commandtext(union node *);
6254 static void cmdlist(union node *, int);
6255 static void cmdtxt(union node *);
6256 static void cmdputs(const char *);
6257 static void showpipe(struct job *, FILE *);
6259 static int sprint_status(char *, int, int);
6260 static void freejob(struct job *);
6261 static struct job *getjob(const char *, int);
6262 static struct job *growjobtab(void);
6263 static void forkchild(struct job *, union node *, int);
6264 static void forkparent(struct job *, union node *, int, pid_t);
6265 static int dowait(int, struct job *);
6266 static int getstatus(struct job *);
6269 set_curjob(struct job *jp, unsigned mode)
6272 struct job **jpp, **curp;
6274 /* first remove from list */
6275 jpp = curp = &curjob;
6280 jpp = &jp1->prev_job;
6282 *jpp = jp1->prev_job;
6284 /* Then re-insert in correct position */
6292 /* job being deleted */
6295 /* newly created job or backgrounded job,
6296 put after all stopped jobs. */
6300 if (!jp1 || jp1->state != JOBSTOPPED)
6303 jpp = &jp1->prev_job;
6309 /* newly stopped job - becomes curjob */
6310 jp->prev_job = *jpp;
6318 * Turn job control on and off.
6320 * Note: This code assumes that the third arg to ioctl is a character
6321 * pointer, which is true on Berkeley systems but not System V. Since
6322 * System V doesn't have job control yet, this isn't a problem now.
6324 * Called with interrupts off.
6333 if (on == jobctl || rootshell == 0)
6337 ofd = fd = open(_PATH_TTY, O_RDWR);
6340 while (!isatty(fd) && --fd >= 0)
6343 fd = fcntl(fd, F_DUPFD, 10);
6347 fcntl(fd, F_SETFD, FD_CLOEXEC);
6348 do { /* while we are in the background */
6349 if ((pgrp = tcgetpgrp(fd)) < 0) {
6351 sh_warnx("can't access tty; job control turned off");
6355 if (pgrp == getpgrp())
6366 xtcsetpgrp(fd, pgrp);
6368 /* turning job control off */
6371 xtcsetpgrp(fd, pgrp);
6398 "Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6399 "kill -l [exitstatus]"
6403 if (**++argv == '-') {
6404 signo = decode_signal(*argv + 1, 1);
6408 while ((c = nextopt("ls:")) != '\0')
6418 signo = decode_signal(optionarg, 1);
6421 "invalid signal number or name: %s",
6432 if (!list && signo < 0)
6435 if ((signo < 0 || !*argv) ^ list) {
6443 for (i = 1; i < NSIG; i++) {
6444 name = u_signal_names(0, &i, 1);
6446 out1fmt(snlfmt, name);
6450 name = u_signal_names(*argptr, &signo, -1);
6452 out1fmt(snlfmt, name);
6454 error("invalid signal number or exit status: %s", *argptr);
6460 if (**argv == '%') {
6461 jp = getjob(*argv, 0);
6462 pid = -jp->ps[0].pid;
6464 pid = number(*argv);
6465 if (kill(pid, signo) != 0) {
6475 #if defined(JOBS) || defined(DEBUG)
6477 jobno(const struct job *jp)
6479 return jp - jobtab + 1;
6485 fgcmd(int argc, char **argv)
6492 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
6497 jp = getjob(*argv, 1);
6498 if (mode == FORK_BG) {
6499 set_curjob(jp, CUR_RUNNING);
6500 fprintf(out, "[%d] ", jobno(jp));
6502 outstr(jp->ps->cmd, out);
6504 retval = restartjob(jp, mode);
6505 } while (*argv && *++argv);
6509 static int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
6513 restartjob(struct job *jp, int mode)
6515 struct procstat *ps;
6521 if (jp->state == JOBDONE)
6523 jp->state = JOBRUNNING;
6525 if (mode == FORK_FG)
6526 xtcsetpgrp(ttyfd, pgid);
6527 killpg(pgid, SIGCONT);
6531 if (WIFSTOPPED(ps->status)) {
6534 } while (ps++, --i);
6536 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
6543 sprint_status(char *s, int status, int sigonly)
6549 st = WEXITSTATUS(status);
6550 if (!WIFEXITED(status)) {
6551 st = WSTOPSIG(status);
6553 if (!WIFSTOPPED(status))
6554 st = WTERMSIG(status);
6557 if (st == SIGINT || st == SIGPIPE)
6559 if (WIFSTOPPED(status))
6563 col = fmtstr(s, 32, u_signal_names(NULL, &st, 0));
6564 if (WCOREDUMP(status)) {
6565 col += fmtstr(s + col, 16, " (core dumped)");
6567 } else if (!sigonly) {
6569 col = fmtstr(s, 16, "Done(%d)", st);
6571 col = fmtstr(s, 16, "Done");
6580 showjob(FILE *out, struct job *jp, int mode)
6582 struct procstat *ps;
6583 struct procstat *psend;
6590 if (mode & SHOW_PGID) {
6591 /* just output process (group) id of pipeline */
6592 fprintf(out, "%d\n", ps->pid);
6596 col = fmtstr(s, 16, "[%d] ", jobno(jp));
6601 else if (curjob && jp == curjob->prev_job)
6604 if (mode & SHOW_PID)
6605 col += fmtstr(s + col, 16, "%d ", ps->pid);
6607 psend = ps + jp->nprocs;
6609 if (jp->state == JOBRUNNING) {
6610 scopy("Running", s + col);
6611 col += strlen("Running");
6613 int status = psend[-1].status;
6615 if (jp->state == JOBSTOPPED)
6616 status = jp->stopstatus;
6618 col += sprint_status(s + col, status, 0);
6624 /* for each process */
6625 col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
6630 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
6632 if (!(mode & SHOW_PID)) {
6636 if (++ps == psend) {
6637 outcslow('\n', out);
6644 if (jp->state == JOBDONE) {
6645 TRACE(("showjob: freeing job %d\n", jobno(jp)));
6652 jobscmd(int argc, char **argv)
6658 while ((m = nextopt("lp")))
6668 showjob(out, getjob(*argv,0), mode);
6671 showjobs(out, mode);
6678 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6679 * statuses have changed since the last call to showjobs.
6683 showjobs(FILE *out, int mode)
6687 TRACE(("showjobs(%x) called\n", mode));
6689 /* If not even one one job changed, there is nothing to do */
6690 while (dowait(DOWAIT_NORMAL, NULL) > 0)
6693 for (jp = curjob; jp; jp = jp->prev_job) {
6694 if (!(mode & SHOW_CHANGED) || jp->changed)
6695 showjob(out, jp, mode);
6701 * Mark a job structure as unused.
6705 freejob(struct job *jp)
6707 struct procstat *ps;
6711 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
6712 if (ps->cmd != nullstr)
6715 if (jp->ps != &jp->ps0)
6718 set_curjob(jp, CUR_DELETE);
6724 waitcmd(int argc, char **argv)
6737 /* wait for all jobs */
6742 /* no running procs */
6745 if (jp->state == JOBRUNNING)
6750 dowait(DOWAIT_BLOCK, 0);
6756 if (**argv != '%') {
6757 pid_t pid = number(*argv);
6761 if (job->ps[job->nprocs - 1].pid == pid)
6763 job = job->prev_job;
6769 job = getjob(*argv, 0);
6770 /* loop until process terminated or stopped */
6771 while (job->state == JOBRUNNING)
6772 dowait(DOWAIT_BLOCK, 0);
6774 retval = getstatus(job);
6786 * Convert a job name to a job structure.
6790 getjob(const char *name, int getctl)
6794 const char *err_msg = "No such job: %s";
6798 char *(*match)(const char *, const char *);
6813 if (c == '+' || c == '%') {
6815 err_msg = "No current job";
6817 } else if (c == '-') {
6820 err_msg = "No previous job";
6831 jp = jobtab + num - 1;
6848 if (match(jp->ps[0].cmd, p)) {
6852 err_msg = "%s: ambiguous";
6859 err_msg = "job %s not created under job control";
6860 if (getctl && jp->jobctl == 0)
6865 error(err_msg, name);
6871 * Return a new job structure.
6872 * Called with interrupts off.
6876 makejob(union node *node, int nprocs)
6881 for (i = njobs, jp = jobtab ; ; jp++) {
6888 if (jp->state != JOBDONE || !jp->waited)
6897 memset(jp, 0, sizeof(*jp));
6902 jp->prev_job = curjob;
6907 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
6909 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
6919 struct job *jp, *jq;
6921 len = njobs * sizeof(*jp);
6923 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
6925 offset = (char *)jp - (char *)jq;
6927 /* Relocate pointers */
6930 jq = (struct job *)((char *)jq + l);
6934 #define joff(p) ((struct job *)((char *)(p) + l))
6935 #define jmove(p) (p) = (void *)((char *)(p) + offset)
6936 if (likely(joff(jp)->ps == &jq->ps0))
6937 jmove(joff(jp)->ps);
6938 if (joff(jp)->prev_job)
6939 jmove(joff(jp)->prev_job);
6949 jp = (struct job *)((char *)jp + len);
6953 } while (--jq >= jp);
6959 * Fork off a subshell. If we are doing job control, give the subshell its
6960 * own process group. Jp is a job structure that the job is to be added to.
6961 * N is the command that will be evaluated by the child. Both jp and n may
6962 * be NULL. The mode parameter can be one of the following:
6963 * FORK_FG - Fork off a foreground process.
6964 * FORK_BG - Fork off a background process.
6965 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
6966 * process group even if job control is on.
6968 * When job control is turned off, background processes have their standard
6969 * input redirected to /dev/null (except for the second and later processes
6972 * Called with interrupts off.
6976 forkchild(struct job *jp, union node *n, int mode)
6980 TRACE(("Child shell %d\n", getpid()));
6981 wasroot = rootshell;
6987 /* do job control only in root shell */
6989 if (mode != FORK_NOJOB && jp->jobctl && wasroot) {
6992 if (jp->nprocs == 0)
6995 pgrp = jp->ps[0].pid;
6996 /* This can fail because we are doing it in the parent also */
6997 (void)setpgid(0, pgrp);
6998 if (mode == FORK_FG)
6999 xtcsetpgrp(ttyfd, pgrp);
7004 if (mode == FORK_BG) {
7007 if (jp->nprocs == 0) {
7009 if (open(_PATH_DEVNULL, O_RDONLY) != 0)
7010 error("Can't open %s", _PATH_DEVNULL);
7013 if (wasroot && iflag) {
7018 for (jp = curjob; jp; jp = jp->prev_job)
7024 forkparent(struct job *jp, union node *n, int mode, pid_t pid)
7026 TRACE(("In parent shell: child = %d\n", pid));
7028 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
7033 if (mode != FORK_NOJOB && jp->jobctl) {
7036 if (jp->nprocs == 0)
7039 pgrp = jp->ps[0].pid;
7040 /* This can fail because we are doing it in the child also */
7041 (void)setpgid(pid, pgrp);
7044 if (mode == FORK_BG) {
7045 backgndpid = pid; /* set $! */
7046 set_curjob(jp, CUR_RUNNING);
7049 struct procstat *ps = &jp->ps[jp->nprocs++];
7055 ps->cmd = commandtext(n);
7061 forkshell(struct job *jp, union node *n, int mode)
7065 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
7068 TRACE(("Fork failed, errno=%d", errno));
7071 error("Cannot fork");
7074 forkchild(jp, n, mode);
7076 forkparent(jp, n, mode, pid);
7081 * Wait for job to finish.
7083 * Under job control we have the problem that while a child process is
7084 * running interrupts generated by the user are sent to the child but not
7085 * to the shell. This means that an infinite loop started by an inter-
7086 * active user may be hard to kill. With job control turned off, an
7087 * interactive user may place an interactive program inside a loop. If
7088 * the interactive program catches interrupts, the user doesn't want
7089 * these interrupts to also abort the loop. The approach we take here
7090 * is to have the shell ignore interrupt signals while waiting for a
7091 * forground process to terminate, and then send itself an interrupt
7092 * signal if the child process was terminated by an interrupt signal.
7093 * Unfortunately, some programs want to do a bit of cleanup and then
7094 * exit on interrupt; unless these processes terminate themselves by
7095 * sending a signal to themselves (instead of calling exit) they will
7096 * confuse this approach.
7098 * Called with interrupts off.
7102 waitforjob(struct job *jp)
7106 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
7107 while (jp->state == JOBRUNNING) {
7108 dowait(DOWAIT_BLOCK, jp);
7113 xtcsetpgrp(ttyfd, rootpid);
7115 * This is truly gross.
7116 * If we're doing job control, then we did a TIOCSPGRP which
7117 * caused us (the shell) to no longer be in the controlling
7118 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7119 * intuit from the subprocess exit status whether a SIGINT
7120 * occurred, and if so interrupt ourselves. Yuck. - mycroft
7125 if (jp->state == JOBDONE)
7133 * Do a wait system call. If job control is compiled in, we accept
7134 * stopped processes. If block is zero, we return a value of zero
7135 * rather than blocking.
7137 * System V doesn't have a non-blocking wait system call. It does
7138 * have a SIGCLD signal that is sent to a process when one of it's
7139 * children dies. The obvious way to use SIGCLD would be to install
7140 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7141 * was received, and have waitproc bump another counter when it got
7142 * the status of a process. Waitproc would then know that a wait
7143 * system call would not block if the two counters were different.
7144 * This approach doesn't work because if a process has children that
7145 * have not been waited for, System V will send it a SIGCLD when it
7146 * installs a signal handler for SIGCLD. What this means is that when
7147 * a child exits, the shell will be sent SIGCLD signals continuously
7148 * until is runs out of stack space, unless it does a wait call before
7149 * restoring the signal handler. The code below takes advantage of
7150 * this (mis)feature by installing a signal handler for SIGCLD and
7151 * then checking to see whether it was called. If there are any
7152 * children to be waited for, it will be.
7154 * If neither SYSV nor BSD is defined, we don't implement nonblocking
7155 * waits at all. In this case, the user will not be informed when
7156 * a background process until the next time she runs a real program
7157 * (as opposed to running a builtin command or just typing return),
7158 * and the jobs command may give out of date information.
7162 waitproc(int block, int *status)
7172 return wait3(status, flags, (struct rusage *)NULL);
7176 * Wait for a process to terminate.
7180 dowait(int block, struct job *job)
7185 struct job *thisjob;
7188 TRACE(("dowait(%d) called\n", block));
7189 pid = waitproc(block, &status);
7190 TRACE(("wait returns pid %d, status=%d\n", pid, status));
7195 for (jp = curjob; jp; jp = jp->prev_job) {
7196 struct procstat *sp;
7197 struct procstat *spend;
7198 if (jp->state == JOBDONE)
7201 spend = jp->ps + jp->nprocs;
7204 if (sp->pid == pid) {
7205 TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
7206 sp->status = status;
7209 if (sp->status == -1)
7212 if (state == JOBRUNNING)
7214 if (WIFSTOPPED(sp->status)) {
7215 jp->stopstatus = sp->status;
7219 } while (++sp < spend);
7224 if (!WIFSTOPPED(status))
7231 if (state != JOBRUNNING) {
7232 thisjob->changed = 1;
7234 if (thisjob->state != state) {
7235 TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
7236 thisjob->state = state;
7238 if (state == JOBSTOPPED) {
7239 set_curjob(thisjob, CUR_STOPPED);
7248 if (thisjob && thisjob == job) {
7252 len = sprint_status(s, status, 1);
7265 * return 1 if there are stopped jobs, otherwise 0
7277 if (jp && jp->state == JOBSTOPPED) {
7278 out2str("You have stopped jobs.\n");
7288 * Return a string identifying a command (to be printed by the
7293 static char *cmdnextc;
7296 commandtext(union node *n)
7300 STARTSTACKSTR(cmdnextc);
7302 name = stackblock();
7303 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
7304 name, cmdnextc, cmdnextc));
7305 return savestr(name);
7309 cmdtxt(union node *n)
7312 struct nodelist *lp;
7322 lp = n->npipe.cmdlist;
7340 cmdtxt(n->nbinary.ch1);
7356 cmdtxt(n->nif.test);
7359 if (n->nif.elsepart) {
7362 n = n->nif.elsepart;
7378 cmdtxt(n->nbinary.ch1);
7388 cmdputs(n->nfor.var);
7390 cmdlist(n->nfor.args, 1);
7395 cmdputs(n->narg.text);
7399 cmdlist(n->ncmd.args, 1);
7400 cmdlist(n->ncmd.redirect, 0);
7413 cmdputs(n->ncase.expr->narg.text);
7415 for (np = n->ncase.cases; np; np = np->nclist.next) {
7416 cmdtxt(np->nclist.pattern);
7418 cmdtxt(np->nclist.body);
7444 s[0] = n->nfile.fd + '0';
7448 if (n->type == NTOFD || n->type == NFROMFD) {
7449 s[0] = n->ndup.dupfd + '0';
7460 cmdlist(union node *np, int sep)
7462 for (; np; np = np->narg.next) {
7466 if (sep && np->narg.next)
7473 cmdputs(const char *s)
7475 const char *p, *str;
7476 char c, cc[2] = " ";
7480 static const char *const vstype[16] = {
7481 nullstr, "}", "-", "+", "?", "=",
7482 "#", "##", "%", "%%"
7485 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
7487 while ((c = *p++) != 0) {
7495 if ((subtype & VSTYPE) == VSLENGTH)
7499 if (!(subtype & VSQUOTE) != !(quoted & 1)) {
7517 case CTLBACKQ+CTLQUOTE:
7520 #ifdef CONFIG_ASH_MATH_SUPPORT
7535 str = vstype[subtype & VSTYPE];
7536 if (subtype & VSNUL)
7547 /* These can only happen inside quotes */
7559 while ((c = *str++)) {
7564 USTPUTC('"', nextc);
7572 showpipe(struct job *jp, FILE *out)
7574 struct procstat *sp;
7575 struct procstat *spend;
7577 spend = jp->ps + jp->nprocs;
7578 for (sp = jp->ps + 1; sp < spend; sp++)
7579 fprintf(out, " | %s", sp->cmd);
7580 outcslow('\n', out);
7585 xtcsetpgrp(int fd, pid_t pgrp)
7587 if (tcsetpgrp(fd, pgrp))
7588 error("Cannot set tty process group (%m)");
7593 getstatus(struct job *job) {
7597 status = job->ps[job->nprocs - 1].status;
7598 retval = WEXITSTATUS(status);
7599 if (!WIFEXITED(status)) {
7601 retval = WSTOPSIG(status);
7602 if (!WIFSTOPPED(status))
7605 /* XXX: limits number of signals */
7606 retval = WTERMSIG(status);
7608 if (retval == SIGINT)
7614 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
7615 jobno(job), job->nprocs, status, retval));
7619 #ifdef CONFIG_ASH_MAIL
7620 /* $NetBSD: mail.c,v 1.15 2002/11/24 22:35:40 christos Exp $ */
7623 * Routines to check for mail. (Perhaps make part of main.c?)
7626 #define MAXMBOXES 10
7628 /* times of mailboxes */
7629 static time_t mailtime[MAXMBOXES];
7630 /* Set if MAIL or MAILPATH is changed. */
7631 static int mail_var_path_changed;
7636 * Print appropriate message(s) if mail has arrived.
7637 * If mail_var_path_changed is set,
7638 * then the value of MAIL has mail_var_path_changed,
7639 * so we just update the values.
7649 struct stackmark smark;
7652 setstackmark(&smark);
7653 mpath = mpathset() ? mpathval() : mailval();
7654 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
7655 p = padvance(&mpath, nullstr);
7660 for (q = p ; *q ; q++);
7665 q[-1] = '\0'; /* delete trailing '/' */
7666 if (stat(p, &statb) < 0) {
7670 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
7673 pathopt ? pathopt : "you have mail"
7676 *mtp = statb.st_mtime;
7678 mail_var_path_changed = 0;
7679 popstackmark(&smark);
7684 changemail(const char *val)
7686 mail_var_path_changed++;
7689 #endif /* CONFIG_ASH_MAIL */
7691 /* $NetBSD: main.c,v 1.46 2002/12/11 19:12:18 christos Exp $ */
7695 static short profile_buf[16384];
7699 static int isloginsh;
7701 static void read_profile(const char *);
7704 * Main routine. We initialize things, parse the arguments, execute
7705 * profiles if we're a login shell, and then call cmdloop to execute
7706 * commands. The setjmp call sets up the location to jump to when an
7707 * exception occurs. When an exception occurs the variable "state"
7708 * is used to figure out how far we had gotten.
7712 ash_main(int argc, char **argv)
7716 struct jmploc jmploc;
7717 struct stackmark smark;
7720 dash_errno = __errno_location();
7724 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7727 if (setjmp(jmploc.loc)) {
7734 switch (exception) {
7744 status = exitstatus;
7747 exitstatus = status;
7749 if (e == EXEXIT || state == 0 || iflag == 0 || ! rootshell)
7753 outcslow('\n', stderr);
7755 popstackmark(&smark);
7756 FORCEINTON; /* enable interrupts */
7759 else if (state == 2)
7761 else if (state == 3)
7769 trputs("Shell args: "); trargs(argv);
7774 setstackmark(&smark);
7775 procargs(argc, argv);
7776 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7778 const char *hp = lookupvar("HISTFILE");
7781 hp = lookupvar("HOME");
7783 char *defhp = concat_path_file(hp, ".ash_history");
7784 setvar("HISTFILE", defhp, 0);
7790 if (argv[0] && argv[0][0] == '-')
7794 read_profile("/etc/profile");
7797 read_profile(".profile");
7803 getuid() == geteuid() && getgid() == getegid() &&
7807 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
7808 read_profile(shinit);
7814 evalstring(minusc, 0);
7816 if (sflag || minusc == NULL) {
7817 state4: /* XXX ??? - why isn't this before the "if" statement */
7818 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7820 const char *hp = lookupvar("HISTFILE");
7823 load_history ( hp );
7833 extern void _mcleanup(void);
7843 * Read and execute commands. "Top" is nonzero for the top level command
7844 * loop; it turns on prompting if the shell is interactive.
7851 struct stackmark smark;
7855 TRACE(("cmdloop(%d) called\n", top));
7856 setstackmark(&smark);
7862 showjobs(stderr, SHOW_CHANGED);
7867 #ifdef CONFIG_ASH_MAIL
7871 n = parsecmd(inter);
7872 /* showtree(n); DEBUG */
7874 if (!top || numeof >= 50)
7876 if (!stoppedjobs()) {
7879 out2str("\nUse \"exit\" to leave shell.\n");
7882 } else if (n != NULL && nflag == 0) {
7883 job_warning = (job_warning == 2) ? 1 : 0;
7887 popstackmark(&smark);
7888 setstackmark(&smark);
7889 if (evalskip == SKIPFILE) {
7894 popstackmark(&smark);
7900 * Read /etc/profile or .profile. Return on error.
7904 read_profile(const char *name)
7911 if ((fd = open(name, O_RDONLY)) >= 0)
7916 /* -q turns off -x and -v just when executing init files */
7919 xflag = 0, xflag_set = 1;
7921 vflag = 0, vflag_set = 1;
7936 * Read a file containing shell functions.
7940 readcmdfile(char *name)
7945 if ((fd = open(name, O_RDONLY)) >= 0)
7948 error("Can't open %s", name);
7956 * Take commands from a file. To be compatible we should do a path
7957 * search for the file, which is necessary to find sub-commands.
7960 static inline char *
7961 find_dot_file(char *name)
7964 const char *path = pathval();
7967 /* don't try this for absolute or relative paths */
7968 if (strchr(name, '/'))
7971 while ((fullname = padvance(&path, name)) != NULL) {
7972 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
7974 * Don't bother freeing here, since it will
7975 * be freed by the caller.
7979 stunalloc(fullname);
7982 /* not found in the PATH */
7983 error(not_found_msg, name);
7988 dotcmd(int argc, char **argv)
7992 if (argc >= 2) { /* That's what SVR2 does */
7994 struct stackmark smark;
7996 setstackmark(&smark);
7997 fullname = find_dot_file(argv[1]);
7998 setinputfile(fullname, 1);
7999 commandname = fullname;
8002 popstackmark(&smark);
8009 exitcmd(int argc, char **argv)
8014 exitstatus = number(argv[1]);
8019 /* $NetBSD: memalloc.c,v 1.27 2003/01/22 20:36:04 dsl Exp $ */
8022 * Like malloc, but returns an error when out of space.
8026 ckmalloc(size_t nbytes)
8032 error(bb_msg_memory_exhausted);
8042 ckrealloc(pointer p, size_t nbytes)
8044 p = realloc(p, nbytes);
8046 error(bb_msg_memory_exhausted);
8052 * Make a copy of a string in safe storage.
8056 savestr(const char *s)
8058 char *p = strdup(s);
8060 error(bb_msg_memory_exhausted);
8066 * Parse trees for commands are allocated in lifo order, so we use a stack
8067 * to make this more efficient, and also to avoid all sorts of exception
8068 * handling code to handle interrupts in the middle of a parse.
8070 * The size 504 was chosen because the Ultrix malloc handles that size
8076 stalloc(size_t nbytes)
8081 aligned = SHELL_ALIGN(nbytes);
8082 if (aligned > stacknleft) {
8085 struct stack_block *sp;
8087 blocksize = aligned;
8088 if (blocksize < MINSIZE)
8089 blocksize = MINSIZE;
8090 len = sizeof(struct stack_block) - MINSIZE + blocksize;
8091 if (len < blocksize)
8092 error(bb_msg_memory_exhausted);
8096 stacknxt = sp->space;
8097 stacknleft = blocksize;
8098 sstrend = stacknxt + blocksize;
8103 stacknxt += aligned;
8104 stacknleft -= aligned;
8110 stunalloc(pointer p)
8113 if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
8114 write(2, "stunalloc\n", 10);
8118 stacknleft += stacknxt - (char *)p;
8125 setstackmark(struct stackmark *mark)
8127 mark->stackp = stackp;
8128 mark->stacknxt = stacknxt;
8129 mark->stacknleft = stacknleft;
8130 mark->marknext = markp;
8136 popstackmark(struct stackmark *mark)
8138 struct stack_block *sp;
8141 markp = mark->marknext;
8142 while (stackp != mark->stackp) {
8147 stacknxt = mark->stacknxt;
8148 stacknleft = mark->stacknleft;
8149 sstrend = mark->stacknxt + mark->stacknleft;
8155 * When the parser reads in a string, it wants to stick the string on the
8156 * stack and only adjust the stack pointer when it knows how big the
8157 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8158 * of space on top of the stack and stackblocklen returns the length of
8159 * this block. Growstackblock will grow this space by at least one byte,
8160 * possibly moving it (like realloc). Grabstackblock actually allocates the
8161 * part of the block that has been used.
8165 growstackblock(void)
8169 newlen = stacknleft * 2;
8170 if (newlen < stacknleft)
8171 error(bb_msg_memory_exhausted);
8175 if (stacknxt == stackp->space && stackp != &stackbase) {
8176 struct stack_block *oldstackp;
8177 struct stackmark *xmark;
8178 struct stack_block *sp;
8179 struct stack_block *prevstackp;
8185 prevstackp = sp->prev;
8186 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
8187 sp = ckrealloc((pointer)sp, grosslen);
8188 sp->prev = prevstackp;
8190 stacknxt = sp->space;
8191 stacknleft = newlen;
8192 sstrend = sp->space + newlen;
8195 * Stack marks pointing to the start of the old block
8196 * must be relocated to point to the new block
8199 while (xmark != NULL && xmark->stackp == oldstackp) {
8200 xmark->stackp = stackp;
8201 xmark->stacknxt = stacknxt;
8202 xmark->stacknleft = stacknleft;
8203 xmark = xmark->marknext;
8207 char *oldspace = stacknxt;
8208 int oldlen = stacknleft;
8209 char *p = stalloc(newlen);
8211 /* free the space we just allocated */
8212 stacknxt = memcpy(p, oldspace, oldlen);
8213 stacknleft += newlen;
8218 grabstackblock(size_t len)
8220 len = SHELL_ALIGN(len);
8226 * The following routines are somewhat easier to use than the above.
8227 * The user declares a variable of type STACKSTR, which may be declared
8228 * to be a register. The macro STARTSTACKSTR initializes things. Then
8229 * the user uses the macro STPUTC to add characters to the string. In
8230 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8231 * grown as necessary. When the user is done, she can just leave the
8232 * string there and refer to it using stackblock(). Or she can allocate
8233 * the space for it using grabstackstr(). If it is necessary to allow
8234 * someone else to use the stack temporarily and then continue to grow
8235 * the string, the user should use grabstack to allocate the space, and
8236 * then call ungrabstr(p) to return to the previous mode of operation.
8238 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8239 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8240 * is space for at least one character.
8246 size_t len = stackblocksize();
8247 if (herefd >= 0 && len >= 1024) {
8248 xwrite(herefd, stackblock(), len);
8249 return stackblock();
8252 return stackblock() + len;
8256 * Called from CHECKSTRSPACE.
8260 makestrspace(size_t newlen, char *p)
8262 size_t len = p - stacknxt;
8263 size_t size = stackblocksize();
8268 size = stackblocksize();
8270 if (nleft >= newlen)
8274 return stackblock() + len;
8278 stnputs(const char *s, size_t n, char *p)
8280 p = makestrspace(n, p);
8281 p = mempcpy(p, s, n);
8286 stputs(const char *s, char *p)
8288 return stnputs(s, strlen(s), p);
8291 /* $NetBSD: mystring.c,v 1.15 2002/11/24 22:35:42 christos Exp $ */
8296 * number(s) Convert a string of digits to an integer.
8297 * is_number(s) Return true if s is a string of digits.
8301 * prefix -- see if pfx is a prefix of string.
8305 prefix(const char *string, const char *pfx)
8308 if (*pfx++ != *string++)
8311 return (char *) string;
8316 * Convert a string of digits to an integer, printing an error message on
8321 number(const char *s)
8332 * Check for a valid number. This should be elsewhere.
8336 is_number(const char *p)
8341 } while (*++p != '\0');
8347 * Produce a possibly single quoted string suitable as input to the shell.
8348 * The return string is allocated on the stack.
8352 single_quote(const char *s) {
8361 len = strchrnul(s, '\'') - s;
8363 q = p = makestrspace(len + 3, p);
8366 q = mempcpy(q, s, len);
8372 len = strspn(s, "'");
8376 q = p = makestrspace(len + 3, p);
8379 q = mempcpy(q, s, len);
8388 return stackblock();
8392 * Like strdup but works with the ash stack.
8396 sstrdup(const char *p)
8398 size_t len = strlen(p) + 1;
8399 return memcpy(stalloc(len), p, len);
8404 calcsize(union node *n)
8408 funcblocksize += nodesize[n->type];
8411 calcsize(n->ncmd.redirect);
8412 calcsize(n->ncmd.args);
8413 calcsize(n->ncmd.assign);
8416 sizenodelist(n->npipe.cmdlist);
8421 calcsize(n->nredir.redirect);
8422 calcsize(n->nredir.n);
8429 calcsize(n->nbinary.ch2);
8430 calcsize(n->nbinary.ch1);
8433 calcsize(n->nif.elsepart);
8434 calcsize(n->nif.ifpart);
8435 calcsize(n->nif.test);
8438 funcstringsize += strlen(n->nfor.var) + 1;
8439 calcsize(n->nfor.body);
8440 calcsize(n->nfor.args);
8443 calcsize(n->ncase.cases);
8444 calcsize(n->ncase.expr);
8447 calcsize(n->nclist.body);
8448 calcsize(n->nclist.pattern);
8449 calcsize(n->nclist.next);
8453 sizenodelist(n->narg.backquote);
8454 funcstringsize += strlen(n->narg.text) + 1;
8455 calcsize(n->narg.next);
8462 calcsize(n->nfile.fname);
8463 calcsize(n->nfile.next);
8467 calcsize(n->ndup.vname);
8468 calcsize(n->ndup.next);
8472 calcsize(n->nhere.doc);
8473 calcsize(n->nhere.next);
8476 calcsize(n->nnot.com);
8484 sizenodelist(struct nodelist *lp)
8487 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8496 copynode(union node *n)
8503 funcblock = (char *) funcblock + nodesize[n->type];
8506 new->ncmd.redirect = copynode(n->ncmd.redirect);
8507 new->ncmd.args = copynode(n->ncmd.args);
8508 new->ncmd.assign = copynode(n->ncmd.assign);
8511 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8512 new->npipe.backgnd = n->npipe.backgnd;
8517 new->nredir.redirect = copynode(n->nredir.redirect);
8518 new->nredir.n = copynode(n->nredir.n);
8525 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8526 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8529 new->nif.elsepart = copynode(n->nif.elsepart);
8530 new->nif.ifpart = copynode(n->nif.ifpart);
8531 new->nif.test = copynode(n->nif.test);
8534 new->nfor.var = nodesavestr(n->nfor.var);
8535 new->nfor.body = copynode(n->nfor.body);
8536 new->nfor.args = copynode(n->nfor.args);
8539 new->ncase.cases = copynode(n->ncase.cases);
8540 new->ncase.expr = copynode(n->ncase.expr);
8543 new->nclist.body = copynode(n->nclist.body);
8544 new->nclist.pattern = copynode(n->nclist.pattern);
8545 new->nclist.next = copynode(n->nclist.next);
8549 new->narg.backquote = copynodelist(n->narg.backquote);
8550 new->narg.text = nodesavestr(n->narg.text);
8551 new->narg.next = copynode(n->narg.next);
8558 new->nfile.fname = copynode(n->nfile.fname);
8559 new->nfile.fd = n->nfile.fd;
8560 new->nfile.next = copynode(n->nfile.next);
8564 new->ndup.vname = copynode(n->ndup.vname);
8565 new->ndup.dupfd = n->ndup.dupfd;
8566 new->ndup.fd = n->ndup.fd;
8567 new->ndup.next = copynode(n->ndup.next);
8571 new->nhere.doc = copynode(n->nhere.doc);
8572 new->nhere.fd = n->nhere.fd;
8573 new->nhere.next = copynode(n->nhere.next);
8576 new->nnot.com = copynode(n->nnot.com);
8579 new->type = n->type;
8584 static struct nodelist *
8585 copynodelist(struct nodelist *lp)
8587 struct nodelist *start;
8588 struct nodelist **lpp;
8593 funcblock = (char *) funcblock +
8594 SHELL_ALIGN(sizeof(struct nodelist));
8595 (*lpp)->n = copynode(lp->n);
8597 lpp = &(*lpp)->next;
8606 nodesavestr(char *s)
8608 char *rtn = funcstring;
8610 funcstring = stpcpy(funcstring, s) + 1;
8617 * Free a parse tree.
8621 freefunc(struct funcnode *f)
8623 if (f && --f->count < 0)
8628 static void options(int);
8629 static void setoption(int, int);
8633 * Process the shell command line arguments.
8637 procargs(int argc, char **argv)
8640 const char *xminusc;
8647 for (i = 0; i < NOPTS; i++)
8653 if (*xargv == NULL) {
8655 error("-c requires an argument");
8658 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8662 for (i = 0; i < NOPTS; i++)
8663 if (optlist[i] == 2)
8668 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8673 } else if (!sflag) {
8674 setinputfile(*xargv, 0);
8680 shellparam.p = xargv;
8681 #ifdef CONFIG_ASH_GETOPTS
8682 shellparam.optind = 1;
8683 shellparam.optoff = -1;
8685 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
8687 shellparam.nparam++;
8700 setinteractive(iflag);
8705 minus_o(char *name, int val)
8710 out1str("Current option settings\n");
8711 for (i = 0; i < NOPTS; i++)
8712 out1fmt("%-16s%s\n", optnames(i),
8713 optlist[i] ? "on" : "off");
8715 for (i = 0; i < NOPTS; i++)
8716 if (equal(name, optnames(i))) {
8720 error("Illegal option -o %s", name);
8725 * Process shell options. The global variable argptr contains a pointer
8726 * to the argument list; we advance it past the options.
8730 options(int cmdline)
8738 while ((p = *argptr) != NULL) {
8740 if ((c = *p++) == '-') {
8742 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8744 /* "-" means turn off -x and -v */
8747 /* "--" means reset params */
8748 else if (*argptr == NULL)
8751 break; /* "-" or "--" terminates options */
8753 } else if (c == '+') {
8759 while ((c = *p++) != '\0') {
8760 if (c == 'c' && cmdline) {
8761 minusc = p; /* command is after shell args*/
8762 } else if (c == 'o') {
8763 minus_o(*argptr, val);
8766 } else if (cmdline && (c == '-')) { // long options
8767 if (strcmp(p, "login") == 0)
8780 setoption(int flag, int val)
8784 for (i = 0; i < NOPTS; i++)
8785 if (optletters(i) == flag) {
8789 error("Illegal option -%c", flag);
8796 * Set the shell parameters.
8800 setparam(char **argv)
8806 for (nparam = 0 ; argv[nparam] ; nparam++);
8807 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
8809 *ap++ = savestr(*argv++);
8812 freeparam(&shellparam);
8813 shellparam.malloc = 1;
8814 shellparam.nparam = nparam;
8815 shellparam.p = newparam;
8816 #ifdef CONFIG_ASH_GETOPTS
8817 shellparam.optind = 1;
8818 shellparam.optoff = -1;
8824 * Free the list of positional parameters.
8828 freeparam(volatile struct shparam *param)
8832 if (param->malloc) {
8833 for (ap = param->p ; *ap ; ap++)
8842 * The shift builtin command.
8846 shiftcmd(int argc, char **argv)
8853 n = number(argv[1]);
8854 if (n > shellparam.nparam)
8855 error("can't shift that many");
8857 shellparam.nparam -= n;
8858 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
8859 if (shellparam.malloc)
8863 while ((*ap2++ = *ap1++) != NULL);
8864 #ifdef CONFIG_ASH_GETOPTS
8865 shellparam.optind = 1;
8866 shellparam.optoff = -1;
8875 * The set command builtin.
8879 setcmd(int argc, char **argv)
8882 return showvars(nullstr, 0, VUNSET);
8886 if (*argptr != NULL) {
8894 #ifdef CONFIG_ASH_GETOPTS
8899 shellparam.optind = number(value);
8900 shellparam.optoff = -1;
8904 #ifdef CONFIG_LOCALE_SUPPORT
8905 static void change_lc_all(const char *value)
8907 if (value != 0 && *value != 0)
8908 setlocale(LC_ALL, value);
8911 static void change_lc_ctype(const char *value)
8913 if (value != 0 && *value != 0)
8914 setlocale(LC_CTYPE, value);
8919 #ifdef CONFIG_ASH_GETOPTS
8921 getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
8928 char **optnext = optfirst + *param_optind - 1;
8930 if (*param_optind <= 1 || *optoff < 0 || !(*(optnext - 1)) ||
8931 strlen(*(optnext - 1)) < *optoff)
8934 p = *(optnext - 1) + *optoff;
8935 if (p == NULL || *p == '\0') {
8936 /* Current word is done, advance */
8937 if (optnext == NULL)
8940 if (p == NULL || *p != '-' || *++p == '\0') {
8947 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
8952 for (q = optstr; *q != c; ) {
8954 if (optstr[0] == ':') {
8957 err |= setvarsafe("OPTARG", s, 0);
8959 fprintf(stderr, "Illegal option -%c\n", c);
8960 (void) unsetvar("OPTARG");
8970 if (*p == '\0' && (p = *optnext) == NULL) {
8971 if (optstr[0] == ':') {
8974 err |= setvarsafe("OPTARG", s, 0);
8977 fprintf(stderr, "No arg for -%c option\n", c);
8978 (void) unsetvar("OPTARG");
8986 err |= setvarsafe("OPTARG", p, 0);
8989 err |= setvarsafe("OPTARG", nullstr, 0);
8992 *optoff = p ? p - *(optnext - 1) : -1;
8993 *param_optind = optnext - optfirst + 1;
8994 fmtstr(s, sizeof(s), "%d", *param_optind);
8995 err |= setvarsafe("OPTIND", s, VNOFUNC);
8998 err |= setvarsafe(optvar, s, 0);
9009 * The getopts builtin. Shellparam.optnext points to the next argument
9010 * to be processed. Shellparam.optptr points to the next character to
9011 * be processed in the current argument. If shellparam.optnext is NULL,
9012 * then it's the first time getopts has been called.
9016 getoptscmd(int argc, char **argv)
9021 error("Usage: getopts optstring var [arg]");
9022 else if (argc == 3) {
9023 optbase = shellparam.p;
9024 if (shellparam.optind > shellparam.nparam + 1) {
9025 shellparam.optind = 1;
9026 shellparam.optoff = -1;
9031 if (shellparam.optind > argc - 2) {
9032 shellparam.optind = 1;
9033 shellparam.optoff = -1;
9037 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9038 &shellparam.optoff);
9040 #endif /* CONFIG_ASH_GETOPTS */
9043 * XXX - should get rid of. have all builtins use getopt(3). the
9044 * library getopt must have the BSD extension static variable "optreset"
9045 * otherwise it can't be used within the shell safely.
9047 * Standard option processing (a la getopt) for builtin routines. The
9048 * only argument that is passed to nextopt is the option string; the
9049 * other arguments are unnecessary. It return the character, or '\0' on
9054 nextopt(const char *optstring)
9060 if ((p = optptr) == NULL || *p == '\0') {
9062 if (p == NULL || *p != '-' || *++p == '\0')
9065 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
9069 for (q = optstring ; *q != c ; ) {
9071 error("Illegal option -%c", c);
9076 if (*p == '\0' && (p = *argptr++) == NULL)
9077 error("No arg for -%c option", c);
9085 /* $NetBSD: output.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
9090 outstr(const char *p, FILE *file)
9108 flushout(FILE *dest)
9116 outcslow(int c, FILE *dest)
9126 out1fmt(const char *fmt, ...)
9133 r = vprintf(fmt, ap);
9141 fmtstr(char *outbuf, size_t length, const char *fmt, ...)
9148 ret = vsnprintf(outbuf, length, fmt, ap);
9156 * Version of write which resumes after a signal is caught.
9160 xwrite(int fd, const void *p, size_t n)
9165 i = bb_full_write(fd, p, n);
9166 } while (i < 0 && errno == EINTR);
9170 /* $NetBSD: parser.c,v 1.54 2002/11/24 22:35:42 christos Exp $ */
9174 * Shell command parser.
9177 #define EOFMARKLEN 79
9181 struct heredoc *next; /* next here document in list */
9182 union node *here; /* redirection node */
9183 char *eofmark; /* string indicating end of input */
9184 int striptabs; /* if set, strip leading tabs */
9189 static struct heredoc *heredoclist; /* list of here documents to read */
9192 static union node *list(int);
9193 static union node *andor(void);
9194 static union node *pipeline(void);
9195 static union node *command(void);
9196 static union node *simplecmd(void);
9197 static union node *makename(void);
9198 static void parsefname(void);
9199 static void parseheredoc(void);
9200 static char peektoken(void);
9201 static int readtoken(void);
9202 static int xxreadtoken(void);
9203 static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
9204 static int noexpand(char *);
9205 static void synexpect(int) __attribute__((__noreturn__));
9206 static void synerror(const char *) __attribute__((__noreturn__));
9207 static void setprompt(int);
9211 goodname(const char *p)
9213 return !*endofname(p);
9217 isassignment(const char *p)
9219 const char *q = endofname(p);
9227 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9228 * valid parse tree indicating a blank line.)
9232 parsecmd(int interact)
9237 doprompt = interact;
9239 setprompt(doprompt);
9254 union node *n1, *n2, *n3;
9257 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9258 if (nlflag == 2 && peektoken())
9264 if (tok == TBACKGND) {
9265 if (n2->type == NPIPE) {
9266 n2->npipe.backgnd = 1;
9268 if (n2->type != NREDIR) {
9269 n3 = stalloc(sizeof(struct nredir));
9271 n3->nredir.redirect = NULL;
9274 n2->type = NBACKGND;
9281 n3 = (union node *)stalloc(sizeof (struct nbinary));
9283 n3->nbinary.ch1 = n1;
9284 n3->nbinary.ch2 = n2;
9300 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9308 pungetc(); /* push back EOF on input */
9324 union node *n1, *n2, *n3;
9329 if ((t = readtoken()) == TAND) {
9331 } else if (t == TOR) {
9337 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9339 n3 = (union node *)stalloc(sizeof (struct nbinary));
9341 n3->nbinary.ch1 = n1;
9342 n3->nbinary.ch2 = n2;
9352 union node *n1, *n2, *pipenode;
9353 struct nodelist *lp, *prev;
9357 TRACE(("pipeline: entered\n"));
9358 if (readtoken() == TNOT) {
9360 checkkwd = CHKKWD | CHKALIAS;
9364 if (readtoken() == TPIPE) {
9365 pipenode = (union node *)stalloc(sizeof (struct npipe));
9366 pipenode->type = NPIPE;
9367 pipenode->npipe.backgnd = 0;
9368 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9369 pipenode->npipe.cmdlist = lp;
9373 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9374 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9377 } while (readtoken() == TPIPE);
9383 n2 = (union node *)stalloc(sizeof (struct nnot));
9396 union node *n1, *n2;
9397 union node *ap, **app;
9398 union node *cp, **cpp;
9399 union node *redir, **rpp;
9406 switch (readtoken()) {
9411 n1 = (union node *)stalloc(sizeof (struct nif));
9413 n1->nif.test = list(0);
9414 if (readtoken() != TTHEN)
9416 n1->nif.ifpart = list(0);
9418 while (readtoken() == TELIF) {
9419 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
9420 n2 = n2->nif.elsepart;
9422 n2->nif.test = list(0);
9423 if (readtoken() != TTHEN)
9425 n2->nif.ifpart = list(0);
9427 if (lasttoken == TELSE)
9428 n2->nif.elsepart = list(0);
9430 n2->nif.elsepart = NULL;
9438 n1 = (union node *)stalloc(sizeof (struct nbinary));
9439 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
9440 n1->nbinary.ch1 = list(0);
9441 if ((got=readtoken()) != TDO) {
9442 TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
9445 n1->nbinary.ch2 = list(0);
9450 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9451 synerror("Bad for loop variable");
9452 n1 = (union node *)stalloc(sizeof (struct nfor));
9454 n1->nfor.var = wordtext;
9455 checkkwd = CHKKWD | CHKALIAS;
9456 if (readtoken() == TIN) {
9458 while (readtoken() == TWORD) {
9459 n2 = (union node *)stalloc(sizeof (struct narg));
9461 n2->narg.text = wordtext;
9462 n2->narg.backquote = backquotelist;
9464 app = &n2->narg.next;
9468 if (lasttoken != TNL && lasttoken != TSEMI)
9471 n2 = (union node *)stalloc(sizeof (struct narg));
9473 n2->narg.text = (char *)dolatstr;
9474 n2->narg.backquote = NULL;
9475 n2->narg.next = NULL;
9478 * Newline or semicolon here is optional (but note
9479 * that the original Bourne shell only allowed NL).
9481 if (lasttoken != TNL && lasttoken != TSEMI)
9484 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9485 if (readtoken() != TDO)
9487 n1->nfor.body = list(0);
9491 n1 = (union node *)stalloc(sizeof (struct ncase));
9493 if (readtoken() != TWORD)
9495 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
9497 n2->narg.text = wordtext;
9498 n2->narg.backquote = backquotelist;
9499 n2->narg.next = NULL;
9501 checkkwd = CHKKWD | CHKALIAS;
9502 } while (readtoken() == TNL);
9503 if (lasttoken != TIN)
9505 cpp = &n1->ncase.cases;
9507 checkkwd = CHKNL | CHKKWD;
9510 if (lasttoken == TLP)
9512 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
9514 app = &cp->nclist.pattern;
9516 *app = ap = (union node *)stalloc(sizeof (struct narg));
9518 ap->narg.text = wordtext;
9519 ap->narg.backquote = backquotelist;
9520 if (readtoken() != TPIPE)
9522 app = &ap->narg.next;
9525 ap->narg.next = NULL;
9526 if (lasttoken != TRP)
9528 cp->nclist.body = list(2);
9530 cpp = &cp->nclist.next;
9532 checkkwd = CHKNL | CHKKWD;
9533 if ((t = readtoken()) != TESAC) {
9535 synexpect(TENDCASE);
9543 n1 = (union node *)stalloc(sizeof (struct nredir));
9544 n1->type = NSUBSHELL;
9545 n1->nredir.n = list(0);
9546 n1->nredir.redirect = NULL;
9559 if (readtoken() != t)
9563 /* Now check for redirection which may follow command */
9564 checkkwd = CHKKWD | CHKALIAS;
9566 while (readtoken() == TREDIR) {
9567 *rpp = n2 = redirnode;
9568 rpp = &n2->nfile.next;
9574 if (n1->type != NSUBSHELL) {
9575 n2 = (union node *)stalloc(sizeof (struct nredir));
9580 n1->nredir.redirect = redir;
9589 union node *args, **app;
9590 union node *n = NULL;
9591 union node *vars, **vpp;
9592 union node **rpp, *redir;
9602 savecheckkwd = CHKALIAS;
9604 checkkwd = savecheckkwd;
9605 switch (readtoken()) {
9607 n = (union node *)stalloc(sizeof (struct narg));
9609 n->narg.text = wordtext;
9610 n->narg.backquote = backquotelist;
9611 if (savecheckkwd && isassignment(wordtext)) {
9613 vpp = &n->narg.next;
9616 app = &n->narg.next;
9621 *rpp = n = redirnode;
9622 rpp = &n->nfile.next;
9623 parsefname(); /* read name of redirection file */
9627 args && app == &args->narg.next &&
9630 struct builtincmd *bcmd;
9633 /* We have a function */
9634 if (readtoken() != TRP)
9636 name = n->narg.text;
9638 !goodname(name) || (
9639 (bcmd = find_builtin(name)) &&
9640 IS_BUILTIN_SPECIAL(bcmd)
9643 synerror("Bad function name");
9645 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9646 n->narg.next = command();
9659 n = (union node *)stalloc(sizeof (struct ncmd));
9661 n->ncmd.args = args;
9662 n->ncmd.assign = vars;
9663 n->ncmd.redirect = redir;
9672 n = (union node *)stalloc(sizeof (struct narg));
9674 n->narg.next = NULL;
9675 n->narg.text = wordtext;
9676 n->narg.backquote = backquotelist;
9680 void fixredir(union node *n, const char *text, int err)
9682 TRACE(("Fix redir %s %d\n", text, err));
9684 n->ndup.vname = NULL;
9686 if (is_digit(text[0]) && text[1] == '\0')
9687 n->ndup.dupfd = digit_val(text[0]);
9688 else if (text[0] == '-' && text[1] == '\0')
9693 synerror("Bad fd number");
9695 n->ndup.vname = makename();
9703 union node *n = redirnode;
9705 if (readtoken() != TWORD)
9707 if (n->type == NHERE) {
9708 struct heredoc *here = heredoc;
9714 TRACE(("Here document %d\n", n->type));
9715 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
9716 synerror("Illegal eof marker for << redirection");
9717 rmescapes(wordtext);
9718 here->eofmark = wordtext;
9720 if (heredoclist == NULL)
9723 for (p = heredoclist ; p->next ; p = p->next);
9726 } else if (n->type == NTOFD || n->type == NFROMFD) {
9727 fixredir(n, wordtext, 0);
9729 n->nfile.fname = makename();
9735 * Input any here documents.
9741 struct heredoc *here;
9752 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9753 here->eofmark, here->striptabs);
9754 n = (union node *)stalloc(sizeof (struct narg));
9755 n->narg.type = NARG;
9756 n->narg.next = NULL;
9757 n->narg.text = wordtext;
9758 n->narg.backquote = backquotelist;
9759 here->here->nhere.doc = n;
9764 static char peektoken(void)
9770 return tokname_array[t][0];
9778 int alreadyseen = tokpushback;
9781 #ifdef CONFIG_ASH_ALIAS
9790 if (checkkwd & CHKNL) {
9797 if (t != TWORD || quoteflag) {
9802 * check for keywords
9804 if (checkkwd & CHKKWD) {
9805 const char *const *pp;
9807 if ((pp = findkwd(wordtext))) {
9808 lasttoken = t = pp - tokname_array;
9809 TRACE(("keyword %s recognized\n", tokname(t)));
9814 if (checkkwd & CHKALIAS) {
9815 #ifdef CONFIG_ASH_ALIAS
9817 if ((ap = lookupalias(wordtext, 1)) != NULL) {
9819 pushstring(ap->val, ap);
9829 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
9831 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
9838 * Read the next input token.
9839 * If the token is a word, we set backquotelist to the list of cmds in
9840 * backquotes. We set quoteflag to true if any part of the word was
9842 * If the token is TREDIR, then we set redirnode to a structure containing
9844 * In all cases, the variable startlinno is set to the number of the line
9845 * on which the token starts.
9847 * [Change comment: here documents and internal procedures]
9848 * [Readtoken shouldn't have any arguments. Perhaps we should make the
9849 * word parsing code into a separate routine. In this case, readtoken
9850 * doesn't need to have any internal procedures, but parseword does.
9851 * We could also make parseoperator in essence the main routine, and
9852 * have parseword (readtoken1?) handle both words and redirection.]
9855 #define NEW_xxreadtoken
9856 #ifdef NEW_xxreadtoken
9858 /* singles must be first! */
9859 static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
9861 static const char xxreadtoken_tokens[] = {
9862 TNL, TLP, TRP, /* only single occurrence allowed */
9863 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
9864 TEOF, /* corresponds to trailing nul */
9865 TAND, TOR, TENDCASE, /* if double occurrence */
9868 #define xxreadtoken_doubles \
9869 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
9870 #define xxreadtoken_singles \
9871 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
9873 static int xxreadtoken()
9885 startlinno = plinno;
9886 for (;;) { /* until token or start of word found */
9889 if ((c != ' ') && (c != '\t')
9890 #ifdef CONFIG_ASH_ALIAS
9895 while ((c = pgetc()) != '\n' && c != PEOF);
9897 } else if (c == '\\') {
9898 if (pgetc() != '\n') {
9902 startlinno = ++plinno;
9907 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
9912 needprompt = doprompt;
9915 p = strchr(xxreadtoken_chars, c);
9918 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
9921 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
9922 if (pgetc() == *p) { /* double occurrence? */
9923 p += xxreadtoken_doubles + 1;
9930 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
9938 #define RETURN(token) return lasttoken = token
9953 startlinno = plinno;
9954 for (;;) { /* until token or start of word found */
9957 case ' ': case '\t':
9958 #ifdef CONFIG_ASH_ALIAS
9963 while ((c = pgetc()) != '\n' && c != PEOF);
9967 if (pgetc() == '\n') {
9968 startlinno = ++plinno;
9977 needprompt = doprompt;
10005 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10008 #endif /* NEW_xxreadtoken */
10012 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10013 * is not NULL, read a here document. In the latter case, eofmark is the
10014 * word which marks the end of the document and striptabs is true if
10015 * leading tabs should be stripped from the document. The argument firstc
10016 * is the first character of the input token or document.
10018 * Because C does not have internal subroutines, I have simulated them
10019 * using goto's to implement the subroutine linkage. The following macros
10020 * will run code that appears at the end of readtoken1.
10023 #define CHECKEND() {goto checkend; checkend_return:;}
10024 #define PARSEREDIR() {goto parseredir; parseredir_return:;}
10025 #define PARSESUB() {goto parsesub; parsesub_return:;}
10026 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10027 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10028 #define PARSEARITH() {goto parsearith; parsearith_return:;}
10031 readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
10036 char line[EOFMARKLEN + 1];
10037 struct nodelist *bqlist;
10040 int varnest; /* levels of variables expansion */
10041 int arinest; /* levels of arithmetic expansion */
10042 int parenlevel; /* levels of parens in arithmetic */
10043 int dqvarnest; /* levels of variables expansion within double quotes */
10045 int prevsyntax; /* syntax before arithmetic */
10047 /* Avoid longjmp clobbering */
10053 (void) &parenlevel;
10056 (void) &prevsyntax;
10060 startlinno = plinno;
10062 if (syntax == DQSYNTAX)
10071 STARTSTACKSTR(out);
10072 loop: { /* for each line, until end of word */
10073 CHECKEND(); /* set c to PEOF if at end of here document */
10074 for (;;) { /* until end of line or end of word */
10075 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10076 switch(SIT(c, syntax)) {
10077 case CNL: /* '\n' */
10078 if (syntax == BASESYNTAX)
10079 goto endword; /* exit outer loop */
10085 goto loop; /* continue outer loop */
10090 if (eofmark == NULL || dblquote)
10091 USTPUTC(CTLESC, out);
10094 case CBACK: /* backslash */
10097 USTPUTC(CTLESC, out);
10098 USTPUTC('\\', out);
10100 } else if (c == '\n') {
10106 c != '\\' && c != '`' &&
10112 USTPUTC(CTLESC, out);
10113 USTPUTC('\\', out);
10115 if (SIT(c, SQSYNTAX) == CCTL)
10116 USTPUTC(CTLESC, out);
10124 if (eofmark == NULL) {
10125 USTPUTC(CTLQUOTEMARK, out);
10133 if (eofmark != NULL && arinest == 0 &&
10137 if (dqvarnest == 0) {
10138 syntax = BASESYNTAX;
10145 case CVAR: /* '$' */
10146 PARSESUB(); /* parse substitution */
10148 case CENDVAR: /* '}' */
10151 if (dqvarnest > 0) {
10154 USTPUTC(CTLENDVAR, out);
10159 #ifdef CONFIG_ASH_MATH_SUPPORT
10160 case CLP: /* '(' in arithmetic */
10164 case CRP: /* ')' in arithmetic */
10165 if (parenlevel > 0) {
10169 if (pgetc() == ')') {
10170 if (--arinest == 0) {
10171 USTPUTC(CTLENDARI, out);
10172 syntax = prevsyntax;
10173 if (syntax == DQSYNTAX)
10181 * unbalanced parens
10182 * (don't 2nd guess - no error)
10190 case CBQUOTE: /* '`' */
10194 goto endword; /* exit outer loop */
10199 goto endword; /* exit outer loop */
10200 #ifdef CONFIG_ASH_ALIAS
10210 #ifdef CONFIG_ASH_MATH_SUPPORT
10211 if (syntax == ARISYNTAX)
10212 synerror("Missing '))'");
10214 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10215 synerror("Unterminated quoted string");
10216 if (varnest != 0) {
10217 startlinno = plinno;
10219 synerror("Missing '}'");
10221 USTPUTC('\0', out);
10222 len = out - (char *)stackblock();
10223 out = stackblock();
10224 if (eofmark == NULL) {
10225 if ((c == '>' || c == '<')
10228 && (*out == '\0' || is_digit(*out))) {
10230 return lasttoken = TREDIR;
10235 quoteflag = quotef;
10236 backquotelist = bqlist;
10237 grabstackblock(len);
10239 return lasttoken = TWORD;
10240 /* end of readtoken routine */
10245 * Check to see whether we are at the end of the here document. When this
10246 * is called, c is set to the first character of the next input line. If
10247 * we are at the end of the here document, this routine sets the c to PEOF.
10252 #ifdef CONFIG_ASH_ALIAS
10258 while (c == '\t') {
10262 if (c == *eofmark) {
10263 if (pfgets(line, sizeof line) != NULL) {
10267 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10268 if (*p == '\n' && *q == '\0') {
10271 needprompt = doprompt;
10273 pushstring(line, NULL);
10278 goto checkend_return;
10283 * Parse a redirection operator. The variable "out" points to a string
10284 * specifying the fd to be redirected. The variable "c" contains the
10285 * first character of the redirection operator.
10292 np = (union node *)stalloc(sizeof (struct nfile));
10297 np->type = NAPPEND;
10299 np->type = NCLOBBER;
10306 } else { /* c == '<' */
10308 switch (c = pgetc()) {
10310 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10311 np = (union node *)stalloc(sizeof (struct nhere));
10315 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10316 heredoc->here = np;
10317 if ((c = pgetc()) == '-') {
10318 heredoc->striptabs = 1;
10320 heredoc->striptabs = 0;
10326 np->type = NFROMFD;
10330 np->type = NFROMTO;
10340 np->nfile.fd = digit_val(fd);
10342 goto parseredir_return;
10347 * Parse a substitution. At this point, we have read the dollar sign
10348 * and nothing else.
10356 static const char types[] = "}-+?=";
10360 c <= PEOA_OR_PEOF ||
10361 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10365 } else if (c == '(') { /* $(command) or $((arith)) */
10366 if (pgetc() == '(') {
10367 #ifdef CONFIG_ASH_MATH_SUPPORT
10370 synerror("We unsupport $((arith))");
10377 USTPUTC(CTLVAR, out);
10378 typeloc = out - (char *)stackblock();
10379 USTPUTC(VSNORMAL, out);
10380 subtype = VSNORMAL;
10384 if ((c = pgetc()) == '}')
10387 subtype = VSLENGTH;
10392 if (c > PEOA_OR_PEOF && is_name(c)) {
10396 } while (c > PEOA_OR_PEOF && is_in_name(c));
10397 } else if (is_digit(c)) {
10401 } while (is_digit(c));
10403 else if (is_special(c)) {
10408 badsub: synerror("Bad substitution");
10412 if (subtype == 0) {
10419 p = strchr(types, c);
10422 subtype = p - types + VSNORMAL;
10428 subtype = c == '#' ? VSTRIMLEFT :
10441 if (dblquote || arinest)
10443 *((char *)stackblock() + typeloc) = subtype | flags;
10444 if (subtype != VSNORMAL) {
10446 if (dblquote || arinest) {
10451 goto parsesub_return;
10456 * Called to parse command substitutions. Newstyle is set if the command
10457 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10458 * list of commands (passed by reference), and savelen is the number of
10459 * characters on the top of the stack which must be preserved.
10463 struct nodelist **nlpp;
10466 char *volatile str;
10467 struct jmploc jmploc;
10468 struct jmploc *volatile savehandler;
10472 (void) &saveprompt;
10475 savepbq = parsebackquote;
10476 if (setjmp(jmploc.loc)) {
10479 parsebackquote = 0;
10480 handler = savehandler;
10481 longjmp(handler->loc, 1);
10485 savelen = out - (char *)stackblock();
10487 str = ckmalloc(savelen);
10488 memcpy(str, stackblock(), savelen);
10490 savehandler = handler;
10494 /* We must read until the closing backquote, giving special
10495 treatment to some slashes, and then push the string and
10496 reread it as input, interpreting it normally. */
10503 STARTSTACKSTR(pout);
10509 switch (pc = pgetc()) {
10514 if ((pc = pgetc()) == '\n') {
10519 * If eating a newline, avoid putting
10520 * the newline into the new character
10521 * stream (via the STPUTC after the
10526 if (pc != '\\' && pc != '`' && pc != '$'
10527 && (!dblquote || pc != '"'))
10528 STPUTC('\\', pout);
10529 if (pc > PEOA_OR_PEOF) {
10535 #ifdef CONFIG_ASH_ALIAS
10538 startlinno = plinno;
10539 synerror("EOF in backquote substitution");
10543 needprompt = doprompt;
10552 STPUTC('\0', pout);
10553 psavelen = pout - (char *)stackblock();
10554 if (psavelen > 0) {
10555 pstr = grabstackstr(pout);
10556 setinputstring(pstr);
10561 nlpp = &(*nlpp)->next;
10562 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10563 (*nlpp)->next = NULL;
10564 parsebackquote = oldstyle;
10567 saveprompt = doprompt;
10574 doprompt = saveprompt;
10576 if (readtoken() != TRP)
10583 * Start reading from old file again, ignoring any pushed back
10584 * tokens left from the backquote parsing
10589 while (stackblocksize() <= savelen)
10591 STARTSTACKSTR(out);
10593 memcpy(out, str, savelen);
10594 STADJUST(savelen, out);
10600 parsebackquote = savepbq;
10601 handler = savehandler;
10602 if (arinest || dblquote)
10603 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10605 USTPUTC(CTLBACKQ, out);
10607 goto parsebackq_oldreturn;
10609 goto parsebackq_newreturn;
10612 #ifdef CONFIG_ASH_MATH_SUPPORT
10614 * Parse an arithmetic expansion (indicate start of one and set state)
10618 if (++arinest == 1) {
10619 prevsyntax = syntax;
10620 syntax = ARISYNTAX;
10621 USTPUTC(CTLARI, out);
10628 * we collapse embedded arithmetic expansion to
10629 * parenthesis, which should be equivalent
10633 goto parsearith_return;
10637 } /* end of readtoken */
10642 * Returns true if the text contains nothing to expand (no dollar signs
10647 noexpand(char *text)
10653 while ((c = *p++) != '\0') {
10654 if (c == CTLQUOTEMARK)
10658 else if (SIT(c, BASESYNTAX) == CCTL)
10666 * Return of a legal variable name (a letter or underscore followed by zero or
10667 * more letters, underscores, and digits).
10671 endofname(const char *name)
10679 if (! is_in_name(*p))
10687 * Called when an unexpected token is read during the parse. The argument
10688 * is the token that is expected, or -1 if more than one type of token can
10689 * occur at this point.
10692 static void synexpect(int token)
10697 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10699 sprintf(msg + l, " (expecting %s)", tokname(token));
10705 synerror(const char *msg)
10707 error("Syntax error: %s", msg);
10713 * called by editline -- any expansions to the prompt
10714 * should be added here.
10717 static void setprompt(int whichprompt)
10719 const char *prompt;
10721 switch (whichprompt) {
10735 static const char *const *findkwd(const char *s)
10737 return bsearch(s, tokname_array + KWDOFFSET,
10738 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
10739 sizeof(const char *), pstrcmp);
10742 /* $NetBSD: redir.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
10745 * Code for dealing with input/output redirection.
10748 #define EMPTY -2 /* marks an unused slot in redirtab */
10750 # define PIPESIZE 4096 /* amount of buffering in a pipe */
10752 # define PIPESIZE PIPE_BUF
10756 * Open a file in noclobber mode.
10757 * The code was copied from bash.
10760 noclobberopen(const char *fname)
10763 struct stat finfo, finfo2;
10766 * If the file exists and is a regular file, return an error
10769 r = stat(fname, &finfo);
10770 if (r == 0 && S_ISREG(finfo.st_mode)) {
10776 * If the file was not present (r != 0), make sure we open it
10777 * exclusively so that if it is created before we open it, our open
10778 * will fail. Make sure that we do not truncate an existing file.
10779 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10780 * file was not a regular file, we leave O_EXCL off.
10783 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10784 fd = open(fname, O_WRONLY|O_CREAT, 0666);
10786 /* If the open failed, return the file descriptor right away. */
10791 * OK, the open succeeded, but the file may have been changed from a
10792 * non-regular file to a regular file between the stat and the open.
10793 * We are assuming that the O_EXCL open handles the case where FILENAME
10794 * did not exist and is symlinked to an existing file between the stat
10799 * If we can open it and fstat the file descriptor, and neither check
10800 * revealed that it was a regular file, and the file has not been
10801 * replaced, return the file descriptor.
10803 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10804 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
10807 /* The file has been replaced. badness. */
10814 * Handle here documents. Normally we fork off a process to write the
10815 * data to a pipe. If the document is short, we can stuff the data in
10816 * the pipe without forking.
10820 openhere(union node *redir)
10826 error("Pipe call failed");
10827 if (redir->type == NHERE) {
10828 len = strlen(redir->nhere.doc->narg.text);
10829 if (len <= PIPESIZE) {
10830 xwrite(pip[1], redir->nhere.doc->narg.text, len);
10834 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
10836 signal(SIGINT, SIG_IGN);
10837 signal(SIGQUIT, SIG_IGN);
10838 signal(SIGHUP, SIG_IGN);
10840 signal(SIGTSTP, SIG_IGN);
10842 signal(SIGPIPE, SIG_DFL);
10843 if (redir->type == NHERE)
10844 xwrite(pip[1], redir->nhere.doc->narg.text, len);
10846 expandhere(redir->nhere.doc, pip[1]);
10855 openredirect(union node *redir)
10860 switch (redir->nfile.type) {
10862 fname = redir->nfile.expfname;
10863 if ((f = open(fname, O_RDONLY)) < 0)
10867 fname = redir->nfile.expfname;
10868 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
10872 /* Take care of noclobber mode. */
10874 fname = redir->nfile.expfname;
10875 if ((f = noclobberopen(fname)) < 0)
10881 fname = redir->nfile.expfname;
10882 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
10886 fname = redir->nfile.expfname;
10887 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
10894 /* Fall through to eliminate warning. */
10901 f = openhere(redir);
10907 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
10909 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
10913 dupredirect(union node *redir, int f)
10915 int fd = redir->nfile.fd;
10917 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
10918 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
10919 copyfd(redir->ndup.dupfd, fd);
10932 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
10933 * old file descriptors are stashed away so that the redirection can be
10934 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
10935 * standard output, and the standard error if it becomes a duplicate of
10936 * stdout, is saved in memory.
10940 redirect(union node *redir, int flags)
10943 struct redirtab *sv;
10954 if (flags & REDIR_PUSH) {
10955 struct redirtab *q;
10956 q = ckmalloc(sizeof (struct redirtab));
10957 q->next = redirlist;
10959 q->nullredirs = nullredirs - 1;
10960 for (i = 0 ; i < 10 ; i++)
10961 q->renamed[i] = EMPTY;
10968 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
10969 n->ndup.dupfd == fd)
10970 continue; /* redirect from/to same file descriptor */
10972 newfd = openredirect(n);
10975 if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
10976 i = fcntl(fd, F_DUPFD, 10);
10983 error("%d: %m", fd);
10993 dupredirect(n, newfd);
10994 } while ((n = n->nfile.next));
11000 * Undo the effects of the last redirection.
11006 struct redirtab *rp;
11009 if (--nullredirs >= 0)
11013 for (i = 0 ; i < 10 ; i++) {
11014 if (rp->renamed[i] != EMPTY) {
11017 copyfd(rp->renamed[i], i);
11019 close(rp->renamed[i]);
11022 redirlist = rp->next;
11023 nullredirs = rp->nullredirs;
11029 * Undo all redirections. Called on error or interrupt.
11033 * Discard all saved file descriptors.
11037 clearredir(int drop)
11049 * Copy a file descriptor to be >= to. Returns -1
11050 * if the source file descriptor is closed, EMPTY if there are no unused
11051 * file descriptors left.
11055 copyfd(int from, int to)
11059 newfd = fcntl(from, F_DUPFD, to);
11061 if (errno == EMFILE)
11064 error("%d: %m", from);
11071 redirectsafe(union node *redir, int flags)
11074 volatile int saveint;
11075 struct jmploc *volatile savehandler = handler;
11076 struct jmploc jmploc;
11079 if (!(err = setjmp(jmploc.loc) * 2)) {
11081 redirect(redir, flags);
11083 handler = savehandler;
11084 if (err && exception != EXERROR)
11085 longjmp(handler->loc, 1);
11086 RESTOREINT(saveint);
11090 /* $NetBSD: show.c,v 1.24 2003/01/22 20:36:04 dsl Exp $ */
11093 static void shtree(union node *, int, char *, FILE*);
11094 static void shcmd(union node *, FILE *);
11095 static void sharg(union node *, FILE *);
11096 static void indent(int, char *, FILE *);
11097 static void trstring(char *);
11101 showtree(union node *n)
11103 trputs("showtree called\n");
11104 shtree(n, 1, NULL, stdout);
11109 shtree(union node *n, int ind, char *pfx, FILE *fp)
11111 struct nodelist *lp;
11117 indent(ind, pfx, fp);
11128 shtree(n->nbinary.ch1, ind, NULL, fp);
11131 shtree(n->nbinary.ch2, ind, NULL, fp);
11139 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
11144 if (n->npipe.backgnd)
11150 fprintf(fp, "<node type %d>", n->type);
11159 shcmd(union node *cmd, FILE *fp)
11167 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11173 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11176 switch (np->nfile.type) {
11177 case NTO: s = ">"; dftfd = 1; break;
11178 case NCLOBBER: s = ">|"; dftfd = 1; break;
11179 case NAPPEND: s = ">>"; dftfd = 1; break;
11180 case NTOFD: s = ">&"; dftfd = 1; break;
11181 case NFROM: s = "<"; dftfd = 0; break;
11182 case NFROMFD: s = "<&"; dftfd = 0; break;
11183 case NFROMTO: s = "<>"; dftfd = 0; break;
11184 default: s = "*error*"; dftfd = 0; break;
11186 if (np->nfile.fd != dftfd)
11187 fprintf(fp, "%d", np->nfile.fd);
11189 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11190 fprintf(fp, "%d", np->ndup.dupfd);
11192 sharg(np->nfile.fname, fp);
11201 sharg(union node *arg, FILE *fp)
11204 struct nodelist *bqlist;
11207 if (arg->type != NARG) {
11208 out1fmt("<node type %d>\n", arg->type);
11211 bqlist = arg->narg.backquote;
11212 for (p = arg->narg.text ; *p ; p++) {
11221 if (subtype == VSLENGTH)
11227 if (subtype & VSNUL)
11230 switch (subtype & VSTYPE) {
11249 case VSTRIMLEFTMAX:
11256 case VSTRIMRIGHTMAX:
11263 out1fmt("<subtype %d>", subtype);
11270 case CTLBACKQ|CTLQUOTE:
11273 shtree(bqlist->n, -1, NULL, fp);
11285 indent(int amount, char *pfx, FILE *fp)
11289 for (i = 0 ; i < amount ; i++) {
11290 if (pfx && i == amount - 1)
11311 putc(c, tracefile);
11315 trace(const char *fmt, ...)
11322 (void) vfprintf(tracefile, fmt, va);
11327 tracev(const char *fmt, va_list va)
11331 (void) vfprintf(tracefile, fmt, va);
11336 trputs(const char *s)
11340 fputs(s, tracefile);
11352 putc('"', tracefile);
11353 for (p = s ; *p ; p++) {
11355 case '\n': c = 'n'; goto backslash;
11356 case '\t': c = 't'; goto backslash;
11357 case '\r': c = 'r'; goto backslash;
11358 case '"': c = '"'; goto backslash;
11359 case '\\': c = '\\'; goto backslash;
11360 case CTLESC: c = 'e'; goto backslash;
11361 case CTLVAR: c = 'v'; goto backslash;
11362 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11363 case CTLBACKQ: c = 'q'; goto backslash;
11364 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
11365 backslash: putc('\\', tracefile);
11366 putc(c, tracefile);
11369 if (*p >= ' ' && *p <= '~')
11370 putc(*p, tracefile);
11372 putc('\\', tracefile);
11373 putc(*p >> 6 & 03, tracefile);
11374 putc(*p >> 3 & 07, tracefile);
11375 putc(*p & 07, tracefile);
11380 putc('"', tracefile);
11392 putc(' ', tracefile);
11394 putc('\n', tracefile);
11410 /* leave open because libedit might be using it */
11413 scopy("./trace", s);
11415 if (!freopen(s, "a", tracefile)) {
11416 fprintf(stderr, "Can't re-open %s\n", s);
11421 if ((tracefile = fopen(s, "a")) == NULL) {
11422 fprintf(stderr, "Can't open %s\n", s);
11428 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11429 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11431 setlinebuf(tracefile);
11432 fputs("\nTracing started.\n", tracefile);
11437 /* $NetBSD: trap.c,v 1.28 2002/11/24 22:35:43 christos Exp $ */
11440 * Sigmode records the current value of the signal handlers for the various
11441 * modes. A value of zero means that the current handler is not known.
11442 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
11445 #define S_DFL 1 /* default signal handling (SIG_DFL) */
11446 #define S_CATCH 2 /* signal is caught */
11447 #define S_IGN 3 /* signal is ignored (SIG_IGN) */
11448 #define S_HARD_IGN 4 /* signal is ignored permenantly */
11449 #define S_RESET 5 /* temporary - to reset a hard ignored sig */
11454 * The trap builtin.
11458 trapcmd(int argc, char **argv)
11467 for (signo = 0 ; signo < NSIG ; signo++) {
11468 if (trap[signo] != NULL) {
11471 sn = u_signal_names(0, &signo, 0);
11474 out1fmt("trap -- %s %s\n",
11475 single_quote(trap[signo]), sn);
11485 if ((signo = decode_signal(*ap, 0)) < 0)
11486 error("%s: bad trap", *ap);
11489 if (action[0] == '-' && action[1] == '\0')
11492 action = savestr(action);
11495 ckfree(trap[signo]);
11496 trap[signo] = action;
11507 * Clear traps on a fork.
11515 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
11516 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
11520 if (tp != &trap[0])
11521 setsignal(tp - trap);
11529 * Set the signal handler for the specified signal. The routine figures
11530 * out what it should be set to.
11534 setsignal(int signo)
11538 struct sigaction act;
11540 if ((t = trap[signo]) == NULL)
11542 else if (*t != '\0')
11546 if (rootshell && action == S_DFL) {
11549 if (iflag || minusc || sflag == 0)
11572 t = &sigmode[signo - 1];
11576 * current setting unknown
11578 if (sigaction(signo, 0, &act) == -1) {
11580 * Pretend it worked; maybe we should give a warning
11581 * here, but other shells don't. We don't alter
11582 * sigmode, so that we retry every time.
11586 if (act.sa_handler == SIG_IGN) {
11587 if (mflag && (signo == SIGTSTP ||
11588 signo == SIGTTIN || signo == SIGTTOU)) {
11589 tsig = S_IGN; /* don't hard ignore these */
11593 tsig = S_RESET; /* force to be set */
11596 if (tsig == S_HARD_IGN || tsig == action)
11600 act.sa_handler = onsig;
11603 act.sa_handler = SIG_IGN;
11606 act.sa_handler = SIG_DFL;
11610 sigfillset(&act.sa_mask);
11611 sigaction(signo, &act, 0);
11619 ignoresig(int signo)
11621 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11622 signal(signo, SIG_IGN);
11624 sigmode[signo - 1] = S_HARD_IGN;
11635 gotsig[signo - 1] = 1;
11636 pendingsigs = signo;
11638 if (exsig || (signo == SIGINT && !trap[SIGINT])) {
11647 * Called to execute a trap. Perhaps we should avoid entering new trap
11648 * handlers while we are executing a trap handler.
11658 savestatus = exitstatus;
11660 while (pendingsigs = 0, barrier(), (p = memchr(q, 1, NSIG - 1))) {
11662 p = trap[p - q + 1];
11666 exitstatus = savestatus;
11672 * Controls whether the shell is interactive or not.
11676 setinteractive(int on)
11678 static int is_interactive;
11680 if (++on == is_interactive)
11682 is_interactive = on;
11684 setsignal(SIGQUIT);
11685 setsignal(SIGTERM);
11686 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11687 if(is_interactive > 1) {
11688 /* Looks like they want an interactive shell */
11689 static int do_banner;
11693 "\n\n" BB_BANNER " Built-in shell (ash)\n"
11694 "Enter 'help' for a list of built-in commands.\n\n");
11702 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11703 /*** List the available builtins ***/
11705 static int helpcmd(int argc, char **argv)
11709 out1fmt("\nBuilt-in commands:\n-------------------\n");
11710 for (col = 0, i = 0; i < NUMBUILTINS; i++) {
11711 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11712 builtincmd[i].name + 1);
11718 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
11720 extern const struct BB_applet applets[];
11721 extern const size_t NUM_APPLETS;
11723 for (i = 0; i < NUM_APPLETS; i++) {
11725 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
11734 return EXIT_SUCCESS;
11736 #endif /* CONFIG_FEATURE_SH_EXTRA_QUIET */
11739 * Called to exit the shell.
11749 status = exitstatus;
11750 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
11751 if (setjmp(loc.loc)) {
11755 if ((p = trap[0]) != NULL && *p != '\0') {
11760 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
11761 if (iflag && rootshell) {
11762 const char *hp = lookupvar("HISTFILE");
11765 save_history ( hp );
11773 static int decode_signal(const char *string, int minsig)
11776 const char *name = u_signal_names(string, &signo, minsig);
11778 return name ? signo : -1;
11781 /* $NetBSD: var.c,v 1.32 2003/01/22 20:36:04 dsl Exp $ */
11783 static struct var *vartab[VTABSIZE];
11785 static int vpcmp(const void *, const void *);
11786 static struct var **findvar(struct var **, const char *);
11789 * Initialize the varable symbol tables and import the environment
11793 #ifdef CONFIG_ASH_GETOPTS
11795 * Safe version of setvar, returns 1 on success 0 on failure.
11799 setvarsafe(const char *name, const char *val, int flags)
11802 volatile int saveint;
11803 struct jmploc *volatile savehandler = handler;
11804 struct jmploc jmploc;
11807 if (setjmp(jmploc.loc))
11811 setvar(name, val, flags);
11814 handler = savehandler;
11815 RESTOREINT(saveint);
11821 * Set the value of a variable. The flags argument is ored with the
11822 * flags of the variable. If val is NULL, the variable is unset.
11826 setvar(const char *name, const char *val, int flags)
11833 q = endofname(name);
11834 p = strchrnul(q, '=');
11835 namelen = p - name;
11836 if (!namelen || p != q)
11837 error("%.*s: bad variable name", namelen, name);
11842 vallen = strlen(val);
11845 p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
11849 p = mempcpy(p, val, vallen);
11852 setvareq(nameeq, flags | VNOSAVE);
11858 * Same as setvar except that the variable and value are passed in
11859 * the first argument as name=value. Since the first argument will
11860 * be actually stored in the table, it should not be a string that
11862 * Called with interrupts off.
11866 setvareq(char *s, int flags)
11868 struct var *vp, **vpp;
11871 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
11872 vp = *findvar(vpp, s);
11874 if (vp->flags & VREADONLY) {
11875 if (flags & VNOSAVE)
11877 error("%.*s: is read only", strchrnul(s, '=') - s, s);
11880 if (flags & VNOSET)
11883 if (vp->func && (flags & VNOFUNC) == 0)
11884 (*vp->func)(strchrnul(s, '=') + 1);
11886 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
11889 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
11891 if (flags & VNOSET)
11894 vp = ckmalloc(sizeof (*vp));
11899 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
11907 * Process a linked list of variable assignments.
11911 listsetvar(struct strlist *list_set_var, int flags)
11913 struct strlist *lp = list_set_var;
11919 setvareq(lp->text, flags);
11920 } while ((lp = lp->next));
11926 * Find the value of a variable. Returns NULL if not set.
11930 lookupvar(const char *name)
11934 if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
11935 return strchrnul(v->text, '=') + 1;
11942 * Search the environment of a builtin command.
11946 bltinlookup(const char *name)
11948 struct strlist *sp;
11950 for (sp = cmdenviron ; sp ; sp = sp->next) {
11951 if (varequal(sp->text, name))
11952 return strchrnul(sp->text, '=') + 1;
11954 return lookupvar(name);
11959 * Generate a list of variables satisfying the given conditions.
11963 listvars(int on, int off, char ***end)
11974 for (vp = *vpp ; vp ; vp = vp->next)
11975 if ((vp->flags & mask) == on) {
11976 if (ep == stackstrend())
11977 ep = growstackstr();
11978 *ep++ = (char *) vp->text;
11980 } while (++vpp < vartab + VTABSIZE);
11981 if (ep == stackstrend())
11982 ep = growstackstr();
11986 return grabstackstr(ep);
11991 * POSIX requires that 'set' (but not export or readonly) output the
11992 * variables in lexicographic order - by the locale's collating order (sigh).
11993 * Maybe we could keep them in an ordered balanced binary tree
11994 * instead of hashed lists.
11995 * For now just roll 'em through qsort for printing...
11999 showvars(const char *sep_prefix, int on, int off)
12002 char **ep, **epend;
12004 ep = listvars(on, off, &epend);
12005 qsort(ep, epend - ep, sizeof(char *), vpcmp);
12007 sep = *sep_prefix ? spcstr : sep_prefix;
12009 for (; ep < epend; ep++) {
12013 p = strchrnul(*ep, '=');
12016 q = single_quote(++p);
12018 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
12027 * The export and readonly commands.
12031 exportcmd(int argc, char **argv)
12037 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12040 notp = nextopt("p") - 'p';
12041 if (notp && ((name = *(aptr = argptr)))) {
12043 if ((p = strchr(name, '=')) != NULL) {
12046 if ((vp = *findvar(hashvar(name), name))) {
12051 setvar(name, p, flag);
12052 } while ((name = *++aptr) != NULL);
12054 showvars(argv[0], flag, 0);
12061 * Make a variable a local variable. When a variable is made local, it's
12062 * value and flags are saved in a localvar structure. The saved values
12063 * will be restored when the shell function returns. We handle the name
12064 * "-" as a special case.
12068 mklocal(char *name)
12070 struct localvar *lvp;
12075 lvp = ckmalloc(sizeof (struct localvar));
12076 if (name[0] == '-' && name[1] == '\0') {
12078 p = ckmalloc(sizeof(optlist));
12079 lvp->text = memcpy(p, optlist, sizeof(optlist));
12084 vpp = hashvar(name);
12085 vp = *findvar(vpp, name);
12086 eq = strchr(name, '=');
12089 setvareq(name, VSTRFIXED);
12091 setvar(name, NULL, VSTRFIXED);
12092 vp = *vpp; /* the new variable */
12093 lvp->flags = VUNSET;
12095 lvp->text = vp->text;
12096 lvp->flags = vp->flags;
12097 vp->flags |= VSTRFIXED|VTEXTFIXED;
12103 lvp->next = localvars;
12109 * The "local" command.
12113 localcmd(int argc, char **argv)
12118 while ((name = *argv++) != NULL) {
12127 * Called after a function returns.
12128 * Interrupts must be off.
12134 struct localvar *lvp;
12137 while ((lvp = localvars) != NULL) {
12138 localvars = lvp->next;
12140 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
12141 if (vp == NULL) { /* $- saved */
12142 memcpy(optlist, lvp->text, sizeof(optlist));
12145 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12146 unsetvar(vp->text);
12149 (*vp->func)(strchrnul(lvp->text, '=') + 1);
12150 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12152 vp->flags = lvp->flags;
12153 vp->text = lvp->text;
12161 * The unset builtin command. We unset the function before we unset the
12162 * variable to allow a function to be unset when there is a readonly variable
12163 * with the same name.
12167 unsetcmd(int argc, char **argv)
12174 while ((i = nextopt("vf")) != '\0') {
12178 for (ap = argptr; *ap ; ap++) {
12193 * Unset the specified variable.
12197 unsetvar(const char *s)
12203 vpp = findvar(hashvar(s), s);
12207 int flags = vp->flags;
12210 if (flags & VREADONLY)
12212 if (flags & VUNSET)
12214 if ((flags & VSTRFIXED) == 0) {
12216 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
12223 vp->flags &= ~VEXPORT;
12236 * Find the appropriate entry in the hash table from the name.
12239 static struct var **
12240 hashvar(const char *p)
12242 unsigned int hashval;
12244 hashval = ((unsigned char) *p) << 4;
12245 while (*p && *p != '=')
12246 hashval += (unsigned char) *p++;
12247 return &vartab[hashval % VTABSIZE];
12253 * Compares two strings up to the first = or '\0'. The first
12254 * string must be terminated by '='; the second may be terminated by
12255 * either '=' or '\0'.
12259 varcmp(const char *p, const char *q)
12263 while ((c = *p) == (d = *q)) {
12264 if (!c || c == '=')
12278 vpcmp(const void *a, const void *b)
12280 return varcmp(*(const char **)a, *(const char **)b);
12283 static struct var **
12284 findvar(struct var **vpp, const char *name)
12286 for (; *vpp; vpp = &(*vpp)->next) {
12287 if (varequal((*vpp)->text, name)) {
12293 /* $NetBSD: setmode.c,v 1.29 2003/01/15 23:58:03 kleink Exp $ */
12296 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
12297 * This code for the times builtin.
12300 #include <sys/times.h>
12302 int timescmd(int ac, char **av) {
12304 long int clk_tck = sysconf(_SC_CLK_TCK);
12307 out1fmt("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
12308 (int) (buf.tms_utime / clk_tck / 60),
12309 ((double) buf.tms_utime) / clk_tck,
12310 (int) (buf.tms_stime / clk_tck / 60),
12311 ((double) buf.tms_stime) / clk_tck,
12312 (int) (buf.tms_cutime / clk_tck / 60),
12313 ((double) buf.tms_cutime) / clk_tck,
12314 (int) (buf.tms_cstime / clk_tck / 60),
12315 ((double) buf.tms_cstime) / clk_tck);
12319 #ifdef CONFIG_ASH_MATH_SUPPORT
12321 dash_arith(const char *s)
12327 result = arith(s, &errcode);
12330 error("divide by zero");
12341 * The exp(1) builtin.
12344 expcmd(int argc, char **argv)
12355 * concatenate arguments
12357 STARTSTACKSTR(concat);
12361 STPUTC(*p++, concat);
12362 if ((p = *ap++) == NULL)
12364 STPUTC(' ', concat);
12366 STPUTC('\0', concat);
12367 p = grabstackstr(concat);
12374 out1fmt("%ld\n", i);
12377 #endif /* CONFIG_ASH_MATH_SUPPORT */
12379 /* $NetBSD: miscbltin.c,v 1.31 2002/11/24 22:35:41 christos Exp $ */
12382 * Miscelaneous builtins.
12388 #if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
12389 typedef enum __rlimit_resource rlim_t;
12395 * The read builtin. The -e option causes backslashes to escape the
12396 * following character.
12398 * This uses unbuffered input, which may be avoidable in some cases.
12402 readcmd(int argc, char **argv)
12417 while ((i = nextopt("p:r")) != '\0') {
12419 prompt = optionarg;
12423 if (prompt && isatty(0)) {
12427 if (*(ap = argptr) == NULL)
12428 error("arg count");
12429 if ((ifs = bltinlookup("IFS")) == NULL)
12436 if (read(0, &c, 1) != 1) {
12448 if (!rflag && c == '\\') {
12454 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12458 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12460 setvar(*ap, stackblock(), 0);
12470 /* Remove trailing blanks */
12471 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12473 setvar(*ap, stackblock(), 0);
12474 while (*++ap != NULL)
12475 setvar(*ap, nullstr, 0);
12480 static int umaskcmd(int argc, char **argv)
12482 static const char permuser[3] = "ugo";
12483 static const char permmode[3] = "rwx";
12484 static const short int permmask[] = {
12485 S_IRUSR, S_IWUSR, S_IXUSR,
12486 S_IRGRP, S_IWGRP, S_IXGRP,
12487 S_IROTH, S_IWOTH, S_IXOTH
12493 int symbolic_mode = 0;
12495 while (nextopt("S") != '\0') {
12504 if ((ap = *argptr) == NULL) {
12505 if (symbolic_mode) {
12509 for (i = 0; i < 3; i++) {
12512 *p++ = permuser[i];
12514 for (j = 0; j < 3; j++) {
12515 if ((mask & permmask[3 * i + j]) == 0) {
12516 *p++ = permmode[j];
12524 out1fmt("%.4o\n", mask);
12527 if (is_digit((unsigned char) *ap)) {
12530 if (*ap >= '8' || *ap < '0')
12531 error(illnum, argv[1]);
12532 mask = (mask << 3) + (*ap - '0');
12533 } while (*++ap != '\0');
12536 mask = ~mask & 0777;
12537 if (!bb_parse_mode(ap, &mask)) {
12538 error("Illegal mode: %s", ap);
12540 umask(~mask & 0777);
12549 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12550 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12551 * ash by J.T. Conklin.
12559 int factor; /* multiply by to get rlim_{cur,max} values */
12563 static const struct limits limits[] = {
12565 { "time(seconds)", RLIMIT_CPU, 1, 't' },
12567 #ifdef RLIMIT_FSIZE
12568 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
12571 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
12573 #ifdef RLIMIT_STACK
12574 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
12577 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
12580 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
12582 #ifdef RLIMIT_MEMLOCK
12583 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
12585 #ifdef RLIMIT_NPROC
12586 { "process(processes)", RLIMIT_NPROC, 1, 'p' },
12588 #ifdef RLIMIT_NOFILE
12589 { "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' },
12592 { "vmemory(kbytes)", RLIMIT_VMEM, 1024, 'v' },
12595 { "swap(kbytes)", RLIMIT_SWAP, 1024, 'w' },
12597 { (char *) 0, 0, 0, '\0' }
12601 ulimitcmd(int argc, char **argv)
12605 enum { SOFT = 0x1, HARD = 0x2 }
12607 const struct limits *l;
12610 struct rlimit limit;
12613 while ((optc = nextopt("HSatfdsmcnpl")) != '\0')
12628 for (l = limits; l->name && l->option != what; l++)
12631 error("internal error (%c)", what);
12633 set = *argptr ? 1 : 0;
12637 if (all || argptr[1])
12638 error("too many arguments");
12639 if (strncmp(p, "unlimited\n", 9) == 0)
12640 val = RLIM_INFINITY;
12644 while ((c = *p++) >= '0' && c <= '9')
12646 val = (val * 10) + (long)(c - '0');
12647 if (val < (rlim_t) 0)
12651 error("bad number");
12656 for (l = limits; l->name; l++) {
12657 getrlimit(l->cmd, &limit);
12659 val = limit.rlim_cur;
12660 else if (how & HARD)
12661 val = limit.rlim_max;
12663 out1fmt("%-20s ", l->name);
12664 if (val == RLIM_INFINITY)
12665 out1fmt("unlimited\n");
12669 out1fmt("%lld\n", (long long) val);
12675 getrlimit(l->cmd, &limit);
12678 limit.rlim_max = val;
12680 limit.rlim_cur = val;
12681 if (setrlimit(l->cmd, &limit) < 0)
12682 error("error setting limit (%m)");
12685 val = limit.rlim_cur;
12686 else if (how & HARD)
12687 val = limit.rlim_max;
12689 if (val == RLIM_INFINITY)
12690 out1fmt("unlimited\n");
12694 out1fmt("%lld\n", (long long) val);
12701 const char *bb_applet_name = "debug stuff usage";
12702 int main(int argc, char **argv)
12704 return ash_main(argc, argv);
12709 * Copyright (c) 1989, 1991, 1993, 1994
12710 * The Regents of the University of California. All rights reserved.
12712 * This code is derived from software contributed to Berkeley by
12713 * Kenneth Almquist.
12715 * Redistribution and use in source and binary forms, with or without
12716 * modification, are permitted provided that the following conditions
12718 * 1. Redistributions of source code must retain the above copyright
12719 * notice, this list of conditions and the following disclaimer.
12720 * 2. Redistributions in binary form must reproduce the above copyright
12721 * notice, this list of conditions and the following disclaimer in the
12722 * documentation and/or other materials provided with the distribution.
12724 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
12725 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
12727 * 4. Neither the name of the University nor the names of its contributors
12728 * may be used to endorse or promote products derived from this software
12729 * without specific prior written permission.
12731 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
12732 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
12733 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
12734 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
12735 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
12736 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
12737 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
12738 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
12739 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
12740 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF