1 /* vi: set sw=4 ts=4: */
3 * ash shell port for busybox
5 * Copyright (c) 1989, 1991, 1993, 1994
6 * The Regents of the University of California. All rights reserved.
8 * Copyright (c) 1997-2003 Herbert Xu <herbert@debian.org>
9 * was re-ported from NetBSD and debianized.
12 * This code is derived from software contributed to Berkeley by
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 * Original BSD copyright notice is retained at the end of this file.
33 * rewrite arith.y to micro stack based cryptic algorithm by
34 * Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
36 * Modified by Vladimir Oleynik <dzo@simtreas.ru> (c) 2001-2003 to be
37 * used in busybox and size optimizations,
38 * support locale, rewrited arith (see notes to this)
44 * The follow should be set to reflect the type of system you have:
45 * JOBS -> 1 if you have Berkeley job control, 0 otherwise.
46 * define SYSV if you are running under System V.
47 * define DEBUG=1 to compile in debugging ('set -o debug' to turn on)
48 * define DEBUG=2 to compile in and turn on debugging.
50 * When debugging is on, debugging info will be written to ./trace and
51 * a quit signal will generate a core dump.
64 #include <sys/types.h>
65 #include <sys/cdefs.h>
66 #include <sys/ioctl.h>
67 #include <sys/param.h>
68 #include <sys/resource.h>
98 #ifdef CONFIG_ASH_JOB_CONTROL
112 static int *dash_errno;
114 #define errno (*dash_errno)
117 #if defined(__uClinux__)
118 #error "Do not even bother, ash will not run on uClinux"
122 #define _DIAGASSERT(assert_expr) assert(assert_expr)
124 #define _DIAGASSERT(assert_expr)
128 #ifdef CONFIG_ASH_ALIAS
129 /* $NetBSD: alias.h,v 1.5 2002/11/24 22:35:38 christos Exp $ */
141 static struct alias *lookupalias(const char *, int);
142 static int aliascmd(int, char **);
143 static int unaliascmd(int, char **);
144 static void rmaliases(void);
145 static int unalias(const char *);
146 static void printalias(const struct alias *);
149 /* $NetBSD: cd.h,v 1.3 2002/11/24 22:35:39 christos Exp $ */
152 static void setpwd(const char *, int);
154 /* $NetBSD: error.h,v 1.15 2002/11/24 22:35:39 christos Exp $ */
158 * Types of operations (passed to the errmsg routine).
162 static const char not_found_msg[] = "%s: not found";
165 #define E_OPEN "No such file" /* opening a file */
166 #define E_CREAT "Directory nonexistent" /* creating a file */
167 #define E_EXEC not_found_msg+4 /* executing a program */
170 * We enclose jmp_buf in a structure so that we can declare pointers to
171 * jump locations. The global variable handler contains the location to
172 * jump to when an exception occurs, and the global variable exception
173 * contains a code identifying the exeception. To implement nested
174 * exception handlers, the user should save the value of handler on entry
175 * to an inner scope, set handler to point to a jmploc structure for the
176 * inner scope, and restore handler on exit from the scope.
183 static struct jmploc *handler;
184 static int exception;
185 static volatile int suppressint;
186 static volatile sig_atomic_t intpending;
188 static int exerrno; /* Last exec error, error for EXEXEC */
191 #define EXINT 0 /* SIGINT received */
192 #define EXERROR 1 /* a generic error */
193 #define EXSHELLPROC 2 /* execute a shell procedure */
194 #define EXEXEC 3 /* command execution failed */
195 #define EXEXIT 4 /* exit the shell */
196 #define EXSIG 5 /* trapped signal in wait(1) */
199 /* do we generate EXSIG events */
201 /* last pending signal */
202 static volatile sig_atomic_t pendingsigs;
205 * These macros allow the user to suspend the handling of interrupt signals
206 * over a period of time. This is similar to SIGHOLD to or sigblock, but
207 * much more efficient and portable. (But hacking the kernel is so much
208 * more fun than worrying about efficiency and portability. :-))
211 #define barrier() ({ __asm__ __volatile__ ("": : :"memory"); })
218 #define SAVEINT(v) ((v) = suppressint)
219 #define RESTOREINT(v) \
222 if ((suppressint = (v)) == 0 && intpending) onint(); \
233 /* EXSIG is turned off by evalbltin(). */
236 static void exraise(int) __attribute__((__noreturn__));
237 static void onint(void) __attribute__((__noreturn__));
239 static void error(const char *, ...) __attribute__((__noreturn__));
240 static void exerror(int, const char *, ...) __attribute__((__noreturn__));
242 static void sh_warnx(const char *, ...);
244 #ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
247 if (--suppressint == 0 && intpending) {
251 #define INTON inton()
252 static void forceinton(void)
258 #define FORCEINTON forceinton()
263 if (--suppressint == 0 && intpending) onint(); \
270 if (intpending) onint(); \
273 #endif /* CONFIG_ASH_OPTIMIZE_FOR_SIZE */
276 * BSD setjmp saves the signal mask, which violates ANSI C and takes time,
277 * so we use _setjmp instead.
280 #if defined(BSD) && !defined(__SVR4) && !defined(__GLIBC__)
281 #define setjmp(jmploc) _setjmp(jmploc)
282 #define longjmp(jmploc, val) _longjmp(jmploc, val)
285 /* $NetBSD: expand.h,v 1.13 2002/11/24 22:35:40 christos Exp $ */
288 struct strlist *next;
294 struct strlist *list;
295 struct strlist **lastp;
301 #define EXP_FULL 0x1 /* perform word splitting & file globbing */
302 #define EXP_TILDE 0x2 /* do normal tilde expansion */
303 #define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
304 #define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
305 #define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
306 #define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
307 #define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
308 #define EXP_WORD 0x80 /* expand word in parameter expansion */
309 #define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */
313 static void expandarg(union node *, struct arglist *, int);
314 #define rmescapes(p) _rmescapes((p), 0)
315 static char *_rmescapes(char *, int);
316 static int casematch(union node *, char *);
318 #ifdef CONFIG_ASH_MATH_SUPPORT
319 static void expari(int);
322 /* $NetBSD: eval.h,v 1.13 2002/11/24 22:35:39 christos Exp $ */
324 static char *commandname; /* currently executing command */
325 static struct strlist *cmdenviron; /* environment for builtin command */
326 static int exitstatus; /* exit status of last command */
327 static int back_exitstatus; /* exit status of backquoted command */
330 struct backcmd { /* result of evalbackcmd */
331 int fd; /* file descriptor to read from */
332 char *buf; /* buffer */
333 int nleft; /* number of chars in buffer */
334 struct job *jp; /* job structure for command */
338 * This file was generated by the mknodes program.
374 union node *redirect;
381 struct nodelist *cmdlist;
388 union node *redirect;
403 union node *elsepart;
434 struct nodelist *backquote;
474 struct nredir nredir;
475 struct nbinary nbinary;
479 struct nclist nclist;
489 struct nodelist *next;
500 static void freefunc(struct funcnode *);
501 /* $NetBSD: parser.h,v 1.15 2002/11/24 22:35:42 christos Exp $ */
503 /* control characters in argument strings */
504 #define CTL_FIRST '\201' /* first 'special' character */
505 #define CTLESC '\201' /* escape next character */
506 #define CTLVAR '\202' /* variable defn */
507 #define CTLENDVAR '\203'
508 #define CTLBACKQ '\204'
509 #define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
510 /* CTLBACKQ | CTLQUOTE == '\205' */
511 #define CTLARI '\206' /* arithmetic expression */
512 #define CTLENDARI '\207'
513 #define CTLQUOTEMARK '\210'
514 #define CTL_LAST '\210' /* last 'special' character */
516 /* variable substitution byte (follows CTLVAR) */
517 #define VSTYPE 0x0f /* type of variable substitution */
518 #define VSNUL 0x10 /* colon--treat the empty string as unset */
519 #define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
521 /* values of VSTYPE field */
522 #define VSNORMAL 0x1 /* normal variable: $var or ${var} */
523 #define VSMINUS 0x2 /* ${var-text} */
524 #define VSPLUS 0x3 /* ${var+text} */
525 #define VSQUESTION 0x4 /* ${var?message} */
526 #define VSASSIGN 0x5 /* ${var=text} */
527 #define VSTRIMRIGHT 0x6 /* ${var%pattern} */
528 #define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
529 #define VSTRIMLEFT 0x8 /* ${var#pattern} */
530 #define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
531 #define VSLENGTH 0xa /* ${#var} */
533 /* values of checkkwd variable */
538 #define IBUFSIZ (BUFSIZ + 1)
541 * NEOF is returned by parsecmd when it encounters an end of file. It
542 * must be distinct from NULL, so we use the address of a variable that
543 * happens to be handy.
545 static int plinno = 1; /* input line number */
547 /* number of characters left in input buffer */
548 static int parsenleft; /* copy of parsefile->nleft */
549 static int parselleft; /* copy of parsefile->lleft */
551 /* next character in input buffer */
552 static char *parsenextc; /* copy of parsefile->nextc */
553 static struct parsefile basepf; /* top level input file */
554 static char basebuf[IBUFSIZ]; /* buffer for top level input file */
555 static struct parsefile *parsefile = &basepf; /* current input file */
558 static int tokpushback; /* last token pushed back */
559 #define NEOF ((union node *)&tokpushback)
560 static int parsebackquote; /* nonzero if we are inside backquotes */
561 static int doprompt; /* if set, prompt the user */
562 static int needprompt; /* true if interactive and at start of line */
563 static int lasttoken; /* last token read */
564 static char *wordtext; /* text of last word returned by readtoken */
566 static struct nodelist *backquotelist;
567 static union node *redirnode;
568 static struct heredoc *heredoc;
569 static int quoteflag; /* set if (part of) last token was quoted */
570 static int startlinno; /* line # where last token started */
572 static union node *parsecmd(int);
573 static void fixredir(union node *, const char *, int);
574 static const char *const *findkwd(const char *);
575 static char *endofname(const char *);
577 /* $NetBSD: shell.h,v 1.16 2003/01/22 20:36:04 dsl Exp $ */
579 typedef void *pointer;
581 static char nullstr[1]; /* zero length string */
582 static const char spcstr[] = " ";
583 static const char snlfmt[] = "%s\n";
584 static const char dolatstr[] = { CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' };
585 static const char illnum[] = "Illegal number: %s";
586 static const char homestr[] = "HOME";
589 #define TRACE(param) trace param
590 #define TRACEV(param) tracev param
593 #define TRACEV(param)
596 #if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
597 #define __builtin_expect(x, expected_value) (x)
600 #define likely(x) __builtin_expect((x),1)
615 #define TENDBQUOTE 12
633 /* first char is indicating which tokens mark the end of a list */
634 static const char *const tokname_array[] = {
649 /* the following are keywords */
668 static const char *tokname(int tok)
674 sprintf(buf + (tok >= TSEMI), "%s%c",
675 tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));
679 /* $NetBSD: machdep.h,v 1.10 2002/10/07 14:26:08 christos Exp $ */
682 * Most machines require the value returned from malloc to be aligned
683 * in some way. The following macro will get this right on many machines.
686 #define SHELL_SIZE (sizeof(union {int i; char *cp; double d; }) - 1)
688 * It appears that grabstackstr() will barf with such alignments
689 * because stalloc() will return a string allocated in a new stackblock.
691 #define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
694 * This file was generated by the mksyntax program.
699 #define CWORD 0 /* character is nothing special */
700 #define CNL 1 /* newline character */
701 #define CBACK 2 /* a backslash character */
702 #define CSQUOTE 3 /* single quote */
703 #define CDQUOTE 4 /* double quote */
704 #define CENDQUOTE 5 /* a terminating quote */
705 #define CBQUOTE 6 /* backwards single quote */
706 #define CVAR 7 /* a dollar sign */
707 #define CENDVAR 8 /* a '}' character */
708 #define CLP 9 /* a left paren in arithmetic */
709 #define CRP 10 /* a right paren in arithmetic */
710 #define CENDFILE 11 /* end of file */
711 #define CCTL 12 /* like CWORD, except it must be escaped */
712 #define CSPCL 13 /* these terminate a word */
713 #define CIGN 14 /* character should be ignored */
715 #ifdef CONFIG_ASH_ALIAS
719 #define PEOA_OR_PEOF PEOA
723 #define PEOA_OR_PEOF PEOF
726 #define is_digit(c) ((unsigned)((c) - '0') <= 9)
727 #define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
728 #define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
731 * is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
732 * (assuming ascii char codes, as the original implementation did)
734 #define is_special(c) \
735 ( (((unsigned int)c) - 33 < 32) \
736 && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
738 #define digit_val(c) ((c) - '0')
741 * This file was generated by the mksyntax program.
744 #ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
745 #define USE_SIT_FUNCTION
748 /* number syntax index */
749 #define BASESYNTAX 0 /* not in quotes */
750 #define DQSYNTAX 1 /* in double quotes */
751 #define SQSYNTAX 2 /* in single quotes */
752 #define ARISYNTAX 3 /* in arithmetic */
754 #ifdef CONFIG_ASH_MATH_SUPPORT
755 static const char S_I_T[][4] = {
756 #ifdef CONFIG_ASH_ALIAS
757 {CSPCL, CIGN, CIGN, CIGN}, /* 0, PEOA */
759 {CSPCL, CWORD, CWORD, CWORD}, /* 1, ' ' */
760 {CNL, CNL, CNL, CNL}, /* 2, \n */
761 {CWORD, CCTL, CCTL, CWORD}, /* 3, !*-/:=?[]~ */
762 {CDQUOTE, CENDQUOTE, CWORD, CWORD}, /* 4, '"' */
763 {CVAR, CVAR, CWORD, CVAR}, /* 5, $ */
764 {CSQUOTE, CWORD, CENDQUOTE, CWORD}, /* 6, "'" */
765 {CSPCL, CWORD, CWORD, CLP}, /* 7, ( */
766 {CSPCL, CWORD, CWORD, CRP}, /* 8, ) */
767 {CBACK, CBACK, CCTL, CBACK}, /* 9, \ */
768 {CBQUOTE, CBQUOTE, CWORD, CBQUOTE}, /* 10, ` */
769 {CENDVAR, CENDVAR, CWORD, CENDVAR}, /* 11, } */
770 #ifndef USE_SIT_FUNCTION
771 {CENDFILE, CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */
772 {CWORD, CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */
773 {CCTL, CCTL, CCTL, CCTL} /* 14, CTLESC ... */
777 static const char S_I_T[][3] = {
778 #ifdef CONFIG_ASH_ALIAS
779 {CSPCL, CIGN, CIGN}, /* 0, PEOA */
781 {CSPCL, CWORD, CWORD}, /* 1, ' ' */
782 {CNL, CNL, CNL}, /* 2, \n */
783 {CWORD, CCTL, CCTL}, /* 3, !*-/:=?[]~ */
784 {CDQUOTE, CENDQUOTE, CWORD}, /* 4, '"' */
785 {CVAR, CVAR, CWORD}, /* 5, $ */
786 {CSQUOTE, CWORD, CENDQUOTE}, /* 6, "'" */
787 {CSPCL, CWORD, CWORD}, /* 7, ( */
788 {CSPCL, CWORD, CWORD}, /* 8, ) */
789 {CBACK, CBACK, CCTL}, /* 9, \ */
790 {CBQUOTE, CBQUOTE, CWORD}, /* 10, ` */
791 {CENDVAR, CENDVAR, CWORD}, /* 11, } */
792 #ifndef USE_SIT_FUNCTION
793 {CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */
794 {CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */
795 {CCTL, CCTL, CCTL} /* 14, CTLESC ... */
798 #endif /* CONFIG_ASH_MATH_SUPPORT */
800 #ifdef USE_SIT_FUNCTION
802 #define U_C(c) ((unsigned char)(c))
804 static int SIT(int c, int syntax)
806 static const char spec_symbls[] = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
807 #ifdef CONFIG_ASH_ALIAS
808 static const char syntax_index_table[] = {
809 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
810 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
811 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
815 static const char syntax_index_table[] = {
816 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
817 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */
818 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
825 if (c == PEOF) /* 2^8+2 */
827 #ifdef CONFIG_ASH_ALIAS
828 if (c == PEOA) /* 2^8+1 */
832 if (U_C(c) >= U_C(CTLESC) && U_C(c) <= U_C(CTLQUOTEMARK))
835 s = strchr(spec_symbls, c);
836 if (s == 0 || *s == 0)
838 indx = syntax_index_table[(s - spec_symbls)];
840 return S_I_T[indx][syntax];
843 #else /* USE_SIT_FUNCTION */
845 #define SIT(c, syntax) S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax]
847 #ifdef CONFIG_ASH_ALIAS
848 #define CSPCL_CIGN_CIGN_CIGN 0
849 #define CSPCL_CWORD_CWORD_CWORD 1
850 #define CNL_CNL_CNL_CNL 2
851 #define CWORD_CCTL_CCTL_CWORD 3
852 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 4
853 #define CVAR_CVAR_CWORD_CVAR 5
854 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 6
855 #define CSPCL_CWORD_CWORD_CLP 7
856 #define CSPCL_CWORD_CWORD_CRP 8
857 #define CBACK_CBACK_CCTL_CBACK 9
858 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10
859 #define CENDVAR_CENDVAR_CWORD_CENDVAR 11
860 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
861 #define CWORD_CWORD_CWORD_CWORD 13
862 #define CCTL_CCTL_CCTL_CCTL 14
864 #define CSPCL_CWORD_CWORD_CWORD 0
865 #define CNL_CNL_CNL_CNL 1
866 #define CWORD_CCTL_CCTL_CWORD 2
867 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 3
868 #define CVAR_CVAR_CWORD_CVAR 4
869 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 5
870 #define CSPCL_CWORD_CWORD_CLP 6
871 #define CSPCL_CWORD_CWORD_CRP 7
872 #define CBACK_CBACK_CCTL_CBACK 8
873 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 9
874 #define CENDVAR_CENDVAR_CWORD_CENDVAR 10
875 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 11
876 #define CWORD_CWORD_CWORD_CWORD 12
877 #define CCTL_CCTL_CCTL_CCTL 13
880 static const char syntax_index_table[258] = {
881 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
882 /* 0 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
883 #ifdef CONFIG_ASH_ALIAS
884 /* 1 PEOA */ CSPCL_CIGN_CIGN_CIGN,
886 /* 2 -128 0x80 */ CWORD_CWORD_CWORD_CWORD,
887 /* 3 -127 CTLESC */ CCTL_CCTL_CCTL_CCTL,
888 /* 4 -126 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
889 /* 5 -125 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
890 /* 6 -124 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
891 /* 7 -123 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
892 /* 8 -122 CTLARI */ CCTL_CCTL_CCTL_CCTL,
893 /* 9 -121 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
894 /* 10 -120 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
895 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD,
896 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD,
897 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD,
898 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD,
899 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD,
900 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD,
901 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD,
902 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD,
903 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,
904 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD,
905 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD,
906 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD,
907 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD,
908 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD,
909 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD,
910 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD,
911 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD,
912 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD,
913 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,
914 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD,
915 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD,
916 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD,
917 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD,
918 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD,
919 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD,
920 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD,
921 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD,
922 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,
923 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,
924 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD,
925 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD,
926 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD,
927 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD,
928 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD,
929 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD,
930 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD,
931 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD,
932 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD,
933 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD,
934 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD,
935 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD,
936 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD,
937 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD,
938 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD,
939 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD,
940 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD,
941 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD,
942 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,
943 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,
944 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD,
945 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD,
946 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD,
947 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD,
948 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD,
949 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD,
950 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD,
951 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD,
952 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD,
953 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD,
954 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD,
955 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD,
956 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD,
957 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD,
958 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD,
959 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD,
960 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD,
961 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD,
962 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD,
963 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD,
964 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD,
965 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD,
966 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD,
967 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD,
968 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD,
969 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD,
970 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD,
971 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD,
972 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD,
973 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,
974 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD,
975 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD,
976 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD,
977 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD,
978 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD,
979 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD,
980 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD,
981 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD,
982 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD,
983 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD,
984 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD,
985 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD,
986 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD,
987 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD,
988 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD,
989 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD,
990 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD,
991 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD,
992 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD,
993 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD,
994 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD,
995 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD,
996 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD,
997 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD,
998 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD,
999 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD,
1000 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD,
1001 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD,
1002 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD,
1003 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD,
1004 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD,
1005 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD,
1006 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD,
1007 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD,
1008 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD,
1009 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD,
1010 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD,
1011 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD,
1012 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD,
1013 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD,
1014 /* 130 0 */ CWORD_CWORD_CWORD_CWORD,
1015 /* 131 1 */ CWORD_CWORD_CWORD_CWORD,
1016 /* 132 2 */ CWORD_CWORD_CWORD_CWORD,
1017 /* 133 3 */ CWORD_CWORD_CWORD_CWORD,
1018 /* 134 4 */ CWORD_CWORD_CWORD_CWORD,
1019 /* 135 5 */ CWORD_CWORD_CWORD_CWORD,
1020 /* 136 6 */ CWORD_CWORD_CWORD_CWORD,
1021 /* 137 7 */ CWORD_CWORD_CWORD_CWORD,
1022 /* 138 8 */ CWORD_CWORD_CWORD_CWORD,
1023 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
1024 /* 140 10 "\n" */ CNL_CNL_CNL_CNL,
1025 /* 141 11 */ CWORD_CWORD_CWORD_CWORD,
1026 /* 142 12 */ CWORD_CWORD_CWORD_CWORD,
1027 /* 143 13 */ CWORD_CWORD_CWORD_CWORD,
1028 /* 144 14 */ CWORD_CWORD_CWORD_CWORD,
1029 /* 145 15 */ CWORD_CWORD_CWORD_CWORD,
1030 /* 146 16 */ CWORD_CWORD_CWORD_CWORD,
1031 /* 147 17 */ CWORD_CWORD_CWORD_CWORD,
1032 /* 148 18 */ CWORD_CWORD_CWORD_CWORD,
1033 /* 149 19 */ CWORD_CWORD_CWORD_CWORD,
1034 /* 150 20 */ CWORD_CWORD_CWORD_CWORD,
1035 /* 151 21 */ CWORD_CWORD_CWORD_CWORD,
1036 /* 152 22 */ CWORD_CWORD_CWORD_CWORD,
1037 /* 153 23 */ CWORD_CWORD_CWORD_CWORD,
1038 /* 154 24 */ CWORD_CWORD_CWORD_CWORD,
1039 /* 155 25 */ CWORD_CWORD_CWORD_CWORD,
1040 /* 156 26 */ CWORD_CWORD_CWORD_CWORD,
1041 /* 157 27 */ CWORD_CWORD_CWORD_CWORD,
1042 /* 158 28 */ CWORD_CWORD_CWORD_CWORD,
1043 /* 159 29 */ CWORD_CWORD_CWORD_CWORD,
1044 /* 160 30 */ CWORD_CWORD_CWORD_CWORD,
1045 /* 161 31 */ CWORD_CWORD_CWORD_CWORD,
1046 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD,
1047 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD,
1048 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
1049 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD,
1050 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR,
1051 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD,
1052 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
1053 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
1054 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP,
1055 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP,
1056 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD,
1057 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD,
1058 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD,
1059 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD,
1060 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD,
1061 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD,
1062 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD,
1063 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD,
1064 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD,
1065 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD,
1066 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD,
1067 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD,
1068 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD,
1069 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD,
1070 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD,
1071 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD,
1072 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD,
1073 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
1074 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
1075 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD,
1076 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
1077 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD,
1078 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD,
1079 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD,
1080 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD,
1081 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD,
1082 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD,
1083 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD,
1084 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD,
1085 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD,
1086 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD,
1087 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD,
1088 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD,
1089 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD,
1090 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD,
1091 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD,
1092 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD,
1093 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD,
1094 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD,
1095 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
1096 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD,
1097 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD,
1098 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD,
1099 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD,
1100 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD,
1101 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD,
1102 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD,
1103 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
1104 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
1105 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD,
1106 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK,
1107 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD,
1108 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD,
1109 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD,
1110 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
1111 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD,
1112 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD,
1113 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD,
1114 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD,
1115 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD,
1116 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD,
1117 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD,
1118 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD,
1119 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD,
1120 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD,
1121 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD,
1122 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD,
1123 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD,
1124 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD,
1125 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD,
1126 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD,
1127 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD,
1128 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD,
1129 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD,
1130 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD,
1131 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD,
1132 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD,
1133 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD,
1134 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD,
1135 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD,
1136 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD,
1137 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD,
1138 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
1139 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
1140 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,
1141 /* 257 127 */ CWORD_CWORD_CWORD_CWORD,
1144 #endif /* USE_SIT_FUNCTION */
1146 /* $NetBSD: alias.c,v 1.11 2002/11/24 22:35:38 christos Exp $ */
1151 static int funcblocksize; /* size of structures in function */
1152 static int funcstringsize; /* size of strings in node */
1153 static pointer funcblock; /* block to allocate function from */
1154 static char *funcstring; /* block to allocate strings from */
1156 static const short nodesize[26] = {
1157 SHELL_ALIGN(sizeof (struct ncmd)),
1158 SHELL_ALIGN(sizeof (struct npipe)),
1159 SHELL_ALIGN(sizeof (struct nredir)),
1160 SHELL_ALIGN(sizeof (struct nredir)),
1161 SHELL_ALIGN(sizeof (struct nredir)),
1162 SHELL_ALIGN(sizeof (struct nbinary)),
1163 SHELL_ALIGN(sizeof (struct nbinary)),
1164 SHELL_ALIGN(sizeof (struct nbinary)),
1165 SHELL_ALIGN(sizeof (struct nif)),
1166 SHELL_ALIGN(sizeof (struct nbinary)),
1167 SHELL_ALIGN(sizeof (struct nbinary)),
1168 SHELL_ALIGN(sizeof (struct nfor)),
1169 SHELL_ALIGN(sizeof (struct ncase)),
1170 SHELL_ALIGN(sizeof (struct nclist)),
1171 SHELL_ALIGN(sizeof (struct narg)),
1172 SHELL_ALIGN(sizeof (struct narg)),
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 nfile)),
1178 SHELL_ALIGN(sizeof (struct ndup)),
1179 SHELL_ALIGN(sizeof (struct ndup)),
1180 SHELL_ALIGN(sizeof (struct nhere)),
1181 SHELL_ALIGN(sizeof (struct nhere)),
1182 SHELL_ALIGN(sizeof (struct nnot)),
1186 static void calcsize(union node *);
1187 static void sizenodelist(struct nodelist *);
1188 static union node *copynode(union node *);
1189 static struct nodelist *copynodelist(struct nodelist *);
1190 static char *nodesavestr(char *);
1194 static void evalstring(char *, int);
1195 union node; /* BLETCH for ansi C */
1196 static void evaltree(union node *, int);
1197 static void evalbackcmd(union node *, struct backcmd *);
1199 /* in_function returns nonzero if we are currently evaluating a function */
1200 #define in_function() funcnest
1201 static int evalskip; /* set if we are skipping commands */
1202 static int skipcount; /* number of levels to skip */
1203 static int funcnest; /* depth of function calls */
1205 /* reasons for skipping commands (see comment on breakcmd routine) */
1212 * This file was generated by the mkbuiltins program.
1216 static int bgcmd(int, char **);
1218 static int breakcmd(int, char **);
1219 static int cdcmd(int, char **);
1220 #ifdef CONFIG_ASH_CMDCMD
1221 static int commandcmd(int, char **);
1223 static int dotcmd(int, char **);
1224 static int evalcmd(int, char **);
1225 static int execcmd(int, char **);
1226 static int exitcmd(int, char **);
1227 static int exportcmd(int, char **);
1228 static int falsecmd(int, char **);
1230 static int fgcmd(int, char **);
1232 #ifdef CONFIG_ASH_GETOPTS
1233 static int getoptscmd(int, char **);
1235 static int hashcmd(int, char **);
1236 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1237 static int helpcmd(int argc, char **argv);
1240 static int jobscmd(int, char **);
1242 #ifdef CONFIG_ASH_MATH_SUPPORT
1243 static int letcmd(int, char **);
1245 static int localcmd(int, char **);
1246 static int pwdcmd(int, char **);
1247 static int readcmd(int, char **);
1248 static int returncmd(int, char **);
1249 static int setcmd(int, char **);
1250 static int shiftcmd(int, char **);
1251 static int timescmd(int, char **);
1252 static int trapcmd(int, char **);
1253 static int truecmd(int, char **);
1254 static int typecmd(int, char **);
1255 static int umaskcmd(int, char **);
1256 static int unsetcmd(int, char **);
1257 static int waitcmd(int, char **);
1258 static int ulimitcmd(int, char **);
1260 static int killcmd(int, char **);
1263 /* $NetBSD: mail.h,v 1.9 2002/11/24 22:35:40 christos Exp $ */
1265 #ifdef CONFIG_ASH_MAIL
1266 static void chkmail(void);
1267 static void changemail(const char *);
1270 /* $NetBSD: exec.h,v 1.20 2003/01/22 20:36:04 dsl Exp $ */
1272 /* values of cmdtype */
1273 #define CMDUNKNOWN -1 /* no entry in table for command */
1274 #define CMDNORMAL 0 /* command is an executable program */
1275 #define CMDFUNCTION 1 /* command is a shell function */
1276 #define CMDBUILTIN 2 /* command is a shell builtin */
1280 int (*builtin)(int, char **);
1281 /* unsigned flags; */
1284 #ifdef CONFIG_ASH_CMDCMD
1286 # ifdef CONFIG_ASH_ALIAS
1287 # define COMMANDCMD (builtincmd + 7)
1288 # define EXECCMD (builtincmd + 10)
1290 # define COMMANDCMD (builtincmd + 6)
1291 # define EXECCMD (builtincmd + 9)
1294 # ifdef CONFIG_ASH_ALIAS
1295 # define COMMANDCMD (builtincmd + 6)
1296 # define EXECCMD (builtincmd + 9)
1298 # define COMMANDCMD (builtincmd + 5)
1299 # define EXECCMD (builtincmd + 8)
1302 #else /* ! CONFIG_ASH_CMDCMD */
1304 # ifdef CONFIG_ASH_ALIAS
1305 # define EXECCMD (builtincmd + 9)
1307 # define EXECCMD (builtincmd + 8)
1310 # ifdef CONFIG_ASH_ALIAS
1311 # define EXECCMD (builtincmd + 8)
1313 # define EXECCMD (builtincmd + 7)
1316 #endif /* CONFIG_ASH_CMDCMD */
1318 #define BUILTIN_NOSPEC "0"
1319 #define BUILTIN_SPECIAL "1"
1320 #define BUILTIN_REGULAR "2"
1321 #define BUILTIN_SPEC_REG "3"
1322 #define BUILTIN_ASSIGN "4"
1323 #define BUILTIN_SPEC_ASSG "5"
1324 #define BUILTIN_REG_ASSG "6"
1325 #define BUILTIN_SPEC_REG_ASSG "7"
1327 #define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1328 #define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
1330 static const struct builtincmd builtincmd[] = {
1331 { BUILTIN_SPEC_REG ".", dotcmd },
1332 { BUILTIN_SPEC_REG ":", truecmd },
1333 #ifdef CONFIG_ASH_ALIAS
1334 { BUILTIN_REG_ASSG "alias", aliascmd },
1337 { BUILTIN_REGULAR "bg", bgcmd },
1339 { BUILTIN_SPEC_REG "break", breakcmd },
1340 { BUILTIN_REGULAR "cd", cdcmd },
1341 { BUILTIN_NOSPEC "chdir", cdcmd },
1342 #ifdef CONFIG_ASH_CMDCMD
1343 { BUILTIN_REGULAR "command", commandcmd },
1345 { BUILTIN_SPEC_REG "continue", breakcmd },
1346 { BUILTIN_SPEC_REG "eval", evalcmd },
1347 { BUILTIN_SPEC_REG "exec", execcmd },
1348 { BUILTIN_SPEC_REG "exit", exitcmd },
1349 { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
1350 { BUILTIN_REGULAR "false", falsecmd },
1352 { BUILTIN_REGULAR "fg", fgcmd },
1354 #ifdef CONFIG_ASH_GETOPTS
1355 { BUILTIN_REGULAR "getopts", getoptscmd },
1357 { BUILTIN_NOSPEC "hash", hashcmd },
1358 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1359 { BUILTIN_NOSPEC "help", helpcmd },
1362 { BUILTIN_REGULAR "jobs", jobscmd },
1363 { BUILTIN_REGULAR "kill", killcmd },
1365 #ifdef CONFIG_ASH_MATH_SUPPORT
1366 { BUILTIN_NOSPEC "let", letcmd },
1368 { BUILTIN_ASSIGN "local", localcmd },
1369 { BUILTIN_NOSPEC "pwd", pwdcmd },
1370 { BUILTIN_REGULAR "read", readcmd },
1371 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
1372 { BUILTIN_SPEC_REG "return", returncmd },
1373 { BUILTIN_SPEC_REG "set", setcmd },
1374 { BUILTIN_SPEC_REG "shift", shiftcmd },
1375 { BUILTIN_SPEC_REG "times", timescmd },
1376 { BUILTIN_SPEC_REG "trap", trapcmd },
1377 { BUILTIN_REGULAR "true", truecmd },
1378 { BUILTIN_NOSPEC "type", typecmd },
1379 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
1380 { BUILTIN_REGULAR "umask", umaskcmd },
1381 #ifdef CONFIG_ASH_ALIAS
1382 { BUILTIN_REGULAR "unalias", unaliascmd },
1384 { BUILTIN_SPEC_REG "unset", unsetcmd },
1385 { BUILTIN_REGULAR "wait", waitcmd },
1388 #define NUMBUILTINS (sizeof (builtincmd) / sizeof (struct builtincmd) )
1396 const struct builtincmd *cmd;
1397 struct funcnode *func;
1402 /* action to find_command() */
1403 #define DO_ERR 0x01 /* prints errors */
1404 #define DO_ABS 0x02 /* checks absolute paths */
1405 #define DO_NOFUNC 0x04 /* don't return shell functions, for command */
1406 #define DO_ALTPATH 0x08 /* using alternate path */
1407 #define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
1409 static const char *pathopt; /* set by padvance */
1411 static void shellexec(char **, const char *, int)
1412 __attribute__((__noreturn__));
1413 static char *padvance(const char **, const char *);
1414 static void find_command(char *, struct cmdentry *, int, const char *);
1415 static struct builtincmd *find_builtin(const char *);
1416 static void hashcd(void);
1417 static void changepath(const char *);
1418 static void defun(char *, union node *);
1419 static void unsetfunc(const char *);
1421 #ifdef CONFIG_ASH_MATH_SUPPORT
1422 static int dash_arith(const char *);
1425 /* $NetBSD: init.h,v 1.9 2002/11/24 22:35:40 christos Exp $ */
1427 static void reset(void);
1429 /* $NetBSD: var.h,v 1.21 2003/01/22 20:36:04 dsl Exp $ */
1436 #define VEXPORT 0x01 /* variable is exported */
1437 #define VREADONLY 0x02 /* variable cannot be modified */
1438 #define VSTRFIXED 0x04 /* variable struct is statically allocated */
1439 #define VTEXTFIXED 0x08 /* text is statically allocated */
1440 #define VSTACK 0x10 /* text is allocated on the stack */
1441 #define VUNSET 0x20 /* the variable is not set */
1442 #define VNOFUNC 0x40 /* don't call the callback function */
1443 #define VNOSET 0x80 /* do not set variable - just readonly test */
1444 #define VNOSAVE 0x100 /* when text is on the heap before setvareq */
1448 struct var *next; /* next entry in hash list */
1449 int flags; /* flags are defined above */
1450 const char *text; /* name=value */
1451 void (*func)(const char *);
1452 /* function to be called when */
1453 /* the variable gets set/unset */
1457 struct localvar *next; /* next local variable in list */
1458 struct var *vp; /* the variable that was made local */
1459 int flags; /* saved flags */
1460 const char *text; /* saved text */
1464 static struct localvar *localvars;
1470 #ifdef CONFIG_ASH_GETOPTS
1471 static void getoptsreset(const char *);
1474 #ifdef CONFIG_LOCALE_SUPPORT
1476 static void change_lc_all(const char *value);
1477 static void change_lc_ctype(const char *value);
1482 static const char defpathvar[] = "PATH=/usr/local/bin:/usr/bin:/sbin:/bin";
1484 static const char defifsvar[] = "IFS= \t\n";
1485 #define defifs (defifsvar + 4)
1487 static const char defifs[] = " \t\n";
1491 static struct var varinit[] = {
1493 { 0, VSTRFIXED|VTEXTFIXED, defifsvar, 0 },
1495 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", 0 },
1498 #ifdef CONFIG_ASH_MAIL
1499 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail },
1500 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail },
1503 { 0, VSTRFIXED|VTEXTFIXED, defpathvar, changepath },
1504 { 0, VSTRFIXED|VTEXTFIXED, "PS1=$ ", 0 },
1505 { 0, VSTRFIXED|VTEXTFIXED, "PS2=> ", 0 },
1506 { 0, VSTRFIXED|VTEXTFIXED, "PS4=+ ", 0 },
1507 #ifdef CONFIG_ASH_GETOPTS
1508 { 0, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset },
1510 #ifdef CONFIG_LOCALE_SUPPORT
1511 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL=", change_lc_all},
1512 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE=", change_lc_ctype},
1514 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
1515 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE=", NULL},
1519 #define vifs varinit[0]
1520 #ifdef CONFIG_ASH_MAIL
1521 #define vmail (&vifs)[1]
1522 #define vmpath (&vmail)[1]
1526 #define vpath (&vmpath)[1]
1527 #define vps1 (&vpath)[1]
1528 #define vps2 (&vps1)[1]
1529 #define vps4 (&vps2)[1]
1530 #define voptind (&vps4)[1]
1532 #define defpath (defpathvar + 5)
1535 * The following macros access the values of the above variables.
1536 * They have to skip over the name. They return the null string
1537 * for unset variables.
1540 #define ifsval() (vifs.text + 4)
1541 #define ifsset() ((vifs.flags & VUNSET) == 0)
1542 #define mailval() (vmail.text + 5)
1543 #define mpathval() (vmpath.text + 9)
1544 #define pathval() (vpath.text + 5)
1545 #define ps1val() (vps1.text + 4)
1546 #define ps2val() (vps2.text + 4)
1547 #define ps4val() (vps4.text + 4)
1548 #define optindval() (voptind.text + 7)
1550 #define mpathset() ((vmpath.flags & VUNSET) == 0)
1552 static void setvar(const char *, const char *, int);
1553 static void setvareq(char *, int);
1554 static void listsetvar(struct strlist *, int);
1555 static char *lookupvar(const char *);
1556 static char *bltinlookup(const char *);
1557 static char **listvars(int, int, char ***);
1558 #define environment() listvars(VEXPORT, VUNSET, 0)
1559 static int showvars(const char *, int, int);
1560 static void poplocalvars(void);
1561 static int unsetvar(const char *);
1562 #ifdef CONFIG_ASH_GETOPTS
1563 static int setvarsafe(const char *, const char *, int);
1565 static int varcmp(const char *, const char *);
1566 static struct var **hashvar(const char *);
1569 static inline int varequal(const char *a, const char *b) {
1570 return !varcmp(a, b);
1574 static int loopnest; /* current loop nesting level */
1577 struct strpush *prev; /* preceding string on stack */
1580 #ifdef CONFIG_ASH_ALIAS
1581 struct alias *ap; /* if push was associated with an alias */
1583 char *string; /* remember the string since it may change */
1587 struct parsefile *prev; /* preceding file on stack */
1588 int linno; /* current line */
1589 int fd; /* file descriptor (or -1 if string) */
1590 int nleft; /* number of chars left in this line */
1591 int lleft; /* number of chars left in this buffer */
1592 char *nextc; /* next char in buffer */
1593 char *buf; /* input buffer */
1594 struct strpush *strpush; /* for pushing strings at this level */
1595 struct strpush basestrpush; /* so pushing one is fast */
1599 * The parsefile structure pointed to by the global variable parsefile
1600 * contains information about the current file being read.
1605 struct redirtab *next;
1610 static struct redirtab *redirlist;
1611 static int nullredirs;
1613 extern char **environ;
1615 /* $NetBSD: output.h,v 1.16 2002/11/24 22:35:42 christos Exp $ */
1618 static void outstr(const char *, FILE *);
1619 static void outcslow(int, FILE *);
1620 static void flushall(void);
1621 static void flushout(FILE *);
1622 static int out1fmt(const char *, ...)
1623 __attribute__((__format__(__printf__,1,2)));
1624 static int fmtstr(char *, size_t, const char *, ...)
1625 __attribute__((__format__(__printf__,3,4)));
1626 static void xwrite(int, const void *, size_t);
1628 static int preverrout_fd; /* save fd2 before print debug if xflag is set. */
1631 static void out1str(const char *p)
1636 static void out2str(const char *p)
1643 * Initialization code.
1647 * This routine initializes the builtin variables.
1658 * PS1 depends on uid
1660 #if defined(CONFIG_FEATURE_COMMAND_EDITING) && defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
1661 vps1.text = "PS1=\\w \\$ ";
1664 vps1.text = "PS1=# ";
1667 end = vp + sizeof(varinit) / sizeof(varinit[0]);
1669 vpp = hashvar(vp->text);
1672 } while (++vp < end);
1681 basepf.nextc = basepf.buf = basebuf;
1686 signal(SIGCHLD, SIG_DFL);
1695 for (envp = environ ; *envp ; envp++) {
1696 if (strchr(*envp, '=')) {
1697 setvareq(*envp, VEXPORT|VTEXTFIXED);
1701 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
1702 setvar("PPID", ppid, 0);
1707 /* PEOF (the end of file marker) */
1710 * The input line number. Input.c just defines this variable, and saves
1711 * and restores it when files are pushed and popped. The user of this
1712 * package must set its value.
1715 static int pgetc(void);
1716 static int pgetc2(void);
1717 static int preadbuffer(void);
1718 static void pungetc(void);
1719 static void pushstring(char *, void *);
1720 static void popstring(void);
1721 static void setinputfile(const char *, int);
1722 static void setinputfd(int, int);
1723 static void setinputstring(char *);
1724 static void popfile(void);
1725 static void popallfiles(void);
1726 static void closescript(void);
1729 /* $NetBSD: jobs.h,v 1.17 2003/01/22 20:36:04 dsl Exp $ */
1732 /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
1735 #define FORK_NOJOB 2
1737 /* mode flags for showjob(s) */
1738 #define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
1739 #define SHOW_PID 0x04 /* include process pid */
1740 #define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
1744 * A job structure contains information about a job. A job is either a
1745 * single process or a set of processes contained in a pipeline. In the
1746 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1751 pid_t pid; /* process id */
1752 int status; /* last process status from wait() */
1753 char *cmd; /* text of command being run */
1757 struct procstat ps0; /* status of process */
1758 struct procstat *ps; /* status or processes when more than one */
1760 int stopstatus; /* status of a stopped job */
1763 nprocs: 16, /* number of processes */
1765 #define JOBRUNNING 0 /* at least one proc running */
1766 #define JOBSTOPPED 1 /* all procs are stopped */
1767 #define JOBDONE 2 /* all procs are completed */
1769 sigint: 1, /* job was killed by SIGINT */
1770 jobctl: 1, /* job running under job control */
1772 waited: 1, /* true if this entry has been waited for */
1773 used: 1, /* true if this entry is in used */
1774 changed: 1; /* true if status has changed */
1775 struct job *prev_job; /* previous job */
1778 static pid_t backgndpid; /* pid of last background process */
1779 static int job_warning; /* user was warned about stopped jobs */
1781 static int jobctl; /* true if doing job control */
1784 static struct job *makejob(union node *, int);
1785 static int forkshell(struct job *, union node *, int);
1786 static int waitforjob(struct job *);
1787 static int stoppedjobs(void);
1790 #define setjobctl(on) /* do nothing */
1792 static void setjobctl(int);
1793 static void showjobs(FILE *, int);
1796 /* $NetBSD: main.h,v 1.9 2002/11/24 22:35:41 christos Exp $ */
1799 /* pid of main shell */
1801 /* true if we aren't a child of the main shell */
1802 static int rootshell;
1804 static void readcmdfile(char *);
1805 static void cmdloop(int);
1807 /* $NetBSD: memalloc.h,v 1.13 2003/01/22 20:36:04 dsl Exp $ */
1811 struct stack_block *stackp;
1814 struct stackmark *marknext;
1817 /* minimum size of a block */
1818 #define MINSIZE SHELL_ALIGN(504)
1820 struct stack_block {
1821 struct stack_block *prev;
1822 char space[MINSIZE];
1825 static struct stack_block stackbase;
1826 static struct stack_block *stackp = &stackbase;
1827 static struct stackmark *markp;
1828 static char *stacknxt = stackbase.space;
1829 static size_t stacknleft = MINSIZE;
1830 static char *sstrend = stackbase.space + MINSIZE;
1831 static int herefd = -1;
1834 static pointer ckmalloc(size_t);
1835 static pointer ckrealloc(pointer, size_t);
1836 static char *savestr(const char *);
1837 static pointer stalloc(size_t);
1838 static void stunalloc(pointer);
1839 static void setstackmark(struct stackmark *);
1840 static void popstackmark(struct stackmark *);
1841 static void growstackblock(void);
1842 static void *growstackstr(void);
1843 static char *makestrspace(size_t, char *);
1844 static char *stnputs(const char *, size_t, char *);
1845 static char *stputs(const char *, char *);
1848 static inline char *_STPUTC(char c, char *p) {
1855 #define stackblock() ((void *)stacknxt)
1856 #define stackblocksize() stacknleft
1857 #define STARTSTACKSTR(p) ((p) = stackblock())
1858 #define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1859 #define CHECKSTRSPACE(n, p) \
1863 size_t m = sstrend - q; \
1865 (p) = makestrspace(l, q); \
1868 #define USTPUTC(c, p) (*p++ = (c))
1869 #define STACKSTRNUL(p) ((p) == sstrend? (p = growstackstr(), *p = '\0') : (*p = '\0'))
1870 #define STUNPUTC(p) (--p)
1871 #define STTOPC(p) p[-1]
1872 #define STADJUST(amount, p) (p += (amount))
1874 #define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1875 #define ungrabstackstr(s, p) stunalloc((s))
1876 #define stackstrend() ((void *)sstrend)
1878 #define ckfree(p) free((pointer)(p))
1880 /* $NetBSD: mystring.h,v 1.10 2002/11/24 22:35:42 christos Exp $ */
1883 #define DOLATSTRLEN 4
1885 static char *prefix(const char *, const char *);
1886 static int number(const char *);
1887 static int is_number(const char *);
1888 static char *single_quote(const char *);
1889 static char *sstrdup(const char *);
1891 #define equal(s1, s2) (strcmp(s1, s2) == 0)
1892 #define scopy(s1, s2) ((void)strcpy(s2, s1))
1894 /* $NetBSD: options.h,v 1.16 2003/01/22 20:36:04 dsl Exp $ */
1897 int nparam; /* # of positional parameters (without $0) */
1898 unsigned char malloc; /* if parameter list dynamically allocated */
1899 char **p; /* parameter list */
1900 #ifdef CONFIG_ASH_GETOPTS
1901 int optind; /* next parameter to be processed by getopts */
1902 int optoff; /* used by getopts */
1907 #define eflag optlist[0]
1908 #define fflag optlist[1]
1909 #define Iflag optlist[2]
1910 #define iflag optlist[3]
1911 #define mflag optlist[4]
1912 #define nflag optlist[5]
1913 #define sflag optlist[6]
1914 #define xflag optlist[7]
1915 #define vflag optlist[8]
1916 #define Cflag optlist[9]
1917 #define aflag optlist[10]
1918 #define bflag optlist[11]
1919 #define uflag optlist[12]
1920 #define qflag optlist[13]
1923 #define nolog optlist[14]
1924 #define debug optlist[15]
1930 /* $NetBSD: options.c,v 1.33 2003/01/22 20:36:04 dsl Exp $ */
1933 static const char *const optletters_optnames[NOPTS] = {
1954 #define optletters(n) optletters_optnames[(n)][0]
1955 #define optnames(n) (&optletters_optnames[(n)][1])
1958 static char optlist[NOPTS];
1961 static char *arg0; /* value of $0 */
1962 static struct shparam shellparam; /* $@ current positional parameters */
1963 static char **argptr; /* argument list for builtin commands */
1964 static char *optionarg; /* set by nextopt (like getopt) */
1965 static char *optptr; /* used by nextopt */
1967 static char *minusc; /* argument to -c option */
1970 static void procargs(int, char **);
1971 static void optschanged(void);
1972 static void setparam(char **);
1973 static void freeparam(volatile struct shparam *);
1974 static int shiftcmd(int, char **);
1975 static int setcmd(int, char **);
1976 static int nextopt(const char *);
1978 /* $NetBSD: redir.h,v 1.14 2002/11/24 22:35:43 christos Exp $ */
1980 /* flags passed to redirect */
1981 #define REDIR_PUSH 01 /* save previous values of file descriptors */
1982 #define REDIR_SAVEFD2 03 /* set preverrout */
1985 static void redirect(union node *, int);
1986 static void popredir(int);
1987 static void clearredir(int);
1988 static int copyfd(int, int);
1989 static int redirectsafe(union node *, int);
1991 /* $NetBSD: show.h,v 1.6 2003/01/22 20:36:04 dsl Exp $ */
1995 static void showtree(union node *);
1996 static void trace(const char *, ...);
1997 static void tracev(const char *, va_list);
1998 static void trargs(char **);
1999 static void trputc(int);
2000 static void trputs(const char *);
2001 static void opentrace(void);
2004 /* $NetBSD: trap.h,v 1.16 2002/11/24 22:35:43 christos Exp $ */
2007 /* trap handler commands */
2008 static char *trap[NSIG];
2009 /* current value of signal */
2010 static char sigmode[NSIG - 1];
2011 /* indicates specified signal received */
2012 static char gotsig[NSIG - 1];
2014 static void clear_traps(void);
2015 static void setsignal(int);
2016 static void ignoresig(int);
2017 static void onsig(int);
2018 static void dotrap(void);
2019 static void setinteractive(int);
2020 static void exitshell(void) __attribute__((__noreturn__));
2021 static int decode_signal(const char *, int);
2024 * This routine is called when an error or an interrupt occurs in an
2025 * interactive shell and control is returned to the main command loop.
2040 parselleft = parsenleft = 0; /* clear input buffer */
2044 /* from parser.c: */
2057 #ifdef CONFIG_ASH_ALIAS
2058 static struct alias *atab[ATABSIZE];
2060 static void setalias(const char *, const char *);
2061 static struct alias *freealias(struct alias *);
2062 static struct alias **__lookupalias(const char *);
2065 setalias(const char *name, const char *val)
2067 struct alias *ap, **app;
2069 app = __lookupalias(name);
2073 if (!(ap->flag & ALIASINUSE)) {
2076 ap->val = savestr(val);
2077 ap->flag &= ~ALIASDEAD;
2080 ap = ckmalloc(sizeof (struct alias));
2081 ap->name = savestr(name);
2082 ap->val = savestr(val);
2091 unalias(const char *name)
2095 app = __lookupalias(name);
2099 *app = freealias(*app);
2110 struct alias *ap, **app;
2114 for (i = 0; i < ATABSIZE; i++) {
2116 for (ap = *app; ap; ap = *app) {
2117 *app = freealias(*app);
2126 static struct alias *
2127 lookupalias(const char *name, int check)
2129 struct alias *ap = *__lookupalias(name);
2131 if (check && ap && (ap->flag & ALIASINUSE))
2137 * TODO - sort output
2140 aliascmd(int argc, char **argv)
2149 for (i = 0; i < ATABSIZE; i++)
2150 for (ap = atab[i]; ap; ap = ap->next) {
2155 while ((n = *++argv) != NULL) {
2156 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
2157 if ((ap = *__lookupalias(n)) == NULL) {
2158 fprintf(stderr, "%s: %s not found\n", "alias", n);
2172 unaliascmd(int argc, char **argv)
2176 while ((i = nextopt("a")) != '\0') {
2182 for (i = 0; *argptr; argptr++) {
2183 if (unalias(*argptr)) {
2184 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
2192 static struct alias *
2193 freealias(struct alias *ap) {
2196 if (ap->flag & ALIASINUSE) {
2197 ap->flag |= ALIASDEAD;
2209 printalias(const struct alias *ap) {
2210 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
2213 static struct alias **
2214 __lookupalias(const char *name) {
2215 unsigned int hashval;
2222 ch = (unsigned char)*p;
2226 ch = (unsigned char)*++p;
2228 app = &atab[hashval % ATABSIZE];
2230 for (; *app; app = &(*app)->next) {
2231 if (equal(name, (*app)->name)) {
2238 #endif /* CONFIG_ASH_ALIAS */
2241 /* $NetBSD: cd.c,v 1.30 2003/01/22 20:36:03 dsl Exp $ */
2244 * The cd and pwd commands.
2247 #define CD_PHYSICAL 1
2250 static int docd(const char *, int);
2251 static int cdopt(void);
2253 static char *curdir = nullstr; /* current working directory */
2254 static char *physdir = nullstr; /* physical working directory */
2263 while ((i = nextopt("LP"))) {
2265 flags ^= CD_PHYSICAL;
2274 cdcmd(int argc, char **argv)
2286 dest = bltinlookup(homestr);
2287 else if (dest[0] == '-' && dest[1] == '\0') {
2288 dest = bltinlookup("OLDPWD");
2311 if (!(path = bltinlookup("CDPATH"))) {
2319 p = padvance(&path, dest);
2320 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2324 if (!docd(p, flags))
2329 error("can't cd to %s", dest);
2332 if (flags & CD_PRINT)
2333 out1fmt(snlfmt, curdir);
2339 * Update curdir (the name of the current directory) in response to a
2343 static inline const char *
2344 updatepwd(const char *dir)
2351 cdcomppath = sstrdup(dir);
2354 if (curdir == nullstr)
2356 new = stputs(curdir, new);
2358 new = makestrspace(strlen(dir) + 2, new);
2359 lim = stackblock() + 1;
2363 if (new > lim && *lim == '/')
2368 if (dir[1] == '/' && dir[2] != '/') {
2374 p = strtok(cdcomppath, "/");
2378 if (p[1] == '.' && p[2] == '\0') {
2385 } else if (p[1] == '\0')
2389 new = stputs(p, new);
2397 return stackblock();
2401 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2402 * know that the current directory has changed.
2406 docd(const char *dest, int flags)
2408 const char *dir = 0;
2411 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2414 if (!(flags & CD_PHYSICAL)) {
2415 dir = updatepwd(dest);
2430 * Find out what the current directory is. If we already know the current
2431 * directory, this routine returns immediately.
2433 static inline char *
2436 char *dir = getcwd(0, 0);
2437 return dir ? dir : nullstr;
2441 pwdcmd(int argc, char **argv)
2444 const char *dir = curdir;
2448 if (physdir == nullstr)
2452 out1fmt(snlfmt, dir);
2457 setpwd(const char *val, int setold)
2461 oldcur = dir = curdir;
2464 setvar("OLDPWD", oldcur, VEXPORT);
2467 if (physdir != nullstr) {
2468 if (physdir != oldcur)
2472 if (oldcur == val || !val) {
2479 if (oldcur != dir && oldcur != nullstr) {
2484 setvar("PWD", dir, VEXPORT);
2487 /* $NetBSD: error.c,v 1.30 2003/01/22 20:36:03 dsl Exp $ */
2490 * Errors and exceptions.
2494 * Code to handle exceptions in C.
2499 static void exverror(int, const char *, va_list)
2500 __attribute__((__noreturn__));
2503 * Called to raise an exception. Since C doesn't include exceptions, we
2504 * just do a longjmp to the exception handler. The type of exception is
2505 * stored in the global variable "exception".
2512 if (handler == NULL)
2518 longjmp(handler->loc, 1);
2523 * Called from trap.c when a SIGINT is received. (If the user specifies
2524 * that SIGINT is to be trapped or ignored using the trap builtin, then
2525 * this routine is not called.) Suppressint is nonzero when interrupts
2526 * are held using the INTOFF macro. (The test for iflag is just
2527 * defensive programming.)
2537 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
2538 if (!(rootshell && iflag)) {
2539 signal(SIGINT, SIG_DFL);
2549 exvwarning(const char *msg, va_list ap)
2562 fprintf(errs, fmt, name, startlinno);
2563 vfprintf(errs, msg, ap);
2564 outcslow('\n', errs);
2568 * Exverror is called to raise the error exception. If the second argument
2569 * is not NULL then error prints an error message using printf style
2570 * formatting. It then raises the error exception.
2573 exverror(int cond, const char *msg, va_list ap)
2577 TRACE(("exverror(%d, \"", cond));
2579 TRACE(("\") pid=%d\n", getpid()));
2581 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
2584 exvwarning(msg, ap);
2593 error(const char *msg, ...)
2598 exverror(EXERROR, msg, ap);
2605 exerror(int cond, const char *msg, ...)
2610 exverror(cond, msg, ap);
2616 * error/warning routines for external builtins
2620 sh_warnx(const char *fmt, ...)
2625 exvwarning(fmt, ap);
2631 * Return a string describing an error. The returned string may be a
2632 * pointer to a static buffer that will be overwritten on the next call.
2633 * Action describes the operation that got the error.
2637 errmsg(int e, const char *em)
2639 if(e == ENOENT || e == ENOTDIR) {
2647 /* $NetBSD: eval.c,v 1.71 2003/01/23 03:33:16 rafal Exp $ */
2650 * Evaluate a command.
2653 /* flags in argument to evaltree */
2654 #define EV_EXIT 01 /* exit after evaluating tree */
2655 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2656 #define EV_BACKCMD 04 /* command executing within back quotes */
2659 static void evalloop(union node *, int);
2660 static void evalfor(union node *, int);
2661 static void evalcase(union node *, int);
2662 static void evalsubshell(union node *, int);
2663 static void expredir(union node *);
2664 static void evalpipe(union node *, int);
2665 static void evalcommand(union node *, int);
2666 static int evalbltin(const struct builtincmd *, int, char **);
2667 static int evalfun(struct funcnode *, int, char **, int);
2668 static void prehash(union node *);
2669 static int bltincmd(int, char **);
2672 static const struct builtincmd bltin = {
2678 * Called to reset things after an exception.
2682 * The eval commmand.
2686 evalcmd(int argc, char **argv)
2695 STARTSTACKSTR(concat);
2698 concat = stputs(p, concat);
2699 if ((p = *ap++) == NULL)
2701 STPUTC(' ', concat);
2703 STPUTC('\0', concat);
2704 p = grabstackstr(concat);
2706 evalstring(p, EV_TESTED);
2713 * Execute a command or commands contained in a string.
2717 evalstring(char *s, int flag)
2720 struct stackmark smark;
2722 setstackmark(&smark);
2725 while ((n = parsecmd(0)) != NEOF) {
2727 popstackmark(&smark);
2732 popstackmark(&smark);
2738 * Evaluate a parse tree. The value is left in the global variable
2743 evaltree(union node *n, int flags)
2746 void (*evalfn)(union node *, int);
2750 TRACE(("evaltree(NULL) called\n"));
2753 TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
2754 getpid(), n, n->type, flags));
2758 out1fmt("Node type = %d\n", n->type);
2763 evaltree(n->nnot.com, EV_TESTED);
2764 status = !exitstatus;
2767 expredir(n->nredir.redirect);
2768 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
2770 evaltree(n->nredir.n, flags & EV_TESTED);
2771 status = exitstatus;
2776 evalfn = evalcommand;
2778 if (eflag && !(flags & EV_TESTED))
2790 evalfn = evalsubshell;
2802 #error NAND + 1 != NOR
2804 #if NOR + 1 != NSEMI
2805 #error NOR + 1 != NSEMI
2807 isor = n->type - NAND;
2810 (flags | ((isor >> 1) - 1)) & EV_TESTED
2812 if (!exitstatus == isor)
2824 evaltree(n->nif.test, EV_TESTED);
2827 if (exitstatus == 0) {
2830 } else if (n->nif.elsepart) {
2831 n = n->nif.elsepart;
2836 defun(n->narg.text, n->narg.next);
2840 exitstatus = status;
2846 if (flags & EV_EXIT || checkexit & exitstatus)
2851 #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
2854 void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
2858 evalloop(union node *n, int flags)
2868 evaltree(n->nbinary.ch1, EV_TESTED);
2870 skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
2874 if (evalskip == SKIPBREAK && --skipcount <= 0)
2879 if (n->type != NWHILE)
2883 evaltree(n->nbinary.ch2, flags);
2884 status = exitstatus;
2889 exitstatus = status;
2895 evalfor(union node *n, int flags)
2897 struct arglist arglist;
2900 struct stackmark smark;
2902 setstackmark(&smark);
2903 arglist.lastp = &arglist.list;
2904 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
2905 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
2910 *arglist.lastp = NULL;
2915 for (sp = arglist.list ; sp ; sp = sp->next) {
2916 setvar(n->nfor.var, sp->text, 0);
2917 evaltree(n->nfor.body, flags);
2919 if (evalskip == SKIPCONT && --skipcount <= 0) {
2923 if (evalskip == SKIPBREAK && --skipcount <= 0)
2930 popstackmark(&smark);
2936 evalcase(union node *n, int flags)
2940 struct arglist arglist;
2941 struct stackmark smark;
2943 setstackmark(&smark);
2944 arglist.lastp = &arglist.list;
2945 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
2947 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2948 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
2949 if (casematch(patp, arglist.list->text)) {
2950 if (evalskip == 0) {
2951 evaltree(cp->nclist.body, flags);
2958 popstackmark(&smark);
2964 * Kick off a subshell to evaluate a tree.
2968 evalsubshell(union node *n, int flags)
2971 int backgnd = (n->type == NBACKGND);
2974 expredir(n->nredir.redirect);
2975 if (!backgnd && flags & EV_EXIT && !trap[0])
2979 if (forkshell(jp, n, backgnd) == 0) {
2983 flags &=~ EV_TESTED;
2985 redirect(n->nredir.redirect, 0);
2986 evaltreenr(n->nredir.n, flags);
2991 status = waitforjob(jp);
2992 exitstatus = status;
2999 * Compute the names of the files in a redirection list.
3003 expredir(union node *n)
3007 for (redir = n ; redir ; redir = redir->nfile.next) {
3009 fn.lastp = &fn.list;
3010 switch (redir->type) {
3016 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
3017 redir->nfile.expfname = fn.list->text;
3021 if (redir->ndup.vname) {
3022 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
3023 fixredir(redir, fn.list->text, 1);
3033 * Evaluate a pipeline. All the processes in the pipeline are children
3034 * of the process creating the pipeline. (This differs from some versions
3035 * of the shell, which make the last process in a pipeline the parent
3040 evalpipe(union node *n, int flags)
3043 struct nodelist *lp;
3048 TRACE(("evalpipe(0x%lx) called\n", (long)n));
3050 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
3054 jp = makejob(n, pipelen);
3056 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
3060 if (pipe(pip) < 0) {
3062 error("Pipe call failed");
3065 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
3078 evaltreenr(lp->n, flags);
3086 if (n->npipe.backgnd == 0) {
3087 exitstatus = waitforjob(jp);
3088 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
3096 * Execute a command inside back quotes. If it's a builtin command, we
3097 * want to save its output in a block obtained from malloc. Otherwise
3098 * we fork off a subprocess and get the output of the command via a pipe.
3099 * Should be called with interrupts off.
3103 evalbackcmd(union node *n, struct backcmd *result)
3115 saveherefd = herefd;
3123 error("Pipe call failed");
3125 if (forkshell(jp, n, FORK_NOJOB) == 0) {
3134 evaltreenr(n, EV_EXIT);
3138 result->fd = pip[0];
3141 herefd = saveherefd;
3143 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
3144 result->fd, result->buf, result->nleft, result->jp));
3147 #ifdef CONFIG_ASH_CMDCMD
3148 static inline char **
3149 parse_command_args(char **argv, const char **path)
3161 if (c == '-' && !*cp) {
3171 /* run 'typecmd' for other options */
3174 } while ((c = *cp++));
3183 * Execute a simple command.
3187 evalcommand(union node *cmd, int flags)
3189 struct stackmark smark;
3191 struct arglist arglist;
3192 struct arglist varlist;
3195 const struct strlist *sp;
3196 struct cmdentry cmdentry;
3205 /* First expand the arguments. */
3206 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
3207 setstackmark(&smark);
3208 back_exitstatus = 0;
3210 cmdentry.cmdtype = CMDBUILTIN;
3211 cmdentry.u.cmd = &bltin;
3212 varlist.lastp = &varlist.list;
3213 *varlist.lastp = NULL;
3214 arglist.lastp = &arglist.list;
3215 *arglist.lastp = NULL;
3218 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
3219 struct strlist **spp;
3221 spp = arglist.lastp;
3222 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
3223 for (sp = *spp; sp; sp = sp->next)
3227 argv = nargv = stalloc(sizeof (char *) * (argc + 1));
3228 for (sp = arglist.list ; sp ; sp = sp->next) {
3229 TRACE(("evalcommand arg: %s\n", sp->text));
3230 *nargv++ = sp->text;
3235 if (iflag && funcnest == 0 && argc > 0)
3236 lastarg = nargv[-1];
3239 expredir(cmd->ncmd.redirect);
3240 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH|REDIR_SAVEFD2);
3243 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
3244 struct strlist **spp;
3247 spp = varlist.lastp;
3248 expandarg(argp, &varlist, EXP_VARTILDE);
3251 * Modify the command lookup path, if a PATH= assignment
3255 if (varequal(p, path))
3259 /* Print the command if xflag is set. */
3262 const char *p = " %s";
3265 dprintf(preverrout_fd, p, ps4val());
3268 for(n = 0; n < 2; n++) {
3270 dprintf(preverrout_fd, p, sp->text);
3278 xwrite(preverrout_fd, "\n", 1);
3284 /* Now locate the command. */
3286 const char *oldpath;
3287 int cmd_flag = DO_ERR;
3292 find_command(argv[0], &cmdentry, cmd_flag, path);
3293 if (cmdentry.cmdtype == CMDUNKNOWN) {
3299 /* implement bltin and command here */
3300 if (cmdentry.cmdtype != CMDBUILTIN)
3303 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
3304 if (cmdentry.u.cmd == EXECCMD)
3306 #ifdef CONFIG_ASH_CMDCMD
3307 if (cmdentry.u.cmd == COMMANDCMD) {
3310 nargv = parse_command_args(argv, &path);
3313 argc -= nargv - argv;
3315 cmd_flag |= DO_NOFUNC;
3323 /* We have a redirection error. */
3327 exitstatus = status;
3331 /* Execute the command. */
3332 switch (cmdentry.cmdtype) {
3334 /* Fork off a child process if necessary. */
3335 if (!(flags & EV_EXIT) || trap[0]) {
3337 jp = makejob(cmd, 1);
3338 if (forkshell(jp, cmd, FORK_FG) != 0) {
3339 exitstatus = waitforjob(jp);
3345 listsetvar(varlist.list, VEXPORT|VSTACK);
3346 shellexec(argv, path, cmdentry.u.index);
3350 cmdenviron = varlist.list;
3352 struct strlist *list = cmdenviron;
3354 if (spclbltin > 0 || argc == 0) {
3356 if (cmd_is_exec && argc > 1)
3359 listsetvar(list, i);
3361 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
3376 exit_status = j + 128;
3377 exitstatus = exit_status;
3379 if (i == EXINT || spclbltin > 0) {
3381 longjmp(handler->loc, 1);
3388 listsetvar(varlist.list, 0);
3389 if (evalfun(cmdentry.u.func, argc, argv, flags))
3395 popredir(cmd_is_exec);
3397 /* dsl: I think this is intended to be used to support
3398 * '_' in 'vi' command mode during line editing...
3399 * However I implemented that within libedit itself.
3401 setvar("_", lastarg, 0);
3402 popstackmark(&smark);
3406 evalbltin(const struct builtincmd *cmd, int argc, char **argv) {
3407 char *volatile savecmdname;
3408 struct jmploc *volatile savehandler;
3409 struct jmploc jmploc;
3412 savecmdname = commandname;
3413 if ((i = setjmp(jmploc.loc)))
3415 savehandler = handler;
3417 commandname = argv[0];
3419 optptr = NULL; /* initialize nextopt */
3420 exitstatus = (*cmd->builtin)(argc, argv);
3423 exitstatus |= ferror(stdout);
3424 commandname = savecmdname;
3426 handler = savehandler;
3432 evalfun(struct funcnode *func, int argc, char **argv, int flags)
3434 volatile struct shparam saveparam;
3435 struct localvar *volatile savelocalvars;
3436 struct jmploc *volatile savehandler;
3437 struct jmploc jmploc;
3440 saveparam = shellparam;
3441 savelocalvars = localvars;
3442 if ((e = setjmp(jmploc.loc))) {
3446 savehandler = handler;
3449 shellparam.malloc = 0;
3452 shellparam.nparam = argc - 1;
3453 shellparam.p = argv + 1;
3454 #ifdef CONFIG_ASH_GETOPTS
3455 shellparam.optind = 1;
3456 shellparam.optoff = -1;
3459 evaltree(&func->n, flags & EV_TESTED);
3465 localvars = savelocalvars;
3466 freeparam(&shellparam);
3467 shellparam = saveparam;
3468 handler = savehandler;
3470 if (evalskip == SKIPFUNC) {
3479 * Search for a command. This is called before we fork so that the
3480 * location of the command will be available in the parent as well as
3485 prehash(union node *n)
3487 struct cmdentry entry;
3489 if (n->type == NCMD && n->ncmd.args)
3490 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
3496 * Builtin commands. Builtin commands whose functions are closely
3497 * tied to evaluation are implemented here.
3505 bltincmd(int argc, char **argv)
3508 * Preserve exitstatus of a previous possible redirection
3511 return back_exitstatus;
3516 * Handle break and continue commands. Break, continue, and return are
3517 * all handled by setting the evalskip flag. The evaluation routines
3518 * above all check this flag, and if it is set they start skipping
3519 * commands rather than executing them. The variable skipcount is
3520 * the number of loops to break/continue, or the number of function
3521 * levels to return. (The latter is always 1.) It should probably
3522 * be an error to break out of more loops than exist, but it isn't
3523 * in the standard shell so we don't make it one here.
3527 breakcmd(int argc, char **argv)
3529 int n = argc > 1 ? number(argv[1]) : 1;
3532 error(illnum, argv[1]);
3536 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
3544 * The return command.
3548 returncmd(int argc, char **argv)
3550 int ret = argc > 1 ? number(argv[1]) : exitstatus;
3553 evalskip = SKIPFUNC;
3558 /* Do what ksh does; skip the rest of the file */
3559 evalskip = SKIPFILE;
3567 falsecmd(int argc, char **argv)
3574 truecmd(int argc, char **argv)
3581 execcmd(int argc, char **argv)
3584 iflag = 0; /* exit on error */
3587 shellexec(argv + 1, pathval(), 0);
3593 /* $NetBSD: exec.c,v 1.35 2003/01/22 20:36:04 dsl Exp $ */
3596 * When commands are first encountered, they are entered in a hash table.
3597 * This ensures that a full path search will not have to be done for them
3598 * on each invocation.
3600 * We should investigate converting to a linear search, even though that
3601 * would make the command name "hash" a misnomer.
3604 #define CMDTABLESIZE 31 /* should be prime */
3605 #define ARB 1 /* actual size determined at run time */
3610 struct tblentry *next; /* next entry in hash chain */
3611 union param param; /* definition of builtin function */
3612 short cmdtype; /* index identifying command */
3613 char rehash; /* if set, cd done since entry created */
3614 char cmdname[ARB]; /* name of command */
3618 static struct tblentry *cmdtable[CMDTABLESIZE];
3619 static int builtinloc = -1; /* index in path of %builtin, or -1 */
3622 static void tryexec(char *, char **, char **);
3623 static void clearcmdentry(int);
3624 static struct tblentry *cmdlookup(const char *, int);
3625 static void delete_cmd_entry(void);
3629 * Exec a program. Never returns. If you change this routine, you may
3630 * have to change the find_command routine as well.
3634 shellexec(char **argv, const char *path, int idx)
3641 envp = environment();
3642 if (strchr(argv[0], '/') != NULL
3643 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3644 || find_applet_by_name(argv[0])
3647 tryexec(argv[0], argv, envp);
3651 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3652 if (--idx < 0 && pathopt == NULL) {
3653 tryexec(cmdname, argv, envp);
3654 if (errno != ENOENT && errno != ENOTDIR)
3661 /* Map to POSIX errors */
3673 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
3674 argv[0], e, suppressint ));
3675 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3681 tryexec(char *cmd, char **argv, char **envp)
3684 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3688 #ifdef CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN
3689 name = bb_get_last_path_component(name);
3690 if(find_applet_by_name(name) != NULL)
3693 if(strchr(name, '/') == NULL && find_applet_by_name(name) != NULL) {
3702 if(strcmp(name, "busybox")) {
3703 for (ap = argv; *ap; ap++);
3704 ap = new = xmalloc((ap - argv + 2) * sizeof(char *));
3705 *ap++ = cmd = "/bin/busybox";
3706 while ((*ap++ = *argv++));
3710 cmd = "/bin/busybox";
3718 execve(cmd, argv, envp);
3719 } while (errno == EINTR);
3721 execve(cmd, argv, envp);
3725 } else if (errno == ENOEXEC) {
3729 for (ap = argv; *ap; ap++)
3731 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
3732 *ap++ = cmd = "/bin/sh";
3733 while ((*ap++ = *argv++))
3743 * Do a path search. The variable path (passed by reference) should be
3744 * set to the start of the path before the first call; padvance will update
3745 * this value as it proceeds. Successive calls to padvance will return
3746 * the possible path expansions in sequence. If an option (indicated by
3747 * a percent sign) appears in the path entry then the global variable
3748 * pathopt will be set to point to it; otherwise pathopt will be set to
3753 padvance(const char **path, const char *name)
3763 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
3764 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
3765 while (stackblocksize() < len)
3769 memcpy(q, start, p - start);
3777 while (*p && *p != ':') p++;
3783 return stalloc(len);
3787 /*** Command hashing code ***/
3790 printentry(struct tblentry *cmdp)
3796 idx = cmdp->param.index;
3799 name = padvance(&path, cmdp->cmdname);
3801 } while (--idx >= 0);
3802 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
3807 hashcmd(int argc, char **argv)
3809 struct tblentry **pp;
3810 struct tblentry *cmdp;
3812 struct cmdentry entry;
3815 while ((c = nextopt("r")) != '\0') {
3819 if (*argptr == NULL) {
3820 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3821 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3822 if (cmdp->cmdtype == CMDNORMAL)
3829 while ((name = *argptr) != NULL) {
3830 if ((cmdp = cmdlookup(name, 0)) != NULL
3831 && (cmdp->cmdtype == CMDNORMAL
3832 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
3834 find_command(name, &entry, DO_ERR, pathval());
3835 if (entry.cmdtype == CMDUNKNOWN)
3844 * Resolve a command name. If you change this routine, you may have to
3845 * change the shellexec routine as well.
3849 find_command(char *name, struct cmdentry *entry, int act, const char *path)
3851 struct tblentry *cmdp;
3858 struct builtincmd *bcmd;
3860 /* If name contains a slash, don't use PATH or hash table */
3861 if (strchr(name, '/') != NULL) {
3862 entry->u.index = -1;
3864 while (stat(name, &statb) < 0) {
3869 entry->cmdtype = CMDUNKNOWN;
3873 entry->cmdtype = CMDNORMAL;
3877 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3878 if (find_applet_by_name(name)) {
3879 entry->cmdtype = CMDNORMAL;
3880 entry->u.index = -1;
3885 updatetbl = (path == pathval());
3888 if (strstr(path, "%builtin") != NULL)
3892 /* If name is in the table, check answer will be ok */
3893 if ((cmdp = cmdlookup(name, 0)) != NULL) {
3896 switch (cmdp->cmdtype) {
3914 } else if (cmdp->rehash == 0)
3915 /* if not invalidated by cd, we're done */
3919 /* If %builtin not in path, check for builtin next */
3920 bcmd = find_builtin(name);
3921 if (bcmd && (IS_BUILTIN_REGULAR(bcmd) || (
3922 act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0
3924 goto builtin_success;
3926 /* We have to search path. */
3927 prev = -1; /* where to start */
3928 if (cmdp && cmdp->rehash) { /* doing a rehash */
3929 if (cmdp->cmdtype == CMDBUILTIN)
3932 prev = cmdp->param.index;
3938 while ((fullname = padvance(&path, name)) != NULL) {
3939 stunalloc(fullname);
3942 if (prefix(pathopt, "builtin")) {
3944 goto builtin_success;
3946 } else if (!(act & DO_NOFUNC) &&
3947 prefix(pathopt, "func")) {
3950 /* ignore unimplemented options */
3954 /* if rehash, don't redo absolute path names */
3955 if (fullname[0] == '/' && idx <= prev) {
3958 TRACE(("searchexec \"%s\": no change\n", name));
3961 while (stat(fullname, &statb) < 0) {
3966 if (errno != ENOENT && errno != ENOTDIR)
3970 e = EACCES; /* if we fail, this will be the error */
3971 if (!S_ISREG(statb.st_mode))
3973 if (pathopt) { /* this is a %func directory */
3974 stalloc(strlen(fullname) + 1);
3975 readcmdfile(fullname);
3976 if ((cmdp = cmdlookup(name, 0)) == NULL ||
3977 cmdp->cmdtype != CMDFUNCTION)
3978 error("%s not defined in %s", name, fullname);
3979 stunalloc(fullname);
3982 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
3984 entry->cmdtype = CMDNORMAL;
3985 entry->u.index = idx;
3989 cmdp = cmdlookup(name, 1);
3990 cmdp->cmdtype = CMDNORMAL;
3991 cmdp->param.index = idx;
3996 /* We failed. If there was an entry for this command, delete it */
3997 if (cmdp && updatetbl)
4000 sh_warnx("%s: %s", name, errmsg(e, E_EXEC));
4001 entry->cmdtype = CMDUNKNOWN;
4006 entry->cmdtype = CMDBUILTIN;
4007 entry->u.cmd = bcmd;
4011 cmdp = cmdlookup(name, 1);
4012 cmdp->cmdtype = CMDBUILTIN;
4013 cmdp->param.cmd = bcmd;
4017 entry->cmdtype = cmdp->cmdtype;
4018 entry->u = cmdp->param;
4023 * Wrapper around strcmp for qsort/bsearch/...
4025 static int pstrcmp(const void *a, const void *b)
4027 return strcmp((const char *) a, (*(const char *const *) b) + 1);
4031 * Search the table of builtin commands.
4034 static struct builtincmd *
4035 find_builtin(const char *name)
4037 struct builtincmd *bp;
4040 name, builtincmd, NUMBUILTINS, sizeof(struct builtincmd),
4049 * Called when a cd is done. Marks all commands so the next time they
4050 * are executed they will be rehashed.
4056 struct tblentry **pp;
4057 struct tblentry *cmdp;
4059 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4060 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4061 if (cmdp->cmdtype == CMDNORMAL || (
4062 cmdp->cmdtype == CMDBUILTIN &&
4063 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) &&
4074 * Fix command hash table when PATH changed.
4075 * Called before PATH is changed. The argument is the new value of PATH;
4076 * pathval() still returns the old value at this point.
4077 * Called with interrupts off.
4081 changepath(const char *newval)
4083 const char *old, *new;
4090 firstchange = 9999; /* assume no change */
4096 if ((*old == '\0' && *new == ':')
4097 || (*old == ':' && *new == '\0'))
4099 old = new; /* ignore subsequent differences */
4103 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
4110 if (builtinloc < 0 && idx_bltin >= 0)
4111 builtinloc = idx_bltin; /* zap builtins */
4112 if (builtinloc >= 0 && idx_bltin < 0)
4114 clearcmdentry(firstchange);
4115 builtinloc = idx_bltin;
4120 * Clear out command entries. The argument specifies the first entry in
4121 * PATH which has changed.
4125 clearcmdentry(int firstchange)
4127 struct tblentry **tblp;
4128 struct tblentry **pp;
4129 struct tblentry *cmdp;
4132 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4134 while ((cmdp = *pp) != NULL) {
4135 if ((cmdp->cmdtype == CMDNORMAL &&
4136 cmdp->param.index >= firstchange)
4137 || (cmdp->cmdtype == CMDBUILTIN &&
4138 builtinloc >= firstchange)) {
4152 * Locate a command in the command hash table. If "add" is nonzero,
4153 * add the command to the table if it is not already present. The
4154 * variable "lastcmdentry" is set to point to the address of the link
4155 * pointing to the entry, so that delete_cmd_entry can delete the
4158 * Interrupts must be off if called with add != 0.
4161 static struct tblentry **lastcmdentry;
4164 static struct tblentry *
4165 cmdlookup(const char *name, int add)
4167 unsigned int hashval;
4169 struct tblentry *cmdp;
4170 struct tblentry **pp;
4173 hashval = (unsigned char)*p << 4;
4175 hashval += (unsigned char)*p++;
4177 pp = &cmdtable[hashval % CMDTABLESIZE];
4178 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4179 if (equal(cmdp->cmdname, name))
4183 if (add && cmdp == NULL) {
4184 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4185 + strlen(name) + 1);
4187 cmdp->cmdtype = CMDUNKNOWN;
4188 strcpy(cmdp->cmdname, name);
4195 * Delete the command entry returned on the last lookup.
4199 delete_cmd_entry(void)
4201 struct tblentry *cmdp;
4204 cmdp = *lastcmdentry;
4205 *lastcmdentry = cmdp->next;
4206 if (cmdp->cmdtype == CMDFUNCTION)
4207 freefunc(cmdp->param.func);
4214 * Add a new command entry, replacing any existing command entry for
4215 * the same name - except special builtins.
4219 addcmdentry(char *name, struct cmdentry *entry)
4221 struct tblentry *cmdp;
4223 cmdp = cmdlookup(name, 1);
4224 if (cmdp->cmdtype == CMDFUNCTION) {
4225 freefunc(cmdp->param.func);
4227 cmdp->cmdtype = entry->cmdtype;
4228 cmdp->param = entry->u;
4233 * Make a copy of a parse tree.
4236 static inline struct funcnode *
4237 copyfunc(union node *n)
4242 funcblocksize = offsetof(struct funcnode, n);
4245 blocksize = funcblocksize;
4246 f = ckmalloc(blocksize + funcstringsize);
4247 funcblock = (char *) f + offsetof(struct funcnode, n);
4248 funcstring = (char *) f + blocksize;
4255 * Define a shell function.
4259 defun(char *name, union node *func)
4261 struct cmdentry entry;
4264 entry.cmdtype = CMDFUNCTION;
4265 entry.u.func = copyfunc(func);
4266 addcmdentry(name, &entry);
4272 * Delete a function if it exists.
4276 unsetfunc(const char *name)
4278 struct tblentry *cmdp;
4280 if ((cmdp = cmdlookup(name, 0)) != NULL &&
4281 cmdp->cmdtype == CMDFUNCTION)
4286 * Locate and print what a word is...
4290 #ifdef CONFIG_ASH_CMDCMD
4292 describe_command(char *command, int describe_command_verbose)
4294 #define describe_command_verbose 1
4296 describe_command(char *command)
4299 struct cmdentry entry;
4300 struct tblentry *cmdp;
4301 #ifdef CONFIG_ASH_ALIAS
4302 const struct alias *ap;
4304 const char *path = pathval();
4306 if (describe_command_verbose) {
4310 /* First look at the keywords */
4311 if (findkwd(command)) {
4312 out1str(describe_command_verbose ? " is a shell keyword" : command);
4316 #ifdef CONFIG_ASH_ALIAS
4317 /* Then look at the aliases */
4318 if ((ap = lookupalias(command, 0)) != NULL) {
4319 if (describe_command_verbose) {
4320 out1fmt(" is an alias for %s", ap->val);
4329 /* Then check if it is a tracked alias */
4330 if ((cmdp = cmdlookup(command, 0)) != NULL) {
4331 entry.cmdtype = cmdp->cmdtype;
4332 entry.u = cmdp->param;
4334 /* Finally use brute force */
4335 find_command(command, &entry, DO_ABS, path);
4338 switch (entry.cmdtype) {
4340 int j = entry.u.index;
4346 p = padvance(&path, command);
4350 if (describe_command_verbose) {
4352 (cmdp ? " a tracked alias for" : nullstr), p
4361 if (describe_command_verbose) {
4362 out1str(" is a shell function");
4369 if (describe_command_verbose) {
4370 out1fmt(" is a %sshell builtin",
4371 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
4372 "special " : nullstr
4380 if (describe_command_verbose) {
4381 out1str(": not found\n");
4387 outstr("\n", stdout);
4392 typecmd(int argc, char **argv)
4397 for (i = 1; i < argc; i++) {
4398 #ifdef CONFIG_ASH_CMDCMD
4399 err |= describe_command(argv[i], 1);
4401 err |= describe_command(argv[i]);
4407 #ifdef CONFIG_ASH_CMDCMD
4409 commandcmd(int argc, char **argv)
4412 int default_path = 0;
4413 int verify_only = 0;
4414 int verbose_verify_only = 0;
4416 while ((c = nextopt("pvV")) != '\0')
4421 "command: nextopt returned character code 0%o\n", c);
4431 verbose_verify_only = 1;
4435 if (default_path + verify_only + verbose_verify_only > 1 ||
4438 "command [-p] command [arg ...]\n"
4439 "command {-v|-V} command\n");
4443 if (verify_only || verbose_verify_only) {
4444 return describe_command(*argptr, verbose_verify_only);
4451 /* $NetBSD: expand.c,v 1.56 2002/11/24 22:35:39 christos Exp $ */
4454 * Routines to expand arguments to commands. We have to deal with
4455 * backquotes, shell variables, and file metacharacters.
4461 #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4462 #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
4463 #define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
4464 #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
4465 #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
4468 * Structure specifying which parts of the string should be searched
4469 * for IFS characters.
4473 struct ifsregion *next; /* next region in list */
4474 int begoff; /* offset of start of region */
4475 int endoff; /* offset of end of region */
4476 int nulonly; /* search for nul bytes only */
4479 /* output of current string */
4480 static char *expdest;
4481 /* list of back quote expressions */
4482 static struct nodelist *argbackq;
4483 /* first struct in list of ifs regions */
4484 static struct ifsregion ifsfirst;
4485 /* last struct in list */
4486 static struct ifsregion *ifslastp;
4487 /* holds expanded arg list */
4488 static struct arglist exparg;
4490 static void argstr(char *, int);
4491 static char *exptilde(char *, char *, int);
4492 static void expbackq(union node *, int, int);
4493 static const char *subevalvar(char *, char *, int, int, int, int, int);
4494 static char *evalvar(char *, int);
4495 static int varisset(char *, int);
4496 static void strtodest(const char *, int, int);
4497 static void memtodest(const char *p, size_t len, int syntax, int quotes);
4498 static void varvalue(char *, int, int);
4499 static void recordregion(int, int, int);
4500 static void removerecordregions(int);
4501 static void ifsbreakup(char *, struct arglist *);
4502 static void ifsfree(void);
4503 static void expandmeta(struct strlist *, int);
4504 static int patmatch(char *, const char *);
4506 static int cvtnum(long);
4507 static size_t esclen(const char *, const char *);
4508 static char *scanleft(char *, char *, char *, char *, int, int);
4509 static char *scanright(char *, char *, char *, char *, int, int);
4510 static void varunset(const char *, const char *, const char *, int)
4511 __attribute__((__noreturn__));
4514 #define pmatch(a, b) !fnmatch((a), (b), 0)
4516 * Prepare a pattern for a expmeta (internal glob(3)) call.
4518 * Returns an stalloced string.
4521 static inline char *
4522 preglob(const char *pattern, int quoted, int flag) {
4523 flag |= RMESCAPE_GLOB;
4525 flag |= RMESCAPE_QUOTED;
4527 return _rmescapes((char *)pattern, flag);
4532 esclen(const char *start, const char *p) {
4535 while (p > start && *--p == CTLESC) {
4543 * Expand shell variables and backquotes inside a here document.
4547 expandhere(union node *arg, int fd)
4550 expandarg(arg, (struct arglist *)NULL, 0);
4551 xwrite(fd, stackblock(), expdest - (char *)stackblock());
4556 * Perform variable substitution and command substitution on an argument,
4557 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4558 * perform splitting and file name expansion. When arglist is NULL, perform
4559 * here document expansion.
4563 expandarg(union node *arg, struct arglist *arglist, int flag)
4568 argbackq = arg->narg.backquote;
4569 STARTSTACKSTR(expdest);
4570 ifsfirst.next = NULL;
4572 argstr(arg->narg.text, flag);
4573 if (arglist == NULL) {
4574 return; /* here document expanded */
4576 STPUTC('\0', expdest);
4577 p = grabstackstr(expdest);
4578 exparg.lastp = &exparg.list;
4582 if (flag & EXP_FULL) {
4583 ifsbreakup(p, &exparg);
4584 *exparg.lastp = NULL;
4585 exparg.lastp = &exparg.list;
4586 expandmeta(exparg.list, flag);
4588 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
4590 sp = (struct strlist *)stalloc(sizeof (struct strlist));
4593 exparg.lastp = &sp->next;
4597 *exparg.lastp = NULL;
4599 *arglist->lastp = exparg.list;
4600 arglist->lastp = exparg.lastp;
4606 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4607 * characters to allow for further processing. Otherwise treat
4608 * $@ like $* since no splitting will be performed.
4612 argstr(char *p, int flag)
4614 static const char spclchars[] = {
4622 CTLBACKQ | CTLQUOTE,
4623 #ifdef CONFIG_ASH_MATH_SUPPORT
4628 const char *reject = spclchars;
4630 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
4631 int breakall = flag & EXP_WORD;
4636 if (!(flag & EXP_VARTILDE)) {
4638 } else if (flag & EXP_VARTILDE2) {
4643 if (flag & EXP_TILDE) {
4649 if (*q == CTLESC && (flag & EXP_QWORD))
4652 p = exptilde(p, q, flag);
4655 startloc = expdest - (char *)stackblock();
4657 length += strcspn(p + length, reject);
4659 if (c && (!(c & 0x80)
4660 #ifdef CONFIG_ASH_MATH_SUPPORT
4664 /* c == '=' || c == ':' || c == CTLENDARI */
4669 expdest = stnputs(p, length, expdest);
4670 newloc = expdest - (char *)stackblock();
4671 if (breakall && !inquotes && newloc > startloc) {
4672 recordregion(startloc, newloc, 0);
4683 if (flag & EXP_VARTILDE2) {
4687 flag |= EXP_VARTILDE2;
4692 * sort of a hack - expand tildes in variable
4693 * assignments (after the first '=' and after ':'s).
4702 case CTLENDVAR: /* ??? */
4705 /* "$@" syntax adherence hack */
4708 !memcmp(p, dolatstr, DOLATSTRLEN) &&
4709 (p[4] == CTLQUOTEMARK || (
4710 p[4] == CTLENDVAR &&
4711 p[5] == CTLQUOTEMARK
4714 p = evalvar(p + 1, flag) + 1;
4717 inquotes = !inquotes;
4730 p = evalvar(p, flag);
4734 case CTLBACKQ|CTLQUOTE:
4735 expbackq(argbackq->n, c, quotes);
4736 argbackq = argbackq->next;
4738 #ifdef CONFIG_ASH_MATH_SUPPORT
4751 exptilde(char *startp, char *p, int flag)
4757 int quotes = flag & (EXP_FULL | EXP_CASE);
4762 while ((c = *++p) != '\0') {
4769 if (flag & EXP_VARTILDE)
4779 if (*name == '\0') {
4780 if ((home = lookupvar(homestr)) == NULL)
4783 if ((pw = getpwnam(name)) == NULL)
4790 startloc = expdest - (char *)stackblock();
4791 strtodest(home, SQSYNTAX, quotes);
4792 recordregion(startloc, expdest - (char *)stackblock(), 0);
4801 removerecordregions(int endoff)
4803 if (ifslastp == NULL)
4806 if (ifsfirst.endoff > endoff) {
4807 while (ifsfirst.next != NULL) {
4808 struct ifsregion *ifsp;
4810 ifsp = ifsfirst.next->next;
4811 ckfree(ifsfirst.next);
4812 ifsfirst.next = ifsp;
4815 if (ifsfirst.begoff > endoff)
4818 ifslastp = &ifsfirst;
4819 ifsfirst.endoff = endoff;
4824 ifslastp = &ifsfirst;
4825 while (ifslastp->next && ifslastp->next->begoff < endoff)
4826 ifslastp=ifslastp->next;
4827 while (ifslastp->next != NULL) {
4828 struct ifsregion *ifsp;
4830 ifsp = ifslastp->next->next;
4831 ckfree(ifslastp->next);
4832 ifslastp->next = ifsp;
4835 if (ifslastp->endoff > endoff)
4836 ifslastp->endoff = endoff;
4840 #ifdef CONFIG_ASH_MATH_SUPPORT
4842 * Expand arithmetic expression. Backup to start of expression,
4843 * evaluate, place result in (backed up) result, adjust string position.
4856 * This routine is slightly over-complicated for
4857 * efficiency. Next we scan backwards looking for the
4858 * start of arithmetic.
4860 start = stackblock();
4867 while (*p != CTLARI) {
4871 error("missing CTLARI (shouldn't happen)");
4876 esc = esclen(start, p);
4886 removerecordregions(begoff);
4895 len = cvtnum(dash_arith(p + 2));
4898 recordregion(begoff, begoff + len, 0);
4903 * Expand stuff in backwards quotes.
4907 expbackq(union node *cmd, int quoted, int quotes)
4915 int syntax = quoted? DQSYNTAX : BASESYNTAX;
4916 struct stackmark smark;
4919 setstackmark(&smark);
4921 startloc = dest - (char *)stackblock();
4923 evalbackcmd(cmd, (struct backcmd *) &in);
4924 popstackmark(&smark);
4931 memtodest(p, i, syntax, quotes);
4935 i = safe_read(in.fd, buf, sizeof buf);
4936 TRACE(("expbackq: read returns %d\n", i));
4946 back_exitstatus = waitforjob(in.jp);
4950 /* Eat all trailing newlines */
4952 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
4957 recordregion(startloc, dest - (char *)stackblock(), 0);
4958 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4959 (dest - (char *)stackblock()) - startloc,
4960 (dest - (char *)stackblock()) - startloc,
4961 stackblock() + startloc));
4966 scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
4977 const char *s = loc2;
4983 match = pmatch(str, s);
4987 if (quotes && *loc == CTLESC)
4997 scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5004 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5007 const char *s = loc2;
5012 match = pmatch(str, s);
5019 esc = esclen(startp, loc);
5031 subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
5035 int saveherefd = herefd;
5036 struct nodelist *saveargbackq = argbackq;
5038 char *rmesc, *rmescend;
5040 char *(*scan)(char *, char *, char *, char *, int , int);
5043 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
5044 STPUTC('\0', expdest);
5045 herefd = saveherefd;
5046 argbackq = saveargbackq;
5047 startp = stackblock() + startloc;
5051 setvar(str, startp, 0);
5052 amount = startp - expdest;
5053 STADJUST(amount, expdest);
5057 varunset(p, str, startp, varflags);
5061 subtype -= VSTRIMRIGHT;
5063 if (subtype < 0 || subtype > 3)
5068 rmescend = stackblock() + strloc;
5070 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5071 if (rmesc != startp) {
5073 startp = stackblock() + startloc;
5077 str = stackblock() + strloc;
5078 preglob(str, varflags & VSQUOTE, 0);
5080 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
5081 zero = subtype >> 1;
5082 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
5083 scan = (subtype & 1) ^ zero ? scanleft : scanright;
5085 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
5088 memmove(startp, loc, str - loc);
5089 loc = startp + (str - loc) - 1;
5092 amount = loc - expdest;
5093 STADJUST(amount, expdest);
5100 * Expand a variable, and return a pointer to the next character in the
5104 evalvar(char *p, int flag)
5118 quotes = flag & (EXP_FULL | EXP_CASE);
5120 subtype = varflags & VSTYPE;
5121 quoted = varflags & VSQUOTE;
5123 easy = (!quoted || (*var == '@' && shellparam.nparam));
5125 startloc = expdest - (char *)stackblock();
5126 p = strchr(p, '=') + 1;
5128 if (!is_name(*var)) {
5129 set = varisset(var, varflags & VSNUL);
5131 if (subtype == VSPLUS)
5134 varvalue(var, quoted, flag);
5135 if (subtype == VSLENGTH) {
5137 expdest - (char *)stackblock() -
5139 STADJUST(-varlen, expdest);
5146 /* jump here after setting a variable with ${var=text} */
5147 val = lookupvar(var);
5148 set = !val || ((varflags & VSNUL) && !*val);
5149 if (subtype == VSPLUS)
5152 varlen = strlen(val);
5153 if (subtype == VSLENGTH)
5156 val, varlen, quoted ? DQSYNTAX : BASESYNTAX,
5163 if (subtype == VSMINUS) {
5167 p, flag | EXP_TILDE |
5168 (quoted ? EXP_QWORD : EXP_WORD)
5177 if (subtype == VSASSIGN || subtype == VSQUESTION) {
5179 if (subevalvar(p, var, 0, subtype, startloc,
5183 * Remove any recorded regions beyond
5186 removerecordregions(startloc);
5197 varunset(p, var, 0, 0);
5199 if (subtype == VSLENGTH) {
5205 if (subtype == VSNORMAL) {
5209 recordregion(startloc, expdest - (char *)stackblock(), quoted);
5218 case VSTRIMRIGHTMAX:
5227 * Terminate the string and start recording the pattern
5230 STPUTC('\0', expdest);
5231 patloc = expdest - (char *)stackblock();
5232 if (subevalvar(p, NULL, patloc, subtype,
5233 startloc, varflags, quotes) == 0) {
5234 int amount = expdest - (
5235 (char *)stackblock() + patloc - 1
5237 STADJUST(-amount, expdest);
5239 /* Remove any recorded regions beyond start of variable */
5240 removerecordregions(startloc);
5245 if (subtype != VSNORMAL) { /* skip to end of alternative */
5248 if ((c = *p++) == CTLESC)
5250 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
5252 argbackq = argbackq->next;
5253 } else if (c == CTLVAR) {
5254 if ((*p++ & VSTYPE) != VSNORMAL)
5256 } else if (c == CTLENDVAR) {
5268 * Test whether a specialized variable is set.
5272 varisset(char *name, int nulok)
5275 return backgndpid != 0;
5276 else if (*name == '@' || *name == '*') {
5277 if (*shellparam.p == NULL)
5283 for (av = shellparam.p; *av; av++)
5288 } else if (is_digit(*name)) {
5290 int num = atoi(name);
5292 if (num > shellparam.nparam)
5298 ap = shellparam.p[num - 1];
5300 if (nulok && (ap == NULL || *ap == '\0'))
5308 * Put a string on the stack.
5312 memtodest(const char *p, size_t len, int syntax, int quotes) {
5315 q = makestrspace(len * 2, q);
5321 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5331 strtodest(const char *p, int syntax, int quotes)
5333 memtodest(p, strlen(p), syntax, quotes);
5338 * Add the value of a specialized variable to the stack string.
5342 varvalue(char *name, int quoted, int flags)
5351 int allow_split = flags & EXP_FULL;
5352 int quotes = flags & (EXP_FULL | EXP_CASE);
5354 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5363 num = shellparam.nparam;
5371 for (i = 0 ; i < NOPTS ; i++) {
5373 STPUTC(optletters(i), expdest);
5377 if (allow_split && quoted) {
5378 sep = 1 << CHAR_BIT;
5383 sep = ifsset() ? ifsval()[0] : ' ';
5385 sepq = (SIT(sep, syntax) == CCTL) || (SIT(sep, syntax) == CBACK);
5388 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
5389 strtodest(p, syntax, quotes);
5400 strtodest(arg0, syntax, quotes);
5404 if (num > 0 && num <= shellparam.nparam) {
5405 strtodest(shellparam.p[num - 1], syntax, quotes);
5413 * Record the fact that we have to scan this region of the
5414 * string for IFS characters.
5418 recordregion(int start, int end, int nulonly)
5420 struct ifsregion *ifsp;
5422 if (ifslastp == NULL) {
5426 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
5428 ifslastp->next = ifsp;
5432 ifslastp->begoff = start;
5433 ifslastp->endoff = end;
5434 ifslastp->nulonly = nulonly;
5439 * Break the argument string into pieces based upon IFS and add the
5440 * strings to the argument list. The regions of the string to be
5441 * searched for IFS characters have been stored by recordregion.
5444 ifsbreakup(char *string, struct arglist *arglist)
5446 struct ifsregion *ifsp;
5451 const char *ifs, *realifs;
5457 if (ifslastp != NULL) {
5460 realifs = ifsset() ? ifsval() : defifs;
5463 p = string + ifsp->begoff;
5464 nulonly = ifsp->nulonly;
5465 ifs = nulonly ? nullstr : realifs;
5467 while (p < string + ifsp->endoff) {
5471 if (strchr(ifs, *p)) {
5473 ifsspc = (strchr(defifs, *p) != NULL);
5474 /* Ignore IFS whitespace at start */
5475 if (q == start && ifsspc) {
5481 sp = (struct strlist *)stalloc(sizeof *sp);
5483 *arglist->lastp = sp;
5484 arglist->lastp = &sp->next;
5488 if (p >= string + ifsp->endoff) {
5494 if (strchr(ifs, *p) == NULL ) {
5497 } else if (strchr(defifs, *p) == NULL) {
5513 } while ((ifsp = ifsp->next) != NULL);
5522 sp = (struct strlist *)stalloc(sizeof *sp);
5524 *arglist->lastp = sp;
5525 arglist->lastp = &sp->next;
5531 struct ifsregion *p;
5536 struct ifsregion *ifsp;
5542 ifsfirst.next = NULL;
5546 static void expmeta(char *, char *);
5547 static struct strlist *expsort(struct strlist *);
5548 static struct strlist *msort(struct strlist *, int);
5550 static char *expdir;
5554 expandmeta(struct strlist *str, int flag)
5556 static const char metachars[] = {
5559 /* TODO - EXP_REDIR */
5562 struct strlist **savelastp;
5568 if (!strpbrk(str->text, metachars))
5570 savelastp = exparg.lastp;
5573 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
5575 int i = strlen(str->text);
5576 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5584 if (exparg.lastp == savelastp) {
5589 *exparg.lastp = str;
5590 rmescapes(str->text);
5591 exparg.lastp = &str->next;
5593 *exparg.lastp = NULL;
5594 *savelastp = sp = expsort(*savelastp);
5595 while (sp->next != NULL)
5597 exparg.lastp = &sp->next;
5604 * Add a file name to the list.
5608 addfname(const char *name)
5612 sp = (struct strlist *)stalloc(sizeof *sp);
5613 sp->text = sstrdup(name);
5615 exparg.lastp = &sp->next;
5620 * Do metacharacter (i.e. *, ?, [...]) expansion.
5624 expmeta(char *enddir, char *name)
5631 struct stat64 statb;
5639 for (p = name; *p; p++) {
5640 if (*p == '*' || *p == '?')
5642 else if (*p == '[') {
5649 if (*q == '/' || *q == '\0')
5656 } else if (*p == '\\')
5658 else if (*p == '/') {
5665 if (metaflag == 0) { /* we've reached the end of the file name */
5666 if (enddir != expdir)
5674 if (metaflag == 0 || lstat64(expdir, &statb) >= 0)
5685 } while (p < start);
5687 if (enddir == expdir) {
5689 } else if (enddir == expdir + 1 && *expdir == '/') {
5695 if ((dirp = opendir(cp)) == NULL)
5697 if (enddir != expdir)
5699 if (*endname == 0) {
5711 while (! intpending && (dp = readdir(dirp)) != NULL) {
5712 if (dp->d_name[0] == '.' && ! matchdot)
5714 if (pmatch(start, dp->d_name)) {
5716 scopy(dp->d_name, enddir);
5719 for (p = enddir, cp = dp->d_name;
5720 (*p++ = *cp++) != '\0';)
5723 expmeta(p, endname);
5733 * Sort the results of file name expansion. It calculates the number of
5734 * strings to sort and then calls msort (short for merge sort) to do the
5738 static struct strlist *
5739 expsort(struct strlist *str)
5745 for (sp = str ; sp ; sp = sp->next)
5747 return msort(str, len);
5751 static struct strlist *
5752 msort(struct strlist *list, int len)
5754 struct strlist *p, *q = NULL;
5755 struct strlist **lpp;
5763 for (n = half ; --n >= 0 ; ) {
5767 q->next = NULL; /* terminate first half of list */
5768 q = msort(list, half); /* sort first half of list */
5769 p = msort(p, len - half); /* sort second half */
5772 #ifdef CONFIG_LOCALE_SUPPORT
5773 if (strcoll(p->text, q->text) < 0)
5775 if (strcmp(p->text, q->text) < 0)
5780 if ((p = *lpp) == NULL) {
5787 if ((q = *lpp) == NULL) {
5798 * Returns true if the pattern matches the string.
5802 patmatch(char *pattern, const char *string)
5804 return pmatch(preglob(pattern, 0, 0), string);
5809 * Remove any CTLESC characters from a string.
5813 _rmescapes(char *str, int flag)
5816 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
5821 p = strpbrk(str, qchars);
5827 if (flag & RMESCAPE_ALLOC) {
5828 size_t len = p - str;
5829 size_t fulllen = len + strlen(p) + 1;
5831 if (flag & RMESCAPE_GROW) {
5832 r = makestrspace(fulllen, expdest);
5833 } else if (flag & RMESCAPE_HEAP) {
5834 r = ckmalloc(fulllen);
5836 r = stalloc(fulllen);
5840 q = mempcpy(q, str, len);
5843 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5844 globbing = flag & RMESCAPE_GLOB;
5845 notescaped = globbing;
5847 if (*p == CTLQUOTEMARK) {
5848 inquotes = ~inquotes;
5850 notescaped = globbing;
5854 /* naked back slash */
5860 if (notescaped && inquotes && *p != '/') {
5864 notescaped = globbing;
5869 if (flag & RMESCAPE_GROW) {
5871 STADJUST(q - r + 1, expdest);
5878 * See if a pattern matches in a case statement.
5882 casematch(union node *pattern, char *val)
5884 struct stackmark smark;
5887 setstackmark(&smark);
5888 argbackq = pattern->narg.backquote;
5889 STARTSTACKSTR(expdest);
5891 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
5892 STACKSTRNUL(expdest);
5893 result = patmatch(stackblock(), val);
5894 popstackmark(&smark);
5907 expdest = makestrspace(32, expdest);
5908 len = fmtstr(expdest, 32, "%ld", num);
5909 STADJUST(len, expdest);
5914 varunset(const char *end, const char *var, const char *umsg, int varflags)
5920 msg = "parameter not set";
5922 if (*end == CTLENDVAR) {
5923 if (varflags & VSNUL)
5928 error("%.*s: %s%s", end - var - 1, var, msg, tail);
5932 /* $NetBSD: input.c,v 1.37 2002/11/24 22:35:40 christos Exp $ */
5935 * This implements the input routines used by the parser.
5938 #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
5939 #define IBUFSIZ (BUFSIZ + 1)
5941 static void pushfile(void);
5944 * Read a line from the script.
5947 static inline char *
5948 pfgets(char *line, int len)
5954 while (--nleft > 0) {
5971 * Read a character from the script, returning PEOF on end of file.
5972 * Nul characters in the input are silently discarded.
5975 #define pgetc_as_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
5977 #ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
5978 #define pgetc_macro() pgetc()
5982 return pgetc_as_macro();
5985 #define pgetc_macro() pgetc_as_macro()
5989 return pgetc_macro();
5995 * Same as pgetc(), but ignores PEOA.
5997 #ifdef CONFIG_ASH_ALIAS
5998 static int pgetc2(void)
6004 } while (c == PEOA);
6008 static inline int pgetc2(void)
6010 return pgetc_macro();
6015 #ifdef CONFIG_FEATURE_COMMAND_EDITING
6016 static const char *cmdedit_prompt;
6017 static inline void putprompt(const char *s)
6022 static inline void putprompt(const char *s)
6032 char *buf = parsefile->buf;
6036 #ifdef CONFIG_FEATURE_COMMAND_EDITING
6037 if (!iflag || parsefile->fd)
6038 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6040 nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
6042 /* Ctrl+C presend */
6047 /* Ctrl+D presend */
6052 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6056 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6057 int flags = fcntl(0, F_GETFL, 0);
6058 if (flags >= 0 && flags & O_NONBLOCK) {
6059 flags &=~ O_NONBLOCK;
6060 if (fcntl(0, F_SETFL, flags) >= 0) {
6061 out2str("sh: turning off NDELAY mode\n");
6071 * Refill the input buffer and return the next input character:
6073 * 1) If a string was pushed back on the input, pop it;
6074 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6075 * from a string so we can't refill the buffer, return EOF.
6076 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6077 * 4) Process input up to the next newline, deleting nul characters.
6087 while (parsefile->strpush) {
6088 #ifdef CONFIG_ASH_ALIAS
6089 if (parsenleft == -1 && parsefile->strpush->ap &&
6090 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
6095 if (--parsenleft >= 0)
6096 return (*parsenextc++);
6098 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6103 if (parselleft <= 0) {
6104 if ((parselleft = preadfd()) <= 0) {
6105 parselleft = parsenleft = EOF_NLEFT;
6112 /* delete nul characters */
6113 for (more = 1; more;) {
6120 parsenleft = q - parsenextc;
6121 more = 0; /* Stop processing here */
6128 if (--parselleft <= 0 && more) {
6129 parsenleft = q - parsenextc - 1;
6140 out2str(parsenextc);
6145 return *parsenextc++;
6149 * Undo the last call to pgetc. Only one character may be pushed back.
6150 * PEOF may be pushed back.
6161 * Push a string back onto the input at this current parsefile level.
6162 * We handle aliases this way.
6165 pushstring(char *s, void *ap)
6172 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6173 if (parsefile->strpush) {
6174 sp = ckmalloc(sizeof (struct strpush));
6175 sp->prev = parsefile->strpush;
6176 parsefile->strpush = sp;
6178 sp = parsefile->strpush = &(parsefile->basestrpush);
6179 sp->prevstring = parsenextc;
6180 sp->prevnleft = parsenleft;
6181 #ifdef CONFIG_ASH_ALIAS
6182 sp->ap = (struct alias *)ap;
6184 ((struct alias *)ap)->flag |= ALIASINUSE;
6196 struct strpush *sp = parsefile->strpush;
6199 #ifdef CONFIG_ASH_ALIAS
6201 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6202 checkkwd |= CHKALIAS;
6204 if (sp->string != sp->ap->val) {
6207 sp->ap->flag &= ~ALIASINUSE;
6208 if (sp->ap->flag & ALIASDEAD) {
6209 unalias(sp->ap->name);
6213 parsenextc = sp->prevstring;
6214 parsenleft = sp->prevnleft;
6215 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6216 parsefile->strpush = sp->prev;
6217 if (sp != &(parsefile->basestrpush))
6223 * Set the input to take input from a file. If push is set, push the
6224 * old input onto the stack first.
6228 setinputfile(const char *fname, int push)
6234 if ((fd = open(fname, O_RDONLY)) < 0)
6235 error("Can't open %s", fname);
6237 fd2 = copyfd(fd, 10);
6240 error("Out of file descriptors");
6243 setinputfd(fd, push);
6249 * Like setinputfile, but takes an open file descriptor. Call this with
6254 setinputfd(int fd, int push)
6256 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
6262 if (parsefile->buf == NULL)
6263 parsefile->buf = ckmalloc(IBUFSIZ);
6264 parselleft = parsenleft = 0;
6270 * Like setinputfile, but takes input from a string.
6274 setinputstring(char *string)
6278 parsenextc = string;
6279 parsenleft = strlen(string);
6280 parsefile->buf = NULL;
6287 * To handle the "." command, a stack of input files is used. Pushfile
6288 * adds a new entry to the stack and popfile restores the previous level.
6294 struct parsefile *pf;
6296 parsefile->nleft = parsenleft;
6297 parsefile->lleft = parselleft;
6298 parsefile->nextc = parsenextc;
6299 parsefile->linno = plinno;
6300 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
6301 pf->prev = parsefile;
6304 pf->basestrpush.prev = NULL;
6312 struct parsefile *pf = parsefile;
6321 parsefile = pf->prev;
6323 parsenleft = parsefile->nleft;
6324 parselleft = parsefile->lleft;
6325 parsenextc = parsefile->nextc;
6326 plinno = parsefile->linno;
6332 * Return to top level.
6338 while (parsefile != &basepf)
6344 * Close the file(s) that the shell is reading commands from. Called
6345 * after a fork is done.
6352 if (parsefile->fd > 0) {
6353 close(parsefile->fd);
6358 /* $NetBSD: jobs.c,v 1.56 2002/11/25 12:13:03 agc Exp $ */
6360 /* mode flags for set_curjob */
6361 #define CUR_DELETE 2
6362 #define CUR_RUNNING 1
6363 #define CUR_STOPPED 0
6365 /* mode flags for dowait */
6366 #define DOWAIT_NORMAL 0
6367 #define DOWAIT_BLOCK 1
6370 static struct job *jobtab;
6372 static unsigned njobs;
6374 /* pgrp of shell on invocation */
6375 static int initialpgrp;
6376 static int ttyfd = -1;
6379 static struct job *curjob;
6380 /* number of presumed living untracked jobs */
6383 static void set_curjob(struct job *, unsigned);
6385 static int restartjob(struct job *, int);
6386 static void xtcsetpgrp(int, pid_t);
6387 static char *commandtext(union node *);
6388 static void cmdlist(union node *, int);
6389 static void cmdtxt(union node *);
6390 static void cmdputs(const char *);
6391 static void showpipe(struct job *, FILE *);
6393 static int sprint_status(char *, int, int);
6394 static void freejob(struct job *);
6395 static struct job *getjob(const char *, int);
6396 static struct job *growjobtab(void);
6397 static void forkchild(struct job *, union node *, int);
6398 static void forkparent(struct job *, union node *, int, pid_t);
6399 static int dowait(int, struct job *);
6400 static int getstatus(struct job *);
6403 set_curjob(struct job *jp, unsigned mode)
6406 struct job **jpp, **curp;
6408 /* first remove from list */
6409 jpp = curp = &curjob;
6414 jpp = &jp1->prev_job;
6416 *jpp = jp1->prev_job;
6418 /* Then re-insert in correct position */
6426 /* job being deleted */
6429 /* newly created job or backgrounded job,
6430 put after all stopped jobs. */
6434 if (!jp1 || jp1->state != JOBSTOPPED)
6437 jpp = &jp1->prev_job;
6443 /* newly stopped job - becomes curjob */
6444 jp->prev_job = *jpp;
6452 * Turn job control on and off.
6454 * Note: This code assumes that the third arg to ioctl is a character
6455 * pointer, which is true on Berkeley systems but not System V. Since
6456 * System V doesn't have job control yet, this isn't a problem now.
6458 * Called with interrupts off.
6467 if (on == jobctl || rootshell == 0)
6471 ofd = fd = open(_PATH_TTY, O_RDWR);
6474 while (!isatty(fd) && --fd >= 0)
6477 fd = fcntl(fd, F_DUPFD, 10);
6481 fcntl(fd, F_SETFD, FD_CLOEXEC);
6482 do { /* while we are in the background */
6483 if ((pgrp = tcgetpgrp(fd)) < 0) {
6485 sh_warnx("can't access tty; job control turned off");
6489 if (pgrp == getpgrp())
6500 xtcsetpgrp(fd, pgrp);
6502 /* turning job control off */
6505 xtcsetpgrp(fd, pgrp);
6519 killcmd(int argc, char **argv)
6530 "Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6531 "kill -l [exitstatus]"
6535 if (**++argv == '-') {
6536 signo = decode_signal(*argv + 1, 1);
6540 while ((c = nextopt("ls:")) != '\0')
6550 signo = decode_signal(optionarg, 1);
6553 "invalid signal number or name: %s",
6564 if (!list && signo < 0)
6567 if ((signo < 0 || !*argv) ^ list) {
6575 for (i = 1; i < NSIG; i++) {
6576 name = u_signal_names(0, &i, 1);
6578 out1fmt(snlfmt, name);
6582 name = u_signal_names(*argptr, &signo, -1);
6584 out1fmt(snlfmt, name);
6586 error("invalid signal number or exit status: %s", *argptr);
6592 if (**argv == '%') {
6593 jp = getjob(*argv, 0);
6594 pid = -jp->ps[0].pid;
6596 pid = number(*argv);
6597 if (kill(pid, signo) != 0) {
6607 #if defined(JOBS) || defined(DEBUG)
6609 jobno(const struct job *jp)
6611 return jp - jobtab + 1;
6617 fgcmd(int argc, char **argv)
6624 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
6629 jp = getjob(*argv, 1);
6630 if (mode == FORK_BG) {
6631 set_curjob(jp, CUR_RUNNING);
6632 fprintf(out, "[%d] ", jobno(jp));
6634 outstr(jp->ps->cmd, out);
6636 retval = restartjob(jp, mode);
6637 } while (*argv && *++argv);
6641 static int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
6645 restartjob(struct job *jp, int mode)
6647 struct procstat *ps;
6653 if (jp->state == JOBDONE)
6655 jp->state = JOBRUNNING;
6657 if (mode == FORK_FG)
6658 xtcsetpgrp(ttyfd, pgid);
6659 killpg(pgid, SIGCONT);
6663 if (WIFSTOPPED(ps->status)) {
6666 } while (ps++, --i);
6668 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
6675 sprint_status(char *s, int status, int sigonly)
6681 st = WEXITSTATUS(status);
6682 if (!WIFEXITED(status)) {
6683 st = WSTOPSIG(status);
6685 if (!WIFSTOPPED(status))
6686 st = WTERMSIG(status);
6689 if (st == SIGINT || st == SIGPIPE)
6691 if (WIFSTOPPED(status))
6695 col = fmtstr(s, 32, u_signal_names(NULL, &st, 0));
6696 if (WCOREDUMP(status)) {
6697 col += fmtstr(s + col, 16, " (core dumped)");
6699 } else if (!sigonly) {
6701 col = fmtstr(s, 16, "Done(%d)", st);
6703 col = fmtstr(s, 16, "Done");
6712 showjob(FILE *out, struct job *jp, int mode)
6714 struct procstat *ps;
6715 struct procstat *psend;
6722 if (mode & SHOW_PGID) {
6723 /* just output process (group) id of pipeline */
6724 fprintf(out, "%d\n", ps->pid);
6728 col = fmtstr(s, 16, "[%d] ", jobno(jp));
6733 else if (curjob && jp == curjob->prev_job)
6736 if (mode & SHOW_PID)
6737 col += fmtstr(s + col, 16, "%d ", ps->pid);
6739 psend = ps + jp->nprocs;
6741 if (jp->state == JOBRUNNING) {
6742 scopy("Running", s + col);
6743 col += strlen("Running");
6745 int status = psend[-1].status;
6747 if (jp->state == JOBSTOPPED)
6748 status = jp->stopstatus;
6750 col += sprint_status(s + col, status, 0);
6756 /* for each process */
6757 col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
6760 fprintf(out, "%s%*c%s",
6761 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
6763 if (!(mode & SHOW_PID)) {
6767 if (++ps == psend) {
6768 outcslow('\n', out);
6775 if (jp->state == JOBDONE) {
6776 TRACE(("showjob: freeing job %d\n", jobno(jp)));
6783 jobscmd(int argc, char **argv)
6789 while ((m = nextopt("lp")))
6799 showjob(out, getjob(*argv,0), mode);
6802 showjobs(out, mode);
6809 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6810 * statuses have changed since the last call to showjobs.
6814 showjobs(FILE *out, int mode)
6818 TRACE(("showjobs(%x) called\n", mode));
6820 /* If not even one one job changed, there is nothing to do */
6821 while (dowait(DOWAIT_NORMAL, NULL) > 0)
6824 for (jp = curjob; jp; jp = jp->prev_job) {
6825 if (!(mode & SHOW_CHANGED) || jp->changed)
6826 showjob(out, jp, mode);
6832 * Mark a job structure as unused.
6836 freejob(struct job *jp)
6838 struct procstat *ps;
6842 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
6843 if (ps->cmd != nullstr)
6846 if (jp->ps != &jp->ps0)
6849 set_curjob(jp, CUR_DELETE);
6855 waitcmd(int argc, char **argv)
6868 /* wait for all jobs */
6873 /* no running procs */
6876 if (jp->state == JOBRUNNING)
6881 dowait(DOWAIT_BLOCK, 0);
6887 if (**argv != '%') {
6888 pid_t pid = number(*argv);
6892 if (job->ps[job->nprocs - 1].pid == pid)
6894 job = job->prev_job;
6900 job = getjob(*argv, 0);
6901 /* loop until process terminated or stopped */
6902 while (job->state == JOBRUNNING)
6903 dowait(DOWAIT_BLOCK, 0);
6905 retval = getstatus(job);
6916 * Convert a job name to a job structure.
6920 getjob(const char *name, int getctl)
6924 const char *err_msg = "No such job: %s";
6928 char *(*match)(const char *, const char *);
6943 if (c == '+' || c == '%') {
6945 err_msg = "No current job";
6947 } else if (c == '-') {
6950 err_msg = "No previous job";
6961 jp = jobtab + num - 1;
6978 if (match(jp->ps[0].cmd, p)) {
6982 err_msg = "%s: ambiguous";
6989 err_msg = "job %s not created under job control";
6990 if (getctl && jp->jobctl == 0)
6995 error(err_msg, name);
7000 * Return a new job structure.
7001 * Called with interrupts off.
7005 makejob(union node *node, int nprocs)
7010 for (i = njobs, jp = jobtab ; ; jp++) {
7017 if (jp->state != JOBDONE || !jp->waited)
7026 memset(jp, 0, sizeof(*jp));
7031 jp->prev_job = curjob;
7036 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
7038 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
7048 struct job *jp, *jq;
7050 len = njobs * sizeof(*jp);
7052 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
7054 offset = (char *)jp - (char *)jq;
7056 /* Relocate pointers */
7059 jq = (struct job *)((char *)jq + l);
7063 #define joff(p) ((struct job *)((char *)(p) + l))
7064 #define jmove(p) (p) = (void *)((char *)(p) + offset)
7065 if (likely(joff(jp)->ps == &jq->ps0))
7066 jmove(joff(jp)->ps);
7067 if (joff(jp)->prev_job)
7068 jmove(joff(jp)->prev_job);
7078 jp = (struct job *)((char *)jp + len);
7082 } while (--jq >= jp);
7088 * Fork off a subshell. If we are doing job control, give the subshell its
7089 * own process group. Jp is a job structure that the job is to be added to.
7090 * N is the command that will be evaluated by the child. Both jp and n may
7091 * be NULL. The mode parameter can be one of the following:
7092 * FORK_FG - Fork off a foreground process.
7093 * FORK_BG - Fork off a background process.
7094 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
7095 * process group even if job control is on.
7097 * When job control is turned off, background processes have their standard
7098 * input redirected to /dev/null (except for the second and later processes
7101 * Called with interrupts off.
7105 forkchild(struct job *jp, union node *n, int mode)
7109 TRACE(("Child shell %d\n", getpid()));
7110 wasroot = rootshell;
7116 /* do job control only in root shell */
7118 if (mode != FORK_NOJOB && jp->jobctl && wasroot) {
7121 if (jp->nprocs == 0)
7124 pgrp = jp->ps[0].pid;
7125 /* This can fail because we are doing it in the parent also */
7126 (void)setpgid(0, pgrp);
7127 if (mode == FORK_FG)
7128 xtcsetpgrp(ttyfd, pgrp);
7133 if (mode == FORK_BG) {
7136 if (jp->nprocs == 0) {
7138 if (open(_PATH_DEVNULL, O_RDONLY) != 0)
7139 error("Can't open %s", _PATH_DEVNULL);
7142 if (wasroot && iflag) {
7147 for (jp = curjob; jp; jp = jp->prev_job)
7153 forkparent(struct job *jp, union node *n, int mode, pid_t pid)
7155 TRACE(("In parent shell: child = %d\n", pid));
7157 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
7162 if (mode != FORK_NOJOB && jp->jobctl) {
7165 if (jp->nprocs == 0)
7168 pgrp = jp->ps[0].pid;
7169 /* This can fail because we are doing it in the child also */
7170 (void)setpgid(pid, pgrp);
7173 if (mode == FORK_BG) {
7174 backgndpid = pid; /* set $! */
7175 set_curjob(jp, CUR_RUNNING);
7178 struct procstat *ps = &jp->ps[jp->nprocs++];
7184 ps->cmd = commandtext(n);
7190 forkshell(struct job *jp, union node *n, int mode)
7194 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
7197 TRACE(("Fork failed, errno=%d", errno));
7200 error("Cannot fork");
7203 forkchild(jp, n, mode);
7205 forkparent(jp, n, mode, pid);
7210 * Wait for job to finish.
7212 * Under job control we have the problem that while a child process is
7213 * running interrupts generated by the user are sent to the child but not
7214 * to the shell. This means that an infinite loop started by an inter-
7215 * active user may be hard to kill. With job control turned off, an
7216 * interactive user may place an interactive program inside a loop. If
7217 * the interactive program catches interrupts, the user doesn't want
7218 * these interrupts to also abort the loop. The approach we take here
7219 * is to have the shell ignore interrupt signals while waiting for a
7220 * forground process to terminate, and then send itself an interrupt
7221 * signal if the child process was terminated by an interrupt signal.
7222 * Unfortunately, some programs want to do a bit of cleanup and then
7223 * exit on interrupt; unless these processes terminate themselves by
7224 * sending a signal to themselves (instead of calling exit) they will
7225 * confuse this approach.
7227 * Called with interrupts off.
7231 waitforjob(struct job *jp)
7235 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
7236 while (jp->state == JOBRUNNING) {
7237 dowait(DOWAIT_BLOCK, jp);
7242 xtcsetpgrp(ttyfd, rootpid);
7244 * This is truly gross.
7245 * If we're doing job control, then we did a TIOCSPGRP which
7246 * caused us (the shell) to no longer be in the controlling
7247 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7248 * intuit from the subprocess exit status whether a SIGINT
7249 * occurred, and if so interrupt ourselves. Yuck. - mycroft
7254 if (jp->state == JOBDONE)
7262 * Do a wait system call. If job control is compiled in, we accept
7263 * stopped processes. If block is zero, we return a value of zero
7264 * rather than blocking.
7266 * System V doesn't have a non-blocking wait system call. It does
7267 * have a SIGCLD signal that is sent to a process when one of it's
7268 * children dies. The obvious way to use SIGCLD would be to install
7269 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7270 * was received, and have waitproc bump another counter when it got
7271 * the status of a process. Waitproc would then know that a wait
7272 * system call would not block if the two counters were different.
7273 * This approach doesn't work because if a process has children that
7274 * have not been waited for, System V will send it a SIGCLD when it
7275 * installs a signal handler for SIGCLD. What this means is that when
7276 * a child exits, the shell will be sent SIGCLD signals continuously
7277 * until is runs out of stack space, unless it does a wait call before
7278 * restoring the signal handler. The code below takes advantage of
7279 * this (mis)feature by installing a signal handler for SIGCLD and
7280 * then checking to see whether it was called. If there are any
7281 * children to be waited for, it will be.
7283 * If neither SYSV nor BSD is defined, we don't implement nonblocking
7284 * waits at all. In this case, the user will not be informed when
7285 * a background process until the next time she runs a real program
7286 * (as opposed to running a builtin command or just typing return),
7287 * and the jobs command may give out of date information.
7291 waitproc(int block, int *status)
7301 return wait3(status, flags, (struct rusage *)NULL);
7305 * Wait for a process to terminate.
7309 dowait(int block, struct job *job)
7314 struct job *thisjob;
7317 TRACE(("dowait(%d) called\n", block));
7318 pid = waitproc(block, &status);
7319 TRACE(("wait returns pid %d, status=%d\n", pid, status));
7324 for (jp = curjob; jp; jp = jp->prev_job) {
7325 struct procstat *sp;
7326 struct procstat *spend;
7327 if (jp->state == JOBDONE)
7330 spend = jp->ps + jp->nprocs;
7333 if (sp->pid == pid) {
7334 TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
7335 sp->status = status;
7338 if (sp->status == -1)
7341 if (state == JOBRUNNING)
7343 if (WIFSTOPPED(sp->status)) {
7344 jp->stopstatus = sp->status;
7348 } while (++sp < spend);
7353 if (!WIFSTOPPED(status))
7360 if (state != JOBRUNNING) {
7361 thisjob->changed = 1;
7363 if (thisjob->state != state) {
7364 TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
7365 thisjob->state = state;
7367 if (state == JOBSTOPPED) {
7368 set_curjob(thisjob, CUR_STOPPED);
7377 if (thisjob && thisjob == job) {
7381 len = sprint_status(s, status, 1);
7393 * return 1 if there are stopped jobs, otherwise 0
7406 if (jp && jp->state == JOBSTOPPED) {
7407 out2str("You have stopped jobs.\n");
7417 * Return a string identifying a command (to be printed by the
7422 static char *cmdnextc;
7425 commandtext(union node *n)
7429 STARTSTACKSTR(cmdnextc);
7431 name = stackblock();
7432 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
7433 name, cmdnextc, cmdnextc));
7434 return savestr(name);
7438 cmdtxt(union node *n)
7441 struct nodelist *lp;
7451 lp = n->npipe.cmdlist;
7469 cmdtxt(n->nbinary.ch1);
7485 cmdtxt(n->nif.test);
7488 if (n->nif.elsepart) {
7491 n = n->nif.elsepart;
7507 cmdtxt(n->nbinary.ch1);
7517 cmdputs(n->nfor.var);
7519 cmdlist(n->nfor.args, 1);
7524 cmdputs(n->narg.text);
7528 cmdlist(n->ncmd.args, 1);
7529 cmdlist(n->ncmd.redirect, 0);
7542 cmdputs(n->ncase.expr->narg.text);
7544 for (np = n->ncase.cases; np; np = np->nclist.next) {
7545 cmdtxt(np->nclist.pattern);
7547 cmdtxt(np->nclist.body);
7573 s[0] = n->nfile.fd + '0';
7577 if (n->type == NTOFD || n->type == NFROMFD) {
7578 s[0] = n->ndup.dupfd + '0';
7589 cmdlist(union node *np, int sep)
7591 for (; np; np = np->narg.next) {
7595 if (sep && np->narg.next)
7601 cmdputs(const char *s)
7603 const char *p, *str;
7604 char c, cc[2] = " ";
7608 static const char *const vstype[16] = {
7609 nullstr, "}", "-", "+", "?", "=",
7610 "#", "##", "%", "%%"
7613 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
7615 while ((c = *p++) != 0) {
7623 if ((subtype & VSTYPE) == VSLENGTH)
7627 if (!(subtype & VSQUOTE) != !(quoted & 1)) {
7645 case CTLBACKQ+CTLQUOTE:
7648 #ifdef CONFIG_ASH_MATH_SUPPORT
7663 str = vstype[subtype & VSTYPE];
7664 if (subtype & VSNUL)
7675 /* These can only happen inside quotes */
7687 while ((c = *str++)) {
7692 USTPUTC('"', nextc);
7700 showpipe(struct job *jp, FILE *out)
7702 struct procstat *sp;
7703 struct procstat *spend;
7705 spend = jp->ps + jp->nprocs;
7706 for (sp = jp->ps + 1; sp < spend; sp++)
7707 fprintf(out, " | %s", sp->cmd);
7708 outcslow('\n', out);
7713 xtcsetpgrp(int fd, pid_t pgrp)
7715 if (tcsetpgrp(fd, pgrp))
7716 error("Cannot set tty process group (%m)");
7721 getstatus(struct job *job) {
7725 status = job->ps[job->nprocs - 1].status;
7726 retval = WEXITSTATUS(status);
7727 if (!WIFEXITED(status)) {
7729 retval = WSTOPSIG(status);
7730 if (!WIFSTOPPED(status))
7733 /* XXX: limits number of signals */
7734 retval = WTERMSIG(status);
7736 if (retval == SIGINT)
7742 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
7743 jobno(job), job->nprocs, status, retval));
7747 #ifdef CONFIG_ASH_MAIL
7748 /* $NetBSD: mail.c,v 1.15 2002/11/24 22:35:40 christos Exp $ */
7751 * Routines to check for mail. (Perhaps make part of main.c?)
7754 #define MAXMBOXES 10
7756 /* times of mailboxes */
7757 static time_t mailtime[MAXMBOXES];
7758 /* Set if MAIL or MAILPATH is changed. */
7759 static int mail_var_path_changed;
7764 * Print appropriate message(s) if mail has arrived.
7765 * If mail_var_path_changed is set,
7766 * then the value of MAIL has mail_var_path_changed,
7767 * so we just update the values.
7777 struct stackmark smark;
7780 setstackmark(&smark);
7781 mpath = mpathset() ? mpathval() : mailval();
7782 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
7783 p = padvance(&mpath, nullstr);
7788 for (q = p ; *q ; q++);
7793 q[-1] = '\0'; /* delete trailing '/' */
7794 if (stat(p, &statb) < 0) {
7798 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
7801 pathopt ? pathopt : "you have mail"
7804 *mtp = statb.st_mtime;
7806 mail_var_path_changed = 0;
7807 popstackmark(&smark);
7812 changemail(const char *val)
7814 mail_var_path_changed++;
7817 #endif /* CONFIG_ASH_MAIL */
7819 /* $NetBSD: main.c,v 1.46 2002/12/11 19:12:18 christos Exp $ */
7823 static short profile_buf[16384];
7827 static int isloginsh;
7829 static void read_profile(const char *);
7832 * Main routine. We initialize things, parse the arguments, execute
7833 * profiles if we're a login shell, and then call cmdloop to execute
7834 * commands. The setjmp call sets up the location to jump to when an
7835 * exception occurs. When an exception occurs the variable "state"
7836 * is used to figure out how far we had gotten.
7840 ash_main(int argc, char **argv)
7844 struct jmploc jmploc;
7845 struct stackmark smark;
7848 dash_errno = __errno_location();
7852 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7855 if (setjmp(jmploc.loc)) {
7862 switch (exception) {
7872 status = exitstatus;
7875 exitstatus = status;
7877 if (e == EXEXIT || state == 0 || iflag == 0 || ! rootshell)
7881 outcslow('\n', stderr);
7883 popstackmark(&smark);
7884 FORCEINTON; /* enable interrupts */
7887 else if (state == 2)
7889 else if (state == 3)
7897 trputs("Shell args: "); trargs(argv);
7902 setstackmark(&smark);
7903 procargs(argc, argv);
7904 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7906 const char *hp = lookupvar("HISTFILE");
7909 hp = lookupvar("HOME");
7911 char *defhp = concat_path_file(hp, ".ash_history");
7912 setvar("HISTFILE", defhp, 0);
7918 if (argv[0] && argv[0][0] == '-')
7922 read_profile("/etc/profile");
7925 read_profile(".profile");
7931 getuid() == geteuid() && getgid() == getegid() &&
7935 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
7936 read_profile(shinit);
7942 evalstring(minusc, 0);
7944 if (sflag || minusc == NULL) {
7945 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7947 const char *hp = lookupvar("HISTFILE");
7950 load_history ( hp );
7953 state4: /* XXX ??? - why isn't this before the "if" statement */
7961 extern void _mcleanup(void);
7971 * Read and execute commands. "Top" is nonzero for the top level command
7972 * loop; it turns on prompting if the shell is interactive.
7979 struct stackmark smark;
7983 TRACE(("cmdloop(%d) called\n", top));
7984 setstackmark(&smark);
7990 showjobs(stderr, SHOW_CHANGED);
7995 #ifdef CONFIG_ASH_MAIL
7999 n = parsecmd(inter);
8000 /* showtree(n); DEBUG */
8002 if (!top || numeof >= 50)
8004 if (!stoppedjobs()) {
8007 out2str("\nUse \"exit\" to leave shell.\n");
8010 } else if (n != NULL && nflag == 0) {
8011 job_warning = (job_warning == 2) ? 1 : 0;
8015 popstackmark(&smark);
8016 setstackmark(&smark);
8017 if (evalskip == SKIPFILE) {
8022 popstackmark(&smark);
8027 * Read /etc/profile or .profile. Return on error.
8031 read_profile(const char *name)
8038 if ((fd = open(name, O_RDONLY)) >= 0)
8043 /* -q turns off -x and -v just when executing init files */
8046 xflag = 0, xflag_set = 1;
8048 vflag = 0, vflag_set = 1;
8062 * Read a file containing shell functions.
8066 readcmdfile(char *name)
8071 if ((fd = open(name, O_RDONLY)) >= 0)
8074 error("Can't open %s", name);
8082 * Take commands from a file. To be compatible we should do a path
8083 * search for the file, which is necessary to find sub-commands.
8086 static inline char *
8087 find_dot_file(char *name)
8090 const char *path = pathval();
8093 /* don't try this for absolute or relative paths */
8094 if (strchr(name, '/'))
8097 while ((fullname = padvance(&path, name)) != NULL) {
8098 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
8100 * Don't bother freeing here, since it will
8101 * be freed by the caller.
8105 stunalloc(fullname);
8108 /* not found in the PATH */
8109 error(not_found_msg, name);
8114 dotcmd(int argc, char **argv)
8118 if (argc >= 2) { /* That's what SVR2 does */
8120 struct stackmark smark;
8122 setstackmark(&smark);
8123 fullname = find_dot_file(argv[1]);
8124 setinputfile(fullname, 1);
8125 commandname = fullname;
8128 popstackmark(&smark);
8135 exitcmd(int argc, char **argv)
8140 exitstatus = number(argv[1]);
8145 /* $NetBSD: memalloc.c,v 1.27 2003/01/22 20:36:04 dsl Exp $ */
8148 * Same for malloc, realloc, but returns an error when out of space.
8152 ckrealloc(pointer p, size_t nbytes)
8154 p = realloc(p, nbytes);
8156 error(bb_msg_memory_exhausted);
8161 ckmalloc(size_t nbytes)
8163 return ckrealloc(NULL, nbytes);
8167 * Make a copy of a string in safe storage.
8171 savestr(const char *s)
8173 char *p = strdup(s);
8175 error(bb_msg_memory_exhausted);
8181 * Parse trees for commands are allocated in lifo order, so we use a stack
8182 * to make this more efficient, and also to avoid all sorts of exception
8183 * handling code to handle interrupts in the middle of a parse.
8185 * The size 504 was chosen because the Ultrix malloc handles that size
8191 stalloc(size_t nbytes)
8196 aligned = SHELL_ALIGN(nbytes);
8197 if (aligned > stacknleft) {
8200 struct stack_block *sp;
8202 blocksize = aligned;
8203 if (blocksize < MINSIZE)
8204 blocksize = MINSIZE;
8205 len = sizeof(struct stack_block) - MINSIZE + blocksize;
8206 if (len < blocksize)
8207 error(bb_msg_memory_exhausted);
8211 stacknxt = sp->space;
8212 stacknleft = blocksize;
8213 sstrend = stacknxt + blocksize;
8218 stacknxt += aligned;
8219 stacknleft -= aligned;
8225 stunalloc(pointer p)
8228 if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
8229 write(2, "stunalloc\n", 10);
8233 stacknleft += stacknxt - (char *)p;
8239 setstackmark(struct stackmark *mark)
8241 mark->stackp = stackp;
8242 mark->stacknxt = stacknxt;
8243 mark->stacknleft = stacknleft;
8244 mark->marknext = markp;
8250 popstackmark(struct stackmark *mark)
8252 struct stack_block *sp;
8255 markp = mark->marknext;
8256 while (stackp != mark->stackp) {
8261 stacknxt = mark->stacknxt;
8262 stacknleft = mark->stacknleft;
8263 sstrend = mark->stacknxt + mark->stacknleft;
8269 * When the parser reads in a string, it wants to stick the string on the
8270 * stack and only adjust the stack pointer when it knows how big the
8271 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8272 * of space on top of the stack and stackblocklen returns the length of
8273 * this block. Growstackblock will grow this space by at least one byte,
8274 * possibly moving it (like realloc). Grabstackblock actually allocates the
8275 * part of the block that has been used.
8279 growstackblock(void)
8283 newlen = stacknleft * 2;
8284 if (newlen < stacknleft)
8285 error(bb_msg_memory_exhausted);
8289 if (stacknxt == stackp->space && stackp != &stackbase) {
8290 struct stack_block *oldstackp;
8291 struct stackmark *xmark;
8292 struct stack_block *sp;
8293 struct stack_block *prevstackp;
8299 prevstackp = sp->prev;
8300 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
8301 sp = ckrealloc((pointer)sp, grosslen);
8302 sp->prev = prevstackp;
8304 stacknxt = sp->space;
8305 stacknleft = newlen;
8306 sstrend = sp->space + newlen;
8309 * Stack marks pointing to the start of the old block
8310 * must be relocated to point to the new block
8313 while (xmark != NULL && xmark->stackp == oldstackp) {
8314 xmark->stackp = stackp;
8315 xmark->stacknxt = stacknxt;
8316 xmark->stacknleft = stacknleft;
8317 xmark = xmark->marknext;
8321 char *oldspace = stacknxt;
8322 int oldlen = stacknleft;
8323 char *p = stalloc(newlen);
8325 /* free the space we just allocated */
8326 stacknxt = memcpy(p, oldspace, oldlen);
8327 stacknleft += newlen;
8332 grabstackblock(size_t len)
8334 len = SHELL_ALIGN(len);
8340 * The following routines are somewhat easier to use than the above.
8341 * The user declares a variable of type STACKSTR, which may be declared
8342 * to be a register. The macro STARTSTACKSTR initializes things. Then
8343 * the user uses the macro STPUTC to add characters to the string. In
8344 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8345 * grown as necessary. When the user is done, she can just leave the
8346 * string there and refer to it using stackblock(). Or she can allocate
8347 * the space for it using grabstackstr(). If it is necessary to allow
8348 * someone else to use the stack temporarily and then continue to grow
8349 * the string, the user should use grabstack to allocate the space, and
8350 * then call ungrabstr(p) to return to the previous mode of operation.
8352 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8353 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8354 * is space for at least one character.
8360 size_t len = stackblocksize();
8361 if (herefd >= 0 && len >= 1024) {
8362 xwrite(herefd, stackblock(), len);
8363 return stackblock();
8366 return stackblock() + len;
8370 * Called from CHECKSTRSPACE.
8374 makestrspace(size_t newlen, char *p)
8376 size_t len = p - stacknxt;
8377 size_t size = stackblocksize();
8382 size = stackblocksize();
8384 if (nleft >= newlen)
8388 return stackblock() + len;
8392 stnputs(const char *s, size_t n, char *p)
8394 p = makestrspace(n, p);
8395 p = mempcpy(p, s, n);
8400 stputs(const char *s, char *p)
8402 return stnputs(s, strlen(s), p);
8405 /* $NetBSD: mystring.c,v 1.15 2002/11/24 22:35:42 christos Exp $ */
8410 * number(s) Convert a string of digits to an integer.
8411 * is_number(s) Return true if s is a string of digits.
8415 * prefix -- see if pfx is a prefix of string.
8419 prefix(const char *string, const char *pfx)
8422 if (*pfx++ != *string++)
8425 return (char *) string;
8430 * Convert a string of digits to an integer, printing an error message on
8435 number(const char *s)
8445 * Check for a valid number. This should be elsewhere.
8449 is_number(const char *p)
8454 } while (*++p != '\0');
8460 * Produce a possibly single quoted string suitable as input to the shell.
8461 * The return string is allocated on the stack.
8465 single_quote(const char *s) {
8474 len = strchrnul(s, '\'') - s;
8476 q = p = makestrspace(len + 3, p);
8479 q = mempcpy(q, s, len);
8485 len = strspn(s, "'");
8489 q = p = makestrspace(len + 3, p);
8492 q = mempcpy(q, s, len);
8501 return stackblock();
8505 * Like strdup but works with the ash stack.
8509 sstrdup(const char *p)
8511 size_t len = strlen(p) + 1;
8512 return memcpy(stalloc(len), p, len);
8517 calcsize(union node *n)
8521 funcblocksize += nodesize[n->type];
8524 calcsize(n->ncmd.redirect);
8525 calcsize(n->ncmd.args);
8526 calcsize(n->ncmd.assign);
8529 sizenodelist(n->npipe.cmdlist);
8534 calcsize(n->nredir.redirect);
8535 calcsize(n->nredir.n);
8542 calcsize(n->nbinary.ch2);
8543 calcsize(n->nbinary.ch1);
8546 calcsize(n->nif.elsepart);
8547 calcsize(n->nif.ifpart);
8548 calcsize(n->nif.test);
8551 funcstringsize += strlen(n->nfor.var) + 1;
8552 calcsize(n->nfor.body);
8553 calcsize(n->nfor.args);
8556 calcsize(n->ncase.cases);
8557 calcsize(n->ncase.expr);
8560 calcsize(n->nclist.body);
8561 calcsize(n->nclist.pattern);
8562 calcsize(n->nclist.next);
8566 sizenodelist(n->narg.backquote);
8567 funcstringsize += strlen(n->narg.text) + 1;
8568 calcsize(n->narg.next);
8575 calcsize(n->nfile.fname);
8576 calcsize(n->nfile.next);
8580 calcsize(n->ndup.vname);
8581 calcsize(n->ndup.next);
8585 calcsize(n->nhere.doc);
8586 calcsize(n->nhere.next);
8589 calcsize(n->nnot.com);
8596 sizenodelist(struct nodelist *lp)
8599 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8607 copynode(union node *n)
8614 funcblock = (char *) funcblock + nodesize[n->type];
8617 new->ncmd.redirect = copynode(n->ncmd.redirect);
8618 new->ncmd.args = copynode(n->ncmd.args);
8619 new->ncmd.assign = copynode(n->ncmd.assign);
8622 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8623 new->npipe.backgnd = n->npipe.backgnd;
8628 new->nredir.redirect = copynode(n->nredir.redirect);
8629 new->nredir.n = copynode(n->nredir.n);
8636 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8637 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8640 new->nif.elsepart = copynode(n->nif.elsepart);
8641 new->nif.ifpart = copynode(n->nif.ifpart);
8642 new->nif.test = copynode(n->nif.test);
8645 new->nfor.var = nodesavestr(n->nfor.var);
8646 new->nfor.body = copynode(n->nfor.body);
8647 new->nfor.args = copynode(n->nfor.args);
8650 new->ncase.cases = copynode(n->ncase.cases);
8651 new->ncase.expr = copynode(n->ncase.expr);
8654 new->nclist.body = copynode(n->nclist.body);
8655 new->nclist.pattern = copynode(n->nclist.pattern);
8656 new->nclist.next = copynode(n->nclist.next);
8660 new->narg.backquote = copynodelist(n->narg.backquote);
8661 new->narg.text = nodesavestr(n->narg.text);
8662 new->narg.next = copynode(n->narg.next);
8669 new->nfile.fname = copynode(n->nfile.fname);
8670 new->nfile.fd = n->nfile.fd;
8671 new->nfile.next = copynode(n->nfile.next);
8675 new->ndup.vname = copynode(n->ndup.vname);
8676 new->ndup.dupfd = n->ndup.dupfd;
8677 new->ndup.fd = n->ndup.fd;
8678 new->ndup.next = copynode(n->ndup.next);
8682 new->nhere.doc = copynode(n->nhere.doc);
8683 new->nhere.fd = n->nhere.fd;
8684 new->nhere.next = copynode(n->nhere.next);
8687 new->nnot.com = copynode(n->nnot.com);
8690 new->type = n->type;
8695 static struct nodelist *
8696 copynodelist(struct nodelist *lp)
8698 struct nodelist *start;
8699 struct nodelist **lpp;
8704 funcblock = (char *) funcblock +
8705 SHELL_ALIGN(sizeof(struct nodelist));
8706 (*lpp)->n = copynode(lp->n);
8708 lpp = &(*lpp)->next;
8716 nodesavestr(char *s)
8718 char *rtn = funcstring;
8720 funcstring = stpcpy(funcstring, s) + 1;
8726 * Free a parse tree.
8730 freefunc(struct funcnode *f)
8732 if (f && --f->count < 0)
8737 static void options(int);
8738 static void setoption(int, int);
8742 * Process the shell command line arguments.
8746 procargs(int argc, char **argv)
8749 const char *xminusc;
8756 for (i = 0; i < NOPTS; i++)
8762 if (*xargv == NULL) {
8764 error("-c requires an argument");
8767 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8771 for (i = 0; i < NOPTS; i++)
8772 if (optlist[i] == 2)
8777 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8782 } else if (!sflag) {
8783 setinputfile(*xargv, 0);
8789 shellparam.p = xargv;
8790 #ifdef CONFIG_ASH_GETOPTS
8791 shellparam.optind = 1;
8792 shellparam.optoff = -1;
8794 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
8796 shellparam.nparam++;
8809 setinteractive(iflag);
8814 minus_o(char *name, int val)
8819 out1str("Current option settings\n");
8820 for (i = 0; i < NOPTS; i++)
8821 out1fmt("%-16s%s\n", optnames(i),
8822 optlist[i] ? "on" : "off");
8824 for (i = 0; i < NOPTS; i++)
8825 if (equal(name, optnames(i))) {
8829 error("Illegal option -o %s", name);
8834 * Process shell options. The global variable argptr contains a pointer
8835 * to the argument list; we advance it past the options.
8839 options(int cmdline)
8847 while ((p = *argptr) != NULL) {
8849 if ((c = *p++) == '-') {
8851 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8853 /* "-" means turn off -x and -v */
8856 /* "--" means reset params */
8857 else if (*argptr == NULL)
8860 break; /* "-" or "--" terminates options */
8862 } else if (c == '+') {
8868 while ((c = *p++) != '\0') {
8869 if (c == 'c' && cmdline) {
8870 minusc = p; /* command is after shell args*/
8871 } else if (c == 'o') {
8872 minus_o(*argptr, val);
8875 } else if (cmdline && (c == '-')) { // long options
8876 if (strcmp(p, "login") == 0)
8888 setoption(int flag, int val)
8892 for (i = 0; i < NOPTS; i++)
8893 if (optletters(i) == flag) {
8897 error("Illegal option -%c", flag);
8904 * Set the shell parameters.
8908 setparam(char **argv)
8914 for (nparam = 0 ; argv[nparam] ; nparam++);
8915 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
8917 *ap++ = savestr(*argv++);
8920 freeparam(&shellparam);
8921 shellparam.malloc = 1;
8922 shellparam.nparam = nparam;
8923 shellparam.p = newparam;
8924 #ifdef CONFIG_ASH_GETOPTS
8925 shellparam.optind = 1;
8926 shellparam.optoff = -1;
8932 * Free the list of positional parameters.
8936 freeparam(volatile struct shparam *param)
8940 if (param->malloc) {
8941 for (ap = param->p ; *ap ; ap++)
8950 * The shift builtin command.
8954 shiftcmd(int argc, char **argv)
8961 n = number(argv[1]);
8962 if (n > shellparam.nparam)
8963 error("can't shift that many");
8965 shellparam.nparam -= n;
8966 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
8967 if (shellparam.malloc)
8971 while ((*ap2++ = *ap1++) != NULL);
8972 #ifdef CONFIG_ASH_GETOPTS
8973 shellparam.optind = 1;
8974 shellparam.optoff = -1;
8983 * The set command builtin.
8987 setcmd(int argc, char **argv)
8990 return showvars(nullstr, 0, VUNSET);
8994 if (*argptr != NULL) {
9002 #ifdef CONFIG_ASH_GETOPTS
9007 shellparam.optind = number(value);
9008 shellparam.optoff = -1;
9012 #ifdef CONFIG_LOCALE_SUPPORT
9013 static void change_lc_all(const char *value)
9015 if (value != 0 && *value != 0)
9016 setlocale(LC_ALL, value);
9019 static void change_lc_ctype(const char *value)
9021 if (value != 0 && *value != 0)
9022 setlocale(LC_CTYPE, value);
9027 #ifdef CONFIG_ASH_GETOPTS
9029 getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
9036 char **optnext = optfirst + *param_optind - 1;
9038 if (*param_optind <= 1 || *optoff < 0 || !(*(optnext - 1)) ||
9039 strlen(*(optnext - 1)) < *optoff)
9042 p = *(optnext - 1) + *optoff;
9043 if (p == NULL || *p == '\0') {
9044 /* Current word is done, advance */
9045 if (optnext == NULL)
9048 if (p == NULL || *p != '-' || *++p == '\0') {
9055 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
9060 for (q = optstr; *q != c; ) {
9062 if (optstr[0] == ':') {
9065 err |= setvarsafe("OPTARG", s, 0);
9067 fprintf(stderr, "Illegal option -%c\n", c);
9068 (void) unsetvar("OPTARG");
9078 if (*p == '\0' && (p = *optnext) == NULL) {
9079 if (optstr[0] == ':') {
9082 err |= setvarsafe("OPTARG", s, 0);
9085 fprintf(stderr, "No arg for -%c option\n", c);
9086 (void) unsetvar("OPTARG");
9094 err |= setvarsafe("OPTARG", p, 0);
9097 err |= setvarsafe("OPTARG", nullstr, 0);
9100 *optoff = p ? p - *(optnext - 1) : -1;
9101 *param_optind = optnext - optfirst + 1;
9102 fmtstr(s, sizeof(s), "%d", *param_optind);
9103 err |= setvarsafe("OPTIND", s, VNOFUNC);
9106 err |= setvarsafe(optvar, s, 0);
9117 * The getopts builtin. Shellparam.optnext points to the next argument
9118 * to be processed. Shellparam.optptr points to the next character to
9119 * be processed in the current argument. If shellparam.optnext is NULL,
9120 * then it's the first time getopts has been called.
9124 getoptscmd(int argc, char **argv)
9129 error("Usage: getopts optstring var [arg]");
9130 else if (argc == 3) {
9131 optbase = shellparam.p;
9132 if (shellparam.optind > shellparam.nparam + 1) {
9133 shellparam.optind = 1;
9134 shellparam.optoff = -1;
9139 if (shellparam.optind > argc - 2) {
9140 shellparam.optind = 1;
9141 shellparam.optoff = -1;
9145 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9146 &shellparam.optoff);
9148 #endif /* CONFIG_ASH_GETOPTS */
9151 * XXX - should get rid of. have all builtins use getopt(3). the
9152 * library getopt must have the BSD extension static variable "optreset"
9153 * otherwise it can't be used within the shell safely.
9155 * Standard option processing (a la getopt) for builtin routines. The
9156 * only argument that is passed to nextopt is the option string; the
9157 * other arguments are unnecessary. It return the character, or '\0' on
9162 nextopt(const char *optstring)
9168 if ((p = optptr) == NULL || *p == '\0') {
9170 if (p == NULL || *p != '-' || *++p == '\0')
9173 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
9177 for (q = optstring ; *q != c ; ) {
9179 error("Illegal option -%c", c);
9184 if (*p == '\0' && (p = *argptr++) == NULL)
9185 error("No arg for -%c option", c);
9194 /* $NetBSD: output.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
9197 outstr(const char *p, FILE *file)
9214 flushout(FILE *dest)
9222 outcslow(int c, FILE *dest)
9232 out1fmt(const char *fmt, ...)
9239 r = vprintf(fmt, ap);
9247 fmtstr(char *outbuf, size_t length, const char *fmt, ...)
9254 ret = vsnprintf(outbuf, length, fmt, ap);
9262 * Version of write which resumes after a signal is caught.
9266 xwrite(int fd, const void *p, size_t n)
9271 i = bb_full_write(fd, p, n);
9272 } while (i < 0 && errno == EINTR);
9276 /* $NetBSD: parser.c,v 1.54 2002/11/24 22:35:42 christos Exp $ */
9280 * Shell command parser.
9283 #define EOFMARKLEN 79
9287 struct heredoc *next; /* next here document in list */
9288 union node *here; /* redirection node */
9289 char *eofmark; /* string indicating end of input */
9290 int striptabs; /* if set, strip leading tabs */
9295 static struct heredoc *heredoclist; /* list of here documents to read */
9298 static union node *list(int);
9299 static union node *andor(void);
9300 static union node *pipeline(void);
9301 static union node *command(void);
9302 static union node *simplecmd(void);
9303 static union node *makename(void);
9304 static void parsefname(void);
9305 static void parseheredoc(void);
9306 static char peektoken(void);
9307 static int readtoken(void);
9308 static int xxreadtoken(void);
9309 static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
9310 static int noexpand(char *);
9311 static void synexpect(int) __attribute__((__noreturn__));
9312 static void synerror(const char *) __attribute__((__noreturn__));
9313 static void setprompt(int);
9317 goodname(const char *p)
9319 return !*endofname(p);
9323 isassignment(const char *p)
9325 const char *q = endofname(p);
9333 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9334 * valid parse tree indicating a blank line.)
9338 parsecmd(int interact)
9343 doprompt = interact;
9345 setprompt(doprompt);
9360 union node *n1, *n2, *n3;
9363 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9364 if (nlflag == 2 && peektoken())
9370 if (tok == TBACKGND) {
9371 if (n2->type == NPIPE) {
9372 n2->npipe.backgnd = 1;
9374 if (n2->type != NREDIR) {
9375 n3 = stalloc(sizeof(struct nredir));
9377 n3->nredir.redirect = NULL;
9380 n2->type = NBACKGND;
9387 n3 = (union node *)stalloc(sizeof (struct nbinary));
9389 n3->nbinary.ch1 = n1;
9390 n3->nbinary.ch2 = n2;
9406 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9414 pungetc(); /* push back EOF on input */
9430 union node *n1, *n2, *n3;
9435 if ((t = readtoken()) == TAND) {
9437 } else if (t == TOR) {
9443 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9445 n3 = (union node *)stalloc(sizeof (struct nbinary));
9447 n3->nbinary.ch1 = n1;
9448 n3->nbinary.ch2 = n2;
9458 union node *n1, *n2, *pipenode;
9459 struct nodelist *lp, *prev;
9463 TRACE(("pipeline: entered\n"));
9464 if (readtoken() == TNOT) {
9466 checkkwd = CHKKWD | CHKALIAS;
9470 if (readtoken() == TPIPE) {
9471 pipenode = (union node *)stalloc(sizeof (struct npipe));
9472 pipenode->type = NPIPE;
9473 pipenode->npipe.backgnd = 0;
9474 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9475 pipenode->npipe.cmdlist = lp;
9479 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9480 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9483 } while (readtoken() == TPIPE);
9489 n2 = (union node *)stalloc(sizeof (struct nnot));
9502 union node *n1, *n2;
9503 union node *ap, **app;
9504 union node *cp, **cpp;
9505 union node *redir, **rpp;
9512 switch (readtoken()) {
9517 n1 = (union node *)stalloc(sizeof (struct nif));
9519 n1->nif.test = list(0);
9520 if (readtoken() != TTHEN)
9522 n1->nif.ifpart = list(0);
9524 while (readtoken() == TELIF) {
9525 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
9526 n2 = n2->nif.elsepart;
9528 n2->nif.test = list(0);
9529 if (readtoken() != TTHEN)
9531 n2->nif.ifpart = list(0);
9533 if (lasttoken == TELSE)
9534 n2->nif.elsepart = list(0);
9536 n2->nif.elsepart = NULL;
9544 n1 = (union node *)stalloc(sizeof (struct nbinary));
9545 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
9546 n1->nbinary.ch1 = list(0);
9547 if ((got=readtoken()) != TDO) {
9548 TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
9551 n1->nbinary.ch2 = list(0);
9556 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9557 synerror("Bad for loop variable");
9558 n1 = (union node *)stalloc(sizeof (struct nfor));
9560 n1->nfor.var = wordtext;
9561 checkkwd = CHKKWD | CHKALIAS;
9562 if (readtoken() == TIN) {
9564 while (readtoken() == TWORD) {
9565 n2 = (union node *)stalloc(sizeof (struct narg));
9567 n2->narg.text = wordtext;
9568 n2->narg.backquote = backquotelist;
9570 app = &n2->narg.next;
9574 if (lasttoken != TNL && lasttoken != TSEMI)
9577 n2 = (union node *)stalloc(sizeof (struct narg));
9579 n2->narg.text = (char *)dolatstr;
9580 n2->narg.backquote = NULL;
9581 n2->narg.next = NULL;
9584 * Newline or semicolon here is optional (but note
9585 * that the original Bourne shell only allowed NL).
9587 if (lasttoken != TNL && lasttoken != TSEMI)
9590 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9591 if (readtoken() != TDO)
9593 n1->nfor.body = list(0);
9597 n1 = (union node *)stalloc(sizeof (struct ncase));
9599 if (readtoken() != TWORD)
9601 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
9603 n2->narg.text = wordtext;
9604 n2->narg.backquote = backquotelist;
9605 n2->narg.next = NULL;
9607 checkkwd = CHKKWD | CHKALIAS;
9608 } while (readtoken() == TNL);
9609 if (lasttoken != TIN)
9611 cpp = &n1->ncase.cases;
9613 checkkwd = CHKNL | CHKKWD;
9616 if (lasttoken == TLP)
9618 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
9620 app = &cp->nclist.pattern;
9622 *app = ap = (union node *)stalloc(sizeof (struct narg));
9624 ap->narg.text = wordtext;
9625 ap->narg.backquote = backquotelist;
9626 if (readtoken() != TPIPE)
9628 app = &ap->narg.next;
9631 ap->narg.next = NULL;
9632 if (lasttoken != TRP)
9634 cp->nclist.body = list(2);
9636 cpp = &cp->nclist.next;
9638 checkkwd = CHKNL | CHKKWD;
9639 if ((t = readtoken()) != TESAC) {
9641 synexpect(TENDCASE);
9649 n1 = (union node *)stalloc(sizeof (struct nredir));
9650 n1->type = NSUBSHELL;
9651 n1->nredir.n = list(0);
9652 n1->nredir.redirect = NULL;
9665 if (readtoken() != t)
9669 /* Now check for redirection which may follow command */
9670 checkkwd = CHKKWD | CHKALIAS;
9672 while (readtoken() == TREDIR) {
9673 *rpp = n2 = redirnode;
9674 rpp = &n2->nfile.next;
9680 if (n1->type != NSUBSHELL) {
9681 n2 = (union node *)stalloc(sizeof (struct nredir));
9686 n1->nredir.redirect = redir;
9695 union node *args, **app;
9696 union node *n = NULL;
9697 union node *vars, **vpp;
9698 union node **rpp, *redir;
9708 savecheckkwd = CHKALIAS;
9710 checkkwd = savecheckkwd;
9711 switch (readtoken()) {
9713 n = (union node *)stalloc(sizeof (struct narg));
9715 n->narg.text = wordtext;
9716 n->narg.backquote = backquotelist;
9717 if (savecheckkwd && isassignment(wordtext)) {
9719 vpp = &n->narg.next;
9722 app = &n->narg.next;
9727 *rpp = n = redirnode;
9728 rpp = &n->nfile.next;
9729 parsefname(); /* read name of redirection file */
9733 args && app == &args->narg.next &&
9736 struct builtincmd *bcmd;
9739 /* We have a function */
9740 if (readtoken() != TRP)
9742 name = n->narg.text;
9744 !goodname(name) || (
9745 (bcmd = find_builtin(name)) &&
9746 IS_BUILTIN_SPECIAL(bcmd)
9749 synerror("Bad function name");
9751 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9752 n->narg.next = command();
9765 n = (union node *)stalloc(sizeof (struct ncmd));
9767 n->ncmd.args = args;
9768 n->ncmd.assign = vars;
9769 n->ncmd.redirect = redir;
9778 n = (union node *)stalloc(sizeof (struct narg));
9780 n->narg.next = NULL;
9781 n->narg.text = wordtext;
9782 n->narg.backquote = backquotelist;
9786 void fixredir(union node *n, const char *text, int err)
9788 TRACE(("Fix redir %s %d\n", text, err));
9790 n->ndup.vname = NULL;
9792 if (is_digit(text[0]) && text[1] == '\0')
9793 n->ndup.dupfd = digit_val(text[0]);
9794 else if (text[0] == '-' && text[1] == '\0')
9799 synerror("Bad fd number");
9801 n->ndup.vname = makename();
9809 union node *n = redirnode;
9811 if (readtoken() != TWORD)
9813 if (n->type == NHERE) {
9814 struct heredoc *here = heredoc;
9820 TRACE(("Here document %d\n", n->type));
9821 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
9822 synerror("Illegal eof marker for << redirection");
9823 rmescapes(wordtext);
9824 here->eofmark = wordtext;
9826 if (heredoclist == NULL)
9829 for (p = heredoclist ; p->next ; p = p->next);
9832 } else if (n->type == NTOFD || n->type == NFROMFD) {
9833 fixredir(n, wordtext, 0);
9835 n->nfile.fname = makename();
9841 * Input any here documents.
9847 struct heredoc *here;
9858 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9859 here->eofmark, here->striptabs);
9860 n = (union node *)stalloc(sizeof (struct narg));
9861 n->narg.type = NARG;
9862 n->narg.next = NULL;
9863 n->narg.text = wordtext;
9864 n->narg.backquote = backquotelist;
9865 here->here->nhere.doc = n;
9870 static char peektoken(void)
9876 return tokname_array[t][0];
9884 int alreadyseen = tokpushback;
9887 #ifdef CONFIG_ASH_ALIAS
9896 if (checkkwd & CHKNL) {
9903 if (t != TWORD || quoteflag) {
9908 * check for keywords
9910 if (checkkwd & CHKKWD) {
9911 const char *const *pp;
9913 if ((pp = findkwd(wordtext))) {
9914 lasttoken = t = pp - tokname_array;
9915 TRACE(("keyword %s recognized\n", tokname(t)));
9920 if (checkkwd & CHKALIAS) {
9921 #ifdef CONFIG_ASH_ALIAS
9923 if ((ap = lookupalias(wordtext, 1)) != NULL) {
9925 pushstring(ap->val, ap);
9935 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
9937 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
9944 * Read the next input token.
9945 * If the token is a word, we set backquotelist to the list of cmds in
9946 * backquotes. We set quoteflag to true if any part of the word was
9948 * If the token is TREDIR, then we set redirnode to a structure containing
9950 * In all cases, the variable startlinno is set to the number of the line
9951 * on which the token starts.
9953 * [Change comment: here documents and internal procedures]
9954 * [Readtoken shouldn't have any arguments. Perhaps we should make the
9955 * word parsing code into a separate routine. In this case, readtoken
9956 * doesn't need to have any internal procedures, but parseword does.
9957 * We could also make parseoperator in essence the main routine, and
9958 * have parseword (readtoken1?) handle both words and redirection.]
9961 #define NEW_xxreadtoken
9962 #ifdef NEW_xxreadtoken
9964 /* singles must be first! */
9965 static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
9967 static const char xxreadtoken_tokens[] = {
9968 TNL, TLP, TRP, /* only single occurrence allowed */
9969 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
9970 TEOF, /* corresponds to trailing nul */
9971 TAND, TOR, TENDCASE, /* if double occurrence */
9974 #define xxreadtoken_doubles \
9975 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
9976 #define xxreadtoken_singles \
9977 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
9979 static int xxreadtoken()
9991 startlinno = plinno;
9992 for (;;) { /* until token or start of word found */
9995 if ((c != ' ') && (c != '\t')
9996 #ifdef CONFIG_ASH_ALIAS
10001 while ((c = pgetc()) != '\n' && c != PEOF);
10003 } else if (c == '\\') {
10004 if (pgetc() != '\n') {
10008 startlinno = ++plinno;
10013 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10018 needprompt = doprompt;
10021 p = strchr(xxreadtoken_chars, c);
10024 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
10027 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
10028 if (pgetc() == *p) { /* double occurrence? */
10029 p += xxreadtoken_doubles + 1;
10036 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
10044 #define RETURN(token) return lasttoken = token
10059 startlinno = plinno;
10060 for (;;) { /* until token or start of word found */
10063 case ' ': case '\t':
10064 #ifdef CONFIG_ASH_ALIAS
10069 while ((c = pgetc()) != '\n' && c != PEOF);
10073 if (pgetc() == '\n') {
10074 startlinno = ++plinno;
10083 needprompt = doprompt;
10088 if (pgetc() == '&')
10093 if (pgetc() == '|')
10098 if (pgetc() == ';')
10111 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10114 #endif /* NEW_xxreadtoken */
10118 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10119 * is not NULL, read a here document. In the latter case, eofmark is the
10120 * word which marks the end of the document and striptabs is true if
10121 * leading tabs should be stripped from the document. The argument firstc
10122 * is the first character of the input token or document.
10124 * Because C does not have internal subroutines, I have simulated them
10125 * using goto's to implement the subroutine linkage. The following macros
10126 * will run code that appears at the end of readtoken1.
10129 #define CHECKEND() {goto checkend; checkend_return:;}
10130 #define PARSEREDIR() {goto parseredir; parseredir_return:;}
10131 #define PARSESUB() {goto parsesub; parsesub_return:;}
10132 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10133 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10134 #define PARSEARITH() {goto parsearith; parsearith_return:;}
10137 readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
10142 char line[EOFMARKLEN + 1];
10143 struct nodelist *bqlist;
10146 int varnest; /* levels of variables expansion */
10147 int arinest; /* levels of arithmetic expansion */
10148 int parenlevel; /* levels of parens in arithmetic */
10149 int dqvarnest; /* levels of variables expansion within double quotes */
10151 int prevsyntax; /* syntax before arithmetic */
10153 /* Avoid longjmp clobbering */
10159 (void) &parenlevel;
10162 (void) &prevsyntax;
10166 startlinno = plinno;
10168 if (syntax == DQSYNTAX)
10177 STARTSTACKSTR(out);
10178 loop: { /* for each line, until end of word */
10179 CHECKEND(); /* set c to PEOF if at end of here document */
10180 for (;;) { /* until end of line or end of word */
10181 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10182 switch(SIT(c, syntax)) {
10183 case CNL: /* '\n' */
10184 if (syntax == BASESYNTAX)
10185 goto endword; /* exit outer loop */
10191 goto loop; /* continue outer loop */
10196 if (eofmark == NULL || dblquote)
10197 USTPUTC(CTLESC, out);
10200 case CBACK: /* backslash */
10203 USTPUTC(CTLESC, out);
10204 USTPUTC('\\', out);
10206 } else if (c == '\n') {
10212 c != '\\' && c != '`' &&
10218 USTPUTC(CTLESC, out);
10219 USTPUTC('\\', out);
10221 if (SIT(c, SQSYNTAX) == CCTL)
10222 USTPUTC(CTLESC, out);
10230 if (eofmark == NULL) {
10231 USTPUTC(CTLQUOTEMARK, out);
10239 if (eofmark != NULL && arinest == 0 &&
10243 if (dqvarnest == 0) {
10244 syntax = BASESYNTAX;
10251 case CVAR: /* '$' */
10252 PARSESUB(); /* parse substitution */
10254 case CENDVAR: /* '}' */
10257 if (dqvarnest > 0) {
10260 USTPUTC(CTLENDVAR, out);
10265 #ifdef CONFIG_ASH_MATH_SUPPORT
10266 case CLP: /* '(' in arithmetic */
10270 case CRP: /* ')' in arithmetic */
10271 if (parenlevel > 0) {
10275 if (pgetc() == ')') {
10276 if (--arinest == 0) {
10277 USTPUTC(CTLENDARI, out);
10278 syntax = prevsyntax;
10279 if (syntax == DQSYNTAX)
10287 * unbalanced parens
10288 * (don't 2nd guess - no error)
10296 case CBQUOTE: /* '`' */
10300 goto endword; /* exit outer loop */
10305 goto endword; /* exit outer loop */
10306 #ifdef CONFIG_ASH_ALIAS
10316 #ifdef CONFIG_ASH_MATH_SUPPORT
10317 if (syntax == ARISYNTAX)
10318 synerror("Missing '))'");
10320 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10321 synerror("Unterminated quoted string");
10322 if (varnest != 0) {
10323 startlinno = plinno;
10325 synerror("Missing '}'");
10327 USTPUTC('\0', out);
10328 len = out - (char *)stackblock();
10329 out = stackblock();
10330 if (eofmark == NULL) {
10331 if ((c == '>' || c == '<')
10334 && (*out == '\0' || is_digit(*out))) {
10336 return lasttoken = TREDIR;
10341 quoteflag = quotef;
10342 backquotelist = bqlist;
10343 grabstackblock(len);
10345 return lasttoken = TWORD;
10346 /* end of readtoken routine */
10351 * Check to see whether we are at the end of the here document. When this
10352 * is called, c is set to the first character of the next input line. If
10353 * we are at the end of the here document, this routine sets the c to PEOF.
10358 #ifdef CONFIG_ASH_ALIAS
10364 while (c == '\t') {
10368 if (c == *eofmark) {
10369 if (pfgets(line, sizeof line) != NULL) {
10373 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10374 if (*p == '\n' && *q == '\0') {
10377 needprompt = doprompt;
10379 pushstring(line, NULL);
10384 goto checkend_return;
10389 * Parse a redirection operator. The variable "out" points to a string
10390 * specifying the fd to be redirected. The variable "c" contains the
10391 * first character of the redirection operator.
10398 np = (union node *)stalloc(sizeof (struct nfile));
10403 np->type = NAPPEND;
10405 np->type = NCLOBBER;
10412 } else { /* c == '<' */
10414 switch (c = pgetc()) {
10416 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10417 np = (union node *)stalloc(sizeof (struct nhere));
10421 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10422 heredoc->here = np;
10423 if ((c = pgetc()) == '-') {
10424 heredoc->striptabs = 1;
10426 heredoc->striptabs = 0;
10432 np->type = NFROMFD;
10436 np->type = NFROMTO;
10446 np->nfile.fd = digit_val(fd);
10448 goto parseredir_return;
10453 * Parse a substitution. At this point, we have read the dollar sign
10454 * and nothing else.
10462 static const char types[] = "}-+?=";
10466 c <= PEOA_OR_PEOF ||
10467 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10471 } else if (c == '(') { /* $(command) or $((arith)) */
10472 if (pgetc() == '(') {
10473 #ifdef CONFIG_ASH_MATH_SUPPORT
10476 synerror("We unsupport $((arith))");
10483 USTPUTC(CTLVAR, out);
10484 typeloc = out - (char *)stackblock();
10485 USTPUTC(VSNORMAL, out);
10486 subtype = VSNORMAL;
10490 if ((c = pgetc()) == '}')
10493 subtype = VSLENGTH;
10498 if (c > PEOA_OR_PEOF && is_name(c)) {
10502 } while (c > PEOA_OR_PEOF && is_in_name(c));
10503 } else if (is_digit(c)) {
10507 } while (is_digit(c));
10509 else if (is_special(c)) {
10514 badsub: synerror("Bad substitution");
10518 if (subtype == 0) {
10525 p = strchr(types, c);
10528 subtype = p - types + VSNORMAL;
10534 subtype = c == '#' ? VSTRIMLEFT :
10547 if (dblquote || arinest)
10549 *((char *)stackblock() + typeloc) = subtype | flags;
10550 if (subtype != VSNORMAL) {
10552 if (dblquote || arinest) {
10557 goto parsesub_return;
10562 * Called to parse command substitutions. Newstyle is set if the command
10563 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10564 * list of commands (passed by reference), and savelen is the number of
10565 * characters on the top of the stack which must be preserved.
10569 struct nodelist **nlpp;
10572 char *volatile str;
10573 struct jmploc jmploc;
10574 struct jmploc *volatile savehandler;
10578 (void) &saveprompt;
10581 savepbq = parsebackquote;
10582 if (setjmp(jmploc.loc)) {
10585 parsebackquote = 0;
10586 handler = savehandler;
10587 longjmp(handler->loc, 1);
10591 savelen = out - (char *)stackblock();
10593 str = ckmalloc(savelen);
10594 memcpy(str, stackblock(), savelen);
10596 savehandler = handler;
10600 /* We must read until the closing backquote, giving special
10601 treatment to some slashes, and then push the string and
10602 reread it as input, interpreting it normally. */
10609 STARTSTACKSTR(pout);
10615 switch (pc = pgetc()) {
10620 if ((pc = pgetc()) == '\n') {
10625 * If eating a newline, avoid putting
10626 * the newline into the new character
10627 * stream (via the STPUTC after the
10632 if (pc != '\\' && pc != '`' && pc != '$'
10633 && (!dblquote || pc != '"'))
10634 STPUTC('\\', pout);
10635 if (pc > PEOA_OR_PEOF) {
10641 #ifdef CONFIG_ASH_ALIAS
10644 startlinno = plinno;
10645 synerror("EOF in backquote substitution");
10649 needprompt = doprompt;
10658 STPUTC('\0', pout);
10659 psavelen = pout - (char *)stackblock();
10660 if (psavelen > 0) {
10661 pstr = grabstackstr(pout);
10662 setinputstring(pstr);
10667 nlpp = &(*nlpp)->next;
10668 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10669 (*nlpp)->next = NULL;
10670 parsebackquote = oldstyle;
10673 saveprompt = doprompt;
10680 doprompt = saveprompt;
10682 if (readtoken() != TRP)
10689 * Start reading from old file again, ignoring any pushed back
10690 * tokens left from the backquote parsing
10695 while (stackblocksize() <= savelen)
10697 STARTSTACKSTR(out);
10699 memcpy(out, str, savelen);
10700 STADJUST(savelen, out);
10706 parsebackquote = savepbq;
10707 handler = savehandler;
10708 if (arinest || dblquote)
10709 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10711 USTPUTC(CTLBACKQ, out);
10713 goto parsebackq_oldreturn;
10715 goto parsebackq_newreturn;
10718 #ifdef CONFIG_ASH_MATH_SUPPORT
10720 * Parse an arithmetic expansion (indicate start of one and set state)
10724 if (++arinest == 1) {
10725 prevsyntax = syntax;
10726 syntax = ARISYNTAX;
10727 USTPUTC(CTLARI, out);
10734 * we collapse embedded arithmetic expansion to
10735 * parenthesis, which should be equivalent
10739 goto parsearith_return;
10743 } /* end of readtoken */
10748 * Returns true if the text contains nothing to expand (no dollar signs
10753 noexpand(char *text)
10759 while ((c = *p++) != '\0') {
10760 if (c == CTLQUOTEMARK)
10764 else if (SIT(c, BASESYNTAX) == CCTL)
10772 * Return of a legal variable name (a letter or underscore followed by zero or
10773 * more letters, underscores, and digits).
10777 endofname(const char *name)
10785 if (! is_in_name(*p))
10793 * Called when an unexpected token is read during the parse. The argument
10794 * is the token that is expected, or -1 if more than one type of token can
10795 * occur at this point.
10798 static void synexpect(int token)
10803 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10805 sprintf(msg + l, " (expecting %s)", tokname(token));
10811 synerror(const char *msg)
10813 error("Syntax error: %s", msg);
10819 * called by editline -- any expansions to the prompt
10820 * should be added here.
10823 static void setprompt(int whichprompt)
10825 const char *prompt;
10827 switch (whichprompt) {
10841 static const char *const *findkwd(const char *s)
10843 return bsearch(s, tokname_array + KWDOFFSET,
10844 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
10845 sizeof(const char *), pstrcmp);
10848 /* $NetBSD: redir.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
10851 * Code for dealing with input/output redirection.
10854 #define EMPTY -2 /* marks an unused slot in redirtab */
10856 # define PIPESIZE 4096 /* amount of buffering in a pipe */
10858 # define PIPESIZE PIPE_BUF
10862 * Open a file in noclobber mode.
10863 * The code was copied from bash.
10866 noclobberopen(const char *fname)
10869 struct stat finfo, finfo2;
10872 * If the file exists and is a regular file, return an error
10875 r = stat(fname, &finfo);
10876 if (r == 0 && S_ISREG(finfo.st_mode)) {
10882 * If the file was not present (r != 0), make sure we open it
10883 * exclusively so that if it is created before we open it, our open
10884 * will fail. Make sure that we do not truncate an existing file.
10885 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10886 * file was not a regular file, we leave O_EXCL off.
10889 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10890 fd = open(fname, O_WRONLY|O_CREAT, 0666);
10892 /* If the open failed, return the file descriptor right away. */
10897 * OK, the open succeeded, but the file may have been changed from a
10898 * non-regular file to a regular file between the stat and the open.
10899 * We are assuming that the O_EXCL open handles the case where FILENAME
10900 * did not exist and is symlinked to an existing file between the stat
10905 * If we can open it and fstat the file descriptor, and neither check
10906 * revealed that it was a regular file, and the file has not been
10907 * replaced, return the file descriptor.
10909 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10910 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
10913 /* The file has been replaced. badness. */
10920 * Handle here documents. Normally we fork off a process to write the
10921 * data to a pipe. If the document is short, we can stuff the data in
10922 * the pipe without forking.
10926 openhere(union node *redir)
10932 error("Pipe call failed");
10933 if (redir->type == NHERE) {
10934 len = strlen(redir->nhere.doc->narg.text);
10935 if (len <= PIPESIZE) {
10936 xwrite(pip[1], redir->nhere.doc->narg.text, len);
10940 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
10942 signal(SIGINT, SIG_IGN);
10943 signal(SIGQUIT, SIG_IGN);
10944 signal(SIGHUP, SIG_IGN);
10946 signal(SIGTSTP, SIG_IGN);
10948 signal(SIGPIPE, SIG_DFL);
10949 if (redir->type == NHERE)
10950 xwrite(pip[1], redir->nhere.doc->narg.text, len);
10952 expandhere(redir->nhere.doc, pip[1]);
10961 openredirect(union node *redir)
10966 switch (redir->nfile.type) {
10968 fname = redir->nfile.expfname;
10969 if ((f = open(fname, O_RDONLY)) < 0)
10973 fname = redir->nfile.expfname;
10974 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
10978 /* Take care of noclobber mode. */
10980 fname = redir->nfile.expfname;
10981 if ((f = noclobberopen(fname)) < 0)
10987 fname = redir->nfile.expfname;
10988 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
10992 fname = redir->nfile.expfname;
10993 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
11000 /* Fall through to eliminate warning. */
11007 f = openhere(redir);
11013 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
11015 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11019 dupredirect(union node *redir, int f)
11021 int fd = redir->nfile.fd;
11023 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11024 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
11025 copyfd(redir->ndup.dupfd, fd);
11038 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11039 * old file descriptors are stashed away so that the redirection can be
11040 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11041 * standard output, and the standard error if it becomes a duplicate of
11042 * stdout, is saved in memory.
11046 redirect(union node *redir, int flags)
11049 struct redirtab *sv;
11060 if (flags & REDIR_PUSH) {
11061 struct redirtab *q;
11062 q = ckmalloc(sizeof (struct redirtab));
11063 q->next = redirlist;
11065 q->nullredirs = nullredirs - 1;
11066 for (i = 0 ; i < 10 ; i++)
11067 q->renamed[i] = EMPTY;
11074 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
11075 n->ndup.dupfd == fd)
11076 continue; /* redirect from/to same file descriptor */
11078 newfd = openredirect(n);
11081 if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
11082 i = fcntl(fd, F_DUPFD, 10);
11089 error("%d: %m", fd);
11099 dupredirect(n, newfd);
11100 } while ((n = n->nfile.next));
11102 if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
11103 preverrout_fd = sv->renamed[2];
11108 * Undo the effects of the last redirection.
11114 struct redirtab *rp;
11117 if (--nullredirs >= 0)
11121 for (i = 0 ; i < 10 ; i++) {
11122 if (rp->renamed[i] != EMPTY) {
11125 copyfd(rp->renamed[i], i);
11127 close(rp->renamed[i]);
11130 redirlist = rp->next;
11131 nullredirs = rp->nullredirs;
11137 * Undo all redirections. Called on error or interrupt.
11141 * Discard all saved file descriptors.
11145 clearredir(int drop)
11157 * Copy a file descriptor to be >= to. Returns -1
11158 * if the source file descriptor is closed, EMPTY if there are no unused
11159 * file descriptors left.
11163 copyfd(int from, int to)
11167 newfd = fcntl(from, F_DUPFD, to);
11169 if (errno == EMFILE)
11172 error("%d: %m", from);
11179 redirectsafe(union node *redir, int flags)
11182 volatile int saveint;
11183 struct jmploc *volatile savehandler = handler;
11184 struct jmploc jmploc;
11187 if (!(err = setjmp(jmploc.loc) * 2)) {
11189 redirect(redir, flags);
11191 handler = savehandler;
11192 if (err && exception != EXERROR)
11193 longjmp(handler->loc, 1);
11194 RESTOREINT(saveint);
11198 /* $NetBSD: show.c,v 1.24 2003/01/22 20:36:04 dsl Exp $ */
11201 static void shtree(union node *, int, char *, FILE*);
11202 static void shcmd(union node *, FILE *);
11203 static void sharg(union node *, FILE *);
11204 static void indent(int, char *, FILE *);
11205 static void trstring(char *);
11209 showtree(union node *n)
11211 trputs("showtree called\n");
11212 shtree(n, 1, NULL, stdout);
11217 shtree(union node *n, int ind, char *pfx, FILE *fp)
11219 struct nodelist *lp;
11225 indent(ind, pfx, fp);
11236 shtree(n->nbinary.ch1, ind, NULL, fp);
11239 shtree(n->nbinary.ch2, ind, NULL, fp);
11247 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
11252 if (n->npipe.backgnd)
11258 fprintf(fp, "<node type %d>", n->type);
11267 shcmd(union node *cmd, FILE *fp)
11275 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11281 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11284 switch (np->nfile.type) {
11285 case NTO: s = ">"; dftfd = 1; break;
11286 case NCLOBBER: s = ">|"; dftfd = 1; break;
11287 case NAPPEND: s = ">>"; dftfd = 1; break;
11288 case NTOFD: s = ">&"; dftfd = 1; break;
11289 case NFROM: s = "<"; dftfd = 0; break;
11290 case NFROMFD: s = "<&"; dftfd = 0; break;
11291 case NFROMTO: s = "<>"; dftfd = 0; break;
11292 default: s = "*error*"; dftfd = 0; break;
11294 if (np->nfile.fd != dftfd)
11295 fprintf(fp, "%d", np->nfile.fd);
11297 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11298 fprintf(fp, "%d", np->ndup.dupfd);
11300 sharg(np->nfile.fname, fp);
11309 sharg(union node *arg, FILE *fp)
11312 struct nodelist *bqlist;
11315 if (arg->type != NARG) {
11316 out1fmt("<node type %d>\n", arg->type);
11319 bqlist = arg->narg.backquote;
11320 for (p = arg->narg.text ; *p ; p++) {
11329 if (subtype == VSLENGTH)
11335 if (subtype & VSNUL)
11338 switch (subtype & VSTYPE) {
11357 case VSTRIMLEFTMAX:
11364 case VSTRIMRIGHTMAX:
11371 out1fmt("<subtype %d>", subtype);
11378 case CTLBACKQ|CTLQUOTE:
11381 shtree(bqlist->n, -1, NULL, fp);
11393 indent(int amount, char *pfx, FILE *fp)
11397 for (i = 0 ; i < amount ; i++) {
11398 if (pfx && i == amount - 1)
11419 putc(c, tracefile);
11423 trace(const char *fmt, ...)
11430 (void) vfprintf(tracefile, fmt, va);
11435 tracev(const char *fmt, va_list va)
11439 (void) vfprintf(tracefile, fmt, va);
11444 trputs(const char *s)
11448 fputs(s, tracefile);
11460 putc('"', tracefile);
11461 for (p = s ; *p ; p++) {
11463 case '\n': c = 'n'; goto backslash;
11464 case '\t': c = 't'; goto backslash;
11465 case '\r': c = 'r'; goto backslash;
11466 case '"': c = '"'; goto backslash;
11467 case '\\': c = '\\'; goto backslash;
11468 case CTLESC: c = 'e'; goto backslash;
11469 case CTLVAR: c = 'v'; goto backslash;
11470 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11471 case CTLBACKQ: c = 'q'; goto backslash;
11472 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
11473 backslash: putc('\\', tracefile);
11474 putc(c, tracefile);
11477 if (*p >= ' ' && *p <= '~')
11478 putc(*p, tracefile);
11480 putc('\\', tracefile);
11481 putc(*p >> 6 & 03, tracefile);
11482 putc(*p >> 3 & 07, tracefile);
11483 putc(*p & 07, tracefile);
11488 putc('"', tracefile);
11500 putc(' ', tracefile);
11502 putc('\n', tracefile);
11518 /* leave open because libedit might be using it */
11521 scopy("./trace", s);
11523 if (!freopen(s, "a", tracefile)) {
11524 fprintf(stderr, "Can't re-open %s\n", s);
11529 if ((tracefile = fopen(s, "a")) == NULL) {
11530 fprintf(stderr, "Can't open %s\n", s);
11536 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11537 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11539 setlinebuf(tracefile);
11540 fputs("\nTracing started.\n", tracefile);
11545 /* $NetBSD: trap.c,v 1.28 2002/11/24 22:35:43 christos Exp $ */
11548 * Sigmode records the current value of the signal handlers for the various
11549 * modes. A value of zero means that the current handler is not known.
11550 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
11553 #define S_DFL 1 /* default signal handling (SIG_DFL) */
11554 #define S_CATCH 2 /* signal is caught */
11555 #define S_IGN 3 /* signal is ignored (SIG_IGN) */
11556 #define S_HARD_IGN 4 /* signal is ignored permenantly */
11557 #define S_RESET 5 /* temporary - to reset a hard ignored sig */
11562 * The trap builtin.
11566 trapcmd(int argc, char **argv)
11575 for (signo = 0 ; signo < NSIG ; signo++) {
11576 if (trap[signo] != NULL) {
11579 sn = u_signal_names(0, &signo, 0);
11582 out1fmt("trap -- %s %s\n",
11583 single_quote(trap[signo]), sn);
11593 if ((signo = decode_signal(*ap, 0)) < 0)
11594 error("%s: bad trap", *ap);
11597 if (action[0] == '-' && action[1] == '\0')
11600 action = savestr(action);
11603 ckfree(trap[signo]);
11604 trap[signo] = action;
11615 * Clear traps on a fork.
11623 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
11624 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
11628 if (tp != &trap[0])
11629 setsignal(tp - trap);
11637 * Set the signal handler for the specified signal. The routine figures
11638 * out what it should be set to.
11642 setsignal(int signo)
11646 struct sigaction act;
11648 if ((t = trap[signo]) == NULL)
11650 else if (*t != '\0')
11654 if (rootshell && action == S_DFL) {
11657 if (iflag || minusc || sflag == 0)
11680 t = &sigmode[signo - 1];
11684 * current setting unknown
11686 if (sigaction(signo, 0, &act) == -1) {
11688 * Pretend it worked; maybe we should give a warning
11689 * here, but other shells don't. We don't alter
11690 * sigmode, so that we retry every time.
11694 if (act.sa_handler == SIG_IGN) {
11695 if (mflag && (signo == SIGTSTP ||
11696 signo == SIGTTIN || signo == SIGTTOU)) {
11697 tsig = S_IGN; /* don't hard ignore these */
11701 tsig = S_RESET; /* force to be set */
11704 if (tsig == S_HARD_IGN || tsig == action)
11708 act.sa_handler = onsig;
11711 act.sa_handler = SIG_IGN;
11714 act.sa_handler = SIG_DFL;
11718 sigfillset(&act.sa_mask);
11719 sigaction(signo, &act, 0);
11727 ignoresig(int signo)
11729 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11730 signal(signo, SIG_IGN);
11732 sigmode[signo - 1] = S_HARD_IGN;
11743 gotsig[signo - 1] = 1;
11744 pendingsigs = signo;
11746 if (exsig || (signo == SIGINT && !trap[SIGINT])) {
11755 * Called to execute a trap. Perhaps we should avoid entering new trap
11756 * handlers while we are executing a trap handler.
11766 savestatus = exitstatus;
11768 while (pendingsigs = 0, barrier(), (p = memchr(q, 1, NSIG - 1))) {
11770 p = trap[p - q + 1];
11774 exitstatus = savestatus;
11780 * Controls whether the shell is interactive or not.
11784 setinteractive(int on)
11786 static int is_interactive;
11788 if (++on == is_interactive)
11790 is_interactive = on;
11792 setsignal(SIGQUIT);
11793 setsignal(SIGTERM);
11794 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11795 if(is_interactive > 1) {
11796 /* Looks like they want an interactive shell */
11797 static int do_banner;
11801 "\n\n" BB_BANNER " Built-in shell (ash)\n"
11802 "Enter 'help' for a list of built-in commands.\n\n");
11810 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11811 /*** List the available builtins ***/
11813 static int helpcmd(int argc, char **argv)
11817 out1fmt("\nBuilt-in commands:\n-------------------\n");
11818 for (col = 0, i = 0; i < NUMBUILTINS; i++) {
11819 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11820 builtincmd[i].name + 1);
11826 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
11828 extern const struct BB_applet applets[];
11829 extern const size_t NUM_APPLETS;
11831 for (i = 0; i < NUM_APPLETS; i++) {
11833 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
11842 return EXIT_SUCCESS;
11844 #endif /* CONFIG_FEATURE_SH_EXTRA_QUIET */
11847 * Called to exit the shell.
11857 status = exitstatus;
11858 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
11859 if (setjmp(loc.loc)) {
11863 if ((p = trap[0]) != NULL && *p != '\0') {
11868 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
11869 if (iflag && rootshell) {
11870 const char *hp = lookupvar("HISTFILE");
11873 save_history ( hp );
11881 static int decode_signal(const char *string, int minsig)
11884 const char *name = u_signal_names(string, &signo, minsig);
11886 return name ? signo : -1;
11889 /* $NetBSD: var.c,v 1.32 2003/01/22 20:36:04 dsl Exp $ */
11891 static struct var *vartab[VTABSIZE];
11893 static int vpcmp(const void *, const void *);
11894 static struct var **findvar(struct var **, const char *);
11897 * Initialize the varable symbol tables and import the environment
11901 #ifdef CONFIG_ASH_GETOPTS
11903 * Safe version of setvar, returns 1 on success 0 on failure.
11907 setvarsafe(const char *name, const char *val, int flags)
11910 volatile int saveint;
11911 struct jmploc *volatile savehandler = handler;
11912 struct jmploc jmploc;
11915 if (setjmp(jmploc.loc))
11919 setvar(name, val, flags);
11922 handler = savehandler;
11923 RESTOREINT(saveint);
11929 * Set the value of a variable. The flags argument is ored with the
11930 * flags of the variable. If val is NULL, the variable is unset.
11934 setvar(const char *name, const char *val, int flags)
11941 q = endofname(name);
11942 p = strchrnul(q, '=');
11943 namelen = p - name;
11944 if (!namelen || p != q)
11945 error("%.*s: bad variable name", namelen, name);
11950 vallen = strlen(val);
11953 p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
11957 p = mempcpy(p, val, vallen);
11960 setvareq(nameeq, flags | VNOSAVE);
11966 * Same as setvar except that the variable and value are passed in
11967 * the first argument as name=value. Since the first argument will
11968 * be actually stored in the table, it should not be a string that
11970 * Called with interrupts off.
11974 setvareq(char *s, int flags)
11976 struct var *vp, **vpp;
11979 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
11980 vp = *findvar(vpp, s);
11982 if (vp->flags & VREADONLY) {
11983 if (flags & VNOSAVE)
11985 error("%.*s: is read only", strchrnul(s, '=') - s, s);
11988 if (flags & VNOSET)
11991 if (vp->func && (flags & VNOFUNC) == 0)
11992 (*vp->func)(strchrnul(s, '=') + 1);
11994 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
11997 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
11999 if (flags & VNOSET)
12002 vp = ckmalloc(sizeof (*vp));
12007 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
12015 * Process a linked list of variable assignments.
12019 listsetvar(struct strlist *list_set_var, int flags)
12021 struct strlist *lp = list_set_var;
12027 setvareq(lp->text, flags);
12028 } while ((lp = lp->next));
12034 * Find the value of a variable. Returns NULL if not set.
12038 lookupvar(const char *name)
12042 if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
12043 return strchrnul(v->text, '=') + 1;
12050 * Search the environment of a builtin command.
12054 bltinlookup(const char *name)
12056 struct strlist *sp;
12058 for (sp = cmdenviron ; sp ; sp = sp->next) {
12059 if (varequal(sp->text, name))
12060 return strchrnul(sp->text, '=') + 1;
12062 return lookupvar(name);
12067 * Generate a list of variables satisfying the given conditions.
12071 listvars(int on, int off, char ***end)
12082 for (vp = *vpp ; vp ; vp = vp->next)
12083 if ((vp->flags & mask) == on) {
12084 if (ep == stackstrend())
12085 ep = growstackstr();
12086 *ep++ = (char *) vp->text;
12088 } while (++vpp < vartab + VTABSIZE);
12089 if (ep == stackstrend())
12090 ep = growstackstr();
12094 return grabstackstr(ep);
12099 * POSIX requires that 'set' (but not export or readonly) output the
12100 * variables in lexicographic order - by the locale's collating order (sigh).
12101 * Maybe we could keep them in an ordered balanced binary tree
12102 * instead of hashed lists.
12103 * For now just roll 'em through qsort for printing...
12107 showvars(const char *sep_prefix, int on, int off)
12110 char **ep, **epend;
12112 ep = listvars(on, off, &epend);
12113 qsort(ep, epend - ep, sizeof(char *), vpcmp);
12115 sep = *sep_prefix ? spcstr : sep_prefix;
12117 for (; ep < epend; ep++) {
12121 p = strchrnul(*ep, '=');
12124 q = single_quote(++p);
12126 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
12135 * The export and readonly commands.
12139 exportcmd(int argc, char **argv)
12145 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12148 notp = nextopt("p") - 'p';
12149 if (notp && ((name = *(aptr = argptr)))) {
12151 if ((p = strchr(name, '=')) != NULL) {
12154 if ((vp = *findvar(hashvar(name), name))) {
12159 setvar(name, p, flag);
12160 } while ((name = *++aptr) != NULL);
12162 showvars(argv[0], flag, 0);
12169 * Make a variable a local variable. When a variable is made local, it's
12170 * value and flags are saved in a localvar structure. The saved values
12171 * will be restored when the shell function returns. We handle the name
12172 * "-" as a special case.
12176 mklocal(char *name)
12178 struct localvar *lvp;
12183 lvp = ckmalloc(sizeof (struct localvar));
12184 if (name[0] == '-' && name[1] == '\0') {
12186 p = ckmalloc(sizeof(optlist));
12187 lvp->text = memcpy(p, optlist, sizeof(optlist));
12192 vpp = hashvar(name);
12193 vp = *findvar(vpp, name);
12194 eq = strchr(name, '=');
12197 setvareq(name, VSTRFIXED);
12199 setvar(name, NULL, VSTRFIXED);
12200 vp = *vpp; /* the new variable */
12201 lvp->flags = VUNSET;
12203 lvp->text = vp->text;
12204 lvp->flags = vp->flags;
12205 vp->flags |= VSTRFIXED|VTEXTFIXED;
12211 lvp->next = localvars;
12217 * The "local" command.
12221 localcmd(int argc, char **argv)
12226 while ((name = *argv++) != NULL) {
12234 * Called after a function returns.
12235 * Interrupts must be off.
12241 struct localvar *lvp;
12244 while ((lvp = localvars) != NULL) {
12245 localvars = lvp->next;
12247 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
12248 if (vp == NULL) { /* $- saved */
12249 memcpy(optlist, lvp->text, sizeof(optlist));
12252 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12253 unsetvar(vp->text);
12256 (*vp->func)(strchrnul(lvp->text, '=') + 1);
12257 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12259 vp->flags = lvp->flags;
12260 vp->text = lvp->text;
12268 * The unset builtin command. We unset the function before we unset the
12269 * variable to allow a function to be unset when there is a readonly variable
12270 * with the same name.
12274 unsetcmd(int argc, char **argv)
12281 while ((i = nextopt("vf")) != '\0') {
12285 for (ap = argptr; *ap ; ap++) {
12300 * Unset the specified variable.
12304 unsetvar(const char *s)
12310 vpp = findvar(hashvar(s), s);
12314 int flags = vp->flags;
12317 if (flags & VREADONLY)
12319 if (flags & VUNSET)
12321 if ((flags & VSTRFIXED) == 0) {
12323 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
12330 vp->flags &= ~VEXPORT;
12343 * Find the appropriate entry in the hash table from the name.
12346 static struct var **
12347 hashvar(const char *p)
12349 unsigned int hashval;
12351 hashval = ((unsigned char) *p) << 4;
12352 while (*p && *p != '=')
12353 hashval += (unsigned char) *p++;
12354 return &vartab[hashval % VTABSIZE];
12360 * Compares two strings up to the first = or '\0'. The first
12361 * string must be terminated by '='; the second may be terminated by
12362 * either '=' or '\0'.
12366 varcmp(const char *p, const char *q)
12370 while ((c = *p) == (d = *q)) {
12371 if (!c || c == '=')
12385 vpcmp(const void *a, const void *b)
12387 return varcmp(*(const char **)a, *(const char **)b);
12390 static struct var **
12391 findvar(struct var **vpp, const char *name)
12393 for (; *vpp; vpp = &(*vpp)->next) {
12394 if (varequal((*vpp)->text, name)) {
12400 /* $NetBSD: setmode.c,v 1.29 2003/01/15 23:58:03 kleink Exp $ */
12402 #include <sys/times.h>
12404 static const unsigned char timescmd_str[] = {
12405 ' ', offsetof(struct tms, tms_utime),
12406 '\n', offsetof(struct tms, tms_stime),
12407 ' ', offsetof(struct tms, tms_cutime),
12408 '\n', offsetof(struct tms, tms_cstime),
12412 static int timescmd(int ac, char **av)
12414 long int clk_tck, s, t;
12415 const unsigned char *p;
12418 clk_tck = sysconf(_SC_CLK_TCK);
12423 t = *(clock_t *)(((char *) &buf) + p[1]);
12425 out1fmt("%ldm%ld.%.3lds%c",
12427 ((t - s * clk_tck) * 1000) / clk_tck,
12429 } while (*(p += 2));
12434 #ifdef CONFIG_ASH_MATH_SUPPORT
12436 dash_arith(const char *s)
12442 result = arith(s, &errcode);
12445 error("exponent less than 0");
12446 else if (errcode == -2)
12447 error("divide by zero");
12448 else if (errcode == -5)
12449 error("expression recursion loop detected");
12460 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12461 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12463 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12467 letcmd(int argc, char **argv)
12474 error("expression expected");
12475 for (ap = argv + 1; *ap; ap++) {
12476 i = dash_arith(*ap);
12481 #endif /* CONFIG_ASH_MATH_SUPPORT */
12483 /* $NetBSD: miscbltin.c,v 1.31 2002/11/24 22:35:41 christos Exp $ */
12486 * Miscelaneous builtins.
12492 #if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
12493 typedef enum __rlimit_resource rlim_t;
12499 * The read builtin. The -e option causes backslashes to escape the
12500 * following character.
12502 * This uses unbuffered input, which may be avoidable in some cases.
12506 readcmd(int argc, char **argv)
12521 while ((i = nextopt("p:r")) != '\0') {
12523 prompt = optionarg;
12527 if (prompt && isatty(0)) {
12530 if (*(ap = argptr) == NULL)
12531 error("arg count");
12532 if ((ifs = bltinlookup("IFS")) == NULL)
12539 if (read(0, &c, 1) != 1) {
12551 if (!rflag && c == '\\') {
12557 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12561 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12563 setvar(*ap, stackblock(), 0);
12573 /* Remove trailing blanks */
12574 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12576 setvar(*ap, stackblock(), 0);
12577 while (*++ap != NULL)
12578 setvar(*ap, nullstr, 0);
12583 static int umaskcmd(int argc, char **argv)
12585 static const char permuser[3] = "ugo";
12586 static const char permmode[3] = "rwx";
12587 static const short int permmask[] = {
12588 S_IRUSR, S_IWUSR, S_IXUSR,
12589 S_IRGRP, S_IWGRP, S_IXGRP,
12590 S_IROTH, S_IWOTH, S_IXOTH
12596 int symbolic_mode = 0;
12598 while (nextopt("S") != '\0') {
12607 if ((ap = *argptr) == NULL) {
12608 if (symbolic_mode) {
12612 for (i = 0; i < 3; i++) {
12615 *p++ = permuser[i];
12617 for (j = 0; j < 3; j++) {
12618 if ((mask & permmask[3 * i + j]) == 0) {
12619 *p++ = permmode[j];
12627 out1fmt("%.4o\n", mask);
12630 if (is_digit((unsigned char) *ap)) {
12633 if (*ap >= '8' || *ap < '0')
12634 error(illnum, argv[1]);
12635 mask = (mask << 3) + (*ap - '0');
12636 } while (*++ap != '\0');
12639 mask = ~mask & 0777;
12640 if (!bb_parse_mode(ap, &mask)) {
12641 error("Illegal mode: %s", ap);
12643 umask(~mask & 0777);
12652 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12653 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12654 * ash by J.T. Conklin.
12662 int factor; /* multiply by to get rlim_{cur,max} values */
12666 static const struct limits limits[] = {
12668 { "time(seconds)", RLIMIT_CPU, 1, 't' },
12670 #ifdef RLIMIT_FSIZE
12671 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
12674 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
12676 #ifdef RLIMIT_STACK
12677 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
12680 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
12683 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
12685 #ifdef RLIMIT_MEMLOCK
12686 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
12688 #ifdef RLIMIT_NPROC
12689 { "process(processes)", RLIMIT_NPROC, 1, 'p' },
12691 #ifdef RLIMIT_NOFILE
12692 { "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' },
12695 { "vmemory(kbytes)", RLIMIT_VMEM, 1024, 'v' },
12698 { "swap(kbytes)", RLIMIT_SWAP, 1024, 'w' },
12700 { (char *) 0, 0, 0, '\0' }
12704 ulimitcmd(int argc, char **argv)
12708 enum { SOFT = 0x1, HARD = 0x2 }
12710 const struct limits *l;
12713 struct rlimit limit;
12716 while ((optc = nextopt("HSatfdsmcnpl")) != '\0')
12731 for (l = limits; l->name && l->option != what; l++)
12734 error("internal error (%c)", what);
12736 set = *argptr ? 1 : 0;
12740 if (all || argptr[1])
12741 error("too many arguments");
12742 if (strncmp(p, "unlimited\n", 9) == 0)
12743 val = RLIM_INFINITY;
12747 while ((c = *p++) >= '0' && c <= '9')
12749 val = (val * 10) + (long)(c - '0');
12750 if (val < (rlim_t) 0)
12754 error("bad number");
12759 for (l = limits; l->name; l++) {
12760 getrlimit(l->cmd, &limit);
12762 val = limit.rlim_cur;
12763 else if (how & HARD)
12764 val = limit.rlim_max;
12766 out1fmt("%-20s ", l->name);
12767 if (val == RLIM_INFINITY)
12768 out1fmt("unlimited\n");
12772 out1fmt("%lld\n", (long long) val);
12778 getrlimit(l->cmd, &limit);
12781 limit.rlim_max = val;
12783 limit.rlim_cur = val;
12784 if (setrlimit(l->cmd, &limit) < 0)
12785 error("error setting limit (%m)");
12788 val = limit.rlim_cur;
12789 else if (how & HARD)
12790 val = limit.rlim_max;
12792 if (val == RLIM_INFINITY)
12793 out1fmt("unlimited\n");
12797 out1fmt("%lld\n", (long long) val);
12804 #ifdef CONFIG_ASH_MATH_SUPPORT
12806 /* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
12808 Permission is hereby granted, free of charge, to any person obtaining
12809 a copy of this software and associated documentation files (the
12810 "Software"), to deal in the Software without restriction, including
12811 without limitation the rights to use, copy, modify, merge, publish,
12812 distribute, sublicense, and/or sell copies of the Software, and to
12813 permit persons to whom the Software is furnished to do so, subject to
12814 the following conditions:
12816 The above copyright notice and this permission notice shall be
12817 included in all copies or substantial portions of the Software.
12819 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12820 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12821 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
12822 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
12823 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
12824 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
12825 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12828 /* This is my infix parser/evaluator. It is optimized for size, intended
12829 * as a replacement for yacc-based parsers. However, it may well be faster
12830 * than a comparable parser writen in yacc. The supported operators are
12831 * listed in #defines below. Parens, order of operations, and error handling
12832 * are supported. This code is threadsafe. The exact expression format should
12833 * be that which POSIX specifies for shells. */
12835 /* The code uses a simple two-stack algorithm. See
12836 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
12837 * for a detailed explaination of the infix-to-postfix algorithm on which
12838 * this is based (this code differs in that it applies operators immediately
12839 * to the stack instead of adding them to a queue to end up with an
12842 /* To use the routine, call it with an expression string and error return
12846 * Aug 24, 2001 Manuel Novoa III
12848 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
12850 * 1) In arith_apply():
12851 * a) Cached values of *numptr and &(numptr[-1]).
12852 * b) Removed redundant test for zero denominator.
12855 * a) Eliminated redundant code for processing operator tokens by moving
12856 * to a table-based implementation. Also folded handling of parens
12858 * b) Combined all 3 loops which called arith_apply to reduce generated
12859 * code size at the cost of speed.
12861 * 3) The following expressions were treated as valid by the original code:
12862 * 1() , 0! , 1 ( *3 ) .
12863 * These bugs have been fixed by internally enclosing the expression in
12864 * parens and then checking that all binary ops and right parens are
12865 * preceded by a valid expression (NUM_TOKEN).
12867 * Note: It may be desireable to replace Aaron's test for whitespace with
12868 * ctype's isspace() if it is used by another busybox applet or if additional
12869 * whitespace chars should be considered. Look below the "#include"s for a
12870 * precompiler test.
12874 * Aug 26, 2001 Manuel Novoa III
12876 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
12878 * Merge in Aaron's comments previously posted to the busybox list,
12879 * modified slightly to take account of my changes to the code.
12884 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12886 * - allow access to variable,
12887 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
12888 * - realize assign syntax (VAR=expr, +=, *= etc)
12889 * - realize exponentiation (** operator)
12890 * - realize comma separated - expr, expr
12891 * - realise ++expr --expr expr++ expr--
12892 * - realise expr ? expr : expr (but, second expr calculate always)
12893 * - allow hexdecimal and octal numbers
12894 * - was restored loses XOR operator
12895 * - remove one goto label, added three ;-)
12896 * - protect $((num num)) as true zero expr (Manuel`s error)
12897 * - always use special isspace(), see comment from bash ;-)
12901 #define arith_isspace(arithval) \
12902 (arithval == ' ' || arithval == '\n' || arithval == '\t')
12905 typedef unsigned char operator;
12907 /* An operator's token id is a bit of a bitfield. The lower 5 bits are the
12908 * precedence, and 3 high bits are an ID unique accross operators of that
12909 * precedence. The ID portion is so that multiple operators can have the
12910 * same precedence, ensuring that the leftmost one is evaluated first.
12911 * Consider * and /. */
12913 #define tok_decl(prec,id) (((id)<<5)|(prec))
12914 #define PREC(op) ((op) & 0x1F)
12916 #define TOK_LPAREN tok_decl(0,0)
12918 #define TOK_COMMA tok_decl(1,0)
12920 #define TOK_ASSIGN tok_decl(2,0)
12921 #define TOK_AND_ASSIGN tok_decl(2,1)
12922 #define TOK_OR_ASSIGN tok_decl(2,2)
12923 #define TOK_XOR_ASSIGN tok_decl(2,3)
12924 #define TOK_PLUS_ASSIGN tok_decl(2,4)
12925 #define TOK_MINUS_ASSIGN tok_decl(2,5)
12926 #define TOK_LSHIFT_ASSIGN tok_decl(2,6)
12927 #define TOK_RSHIFT_ASSIGN tok_decl(2,7)
12929 #define TOK_MUL_ASSIGN tok_decl(3,0)
12930 #define TOK_DIV_ASSIGN tok_decl(3,1)
12931 #define TOK_REM_ASSIGN tok_decl(3,2)
12933 /* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
12934 #define convert_prec_is_assing(prec) do { if(prec == 3) prec = 2; } while(0)
12936 /* conditional is right associativity too */
12937 #define TOK_CONDITIONAL tok_decl(4,0)
12938 #define TOK_CONDITIONAL_SEP tok_decl(4,1)
12940 #define TOK_OR tok_decl(5,0)
12942 #define TOK_AND tok_decl(6,0)
12944 #define TOK_BOR tok_decl(7,0)
12946 #define TOK_BXOR tok_decl(8,0)
12948 #define TOK_BAND tok_decl(9,0)
12950 #define TOK_EQ tok_decl(10,0)
12951 #define TOK_NE tok_decl(10,1)
12953 #define TOK_LT tok_decl(11,0)
12954 #define TOK_GT tok_decl(11,1)
12955 #define TOK_GE tok_decl(11,2)
12956 #define TOK_LE tok_decl(11,3)
12958 #define TOK_LSHIFT tok_decl(12,0)
12959 #define TOK_RSHIFT tok_decl(12,1)
12961 #define TOK_ADD tok_decl(13,0)
12962 #define TOK_SUB tok_decl(13,1)
12964 #define TOK_MUL tok_decl(14,0)
12965 #define TOK_DIV tok_decl(14,1)
12966 #define TOK_REM tok_decl(14,2)
12968 /* exponent is right associativity */
12969 #define TOK_EXPONENT tok_decl(15,1)
12971 /* For now unary operators. */
12972 #define UNARYPREC 16
12973 #define TOK_BNOT tok_decl(UNARYPREC,0)
12974 #define TOK_NOT tok_decl(UNARYPREC,1)
12976 #define TOK_UMINUS tok_decl(UNARYPREC+1,0)
12977 #define TOK_UPLUS tok_decl(UNARYPREC+1,1)
12979 #define PREC_PRE (UNARYPREC+2)
12981 #define TOK_PRE_INC tok_decl(PREC_PRE, 0)
12982 #define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
12984 #define PREC_POST (UNARYPREC+3)
12986 #define TOK_POST_INC tok_decl(PREC_POST, 0)
12987 #define TOK_POST_DEC tok_decl(PREC_POST, 1)
12989 #define SPEC_PREC (UNARYPREC+4)
12991 #define TOK_NUM tok_decl(SPEC_PREC, 0)
12992 #define TOK_RPAREN tok_decl(SPEC_PREC, 1)
12994 #define NUMPTR (*numstackptr)
12996 static inline int tok_have_assign(operator op)
12998 operator prec = PREC(op);
13000 convert_prec_is_assing(prec);
13001 return (prec == PREC(TOK_ASSIGN) ||
13002 prec == PREC_PRE || prec == PREC_POST);
13005 static inline int is_right_associativity(operator prec)
13007 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) ||
13008 prec == PREC(TOK_CONDITIONAL));
13012 typedef struct ARITCH_VAR_NUM {
13014 long contidional_second_val;
13015 char contidional_second_val_initialized;
13016 char *var; /* if NULL then is regular number,
13017 else is varable name */
13021 typedef struct CHK_VAR_RECURSIVE_LOOPED {
13023 struct CHK_VAR_RECURSIVE_LOOPED *next;
13024 } chk_var_recursive_looped_t;
13026 static chk_var_recursive_looped_t *prev_chk_var_recursive;
13029 static int arith_lookup_val(v_n_t *t)
13032 const char * p = lookupvar(t->var);
13037 /* recursive try as expression */
13038 chk_var_recursive_looped_t *cur;
13039 chk_var_recursive_looped_t cur_save;
13041 for(cur = prev_chk_var_recursive; cur; cur = cur->next) {
13042 if(strcmp(cur->var, t->var) == 0) {
13043 /* expression recursion loop detected */
13047 /* save current lookuped var name */
13048 cur = prev_chk_var_recursive;
13049 cur_save.var = t->var;
13050 cur_save.next = cur;
13051 prev_chk_var_recursive = &cur_save;
13053 t->val = arith (p, &errcode);
13054 /* restore previous ptr after recursiving */
13055 prev_chk_var_recursive = cur;
13058 /* allow undefined var as 0 */
13065 /* "applying" a token means performing it on the top elements on the integer
13066 * stack. For a unary operator it will only change the top element, but a
13067 * binary operator will pop two arguments and push a result */
13069 arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
13074 int ret_arith_lookup_val;
13076 if (NUMPTR == numstack) goto err; /* There is no operator that can work
13077 without arguments */
13078 numptr_m1 = NUMPTR - 1;
13080 /* check operand is var with noninteger value */
13081 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13082 if(ret_arith_lookup_val)
13083 return ret_arith_lookup_val;
13085 rez = numptr_m1->val;
13086 if (op == TOK_UMINUS)
13088 else if (op == TOK_NOT)
13090 else if (op == TOK_BNOT)
13092 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
13094 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
13096 else if (op != TOK_UPLUS) {
13097 /* Binary operators */
13099 /* check and binary operators need two arguments */
13100 if (numptr_m1 == numstack) goto err;
13102 /* ... and they pop one */
13105 if (op == TOK_CONDITIONAL) {
13106 if(! numptr_m1->contidional_second_val_initialized) {
13107 /* protect $((expr1 ? expr2)) without ": expr" */
13110 rez = numptr_m1->contidional_second_val;
13111 } else if(numptr_m1->contidional_second_val_initialized) {
13112 /* protect $((expr1 : expr2)) without "expr ? " */
13115 numptr_m1 = NUMPTR - 1;
13116 if(op != TOK_ASSIGN) {
13117 /* check operand is var with noninteger value for not '=' */
13118 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13119 if(ret_arith_lookup_val)
13120 return ret_arith_lookup_val;
13122 if (op == TOK_CONDITIONAL) {
13123 numptr_m1->contidional_second_val = rez;
13125 rez = numptr_m1->val;
13126 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
13128 else if (op == TOK_OR)
13129 rez = numptr_val || rez;
13130 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
13132 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
13134 else if (op == TOK_AND)
13135 rez = rez && numptr_val;
13136 else if (op == TOK_EQ)
13137 rez = (rez == numptr_val);
13138 else if (op == TOK_NE)
13139 rez = (rez != numptr_val);
13140 else if (op == TOK_GE)
13141 rez = (rez >= numptr_val);
13142 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
13143 rez >>= numptr_val;
13144 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
13145 rez <<= numptr_val;
13146 else if (op == TOK_GT)
13147 rez = (rez > numptr_val);
13148 else if (op == TOK_LT)
13149 rez = (rez < numptr_val);
13150 else if (op == TOK_LE)
13151 rez = (rez <= numptr_val);
13152 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
13154 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
13156 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
13158 else if (op == TOK_ASSIGN || op == TOK_COMMA)
13160 else if (op == TOK_CONDITIONAL_SEP) {
13161 if (numptr_m1 == numstack) {
13162 /* protect $((expr : expr)) without "expr ? " */
13165 numptr_m1->contidional_second_val_initialized = op;
13166 numptr_m1->contidional_second_val = numptr_val;
13168 else if (op == TOK_CONDITIONAL) {
13170 numptr_val : numptr_m1->contidional_second_val;
13172 else if(op == TOK_EXPONENT) {
13174 return -3; /* exponent less than 0 */
13179 while(numptr_val--)
13184 else if(numptr_val==0) /* zero divisor check */
13186 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
13188 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
13191 if(tok_have_assign(op)) {
13194 if(numptr_m1->var == NULL) {
13198 /* save to shell variable */
13199 sprintf(buf, "%ld", rez);
13200 setvar(numptr_m1->var, buf, 0);
13201 /* after saving, make previous value for v++ or v-- */
13202 if(op == TOK_POST_INC)
13204 else if(op == TOK_POST_DEC)
13207 numptr_m1->val = rez;
13208 /* protect geting var value, is number now */
13209 numptr_m1->var = NULL;
13214 /* longest must first */
13215 static const char op_tokens[] = {
13216 '<','<','=',0, TOK_LSHIFT_ASSIGN,
13217 '>','>','=',0, TOK_RSHIFT_ASSIGN,
13218 '<','<', 0, TOK_LSHIFT,
13219 '>','>', 0, TOK_RSHIFT,
13220 '|','|', 0, TOK_OR,
13221 '&','&', 0, TOK_AND,
13222 '!','=', 0, TOK_NE,
13223 '<','=', 0, TOK_LE,
13224 '>','=', 0, TOK_GE,
13225 '=','=', 0, TOK_EQ,
13226 '|','=', 0, TOK_OR_ASSIGN,
13227 '&','=', 0, TOK_AND_ASSIGN,
13228 '*','=', 0, TOK_MUL_ASSIGN,
13229 '/','=', 0, TOK_DIV_ASSIGN,
13230 '%','=', 0, TOK_REM_ASSIGN,
13231 '+','=', 0, TOK_PLUS_ASSIGN,
13232 '-','=', 0, TOK_MINUS_ASSIGN,
13233 '-','-', 0, TOK_POST_DEC,
13234 '^','=', 0, TOK_XOR_ASSIGN,
13235 '+','+', 0, TOK_POST_INC,
13236 '*','*', 0, TOK_EXPONENT,
13240 '=', 0, TOK_ASSIGN,
13252 '?', 0, TOK_CONDITIONAL,
13253 ':', 0, TOK_CONDITIONAL_SEP,
13254 ')', 0, TOK_RPAREN,
13255 '(', 0, TOK_LPAREN,
13259 #define endexpression &op_tokens[sizeof(op_tokens)-7]
13262 extern long arith (const char *expr, int *perrcode)
13264 register char arithval; /* Current character under analysis */
13265 operator lasttok, op;
13268 const char *p = endexpression;
13271 size_t datasizes = strlen(expr) + 2;
13273 /* Stack of integers */
13274 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
13275 * in any given correct or incorrect expression is left as an excersize to
13277 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
13278 *numstackptr = numstack;
13279 /* Stack of operator tokens */
13280 operator *stack = alloca((datasizes) * sizeof(operator)),
13283 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
13284 *perrcode = errcode = 0;
13287 if ((arithval = *expr) == 0) {
13288 if (p == endexpression) {
13289 /* Null expression. */
13293 /* This is only reached after all tokens have been extracted from the
13294 * input stream. If there are still tokens on the operator stack, they
13295 * are to be applied in order. At the end, there should be a final
13296 * result on the integer stack */
13298 if (expr != endexpression + 1) {
13299 /* If we haven't done so already, */
13300 /* append a closing right paren */
13301 expr = endexpression;
13302 /* and let the loop process it. */
13305 /* At this point, we're done with the expression. */
13306 if (numstackptr != numstack+1) {
13307 /* ... but if there isn't, it's bad */
13309 return (*perrcode = -1);
13311 if(numstack->var) {
13312 /* expression is $((var)) only, lookup now */
13313 errcode = arith_lookup_val(numstack);
13316 *perrcode = errcode;
13317 return numstack->val;
13319 /* Continue processing the expression. */
13320 if (arith_isspace(arithval)) {
13321 /* Skip whitespace */
13324 if((p = endofname(expr)) != expr) {
13325 int var_name_size = (p-expr) + 1; /* trailing zero */
13327 numstackptr->var = alloca(var_name_size);
13328 safe_strncpy(numstackptr->var, expr, var_name_size);
13331 numstackptr->contidional_second_val_initialized = 0;
13335 } else if (is_digit(arithval)) {
13336 numstackptr->var = NULL;
13337 numstackptr->val = strtol(expr, (char **) &expr, 0);
13340 for(p = op_tokens; ; p++) {
13344 /* strange operator not found */
13347 for(o = expr; *p && *o == *p; p++)
13354 /* skip tail uncompared token */
13357 /* skip zero delim */
13362 /* post grammar: a++ reduce to num */
13363 if(lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13366 /* Plus and minus are binary (not unary) _only_ if the last
13367 * token was as number, or a right paren (which pretends to be
13368 * a number, since it evaluates to one). Think about it.
13369 * It makes sense. */
13370 if (lasttok != TOK_NUM) {
13386 /* We don't want a unary operator to cause recursive descent on the
13387 * stack, because there can be many in a row and it could cause an
13388 * operator to be evaluated before its argument is pushed onto the
13389 * integer stack. */
13390 /* But for binary operators, "apply" everything on the operator
13391 * stack until we find an operator with a lesser priority than the
13392 * one we have just extracted. */
13393 /* Left paren is given the lowest priority so it will never be
13394 * "applied" in this way.
13395 * if associativity is right and priority eq, applied also skip
13398 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13399 /* not left paren or unary */
13400 if (lasttok != TOK_NUM) {
13401 /* binary op must be preceded by a num */
13404 while (stackptr != stack) {
13405 if (op == TOK_RPAREN) {
13406 /* The algorithm employed here is simple: while we don't
13407 * hit an open paren nor the bottom of the stack, pop
13408 * tokens and apply them */
13409 if (stackptr[-1] == TOK_LPAREN) {
13411 /* Any operator directly after a */
13413 /* close paren should consider itself binary */
13417 operator prev_prec = PREC(stackptr[-1]);
13419 convert_prec_is_assing(prec);
13420 convert_prec_is_assing(prev_prec);
13421 if (prev_prec < prec)
13423 /* check right assoc */
13424 if(prev_prec == prec && is_right_associativity(prec))
13427 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13428 if(errcode) goto ret;
13430 if (op == TOK_RPAREN) {
13435 /* Push this operator to the stack and remember it. */
13436 *stackptr++ = lasttok = op;
13443 #endif /* CONFIG_ASH_MATH_SUPPORT */
13447 const char *bb_applet_name = "debug stuff usage";
13448 int main(int argc, char **argv)
13450 return ash_main(argc, argv);
13455 * Copyright (c) 1989, 1991, 1993, 1994
13456 * The Regents of the University of California. All rights reserved.
13458 * This code is derived from software contributed to Berkeley by
13459 * Kenneth Almquist.
13461 * Redistribution and use in source and binary forms, with or without
13462 * modification, are permitted provided that the following conditions
13464 * 1. Redistributions of source code must retain the above copyright
13465 * notice, this list of conditions and the following disclaimer.
13466 * 2. Redistributions in binary form must reproduce the above copyright
13467 * notice, this list of conditions and the following disclaimer in the
13468 * documentation and/or other materials provided with the distribution.
13470 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
13471 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
13473 * 4. Neither the name of the University nor the names of its contributors
13474 * may be used to endorse or promote products derived from this software
13475 * without specific prior written permission.
13477 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13478 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13479 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13480 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13481 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13482 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13483 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13484 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13485 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13486 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF