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 */
555 struct strpush *prev; /* preceding string on stack */
558 #ifdef CONFIG_ASH_ALIAS
559 struct alias *ap; /* if push was associated with an alias */
561 char *string; /* remember the string since it may change */
565 struct parsefile *prev; /* preceding file on stack */
566 int linno; /* current line */
567 int fd; /* file descriptor (or -1 if string) */
568 int nleft; /* number of chars left in this line */
569 int lleft; /* number of chars left in this buffer */
570 char *nextc; /* next char in buffer */
571 char *buf; /* input buffer */
572 struct strpush *strpush; /* for pushing strings at this level */
573 struct strpush basestrpush; /* so pushing one is fast */
576 static struct parsefile basepf; /* top level input file */
577 static char basebuf[IBUFSIZ]; /* buffer for top level input file */
578 static struct parsefile *parsefile = &basepf; /* current input file */
581 static int tokpushback; /* last token pushed back */
582 #define NEOF ((union node *)&tokpushback)
583 static int parsebackquote; /* nonzero if we are inside backquotes */
584 static int doprompt; /* if set, prompt the user */
585 static int needprompt; /* true if interactive and at start of line */
586 static int lasttoken; /* last token read */
587 static char *wordtext; /* text of last word returned by readtoken */
589 static struct nodelist *backquotelist;
590 static union node *redirnode;
591 static struct heredoc *heredoc;
592 static int quoteflag; /* set if (part of) last token was quoted */
593 static int startlinno; /* line # where last token started */
595 static union node *parsecmd(int);
596 static void fixredir(union node *, const char *, int);
597 static const char *const *findkwd(const char *);
598 static char *endofname(const char *);
600 /* $NetBSD: shell.h,v 1.16 2003/01/22 20:36:04 dsl Exp $ */
602 typedef void *pointer;
604 static char nullstr[1]; /* zero length string */
605 static const char spcstr[] = " ";
606 static const char snlfmt[] = "%s\n";
607 static const char dolatstr[] = { CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' };
608 static const char illnum[] = "Illegal number: %s";
609 static const char homestr[] = "HOME";
612 #define TRACE(param) trace param
613 #define TRACEV(param) tracev param
616 #define TRACEV(param)
619 #if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
620 #define __builtin_expect(x, expected_value) (x)
623 #define likely(x) __builtin_expect((x),1)
638 #define TENDBQUOTE 12
656 /* first char is indicating which tokens mark the end of a list */
657 static const char *const tokname_array[] = {
672 /* the following are keywords */
691 static const char *tokname(int tok)
697 sprintf(buf + (tok >= TSEMI), "%s%c",
698 tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));
702 /* $NetBSD: machdep.h,v 1.10 2002/10/07 14:26:08 christos Exp $ */
705 * Most machines require the value returned from malloc to be aligned
706 * in some way. The following macro will get this right on many machines.
709 #define SHELL_SIZE (sizeof(union {int i; char *cp; double d; }) - 1)
711 * It appears that grabstackstr() will barf with such alignments
712 * because stalloc() will return a string allocated in a new stackblock.
714 #define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
717 * This file was generated by the mksyntax program.
722 #define CWORD 0 /* character is nothing special */
723 #define CNL 1 /* newline character */
724 #define CBACK 2 /* a backslash character */
725 #define CSQUOTE 3 /* single quote */
726 #define CDQUOTE 4 /* double quote */
727 #define CENDQUOTE 5 /* a terminating quote */
728 #define CBQUOTE 6 /* backwards single quote */
729 #define CVAR 7 /* a dollar sign */
730 #define CENDVAR 8 /* a '}' character */
731 #define CLP 9 /* a left paren in arithmetic */
732 #define CRP 10 /* a right paren in arithmetic */
733 #define CENDFILE 11 /* end of file */
734 #define CCTL 12 /* like CWORD, except it must be escaped */
735 #define CSPCL 13 /* these terminate a word */
736 #define CIGN 14 /* character should be ignored */
738 #ifdef CONFIG_ASH_ALIAS
742 #define PEOA_OR_PEOF PEOA
746 #define PEOA_OR_PEOF PEOF
749 #define is_digit(c) ((unsigned)((c) - '0') <= 9)
750 #define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
751 #define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
754 * is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
755 * (assuming ascii char codes, as the original implementation did)
757 #define is_special(c) \
758 ( (((unsigned int)c) - 33 < 32) \
759 && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
761 #define digit_val(c) ((c) - '0')
764 * This file was generated by the mksyntax program.
767 #ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
768 #define USE_SIT_FUNCTION
771 /* number syntax index */
772 #define BASESYNTAX 0 /* not in quotes */
773 #define DQSYNTAX 1 /* in double quotes */
774 #define SQSYNTAX 2 /* in single quotes */
775 #define ARISYNTAX 3 /* in arithmetic */
777 #ifdef CONFIG_ASH_MATH_SUPPORT
778 static const char S_I_T[][4] = {
779 #ifdef CONFIG_ASH_ALIAS
780 {CSPCL, CIGN, CIGN, CIGN}, /* 0, PEOA */
782 {CSPCL, CWORD, CWORD, CWORD}, /* 1, ' ' */
783 {CNL, CNL, CNL, CNL}, /* 2, \n */
784 {CWORD, CCTL, CCTL, CWORD}, /* 3, !*-/:=?[]~ */
785 {CDQUOTE, CENDQUOTE, CWORD, CWORD}, /* 4, '"' */
786 {CVAR, CVAR, CWORD, CVAR}, /* 5, $ */
787 {CSQUOTE, CWORD, CENDQUOTE, CWORD}, /* 6, "'" */
788 {CSPCL, CWORD, CWORD, CLP}, /* 7, ( */
789 {CSPCL, CWORD, CWORD, CRP}, /* 8, ) */
790 {CBACK, CBACK, CCTL, CBACK}, /* 9, \ */
791 {CBQUOTE, CBQUOTE, CWORD, CBQUOTE}, /* 10, ` */
792 {CENDVAR, CENDVAR, CWORD, CENDVAR}, /* 11, } */
793 #ifndef USE_SIT_FUNCTION
794 {CENDFILE, CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */
795 {CWORD, CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */
796 {CCTL, CCTL, CCTL, CCTL} /* 14, CTLESC ... */
800 static const char S_I_T[][3] = {
801 #ifdef CONFIG_ASH_ALIAS
802 {CSPCL, CIGN, CIGN}, /* 0, PEOA */
804 {CSPCL, CWORD, CWORD}, /* 1, ' ' */
805 {CNL, CNL, CNL}, /* 2, \n */
806 {CWORD, CCTL, CCTL}, /* 3, !*-/:=?[]~ */
807 {CDQUOTE, CENDQUOTE, CWORD}, /* 4, '"' */
808 {CVAR, CVAR, CWORD}, /* 5, $ */
809 {CSQUOTE, CWORD, CENDQUOTE}, /* 6, "'" */
810 {CSPCL, CWORD, CWORD}, /* 7, ( */
811 {CSPCL, CWORD, CWORD}, /* 8, ) */
812 {CBACK, CBACK, CCTL}, /* 9, \ */
813 {CBQUOTE, CBQUOTE, CWORD}, /* 10, ` */
814 {CENDVAR, CENDVAR, CWORD}, /* 11, } */
815 #ifndef USE_SIT_FUNCTION
816 {CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */
817 {CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */
818 {CCTL, CCTL, CCTL} /* 14, CTLESC ... */
821 #endif /* CONFIG_ASH_MATH_SUPPORT */
823 #ifdef USE_SIT_FUNCTION
825 #define U_C(c) ((unsigned char)(c))
827 static int SIT(int c, int syntax)
829 static const char spec_symbls[] = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
830 #ifdef CONFIG_ASH_ALIAS
831 static const char syntax_index_table[] = {
832 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
833 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
834 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
838 static const char syntax_index_table[] = {
839 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
840 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */
841 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
848 if (c == PEOF) /* 2^8+2 */
850 #ifdef CONFIG_ASH_ALIAS
851 if (c == PEOA) /* 2^8+1 */
855 if (U_C(c) >= U_C(CTLESC) && U_C(c) <= U_C(CTLQUOTEMARK))
858 s = strchr(spec_symbls, c);
859 if (s == 0 || *s == 0)
861 indx = syntax_index_table[(s - spec_symbls)];
863 return S_I_T[indx][syntax];
866 #else /* USE_SIT_FUNCTION */
868 #define SIT(c, syntax) S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax]
870 #ifdef CONFIG_ASH_ALIAS
871 #define CSPCL_CIGN_CIGN_CIGN 0
872 #define CSPCL_CWORD_CWORD_CWORD 1
873 #define CNL_CNL_CNL_CNL 2
874 #define CWORD_CCTL_CCTL_CWORD 3
875 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 4
876 #define CVAR_CVAR_CWORD_CVAR 5
877 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 6
878 #define CSPCL_CWORD_CWORD_CLP 7
879 #define CSPCL_CWORD_CWORD_CRP 8
880 #define CBACK_CBACK_CCTL_CBACK 9
881 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10
882 #define CENDVAR_CENDVAR_CWORD_CENDVAR 11
883 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
884 #define CWORD_CWORD_CWORD_CWORD 13
885 #define CCTL_CCTL_CCTL_CCTL 14
887 #define CSPCL_CWORD_CWORD_CWORD 0
888 #define CNL_CNL_CNL_CNL 1
889 #define CWORD_CCTL_CCTL_CWORD 2
890 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 3
891 #define CVAR_CVAR_CWORD_CVAR 4
892 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 5
893 #define CSPCL_CWORD_CWORD_CLP 6
894 #define CSPCL_CWORD_CWORD_CRP 7
895 #define CBACK_CBACK_CCTL_CBACK 8
896 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 9
897 #define CENDVAR_CENDVAR_CWORD_CENDVAR 10
898 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 11
899 #define CWORD_CWORD_CWORD_CWORD 12
900 #define CCTL_CCTL_CCTL_CCTL 13
903 static const char syntax_index_table[258] = {
904 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
905 /* 0 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
906 #ifdef CONFIG_ASH_ALIAS
907 /* 1 PEOA */ CSPCL_CIGN_CIGN_CIGN,
909 /* 2 -128 0x80 */ CWORD_CWORD_CWORD_CWORD,
910 /* 3 -127 CTLESC */ CCTL_CCTL_CCTL_CCTL,
911 /* 4 -126 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
912 /* 5 -125 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
913 /* 6 -124 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
914 /* 7 -123 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
915 /* 8 -122 CTLARI */ CCTL_CCTL_CCTL_CCTL,
916 /* 9 -121 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
917 /* 10 -120 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
918 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD,
919 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD,
920 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD,
921 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD,
922 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD,
923 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD,
924 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD,
925 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD,
926 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,
927 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD,
928 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD,
929 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD,
930 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD,
931 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD,
932 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD,
933 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD,
934 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD,
935 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD,
936 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,
937 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD,
938 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD,
939 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD,
940 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD,
941 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD,
942 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD,
943 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD,
944 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD,
945 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,
946 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,
947 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD,
948 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD,
949 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD,
950 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD,
951 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD,
952 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD,
953 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD,
954 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD,
955 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD,
956 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD,
957 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD,
958 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD,
959 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD,
960 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD,
961 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD,
962 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD,
963 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD,
964 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD,
965 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,
966 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,
967 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD,
968 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD,
969 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD,
970 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD,
971 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD,
972 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD,
973 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD,
974 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD,
975 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD,
976 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD,
977 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD,
978 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD,
979 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD,
980 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD,
981 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD,
982 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD,
983 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD,
984 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD,
985 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD,
986 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD,
987 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD,
988 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD,
989 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD,
990 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD,
991 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD,
992 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD,
993 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD,
994 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD,
995 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD,
996 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,
997 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD,
998 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD,
999 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD,
1000 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD,
1001 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD,
1002 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD,
1003 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD,
1004 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD,
1005 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD,
1006 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD,
1007 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD,
1008 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD,
1009 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD,
1010 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD,
1011 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD,
1012 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD,
1013 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD,
1014 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD,
1015 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD,
1016 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD,
1017 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD,
1018 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD,
1019 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD,
1020 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD,
1021 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD,
1022 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD,
1023 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD,
1024 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD,
1025 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD,
1026 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD,
1027 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD,
1028 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD,
1029 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD,
1030 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD,
1031 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD,
1032 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD,
1033 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD,
1034 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD,
1035 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD,
1036 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD,
1037 /* 130 0 */ CWORD_CWORD_CWORD_CWORD,
1038 /* 131 1 */ CWORD_CWORD_CWORD_CWORD,
1039 /* 132 2 */ CWORD_CWORD_CWORD_CWORD,
1040 /* 133 3 */ CWORD_CWORD_CWORD_CWORD,
1041 /* 134 4 */ CWORD_CWORD_CWORD_CWORD,
1042 /* 135 5 */ CWORD_CWORD_CWORD_CWORD,
1043 /* 136 6 */ CWORD_CWORD_CWORD_CWORD,
1044 /* 137 7 */ CWORD_CWORD_CWORD_CWORD,
1045 /* 138 8 */ CWORD_CWORD_CWORD_CWORD,
1046 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
1047 /* 140 10 "\n" */ CNL_CNL_CNL_CNL,
1048 /* 141 11 */ CWORD_CWORD_CWORD_CWORD,
1049 /* 142 12 */ CWORD_CWORD_CWORD_CWORD,
1050 /* 143 13 */ CWORD_CWORD_CWORD_CWORD,
1051 /* 144 14 */ CWORD_CWORD_CWORD_CWORD,
1052 /* 145 15 */ CWORD_CWORD_CWORD_CWORD,
1053 /* 146 16 */ CWORD_CWORD_CWORD_CWORD,
1054 /* 147 17 */ CWORD_CWORD_CWORD_CWORD,
1055 /* 148 18 */ CWORD_CWORD_CWORD_CWORD,
1056 /* 149 19 */ CWORD_CWORD_CWORD_CWORD,
1057 /* 150 20 */ CWORD_CWORD_CWORD_CWORD,
1058 /* 151 21 */ CWORD_CWORD_CWORD_CWORD,
1059 /* 152 22 */ CWORD_CWORD_CWORD_CWORD,
1060 /* 153 23 */ CWORD_CWORD_CWORD_CWORD,
1061 /* 154 24 */ CWORD_CWORD_CWORD_CWORD,
1062 /* 155 25 */ CWORD_CWORD_CWORD_CWORD,
1063 /* 156 26 */ CWORD_CWORD_CWORD_CWORD,
1064 /* 157 27 */ CWORD_CWORD_CWORD_CWORD,
1065 /* 158 28 */ CWORD_CWORD_CWORD_CWORD,
1066 /* 159 29 */ CWORD_CWORD_CWORD_CWORD,
1067 /* 160 30 */ CWORD_CWORD_CWORD_CWORD,
1068 /* 161 31 */ CWORD_CWORD_CWORD_CWORD,
1069 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD,
1070 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD,
1071 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
1072 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD,
1073 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR,
1074 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD,
1075 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
1076 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
1077 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP,
1078 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP,
1079 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD,
1080 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD,
1081 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD,
1082 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD,
1083 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD,
1084 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD,
1085 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD,
1086 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD,
1087 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD,
1088 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD,
1089 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD,
1090 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD,
1091 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD,
1092 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD,
1093 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD,
1094 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD,
1095 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD,
1096 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
1097 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
1098 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD,
1099 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
1100 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD,
1101 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD,
1102 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD,
1103 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD,
1104 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD,
1105 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD,
1106 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD,
1107 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD,
1108 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD,
1109 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD,
1110 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD,
1111 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD,
1112 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD,
1113 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD,
1114 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD,
1115 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD,
1116 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD,
1117 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD,
1118 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
1119 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD,
1120 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD,
1121 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD,
1122 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD,
1123 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD,
1124 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD,
1125 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD,
1126 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
1127 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
1128 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD,
1129 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK,
1130 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD,
1131 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD,
1132 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD,
1133 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
1134 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD,
1135 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD,
1136 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD,
1137 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD,
1138 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD,
1139 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD,
1140 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD,
1141 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD,
1142 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD,
1143 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD,
1144 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD,
1145 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD,
1146 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD,
1147 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD,
1148 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD,
1149 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD,
1150 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD,
1151 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD,
1152 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD,
1153 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD,
1154 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD,
1155 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD,
1156 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD,
1157 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD,
1158 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD,
1159 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD,
1160 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD,
1161 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
1162 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
1163 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,
1164 /* 257 127 */ CWORD_CWORD_CWORD_CWORD,
1167 #endif /* USE_SIT_FUNCTION */
1169 /* $NetBSD: alias.c,v 1.11 2002/11/24 22:35:38 christos Exp $ */
1174 static int funcblocksize; /* size of structures in function */
1175 static int funcstringsize; /* size of strings in node */
1176 static pointer funcblock; /* block to allocate function from */
1177 static char *funcstring; /* block to allocate strings from */
1179 static const short nodesize[26] = {
1180 SHELL_ALIGN(sizeof (struct ncmd)),
1181 SHELL_ALIGN(sizeof (struct npipe)),
1182 SHELL_ALIGN(sizeof (struct nredir)),
1183 SHELL_ALIGN(sizeof (struct nredir)),
1184 SHELL_ALIGN(sizeof (struct nredir)),
1185 SHELL_ALIGN(sizeof (struct nbinary)),
1186 SHELL_ALIGN(sizeof (struct nbinary)),
1187 SHELL_ALIGN(sizeof (struct nbinary)),
1188 SHELL_ALIGN(sizeof (struct nif)),
1189 SHELL_ALIGN(sizeof (struct nbinary)),
1190 SHELL_ALIGN(sizeof (struct nbinary)),
1191 SHELL_ALIGN(sizeof (struct nfor)),
1192 SHELL_ALIGN(sizeof (struct ncase)),
1193 SHELL_ALIGN(sizeof (struct nclist)),
1194 SHELL_ALIGN(sizeof (struct narg)),
1195 SHELL_ALIGN(sizeof (struct narg)),
1196 SHELL_ALIGN(sizeof (struct nfile)),
1197 SHELL_ALIGN(sizeof (struct nfile)),
1198 SHELL_ALIGN(sizeof (struct nfile)),
1199 SHELL_ALIGN(sizeof (struct nfile)),
1200 SHELL_ALIGN(sizeof (struct nfile)),
1201 SHELL_ALIGN(sizeof (struct ndup)),
1202 SHELL_ALIGN(sizeof (struct ndup)),
1203 SHELL_ALIGN(sizeof (struct nhere)),
1204 SHELL_ALIGN(sizeof (struct nhere)),
1205 SHELL_ALIGN(sizeof (struct nnot)),
1209 static void calcsize(union node *);
1210 static void sizenodelist(struct nodelist *);
1211 static union node *copynode(union node *);
1212 static struct nodelist *copynodelist(struct nodelist *);
1213 static char *nodesavestr(char *);
1217 static void evalstring(char *, int);
1218 union node; /* BLETCH for ansi C */
1219 static void evaltree(union node *, int);
1220 static void evalbackcmd(union node *, struct backcmd *);
1222 /* in_function returns nonzero if we are currently evaluating a function */
1223 #define in_function() funcnest
1224 static int evalskip; /* set if we are skipping commands */
1225 static int skipcount; /* number of levels to skip */
1226 static int funcnest; /* depth of function calls */
1228 /* reasons for skipping commands (see comment on breakcmd routine) */
1235 * This file was generated by the mkbuiltins program.
1239 static int bgcmd(int, char **);
1241 static int breakcmd(int, char **);
1242 static int cdcmd(int, char **);
1243 #ifdef CONFIG_ASH_CMDCMD
1244 static int commandcmd(int, char **);
1246 static int dotcmd(int, char **);
1247 static int evalcmd(int, char **);
1248 static int execcmd(int, char **);
1249 static int exitcmd(int, char **);
1250 static int exportcmd(int, char **);
1251 static int falsecmd(int, char **);
1253 static int fgcmd(int, char **);
1255 #ifdef CONFIG_ASH_GETOPTS
1256 static int getoptscmd(int, char **);
1258 static int hashcmd(int, char **);
1259 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1260 static int helpcmd(int argc, char **argv);
1263 static int jobscmd(int, char **);
1265 #ifdef CONFIG_ASH_MATH_SUPPORT
1266 static int letcmd(int, char **);
1268 static int localcmd(int, char **);
1269 static int pwdcmd(int, char **);
1270 static int readcmd(int, char **);
1271 static int returncmd(int, char **);
1272 static int setcmd(int, char **);
1273 static int shiftcmd(int, char **);
1274 static int timescmd(int, char **);
1275 static int trapcmd(int, char **);
1276 static int truecmd(int, char **);
1277 static int typecmd(int, char **);
1278 static int umaskcmd(int, char **);
1279 static int unsetcmd(int, char **);
1280 static int waitcmd(int, char **);
1281 static int ulimitcmd(int, char **);
1283 static int killcmd(int, char **);
1286 /* $NetBSD: mail.h,v 1.9 2002/11/24 22:35:40 christos Exp $ */
1288 #ifdef CONFIG_ASH_MAIL
1289 static void chkmail(void);
1290 static void changemail(const char *);
1293 /* $NetBSD: exec.h,v 1.20 2003/01/22 20:36:04 dsl Exp $ */
1295 /* values of cmdtype */
1296 #define CMDUNKNOWN -1 /* no entry in table for command */
1297 #define CMDNORMAL 0 /* command is an executable program */
1298 #define CMDFUNCTION 1 /* command is a shell function */
1299 #define CMDBUILTIN 2 /* command is a shell builtin */
1303 int (*builtin)(int, char **);
1304 /* unsigned flags; */
1307 #ifdef CONFIG_ASH_CMDCMD
1309 # ifdef CONFIG_ASH_ALIAS
1310 # define COMMANDCMD (builtincmd + 7)
1311 # define EXECCMD (builtincmd + 10)
1313 # define COMMANDCMD (builtincmd + 6)
1314 # define EXECCMD (builtincmd + 9)
1317 # ifdef CONFIG_ASH_ALIAS
1318 # define COMMANDCMD (builtincmd + 6)
1319 # define EXECCMD (builtincmd + 9)
1321 # define COMMANDCMD (builtincmd + 5)
1322 # define EXECCMD (builtincmd + 8)
1325 #else /* ! CONFIG_ASH_CMDCMD */
1327 # ifdef CONFIG_ASH_ALIAS
1328 # define EXECCMD (builtincmd + 9)
1330 # define EXECCMD (builtincmd + 8)
1333 # ifdef CONFIG_ASH_ALIAS
1334 # define EXECCMD (builtincmd + 8)
1336 # define EXECCMD (builtincmd + 7)
1339 #endif /* CONFIG_ASH_CMDCMD */
1341 #define BUILTIN_NOSPEC "0"
1342 #define BUILTIN_SPECIAL "1"
1343 #define BUILTIN_REGULAR "2"
1344 #define BUILTIN_SPEC_REG "3"
1345 #define BUILTIN_ASSIGN "4"
1346 #define BUILTIN_SPEC_ASSG "5"
1347 #define BUILTIN_REG_ASSG "6"
1348 #define BUILTIN_SPEC_REG_ASSG "7"
1350 #define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1351 #define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
1353 static const struct builtincmd builtincmd[] = {
1354 { BUILTIN_SPEC_REG ".", dotcmd },
1355 { BUILTIN_SPEC_REG ":", truecmd },
1356 #ifdef CONFIG_ASH_ALIAS
1357 { BUILTIN_REG_ASSG "alias", aliascmd },
1360 { BUILTIN_REGULAR "bg", bgcmd },
1362 { BUILTIN_SPEC_REG "break", breakcmd },
1363 { BUILTIN_REGULAR "cd", cdcmd },
1364 { BUILTIN_NOSPEC "chdir", cdcmd },
1365 #ifdef CONFIG_ASH_CMDCMD
1366 { BUILTIN_REGULAR "command", commandcmd },
1368 { BUILTIN_SPEC_REG "continue", breakcmd },
1369 { BUILTIN_SPEC_REG "eval", evalcmd },
1370 { BUILTIN_SPEC_REG "exec", execcmd },
1371 { BUILTIN_SPEC_REG "exit", exitcmd },
1372 { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
1373 { BUILTIN_REGULAR "false", falsecmd },
1375 { BUILTIN_REGULAR "fg", fgcmd },
1377 #ifdef CONFIG_ASH_GETOPTS
1378 { BUILTIN_REGULAR "getopts", getoptscmd },
1380 { BUILTIN_NOSPEC "hash", hashcmd },
1381 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1382 { BUILTIN_NOSPEC "help", helpcmd },
1385 { BUILTIN_REGULAR "jobs", jobscmd },
1386 { BUILTIN_REGULAR "kill", killcmd },
1388 #ifdef CONFIG_ASH_MATH_SUPPORT
1389 { BUILTIN_NOSPEC "let", letcmd },
1391 { BUILTIN_ASSIGN "local", localcmd },
1392 { BUILTIN_NOSPEC "pwd", pwdcmd },
1393 { BUILTIN_REGULAR "read", readcmd },
1394 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
1395 { BUILTIN_SPEC_REG "return", returncmd },
1396 { BUILTIN_SPEC_REG "set", setcmd },
1397 { BUILTIN_SPEC_REG "shift", shiftcmd },
1398 { BUILTIN_SPEC_REG "times", timescmd },
1399 { BUILTIN_SPEC_REG "trap", trapcmd },
1400 { BUILTIN_REGULAR "true", truecmd },
1401 { BUILTIN_NOSPEC "type", typecmd },
1402 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
1403 { BUILTIN_REGULAR "umask", umaskcmd },
1404 #ifdef CONFIG_ASH_ALIAS
1405 { BUILTIN_REGULAR "unalias", unaliascmd },
1407 { BUILTIN_SPEC_REG "unset", unsetcmd },
1408 { BUILTIN_REGULAR "wait", waitcmd },
1411 #define NUMBUILTINS (sizeof (builtincmd) / sizeof (struct builtincmd) )
1419 const struct builtincmd *cmd;
1420 struct funcnode *func;
1425 /* action to find_command() */
1426 #define DO_ERR 0x01 /* prints errors */
1427 #define DO_ABS 0x02 /* checks absolute paths */
1428 #define DO_NOFUNC 0x04 /* don't return shell functions, for command */
1429 #define DO_ALTPATH 0x08 /* using alternate path */
1430 #define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
1432 static const char *pathopt; /* set by padvance */
1434 static void shellexec(char **, const char *, int)
1435 __attribute__((__noreturn__));
1436 static char *padvance(const char **, const char *);
1437 static void find_command(char *, struct cmdentry *, int, const char *);
1438 static struct builtincmd *find_builtin(const char *);
1439 static void hashcd(void);
1440 static void changepath(const char *);
1441 static void defun(char *, union node *);
1442 static void unsetfunc(const char *);
1444 #ifdef CONFIG_ASH_MATH_SUPPORT
1445 static int dash_arith(const char *);
1448 /* $NetBSD: init.h,v 1.9 2002/11/24 22:35:40 christos Exp $ */
1450 static void reset(void);
1452 /* $NetBSD: var.h,v 1.21 2003/01/22 20:36:04 dsl Exp $ */
1459 #define VEXPORT 0x01 /* variable is exported */
1460 #define VREADONLY 0x02 /* variable cannot be modified */
1461 #define VSTRFIXED 0x04 /* variable struct is statically allocated */
1462 #define VTEXTFIXED 0x08 /* text is statically allocated */
1463 #define VSTACK 0x10 /* text is allocated on the stack */
1464 #define VUNSET 0x20 /* the variable is not set */
1465 #define VNOFUNC 0x40 /* don't call the callback function */
1466 #define VNOSET 0x80 /* do not set variable - just readonly test */
1467 #define VNOSAVE 0x100 /* when text is on the heap before setvareq */
1471 struct var *next; /* next entry in hash list */
1472 int flags; /* flags are defined above */
1473 const char *text; /* name=value */
1474 void (*func)(const char *);
1475 /* function to be called when */
1476 /* the variable gets set/unset */
1480 struct localvar *next; /* next local variable in list */
1481 struct var *vp; /* the variable that was made local */
1482 int flags; /* saved flags */
1483 const char *text; /* saved text */
1487 static struct localvar *localvars;
1493 #ifdef CONFIG_ASH_GETOPTS
1494 static void getoptsreset(const char *);
1497 #ifdef CONFIG_LOCALE_SUPPORT
1499 static void change_lc_all(const char *value);
1500 static void change_lc_ctype(const char *value);
1505 static const char defpathvar[] = "PATH=/usr/local/bin:/usr/bin:/sbin:/bin";
1507 static const char defifsvar[] = "IFS= \t\n";
1508 #define defifs (defifsvar + 4)
1510 static const char defifs[] = " \t\n";
1514 static struct var varinit[] = {
1516 { 0, VSTRFIXED|VTEXTFIXED, defifsvar, 0 },
1518 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", 0 },
1521 #ifdef CONFIG_ASH_MAIL
1522 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail },
1523 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail },
1526 { 0, VSTRFIXED|VTEXTFIXED, defpathvar, changepath },
1527 { 0, VSTRFIXED|VTEXTFIXED, "PS1=$ ", 0 },
1528 { 0, VSTRFIXED|VTEXTFIXED, "PS2=> ", 0 },
1529 { 0, VSTRFIXED|VTEXTFIXED, "PS4=+ ", 0 },
1530 #ifdef CONFIG_ASH_GETOPTS
1531 { 0, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset },
1533 #ifdef CONFIG_LOCALE_SUPPORT
1534 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL=", change_lc_all},
1535 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE=", change_lc_ctype},
1537 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
1538 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE=", NULL},
1542 #define vifs varinit[0]
1543 #ifdef CONFIG_ASH_MAIL
1544 #define vmail (&vifs)[1]
1545 #define vmpath (&vmail)[1]
1549 #define vpath (&vmpath)[1]
1550 #define vps1 (&vpath)[1]
1551 #define vps2 (&vps1)[1]
1552 #define vps4 (&vps2)[1]
1553 #define voptind (&vps4)[1]
1555 #define defpath (defpathvar + 5)
1558 * The following macros access the values of the above variables.
1559 * They have to skip over the name. They return the null string
1560 * for unset variables.
1563 #define ifsval() (vifs.text + 4)
1564 #define ifsset() ((vifs.flags & VUNSET) == 0)
1565 #define mailval() (vmail.text + 5)
1566 #define mpathval() (vmpath.text + 9)
1567 #define pathval() (vpath.text + 5)
1568 #define ps1val() (vps1.text + 4)
1569 #define ps2val() (vps2.text + 4)
1570 #define ps4val() (vps4.text + 4)
1571 #define optindval() (voptind.text + 7)
1573 #define mpathset() ((vmpath.flags & VUNSET) == 0)
1575 static void setvar(const char *, const char *, int);
1576 static void setvareq(char *, int);
1577 static void listsetvar(struct strlist *, int);
1578 static char *lookupvar(const char *);
1579 static char *bltinlookup(const char *);
1580 static char **listvars(int, int, char ***);
1581 #define environment() listvars(VEXPORT, VUNSET, 0)
1582 static int showvars(const char *, int, int);
1583 static void poplocalvars(void);
1584 static int unsetvar(const char *);
1585 #ifdef CONFIG_ASH_GETOPTS
1586 static int setvarsafe(const char *, const char *, int);
1588 static int varcmp(const char *, const char *);
1589 static struct var **hashvar(const char *);
1592 static inline int varequal(const char *a, const char *b) {
1593 return !varcmp(a, b);
1597 static int loopnest; /* current loop nesting level */
1600 * The parsefile structure pointed to by the global variable parsefile
1601 * contains information about the current file being read.
1606 struct redirtab *next;
1611 static struct redirtab *redirlist;
1612 static int nullredirs;
1614 extern char **environ;
1616 /* $NetBSD: output.h,v 1.16 2002/11/24 22:35:42 christos Exp $ */
1619 static void outstr(const char *, FILE *);
1620 static void outcslow(int, FILE *);
1621 static void flushall(void);
1622 static void flushout(FILE *);
1623 static int out1fmt(const char *, ...)
1624 __attribute__((__format__(__printf__,1,2)));
1625 static int fmtstr(char *, size_t, const char *, ...)
1626 __attribute__((__format__(__printf__,3,4)));
1627 static void xwrite(int, const void *, size_t);
1629 static int preverrout_fd; /* save fd2 before print debug if xflag is set. */
1632 static void out1str(const char *p)
1637 static void out2str(const char *p)
1644 * Initialization code.
1648 * This routine initializes the builtin variables.
1659 * PS1 depends on uid
1661 #if defined(CONFIG_FEATURE_COMMAND_EDITING) && defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
1662 vps1.text = "PS1=\\w \\$ ";
1665 vps1.text = "PS1=# ";
1668 end = vp + sizeof(varinit) / sizeof(varinit[0]);
1670 vpp = hashvar(vp->text);
1673 } while (++vp < end);
1682 basepf.nextc = basepf.buf = basebuf;
1687 signal(SIGCHLD, SIG_DFL);
1696 for (envp = environ ; *envp ; envp++) {
1697 if (strchr(*envp, '=')) {
1698 setvareq(*envp, VEXPORT|VTEXTFIXED);
1702 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
1703 setvar("PPID", ppid, 0);
1708 /* PEOF (the end of file marker) */
1711 * The input line number. Input.c just defines this variable, and saves
1712 * and restores it when files are pushed and popped. The user of this
1713 * package must set its value.
1716 static int pgetc(void);
1717 static int pgetc2(void);
1718 static int preadbuffer(void);
1719 static void pungetc(void);
1720 static void pushstring(char *, void *);
1721 static void popstring(void);
1722 static void setinputfile(const char *, int);
1723 static void setinputfd(int, int);
1724 static void setinputstring(char *);
1725 static void popfile(void);
1726 static void popallfiles(void);
1727 static void closescript(void);
1730 /* $NetBSD: jobs.h,v 1.17 2003/01/22 20:36:04 dsl Exp $ */
1733 /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
1736 #define FORK_NOJOB 2
1738 /* mode flags for showjob(s) */
1739 #define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
1740 #define SHOW_PID 0x04 /* include process pid */
1741 #define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
1745 * A job structure contains information about a job. A job is either a
1746 * single process or a set of processes contained in a pipeline. In the
1747 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1752 pid_t pid; /* process id */
1753 int status; /* last process status from wait() */
1754 char *cmd; /* text of command being run */
1758 struct procstat ps0; /* status of process */
1759 struct procstat *ps; /* status or processes when more than one */
1761 int stopstatus; /* status of a stopped job */
1764 nprocs: 16, /* number of processes */
1766 #define JOBRUNNING 0 /* at least one proc running */
1767 #define JOBSTOPPED 1 /* all procs are stopped */
1768 #define JOBDONE 2 /* all procs are completed */
1770 sigint: 1, /* job was killed by SIGINT */
1771 jobctl: 1, /* job running under job control */
1773 waited: 1, /* true if this entry has been waited for */
1774 used: 1, /* true if this entry is in used */
1775 changed: 1; /* true if status has changed */
1776 struct job *prev_job; /* previous job */
1779 static pid_t backgndpid; /* pid of last background process */
1780 static int job_warning; /* user was warned about stopped jobs */
1782 static int jobctl; /* true if doing job control */
1785 static struct job *makejob(union node *, int);
1786 static int forkshell(struct job *, union node *, int);
1787 static int waitforjob(struct job *);
1788 static int stoppedjobs(void);
1791 #define setjobctl(on) /* do nothing */
1793 static void setjobctl(int);
1794 static void showjobs(FILE *, int);
1797 /* $NetBSD: main.h,v 1.9 2002/11/24 22:35:41 christos Exp $ */
1800 /* pid of main shell */
1802 /* true if we aren't a child of the main shell */
1803 static int rootshell;
1805 static void readcmdfile(char *);
1806 static void cmdloop(int);
1808 /* $NetBSD: memalloc.h,v 1.13 2003/01/22 20:36:04 dsl Exp $ */
1812 struct stack_block *stackp;
1815 struct stackmark *marknext;
1818 /* minimum size of a block */
1819 #define MINSIZE SHELL_ALIGN(504)
1821 struct stack_block {
1822 struct stack_block *prev;
1823 char space[MINSIZE];
1826 static struct stack_block stackbase;
1827 static struct stack_block *stackp = &stackbase;
1828 static struct stackmark *markp;
1829 static char *stacknxt = stackbase.space;
1830 static size_t stacknleft = MINSIZE;
1831 static char *sstrend = stackbase.space + MINSIZE;
1832 static int herefd = -1;
1835 static pointer ckmalloc(size_t);
1836 static pointer ckrealloc(pointer, size_t);
1837 static char *savestr(const char *);
1838 static pointer stalloc(size_t);
1839 static void stunalloc(pointer);
1840 static void setstackmark(struct stackmark *);
1841 static void popstackmark(struct stackmark *);
1842 static void growstackblock(void);
1843 static void *growstackstr(void);
1844 static char *makestrspace(size_t, char *);
1845 static char *stnputs(const char *, size_t, char *);
1846 static char *stputs(const char *, char *);
1849 static inline char *_STPUTC(char c, char *p) {
1856 #define stackblock() ((void *)stacknxt)
1857 #define stackblocksize() stacknleft
1858 #define STARTSTACKSTR(p) ((p) = stackblock())
1859 #define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1860 #define CHECKSTRSPACE(n, p) \
1864 size_t m = sstrend - q; \
1866 (p) = makestrspace(l, q); \
1869 #define USTPUTC(c, p) (*p++ = (c))
1870 #define STACKSTRNUL(p) ((p) == sstrend? (p = growstackstr(), *p = '\0') : (*p = '\0'))
1871 #define STUNPUTC(p) (--p)
1872 #define STTOPC(p) p[-1]
1873 #define STADJUST(amount, p) (p += (amount))
1875 #define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1876 #define ungrabstackstr(s, p) stunalloc((s))
1877 #define stackstrend() ((void *)sstrend)
1879 #define ckfree(p) free((pointer)(p))
1881 /* $NetBSD: mystring.h,v 1.10 2002/11/24 22:35:42 christos Exp $ */
1884 #define DOLATSTRLEN 4
1886 static char *prefix(const char *, const char *);
1887 static int number(const char *);
1888 static int is_number(const char *);
1889 static char *single_quote(const char *);
1890 static char *sstrdup(const char *);
1892 #define equal(s1, s2) (strcmp(s1, s2) == 0)
1893 #define scopy(s1, s2) ((void)strcpy(s2, s1))
1895 /* $NetBSD: options.h,v 1.16 2003/01/22 20:36:04 dsl Exp $ */
1898 int nparam; /* # of positional parameters (without $0) */
1899 unsigned char malloc; /* if parameter list dynamically allocated */
1900 char **p; /* parameter list */
1901 #ifdef CONFIG_ASH_GETOPTS
1902 int optind; /* next parameter to be processed by getopts */
1903 int optoff; /* used by getopts */
1908 #define eflag optlist[0]
1909 #define fflag optlist[1]
1910 #define Iflag optlist[2]
1911 #define iflag optlist[3]
1912 #define mflag optlist[4]
1913 #define nflag optlist[5]
1914 #define sflag optlist[6]
1915 #define xflag optlist[7]
1916 #define vflag optlist[8]
1917 #define Cflag optlist[9]
1918 #define aflag optlist[10]
1919 #define bflag optlist[11]
1920 #define uflag optlist[12]
1921 #define qflag optlist[13]
1924 #define nolog optlist[14]
1925 #define debug optlist[15]
1931 /* $NetBSD: options.c,v 1.33 2003/01/22 20:36:04 dsl Exp $ */
1934 static const char *const optletters_optnames[NOPTS] = {
1955 #define optletters(n) optletters_optnames[(n)][0]
1956 #define optnames(n) (&optletters_optnames[(n)][1])
1959 static char optlist[NOPTS];
1962 static char *arg0; /* value of $0 */
1963 static struct shparam shellparam; /* $@ current positional parameters */
1964 static char **argptr; /* argument list for builtin commands */
1965 static char *optionarg; /* set by nextopt (like getopt) */
1966 static char *optptr; /* used by nextopt */
1968 static char *minusc; /* argument to -c option */
1971 static void procargs(int, char **);
1972 static void optschanged(void);
1973 static void setparam(char **);
1974 static void freeparam(volatile struct shparam *);
1975 static int shiftcmd(int, char **);
1976 static int setcmd(int, char **);
1977 static int nextopt(const char *);
1979 /* $NetBSD: redir.h,v 1.14 2002/11/24 22:35:43 christos Exp $ */
1981 /* flags passed to redirect */
1982 #define REDIR_PUSH 01 /* save previous values of file descriptors */
1983 #define REDIR_SAVEFD2 03 /* set preverrout */
1986 static void redirect(union node *, int);
1987 static void popredir(int);
1988 static void clearredir(int);
1989 static int copyfd(int, int);
1990 static int redirectsafe(union node *, int);
1992 /* $NetBSD: show.h,v 1.6 2003/01/22 20:36:04 dsl Exp $ */
1996 static void showtree(union node *);
1997 static void trace(const char *, ...);
1998 static void tracev(const char *, va_list);
1999 static void trargs(char **);
2000 static void trputc(int);
2001 static void trputs(const char *);
2002 static void opentrace(void);
2005 /* $NetBSD: trap.h,v 1.16 2002/11/24 22:35:43 christos Exp $ */
2008 /* trap handler commands */
2009 static char *trap[NSIG];
2010 /* current value of signal */
2011 static char sigmode[NSIG - 1];
2012 /* indicates specified signal received */
2013 static char gotsig[NSIG - 1];
2015 static void clear_traps(void);
2016 static void setsignal(int);
2017 static void ignoresig(int);
2018 static void onsig(int);
2019 static void dotrap(void);
2020 static void setinteractive(int);
2021 static void exitshell(void) __attribute__((__noreturn__));
2022 static int decode_signal(const char *, int);
2025 * This routine is called when an error or an interrupt occurs in an
2026 * interactive shell and control is returned to the main command loop.
2041 parselleft = parsenleft = 0; /* clear input buffer */
2045 /* from parser.c: */
2058 #ifdef CONFIG_ASH_ALIAS
2059 static struct alias *atab[ATABSIZE];
2061 static void setalias(const char *, const char *);
2062 static struct alias *freealias(struct alias *);
2063 static struct alias **__lookupalias(const char *);
2066 setalias(const char *name, const char *val)
2068 struct alias *ap, **app;
2070 app = __lookupalias(name);
2074 if (!(ap->flag & ALIASINUSE)) {
2077 ap->val = savestr(val);
2078 ap->flag &= ~ALIASDEAD;
2081 ap = ckmalloc(sizeof (struct alias));
2082 ap->name = savestr(name);
2083 ap->val = savestr(val);
2092 unalias(const char *name)
2096 app = __lookupalias(name);
2100 *app = freealias(*app);
2111 struct alias *ap, **app;
2115 for (i = 0; i < ATABSIZE; i++) {
2117 for (ap = *app; ap; ap = *app) {
2118 *app = freealias(*app);
2127 static struct alias *
2128 lookupalias(const char *name, int check)
2130 struct alias *ap = *__lookupalias(name);
2132 if (check && ap && (ap->flag & ALIASINUSE))
2138 * TODO - sort output
2141 aliascmd(int argc, char **argv)
2150 for (i = 0; i < ATABSIZE; i++)
2151 for (ap = atab[i]; ap; ap = ap->next) {
2156 while ((n = *++argv) != NULL) {
2157 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
2158 if ((ap = *__lookupalias(n)) == NULL) {
2159 fprintf(stderr, "%s: %s not found\n", "alias", n);
2173 unaliascmd(int argc, char **argv)
2177 while ((i = nextopt("a")) != '\0') {
2183 for (i = 0; *argptr; argptr++) {
2184 if (unalias(*argptr)) {
2185 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
2193 static struct alias *
2194 freealias(struct alias *ap) {
2197 if (ap->flag & ALIASINUSE) {
2198 ap->flag |= ALIASDEAD;
2210 printalias(const struct alias *ap) {
2211 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
2214 static struct alias **
2215 __lookupalias(const char *name) {
2216 unsigned int hashval;
2223 ch = (unsigned char)*p;
2227 ch = (unsigned char)*++p;
2229 app = &atab[hashval % ATABSIZE];
2231 for (; *app; app = &(*app)->next) {
2232 if (equal(name, (*app)->name)) {
2239 #endif /* CONFIG_ASH_ALIAS */
2242 /* $NetBSD: cd.c,v 1.30 2003/01/22 20:36:03 dsl Exp $ */
2245 * The cd and pwd commands.
2248 #define CD_PHYSICAL 1
2251 static int docd(const char *, int);
2252 static int cdopt(void);
2254 static char *curdir = nullstr; /* current working directory */
2255 static char *physdir = nullstr; /* physical working directory */
2264 while ((i = nextopt("LP"))) {
2266 flags ^= CD_PHYSICAL;
2275 cdcmd(int argc, char **argv)
2287 dest = bltinlookup(homestr);
2288 else if (dest[0] == '-' && dest[1] == '\0') {
2289 dest = bltinlookup("OLDPWD");
2312 if (!(path = bltinlookup("CDPATH"))) {
2320 p = padvance(&path, dest);
2321 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2325 if (!docd(p, flags))
2330 error("can't cd to %s", dest);
2333 if (flags & CD_PRINT)
2334 out1fmt(snlfmt, curdir);
2340 * Update curdir (the name of the current directory) in response to a
2344 static inline const char *
2345 updatepwd(const char *dir)
2352 cdcomppath = sstrdup(dir);
2355 if (curdir == nullstr)
2357 new = stputs(curdir, new);
2359 new = makestrspace(strlen(dir) + 2, new);
2360 lim = stackblock() + 1;
2364 if (new > lim && *lim == '/')
2369 if (dir[1] == '/' && dir[2] != '/') {
2375 p = strtok(cdcomppath, "/");
2379 if (p[1] == '.' && p[2] == '\0') {
2386 } else if (p[1] == '\0')
2390 new = stputs(p, new);
2398 return stackblock();
2402 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2403 * know that the current directory has changed.
2407 docd(const char *dest, int flags)
2409 const char *dir = 0;
2412 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2415 if (!(flags & CD_PHYSICAL)) {
2416 dir = updatepwd(dest);
2431 * Find out what the current directory is. If we already know the current
2432 * directory, this routine returns immediately.
2434 static inline char *
2437 char *dir = getcwd(0, 0);
2438 return dir ? dir : nullstr;
2442 pwdcmd(int argc, char **argv)
2445 const char *dir = curdir;
2449 if (physdir == nullstr)
2453 out1fmt(snlfmt, dir);
2458 setpwd(const char *val, int setold)
2462 oldcur = dir = curdir;
2465 setvar("OLDPWD", oldcur, VEXPORT);
2468 if (physdir != nullstr) {
2469 if (physdir != oldcur)
2473 if (oldcur == val || !val) {
2480 if (oldcur != dir && oldcur != nullstr) {
2485 setvar("PWD", dir, VEXPORT);
2488 /* $NetBSD: error.c,v 1.30 2003/01/22 20:36:03 dsl Exp $ */
2491 * Errors and exceptions.
2495 * Code to handle exceptions in C.
2500 static void exverror(int, const char *, va_list)
2501 __attribute__((__noreturn__));
2504 * Called to raise an exception. Since C doesn't include exceptions, we
2505 * just do a longjmp to the exception handler. The type of exception is
2506 * stored in the global variable "exception".
2513 if (handler == NULL)
2519 longjmp(handler->loc, 1);
2524 * Called from trap.c when a SIGINT is received. (If the user specifies
2525 * that SIGINT is to be trapped or ignored using the trap builtin, then
2526 * this routine is not called.) Suppressint is nonzero when interrupts
2527 * are held using the INTOFF macro. (The test for iflag is just
2528 * defensive programming.)
2538 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
2539 if (!(rootshell && iflag)) {
2540 signal(SIGINT, SIG_DFL);
2550 exvwarning(const char *msg, va_list ap)
2563 fprintf(errs, fmt, name, startlinno);
2564 vfprintf(errs, msg, ap);
2565 outcslow('\n', errs);
2569 * Exverror is called to raise the error exception. If the second argument
2570 * is not NULL then error prints an error message using printf style
2571 * formatting. It then raises the error exception.
2574 exverror(int cond, const char *msg, va_list ap)
2578 TRACE(("exverror(%d, \"", cond));
2580 TRACE(("\") pid=%d\n", getpid()));
2582 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
2585 exvwarning(msg, ap);
2594 error(const char *msg, ...)
2599 exverror(EXERROR, msg, ap);
2606 exerror(int cond, const char *msg, ...)
2611 exverror(cond, msg, ap);
2617 * error/warning routines for external builtins
2621 sh_warnx(const char *fmt, ...)
2626 exvwarning(fmt, ap);
2632 * Return a string describing an error. The returned string may be a
2633 * pointer to a static buffer that will be overwritten on the next call.
2634 * Action describes the operation that got the error.
2638 errmsg(int e, const char *em)
2640 if(e == ENOENT || e == ENOTDIR) {
2648 /* $NetBSD: eval.c,v 1.71 2003/01/23 03:33:16 rafal Exp $ */
2651 * Evaluate a command.
2654 /* flags in argument to evaltree */
2655 #define EV_EXIT 01 /* exit after evaluating tree */
2656 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2657 #define EV_BACKCMD 04 /* command executing within back quotes */
2660 static void evalloop(union node *, int);
2661 static void evalfor(union node *, int);
2662 static void evalcase(union node *, int);
2663 static void evalsubshell(union node *, int);
2664 static void expredir(union node *);
2665 static void evalpipe(union node *, int);
2666 static void evalcommand(union node *, int);
2667 static int evalbltin(const struct builtincmd *, int, char **);
2668 static int evalfun(struct funcnode *, int, char **, int);
2669 static void prehash(union node *);
2670 static int bltincmd(int, char **);
2673 static const struct builtincmd bltin = {
2679 * Called to reset things after an exception.
2683 * The eval commmand.
2687 evalcmd(int argc, char **argv)
2696 STARTSTACKSTR(concat);
2699 concat = stputs(p, concat);
2700 if ((p = *ap++) == NULL)
2702 STPUTC(' ', concat);
2704 STPUTC('\0', concat);
2705 p = grabstackstr(concat);
2707 evalstring(p, EV_TESTED);
2714 * Execute a command or commands contained in a string.
2718 evalstring(char *s, int flag)
2721 struct stackmark smark;
2723 setstackmark(&smark);
2726 while ((n = parsecmd(0)) != NEOF) {
2728 popstackmark(&smark);
2733 popstackmark(&smark);
2739 * Evaluate a parse tree. The value is left in the global variable
2744 evaltree(union node *n, int flags)
2747 void (*evalfn)(union node *, int);
2751 TRACE(("evaltree(NULL) called\n"));
2754 TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
2755 getpid(), n, n->type, flags));
2759 out1fmt("Node type = %d\n", n->type);
2764 evaltree(n->nnot.com, EV_TESTED);
2765 status = !exitstatus;
2768 expredir(n->nredir.redirect);
2769 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
2771 evaltree(n->nredir.n, flags & EV_TESTED);
2772 status = exitstatus;
2777 evalfn = evalcommand;
2779 if (eflag && !(flags & EV_TESTED))
2791 evalfn = evalsubshell;
2803 #error NAND + 1 != NOR
2805 #if NOR + 1 != NSEMI
2806 #error NOR + 1 != NSEMI
2808 isor = n->type - NAND;
2811 (flags | ((isor >> 1) - 1)) & EV_TESTED
2813 if (!exitstatus == isor)
2825 evaltree(n->nif.test, EV_TESTED);
2828 if (exitstatus == 0) {
2831 } else if (n->nif.elsepart) {
2832 n = n->nif.elsepart;
2837 defun(n->narg.text, n->narg.next);
2841 exitstatus = status;
2847 if (flags & EV_EXIT || checkexit & exitstatus)
2852 #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
2855 void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
2859 evalloop(union node *n, int flags)
2869 evaltree(n->nbinary.ch1, EV_TESTED);
2871 skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
2875 if (evalskip == SKIPBREAK && --skipcount <= 0)
2880 if (n->type != NWHILE)
2884 evaltree(n->nbinary.ch2, flags);
2885 status = exitstatus;
2890 exitstatus = status;
2896 evalfor(union node *n, int flags)
2898 struct arglist arglist;
2901 struct stackmark smark;
2903 setstackmark(&smark);
2904 arglist.lastp = &arglist.list;
2905 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
2906 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
2911 *arglist.lastp = NULL;
2916 for (sp = arglist.list ; sp ; sp = sp->next) {
2917 setvar(n->nfor.var, sp->text, 0);
2918 evaltree(n->nfor.body, flags);
2920 if (evalskip == SKIPCONT && --skipcount <= 0) {
2924 if (evalskip == SKIPBREAK && --skipcount <= 0)
2931 popstackmark(&smark);
2937 evalcase(union node *n, int flags)
2941 struct arglist arglist;
2942 struct stackmark smark;
2944 setstackmark(&smark);
2945 arglist.lastp = &arglist.list;
2946 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
2948 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2949 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
2950 if (casematch(patp, arglist.list->text)) {
2951 if (evalskip == 0) {
2952 evaltree(cp->nclist.body, flags);
2959 popstackmark(&smark);
2965 * Kick off a subshell to evaluate a tree.
2969 evalsubshell(union node *n, int flags)
2972 int backgnd = (n->type == NBACKGND);
2975 expredir(n->nredir.redirect);
2976 if (!backgnd && flags & EV_EXIT && !trap[0])
2980 if (forkshell(jp, n, backgnd) == 0) {
2984 flags &=~ EV_TESTED;
2986 redirect(n->nredir.redirect, 0);
2987 evaltreenr(n->nredir.n, flags);
2992 status = waitforjob(jp);
2993 exitstatus = status;
3000 * Compute the names of the files in a redirection list.
3004 expredir(union node *n)
3008 for (redir = n ; redir ; redir = redir->nfile.next) {
3010 fn.lastp = &fn.list;
3011 switch (redir->type) {
3017 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
3018 redir->nfile.expfname = fn.list->text;
3022 if (redir->ndup.vname) {
3023 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
3024 fixredir(redir, fn.list->text, 1);
3034 * Evaluate a pipeline. All the processes in the pipeline are children
3035 * of the process creating the pipeline. (This differs from some versions
3036 * of the shell, which make the last process in a pipeline the parent
3041 evalpipe(union node *n, int flags)
3044 struct nodelist *lp;
3049 TRACE(("evalpipe(0x%lx) called\n", (long)n));
3051 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
3055 jp = makejob(n, pipelen);
3057 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
3061 if (pipe(pip) < 0) {
3063 error("Pipe call failed");
3066 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
3079 evaltreenr(lp->n, flags);
3087 if (n->npipe.backgnd == 0) {
3088 exitstatus = waitforjob(jp);
3089 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
3097 * Execute a command inside back quotes. If it's a builtin command, we
3098 * want to save its output in a block obtained from malloc. Otherwise
3099 * we fork off a subprocess and get the output of the command via a pipe.
3100 * Should be called with interrupts off.
3104 evalbackcmd(union node *n, struct backcmd *result)
3116 saveherefd = herefd;
3124 error("Pipe call failed");
3126 if (forkshell(jp, n, FORK_NOJOB) == 0) {
3135 evaltreenr(n, EV_EXIT);
3139 result->fd = pip[0];
3142 herefd = saveherefd;
3144 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
3145 result->fd, result->buf, result->nleft, result->jp));
3148 #ifdef CONFIG_ASH_CMDCMD
3149 static inline char **
3150 parse_command_args(char **argv, const char **path)
3162 if (c == '-' && !*cp) {
3172 /* run 'typecmd' for other options */
3175 } while ((c = *cp++));
3184 * Execute a simple command.
3188 evalcommand(union node *cmd, int flags)
3190 struct stackmark smark;
3192 struct arglist arglist;
3193 struct arglist varlist;
3196 const struct strlist *sp;
3197 struct cmdentry cmdentry;
3206 /* First expand the arguments. */
3207 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
3208 setstackmark(&smark);
3209 back_exitstatus = 0;
3211 cmdentry.cmdtype = CMDBUILTIN;
3212 cmdentry.u.cmd = &bltin;
3213 varlist.lastp = &varlist.list;
3214 *varlist.lastp = NULL;
3215 arglist.lastp = &arglist.list;
3216 *arglist.lastp = NULL;
3219 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
3220 struct strlist **spp;
3222 spp = arglist.lastp;
3223 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
3224 for (sp = *spp; sp; sp = sp->next)
3228 argv = nargv = stalloc(sizeof (char *) * (argc + 1));
3229 for (sp = arglist.list ; sp ; sp = sp->next) {
3230 TRACE(("evalcommand arg: %s\n", sp->text));
3231 *nargv++ = sp->text;
3236 if (iflag && funcnest == 0 && argc > 0)
3237 lastarg = nargv[-1];
3240 expredir(cmd->ncmd.redirect);
3241 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH|REDIR_SAVEFD2);
3244 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
3245 struct strlist **spp;
3248 spp = varlist.lastp;
3249 expandarg(argp, &varlist, EXP_VARTILDE);
3252 * Modify the command lookup path, if a PATH= assignment
3256 if (varequal(p, path))
3260 /* Print the command if xflag is set. */
3263 const char *p = " %s";
3266 dprintf(preverrout_fd, p, ps4val());
3269 for(n = 0; n < 2; n++) {
3271 dprintf(preverrout_fd, p, sp->text);
3279 xwrite(preverrout_fd, "\n", 1);
3285 /* Now locate the command. */
3287 const char *oldpath;
3288 int cmd_flag = DO_ERR;
3293 find_command(argv[0], &cmdentry, cmd_flag, path);
3294 if (cmdentry.cmdtype == CMDUNKNOWN) {
3300 /* implement bltin and command here */
3301 if (cmdentry.cmdtype != CMDBUILTIN)
3304 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
3305 if (cmdentry.u.cmd == EXECCMD)
3307 #ifdef CONFIG_ASH_CMDCMD
3308 if (cmdentry.u.cmd == COMMANDCMD) {
3311 nargv = parse_command_args(argv, &path);
3314 argc -= nargv - argv;
3316 cmd_flag |= DO_NOFUNC;
3324 /* We have a redirection error. */
3328 exitstatus = status;
3332 /* Execute the command. */
3333 switch (cmdentry.cmdtype) {
3335 /* Fork off a child process if necessary. */
3336 if (!(flags & EV_EXIT) || trap[0]) {
3338 jp = makejob(cmd, 1);
3339 if (forkshell(jp, cmd, FORK_FG) != 0) {
3340 exitstatus = waitforjob(jp);
3346 listsetvar(varlist.list, VEXPORT|VSTACK);
3347 shellexec(argv, path, cmdentry.u.index);
3351 cmdenviron = varlist.list;
3353 struct strlist *list = cmdenviron;
3355 if (spclbltin > 0 || argc == 0) {
3357 if (cmd_is_exec && argc > 1)
3360 listsetvar(list, i);
3362 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
3377 exit_status = j + 128;
3378 exitstatus = exit_status;
3380 if (i == EXINT || spclbltin > 0) {
3382 longjmp(handler->loc, 1);
3389 listsetvar(varlist.list, 0);
3390 if (evalfun(cmdentry.u.func, argc, argv, flags))
3396 popredir(cmd_is_exec);
3398 /* dsl: I think this is intended to be used to support
3399 * '_' in 'vi' command mode during line editing...
3400 * However I implemented that within libedit itself.
3402 setvar("_", lastarg, 0);
3403 popstackmark(&smark);
3407 evalbltin(const struct builtincmd *cmd, int argc, char **argv) {
3408 char *volatile savecmdname;
3409 struct jmploc *volatile savehandler;
3410 struct jmploc jmploc;
3413 savecmdname = commandname;
3414 if ((i = setjmp(jmploc.loc)))
3416 savehandler = handler;
3418 commandname = argv[0];
3420 optptr = NULL; /* initialize nextopt */
3421 exitstatus = (*cmd->builtin)(argc, argv);
3424 exitstatus |= ferror(stdout);
3425 commandname = savecmdname;
3427 handler = savehandler;
3433 evalfun(struct funcnode *func, int argc, char **argv, int flags)
3435 volatile struct shparam saveparam;
3436 struct localvar *volatile savelocalvars;
3437 struct jmploc *volatile savehandler;
3438 struct jmploc jmploc;
3441 saveparam = shellparam;
3442 savelocalvars = localvars;
3443 if ((e = setjmp(jmploc.loc))) {
3447 savehandler = handler;
3450 shellparam.malloc = 0;
3453 shellparam.nparam = argc - 1;
3454 shellparam.p = argv + 1;
3455 #ifdef CONFIG_ASH_GETOPTS
3456 shellparam.optind = 1;
3457 shellparam.optoff = -1;
3460 evaltree(&func->n, flags & EV_TESTED);
3466 localvars = savelocalvars;
3467 freeparam(&shellparam);
3468 shellparam = saveparam;
3469 handler = savehandler;
3471 if (evalskip == SKIPFUNC) {
3480 * Search for a command. This is called before we fork so that the
3481 * location of the command will be available in the parent as well as
3486 prehash(union node *n)
3488 struct cmdentry entry;
3490 if (n->type == NCMD && n->ncmd.args)
3491 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
3497 * Builtin commands. Builtin commands whose functions are closely
3498 * tied to evaluation are implemented here.
3506 bltincmd(int argc, char **argv)
3509 * Preserve exitstatus of a previous possible redirection
3512 return back_exitstatus;
3517 * Handle break and continue commands. Break, continue, and return are
3518 * all handled by setting the evalskip flag. The evaluation routines
3519 * above all check this flag, and if it is set they start skipping
3520 * commands rather than executing them. The variable skipcount is
3521 * the number of loops to break/continue, or the number of function
3522 * levels to return. (The latter is always 1.) It should probably
3523 * be an error to break out of more loops than exist, but it isn't
3524 * in the standard shell so we don't make it one here.
3528 breakcmd(int argc, char **argv)
3530 int n = argc > 1 ? number(argv[1]) : 1;
3533 error(illnum, argv[1]);
3537 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
3545 * The return command.
3549 returncmd(int argc, char **argv)
3551 int ret = argc > 1 ? number(argv[1]) : exitstatus;
3554 evalskip = SKIPFUNC;
3559 /* Do what ksh does; skip the rest of the file */
3560 evalskip = SKIPFILE;
3568 falsecmd(int argc, char **argv)
3575 truecmd(int argc, char **argv)
3582 execcmd(int argc, char **argv)
3585 iflag = 0; /* exit on error */
3588 shellexec(argv + 1, pathval(), 0);
3594 /* $NetBSD: exec.c,v 1.35 2003/01/22 20:36:04 dsl Exp $ */
3597 * When commands are first encountered, they are entered in a hash table.
3598 * This ensures that a full path search will not have to be done for them
3599 * on each invocation.
3601 * We should investigate converting to a linear search, even though that
3602 * would make the command name "hash" a misnomer.
3605 #define CMDTABLESIZE 31 /* should be prime */
3606 #define ARB 1 /* actual size determined at run time */
3611 struct tblentry *next; /* next entry in hash chain */
3612 union param param; /* definition of builtin function */
3613 short cmdtype; /* index identifying command */
3614 char rehash; /* if set, cd done since entry created */
3615 char cmdname[ARB]; /* name of command */
3619 static struct tblentry *cmdtable[CMDTABLESIZE];
3620 static int builtinloc = -1; /* index in path of %builtin, or -1 */
3623 static void tryexec(char *, char **, char **);
3624 static void clearcmdentry(int);
3625 static struct tblentry *cmdlookup(const char *, int);
3626 static void delete_cmd_entry(void);
3630 * Exec a program. Never returns. If you change this routine, you may
3631 * have to change the find_command routine as well.
3635 shellexec(char **argv, const char *path, int idx)
3642 envp = environment();
3643 if (strchr(argv[0], '/') != NULL
3644 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3645 || find_applet_by_name(argv[0])
3648 tryexec(argv[0], argv, envp);
3652 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3653 if (--idx < 0 && pathopt == NULL) {
3654 tryexec(cmdname, argv, envp);
3655 if (errno != ENOENT && errno != ENOTDIR)
3662 /* Map to POSIX errors */
3674 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
3675 argv[0], e, suppressint ));
3676 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3682 tryexec(char *cmd, char **argv, char **envp)
3685 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3689 #ifdef CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN
3690 name = bb_get_last_path_component(name);
3691 if(find_applet_by_name(name) != NULL)
3694 if(strchr(name, '/') == NULL && find_applet_by_name(name) != NULL) {
3703 if(strcmp(name, "busybox")) {
3704 for (ap = argv; *ap; ap++);
3705 ap = new = xmalloc((ap - argv + 2) * sizeof(char *));
3706 *ap++ = cmd = "/bin/busybox";
3707 while ((*ap++ = *argv++));
3711 cmd = "/bin/busybox";
3719 execve(cmd, argv, envp);
3720 } while (errno == EINTR);
3722 execve(cmd, argv, envp);
3726 } else if (errno == ENOEXEC) {
3730 for (ap = argv; *ap; ap++)
3732 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
3734 *ap = cmd = (char *)DEFAULT_SHELL;
3737 while ((*ap++ = *argv++))
3747 * Do a path search. The variable path (passed by reference) should be
3748 * set to the start of the path before the first call; padvance will update
3749 * this value as it proceeds. Successive calls to padvance will return
3750 * the possible path expansions in sequence. If an option (indicated by
3751 * a percent sign) appears in the path entry then the global variable
3752 * pathopt will be set to point to it; otherwise pathopt will be set to
3757 padvance(const char **path, const char *name)
3767 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
3768 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
3769 while (stackblocksize() < len)
3773 memcpy(q, start, p - start);
3781 while (*p && *p != ':') p++;
3787 return stalloc(len);
3791 /*** Command hashing code ***/
3794 printentry(struct tblentry *cmdp)
3800 idx = cmdp->param.index;
3803 name = padvance(&path, cmdp->cmdname);
3805 } while (--idx >= 0);
3806 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
3811 hashcmd(int argc, char **argv)
3813 struct tblentry **pp;
3814 struct tblentry *cmdp;
3816 struct cmdentry entry;
3819 while ((c = nextopt("r")) != '\0') {
3823 if (*argptr == NULL) {
3824 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3825 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3826 if (cmdp->cmdtype == CMDNORMAL)
3833 while ((name = *argptr) != NULL) {
3834 if ((cmdp = cmdlookup(name, 0)) != NULL
3835 && (cmdp->cmdtype == CMDNORMAL
3836 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
3838 find_command(name, &entry, DO_ERR, pathval());
3839 if (entry.cmdtype == CMDUNKNOWN)
3848 * Resolve a command name. If you change this routine, you may have to
3849 * change the shellexec routine as well.
3853 find_command(char *name, struct cmdentry *entry, int act, const char *path)
3855 struct tblentry *cmdp;
3862 struct builtincmd *bcmd;
3864 /* If name contains a slash, don't use PATH or hash table */
3865 if (strchr(name, '/') != NULL) {
3866 entry->u.index = -1;
3868 while (stat(name, &statb) < 0) {
3873 entry->cmdtype = CMDUNKNOWN;
3877 entry->cmdtype = CMDNORMAL;
3881 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3882 if (find_applet_by_name(name)) {
3883 entry->cmdtype = CMDNORMAL;
3884 entry->u.index = -1;
3889 updatetbl = (path == pathval());
3892 if (strstr(path, "%builtin") != NULL)
3896 /* If name is in the table, check answer will be ok */
3897 if ((cmdp = cmdlookup(name, 0)) != NULL) {
3900 switch (cmdp->cmdtype) {
3918 } else if (cmdp->rehash == 0)
3919 /* if not invalidated by cd, we're done */
3923 /* If %builtin not in path, check for builtin next */
3924 bcmd = find_builtin(name);
3925 if (bcmd && (IS_BUILTIN_REGULAR(bcmd) || (
3926 act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0
3928 goto builtin_success;
3930 /* We have to search path. */
3931 prev = -1; /* where to start */
3932 if (cmdp && cmdp->rehash) { /* doing a rehash */
3933 if (cmdp->cmdtype == CMDBUILTIN)
3936 prev = cmdp->param.index;
3942 while ((fullname = padvance(&path, name)) != NULL) {
3943 stunalloc(fullname);
3946 if (prefix(pathopt, "builtin")) {
3948 goto builtin_success;
3950 } else if (!(act & DO_NOFUNC) &&
3951 prefix(pathopt, "func")) {
3954 /* ignore unimplemented options */
3958 /* if rehash, don't redo absolute path names */
3959 if (fullname[0] == '/' && idx <= prev) {
3962 TRACE(("searchexec \"%s\": no change\n", name));
3965 while (stat(fullname, &statb) < 0) {
3970 if (errno != ENOENT && errno != ENOTDIR)
3974 e = EACCES; /* if we fail, this will be the error */
3975 if (!S_ISREG(statb.st_mode))
3977 if (pathopt) { /* this is a %func directory */
3978 stalloc(strlen(fullname) + 1);
3979 readcmdfile(fullname);
3980 if ((cmdp = cmdlookup(name, 0)) == NULL ||
3981 cmdp->cmdtype != CMDFUNCTION)
3982 error("%s not defined in %s", name, fullname);
3983 stunalloc(fullname);
3986 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
3988 entry->cmdtype = CMDNORMAL;
3989 entry->u.index = idx;
3993 cmdp = cmdlookup(name, 1);
3994 cmdp->cmdtype = CMDNORMAL;
3995 cmdp->param.index = idx;
4000 /* We failed. If there was an entry for this command, delete it */
4001 if (cmdp && updatetbl)
4004 sh_warnx("%s: %s", name, errmsg(e, E_EXEC));
4005 entry->cmdtype = CMDUNKNOWN;
4010 entry->cmdtype = CMDBUILTIN;
4011 entry->u.cmd = bcmd;
4015 cmdp = cmdlookup(name, 1);
4016 cmdp->cmdtype = CMDBUILTIN;
4017 cmdp->param.cmd = bcmd;
4021 entry->cmdtype = cmdp->cmdtype;
4022 entry->u = cmdp->param;
4027 * Wrapper around strcmp for qsort/bsearch/...
4029 static int pstrcmp(const void *a, const void *b)
4031 return strcmp((const char *) a, (*(const char *const *) b) + 1);
4035 * Search the table of builtin commands.
4038 static struct builtincmd *
4039 find_builtin(const char *name)
4041 struct builtincmd *bp;
4044 name, builtincmd, NUMBUILTINS, sizeof(struct builtincmd),
4053 * Called when a cd is done. Marks all commands so the next time they
4054 * are executed they will be rehashed.
4060 struct tblentry **pp;
4061 struct tblentry *cmdp;
4063 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4064 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4065 if (cmdp->cmdtype == CMDNORMAL || (
4066 cmdp->cmdtype == CMDBUILTIN &&
4067 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) &&
4078 * Fix command hash table when PATH changed.
4079 * Called before PATH is changed. The argument is the new value of PATH;
4080 * pathval() still returns the old value at this point.
4081 * Called with interrupts off.
4085 changepath(const char *newval)
4087 const char *old, *new;
4094 firstchange = 9999; /* assume no change */
4100 if ((*old == '\0' && *new == ':')
4101 || (*old == ':' && *new == '\0'))
4103 old = new; /* ignore subsequent differences */
4107 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
4114 if (builtinloc < 0 && idx_bltin >= 0)
4115 builtinloc = idx_bltin; /* zap builtins */
4116 if (builtinloc >= 0 && idx_bltin < 0)
4118 clearcmdentry(firstchange);
4119 builtinloc = idx_bltin;
4124 * Clear out command entries. The argument specifies the first entry in
4125 * PATH which has changed.
4129 clearcmdentry(int firstchange)
4131 struct tblentry **tblp;
4132 struct tblentry **pp;
4133 struct tblentry *cmdp;
4136 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4138 while ((cmdp = *pp) != NULL) {
4139 if ((cmdp->cmdtype == CMDNORMAL &&
4140 cmdp->param.index >= firstchange)
4141 || (cmdp->cmdtype == CMDBUILTIN &&
4142 builtinloc >= firstchange)) {
4156 * Locate a command in the command hash table. If "add" is nonzero,
4157 * add the command to the table if it is not already present. The
4158 * variable "lastcmdentry" is set to point to the address of the link
4159 * pointing to the entry, so that delete_cmd_entry can delete the
4162 * Interrupts must be off if called with add != 0.
4165 static struct tblentry **lastcmdentry;
4168 static struct tblentry *
4169 cmdlookup(const char *name, int add)
4171 unsigned int hashval;
4173 struct tblentry *cmdp;
4174 struct tblentry **pp;
4177 hashval = (unsigned char)*p << 4;
4179 hashval += (unsigned char)*p++;
4181 pp = &cmdtable[hashval % CMDTABLESIZE];
4182 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4183 if (equal(cmdp->cmdname, name))
4187 if (add && cmdp == NULL) {
4188 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4189 + strlen(name) + 1);
4191 cmdp->cmdtype = CMDUNKNOWN;
4192 strcpy(cmdp->cmdname, name);
4199 * Delete the command entry returned on the last lookup.
4203 delete_cmd_entry(void)
4205 struct tblentry *cmdp;
4208 cmdp = *lastcmdentry;
4209 *lastcmdentry = cmdp->next;
4210 if (cmdp->cmdtype == CMDFUNCTION)
4211 freefunc(cmdp->param.func);
4218 * Add a new command entry, replacing any existing command entry for
4219 * the same name - except special builtins.
4223 addcmdentry(char *name, struct cmdentry *entry)
4225 struct tblentry *cmdp;
4227 cmdp = cmdlookup(name, 1);
4228 if (cmdp->cmdtype == CMDFUNCTION) {
4229 freefunc(cmdp->param.func);
4231 cmdp->cmdtype = entry->cmdtype;
4232 cmdp->param = entry->u;
4237 * Make a copy of a parse tree.
4240 static inline struct funcnode *
4241 copyfunc(union node *n)
4246 funcblocksize = offsetof(struct funcnode, n);
4249 blocksize = funcblocksize;
4250 f = ckmalloc(blocksize + funcstringsize);
4251 funcblock = (char *) f + offsetof(struct funcnode, n);
4252 funcstring = (char *) f + blocksize;
4259 * Define a shell function.
4263 defun(char *name, union node *func)
4265 struct cmdentry entry;
4268 entry.cmdtype = CMDFUNCTION;
4269 entry.u.func = copyfunc(func);
4270 addcmdentry(name, &entry);
4276 * Delete a function if it exists.
4280 unsetfunc(const char *name)
4282 struct tblentry *cmdp;
4284 if ((cmdp = cmdlookup(name, 0)) != NULL &&
4285 cmdp->cmdtype == CMDFUNCTION)
4290 * Locate and print what a word is...
4294 #ifdef CONFIG_ASH_CMDCMD
4296 describe_command(char *command, int describe_command_verbose)
4298 #define describe_command_verbose 1
4300 describe_command(char *command)
4303 struct cmdentry entry;
4304 struct tblentry *cmdp;
4305 #ifdef CONFIG_ASH_ALIAS
4306 const struct alias *ap;
4308 const char *path = pathval();
4310 if (describe_command_verbose) {
4314 /* First look at the keywords */
4315 if (findkwd(command)) {
4316 out1str(describe_command_verbose ? " is a shell keyword" : command);
4320 #ifdef CONFIG_ASH_ALIAS
4321 /* Then look at the aliases */
4322 if ((ap = lookupalias(command, 0)) != NULL) {
4323 if (describe_command_verbose) {
4324 out1fmt(" is an alias for %s", ap->val);
4333 /* Then check if it is a tracked alias */
4334 if ((cmdp = cmdlookup(command, 0)) != NULL) {
4335 entry.cmdtype = cmdp->cmdtype;
4336 entry.u = cmdp->param;
4338 /* Finally use brute force */
4339 find_command(command, &entry, DO_ABS, path);
4342 switch (entry.cmdtype) {
4344 int j = entry.u.index;
4350 p = padvance(&path, command);
4354 if (describe_command_verbose) {
4356 (cmdp ? " a tracked alias for" : nullstr), p
4365 if (describe_command_verbose) {
4366 out1str(" is a shell function");
4373 if (describe_command_verbose) {
4374 out1fmt(" is a %sshell builtin",
4375 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
4376 "special " : nullstr
4384 if (describe_command_verbose) {
4385 out1str(": not found\n");
4391 outstr("\n", stdout);
4396 typecmd(int argc, char **argv)
4401 for (i = 1; i < argc; i++) {
4402 #ifdef CONFIG_ASH_CMDCMD
4403 err |= describe_command(argv[i], 1);
4405 err |= describe_command(argv[i]);
4411 #ifdef CONFIG_ASH_CMDCMD
4413 commandcmd(int argc, char **argv)
4416 int default_path = 0;
4417 int verify_only = 0;
4418 int verbose_verify_only = 0;
4420 while ((c = nextopt("pvV")) != '\0')
4425 "command: nextopt returned character code 0%o\n", c);
4435 verbose_verify_only = 1;
4439 if (default_path + verify_only + verbose_verify_only > 1 ||
4442 "command [-p] command [arg ...]\n"
4443 "command {-v|-V} command\n");
4447 if (verify_only || verbose_verify_only) {
4448 return describe_command(*argptr, verbose_verify_only);
4455 /* $NetBSD: expand.c,v 1.56 2002/11/24 22:35:39 christos Exp $ */
4458 * Routines to expand arguments to commands. We have to deal with
4459 * backquotes, shell variables, and file metacharacters.
4465 #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4466 #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
4467 #define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
4468 #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
4469 #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
4472 * Structure specifying which parts of the string should be searched
4473 * for IFS characters.
4477 struct ifsregion *next; /* next region in list */
4478 int begoff; /* offset of start of region */
4479 int endoff; /* offset of end of region */
4480 int nulonly; /* search for nul bytes only */
4483 /* output of current string */
4484 static char *expdest;
4485 /* list of back quote expressions */
4486 static struct nodelist *argbackq;
4487 /* first struct in list of ifs regions */
4488 static struct ifsregion ifsfirst;
4489 /* last struct in list */
4490 static struct ifsregion *ifslastp;
4491 /* holds expanded arg list */
4492 static struct arglist exparg;
4494 static void argstr(char *, int);
4495 static char *exptilde(char *, char *, int);
4496 static void expbackq(union node *, int, int);
4497 static const char *subevalvar(char *, char *, int, int, int, int, int);
4498 static char *evalvar(char *, int);
4499 static int varisset(char *, int);
4500 static void strtodest(const char *, int, int);
4501 static void memtodest(const char *p, size_t len, int syntax, int quotes);
4502 static void varvalue(char *, int, int);
4503 static void recordregion(int, int, int);
4504 static void removerecordregions(int);
4505 static void ifsbreakup(char *, struct arglist *);
4506 static void ifsfree(void);
4507 static void expandmeta(struct strlist *, int);
4508 static int patmatch(char *, const char *);
4510 static int cvtnum(long);
4511 static size_t esclen(const char *, const char *);
4512 static char *scanleft(char *, char *, char *, char *, int, int);
4513 static char *scanright(char *, char *, char *, char *, int, int);
4514 static void varunset(const char *, const char *, const char *, int)
4515 __attribute__((__noreturn__));
4518 #define pmatch(a, b) !fnmatch((a), (b), 0)
4520 * Prepare a pattern for a expmeta (internal glob(3)) call.
4522 * Returns an stalloced string.
4525 static inline char *
4526 preglob(const char *pattern, int quoted, int flag) {
4527 flag |= RMESCAPE_GLOB;
4529 flag |= RMESCAPE_QUOTED;
4531 return _rmescapes((char *)pattern, flag);
4536 esclen(const char *start, const char *p) {
4539 while (p > start && *--p == CTLESC) {
4547 * Expand shell variables and backquotes inside a here document.
4551 expandhere(union node *arg, int fd)
4554 expandarg(arg, (struct arglist *)NULL, 0);
4555 xwrite(fd, stackblock(), expdest - (char *)stackblock());
4560 * Perform variable substitution and command substitution on an argument,
4561 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4562 * perform splitting and file name expansion. When arglist is NULL, perform
4563 * here document expansion.
4567 expandarg(union node *arg, struct arglist *arglist, int flag)
4572 argbackq = arg->narg.backquote;
4573 STARTSTACKSTR(expdest);
4574 ifsfirst.next = NULL;
4576 argstr(arg->narg.text, flag);
4577 if (arglist == NULL) {
4578 return; /* here document expanded */
4580 STPUTC('\0', expdest);
4581 p = grabstackstr(expdest);
4582 exparg.lastp = &exparg.list;
4586 if (flag & EXP_FULL) {
4587 ifsbreakup(p, &exparg);
4588 *exparg.lastp = NULL;
4589 exparg.lastp = &exparg.list;
4590 expandmeta(exparg.list, flag);
4592 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
4594 sp = (struct strlist *)stalloc(sizeof (struct strlist));
4597 exparg.lastp = &sp->next;
4601 *exparg.lastp = NULL;
4603 *arglist->lastp = exparg.list;
4604 arglist->lastp = exparg.lastp;
4610 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4611 * characters to allow for further processing. Otherwise treat
4612 * $@ like $* since no splitting will be performed.
4616 argstr(char *p, int flag)
4618 static const char spclchars[] = {
4626 CTLBACKQ | CTLQUOTE,
4627 #ifdef CONFIG_ASH_MATH_SUPPORT
4632 const char *reject = spclchars;
4634 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
4635 int breakall = flag & EXP_WORD;
4640 if (!(flag & EXP_VARTILDE)) {
4642 } else if (flag & EXP_VARTILDE2) {
4647 if (flag & EXP_TILDE) {
4653 if (*q == CTLESC && (flag & EXP_QWORD))
4656 p = exptilde(p, q, flag);
4659 startloc = expdest - (char *)stackblock();
4661 length += strcspn(p + length, reject);
4663 if (c && (!(c & 0x80)
4664 #ifdef CONFIG_ASH_MATH_SUPPORT
4668 /* c == '=' || c == ':' || c == CTLENDARI */
4673 expdest = stnputs(p, length, expdest);
4674 newloc = expdest - (char *)stackblock();
4675 if (breakall && !inquotes && newloc > startloc) {
4676 recordregion(startloc, newloc, 0);
4687 if (flag & EXP_VARTILDE2) {
4691 flag |= EXP_VARTILDE2;
4696 * sort of a hack - expand tildes in variable
4697 * assignments (after the first '=' and after ':'s).
4706 case CTLENDVAR: /* ??? */
4709 /* "$@" syntax adherence hack */
4712 !memcmp(p, dolatstr, DOLATSTRLEN) &&
4713 (p[4] == CTLQUOTEMARK || (
4714 p[4] == CTLENDVAR &&
4715 p[5] == CTLQUOTEMARK
4718 p = evalvar(p + 1, flag) + 1;
4721 inquotes = !inquotes;
4734 p = evalvar(p, flag);
4738 case CTLBACKQ|CTLQUOTE:
4739 expbackq(argbackq->n, c, quotes);
4740 argbackq = argbackq->next;
4742 #ifdef CONFIG_ASH_MATH_SUPPORT
4755 exptilde(char *startp, char *p, int flag)
4761 int quotes = flag & (EXP_FULL | EXP_CASE);
4766 while ((c = *++p) != '\0') {
4773 if (flag & EXP_VARTILDE)
4783 if (*name == '\0') {
4784 if ((home = lookupvar(homestr)) == NULL)
4787 if ((pw = getpwnam(name)) == NULL)
4794 startloc = expdest - (char *)stackblock();
4795 strtodest(home, SQSYNTAX, quotes);
4796 recordregion(startloc, expdest - (char *)stackblock(), 0);
4805 removerecordregions(int endoff)
4807 if (ifslastp == NULL)
4810 if (ifsfirst.endoff > endoff) {
4811 while (ifsfirst.next != NULL) {
4812 struct ifsregion *ifsp;
4814 ifsp = ifsfirst.next->next;
4815 ckfree(ifsfirst.next);
4816 ifsfirst.next = ifsp;
4819 if (ifsfirst.begoff > endoff)
4822 ifslastp = &ifsfirst;
4823 ifsfirst.endoff = endoff;
4828 ifslastp = &ifsfirst;
4829 while (ifslastp->next && ifslastp->next->begoff < endoff)
4830 ifslastp=ifslastp->next;
4831 while (ifslastp->next != NULL) {
4832 struct ifsregion *ifsp;
4834 ifsp = ifslastp->next->next;
4835 ckfree(ifslastp->next);
4836 ifslastp->next = ifsp;
4839 if (ifslastp->endoff > endoff)
4840 ifslastp->endoff = endoff;
4844 #ifdef CONFIG_ASH_MATH_SUPPORT
4846 * Expand arithmetic expression. Backup to start of expression,
4847 * evaluate, place result in (backed up) result, adjust string position.
4860 * This routine is slightly over-complicated for
4861 * efficiency. Next we scan backwards looking for the
4862 * start of arithmetic.
4864 start = stackblock();
4871 while (*p != CTLARI) {
4875 error("missing CTLARI (shouldn't happen)");
4880 esc = esclen(start, p);
4890 removerecordregions(begoff);
4899 len = cvtnum(dash_arith(p + 2));
4902 recordregion(begoff, begoff + len, 0);
4907 * Expand stuff in backwards quotes.
4911 expbackq(union node *cmd, int quoted, int quotes)
4919 int syntax = quoted? DQSYNTAX : BASESYNTAX;
4920 struct stackmark smark;
4923 setstackmark(&smark);
4925 startloc = dest - (char *)stackblock();
4927 evalbackcmd(cmd, (struct backcmd *) &in);
4928 popstackmark(&smark);
4935 memtodest(p, i, syntax, quotes);
4939 i = safe_read(in.fd, buf, sizeof buf);
4940 TRACE(("expbackq: read returns %d\n", i));
4950 back_exitstatus = waitforjob(in.jp);
4954 /* Eat all trailing newlines */
4956 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
4961 recordregion(startloc, dest - (char *)stackblock(), 0);
4962 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4963 (dest - (char *)stackblock()) - startloc,
4964 (dest - (char *)stackblock()) - startloc,
4965 stackblock() + startloc));
4970 scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
4981 const char *s = loc2;
4987 match = pmatch(str, s);
4991 if (quotes && *loc == CTLESC)
5001 scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5008 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5011 const char *s = loc2;
5016 match = pmatch(str, s);
5023 esc = esclen(startp, loc);
5035 subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
5039 int saveherefd = herefd;
5040 struct nodelist *saveargbackq = argbackq;
5042 char *rmesc, *rmescend;
5044 char *(*scan)(char *, char *, char *, char *, int , int);
5047 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
5048 STPUTC('\0', expdest);
5049 herefd = saveherefd;
5050 argbackq = saveargbackq;
5051 startp = stackblock() + startloc;
5055 setvar(str, startp, 0);
5056 amount = startp - expdest;
5057 STADJUST(amount, expdest);
5061 varunset(p, str, startp, varflags);
5065 subtype -= VSTRIMRIGHT;
5067 if (subtype < 0 || subtype > 3)
5072 rmescend = stackblock() + strloc;
5074 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5075 if (rmesc != startp) {
5077 startp = stackblock() + startloc;
5081 str = stackblock() + strloc;
5082 preglob(str, varflags & VSQUOTE, 0);
5084 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
5085 zero = subtype >> 1;
5086 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
5087 scan = (subtype & 1) ^ zero ? scanleft : scanright;
5089 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
5092 memmove(startp, loc, str - loc);
5093 loc = startp + (str - loc) - 1;
5096 amount = loc - expdest;
5097 STADJUST(amount, expdest);
5104 * Expand a variable, and return a pointer to the next character in the
5108 evalvar(char *p, int flag)
5122 quotes = flag & (EXP_FULL | EXP_CASE);
5124 subtype = varflags & VSTYPE;
5125 quoted = varflags & VSQUOTE;
5127 easy = (!quoted || (*var == '@' && shellparam.nparam));
5129 startloc = expdest - (char *)stackblock();
5130 p = strchr(p, '=') + 1;
5132 if (!is_name(*var)) {
5133 set = varisset(var, varflags & VSNUL);
5135 if (subtype == VSPLUS)
5138 varvalue(var, quoted, flag);
5139 if (subtype == VSLENGTH) {
5141 expdest - (char *)stackblock() -
5143 STADJUST(-varlen, expdest);
5150 /* jump here after setting a variable with ${var=text} */
5151 val = lookupvar(var);
5152 set = !val || ((varflags & VSNUL) && !*val);
5153 if (subtype == VSPLUS)
5156 varlen = strlen(val);
5157 if (subtype == VSLENGTH)
5160 val, varlen, quoted ? DQSYNTAX : BASESYNTAX,
5167 if (subtype == VSMINUS) {
5171 p, flag | EXP_TILDE |
5172 (quoted ? EXP_QWORD : EXP_WORD)
5181 if (subtype == VSASSIGN || subtype == VSQUESTION) {
5183 if (subevalvar(p, var, 0, subtype, startloc,
5187 * Remove any recorded regions beyond
5190 removerecordregions(startloc);
5201 varunset(p, var, 0, 0);
5203 if (subtype == VSLENGTH) {
5209 if (subtype == VSNORMAL) {
5213 recordregion(startloc, expdest - (char *)stackblock(), quoted);
5222 case VSTRIMRIGHTMAX:
5231 * Terminate the string and start recording the pattern
5234 STPUTC('\0', expdest);
5235 patloc = expdest - (char *)stackblock();
5236 if (subevalvar(p, NULL, patloc, subtype,
5237 startloc, varflags, quotes) == 0) {
5238 int amount = expdest - (
5239 (char *)stackblock() + patloc - 1
5241 STADJUST(-amount, expdest);
5243 /* Remove any recorded regions beyond start of variable */
5244 removerecordregions(startloc);
5249 if (subtype != VSNORMAL) { /* skip to end of alternative */
5252 if ((c = *p++) == CTLESC)
5254 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
5256 argbackq = argbackq->next;
5257 } else if (c == CTLVAR) {
5258 if ((*p++ & VSTYPE) != VSNORMAL)
5260 } else if (c == CTLENDVAR) {
5272 * Test whether a specialized variable is set.
5276 varisset(char *name, int nulok)
5279 return backgndpid != 0;
5280 else if (*name == '@' || *name == '*') {
5281 if (*shellparam.p == NULL)
5287 for (av = shellparam.p; *av; av++)
5292 } else if (is_digit(*name)) {
5294 int num = atoi(name);
5296 if (num > shellparam.nparam)
5302 ap = shellparam.p[num - 1];
5304 if (nulok && (ap == NULL || *ap == '\0'))
5312 * Put a string on the stack.
5316 memtodest(const char *p, size_t len, int syntax, int quotes) {
5319 q = makestrspace(len * 2, q);
5325 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5335 strtodest(const char *p, int syntax, int quotes)
5337 memtodest(p, strlen(p), syntax, quotes);
5342 * Add the value of a specialized variable to the stack string.
5346 varvalue(char *name, int quoted, int flags)
5355 int allow_split = flags & EXP_FULL;
5356 int quotes = flags & (EXP_FULL | EXP_CASE);
5358 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5367 num = shellparam.nparam;
5375 for (i = 0 ; i < NOPTS ; i++) {
5377 STPUTC(optletters(i), expdest);
5381 if (allow_split && quoted) {
5382 sep = 1 << CHAR_BIT;
5387 sep = ifsset() ? ifsval()[0] : ' ';
5389 sepq = (SIT(sep, syntax) == CCTL) || (SIT(sep, syntax) == CBACK);
5392 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
5393 strtodest(p, syntax, quotes);
5404 strtodest(arg0, syntax, quotes);
5408 if (num > 0 && num <= shellparam.nparam) {
5409 strtodest(shellparam.p[num - 1], syntax, quotes);
5417 * Record the fact that we have to scan this region of the
5418 * string for IFS characters.
5422 recordregion(int start, int end, int nulonly)
5424 struct ifsregion *ifsp;
5426 if (ifslastp == NULL) {
5430 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
5432 ifslastp->next = ifsp;
5436 ifslastp->begoff = start;
5437 ifslastp->endoff = end;
5438 ifslastp->nulonly = nulonly;
5443 * Break the argument string into pieces based upon IFS and add the
5444 * strings to the argument list. The regions of the string to be
5445 * searched for IFS characters have been stored by recordregion.
5448 ifsbreakup(char *string, struct arglist *arglist)
5450 struct ifsregion *ifsp;
5455 const char *ifs, *realifs;
5461 if (ifslastp != NULL) {
5464 realifs = ifsset() ? ifsval() : defifs;
5467 p = string + ifsp->begoff;
5468 nulonly = ifsp->nulonly;
5469 ifs = nulonly ? nullstr : realifs;
5471 while (p < string + ifsp->endoff) {
5475 if (strchr(ifs, *p)) {
5477 ifsspc = (strchr(defifs, *p) != NULL);
5478 /* Ignore IFS whitespace at start */
5479 if (q == start && ifsspc) {
5485 sp = (struct strlist *)stalloc(sizeof *sp);
5487 *arglist->lastp = sp;
5488 arglist->lastp = &sp->next;
5492 if (p >= string + ifsp->endoff) {
5498 if (strchr(ifs, *p) == NULL ) {
5501 } else if (strchr(defifs, *p) == NULL) {
5517 } while ((ifsp = ifsp->next) != NULL);
5526 sp = (struct strlist *)stalloc(sizeof *sp);
5528 *arglist->lastp = sp;
5529 arglist->lastp = &sp->next;
5535 struct ifsregion *p;
5540 struct ifsregion *ifsp;
5546 ifsfirst.next = NULL;
5550 static void expmeta(char *, char *);
5551 static struct strlist *expsort(struct strlist *);
5552 static struct strlist *msort(struct strlist *, int);
5554 static char *expdir;
5558 expandmeta(struct strlist *str, int flag)
5560 static const char metachars[] = {
5563 /* TODO - EXP_REDIR */
5566 struct strlist **savelastp;
5572 if (!strpbrk(str->text, metachars))
5574 savelastp = exparg.lastp;
5577 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
5579 int i = strlen(str->text);
5580 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5588 if (exparg.lastp == savelastp) {
5593 *exparg.lastp = str;
5594 rmescapes(str->text);
5595 exparg.lastp = &str->next;
5597 *exparg.lastp = NULL;
5598 *savelastp = sp = expsort(*savelastp);
5599 while (sp->next != NULL)
5601 exparg.lastp = &sp->next;
5608 * Add a file name to the list.
5612 addfname(const char *name)
5616 sp = (struct strlist *)stalloc(sizeof *sp);
5617 sp->text = sstrdup(name);
5619 exparg.lastp = &sp->next;
5624 * Do metacharacter (i.e. *, ?, [...]) expansion.
5628 expmeta(char *enddir, char *name)
5643 for (p = name; *p; p++) {
5644 if (*p == '*' || *p == '?')
5646 else if (*p == '[') {
5653 if (*q == '/' || *q == '\0')
5660 } else if (*p == '\\')
5662 else if (*p == '/') {
5669 if (metaflag == 0) { /* we've reached the end of the file name */
5670 if (enddir != expdir)
5678 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
5689 } while (p < start);
5691 if (enddir == expdir) {
5693 } else if (enddir == expdir + 1 && *expdir == '/') {
5699 if ((dirp = opendir(cp)) == NULL)
5701 if (enddir != expdir)
5703 if (*endname == 0) {
5715 while (! intpending && (dp = readdir(dirp)) != NULL) {
5716 if (dp->d_name[0] == '.' && ! matchdot)
5718 if (pmatch(start, dp->d_name)) {
5720 scopy(dp->d_name, enddir);
5723 for (p = enddir, cp = dp->d_name;
5724 (*p++ = *cp++) != '\0';)
5727 expmeta(p, endname);
5737 * Sort the results of file name expansion. It calculates the number of
5738 * strings to sort and then calls msort (short for merge sort) to do the
5742 static struct strlist *
5743 expsort(struct strlist *str)
5749 for (sp = str ; sp ; sp = sp->next)
5751 return msort(str, len);
5755 static struct strlist *
5756 msort(struct strlist *list, int len)
5758 struct strlist *p, *q = NULL;
5759 struct strlist **lpp;
5767 for (n = half ; --n >= 0 ; ) {
5771 q->next = NULL; /* terminate first half of list */
5772 q = msort(list, half); /* sort first half of list */
5773 p = msort(p, len - half); /* sort second half */
5776 #ifdef CONFIG_LOCALE_SUPPORT
5777 if (strcoll(p->text, q->text) < 0)
5779 if (strcmp(p->text, q->text) < 0)
5784 if ((p = *lpp) == NULL) {
5791 if ((q = *lpp) == NULL) {
5802 * Returns true if the pattern matches the string.
5806 patmatch(char *pattern, const char *string)
5808 return pmatch(preglob(pattern, 0, 0), string);
5813 * Remove any CTLESC characters from a string.
5817 _rmescapes(char *str, int flag)
5820 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
5825 p = strpbrk(str, qchars);
5831 if (flag & RMESCAPE_ALLOC) {
5832 size_t len = p - str;
5833 size_t fulllen = len + strlen(p) + 1;
5835 if (flag & RMESCAPE_GROW) {
5836 r = makestrspace(fulllen, expdest);
5837 } else if (flag & RMESCAPE_HEAP) {
5838 r = ckmalloc(fulllen);
5840 r = stalloc(fulllen);
5844 q = mempcpy(q, str, len);
5847 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5848 globbing = flag & RMESCAPE_GLOB;
5849 notescaped = globbing;
5851 if (*p == CTLQUOTEMARK) {
5852 inquotes = ~inquotes;
5854 notescaped = globbing;
5858 /* naked back slash */
5864 if (notescaped && inquotes && *p != '/') {
5868 notescaped = globbing;
5873 if (flag & RMESCAPE_GROW) {
5875 STADJUST(q - r + 1, expdest);
5882 * See if a pattern matches in a case statement.
5886 casematch(union node *pattern, char *val)
5888 struct stackmark smark;
5891 setstackmark(&smark);
5892 argbackq = pattern->narg.backquote;
5893 STARTSTACKSTR(expdest);
5895 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
5896 STACKSTRNUL(expdest);
5897 result = patmatch(stackblock(), val);
5898 popstackmark(&smark);
5911 expdest = makestrspace(32, expdest);
5912 len = fmtstr(expdest, 32, "%ld", num);
5913 STADJUST(len, expdest);
5918 varunset(const char *end, const char *var, const char *umsg, int varflags)
5924 msg = "parameter not set";
5926 if (*end == CTLENDVAR) {
5927 if (varflags & VSNUL)
5932 error("%.*s: %s%s", end - var - 1, var, msg, tail);
5936 /* $NetBSD: input.c,v 1.37 2002/11/24 22:35:40 christos Exp $ */
5939 * This implements the input routines used by the parser.
5942 #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
5943 #define IBUFSIZ (BUFSIZ + 1)
5945 static void pushfile(void);
5948 * Read a line from the script.
5951 static inline char *
5952 pfgets(char *line, int len)
5958 while (--nleft > 0) {
5975 * Read a character from the script, returning PEOF on end of file.
5976 * Nul characters in the input are silently discarded.
5979 #define pgetc_as_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
5981 #ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
5982 #define pgetc_macro() pgetc()
5986 return pgetc_as_macro();
5989 #define pgetc_macro() pgetc_as_macro()
5993 return pgetc_macro();
5999 * Same as pgetc(), but ignores PEOA.
6001 #ifdef CONFIG_ASH_ALIAS
6002 static int pgetc2(void)
6008 } while (c == PEOA);
6012 static inline int pgetc2(void)
6014 return pgetc_macro();
6019 #ifdef CONFIG_FEATURE_COMMAND_EDITING
6020 static const char *cmdedit_prompt;
6021 static inline void putprompt(const char *s)
6026 static inline void putprompt(const char *s)
6036 char *buf = parsefile->buf;
6040 #ifdef CONFIG_FEATURE_COMMAND_EDITING
6041 if (!iflag || parsefile->fd)
6042 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6044 nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
6046 /* Ctrl+C presend */
6051 /* Ctrl+D presend */
6056 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6060 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6061 int flags = fcntl(0, F_GETFL, 0);
6062 if (flags >= 0 && flags & O_NONBLOCK) {
6063 flags &=~ O_NONBLOCK;
6064 if (fcntl(0, F_SETFL, flags) >= 0) {
6065 out2str("sh: turning off NDELAY mode\n");
6075 * Refill the input buffer and return the next input character:
6077 * 1) If a string was pushed back on the input, pop it;
6078 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6079 * from a string so we can't refill the buffer, return EOF.
6080 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6081 * 4) Process input up to the next newline, deleting nul characters.
6091 while (parsefile->strpush) {
6092 #ifdef CONFIG_ASH_ALIAS
6093 if (parsenleft == -1 && parsefile->strpush->ap &&
6094 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
6099 if (--parsenleft >= 0)
6100 return (*parsenextc++);
6102 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6107 if (parselleft <= 0) {
6108 if ((parselleft = preadfd()) <= 0) {
6109 parselleft = parsenleft = EOF_NLEFT;
6116 /* delete nul characters */
6117 for (more = 1; more;) {
6124 parsenleft = q - parsenextc;
6125 more = 0; /* Stop processing here */
6132 if (--parselleft <= 0 && more) {
6133 parsenleft = q - parsenextc - 1;
6144 out2str(parsenextc);
6149 return *parsenextc++;
6153 * Undo the last call to pgetc. Only one character may be pushed back.
6154 * PEOF may be pushed back.
6165 * Push a string back onto the input at this current parsefile level.
6166 * We handle aliases this way.
6169 pushstring(char *s, void *ap)
6176 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6177 if (parsefile->strpush) {
6178 sp = ckmalloc(sizeof (struct strpush));
6179 sp->prev = parsefile->strpush;
6180 parsefile->strpush = sp;
6182 sp = parsefile->strpush = &(parsefile->basestrpush);
6183 sp->prevstring = parsenextc;
6184 sp->prevnleft = parsenleft;
6185 #ifdef CONFIG_ASH_ALIAS
6186 sp->ap = (struct alias *)ap;
6188 ((struct alias *)ap)->flag |= ALIASINUSE;
6200 struct strpush *sp = parsefile->strpush;
6203 #ifdef CONFIG_ASH_ALIAS
6205 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6206 checkkwd |= CHKALIAS;
6208 if (sp->string != sp->ap->val) {
6211 sp->ap->flag &= ~ALIASINUSE;
6212 if (sp->ap->flag & ALIASDEAD) {
6213 unalias(sp->ap->name);
6217 parsenextc = sp->prevstring;
6218 parsenleft = sp->prevnleft;
6219 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6220 parsefile->strpush = sp->prev;
6221 if (sp != &(parsefile->basestrpush))
6227 * Set the input to take input from a file. If push is set, push the
6228 * old input onto the stack first.
6232 setinputfile(const char *fname, int push)
6238 if ((fd = open(fname, O_RDONLY)) < 0)
6239 error("Can't open %s", fname);
6241 fd2 = copyfd(fd, 10);
6244 error("Out of file descriptors");
6247 setinputfd(fd, push);
6253 * Like setinputfile, but takes an open file descriptor. Call this with
6258 setinputfd(int fd, int push)
6260 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
6266 if (parsefile->buf == NULL)
6267 parsefile->buf = ckmalloc(IBUFSIZ);
6268 parselleft = parsenleft = 0;
6274 * Like setinputfile, but takes input from a string.
6278 setinputstring(char *string)
6282 parsenextc = string;
6283 parsenleft = strlen(string);
6284 parsefile->buf = NULL;
6291 * To handle the "." command, a stack of input files is used. Pushfile
6292 * adds a new entry to the stack and popfile restores the previous level.
6298 struct parsefile *pf;
6300 parsefile->nleft = parsenleft;
6301 parsefile->lleft = parselleft;
6302 parsefile->nextc = parsenextc;
6303 parsefile->linno = plinno;
6304 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
6305 pf->prev = parsefile;
6308 pf->basestrpush.prev = NULL;
6316 struct parsefile *pf = parsefile;
6325 parsefile = pf->prev;
6327 parsenleft = parsefile->nleft;
6328 parselleft = parsefile->lleft;
6329 parsenextc = parsefile->nextc;
6330 plinno = parsefile->linno;
6336 * Return to top level.
6342 while (parsefile != &basepf)
6348 * Close the file(s) that the shell is reading commands from. Called
6349 * after a fork is done.
6356 if (parsefile->fd > 0) {
6357 close(parsefile->fd);
6362 /* $NetBSD: jobs.c,v 1.56 2002/11/25 12:13:03 agc Exp $ */
6364 /* mode flags for set_curjob */
6365 #define CUR_DELETE 2
6366 #define CUR_RUNNING 1
6367 #define CUR_STOPPED 0
6369 /* mode flags for dowait */
6370 #define DOWAIT_NORMAL 0
6371 #define DOWAIT_BLOCK 1
6374 static struct job *jobtab;
6376 static unsigned njobs;
6378 /* pgrp of shell on invocation */
6379 static int initialpgrp;
6380 static int ttyfd = -1;
6383 static struct job *curjob;
6384 /* number of presumed living untracked jobs */
6387 static void set_curjob(struct job *, unsigned);
6389 static int restartjob(struct job *, int);
6390 static void xtcsetpgrp(int, pid_t);
6391 static char *commandtext(union node *);
6392 static void cmdlist(union node *, int);
6393 static void cmdtxt(union node *);
6394 static void cmdputs(const char *);
6395 static void showpipe(struct job *, FILE *);
6397 static int sprint_status(char *, int, int);
6398 static void freejob(struct job *);
6399 static struct job *getjob(const char *, int);
6400 static struct job *growjobtab(void);
6401 static void forkchild(struct job *, union node *, int);
6402 static void forkparent(struct job *, union node *, int, pid_t);
6403 static int dowait(int, struct job *);
6404 static int getstatus(struct job *);
6407 set_curjob(struct job *jp, unsigned mode)
6410 struct job **jpp, **curp;
6412 /* first remove from list */
6413 jpp = curp = &curjob;
6418 jpp = &jp1->prev_job;
6420 *jpp = jp1->prev_job;
6422 /* Then re-insert in correct position */
6430 /* job being deleted */
6433 /* newly created job or backgrounded job,
6434 put after all stopped jobs. */
6438 if (!jp1 || jp1->state != JOBSTOPPED)
6441 jpp = &jp1->prev_job;
6447 /* newly stopped job - becomes curjob */
6448 jp->prev_job = *jpp;
6456 * Turn job control on and off.
6458 * Note: This code assumes that the third arg to ioctl is a character
6459 * pointer, which is true on Berkeley systems but not System V. Since
6460 * System V doesn't have job control yet, this isn't a problem now.
6462 * Called with interrupts off.
6471 if (on == jobctl || rootshell == 0)
6475 ofd = fd = open(_PATH_TTY, O_RDWR);
6478 while (!isatty(fd) && --fd >= 0)
6481 fd = fcntl(fd, F_DUPFD, 10);
6485 fcntl(fd, F_SETFD, FD_CLOEXEC);
6486 do { /* while we are in the background */
6487 if ((pgrp = tcgetpgrp(fd)) < 0) {
6489 sh_warnx("can't access tty; job control turned off");
6493 if (pgrp == getpgrp())
6504 xtcsetpgrp(fd, pgrp);
6506 /* turning job control off */
6509 xtcsetpgrp(fd, pgrp);
6523 killcmd(int argc, char **argv)
6534 "Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6535 "kill -l [exitstatus]"
6539 if (**++argv == '-') {
6540 signo = decode_signal(*argv + 1, 1);
6544 while ((c = nextopt("ls:")) != '\0')
6554 signo = decode_signal(optionarg, 1);
6557 "invalid signal number or name: %s",
6568 if (!list && signo < 0)
6571 if ((signo < 0 || !*argv) ^ list) {
6579 for (i = 1; i < NSIG; i++) {
6580 name = u_signal_names(0, &i, 1);
6582 out1fmt(snlfmt, name);
6586 name = u_signal_names(*argptr, &signo, -1);
6588 out1fmt(snlfmt, name);
6590 error("invalid signal number or exit status: %s", *argptr);
6596 if (**argv == '%') {
6597 jp = getjob(*argv, 0);
6598 pid = -jp->ps[0].pid;
6600 pid = number(*argv);
6601 if (kill(pid, signo) != 0) {
6611 #if defined(JOBS) || defined(DEBUG)
6613 jobno(const struct job *jp)
6615 return jp - jobtab + 1;
6621 fgcmd(int argc, char **argv)
6628 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
6633 jp = getjob(*argv, 1);
6634 if (mode == FORK_BG) {
6635 set_curjob(jp, CUR_RUNNING);
6636 fprintf(out, "[%d] ", jobno(jp));
6638 outstr(jp->ps->cmd, out);
6640 retval = restartjob(jp, mode);
6641 } while (*argv && *++argv);
6645 static int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
6649 restartjob(struct job *jp, int mode)
6651 struct procstat *ps;
6657 if (jp->state == JOBDONE)
6659 jp->state = JOBRUNNING;
6661 if (mode == FORK_FG)
6662 xtcsetpgrp(ttyfd, pgid);
6663 killpg(pgid, SIGCONT);
6667 if (WIFSTOPPED(ps->status)) {
6670 } while (ps++, --i);
6672 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
6679 sprint_status(char *s, int status, int sigonly)
6685 st = WEXITSTATUS(status);
6686 if (!WIFEXITED(status)) {
6687 st = WTERMSIG(status);
6689 if (WIFSTOPPED(status))
6690 st = WSTOPSIG(status);
6693 if (st == SIGINT || st == SIGPIPE)
6695 if (WIFSTOPPED(status))
6699 col = fmtstr(s, 32, u_signal_names(NULL, &st, 0));
6700 if (WCOREDUMP(status)) {
6701 col += fmtstr(s + col, 16, " (core dumped)");
6703 } else if (!sigonly) {
6705 col = fmtstr(s, 16, "Done(%d)", st);
6707 col = fmtstr(s, 16, "Done");
6716 showjob(FILE *out, struct job *jp, int mode)
6718 struct procstat *ps;
6719 struct procstat *psend;
6726 if (mode & SHOW_PGID) {
6727 /* just output process (group) id of pipeline */
6728 fprintf(out, "%d\n", ps->pid);
6732 col = fmtstr(s, 16, "[%d] ", jobno(jp));
6737 else if (curjob && jp == curjob->prev_job)
6740 if (mode & SHOW_PID)
6741 col += fmtstr(s + col, 16, "%d ", ps->pid);
6743 psend = ps + jp->nprocs;
6745 if (jp->state == JOBRUNNING) {
6746 scopy("Running", s + col);
6747 col += strlen("Running");
6749 int status = psend[-1].status;
6751 if (jp->state == JOBSTOPPED)
6752 status = jp->stopstatus;
6754 col += sprint_status(s + col, status, 0);
6760 /* for each process */
6761 col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
6764 fprintf(out, "%s%*c%s",
6765 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
6767 if (!(mode & SHOW_PID)) {
6771 if (++ps == psend) {
6772 outcslow('\n', out);
6779 if (jp->state == JOBDONE) {
6780 TRACE(("showjob: freeing job %d\n", jobno(jp)));
6787 jobscmd(int argc, char **argv)
6793 while ((m = nextopt("lp")))
6803 showjob(out, getjob(*argv,0), mode);
6806 showjobs(out, mode);
6813 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6814 * statuses have changed since the last call to showjobs.
6818 showjobs(FILE *out, int mode)
6822 TRACE(("showjobs(%x) called\n", mode));
6824 /* If not even one one job changed, there is nothing to do */
6825 while (dowait(DOWAIT_NORMAL, NULL) > 0)
6828 for (jp = curjob; jp; jp = jp->prev_job) {
6829 if (!(mode & SHOW_CHANGED) || jp->changed)
6830 showjob(out, jp, mode);
6836 * Mark a job structure as unused.
6840 freejob(struct job *jp)
6842 struct procstat *ps;
6846 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
6847 if (ps->cmd != nullstr)
6850 if (jp->ps != &jp->ps0)
6853 set_curjob(jp, CUR_DELETE);
6859 waitcmd(int argc, char **argv)
6872 /* wait for all jobs */
6877 /* no running procs */
6880 if (jp->state == JOBRUNNING)
6885 dowait(DOWAIT_BLOCK, 0);
6891 if (**argv != '%') {
6892 pid_t pid = number(*argv);
6896 if (job->ps[job->nprocs - 1].pid == pid)
6898 job = job->prev_job;
6904 job = getjob(*argv, 0);
6905 /* loop until process terminated or stopped */
6906 while (job->state == JOBRUNNING)
6907 dowait(DOWAIT_BLOCK, 0);
6909 retval = getstatus(job);
6920 * Convert a job name to a job structure.
6924 getjob(const char *name, int getctl)
6928 const char *err_msg = "No such job: %s";
6932 char *(*match)(const char *, const char *);
6947 if (c == '+' || c == '%') {
6949 err_msg = "No current job";
6951 } else if (c == '-') {
6954 err_msg = "No previous job";
6965 jp = jobtab + num - 1;
6982 if (match(jp->ps[0].cmd, p)) {
6986 err_msg = "%s: ambiguous";
6993 err_msg = "job %s not created under job control";
6994 if (getctl && jp->jobctl == 0)
6999 error(err_msg, name);
7004 * Return a new job structure.
7005 * Called with interrupts off.
7009 makejob(union node *node, int nprocs)
7014 for (i = njobs, jp = jobtab ; ; jp++) {
7021 if (jp->state != JOBDONE || !jp->waited)
7030 memset(jp, 0, sizeof(*jp));
7035 jp->prev_job = curjob;
7040 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
7042 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
7052 struct job *jp, *jq;
7054 len = njobs * sizeof(*jp);
7056 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
7058 offset = (char *)jp - (char *)jq;
7060 /* Relocate pointers */
7063 jq = (struct job *)((char *)jq + l);
7067 #define joff(p) ((struct job *)((char *)(p) + l))
7068 #define jmove(p) (p) = (void *)((char *)(p) + offset)
7069 if (likely(joff(jp)->ps == &jq->ps0))
7070 jmove(joff(jp)->ps);
7071 if (joff(jp)->prev_job)
7072 jmove(joff(jp)->prev_job);
7082 jp = (struct job *)((char *)jp + len);
7086 } while (--jq >= jp);
7092 * Fork off a subshell. If we are doing job control, give the subshell its
7093 * own process group. Jp is a job structure that the job is to be added to.
7094 * N is the command that will be evaluated by the child. Both jp and n may
7095 * be NULL. The mode parameter can be one of the following:
7096 * FORK_FG - Fork off a foreground process.
7097 * FORK_BG - Fork off a background process.
7098 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
7099 * process group even if job control is on.
7101 * When job control is turned off, background processes have their standard
7102 * input redirected to /dev/null (except for the second and later processes
7105 * Called with interrupts off.
7109 forkchild(struct job *jp, union node *n, int mode)
7113 TRACE(("Child shell %d\n", getpid()));
7114 wasroot = rootshell;
7120 /* do job control only in root shell */
7122 if (mode != FORK_NOJOB && jp->jobctl && wasroot) {
7125 if (jp->nprocs == 0)
7128 pgrp = jp->ps[0].pid;
7129 /* This can fail because we are doing it in the parent also */
7130 (void)setpgid(0, pgrp);
7131 if (mode == FORK_FG)
7132 xtcsetpgrp(ttyfd, pgrp);
7137 if (mode == FORK_BG) {
7140 if (jp->nprocs == 0) {
7142 if (open(_PATH_DEVNULL, O_RDONLY) != 0)
7143 error("Can't open %s", _PATH_DEVNULL);
7146 if (wasroot && iflag) {
7151 for (jp = curjob; jp; jp = jp->prev_job)
7157 forkparent(struct job *jp, union node *n, int mode, pid_t pid)
7159 TRACE(("In parent shell: child = %d\n", pid));
7161 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
7166 if (mode != FORK_NOJOB && jp->jobctl) {
7169 if (jp->nprocs == 0)
7172 pgrp = jp->ps[0].pid;
7173 /* This can fail because we are doing it in the child also */
7174 (void)setpgid(pid, pgrp);
7177 if (mode == FORK_BG) {
7178 backgndpid = pid; /* set $! */
7179 set_curjob(jp, CUR_RUNNING);
7182 struct procstat *ps = &jp->ps[jp->nprocs++];
7188 ps->cmd = commandtext(n);
7194 forkshell(struct job *jp, union node *n, int mode)
7198 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
7201 TRACE(("Fork failed, errno=%d", errno));
7204 error("Cannot fork");
7207 forkchild(jp, n, mode);
7209 forkparent(jp, n, mode, pid);
7214 * Wait for job to finish.
7216 * Under job control we have the problem that while a child process is
7217 * running interrupts generated by the user are sent to the child but not
7218 * to the shell. This means that an infinite loop started by an inter-
7219 * active user may be hard to kill. With job control turned off, an
7220 * interactive user may place an interactive program inside a loop. If
7221 * the interactive program catches interrupts, the user doesn't want
7222 * these interrupts to also abort the loop. The approach we take here
7223 * is to have the shell ignore interrupt signals while waiting for a
7224 * forground process to terminate, and then send itself an interrupt
7225 * signal if the child process was terminated by an interrupt signal.
7226 * Unfortunately, some programs want to do a bit of cleanup and then
7227 * exit on interrupt; unless these processes terminate themselves by
7228 * sending a signal to themselves (instead of calling exit) they will
7229 * confuse this approach.
7231 * Called with interrupts off.
7235 waitforjob(struct job *jp)
7239 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
7240 while (jp->state == JOBRUNNING) {
7241 dowait(DOWAIT_BLOCK, jp);
7246 xtcsetpgrp(ttyfd, rootpid);
7248 * This is truly gross.
7249 * If we're doing job control, then we did a TIOCSPGRP which
7250 * caused us (the shell) to no longer be in the controlling
7251 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7252 * intuit from the subprocess exit status whether a SIGINT
7253 * occurred, and if so interrupt ourselves. Yuck. - mycroft
7258 if (jp->state == JOBDONE)
7266 * Do a wait system call. If job control is compiled in, we accept
7267 * stopped processes. If block is zero, we return a value of zero
7268 * rather than blocking.
7270 * System V doesn't have a non-blocking wait system call. It does
7271 * have a SIGCLD signal that is sent to a process when one of it's
7272 * children dies. The obvious way to use SIGCLD would be to install
7273 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7274 * was received, and have waitproc bump another counter when it got
7275 * the status of a process. Waitproc would then know that a wait
7276 * system call would not block if the two counters were different.
7277 * This approach doesn't work because if a process has children that
7278 * have not been waited for, System V will send it a SIGCLD when it
7279 * installs a signal handler for SIGCLD. What this means is that when
7280 * a child exits, the shell will be sent SIGCLD signals continuously
7281 * until is runs out of stack space, unless it does a wait call before
7282 * restoring the signal handler. The code below takes advantage of
7283 * this (mis)feature by installing a signal handler for SIGCLD and
7284 * then checking to see whether it was called. If there are any
7285 * children to be waited for, it will be.
7287 * If neither SYSV nor BSD is defined, we don't implement nonblocking
7288 * waits at all. In this case, the user will not be informed when
7289 * a background process until the next time she runs a real program
7290 * (as opposed to running a builtin command or just typing return),
7291 * and the jobs command may give out of date information.
7295 waitproc(int block, int *status)
7305 return wait3(status, flags, (struct rusage *)NULL);
7309 * Wait for a process to terminate.
7313 dowait(int block, struct job *job)
7318 struct job *thisjob;
7321 TRACE(("dowait(%d) called\n", block));
7322 pid = waitproc(block, &status);
7323 TRACE(("wait returns pid %d, status=%d\n", pid, status));
7328 for (jp = curjob; jp; jp = jp->prev_job) {
7329 struct procstat *sp;
7330 struct procstat *spend;
7331 if (jp->state == JOBDONE)
7334 spend = jp->ps + jp->nprocs;
7337 if (sp->pid == pid) {
7338 TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
7339 sp->status = status;
7342 if (sp->status == -1)
7345 if (state == JOBRUNNING)
7347 if (WIFSTOPPED(sp->status)) {
7348 jp->stopstatus = sp->status;
7352 } while (++sp < spend);
7357 if (!WIFSTOPPED(status))
7364 if (state != JOBRUNNING) {
7365 thisjob->changed = 1;
7367 if (thisjob->state != state) {
7368 TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
7369 thisjob->state = state;
7371 if (state == JOBSTOPPED) {
7372 set_curjob(thisjob, CUR_STOPPED);
7381 if (thisjob && thisjob == job) {
7385 len = sprint_status(s, status, 1);
7397 * return 1 if there are stopped jobs, otherwise 0
7410 if (jp && jp->state == JOBSTOPPED) {
7411 out2str("You have stopped jobs.\n");
7421 * Return a string identifying a command (to be printed by the
7426 static char *cmdnextc;
7429 commandtext(union node *n)
7433 STARTSTACKSTR(cmdnextc);
7435 name = stackblock();
7436 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
7437 name, cmdnextc, cmdnextc));
7438 return savestr(name);
7442 cmdtxt(union node *n)
7445 struct nodelist *lp;
7455 lp = n->npipe.cmdlist;
7473 cmdtxt(n->nbinary.ch1);
7489 cmdtxt(n->nif.test);
7492 if (n->nif.elsepart) {
7495 n = n->nif.elsepart;
7511 cmdtxt(n->nbinary.ch1);
7521 cmdputs(n->nfor.var);
7523 cmdlist(n->nfor.args, 1);
7528 cmdputs(n->narg.text);
7532 cmdlist(n->ncmd.args, 1);
7533 cmdlist(n->ncmd.redirect, 0);
7546 cmdputs(n->ncase.expr->narg.text);
7548 for (np = n->ncase.cases; np; np = np->nclist.next) {
7549 cmdtxt(np->nclist.pattern);
7551 cmdtxt(np->nclist.body);
7577 s[0] = n->nfile.fd + '0';
7581 if (n->type == NTOFD || n->type == NFROMFD) {
7582 s[0] = n->ndup.dupfd + '0';
7593 cmdlist(union node *np, int sep)
7595 for (; np; np = np->narg.next) {
7599 if (sep && np->narg.next)
7605 cmdputs(const char *s)
7607 const char *p, *str;
7608 char c, cc[2] = " ";
7612 static const char *const vstype[16] = {
7613 nullstr, "}", "-", "+", "?", "=",
7614 "#", "##", "%", "%%"
7617 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
7619 while ((c = *p++) != 0) {
7627 if ((subtype & VSTYPE) == VSLENGTH)
7631 if (!(subtype & VSQUOTE) != !(quoted & 1)) {
7649 case CTLBACKQ+CTLQUOTE:
7652 #ifdef CONFIG_ASH_MATH_SUPPORT
7667 str = vstype[subtype & VSTYPE];
7668 if (subtype & VSNUL)
7679 /* These can only happen inside quotes */
7691 while ((c = *str++)) {
7696 USTPUTC('"', nextc);
7704 showpipe(struct job *jp, FILE *out)
7706 struct procstat *sp;
7707 struct procstat *spend;
7709 spend = jp->ps + jp->nprocs;
7710 for (sp = jp->ps + 1; sp < spend; sp++)
7711 fprintf(out, " | %s", sp->cmd);
7712 outcslow('\n', out);
7717 xtcsetpgrp(int fd, pid_t pgrp)
7719 if (tcsetpgrp(fd, pgrp))
7720 error("Cannot set tty process group (%m)");
7725 getstatus(struct job *job) {
7729 status = job->ps[job->nprocs - 1].status;
7730 retval = WEXITSTATUS(status);
7731 if (!WIFEXITED(status)) {
7733 retval = WSTOPSIG(status);
7734 if (!WIFSTOPPED(status))
7737 /* XXX: limits number of signals */
7738 retval = WTERMSIG(status);
7740 if (retval == SIGINT)
7746 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
7747 jobno(job), job->nprocs, status, retval));
7751 #ifdef CONFIG_ASH_MAIL
7752 /* $NetBSD: mail.c,v 1.15 2002/11/24 22:35:40 christos Exp $ */
7755 * Routines to check for mail. (Perhaps make part of main.c?)
7758 #define MAXMBOXES 10
7760 /* times of mailboxes */
7761 static time_t mailtime[MAXMBOXES];
7762 /* Set if MAIL or MAILPATH is changed. */
7763 static int mail_var_path_changed;
7768 * Print appropriate message(s) if mail has arrived.
7769 * If mail_var_path_changed is set,
7770 * then the value of MAIL has mail_var_path_changed,
7771 * so we just update the values.
7781 struct stackmark smark;
7784 setstackmark(&smark);
7785 mpath = mpathset() ? mpathval() : mailval();
7786 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
7787 p = padvance(&mpath, nullstr);
7792 for (q = p ; *q ; q++);
7797 q[-1] = '\0'; /* delete trailing '/' */
7798 if (stat(p, &statb) < 0) {
7802 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
7805 pathopt ? pathopt : "you have mail"
7808 *mtp = statb.st_mtime;
7810 mail_var_path_changed = 0;
7811 popstackmark(&smark);
7816 changemail(const char *val)
7818 mail_var_path_changed++;
7821 #endif /* CONFIG_ASH_MAIL */
7823 /* $NetBSD: main.c,v 1.46 2002/12/11 19:12:18 christos Exp $ */
7827 static short profile_buf[16384];
7831 static int isloginsh;
7833 static void read_profile(const char *);
7836 * Main routine. We initialize things, parse the arguments, execute
7837 * profiles if we're a login shell, and then call cmdloop to execute
7838 * commands. The setjmp call sets up the location to jump to when an
7839 * exception occurs. When an exception occurs the variable "state"
7840 * is used to figure out how far we had gotten.
7844 ash_main(int argc, char **argv)
7848 struct jmploc jmploc;
7849 struct stackmark smark;
7852 dash_errno = __errno_location();
7856 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7859 if (setjmp(jmploc.loc)) {
7866 switch (exception) {
7876 status = exitstatus;
7879 exitstatus = status;
7881 if (e == EXEXIT || state == 0 || iflag == 0 || ! rootshell)
7885 outcslow('\n', stderr);
7887 popstackmark(&smark);
7888 FORCEINTON; /* enable interrupts */
7891 else if (state == 2)
7893 else if (state == 3)
7901 trputs("Shell args: "); trargs(argv);
7906 setstackmark(&smark);
7907 procargs(argc, argv);
7908 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7910 const char *hp = lookupvar("HISTFILE");
7913 hp = lookupvar("HOME");
7915 char *defhp = concat_path_file(hp, ".ash_history");
7916 setvar("HISTFILE", defhp, 0);
7922 if (argv[0] && argv[0][0] == '-')
7926 read_profile("/etc/profile");
7929 read_profile(".profile");
7935 getuid() == geteuid() && getgid() == getegid() &&
7939 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
7940 read_profile(shinit);
7946 evalstring(minusc, 0);
7948 if (sflag || minusc == NULL) {
7949 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7951 const char *hp = lookupvar("HISTFILE");
7954 load_history ( hp );
7957 state4: /* XXX ??? - why isn't this before the "if" statement */
7965 extern void _mcleanup(void);
7975 * Read and execute commands. "Top" is nonzero for the top level command
7976 * loop; it turns on prompting if the shell is interactive.
7983 struct stackmark smark;
7987 TRACE(("cmdloop(%d) called\n", top));
7988 setstackmark(&smark);
7994 showjobs(stderr, SHOW_CHANGED);
7999 #ifdef CONFIG_ASH_MAIL
8003 n = parsecmd(inter);
8004 /* showtree(n); DEBUG */
8006 if (!top || numeof >= 50)
8008 if (!stoppedjobs()) {
8011 out2str("\nUse \"exit\" to leave shell.\n");
8014 } else if (n != NULL && nflag == 0) {
8015 job_warning = (job_warning == 2) ? 1 : 0;
8019 popstackmark(&smark);
8020 setstackmark(&smark);
8021 if (evalskip == SKIPFILE) {
8026 popstackmark(&smark);
8031 * Read /etc/profile or .profile. Return on error.
8035 read_profile(const char *name)
8042 if ((fd = open(name, O_RDONLY)) >= 0)
8047 /* -q turns off -x and -v just when executing init files */
8050 xflag = 0, xflag_set = 1;
8052 vflag = 0, vflag_set = 1;
8066 * Read a file containing shell functions.
8070 readcmdfile(char *name)
8075 if ((fd = open(name, O_RDONLY)) >= 0)
8078 error("Can't open %s", name);
8086 * Take commands from a file. To be compatible we should do a path
8087 * search for the file, which is necessary to find sub-commands.
8090 static inline char *
8091 find_dot_file(char *name)
8094 const char *path = pathval();
8097 /* don't try this for absolute or relative paths */
8098 if (strchr(name, '/'))
8101 while ((fullname = padvance(&path, name)) != NULL) {
8102 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
8104 * Don't bother freeing here, since it will
8105 * be freed by the caller.
8109 stunalloc(fullname);
8112 /* not found in the PATH */
8113 error(not_found_msg, name);
8118 dotcmd(int argc, char **argv)
8122 if (argc >= 2) { /* That's what SVR2 does */
8124 struct stackmark smark;
8126 setstackmark(&smark);
8127 fullname = find_dot_file(argv[1]);
8128 setinputfile(fullname, 1);
8129 commandname = fullname;
8132 popstackmark(&smark);
8139 exitcmd(int argc, char **argv)
8144 exitstatus = number(argv[1]);
8149 /* $NetBSD: memalloc.c,v 1.27 2003/01/22 20:36:04 dsl Exp $ */
8152 * Same for malloc, realloc, but returns an error when out of space.
8156 ckrealloc(pointer p, size_t nbytes)
8158 p = realloc(p, nbytes);
8160 error(bb_msg_memory_exhausted);
8165 ckmalloc(size_t nbytes)
8167 return ckrealloc(NULL, nbytes);
8171 * Make a copy of a string in safe storage.
8175 savestr(const char *s)
8177 char *p = strdup(s);
8179 error(bb_msg_memory_exhausted);
8185 * Parse trees for commands are allocated in lifo order, so we use a stack
8186 * to make this more efficient, and also to avoid all sorts of exception
8187 * handling code to handle interrupts in the middle of a parse.
8189 * The size 504 was chosen because the Ultrix malloc handles that size
8195 stalloc(size_t nbytes)
8200 aligned = SHELL_ALIGN(nbytes);
8201 if (aligned > stacknleft) {
8204 struct stack_block *sp;
8206 blocksize = aligned;
8207 if (blocksize < MINSIZE)
8208 blocksize = MINSIZE;
8209 len = sizeof(struct stack_block) - MINSIZE + blocksize;
8210 if (len < blocksize)
8211 error(bb_msg_memory_exhausted);
8215 stacknxt = sp->space;
8216 stacknleft = blocksize;
8217 sstrend = stacknxt + blocksize;
8222 stacknxt += aligned;
8223 stacknleft -= aligned;
8229 stunalloc(pointer p)
8232 if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
8233 write(2, "stunalloc\n", 10);
8237 stacknleft += stacknxt - (char *)p;
8243 setstackmark(struct stackmark *mark)
8245 mark->stackp = stackp;
8246 mark->stacknxt = stacknxt;
8247 mark->stacknleft = stacknleft;
8248 mark->marknext = markp;
8254 popstackmark(struct stackmark *mark)
8256 struct stack_block *sp;
8259 markp = mark->marknext;
8260 while (stackp != mark->stackp) {
8265 stacknxt = mark->stacknxt;
8266 stacknleft = mark->stacknleft;
8267 sstrend = mark->stacknxt + mark->stacknleft;
8273 * When the parser reads in a string, it wants to stick the string on the
8274 * stack and only adjust the stack pointer when it knows how big the
8275 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8276 * of space on top of the stack and stackblocklen returns the length of
8277 * this block. Growstackblock will grow this space by at least one byte,
8278 * possibly moving it (like realloc). Grabstackblock actually allocates the
8279 * part of the block that has been used.
8283 growstackblock(void)
8287 newlen = stacknleft * 2;
8288 if (newlen < stacknleft)
8289 error(bb_msg_memory_exhausted);
8293 if (stacknxt == stackp->space && stackp != &stackbase) {
8294 struct stack_block *oldstackp;
8295 struct stackmark *xmark;
8296 struct stack_block *sp;
8297 struct stack_block *prevstackp;
8303 prevstackp = sp->prev;
8304 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
8305 sp = ckrealloc((pointer)sp, grosslen);
8306 sp->prev = prevstackp;
8308 stacknxt = sp->space;
8309 stacknleft = newlen;
8310 sstrend = sp->space + newlen;
8313 * Stack marks pointing to the start of the old block
8314 * must be relocated to point to the new block
8317 while (xmark != NULL && xmark->stackp == oldstackp) {
8318 xmark->stackp = stackp;
8319 xmark->stacknxt = stacknxt;
8320 xmark->stacknleft = stacknleft;
8321 xmark = xmark->marknext;
8325 char *oldspace = stacknxt;
8326 int oldlen = stacknleft;
8327 char *p = stalloc(newlen);
8329 /* free the space we just allocated */
8330 stacknxt = memcpy(p, oldspace, oldlen);
8331 stacknleft += newlen;
8336 grabstackblock(size_t len)
8338 len = SHELL_ALIGN(len);
8344 * The following routines are somewhat easier to use than the above.
8345 * The user declares a variable of type STACKSTR, which may be declared
8346 * to be a register. The macro STARTSTACKSTR initializes things. Then
8347 * the user uses the macro STPUTC to add characters to the string. In
8348 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8349 * grown as necessary. When the user is done, she can just leave the
8350 * string there and refer to it using stackblock(). Or she can allocate
8351 * the space for it using grabstackstr(). If it is necessary to allow
8352 * someone else to use the stack temporarily and then continue to grow
8353 * the string, the user should use grabstack to allocate the space, and
8354 * then call ungrabstr(p) to return to the previous mode of operation.
8356 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8357 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8358 * is space for at least one character.
8364 size_t len = stackblocksize();
8365 if (herefd >= 0 && len >= 1024) {
8366 xwrite(herefd, stackblock(), len);
8367 return stackblock();
8370 return stackblock() + len;
8374 * Called from CHECKSTRSPACE.
8378 makestrspace(size_t newlen, char *p)
8380 size_t len = p - stacknxt;
8381 size_t size = stackblocksize();
8386 size = stackblocksize();
8388 if (nleft >= newlen)
8392 return stackblock() + len;
8396 stnputs(const char *s, size_t n, char *p)
8398 p = makestrspace(n, p);
8399 p = mempcpy(p, s, n);
8404 stputs(const char *s, char *p)
8406 return stnputs(s, strlen(s), p);
8409 /* $NetBSD: mystring.c,v 1.15 2002/11/24 22:35:42 christos Exp $ */
8414 * number(s) Convert a string of digits to an integer.
8415 * is_number(s) Return true if s is a string of digits.
8419 * prefix -- see if pfx is a prefix of string.
8423 prefix(const char *string, const char *pfx)
8426 if (*pfx++ != *string++)
8429 return (char *) string;
8434 * Convert a string of digits to an integer, printing an error message on
8439 number(const char *s)
8449 * Check for a valid number. This should be elsewhere.
8453 is_number(const char *p)
8458 } while (*++p != '\0');
8464 * Produce a possibly single quoted string suitable as input to the shell.
8465 * The return string is allocated on the stack.
8469 single_quote(const char *s) {
8478 len = strchrnul(s, '\'') - s;
8480 q = p = makestrspace(len + 3, p);
8483 q = mempcpy(q, s, len);
8489 len = strspn(s, "'");
8493 q = p = makestrspace(len + 3, p);
8496 q = mempcpy(q, s, len);
8505 return stackblock();
8509 * Like strdup but works with the ash stack.
8513 sstrdup(const char *p)
8515 size_t len = strlen(p) + 1;
8516 return memcpy(stalloc(len), p, len);
8521 calcsize(union node *n)
8525 funcblocksize += nodesize[n->type];
8528 calcsize(n->ncmd.redirect);
8529 calcsize(n->ncmd.args);
8530 calcsize(n->ncmd.assign);
8533 sizenodelist(n->npipe.cmdlist);
8538 calcsize(n->nredir.redirect);
8539 calcsize(n->nredir.n);
8546 calcsize(n->nbinary.ch2);
8547 calcsize(n->nbinary.ch1);
8550 calcsize(n->nif.elsepart);
8551 calcsize(n->nif.ifpart);
8552 calcsize(n->nif.test);
8555 funcstringsize += strlen(n->nfor.var) + 1;
8556 calcsize(n->nfor.body);
8557 calcsize(n->nfor.args);
8560 calcsize(n->ncase.cases);
8561 calcsize(n->ncase.expr);
8564 calcsize(n->nclist.body);
8565 calcsize(n->nclist.pattern);
8566 calcsize(n->nclist.next);
8570 sizenodelist(n->narg.backquote);
8571 funcstringsize += strlen(n->narg.text) + 1;
8572 calcsize(n->narg.next);
8579 calcsize(n->nfile.fname);
8580 calcsize(n->nfile.next);
8584 calcsize(n->ndup.vname);
8585 calcsize(n->ndup.next);
8589 calcsize(n->nhere.doc);
8590 calcsize(n->nhere.next);
8593 calcsize(n->nnot.com);
8600 sizenodelist(struct nodelist *lp)
8603 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8611 copynode(union node *n)
8618 funcblock = (char *) funcblock + nodesize[n->type];
8621 new->ncmd.redirect = copynode(n->ncmd.redirect);
8622 new->ncmd.args = copynode(n->ncmd.args);
8623 new->ncmd.assign = copynode(n->ncmd.assign);
8626 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8627 new->npipe.backgnd = n->npipe.backgnd;
8632 new->nredir.redirect = copynode(n->nredir.redirect);
8633 new->nredir.n = copynode(n->nredir.n);
8640 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8641 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8644 new->nif.elsepart = copynode(n->nif.elsepart);
8645 new->nif.ifpart = copynode(n->nif.ifpart);
8646 new->nif.test = copynode(n->nif.test);
8649 new->nfor.var = nodesavestr(n->nfor.var);
8650 new->nfor.body = copynode(n->nfor.body);
8651 new->nfor.args = copynode(n->nfor.args);
8654 new->ncase.cases = copynode(n->ncase.cases);
8655 new->ncase.expr = copynode(n->ncase.expr);
8658 new->nclist.body = copynode(n->nclist.body);
8659 new->nclist.pattern = copynode(n->nclist.pattern);
8660 new->nclist.next = copynode(n->nclist.next);
8664 new->narg.backquote = copynodelist(n->narg.backquote);
8665 new->narg.text = nodesavestr(n->narg.text);
8666 new->narg.next = copynode(n->narg.next);
8673 new->nfile.fname = copynode(n->nfile.fname);
8674 new->nfile.fd = n->nfile.fd;
8675 new->nfile.next = copynode(n->nfile.next);
8679 new->ndup.vname = copynode(n->ndup.vname);
8680 new->ndup.dupfd = n->ndup.dupfd;
8681 new->ndup.fd = n->ndup.fd;
8682 new->ndup.next = copynode(n->ndup.next);
8686 new->nhere.doc = copynode(n->nhere.doc);
8687 new->nhere.fd = n->nhere.fd;
8688 new->nhere.next = copynode(n->nhere.next);
8691 new->nnot.com = copynode(n->nnot.com);
8694 new->type = n->type;
8699 static struct nodelist *
8700 copynodelist(struct nodelist *lp)
8702 struct nodelist *start;
8703 struct nodelist **lpp;
8708 funcblock = (char *) funcblock +
8709 SHELL_ALIGN(sizeof(struct nodelist));
8710 (*lpp)->n = copynode(lp->n);
8712 lpp = &(*lpp)->next;
8720 nodesavestr(char *s)
8722 char *rtn = funcstring;
8724 funcstring = stpcpy(funcstring, s) + 1;
8730 * Free a parse tree.
8734 freefunc(struct funcnode *f)
8736 if (f && --f->count < 0)
8741 static void options(int);
8742 static void setoption(int, int);
8746 * Process the shell command line arguments.
8750 procargs(int argc, char **argv)
8753 const char *xminusc;
8760 for (i = 0; i < NOPTS; i++)
8766 if (*xargv == NULL) {
8768 error("-c requires an argument");
8771 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8775 for (i = 0; i < NOPTS; i++)
8776 if (optlist[i] == 2)
8781 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8786 } else if (!sflag) {
8787 setinputfile(*xargv, 0);
8793 shellparam.p = xargv;
8794 #ifdef CONFIG_ASH_GETOPTS
8795 shellparam.optind = 1;
8796 shellparam.optoff = -1;
8798 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
8800 shellparam.nparam++;
8813 setinteractive(iflag);
8818 minus_o(char *name, int val)
8823 out1str("Current option settings\n");
8824 for (i = 0; i < NOPTS; i++)
8825 out1fmt("%-16s%s\n", optnames(i),
8826 optlist[i] ? "on" : "off");
8828 for (i = 0; i < NOPTS; i++)
8829 if (equal(name, optnames(i))) {
8833 error("Illegal option -o %s", name);
8838 * Process shell options. The global variable argptr contains a pointer
8839 * to the argument list; we advance it past the options.
8843 options(int cmdline)
8851 while ((p = *argptr) != NULL) {
8853 if ((c = *p++) == '-') {
8855 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8857 /* "-" means turn off -x and -v */
8860 /* "--" means reset params */
8861 else if (*argptr == NULL)
8864 break; /* "-" or "--" terminates options */
8866 } else if (c == '+') {
8872 while ((c = *p++) != '\0') {
8873 if (c == 'c' && cmdline) {
8874 minusc = p; /* command is after shell args*/
8875 } else if (c == 'o') {
8876 minus_o(*argptr, val);
8879 } else if (cmdline && (c == '-')) { // long options
8880 if (strcmp(p, "login") == 0)
8892 setoption(int flag, int val)
8896 for (i = 0; i < NOPTS; i++)
8897 if (optletters(i) == flag) {
8901 error("Illegal option -%c", flag);
8908 * Set the shell parameters.
8912 setparam(char **argv)
8918 for (nparam = 0 ; argv[nparam] ; nparam++);
8919 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
8921 *ap++ = savestr(*argv++);
8924 freeparam(&shellparam);
8925 shellparam.malloc = 1;
8926 shellparam.nparam = nparam;
8927 shellparam.p = newparam;
8928 #ifdef CONFIG_ASH_GETOPTS
8929 shellparam.optind = 1;
8930 shellparam.optoff = -1;
8936 * Free the list of positional parameters.
8940 freeparam(volatile struct shparam *param)
8944 if (param->malloc) {
8945 for (ap = param->p ; *ap ; ap++)
8954 * The shift builtin command.
8958 shiftcmd(int argc, char **argv)
8965 n = number(argv[1]);
8966 if (n > shellparam.nparam)
8967 error("can't shift that many");
8969 shellparam.nparam -= n;
8970 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
8971 if (shellparam.malloc)
8975 while ((*ap2++ = *ap1++) != NULL);
8976 #ifdef CONFIG_ASH_GETOPTS
8977 shellparam.optind = 1;
8978 shellparam.optoff = -1;
8987 * The set command builtin.
8991 setcmd(int argc, char **argv)
8994 return showvars(nullstr, 0, VUNSET);
8998 if (*argptr != NULL) {
9006 #ifdef CONFIG_ASH_GETOPTS
9011 shellparam.optind = number(value);
9012 shellparam.optoff = -1;
9016 #ifdef CONFIG_LOCALE_SUPPORT
9017 static void change_lc_all(const char *value)
9019 if (value != 0 && *value != 0)
9020 setlocale(LC_ALL, value);
9023 static void change_lc_ctype(const char *value)
9025 if (value != 0 && *value != 0)
9026 setlocale(LC_CTYPE, value);
9031 #ifdef CONFIG_ASH_GETOPTS
9033 getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
9040 char **optnext = optfirst + *param_optind - 1;
9042 if (*param_optind <= 1 || *optoff < 0 || !(*(optnext - 1)) ||
9043 strlen(*(optnext - 1)) < *optoff)
9046 p = *(optnext - 1) + *optoff;
9047 if (p == NULL || *p == '\0') {
9048 /* Current word is done, advance */
9049 if (optnext == NULL)
9052 if (p == NULL || *p != '-' || *++p == '\0') {
9059 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
9064 for (q = optstr; *q != c; ) {
9066 if (optstr[0] == ':') {
9069 err |= setvarsafe("OPTARG", s, 0);
9071 fprintf(stderr, "Illegal option -%c\n", c);
9072 (void) unsetvar("OPTARG");
9082 if (*p == '\0' && (p = *optnext) == NULL) {
9083 if (optstr[0] == ':') {
9086 err |= setvarsafe("OPTARG", s, 0);
9089 fprintf(stderr, "No arg for -%c option\n", c);
9090 (void) unsetvar("OPTARG");
9098 err |= setvarsafe("OPTARG", p, 0);
9101 err |= setvarsafe("OPTARG", nullstr, 0);
9104 *optoff = p ? p - *(optnext - 1) : -1;
9105 *param_optind = optnext - optfirst + 1;
9106 fmtstr(s, sizeof(s), "%d", *param_optind);
9107 err |= setvarsafe("OPTIND", s, VNOFUNC);
9110 err |= setvarsafe(optvar, s, 0);
9121 * The getopts builtin. Shellparam.optnext points to the next argument
9122 * to be processed. Shellparam.optptr points to the next character to
9123 * be processed in the current argument. If shellparam.optnext is NULL,
9124 * then it's the first time getopts has been called.
9128 getoptscmd(int argc, char **argv)
9133 error("Usage: getopts optstring var [arg]");
9134 else if (argc == 3) {
9135 optbase = shellparam.p;
9136 if (shellparam.optind > shellparam.nparam + 1) {
9137 shellparam.optind = 1;
9138 shellparam.optoff = -1;
9143 if (shellparam.optind > argc - 2) {
9144 shellparam.optind = 1;
9145 shellparam.optoff = -1;
9149 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9150 &shellparam.optoff);
9152 #endif /* CONFIG_ASH_GETOPTS */
9155 * XXX - should get rid of. have all builtins use getopt(3). the
9156 * library getopt must have the BSD extension static variable "optreset"
9157 * otherwise it can't be used within the shell safely.
9159 * Standard option processing (a la getopt) for builtin routines. The
9160 * only argument that is passed to nextopt is the option string; the
9161 * other arguments are unnecessary. It return the character, or '\0' on
9166 nextopt(const char *optstring)
9172 if ((p = optptr) == NULL || *p == '\0') {
9174 if (p == NULL || *p != '-' || *++p == '\0')
9177 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
9181 for (q = optstring ; *q != c ; ) {
9183 error("Illegal option -%c", c);
9188 if (*p == '\0' && (p = *argptr++) == NULL)
9189 error("No arg for -%c option", c);
9198 /* $NetBSD: output.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
9201 outstr(const char *p, FILE *file)
9218 flushout(FILE *dest)
9226 outcslow(int c, FILE *dest)
9236 out1fmt(const char *fmt, ...)
9243 r = vprintf(fmt, ap);
9251 fmtstr(char *outbuf, size_t length, const char *fmt, ...)
9258 ret = vsnprintf(outbuf, length, fmt, ap);
9266 * Version of write which resumes after a signal is caught.
9270 xwrite(int fd, const void *p, size_t n)
9275 i = bb_full_write(fd, p, n);
9276 } while (i < 0 && errno == EINTR);
9280 /* $NetBSD: parser.c,v 1.54 2002/11/24 22:35:42 christos Exp $ */
9284 * Shell command parser.
9287 #define EOFMARKLEN 79
9291 struct heredoc *next; /* next here document in list */
9292 union node *here; /* redirection node */
9293 char *eofmark; /* string indicating end of input */
9294 int striptabs; /* if set, strip leading tabs */
9299 static struct heredoc *heredoclist; /* list of here documents to read */
9302 static union node *list(int);
9303 static union node *andor(void);
9304 static union node *pipeline(void);
9305 static union node *command(void);
9306 static union node *simplecmd(void);
9307 static union node *makename(void);
9308 static void parsefname(void);
9309 static void parseheredoc(void);
9310 static char peektoken(void);
9311 static int readtoken(void);
9312 static int xxreadtoken(void);
9313 static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
9314 static int noexpand(char *);
9315 static void synexpect(int) __attribute__((__noreturn__));
9316 static void synerror(const char *) __attribute__((__noreturn__));
9317 static void setprompt(int);
9321 goodname(const char *p)
9323 return !*endofname(p);
9327 isassignment(const char *p)
9329 const char *q = endofname(p);
9337 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9338 * valid parse tree indicating a blank line.)
9342 parsecmd(int interact)
9347 doprompt = interact;
9349 setprompt(doprompt);
9364 union node *n1, *n2, *n3;
9367 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9368 if (nlflag == 2 && peektoken())
9374 if (tok == TBACKGND) {
9375 if (n2->type == NPIPE) {
9376 n2->npipe.backgnd = 1;
9378 if (n2->type != NREDIR) {
9379 n3 = stalloc(sizeof(struct nredir));
9381 n3->nredir.redirect = NULL;
9384 n2->type = NBACKGND;
9391 n3 = (union node *)stalloc(sizeof (struct nbinary));
9393 n3->nbinary.ch1 = n1;
9394 n3->nbinary.ch2 = n2;
9410 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9418 pungetc(); /* push back EOF on input */
9434 union node *n1, *n2, *n3;
9439 if ((t = readtoken()) == TAND) {
9441 } else if (t == TOR) {
9447 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9449 n3 = (union node *)stalloc(sizeof (struct nbinary));
9451 n3->nbinary.ch1 = n1;
9452 n3->nbinary.ch2 = n2;
9462 union node *n1, *n2, *pipenode;
9463 struct nodelist *lp, *prev;
9467 TRACE(("pipeline: entered\n"));
9468 if (readtoken() == TNOT) {
9470 checkkwd = CHKKWD | CHKALIAS;
9474 if (readtoken() == TPIPE) {
9475 pipenode = (union node *)stalloc(sizeof (struct npipe));
9476 pipenode->type = NPIPE;
9477 pipenode->npipe.backgnd = 0;
9478 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9479 pipenode->npipe.cmdlist = lp;
9483 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9484 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9487 } while (readtoken() == TPIPE);
9493 n2 = (union node *)stalloc(sizeof (struct nnot));
9506 union node *n1, *n2;
9507 union node *ap, **app;
9508 union node *cp, **cpp;
9509 union node *redir, **rpp;
9516 switch (readtoken()) {
9521 n1 = (union node *)stalloc(sizeof (struct nif));
9523 n1->nif.test = list(0);
9524 if (readtoken() != TTHEN)
9526 n1->nif.ifpart = list(0);
9528 while (readtoken() == TELIF) {
9529 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
9530 n2 = n2->nif.elsepart;
9532 n2->nif.test = list(0);
9533 if (readtoken() != TTHEN)
9535 n2->nif.ifpart = list(0);
9537 if (lasttoken == TELSE)
9538 n2->nif.elsepart = list(0);
9540 n2->nif.elsepart = NULL;
9548 n1 = (union node *)stalloc(sizeof (struct nbinary));
9549 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
9550 n1->nbinary.ch1 = list(0);
9551 if ((got=readtoken()) != TDO) {
9552 TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
9555 n1->nbinary.ch2 = list(0);
9560 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9561 synerror("Bad for loop variable");
9562 n1 = (union node *)stalloc(sizeof (struct nfor));
9564 n1->nfor.var = wordtext;
9565 checkkwd = CHKKWD | CHKALIAS;
9566 if (readtoken() == TIN) {
9568 while (readtoken() == TWORD) {
9569 n2 = (union node *)stalloc(sizeof (struct narg));
9571 n2->narg.text = wordtext;
9572 n2->narg.backquote = backquotelist;
9574 app = &n2->narg.next;
9578 if (lasttoken != TNL && lasttoken != TSEMI)
9581 n2 = (union node *)stalloc(sizeof (struct narg));
9583 n2->narg.text = (char *)dolatstr;
9584 n2->narg.backquote = NULL;
9585 n2->narg.next = NULL;
9588 * Newline or semicolon here is optional (but note
9589 * that the original Bourne shell only allowed NL).
9591 if (lasttoken != TNL && lasttoken != TSEMI)
9594 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9595 if (readtoken() != TDO)
9597 n1->nfor.body = list(0);
9601 n1 = (union node *)stalloc(sizeof (struct ncase));
9603 if (readtoken() != TWORD)
9605 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
9607 n2->narg.text = wordtext;
9608 n2->narg.backquote = backquotelist;
9609 n2->narg.next = NULL;
9611 checkkwd = CHKKWD | CHKALIAS;
9612 } while (readtoken() == TNL);
9613 if (lasttoken != TIN)
9615 cpp = &n1->ncase.cases;
9617 checkkwd = CHKNL | CHKKWD;
9620 if (lasttoken == TLP)
9622 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
9624 app = &cp->nclist.pattern;
9626 *app = ap = (union node *)stalloc(sizeof (struct narg));
9628 ap->narg.text = wordtext;
9629 ap->narg.backquote = backquotelist;
9630 if (readtoken() != TPIPE)
9632 app = &ap->narg.next;
9635 ap->narg.next = NULL;
9636 if (lasttoken != TRP)
9638 cp->nclist.body = list(2);
9640 cpp = &cp->nclist.next;
9642 checkkwd = CHKNL | CHKKWD;
9643 if ((t = readtoken()) != TESAC) {
9645 synexpect(TENDCASE);
9653 n1 = (union node *)stalloc(sizeof (struct nredir));
9654 n1->type = NSUBSHELL;
9655 n1->nredir.n = list(0);
9656 n1->nredir.redirect = NULL;
9669 if (readtoken() != t)
9673 /* Now check for redirection which may follow command */
9674 checkkwd = CHKKWD | CHKALIAS;
9676 while (readtoken() == TREDIR) {
9677 *rpp = n2 = redirnode;
9678 rpp = &n2->nfile.next;
9684 if (n1->type != NSUBSHELL) {
9685 n2 = (union node *)stalloc(sizeof (struct nredir));
9690 n1->nredir.redirect = redir;
9699 union node *args, **app;
9700 union node *n = NULL;
9701 union node *vars, **vpp;
9702 union node **rpp, *redir;
9712 savecheckkwd = CHKALIAS;
9714 checkkwd = savecheckkwd;
9715 switch (readtoken()) {
9717 n = (union node *)stalloc(sizeof (struct narg));
9719 n->narg.text = wordtext;
9720 n->narg.backquote = backquotelist;
9721 if (savecheckkwd && isassignment(wordtext)) {
9723 vpp = &n->narg.next;
9726 app = &n->narg.next;
9731 *rpp = n = redirnode;
9732 rpp = &n->nfile.next;
9733 parsefname(); /* read name of redirection file */
9737 args && app == &args->narg.next &&
9740 struct builtincmd *bcmd;
9743 /* We have a function */
9744 if (readtoken() != TRP)
9746 name = n->narg.text;
9748 !goodname(name) || (
9749 (bcmd = find_builtin(name)) &&
9750 IS_BUILTIN_SPECIAL(bcmd)
9753 synerror("Bad function name");
9755 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9756 n->narg.next = command();
9769 n = (union node *)stalloc(sizeof (struct ncmd));
9771 n->ncmd.args = args;
9772 n->ncmd.assign = vars;
9773 n->ncmd.redirect = redir;
9782 n = (union node *)stalloc(sizeof (struct narg));
9784 n->narg.next = NULL;
9785 n->narg.text = wordtext;
9786 n->narg.backquote = backquotelist;
9790 void fixredir(union node *n, const char *text, int err)
9792 TRACE(("Fix redir %s %d\n", text, err));
9794 n->ndup.vname = NULL;
9796 if (is_digit(text[0]) && text[1] == '\0')
9797 n->ndup.dupfd = digit_val(text[0]);
9798 else if (text[0] == '-' && text[1] == '\0')
9803 synerror("Bad fd number");
9805 n->ndup.vname = makename();
9813 union node *n = redirnode;
9815 if (readtoken() != TWORD)
9817 if (n->type == NHERE) {
9818 struct heredoc *here = heredoc;
9824 TRACE(("Here document %d\n", n->type));
9825 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
9826 synerror("Illegal eof marker for << redirection");
9827 rmescapes(wordtext);
9828 here->eofmark = wordtext;
9830 if (heredoclist == NULL)
9833 for (p = heredoclist ; p->next ; p = p->next);
9836 } else if (n->type == NTOFD || n->type == NFROMFD) {
9837 fixredir(n, wordtext, 0);
9839 n->nfile.fname = makename();
9845 * Input any here documents.
9851 struct heredoc *here;
9862 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9863 here->eofmark, here->striptabs);
9864 n = (union node *)stalloc(sizeof (struct narg));
9865 n->narg.type = NARG;
9866 n->narg.next = NULL;
9867 n->narg.text = wordtext;
9868 n->narg.backquote = backquotelist;
9869 here->here->nhere.doc = n;
9874 static char peektoken(void)
9880 return tokname_array[t][0];
9888 int alreadyseen = tokpushback;
9891 #ifdef CONFIG_ASH_ALIAS
9900 if (checkkwd & CHKNL) {
9907 if (t != TWORD || quoteflag) {
9912 * check for keywords
9914 if (checkkwd & CHKKWD) {
9915 const char *const *pp;
9917 if ((pp = findkwd(wordtext))) {
9918 lasttoken = t = pp - tokname_array;
9919 TRACE(("keyword %s recognized\n", tokname(t)));
9924 if (checkkwd & CHKALIAS) {
9925 #ifdef CONFIG_ASH_ALIAS
9927 if ((ap = lookupalias(wordtext, 1)) != NULL) {
9929 pushstring(ap->val, ap);
9939 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
9941 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
9948 * Read the next input token.
9949 * If the token is a word, we set backquotelist to the list of cmds in
9950 * backquotes. We set quoteflag to true if any part of the word was
9952 * If the token is TREDIR, then we set redirnode to a structure containing
9954 * In all cases, the variable startlinno is set to the number of the line
9955 * on which the token starts.
9957 * [Change comment: here documents and internal procedures]
9958 * [Readtoken shouldn't have any arguments. Perhaps we should make the
9959 * word parsing code into a separate routine. In this case, readtoken
9960 * doesn't need to have any internal procedures, but parseword does.
9961 * We could also make parseoperator in essence the main routine, and
9962 * have parseword (readtoken1?) handle both words and redirection.]
9965 #define NEW_xxreadtoken
9966 #ifdef NEW_xxreadtoken
9968 /* singles must be first! */
9969 static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
9971 static const char xxreadtoken_tokens[] = {
9972 TNL, TLP, TRP, /* only single occurrence allowed */
9973 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
9974 TEOF, /* corresponds to trailing nul */
9975 TAND, TOR, TENDCASE, /* if double occurrence */
9978 #define xxreadtoken_doubles \
9979 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
9980 #define xxreadtoken_singles \
9981 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
9983 static int xxreadtoken()
9995 startlinno = plinno;
9996 for (;;) { /* until token or start of word found */
9999 if ((c != ' ') && (c != '\t')
10000 #ifdef CONFIG_ASH_ALIAS
10005 while ((c = pgetc()) != '\n' && c != PEOF);
10007 } else if (c == '\\') {
10008 if (pgetc() != '\n') {
10012 startlinno = ++plinno;
10017 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10022 needprompt = doprompt;
10025 p = strchr(xxreadtoken_chars, c);
10028 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
10031 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
10032 if (pgetc() == *p) { /* double occurrence? */
10033 p += xxreadtoken_doubles + 1;
10040 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
10048 #define RETURN(token) return lasttoken = token
10063 startlinno = plinno;
10064 for (;;) { /* until token or start of word found */
10067 case ' ': case '\t':
10068 #ifdef CONFIG_ASH_ALIAS
10073 while ((c = pgetc()) != '\n' && c != PEOF);
10077 if (pgetc() == '\n') {
10078 startlinno = ++plinno;
10087 needprompt = doprompt;
10092 if (pgetc() == '&')
10097 if (pgetc() == '|')
10102 if (pgetc() == ';')
10115 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10118 #endif /* NEW_xxreadtoken */
10122 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10123 * is not NULL, read a here document. In the latter case, eofmark is the
10124 * word which marks the end of the document and striptabs is true if
10125 * leading tabs should be stripped from the document. The argument firstc
10126 * is the first character of the input token or document.
10128 * Because C does not have internal subroutines, I have simulated them
10129 * using goto's to implement the subroutine linkage. The following macros
10130 * will run code that appears at the end of readtoken1.
10133 #define CHECKEND() {goto checkend; checkend_return:;}
10134 #define PARSEREDIR() {goto parseredir; parseredir_return:;}
10135 #define PARSESUB() {goto parsesub; parsesub_return:;}
10136 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10137 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10138 #define PARSEARITH() {goto parsearith; parsearith_return:;}
10141 readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
10146 char line[EOFMARKLEN + 1];
10147 struct nodelist *bqlist;
10150 int varnest; /* levels of variables expansion */
10151 int arinest; /* levels of arithmetic expansion */
10152 int parenlevel; /* levels of parens in arithmetic */
10153 int dqvarnest; /* levels of variables expansion within double quotes */
10155 int prevsyntax; /* syntax before arithmetic */
10157 /* Avoid longjmp clobbering */
10163 (void) &parenlevel;
10166 (void) &prevsyntax;
10170 startlinno = plinno;
10172 if (syntax == DQSYNTAX)
10181 STARTSTACKSTR(out);
10182 loop: { /* for each line, until end of word */
10183 CHECKEND(); /* set c to PEOF if at end of here document */
10184 for (;;) { /* until end of line or end of word */
10185 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10186 switch(SIT(c, syntax)) {
10187 case CNL: /* '\n' */
10188 if (syntax == BASESYNTAX)
10189 goto endword; /* exit outer loop */
10195 goto loop; /* continue outer loop */
10200 if (eofmark == NULL || dblquote)
10201 USTPUTC(CTLESC, out);
10204 case CBACK: /* backslash */
10207 USTPUTC(CTLESC, out);
10208 USTPUTC('\\', out);
10210 } else if (c == '\n') {
10216 c != '\\' && c != '`' &&
10222 USTPUTC(CTLESC, out);
10223 USTPUTC('\\', out);
10225 if (SIT(c, SQSYNTAX) == CCTL)
10226 USTPUTC(CTLESC, out);
10234 if (eofmark == NULL) {
10235 USTPUTC(CTLQUOTEMARK, out);
10243 if (eofmark != NULL && arinest == 0 &&
10247 if (dqvarnest == 0) {
10248 syntax = BASESYNTAX;
10255 case CVAR: /* '$' */
10256 PARSESUB(); /* parse substitution */
10258 case CENDVAR: /* '}' */
10261 if (dqvarnest > 0) {
10264 USTPUTC(CTLENDVAR, out);
10269 #ifdef CONFIG_ASH_MATH_SUPPORT
10270 case CLP: /* '(' in arithmetic */
10274 case CRP: /* ')' in arithmetic */
10275 if (parenlevel > 0) {
10279 if (pgetc() == ')') {
10280 if (--arinest == 0) {
10281 USTPUTC(CTLENDARI, out);
10282 syntax = prevsyntax;
10283 if (syntax == DQSYNTAX)
10291 * unbalanced parens
10292 * (don't 2nd guess - no error)
10300 case CBQUOTE: /* '`' */
10304 goto endword; /* exit outer loop */
10309 goto endword; /* exit outer loop */
10310 #ifdef CONFIG_ASH_ALIAS
10320 #ifdef CONFIG_ASH_MATH_SUPPORT
10321 if (syntax == ARISYNTAX)
10322 synerror("Missing '))'");
10324 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10325 synerror("Unterminated quoted string");
10326 if (varnest != 0) {
10327 startlinno = plinno;
10329 synerror("Missing '}'");
10331 USTPUTC('\0', out);
10332 len = out - (char *)stackblock();
10333 out = stackblock();
10334 if (eofmark == NULL) {
10335 if ((c == '>' || c == '<')
10338 && (*out == '\0' || is_digit(*out))) {
10340 return lasttoken = TREDIR;
10345 quoteflag = quotef;
10346 backquotelist = bqlist;
10347 grabstackblock(len);
10349 return lasttoken = TWORD;
10350 /* end of readtoken routine */
10355 * Check to see whether we are at the end of the here document. When this
10356 * is called, c is set to the first character of the next input line. If
10357 * we are at the end of the here document, this routine sets the c to PEOF.
10362 #ifdef CONFIG_ASH_ALIAS
10368 while (c == '\t') {
10372 if (c == *eofmark) {
10373 if (pfgets(line, sizeof line) != NULL) {
10377 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10378 if (*p == '\n' && *q == '\0') {
10381 needprompt = doprompt;
10383 pushstring(line, NULL);
10388 goto checkend_return;
10393 * Parse a redirection operator. The variable "out" points to a string
10394 * specifying the fd to be redirected. The variable "c" contains the
10395 * first character of the redirection operator.
10402 np = (union node *)stalloc(sizeof (struct nfile));
10407 np->type = NAPPEND;
10409 np->type = NCLOBBER;
10416 } else { /* c == '<' */
10418 switch (c = pgetc()) {
10420 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10421 np = (union node *)stalloc(sizeof (struct nhere));
10425 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10426 heredoc->here = np;
10427 if ((c = pgetc()) == '-') {
10428 heredoc->striptabs = 1;
10430 heredoc->striptabs = 0;
10436 np->type = NFROMFD;
10440 np->type = NFROMTO;
10450 np->nfile.fd = digit_val(fd);
10452 goto parseredir_return;
10457 * Parse a substitution. At this point, we have read the dollar sign
10458 * and nothing else.
10466 static const char types[] = "}-+?=";
10470 c <= PEOA_OR_PEOF ||
10471 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10475 } else if (c == '(') { /* $(command) or $((arith)) */
10476 if (pgetc() == '(') {
10477 #ifdef CONFIG_ASH_MATH_SUPPORT
10480 synerror("We unsupport $((arith))");
10487 USTPUTC(CTLVAR, out);
10488 typeloc = out - (char *)stackblock();
10489 USTPUTC(VSNORMAL, out);
10490 subtype = VSNORMAL;
10494 if ((c = pgetc()) == '}')
10497 subtype = VSLENGTH;
10502 if (c > PEOA_OR_PEOF && is_name(c)) {
10506 } while (c > PEOA_OR_PEOF && is_in_name(c));
10507 } else if (is_digit(c)) {
10511 } while (is_digit(c));
10513 else if (is_special(c)) {
10518 badsub: synerror("Bad substitution");
10522 if (subtype == 0) {
10529 p = strchr(types, c);
10532 subtype = p - types + VSNORMAL;
10538 subtype = c == '#' ? VSTRIMLEFT :
10551 if (dblquote || arinest)
10553 *((char *)stackblock() + typeloc) = subtype | flags;
10554 if (subtype != VSNORMAL) {
10556 if (dblquote || arinest) {
10561 goto parsesub_return;
10566 * Called to parse command substitutions. Newstyle is set if the command
10567 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10568 * list of commands (passed by reference), and savelen is the number of
10569 * characters on the top of the stack which must be preserved.
10573 struct nodelist **nlpp;
10576 char *volatile str;
10577 struct jmploc jmploc;
10578 struct jmploc *volatile savehandler;
10582 (void) &saveprompt;
10585 savepbq = parsebackquote;
10586 if (setjmp(jmploc.loc)) {
10589 parsebackquote = 0;
10590 handler = savehandler;
10591 longjmp(handler->loc, 1);
10595 savelen = out - (char *)stackblock();
10597 str = ckmalloc(savelen);
10598 memcpy(str, stackblock(), savelen);
10600 savehandler = handler;
10604 /* We must read until the closing backquote, giving special
10605 treatment to some slashes, and then push the string and
10606 reread it as input, interpreting it normally. */
10613 STARTSTACKSTR(pout);
10619 switch (pc = pgetc()) {
10624 if ((pc = pgetc()) == '\n') {
10629 * If eating a newline, avoid putting
10630 * the newline into the new character
10631 * stream (via the STPUTC after the
10636 if (pc != '\\' && pc != '`' && pc != '$'
10637 && (!dblquote || pc != '"'))
10638 STPUTC('\\', pout);
10639 if (pc > PEOA_OR_PEOF) {
10645 #ifdef CONFIG_ASH_ALIAS
10648 startlinno = plinno;
10649 synerror("EOF in backquote substitution");
10653 needprompt = doprompt;
10662 STPUTC('\0', pout);
10663 psavelen = pout - (char *)stackblock();
10664 if (psavelen > 0) {
10665 pstr = grabstackstr(pout);
10666 setinputstring(pstr);
10671 nlpp = &(*nlpp)->next;
10672 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10673 (*nlpp)->next = NULL;
10674 parsebackquote = oldstyle;
10677 saveprompt = doprompt;
10684 doprompt = saveprompt;
10686 if (readtoken() != TRP)
10693 * Start reading from old file again, ignoring any pushed back
10694 * tokens left from the backquote parsing
10699 while (stackblocksize() <= savelen)
10701 STARTSTACKSTR(out);
10703 memcpy(out, str, savelen);
10704 STADJUST(savelen, out);
10710 parsebackquote = savepbq;
10711 handler = savehandler;
10712 if (arinest || dblquote)
10713 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10715 USTPUTC(CTLBACKQ, out);
10717 goto parsebackq_oldreturn;
10719 goto parsebackq_newreturn;
10722 #ifdef CONFIG_ASH_MATH_SUPPORT
10724 * Parse an arithmetic expansion (indicate start of one and set state)
10728 if (++arinest == 1) {
10729 prevsyntax = syntax;
10730 syntax = ARISYNTAX;
10731 USTPUTC(CTLARI, out);
10738 * we collapse embedded arithmetic expansion to
10739 * parenthesis, which should be equivalent
10743 goto parsearith_return;
10747 } /* end of readtoken */
10752 * Returns true if the text contains nothing to expand (no dollar signs
10757 noexpand(char *text)
10763 while ((c = *p++) != '\0') {
10764 if (c == CTLQUOTEMARK)
10768 else if (SIT(c, BASESYNTAX) == CCTL)
10776 * Return of a legal variable name (a letter or underscore followed by zero or
10777 * more letters, underscores, and digits).
10781 endofname(const char *name)
10789 if (! is_in_name(*p))
10797 * Called when an unexpected token is read during the parse. The argument
10798 * is the token that is expected, or -1 if more than one type of token can
10799 * occur at this point.
10802 static void synexpect(int token)
10807 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10809 sprintf(msg + l, " (expecting %s)", tokname(token));
10815 synerror(const char *msg)
10817 error("Syntax error: %s", msg);
10823 * called by editline -- any expansions to the prompt
10824 * should be added here.
10827 static void setprompt(int whichprompt)
10829 const char *prompt;
10831 switch (whichprompt) {
10845 static const char *const *findkwd(const char *s)
10847 return bsearch(s, tokname_array + KWDOFFSET,
10848 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
10849 sizeof(const char *), pstrcmp);
10852 /* $NetBSD: redir.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
10855 * Code for dealing with input/output redirection.
10858 #define EMPTY -2 /* marks an unused slot in redirtab */
10860 # define PIPESIZE 4096 /* amount of buffering in a pipe */
10862 # define PIPESIZE PIPE_BUF
10866 * Open a file in noclobber mode.
10867 * The code was copied from bash.
10870 noclobberopen(const char *fname)
10873 struct stat finfo, finfo2;
10876 * If the file exists and is a regular file, return an error
10879 r = stat(fname, &finfo);
10880 if (r == 0 && S_ISREG(finfo.st_mode)) {
10886 * If the file was not present (r != 0), make sure we open it
10887 * exclusively so that if it is created before we open it, our open
10888 * will fail. Make sure that we do not truncate an existing file.
10889 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10890 * file was not a regular file, we leave O_EXCL off.
10893 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10894 fd = open(fname, O_WRONLY|O_CREAT, 0666);
10896 /* If the open failed, return the file descriptor right away. */
10901 * OK, the open succeeded, but the file may have been changed from a
10902 * non-regular file to a regular file between the stat and the open.
10903 * We are assuming that the O_EXCL open handles the case where FILENAME
10904 * did not exist and is symlinked to an existing file between the stat
10909 * If we can open it and fstat the file descriptor, and neither check
10910 * revealed that it was a regular file, and the file has not been
10911 * replaced, return the file descriptor.
10913 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10914 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
10917 /* The file has been replaced. badness. */
10924 * Handle here documents. Normally we fork off a process to write the
10925 * data to a pipe. If the document is short, we can stuff the data in
10926 * the pipe without forking.
10930 openhere(union node *redir)
10936 error("Pipe call failed");
10937 if (redir->type == NHERE) {
10938 len = strlen(redir->nhere.doc->narg.text);
10939 if (len <= PIPESIZE) {
10940 xwrite(pip[1], redir->nhere.doc->narg.text, len);
10944 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
10946 signal(SIGINT, SIG_IGN);
10947 signal(SIGQUIT, SIG_IGN);
10948 signal(SIGHUP, SIG_IGN);
10950 signal(SIGTSTP, SIG_IGN);
10952 signal(SIGPIPE, SIG_DFL);
10953 if (redir->type == NHERE)
10954 xwrite(pip[1], redir->nhere.doc->narg.text, len);
10956 expandhere(redir->nhere.doc, pip[1]);
10965 openredirect(union node *redir)
10970 switch (redir->nfile.type) {
10972 fname = redir->nfile.expfname;
10973 if ((f = open(fname, O_RDONLY)) < 0)
10977 fname = redir->nfile.expfname;
10978 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
10982 /* Take care of noclobber mode. */
10984 fname = redir->nfile.expfname;
10985 if ((f = noclobberopen(fname)) < 0)
10991 fname = redir->nfile.expfname;
10992 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
10996 fname = redir->nfile.expfname;
10997 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
11004 /* Fall through to eliminate warning. */
11011 f = openhere(redir);
11017 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
11019 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11023 dupredirect(union node *redir, int f)
11025 int fd = redir->nfile.fd;
11027 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11028 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
11029 copyfd(redir->ndup.dupfd, fd);
11042 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11043 * old file descriptors are stashed away so that the redirection can be
11044 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11045 * standard output, and the standard error if it becomes a duplicate of
11046 * stdout, is saved in memory.
11050 redirect(union node *redir, int flags)
11053 struct redirtab *sv;
11064 if (flags & REDIR_PUSH) {
11065 struct redirtab *q;
11066 q = ckmalloc(sizeof (struct redirtab));
11067 q->next = redirlist;
11069 q->nullredirs = nullredirs - 1;
11070 for (i = 0 ; i < 10 ; i++)
11071 q->renamed[i] = EMPTY;
11078 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
11079 n->ndup.dupfd == fd)
11080 continue; /* redirect from/to same file descriptor */
11082 newfd = openredirect(n);
11085 if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
11086 i = fcntl(fd, F_DUPFD, 10);
11093 error("%d: %m", fd);
11103 dupredirect(n, newfd);
11104 } while ((n = n->nfile.next));
11106 if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
11107 preverrout_fd = sv->renamed[2];
11112 * Undo the effects of the last redirection.
11118 struct redirtab *rp;
11121 if (--nullredirs >= 0)
11125 for (i = 0 ; i < 10 ; i++) {
11126 if (rp->renamed[i] != EMPTY) {
11129 copyfd(rp->renamed[i], i);
11131 close(rp->renamed[i]);
11134 redirlist = rp->next;
11135 nullredirs = rp->nullredirs;
11141 * Undo all redirections. Called on error or interrupt.
11145 * Discard all saved file descriptors.
11149 clearredir(int drop)
11161 * Copy a file descriptor to be >= to. Returns -1
11162 * if the source file descriptor is closed, EMPTY if there are no unused
11163 * file descriptors left.
11167 copyfd(int from, int to)
11171 newfd = fcntl(from, F_DUPFD, to);
11173 if (errno == EMFILE)
11176 error("%d: %m", from);
11183 redirectsafe(union node *redir, int flags)
11186 volatile int saveint;
11187 struct jmploc *volatile savehandler = handler;
11188 struct jmploc jmploc;
11191 if (!(err = setjmp(jmploc.loc) * 2)) {
11193 redirect(redir, flags);
11195 handler = savehandler;
11196 if (err && exception != EXERROR)
11197 longjmp(handler->loc, 1);
11198 RESTOREINT(saveint);
11202 /* $NetBSD: show.c,v 1.24 2003/01/22 20:36:04 dsl Exp $ */
11205 static void shtree(union node *, int, char *, FILE*);
11206 static void shcmd(union node *, FILE *);
11207 static void sharg(union node *, FILE *);
11208 static void indent(int, char *, FILE *);
11209 static void trstring(char *);
11213 showtree(union node *n)
11215 trputs("showtree called\n");
11216 shtree(n, 1, NULL, stdout);
11221 shtree(union node *n, int ind, char *pfx, FILE *fp)
11223 struct nodelist *lp;
11229 indent(ind, pfx, fp);
11240 shtree(n->nbinary.ch1, ind, NULL, fp);
11243 shtree(n->nbinary.ch2, ind, NULL, fp);
11251 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
11256 if (n->npipe.backgnd)
11262 fprintf(fp, "<node type %d>", n->type);
11271 shcmd(union node *cmd, FILE *fp)
11279 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11285 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11288 switch (np->nfile.type) {
11289 case NTO: s = ">"; dftfd = 1; break;
11290 case NCLOBBER: s = ">|"; dftfd = 1; break;
11291 case NAPPEND: s = ">>"; dftfd = 1; break;
11292 case NTOFD: s = ">&"; dftfd = 1; break;
11293 case NFROM: s = "<"; dftfd = 0; break;
11294 case NFROMFD: s = "<&"; dftfd = 0; break;
11295 case NFROMTO: s = "<>"; dftfd = 0; break;
11296 default: s = "*error*"; dftfd = 0; break;
11298 if (np->nfile.fd != dftfd)
11299 fprintf(fp, "%d", np->nfile.fd);
11301 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11302 fprintf(fp, "%d", np->ndup.dupfd);
11304 sharg(np->nfile.fname, fp);
11313 sharg(union node *arg, FILE *fp)
11316 struct nodelist *bqlist;
11319 if (arg->type != NARG) {
11320 out1fmt("<node type %d>\n", arg->type);
11323 bqlist = arg->narg.backquote;
11324 for (p = arg->narg.text ; *p ; p++) {
11333 if (subtype == VSLENGTH)
11339 if (subtype & VSNUL)
11342 switch (subtype & VSTYPE) {
11361 case VSTRIMLEFTMAX:
11368 case VSTRIMRIGHTMAX:
11375 out1fmt("<subtype %d>", subtype);
11382 case CTLBACKQ|CTLQUOTE:
11385 shtree(bqlist->n, -1, NULL, fp);
11397 indent(int amount, char *pfx, FILE *fp)
11401 for (i = 0 ; i < amount ; i++) {
11402 if (pfx && i == amount - 1)
11423 putc(c, tracefile);
11427 trace(const char *fmt, ...)
11434 (void) vfprintf(tracefile, fmt, va);
11439 tracev(const char *fmt, va_list va)
11443 (void) vfprintf(tracefile, fmt, va);
11448 trputs(const char *s)
11452 fputs(s, tracefile);
11464 putc('"', tracefile);
11465 for (p = s ; *p ; p++) {
11467 case '\n': c = 'n'; goto backslash;
11468 case '\t': c = 't'; goto backslash;
11469 case '\r': c = 'r'; goto backslash;
11470 case '"': c = '"'; goto backslash;
11471 case '\\': c = '\\'; goto backslash;
11472 case CTLESC: c = 'e'; goto backslash;
11473 case CTLVAR: c = 'v'; goto backslash;
11474 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11475 case CTLBACKQ: c = 'q'; goto backslash;
11476 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
11477 backslash: putc('\\', tracefile);
11478 putc(c, tracefile);
11481 if (*p >= ' ' && *p <= '~')
11482 putc(*p, tracefile);
11484 putc('\\', tracefile);
11485 putc(*p >> 6 & 03, tracefile);
11486 putc(*p >> 3 & 07, tracefile);
11487 putc(*p & 07, tracefile);
11492 putc('"', tracefile);
11504 putc(' ', tracefile);
11506 putc('\n', tracefile);
11522 /* leave open because libedit might be using it */
11525 scopy("./trace", s);
11527 if (!freopen(s, "a", tracefile)) {
11528 fprintf(stderr, "Can't re-open %s\n", s);
11533 if ((tracefile = fopen(s, "a")) == NULL) {
11534 fprintf(stderr, "Can't open %s\n", s);
11540 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11541 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11543 setlinebuf(tracefile);
11544 fputs("\nTracing started.\n", tracefile);
11549 /* $NetBSD: trap.c,v 1.28 2002/11/24 22:35:43 christos Exp $ */
11552 * Sigmode records the current value of the signal handlers for the various
11553 * modes. A value of zero means that the current handler is not known.
11554 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
11557 #define S_DFL 1 /* default signal handling (SIG_DFL) */
11558 #define S_CATCH 2 /* signal is caught */
11559 #define S_IGN 3 /* signal is ignored (SIG_IGN) */
11560 #define S_HARD_IGN 4 /* signal is ignored permenantly */
11561 #define S_RESET 5 /* temporary - to reset a hard ignored sig */
11566 * The trap builtin.
11570 trapcmd(int argc, char **argv)
11579 for (signo = 0 ; signo < NSIG ; signo++) {
11580 if (trap[signo] != NULL) {
11583 sn = u_signal_names(0, &signo, 0);
11586 out1fmt("trap -- %s %s\n",
11587 single_quote(trap[signo]), sn);
11597 if ((signo = decode_signal(*ap, 0)) < 0)
11598 error("%s: bad trap", *ap);
11601 if (action[0] == '-' && action[1] == '\0')
11604 action = savestr(action);
11607 ckfree(trap[signo]);
11608 trap[signo] = action;
11619 * Clear traps on a fork.
11627 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
11628 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
11632 if (tp != &trap[0])
11633 setsignal(tp - trap);
11641 * Set the signal handler for the specified signal. The routine figures
11642 * out what it should be set to.
11646 setsignal(int signo)
11650 struct sigaction act;
11652 if ((t = trap[signo]) == NULL)
11654 else if (*t != '\0')
11658 if (rootshell && action == S_DFL) {
11661 if (iflag || minusc || sflag == 0)
11684 t = &sigmode[signo - 1];
11688 * current setting unknown
11690 if (sigaction(signo, 0, &act) == -1) {
11692 * Pretend it worked; maybe we should give a warning
11693 * here, but other shells don't. We don't alter
11694 * sigmode, so that we retry every time.
11698 if (act.sa_handler == SIG_IGN) {
11699 if (mflag && (signo == SIGTSTP ||
11700 signo == SIGTTIN || signo == SIGTTOU)) {
11701 tsig = S_IGN; /* don't hard ignore these */
11705 tsig = S_RESET; /* force to be set */
11708 if (tsig == S_HARD_IGN || tsig == action)
11712 act.sa_handler = onsig;
11715 act.sa_handler = SIG_IGN;
11718 act.sa_handler = SIG_DFL;
11722 sigfillset(&act.sa_mask);
11723 sigaction(signo, &act, 0);
11731 ignoresig(int signo)
11733 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11734 signal(signo, SIG_IGN);
11736 sigmode[signo - 1] = S_HARD_IGN;
11747 gotsig[signo - 1] = 1;
11748 pendingsigs = signo;
11750 if (exsig || (signo == SIGINT && !trap[SIGINT])) {
11759 * Called to execute a trap. Perhaps we should avoid entering new trap
11760 * handlers while we are executing a trap handler.
11770 savestatus = exitstatus;
11772 while (pendingsigs = 0, barrier(), (p = memchr(q, 1, NSIG - 1))) {
11774 p = trap[p - q + 1];
11778 exitstatus = savestatus;
11784 * Controls whether the shell is interactive or not.
11788 setinteractive(int on)
11790 static int is_interactive;
11792 if (++on == is_interactive)
11794 is_interactive = on;
11796 setsignal(SIGQUIT);
11797 setsignal(SIGTERM);
11798 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11799 if(is_interactive > 1) {
11800 /* Looks like they want an interactive shell */
11801 static int do_banner;
11805 "\n\n" BB_BANNER " Built-in shell (ash)\n"
11806 "Enter 'help' for a list of built-in commands.\n\n");
11814 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11815 /*** List the available builtins ***/
11817 static int helpcmd(int argc, char **argv)
11821 out1fmt("\nBuilt-in commands:\n-------------------\n");
11822 for (col = 0, i = 0; i < NUMBUILTINS; i++) {
11823 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11824 builtincmd[i].name + 1);
11830 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
11832 extern const struct BB_applet applets[];
11833 extern const size_t NUM_APPLETS;
11835 for (i = 0; i < NUM_APPLETS; i++) {
11837 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
11846 return EXIT_SUCCESS;
11848 #endif /* CONFIG_FEATURE_SH_EXTRA_QUIET */
11851 * Called to exit the shell.
11861 status = exitstatus;
11862 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
11863 if (setjmp(loc.loc)) {
11867 if ((p = trap[0]) != NULL && *p != '\0') {
11872 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
11873 if (iflag && rootshell) {
11874 const char *hp = lookupvar("HISTFILE");
11877 save_history ( hp );
11885 static int decode_signal(const char *string, int minsig)
11888 const char *name = u_signal_names(string, &signo, minsig);
11890 return name ? signo : -1;
11893 /* $NetBSD: var.c,v 1.32 2003/01/22 20:36:04 dsl Exp $ */
11895 static struct var *vartab[VTABSIZE];
11897 static int vpcmp(const void *, const void *);
11898 static struct var **findvar(struct var **, const char *);
11901 * Initialize the varable symbol tables and import the environment
11905 #ifdef CONFIG_ASH_GETOPTS
11907 * Safe version of setvar, returns 1 on success 0 on failure.
11911 setvarsafe(const char *name, const char *val, int flags)
11914 volatile int saveint;
11915 struct jmploc *volatile savehandler = handler;
11916 struct jmploc jmploc;
11919 if (setjmp(jmploc.loc))
11923 setvar(name, val, flags);
11926 handler = savehandler;
11927 RESTOREINT(saveint);
11933 * Set the value of a variable. The flags argument is ored with the
11934 * flags of the variable. If val is NULL, the variable is unset.
11938 setvar(const char *name, const char *val, int flags)
11945 q = endofname(name);
11946 p = strchrnul(q, '=');
11947 namelen = p - name;
11948 if (!namelen || p != q)
11949 error("%.*s: bad variable name", namelen, name);
11954 vallen = strlen(val);
11957 p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
11961 p = mempcpy(p, val, vallen);
11964 setvareq(nameeq, flags | VNOSAVE);
11970 * Same as setvar except that the variable and value are passed in
11971 * the first argument as name=value. Since the first argument will
11972 * be actually stored in the table, it should not be a string that
11974 * Called with interrupts off.
11978 setvareq(char *s, int flags)
11980 struct var *vp, **vpp;
11983 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
11984 vp = *findvar(vpp, s);
11986 if (vp->flags & VREADONLY) {
11987 if (flags & VNOSAVE)
11989 error("%.*s: is read only", strchrnul(s, '=') - s, s);
11992 if (flags & VNOSET)
11995 if (vp->func && (flags & VNOFUNC) == 0)
11996 (*vp->func)(strchrnul(s, '=') + 1);
11998 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12001 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
12003 if (flags & VNOSET)
12006 vp = ckmalloc(sizeof (*vp));
12011 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
12019 * Process a linked list of variable assignments.
12023 listsetvar(struct strlist *list_set_var, int flags)
12025 struct strlist *lp = list_set_var;
12031 setvareq(lp->text, flags);
12032 } while ((lp = lp->next));
12038 * Find the value of a variable. Returns NULL if not set.
12042 lookupvar(const char *name)
12046 if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
12047 return strchrnul(v->text, '=') + 1;
12054 * Search the environment of a builtin command.
12058 bltinlookup(const char *name)
12060 struct strlist *sp;
12062 for (sp = cmdenviron ; sp ; sp = sp->next) {
12063 if (varequal(sp->text, name))
12064 return strchrnul(sp->text, '=') + 1;
12066 return lookupvar(name);
12071 * Generate a list of variables satisfying the given conditions.
12075 listvars(int on, int off, char ***end)
12086 for (vp = *vpp ; vp ; vp = vp->next)
12087 if ((vp->flags & mask) == on) {
12088 if (ep == stackstrend())
12089 ep = growstackstr();
12090 *ep++ = (char *) vp->text;
12092 } while (++vpp < vartab + VTABSIZE);
12093 if (ep == stackstrend())
12094 ep = growstackstr();
12098 return grabstackstr(ep);
12103 * POSIX requires that 'set' (but not export or readonly) output the
12104 * variables in lexicographic order - by the locale's collating order (sigh).
12105 * Maybe we could keep them in an ordered balanced binary tree
12106 * instead of hashed lists.
12107 * For now just roll 'em through qsort for printing...
12111 showvars(const char *sep_prefix, int on, int off)
12114 char **ep, **epend;
12116 ep = listvars(on, off, &epend);
12117 qsort(ep, epend - ep, sizeof(char *), vpcmp);
12119 sep = *sep_prefix ? spcstr : sep_prefix;
12121 for (; ep < epend; ep++) {
12125 p = strchrnul(*ep, '=');
12128 q = single_quote(++p);
12130 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
12139 * The export and readonly commands.
12143 exportcmd(int argc, char **argv)
12149 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12152 notp = nextopt("p") - 'p';
12153 if (notp && ((name = *(aptr = argptr)))) {
12155 if ((p = strchr(name, '=')) != NULL) {
12158 if ((vp = *findvar(hashvar(name), name))) {
12163 setvar(name, p, flag);
12164 } while ((name = *++aptr) != NULL);
12166 showvars(argv[0], flag, 0);
12173 * Make a variable a local variable. When a variable is made local, it's
12174 * value and flags are saved in a localvar structure. The saved values
12175 * will be restored when the shell function returns. We handle the name
12176 * "-" as a special case.
12180 mklocal(char *name)
12182 struct localvar *lvp;
12187 lvp = ckmalloc(sizeof (struct localvar));
12188 if (name[0] == '-' && name[1] == '\0') {
12190 p = ckmalloc(sizeof(optlist));
12191 lvp->text = memcpy(p, optlist, sizeof(optlist));
12196 vpp = hashvar(name);
12197 vp = *findvar(vpp, name);
12198 eq = strchr(name, '=');
12201 setvareq(name, VSTRFIXED);
12203 setvar(name, NULL, VSTRFIXED);
12204 vp = *vpp; /* the new variable */
12205 lvp->flags = VUNSET;
12207 lvp->text = vp->text;
12208 lvp->flags = vp->flags;
12209 vp->flags |= VSTRFIXED|VTEXTFIXED;
12215 lvp->next = localvars;
12221 * The "local" command.
12225 localcmd(int argc, char **argv)
12230 while ((name = *argv++) != NULL) {
12238 * Called after a function returns.
12239 * Interrupts must be off.
12245 struct localvar *lvp;
12248 while ((lvp = localvars) != NULL) {
12249 localvars = lvp->next;
12251 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
12252 if (vp == NULL) { /* $- saved */
12253 memcpy(optlist, lvp->text, sizeof(optlist));
12256 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12257 unsetvar(vp->text);
12260 (*vp->func)(strchrnul(lvp->text, '=') + 1);
12261 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12263 vp->flags = lvp->flags;
12264 vp->text = lvp->text;
12272 * The unset builtin command. We unset the function before we unset the
12273 * variable to allow a function to be unset when there is a readonly variable
12274 * with the same name.
12278 unsetcmd(int argc, char **argv)
12285 while ((i = nextopt("vf")) != '\0') {
12289 for (ap = argptr; *ap ; ap++) {
12304 * Unset the specified variable.
12308 unsetvar(const char *s)
12314 vpp = findvar(hashvar(s), s);
12318 int flags = vp->flags;
12321 if (flags & VREADONLY)
12323 if (flags & VUNSET)
12325 if ((flags & VSTRFIXED) == 0) {
12327 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
12334 vp->flags &= ~VEXPORT;
12347 * Find the appropriate entry in the hash table from the name.
12350 static struct var **
12351 hashvar(const char *p)
12353 unsigned int hashval;
12355 hashval = ((unsigned char) *p) << 4;
12356 while (*p && *p != '=')
12357 hashval += (unsigned char) *p++;
12358 return &vartab[hashval % VTABSIZE];
12364 * Compares two strings up to the first = or '\0'. The first
12365 * string must be terminated by '='; the second may be terminated by
12366 * either '=' or '\0'.
12370 varcmp(const char *p, const char *q)
12374 while ((c = *p) == (d = *q)) {
12375 if (!c || c == '=')
12389 vpcmp(const void *a, const void *b)
12391 return varcmp(*(const char **)a, *(const char **)b);
12394 static struct var **
12395 findvar(struct var **vpp, const char *name)
12397 for (; *vpp; vpp = &(*vpp)->next) {
12398 if (varequal((*vpp)->text, name)) {
12404 /* $NetBSD: setmode.c,v 1.29 2003/01/15 23:58:03 kleink Exp $ */
12406 #include <sys/times.h>
12408 static const unsigned char timescmd_str[] = {
12409 ' ', offsetof(struct tms, tms_utime),
12410 '\n', offsetof(struct tms, tms_stime),
12411 ' ', offsetof(struct tms, tms_cutime),
12412 '\n', offsetof(struct tms, tms_cstime),
12416 static int timescmd(int ac, char **av)
12418 long int clk_tck, s, t;
12419 const unsigned char *p;
12422 clk_tck = sysconf(_SC_CLK_TCK);
12427 t = *(clock_t *)(((char *) &buf) + p[1]);
12429 out1fmt("%ldm%ld.%.3lds%c",
12431 ((t - s * clk_tck) * 1000) / clk_tck,
12433 } while (*(p += 2));
12438 #ifdef CONFIG_ASH_MATH_SUPPORT
12440 dash_arith(const char *s)
12446 result = arith(s, &errcode);
12449 error("exponent less than 0");
12450 else if (errcode == -2)
12451 error("divide by zero");
12452 else if (errcode == -5)
12453 error("expression recursion loop detected");
12464 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12465 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12467 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12471 letcmd(int argc, char **argv)
12478 error("expression expected");
12479 for (ap = argv + 1; *ap; ap++) {
12480 i = dash_arith(*ap);
12485 #endif /* CONFIG_ASH_MATH_SUPPORT */
12487 /* $NetBSD: miscbltin.c,v 1.31 2002/11/24 22:35:41 christos Exp $ */
12490 * Miscelaneous builtins.
12496 #if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
12497 typedef enum __rlimit_resource rlim_t;
12503 * The read builtin. The -e option causes backslashes to escape the
12504 * following character.
12506 * This uses unbuffered input, which may be avoidable in some cases.
12510 readcmd(int argc, char **argv)
12525 while ((i = nextopt("p:r")) != '\0') {
12527 prompt = optionarg;
12531 if (prompt && isatty(0)) {
12534 if (*(ap = argptr) == NULL)
12535 error("arg count");
12536 if ((ifs = bltinlookup("IFS")) == NULL)
12543 if (read(0, &c, 1) != 1) {
12555 if (!rflag && c == '\\') {
12561 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12565 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12567 setvar(*ap, stackblock(), 0);
12577 /* Remove trailing blanks */
12578 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12580 setvar(*ap, stackblock(), 0);
12581 while (*++ap != NULL)
12582 setvar(*ap, nullstr, 0);
12587 static int umaskcmd(int argc, char **argv)
12589 static const char permuser[3] = "ugo";
12590 static const char permmode[3] = "rwx";
12591 static const short int permmask[] = {
12592 S_IRUSR, S_IWUSR, S_IXUSR,
12593 S_IRGRP, S_IWGRP, S_IXGRP,
12594 S_IROTH, S_IWOTH, S_IXOTH
12600 int symbolic_mode = 0;
12602 while (nextopt("S") != '\0') {
12611 if ((ap = *argptr) == NULL) {
12612 if (symbolic_mode) {
12616 for (i = 0; i < 3; i++) {
12619 *p++ = permuser[i];
12621 for (j = 0; j < 3; j++) {
12622 if ((mask & permmask[3 * i + j]) == 0) {
12623 *p++ = permmode[j];
12631 out1fmt("%.4o\n", mask);
12634 if (is_digit((unsigned char) *ap)) {
12637 if (*ap >= '8' || *ap < '0')
12638 error(illnum, argv[1]);
12639 mask = (mask << 3) + (*ap - '0');
12640 } while (*++ap != '\0');
12643 mask = ~mask & 0777;
12644 if (!bb_parse_mode(ap, &mask)) {
12645 error("Illegal mode: %s", ap);
12647 umask(~mask & 0777);
12656 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12657 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12658 * ash by J.T. Conklin.
12666 int factor; /* multiply by to get rlim_{cur,max} values */
12670 static const struct limits limits[] = {
12672 { "time(seconds)", RLIMIT_CPU, 1, 't' },
12674 #ifdef RLIMIT_FSIZE
12675 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
12678 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
12680 #ifdef RLIMIT_STACK
12681 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
12684 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
12687 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
12689 #ifdef RLIMIT_MEMLOCK
12690 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
12692 #ifdef RLIMIT_NPROC
12693 { "process(processes)", RLIMIT_NPROC, 1, 'p' },
12695 #ifdef RLIMIT_NOFILE
12696 { "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' },
12699 { "vmemory(kbytes)", RLIMIT_VMEM, 1024, 'v' },
12702 { "swap(kbytes)", RLIMIT_SWAP, 1024, 'w' },
12704 { (char *) 0, 0, 0, '\0' }
12708 ulimitcmd(int argc, char **argv)
12712 enum { SOFT = 0x1, HARD = 0x2 }
12714 const struct limits *l;
12717 struct rlimit limit;
12720 while ((optc = nextopt("HSatfdsmcnpl")) != '\0')
12735 for (l = limits; l->name && l->option != what; l++)
12738 error("internal error (%c)", what);
12740 set = *argptr ? 1 : 0;
12744 if (all || argptr[1])
12745 error("too many arguments");
12746 if (strncmp(p, "unlimited\n", 9) == 0)
12747 val = RLIM_INFINITY;
12751 while ((c = *p++) >= '0' && c <= '9')
12753 val = (val * 10) + (long)(c - '0');
12754 if (val < (rlim_t) 0)
12758 error("bad number");
12763 for (l = limits; l->name; l++) {
12764 getrlimit(l->cmd, &limit);
12766 val = limit.rlim_cur;
12767 else if (how & HARD)
12768 val = limit.rlim_max;
12770 out1fmt("%-20s ", l->name);
12771 if (val == RLIM_INFINITY)
12772 out1fmt("unlimited\n");
12776 out1fmt("%lld\n", (long long) val);
12782 getrlimit(l->cmd, &limit);
12785 limit.rlim_max = val;
12787 limit.rlim_cur = val;
12788 if (setrlimit(l->cmd, &limit) < 0)
12789 error("error setting limit (%m)");
12792 val = limit.rlim_cur;
12793 else if (how & HARD)
12794 val = limit.rlim_max;
12796 if (val == RLIM_INFINITY)
12797 out1fmt("unlimited\n");
12801 out1fmt("%lld\n", (long long) val);
12808 #ifdef CONFIG_ASH_MATH_SUPPORT
12810 /* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
12812 Permission is hereby granted, free of charge, to any person obtaining
12813 a copy of this software and associated documentation files (the
12814 "Software"), to deal in the Software without restriction, including
12815 without limitation the rights to use, copy, modify, merge, publish,
12816 distribute, sublicense, and/or sell copies of the Software, and to
12817 permit persons to whom the Software is furnished to do so, subject to
12818 the following conditions:
12820 The above copyright notice and this permission notice shall be
12821 included in all copies or substantial portions of the Software.
12823 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12824 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12825 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
12826 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
12827 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
12828 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
12829 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12832 /* This is my infix parser/evaluator. It is optimized for size, intended
12833 * as a replacement for yacc-based parsers. However, it may well be faster
12834 * than a comparable parser writen in yacc. The supported operators are
12835 * listed in #defines below. Parens, order of operations, and error handling
12836 * are supported. This code is threadsafe. The exact expression format should
12837 * be that which POSIX specifies for shells. */
12839 /* The code uses a simple two-stack algorithm. See
12840 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
12841 * for a detailed explaination of the infix-to-postfix algorithm on which
12842 * this is based (this code differs in that it applies operators immediately
12843 * to the stack instead of adding them to a queue to end up with an
12846 /* To use the routine, call it with an expression string and error return
12850 * Aug 24, 2001 Manuel Novoa III
12852 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
12854 * 1) In arith_apply():
12855 * a) Cached values of *numptr and &(numptr[-1]).
12856 * b) Removed redundant test for zero denominator.
12859 * a) Eliminated redundant code for processing operator tokens by moving
12860 * to a table-based implementation. Also folded handling of parens
12862 * b) Combined all 3 loops which called arith_apply to reduce generated
12863 * code size at the cost of speed.
12865 * 3) The following expressions were treated as valid by the original code:
12866 * 1() , 0! , 1 ( *3 ) .
12867 * These bugs have been fixed by internally enclosing the expression in
12868 * parens and then checking that all binary ops and right parens are
12869 * preceded by a valid expression (NUM_TOKEN).
12871 * Note: It may be desireable to replace Aaron's test for whitespace with
12872 * ctype's isspace() if it is used by another busybox applet or if additional
12873 * whitespace chars should be considered. Look below the "#include"s for a
12874 * precompiler test.
12878 * Aug 26, 2001 Manuel Novoa III
12880 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
12882 * Merge in Aaron's comments previously posted to the busybox list,
12883 * modified slightly to take account of my changes to the code.
12888 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12890 * - allow access to variable,
12891 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
12892 * - realize assign syntax (VAR=expr, +=, *= etc)
12893 * - realize exponentiation (** operator)
12894 * - realize comma separated - expr, expr
12895 * - realise ++expr --expr expr++ expr--
12896 * - realise expr ? expr : expr (but, second expr calculate always)
12897 * - allow hexdecimal and octal numbers
12898 * - was restored loses XOR operator
12899 * - remove one goto label, added three ;-)
12900 * - protect $((num num)) as true zero expr (Manuel`s error)
12901 * - always use special isspace(), see comment from bash ;-)
12905 #define arith_isspace(arithval) \
12906 (arithval == ' ' || arithval == '\n' || arithval == '\t')
12909 typedef unsigned char operator;
12911 /* An operator's token id is a bit of a bitfield. The lower 5 bits are the
12912 * precedence, and 3 high bits are an ID unique accross operators of that
12913 * precedence. The ID portion is so that multiple operators can have the
12914 * same precedence, ensuring that the leftmost one is evaluated first.
12915 * Consider * and /. */
12917 #define tok_decl(prec,id) (((id)<<5)|(prec))
12918 #define PREC(op) ((op) & 0x1F)
12920 #define TOK_LPAREN tok_decl(0,0)
12922 #define TOK_COMMA tok_decl(1,0)
12924 #define TOK_ASSIGN tok_decl(2,0)
12925 #define TOK_AND_ASSIGN tok_decl(2,1)
12926 #define TOK_OR_ASSIGN tok_decl(2,2)
12927 #define TOK_XOR_ASSIGN tok_decl(2,3)
12928 #define TOK_PLUS_ASSIGN tok_decl(2,4)
12929 #define TOK_MINUS_ASSIGN tok_decl(2,5)
12930 #define TOK_LSHIFT_ASSIGN tok_decl(2,6)
12931 #define TOK_RSHIFT_ASSIGN tok_decl(2,7)
12933 #define TOK_MUL_ASSIGN tok_decl(3,0)
12934 #define TOK_DIV_ASSIGN tok_decl(3,1)
12935 #define TOK_REM_ASSIGN tok_decl(3,2)
12937 /* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
12938 #define convert_prec_is_assing(prec) do { if(prec == 3) prec = 2; } while(0)
12940 /* conditional is right associativity too */
12941 #define TOK_CONDITIONAL tok_decl(4,0)
12942 #define TOK_CONDITIONAL_SEP tok_decl(4,1)
12944 #define TOK_OR tok_decl(5,0)
12946 #define TOK_AND tok_decl(6,0)
12948 #define TOK_BOR tok_decl(7,0)
12950 #define TOK_BXOR tok_decl(8,0)
12952 #define TOK_BAND tok_decl(9,0)
12954 #define TOK_EQ tok_decl(10,0)
12955 #define TOK_NE tok_decl(10,1)
12957 #define TOK_LT tok_decl(11,0)
12958 #define TOK_GT tok_decl(11,1)
12959 #define TOK_GE tok_decl(11,2)
12960 #define TOK_LE tok_decl(11,3)
12962 #define TOK_LSHIFT tok_decl(12,0)
12963 #define TOK_RSHIFT tok_decl(12,1)
12965 #define TOK_ADD tok_decl(13,0)
12966 #define TOK_SUB tok_decl(13,1)
12968 #define TOK_MUL tok_decl(14,0)
12969 #define TOK_DIV tok_decl(14,1)
12970 #define TOK_REM tok_decl(14,2)
12972 /* exponent is right associativity */
12973 #define TOK_EXPONENT tok_decl(15,1)
12975 /* For now unary operators. */
12976 #define UNARYPREC 16
12977 #define TOK_BNOT tok_decl(UNARYPREC,0)
12978 #define TOK_NOT tok_decl(UNARYPREC,1)
12980 #define TOK_UMINUS tok_decl(UNARYPREC+1,0)
12981 #define TOK_UPLUS tok_decl(UNARYPREC+1,1)
12983 #define PREC_PRE (UNARYPREC+2)
12985 #define TOK_PRE_INC tok_decl(PREC_PRE, 0)
12986 #define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
12988 #define PREC_POST (UNARYPREC+3)
12990 #define TOK_POST_INC tok_decl(PREC_POST, 0)
12991 #define TOK_POST_DEC tok_decl(PREC_POST, 1)
12993 #define SPEC_PREC (UNARYPREC+4)
12995 #define TOK_NUM tok_decl(SPEC_PREC, 0)
12996 #define TOK_RPAREN tok_decl(SPEC_PREC, 1)
12998 #define NUMPTR (*numstackptr)
13000 static inline int tok_have_assign(operator op)
13002 operator prec = PREC(op);
13004 convert_prec_is_assing(prec);
13005 return (prec == PREC(TOK_ASSIGN) ||
13006 prec == PREC_PRE || prec == PREC_POST);
13009 static inline int is_right_associativity(operator prec)
13011 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) ||
13012 prec == PREC(TOK_CONDITIONAL));
13016 typedef struct ARITCH_VAR_NUM {
13018 long contidional_second_val;
13019 char contidional_second_val_initialized;
13020 char *var; /* if NULL then is regular number,
13021 else is varable name */
13025 typedef struct CHK_VAR_RECURSIVE_LOOPED {
13027 struct CHK_VAR_RECURSIVE_LOOPED *next;
13028 } chk_var_recursive_looped_t;
13030 static chk_var_recursive_looped_t *prev_chk_var_recursive;
13033 static int arith_lookup_val(v_n_t *t)
13036 const char * p = lookupvar(t->var);
13041 /* recursive try as expression */
13042 chk_var_recursive_looped_t *cur;
13043 chk_var_recursive_looped_t cur_save;
13045 for(cur = prev_chk_var_recursive; cur; cur = cur->next) {
13046 if(strcmp(cur->var, t->var) == 0) {
13047 /* expression recursion loop detected */
13051 /* save current lookuped var name */
13052 cur = prev_chk_var_recursive;
13053 cur_save.var = t->var;
13054 cur_save.next = cur;
13055 prev_chk_var_recursive = &cur_save;
13057 t->val = arith (p, &errcode);
13058 /* restore previous ptr after recursiving */
13059 prev_chk_var_recursive = cur;
13062 /* allow undefined var as 0 */
13069 /* "applying" a token means performing it on the top elements on the integer
13070 * stack. For a unary operator it will only change the top element, but a
13071 * binary operator will pop two arguments and push a result */
13073 arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
13078 int ret_arith_lookup_val;
13080 if (NUMPTR == numstack) goto err; /* There is no operator that can work
13081 without arguments */
13082 numptr_m1 = NUMPTR - 1;
13084 /* check operand is var with noninteger value */
13085 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13086 if(ret_arith_lookup_val)
13087 return ret_arith_lookup_val;
13089 rez = numptr_m1->val;
13090 if (op == TOK_UMINUS)
13092 else if (op == TOK_NOT)
13094 else if (op == TOK_BNOT)
13096 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
13098 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
13100 else if (op != TOK_UPLUS) {
13101 /* Binary operators */
13103 /* check and binary operators need two arguments */
13104 if (numptr_m1 == numstack) goto err;
13106 /* ... and they pop one */
13109 if (op == TOK_CONDITIONAL) {
13110 if(! numptr_m1->contidional_second_val_initialized) {
13111 /* protect $((expr1 ? expr2)) without ": expr" */
13114 rez = numptr_m1->contidional_second_val;
13115 } else if(numptr_m1->contidional_second_val_initialized) {
13116 /* protect $((expr1 : expr2)) without "expr ? " */
13119 numptr_m1 = NUMPTR - 1;
13120 if(op != TOK_ASSIGN) {
13121 /* check operand is var with noninteger value for not '=' */
13122 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13123 if(ret_arith_lookup_val)
13124 return ret_arith_lookup_val;
13126 if (op == TOK_CONDITIONAL) {
13127 numptr_m1->contidional_second_val = rez;
13129 rez = numptr_m1->val;
13130 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
13132 else if (op == TOK_OR)
13133 rez = numptr_val || rez;
13134 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
13136 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
13138 else if (op == TOK_AND)
13139 rez = rez && numptr_val;
13140 else if (op == TOK_EQ)
13141 rez = (rez == numptr_val);
13142 else if (op == TOK_NE)
13143 rez = (rez != numptr_val);
13144 else if (op == TOK_GE)
13145 rez = (rez >= numptr_val);
13146 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
13147 rez >>= numptr_val;
13148 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
13149 rez <<= numptr_val;
13150 else if (op == TOK_GT)
13151 rez = (rez > numptr_val);
13152 else if (op == TOK_LT)
13153 rez = (rez < numptr_val);
13154 else if (op == TOK_LE)
13155 rez = (rez <= numptr_val);
13156 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
13158 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
13160 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
13162 else if (op == TOK_ASSIGN || op == TOK_COMMA)
13164 else if (op == TOK_CONDITIONAL_SEP) {
13165 if (numptr_m1 == numstack) {
13166 /* protect $((expr : expr)) without "expr ? " */
13169 numptr_m1->contidional_second_val_initialized = op;
13170 numptr_m1->contidional_second_val = numptr_val;
13172 else if (op == TOK_CONDITIONAL) {
13174 numptr_val : numptr_m1->contidional_second_val;
13176 else if(op == TOK_EXPONENT) {
13178 return -3; /* exponent less than 0 */
13183 while(numptr_val--)
13188 else if(numptr_val==0) /* zero divisor check */
13190 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
13192 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
13195 if(tok_have_assign(op)) {
13198 if(numptr_m1->var == NULL) {
13202 /* save to shell variable */
13203 sprintf(buf, "%ld", rez);
13204 setvar(numptr_m1->var, buf, 0);
13205 /* after saving, make previous value for v++ or v-- */
13206 if(op == TOK_POST_INC)
13208 else if(op == TOK_POST_DEC)
13211 numptr_m1->val = rez;
13212 /* protect geting var value, is number now */
13213 numptr_m1->var = NULL;
13218 /* longest must first */
13219 static const char op_tokens[] = {
13220 '<','<','=',0, TOK_LSHIFT_ASSIGN,
13221 '>','>','=',0, TOK_RSHIFT_ASSIGN,
13222 '<','<', 0, TOK_LSHIFT,
13223 '>','>', 0, TOK_RSHIFT,
13224 '|','|', 0, TOK_OR,
13225 '&','&', 0, TOK_AND,
13226 '!','=', 0, TOK_NE,
13227 '<','=', 0, TOK_LE,
13228 '>','=', 0, TOK_GE,
13229 '=','=', 0, TOK_EQ,
13230 '|','=', 0, TOK_OR_ASSIGN,
13231 '&','=', 0, TOK_AND_ASSIGN,
13232 '*','=', 0, TOK_MUL_ASSIGN,
13233 '/','=', 0, TOK_DIV_ASSIGN,
13234 '%','=', 0, TOK_REM_ASSIGN,
13235 '+','=', 0, TOK_PLUS_ASSIGN,
13236 '-','=', 0, TOK_MINUS_ASSIGN,
13237 '-','-', 0, TOK_POST_DEC,
13238 '^','=', 0, TOK_XOR_ASSIGN,
13239 '+','+', 0, TOK_POST_INC,
13240 '*','*', 0, TOK_EXPONENT,
13244 '=', 0, TOK_ASSIGN,
13256 '?', 0, TOK_CONDITIONAL,
13257 ':', 0, TOK_CONDITIONAL_SEP,
13258 ')', 0, TOK_RPAREN,
13259 '(', 0, TOK_LPAREN,
13263 #define endexpression &op_tokens[sizeof(op_tokens)-7]
13266 extern long arith (const char *expr, int *perrcode)
13268 register char arithval; /* Current character under analysis */
13269 operator lasttok, op;
13272 const char *p = endexpression;
13275 size_t datasizes = strlen(expr) + 2;
13277 /* Stack of integers */
13278 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
13279 * in any given correct or incorrect expression is left as an excersize to
13281 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
13282 *numstackptr = numstack;
13283 /* Stack of operator tokens */
13284 operator *stack = alloca((datasizes) * sizeof(operator)),
13287 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
13288 *perrcode = errcode = 0;
13291 if ((arithval = *expr) == 0) {
13292 if (p == endexpression) {
13293 /* Null expression. */
13297 /* This is only reached after all tokens have been extracted from the
13298 * input stream. If there are still tokens on the operator stack, they
13299 * are to be applied in order. At the end, there should be a final
13300 * result on the integer stack */
13302 if (expr != endexpression + 1) {
13303 /* If we haven't done so already, */
13304 /* append a closing right paren */
13305 expr = endexpression;
13306 /* and let the loop process it. */
13309 /* At this point, we're done with the expression. */
13310 if (numstackptr != numstack+1) {
13311 /* ... but if there isn't, it's bad */
13313 return (*perrcode = -1);
13315 if(numstack->var) {
13316 /* expression is $((var)) only, lookup now */
13317 errcode = arith_lookup_val(numstack);
13320 *perrcode = errcode;
13321 return numstack->val;
13323 /* Continue processing the expression. */
13324 if (arith_isspace(arithval)) {
13325 /* Skip whitespace */
13328 if((p = endofname(expr)) != expr) {
13329 int var_name_size = (p-expr) + 1; /* trailing zero */
13331 numstackptr->var = alloca(var_name_size);
13332 safe_strncpy(numstackptr->var, expr, var_name_size);
13335 numstackptr->contidional_second_val_initialized = 0;
13339 } else if (is_digit(arithval)) {
13340 numstackptr->var = NULL;
13341 numstackptr->val = strtol(expr, (char **) &expr, 0);
13344 for(p = op_tokens; ; p++) {
13348 /* strange operator not found */
13351 for(o = expr; *p && *o == *p; p++)
13358 /* skip tail uncompared token */
13361 /* skip zero delim */
13366 /* post grammar: a++ reduce to num */
13367 if(lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13370 /* Plus and minus are binary (not unary) _only_ if the last
13371 * token was as number, or a right paren (which pretends to be
13372 * a number, since it evaluates to one). Think about it.
13373 * It makes sense. */
13374 if (lasttok != TOK_NUM) {
13390 /* We don't want a unary operator to cause recursive descent on the
13391 * stack, because there can be many in a row and it could cause an
13392 * operator to be evaluated before its argument is pushed onto the
13393 * integer stack. */
13394 /* But for binary operators, "apply" everything on the operator
13395 * stack until we find an operator with a lesser priority than the
13396 * one we have just extracted. */
13397 /* Left paren is given the lowest priority so it will never be
13398 * "applied" in this way.
13399 * if associativity is right and priority eq, applied also skip
13402 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13403 /* not left paren or unary */
13404 if (lasttok != TOK_NUM) {
13405 /* binary op must be preceded by a num */
13408 while (stackptr != stack) {
13409 if (op == TOK_RPAREN) {
13410 /* The algorithm employed here is simple: while we don't
13411 * hit an open paren nor the bottom of the stack, pop
13412 * tokens and apply them */
13413 if (stackptr[-1] == TOK_LPAREN) {
13415 /* Any operator directly after a */
13417 /* close paren should consider itself binary */
13421 operator prev_prec = PREC(stackptr[-1]);
13423 convert_prec_is_assing(prec);
13424 convert_prec_is_assing(prev_prec);
13425 if (prev_prec < prec)
13427 /* check right assoc */
13428 if(prev_prec == prec && is_right_associativity(prec))
13431 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13432 if(errcode) goto ret;
13434 if (op == TOK_RPAREN) {
13439 /* Push this operator to the stack and remember it. */
13440 *stackptr++ = lasttok = op;
13447 #endif /* CONFIG_ASH_MATH_SUPPORT */
13451 const char *bb_applet_name = "debug stuff usage";
13452 int main(int argc, char **argv)
13454 return ash_main(argc, argv);
13459 * Copyright (c) 1989, 1991, 1993, 1994
13460 * The Regents of the University of California. All rights reserved.
13462 * This code is derived from software contributed to Berkeley by
13463 * Kenneth Almquist.
13465 * Redistribution and use in source and binary forms, with or without
13466 * modification, are permitted provided that the following conditions
13468 * 1. Redistributions of source code must retain the above copyright
13469 * notice, this list of conditions and the following disclaimer.
13470 * 2. Redistributions in binary form must reproduce the above copyright
13471 * notice, this list of conditions and the following disclaimer in the
13472 * documentation and/or other materials provided with the distribution.
13474 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
13475 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
13477 * 4. Neither the name of the University nor the names of its contributors
13478 * may be used to endorse or promote products derived from this software
13479 * without specific prior written permission.
13481 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13482 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13483 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13484 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13485 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13486 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13487 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13488 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13489 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13490 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF