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 *);
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);
2714 * Execute a command or commands contained in a string.
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 void strtodest(const char *, int, int);
4500 static void memtodest(const char *p, size_t len, int syntax, int quotes);
4501 static ssize_t varvalue(char *, int, int);
4502 static void recordregion(int, int, int);
4503 static void removerecordregions(int);
4504 static void ifsbreakup(char *, struct arglist *);
4505 static void ifsfree(void);
4506 static void expandmeta(struct strlist *, int);
4507 static int patmatch(char *, const char *);
4509 static int cvtnum(long);
4510 static size_t esclen(const char *, const char *);
4511 static char *scanleft(char *, char *, char *, char *, int, int);
4512 static char *scanright(char *, char *, char *, char *, int, int);
4513 static void varunset(const char *, const char *, const char *, int)
4514 __attribute__((__noreturn__));
4517 #define pmatch(a, b) !fnmatch((a), (b), 0)
4519 * Prepare a pattern for a expmeta (internal glob(3)) call.
4521 * Returns an stalloced string.
4524 static inline char *
4525 preglob(const char *pattern, int quoted, int flag) {
4526 flag |= RMESCAPE_GLOB;
4528 flag |= RMESCAPE_QUOTED;
4530 return _rmescapes((char *)pattern, flag);
4535 esclen(const char *start, const char *p) {
4538 while (p > start && *--p == CTLESC) {
4546 * Expand shell variables and backquotes inside a here document.
4550 expandhere(union node *arg, int fd)
4553 expandarg(arg, (struct arglist *)NULL, 0);
4554 xwrite(fd, stackblock(), expdest - (char *)stackblock());
4559 * Perform variable substitution and command substitution on an argument,
4560 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4561 * perform splitting and file name expansion. When arglist is NULL, perform
4562 * here document expansion.
4566 expandarg(union node *arg, struct arglist *arglist, int flag)
4571 argbackq = arg->narg.backquote;
4572 STARTSTACKSTR(expdest);
4573 ifsfirst.next = NULL;
4575 argstr(arg->narg.text, flag);
4576 if (arglist == NULL) {
4577 return; /* here document expanded */
4579 STPUTC('\0', expdest);
4580 p = grabstackstr(expdest);
4581 exparg.lastp = &exparg.list;
4585 if (flag & EXP_FULL) {
4586 ifsbreakup(p, &exparg);
4587 *exparg.lastp = NULL;
4588 exparg.lastp = &exparg.list;
4589 expandmeta(exparg.list, flag);
4591 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
4593 sp = (struct strlist *)stalloc(sizeof (struct strlist));
4596 exparg.lastp = &sp->next;
4600 *exparg.lastp = NULL;
4602 *arglist->lastp = exparg.list;
4603 arglist->lastp = exparg.lastp;
4609 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4610 * characters to allow for further processing. Otherwise treat
4611 * $@ like $* since no splitting will be performed.
4615 argstr(char *p, int flag)
4617 static const char spclchars[] = {
4625 CTLBACKQ | CTLQUOTE,
4626 #ifdef CONFIG_ASH_MATH_SUPPORT
4631 const char *reject = spclchars;
4633 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
4634 int breakall = flag & EXP_WORD;
4639 if (!(flag & EXP_VARTILDE)) {
4641 } else if (flag & EXP_VARTILDE2) {
4646 if (flag & EXP_TILDE) {
4652 if (*q == CTLESC && (flag & EXP_QWORD))
4655 p = exptilde(p, q, flag);
4658 startloc = expdest - (char *)stackblock();
4660 length += strcspn(p + length, reject);
4662 if (c && (!(c & 0x80)
4663 #ifdef CONFIG_ASH_MATH_SUPPORT
4667 /* c == '=' || c == ':' || c == CTLENDARI */
4672 expdest = stnputs(p, length, expdest);
4673 newloc = expdest - (char *)stackblock();
4674 if (breakall && !inquotes && newloc > startloc) {
4675 recordregion(startloc, newloc, 0);
4686 if (flag & EXP_VARTILDE2) {
4690 flag |= EXP_VARTILDE2;
4695 * sort of a hack - expand tildes in variable
4696 * assignments (after the first '=' and after ':'s).
4705 case CTLENDVAR: /* ??? */
4708 /* "$@" syntax adherence hack */
4711 !memcmp(p, dolatstr, DOLATSTRLEN) &&
4712 (p[4] == CTLQUOTEMARK || (
4713 p[4] == CTLENDVAR &&
4714 p[5] == CTLQUOTEMARK
4717 p = evalvar(p + 1, flag) + 1;
4720 inquotes = !inquotes;
4733 p = evalvar(p, flag);
4737 case CTLBACKQ|CTLQUOTE:
4738 expbackq(argbackq->n, c, quotes);
4739 argbackq = argbackq->next;
4741 #ifdef CONFIG_ASH_MATH_SUPPORT
4754 exptilde(char *startp, char *p, int flag)
4760 int quotes = flag & (EXP_FULL | EXP_CASE);
4765 while ((c = *++p) != '\0') {
4772 if (flag & EXP_VARTILDE)
4782 if (*name == '\0') {
4783 if ((home = lookupvar(homestr)) == NULL)
4786 if ((pw = getpwnam(name)) == NULL)
4793 startloc = expdest - (char *)stackblock();
4794 strtodest(home, SQSYNTAX, quotes);
4795 recordregion(startloc, expdest - (char *)stackblock(), 0);
4804 removerecordregions(int endoff)
4806 if (ifslastp == NULL)
4809 if (ifsfirst.endoff > endoff) {
4810 while (ifsfirst.next != NULL) {
4811 struct ifsregion *ifsp;
4813 ifsp = ifsfirst.next->next;
4814 ckfree(ifsfirst.next);
4815 ifsfirst.next = ifsp;
4818 if (ifsfirst.begoff > endoff)
4821 ifslastp = &ifsfirst;
4822 ifsfirst.endoff = endoff;
4827 ifslastp = &ifsfirst;
4828 while (ifslastp->next && ifslastp->next->begoff < endoff)
4829 ifslastp=ifslastp->next;
4830 while (ifslastp->next != NULL) {
4831 struct ifsregion *ifsp;
4833 ifsp = ifslastp->next->next;
4834 ckfree(ifslastp->next);
4835 ifslastp->next = ifsp;
4838 if (ifslastp->endoff > endoff)
4839 ifslastp->endoff = endoff;
4843 #ifdef CONFIG_ASH_MATH_SUPPORT
4845 * Expand arithmetic expression. Backup to start of expression,
4846 * evaluate, place result in (backed up) result, adjust string position.
4859 * This routine is slightly over-complicated for
4860 * efficiency. Next we scan backwards looking for the
4861 * start of arithmetic.
4863 start = stackblock();
4870 while (*p != CTLARI) {
4874 error("missing CTLARI (shouldn't happen)");
4879 esc = esclen(start, p);
4889 removerecordregions(begoff);
4898 len = cvtnum(dash_arith(p + 2));
4901 recordregion(begoff, begoff + len, 0);
4906 * Expand stuff in backwards quotes.
4910 expbackq(union node *cmd, int quoted, int quotes)
4918 int syntax = quoted? DQSYNTAX : BASESYNTAX;
4919 struct stackmark smark;
4922 setstackmark(&smark);
4924 startloc = dest - (char *)stackblock();
4926 evalbackcmd(cmd, (struct backcmd *) &in);
4927 popstackmark(&smark);
4934 memtodest(p, i, syntax, quotes);
4938 i = safe_read(in.fd, buf, sizeof buf);
4939 TRACE(("expbackq: read returns %d\n", i));
4949 back_exitstatus = waitforjob(in.jp);
4953 /* Eat all trailing newlines */
4955 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
4960 recordregion(startloc, dest - (char *)stackblock(), 0);
4961 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4962 (dest - (char *)stackblock()) - startloc,
4963 (dest - (char *)stackblock()) - startloc,
4964 stackblock() + startloc));
4969 scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
4980 const char *s = loc2;
4986 match = pmatch(str, s);
4990 if (quotes && *loc == CTLESC)
5000 scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5007 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5010 const char *s = loc2;
5015 match = pmatch(str, s);
5022 esc = esclen(startp, loc);
5034 subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
5038 int saveherefd = herefd;
5039 struct nodelist *saveargbackq = argbackq;
5041 char *rmesc, *rmescend;
5043 char *(*scan)(char *, char *, char *, char *, int , int);
5046 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
5047 STPUTC('\0', expdest);
5048 herefd = saveherefd;
5049 argbackq = saveargbackq;
5050 startp = stackblock() + startloc;
5054 setvar(str, startp, 0);
5055 amount = startp - expdest;
5056 STADJUST(amount, expdest);
5060 varunset(p, str, startp, varflags);
5064 subtype -= VSTRIMRIGHT;
5066 if (subtype < 0 || subtype > 3)
5071 rmescend = stackblock() + strloc;
5073 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5074 if (rmesc != startp) {
5076 startp = stackblock() + startloc;
5080 str = stackblock() + strloc;
5081 preglob(str, varflags & VSQUOTE, 0);
5083 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
5084 zero = subtype >> 1;
5085 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
5086 scan = (subtype & 1) ^ zero ? scanleft : scanright;
5088 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
5091 memmove(startp, loc, str - loc);
5092 loc = startp + (str - loc) - 1;
5095 amount = loc - expdest;
5096 STADJUST(amount, expdest);
5103 * Expand a variable, and return a pointer to the next character in the
5107 evalvar(char *p, int flag)
5120 quotes = flag & (EXP_FULL | EXP_CASE);
5122 subtype = varflags & VSTYPE;
5123 quoted = varflags & VSQUOTE;
5125 easy = (!quoted || (*var == '@' && shellparam.nparam));
5126 startloc = expdest - (char *)stackblock();
5127 p = strchr(p, '=') + 1;
5130 varlen = varvalue(var, varflags, flag);
5131 if (varflags & VSNUL)
5134 if (subtype == VSPLUS) {
5135 varlen = -1 - varlen;
5139 if (subtype == VSMINUS) {
5143 p, flag | EXP_TILDE |
5144 (quoted ? EXP_QWORD : EXP_WORD)
5153 if (subtype == VSASSIGN || subtype == VSQUESTION) {
5155 if (subevalvar(p, var, 0, subtype, startloc,
5159 * Remove any recorded regions beyond
5162 removerecordregions(startloc);
5172 if (varlen < 0 && uflag)
5173 varunset(p, var, 0, 0);
5175 if (subtype == VSLENGTH) {
5176 cvtnum(varlen > 0 ? varlen : 0);
5180 if (subtype == VSNORMAL) {
5184 recordregion(startloc, expdest - (char *)stackblock(), quoted);
5193 case VSTRIMRIGHTMAX:
5202 * Terminate the string and start recording the pattern
5205 STPUTC('\0', expdest);
5206 patloc = expdest - (char *)stackblock();
5207 if (subevalvar(p, NULL, patloc, subtype,
5208 startloc, varflags, quotes) == 0) {
5209 int amount = expdest - (
5210 (char *)stackblock() + patloc - 1
5212 STADJUST(-amount, expdest);
5214 /* Remove any recorded regions beyond start of variable */
5215 removerecordregions(startloc);
5220 if (subtype != VSNORMAL) { /* skip to end of alternative */
5223 if ((c = *p++) == CTLESC)
5225 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
5227 argbackq = argbackq->next;
5228 } else if (c == CTLVAR) {
5229 if ((*p++ & VSTYPE) != VSNORMAL)
5231 } else if (c == CTLENDVAR) {
5242 * Put a string on the stack.
5246 memtodest(const char *p, size_t len, int syntax, int quotes) {
5249 q = makestrspace(len * 2, q);
5255 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5265 strtodest(const char *p, int syntax, int quotes)
5267 memtodest(p, strlen(p), syntax, quotes);
5272 * Add the value of a specialized variable to the stack string.
5276 varvalue(char *name, int varflags, int flags)
5286 int quoted = varflags & VSQUOTE;
5287 int subtype = varflags & VSTYPE;
5288 int quotes = flags & (EXP_FULL | EXP_CASE);
5290 if (quoted && (flags & EXP_FULL))
5291 sep = 1 << CHAR_BIT;
5293 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5302 num = shellparam.nparam;
5312 p = makestrspace(NOPTS, expdest);
5313 for (i = NOPTS - 1; i >= 0; i--) {
5315 USTPUTC(optletters(i), p);
5326 sep = ifsset() ? ifsval()[0] : ' ';
5327 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
5330 if (!(ap = shellparam.p))
5332 while ((p = *ap++)) {
5335 partlen = strlen(p);
5338 if (len > partlen && sep) {
5342 if (subtype == VSPLUS || subtype == VSLENGTH) {
5352 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5353 memtodest(p, partlen, syntax, quotes);
5367 if (num < 0 || num > shellparam.nparam)
5369 p = num ? shellparam.p[num - 1] : arg0;
5372 p = lookupvar(name);
5378 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5379 memtodest(p, len, syntax, quotes);
5383 if (subtype == VSPLUS || subtype == VSLENGTH)
5384 STADJUST(-len, expdest);
5390 * Record the fact that we have to scan this region of the
5391 * string for IFS characters.
5395 recordregion(int start, int end, int nulonly)
5397 struct ifsregion *ifsp;
5399 if (ifslastp == NULL) {
5403 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
5405 ifslastp->next = ifsp;
5409 ifslastp->begoff = start;
5410 ifslastp->endoff = end;
5411 ifslastp->nulonly = nulonly;
5416 * Break the argument string into pieces based upon IFS and add the
5417 * strings to the argument list. The regions of the string to be
5418 * searched for IFS characters have been stored by recordregion.
5421 ifsbreakup(char *string, struct arglist *arglist)
5423 struct ifsregion *ifsp;
5428 const char *ifs, *realifs;
5434 if (ifslastp != NULL) {
5437 realifs = ifsset() ? ifsval() : defifs;
5440 p = string + ifsp->begoff;
5441 nulonly = ifsp->nulonly;
5442 ifs = nulonly ? nullstr : realifs;
5444 while (p < string + ifsp->endoff) {
5448 if (strchr(ifs, *p)) {
5450 ifsspc = (strchr(defifs, *p) != NULL);
5451 /* Ignore IFS whitespace at start */
5452 if (q == start && ifsspc) {
5458 sp = (struct strlist *)stalloc(sizeof *sp);
5460 *arglist->lastp = sp;
5461 arglist->lastp = &sp->next;
5465 if (p >= string + ifsp->endoff) {
5471 if (strchr(ifs, *p) == NULL ) {
5474 } else if (strchr(defifs, *p) == NULL) {
5490 } while ((ifsp = ifsp->next) != NULL);
5499 sp = (struct strlist *)stalloc(sizeof *sp);
5501 *arglist->lastp = sp;
5502 arglist->lastp = &sp->next;
5508 struct ifsregion *p;
5513 struct ifsregion *ifsp;
5519 ifsfirst.next = NULL;
5523 static void expmeta(char *, char *);
5524 static struct strlist *expsort(struct strlist *);
5525 static struct strlist *msort(struct strlist *, int);
5527 static char *expdir;
5531 expandmeta(struct strlist *str, int flag)
5533 static const char metachars[] = {
5536 /* TODO - EXP_REDIR */
5539 struct strlist **savelastp;
5545 if (!strpbrk(str->text, metachars))
5547 savelastp = exparg.lastp;
5550 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
5552 int i = strlen(str->text);
5553 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5561 if (exparg.lastp == savelastp) {
5566 *exparg.lastp = str;
5567 rmescapes(str->text);
5568 exparg.lastp = &str->next;
5570 *exparg.lastp = NULL;
5571 *savelastp = sp = expsort(*savelastp);
5572 while (sp->next != NULL)
5574 exparg.lastp = &sp->next;
5581 * Add a file name to the list.
5585 addfname(const char *name)
5589 sp = (struct strlist *)stalloc(sizeof *sp);
5590 sp->text = sstrdup(name);
5592 exparg.lastp = &sp->next;
5597 * Do metacharacter (i.e. *, ?, [...]) expansion.
5601 expmeta(char *enddir, char *name)
5616 for (p = name; *p; p++) {
5617 if (*p == '*' || *p == '?')
5619 else if (*p == '[') {
5626 if (*q == '/' || *q == '\0')
5633 } else if (*p == '\\')
5635 else if (*p == '/') {
5642 if (metaflag == 0) { /* we've reached the end of the file name */
5643 if (enddir != expdir)
5651 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
5662 } while (p < start);
5664 if (enddir == expdir) {
5666 } else if (enddir == expdir + 1 && *expdir == '/') {
5672 if ((dirp = opendir(cp)) == NULL)
5674 if (enddir != expdir)
5676 if (*endname == 0) {
5688 while (! intpending && (dp = readdir(dirp)) != NULL) {
5689 if (dp->d_name[0] == '.' && ! matchdot)
5691 if (pmatch(start, dp->d_name)) {
5693 scopy(dp->d_name, enddir);
5696 for (p = enddir, cp = dp->d_name;
5697 (*p++ = *cp++) != '\0';)
5700 expmeta(p, endname);
5710 * Sort the results of file name expansion. It calculates the number of
5711 * strings to sort and then calls msort (short for merge sort) to do the
5715 static struct strlist *
5716 expsort(struct strlist *str)
5722 for (sp = str ; sp ; sp = sp->next)
5724 return msort(str, len);
5728 static struct strlist *
5729 msort(struct strlist *list, int len)
5731 struct strlist *p, *q = NULL;
5732 struct strlist **lpp;
5740 for (n = half ; --n >= 0 ; ) {
5744 q->next = NULL; /* terminate first half of list */
5745 q = msort(list, half); /* sort first half of list */
5746 p = msort(p, len - half); /* sort second half */
5749 #ifdef CONFIG_LOCALE_SUPPORT
5750 if (strcoll(p->text, q->text) < 0)
5752 if (strcmp(p->text, q->text) < 0)
5757 if ((p = *lpp) == NULL) {
5764 if ((q = *lpp) == NULL) {
5775 * Returns true if the pattern matches the string.
5779 patmatch(char *pattern, const char *string)
5781 return pmatch(preglob(pattern, 0, 0), string);
5786 * Remove any CTLESC characters from a string.
5790 _rmescapes(char *str, int flag)
5793 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
5798 p = strpbrk(str, qchars);
5804 if (flag & RMESCAPE_ALLOC) {
5805 size_t len = p - str;
5806 size_t fulllen = len + strlen(p) + 1;
5808 if (flag & RMESCAPE_GROW) {
5809 r = makestrspace(fulllen, expdest);
5810 } else if (flag & RMESCAPE_HEAP) {
5811 r = ckmalloc(fulllen);
5813 r = stalloc(fulllen);
5817 q = mempcpy(q, str, len);
5820 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5821 globbing = flag & RMESCAPE_GLOB;
5822 notescaped = globbing;
5824 if (*p == CTLQUOTEMARK) {
5825 inquotes = ~inquotes;
5827 notescaped = globbing;
5831 /* naked back slash */
5837 if (notescaped && inquotes && *p != '/') {
5841 notescaped = globbing;
5846 if (flag & RMESCAPE_GROW) {
5848 STADJUST(q - r + 1, expdest);
5855 * See if a pattern matches in a case statement.
5859 casematch(union node *pattern, char *val)
5861 struct stackmark smark;
5864 setstackmark(&smark);
5865 argbackq = pattern->narg.backquote;
5866 STARTSTACKSTR(expdest);
5868 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
5869 STACKSTRNUL(expdest);
5870 result = patmatch(stackblock(), val);
5871 popstackmark(&smark);
5884 expdest = makestrspace(32, expdest);
5885 len = fmtstr(expdest, 32, "%ld", num);
5886 STADJUST(len, expdest);
5891 varunset(const char *end, const char *var, const char *umsg, int varflags)
5897 msg = "parameter not set";
5899 if (*end == CTLENDVAR) {
5900 if (varflags & VSNUL)
5905 error("%.*s: %s%s", end - var - 1, var, msg, tail);
5909 /* $NetBSD: input.c,v 1.37 2002/11/24 22:35:40 christos Exp $ */
5912 * This implements the input routines used by the parser.
5915 #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
5916 #define IBUFSIZ (BUFSIZ + 1)
5918 static void pushfile(void);
5921 * Read a line from the script.
5924 static inline char *
5925 pfgets(char *line, int len)
5931 while (--nleft > 0) {
5948 * Read a character from the script, returning PEOF on end of file.
5949 * Nul characters in the input are silently discarded.
5952 #define pgetc_as_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
5954 #ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
5955 #define pgetc_macro() pgetc()
5959 return pgetc_as_macro();
5962 #define pgetc_macro() pgetc_as_macro()
5966 return pgetc_macro();
5972 * Same as pgetc(), but ignores PEOA.
5974 #ifdef CONFIG_ASH_ALIAS
5975 static int pgetc2(void)
5981 } while (c == PEOA);
5985 static inline int pgetc2(void)
5987 return pgetc_macro();
5992 #ifdef CONFIG_FEATURE_COMMAND_EDITING
5993 static const char *cmdedit_prompt;
5994 static inline void putprompt(const char *s)
5999 static inline void putprompt(const char *s)
6009 char *buf = parsefile->buf;
6013 #ifdef CONFIG_FEATURE_COMMAND_EDITING
6014 if (!iflag || parsefile->fd)
6015 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6017 nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
6019 /* Ctrl+C presend */
6024 /* Ctrl+D presend */
6029 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6033 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6034 int flags = fcntl(0, F_GETFL, 0);
6035 if (flags >= 0 && flags & O_NONBLOCK) {
6036 flags &=~ O_NONBLOCK;
6037 if (fcntl(0, F_SETFL, flags) >= 0) {
6038 out2str("sh: turning off NDELAY mode\n");
6048 * Refill the input buffer and return the next input character:
6050 * 1) If a string was pushed back on the input, pop it;
6051 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6052 * from a string so we can't refill the buffer, return EOF.
6053 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6054 * 4) Process input up to the next newline, deleting nul characters.
6064 while (parsefile->strpush) {
6065 #ifdef CONFIG_ASH_ALIAS
6066 if (parsenleft == -1 && parsefile->strpush->ap &&
6067 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
6072 if (--parsenleft >= 0)
6073 return (*parsenextc++);
6075 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6080 if (parselleft <= 0) {
6081 if ((parselleft = preadfd()) <= 0) {
6082 parselleft = parsenleft = EOF_NLEFT;
6089 /* delete nul characters */
6090 for (more = 1; more;) {
6097 parsenleft = q - parsenextc;
6098 more = 0; /* Stop processing here */
6105 if (--parselleft <= 0 && more) {
6106 parsenleft = q - parsenextc - 1;
6117 out2str(parsenextc);
6122 return *parsenextc++;
6126 * Undo the last call to pgetc. Only one character may be pushed back.
6127 * PEOF may be pushed back.
6138 * Push a string back onto the input at this current parsefile level.
6139 * We handle aliases this way.
6142 pushstring(char *s, void *ap)
6149 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6150 if (parsefile->strpush) {
6151 sp = ckmalloc(sizeof (struct strpush));
6152 sp->prev = parsefile->strpush;
6153 parsefile->strpush = sp;
6155 sp = parsefile->strpush = &(parsefile->basestrpush);
6156 sp->prevstring = parsenextc;
6157 sp->prevnleft = parsenleft;
6158 #ifdef CONFIG_ASH_ALIAS
6159 sp->ap = (struct alias *)ap;
6161 ((struct alias *)ap)->flag |= ALIASINUSE;
6173 struct strpush *sp = parsefile->strpush;
6176 #ifdef CONFIG_ASH_ALIAS
6178 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6179 checkkwd |= CHKALIAS;
6181 if (sp->string != sp->ap->val) {
6184 sp->ap->flag &= ~ALIASINUSE;
6185 if (sp->ap->flag & ALIASDEAD) {
6186 unalias(sp->ap->name);
6190 parsenextc = sp->prevstring;
6191 parsenleft = sp->prevnleft;
6192 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6193 parsefile->strpush = sp->prev;
6194 if (sp != &(parsefile->basestrpush))
6200 * Set the input to take input from a file. If push is set, push the
6201 * old input onto the stack first.
6205 setinputfile(const char *fname, int push)
6211 if ((fd = open(fname, O_RDONLY)) < 0)
6212 error("Can't open %s", fname);
6214 fd2 = copyfd(fd, 10);
6217 error("Out of file descriptors");
6220 setinputfd(fd, push);
6226 * Like setinputfile, but takes an open file descriptor. Call this with
6231 setinputfd(int fd, int push)
6233 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
6239 if (parsefile->buf == NULL)
6240 parsefile->buf = ckmalloc(IBUFSIZ);
6241 parselleft = parsenleft = 0;
6247 * Like setinputfile, but takes input from a string.
6251 setinputstring(char *string)
6255 parsenextc = string;
6256 parsenleft = strlen(string);
6257 parsefile->buf = NULL;
6264 * To handle the "." command, a stack of input files is used. Pushfile
6265 * adds a new entry to the stack and popfile restores the previous level.
6271 struct parsefile *pf;
6273 parsefile->nleft = parsenleft;
6274 parsefile->lleft = parselleft;
6275 parsefile->nextc = parsenextc;
6276 parsefile->linno = plinno;
6277 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
6278 pf->prev = parsefile;
6281 pf->basestrpush.prev = NULL;
6289 struct parsefile *pf = parsefile;
6298 parsefile = pf->prev;
6300 parsenleft = parsefile->nleft;
6301 parselleft = parsefile->lleft;
6302 parsenextc = parsefile->nextc;
6303 plinno = parsefile->linno;
6309 * Return to top level.
6315 while (parsefile != &basepf)
6321 * Close the file(s) that the shell is reading commands from. Called
6322 * after a fork is done.
6329 if (parsefile->fd > 0) {
6330 close(parsefile->fd);
6335 /* $NetBSD: jobs.c,v 1.56 2002/11/25 12:13:03 agc Exp $ */
6337 /* mode flags for set_curjob */
6338 #define CUR_DELETE 2
6339 #define CUR_RUNNING 1
6340 #define CUR_STOPPED 0
6342 /* mode flags for dowait */
6343 #define DOWAIT_NORMAL 0
6344 #define DOWAIT_BLOCK 1
6347 static struct job *jobtab;
6349 static unsigned njobs;
6351 /* pgrp of shell on invocation */
6352 static int initialpgrp;
6353 static int ttyfd = -1;
6356 static struct job *curjob;
6357 /* number of presumed living untracked jobs */
6360 static void set_curjob(struct job *, unsigned);
6362 static int restartjob(struct job *, int);
6363 static void xtcsetpgrp(int, pid_t);
6364 static char *commandtext(union node *);
6365 static void cmdlist(union node *, int);
6366 static void cmdtxt(union node *);
6367 static void cmdputs(const char *);
6368 static void showpipe(struct job *, FILE *);
6370 static int sprint_status(char *, int, int);
6371 static void freejob(struct job *);
6372 static struct job *getjob(const char *, int);
6373 static struct job *growjobtab(void);
6374 static void forkchild(struct job *, union node *, int);
6375 static void forkparent(struct job *, union node *, int, pid_t);
6376 static int dowait(int, struct job *);
6377 static int getstatus(struct job *);
6380 set_curjob(struct job *jp, unsigned mode)
6383 struct job **jpp, **curp;
6385 /* first remove from list */
6386 jpp = curp = &curjob;
6391 jpp = &jp1->prev_job;
6393 *jpp = jp1->prev_job;
6395 /* Then re-insert in correct position */
6403 /* job being deleted */
6406 /* newly created job or backgrounded job,
6407 put after all stopped jobs. */
6411 if (!jp1 || jp1->state != JOBSTOPPED)
6414 jpp = &jp1->prev_job;
6420 /* newly stopped job - becomes curjob */
6421 jp->prev_job = *jpp;
6429 * Turn job control on and off.
6431 * Note: This code assumes that the third arg to ioctl is a character
6432 * pointer, which is true on Berkeley systems but not System V. Since
6433 * System V doesn't have job control yet, this isn't a problem now.
6435 * Called with interrupts off.
6444 if (on == jobctl || rootshell == 0)
6448 ofd = fd = open(_PATH_TTY, O_RDWR);
6451 while (!isatty(fd) && --fd >= 0)
6454 fd = fcntl(fd, F_DUPFD, 10);
6458 fcntl(fd, F_SETFD, FD_CLOEXEC);
6459 do { /* while we are in the background */
6460 if ((pgrp = tcgetpgrp(fd)) < 0) {
6462 sh_warnx("can't access tty; job control turned off");
6466 if (pgrp == getpgrp())
6477 xtcsetpgrp(fd, pgrp);
6479 /* turning job control off */
6482 xtcsetpgrp(fd, pgrp);
6496 killcmd(int argc, char **argv)
6507 "Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6508 "kill -l [exitstatus]"
6512 if (**++argv == '-') {
6513 signo = decode_signal(*argv + 1, 1);
6517 while ((c = nextopt("ls:")) != '\0')
6527 signo = decode_signal(optionarg, 1);
6530 "invalid signal number or name: %s",
6541 if (!list && signo < 0)
6544 if ((signo < 0 || !*argv) ^ list) {
6552 for (i = 1; i < NSIG; i++) {
6553 name = u_signal_names(0, &i, 1);
6555 out1fmt(snlfmt, name);
6559 name = u_signal_names(*argptr, &signo, -1);
6561 out1fmt(snlfmt, name);
6563 error("invalid signal number or exit status: %s", *argptr);
6569 if (**argv == '%') {
6570 jp = getjob(*argv, 0);
6571 pid = -jp->ps[0].pid;
6573 pid = number(*argv);
6574 if (kill(pid, signo) != 0) {
6584 #if defined(JOBS) || defined(DEBUG)
6586 jobno(const struct job *jp)
6588 return jp - jobtab + 1;
6594 fgcmd(int argc, char **argv)
6601 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
6606 jp = getjob(*argv, 1);
6607 if (mode == FORK_BG) {
6608 set_curjob(jp, CUR_RUNNING);
6609 fprintf(out, "[%d] ", jobno(jp));
6611 outstr(jp->ps->cmd, out);
6613 retval = restartjob(jp, mode);
6614 } while (*argv && *++argv);
6618 static int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
6622 restartjob(struct job *jp, int mode)
6624 struct procstat *ps;
6630 if (jp->state == JOBDONE)
6632 jp->state = JOBRUNNING;
6634 if (mode == FORK_FG)
6635 xtcsetpgrp(ttyfd, pgid);
6636 killpg(pgid, SIGCONT);
6640 if (WIFSTOPPED(ps->status)) {
6643 } while (ps++, --i);
6645 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
6652 sprint_status(char *s, int status, int sigonly)
6658 if (!WIFEXITED(status)) {
6660 if (WIFSTOPPED(status))
6661 st = WSTOPSIG(status);
6664 st = WTERMSIG(status);
6666 if (st == SIGINT || st == SIGPIPE)
6669 if (WIFSTOPPED(status))
6674 col = fmtstr(s, 32, strsignal(st));
6675 if (WCOREDUMP(status)) {
6676 col += fmtstr(s + col, 16, " (core dumped)");
6678 } else if (!sigonly) {
6679 st = WEXITSTATUS(status);
6681 col = fmtstr(s, 16, "Done(%d)", st);
6683 col = fmtstr(s, 16, "Done");
6692 showjob(FILE *out, struct job *jp, int mode)
6694 struct procstat *ps;
6695 struct procstat *psend;
6702 if (mode & SHOW_PGID) {
6703 /* just output process (group) id of pipeline */
6704 fprintf(out, "%d\n", ps->pid);
6708 col = fmtstr(s, 16, "[%d] ", jobno(jp));
6713 else if (curjob && jp == curjob->prev_job)
6716 if (mode & SHOW_PID)
6717 col += fmtstr(s + col, 16, "%d ", ps->pid);
6719 psend = ps + jp->nprocs;
6721 if (jp->state == JOBRUNNING) {
6722 scopy("Running", s + col);
6723 col += strlen("Running");
6725 int status = psend[-1].status;
6727 if (jp->state == JOBSTOPPED)
6728 status = jp->stopstatus;
6730 col += sprint_status(s + col, status, 0);
6736 /* for each process */
6737 col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
6740 fprintf(out, "%s%*c%s",
6741 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
6743 if (!(mode & SHOW_PID)) {
6747 if (++ps == psend) {
6748 outcslow('\n', out);
6755 if (jp->state == JOBDONE) {
6756 TRACE(("showjob: freeing job %d\n", jobno(jp)));
6763 jobscmd(int argc, char **argv)
6769 while ((m = nextopt("lp")))
6779 showjob(out, getjob(*argv,0), mode);
6782 showjobs(out, mode);
6789 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6790 * statuses have changed since the last call to showjobs.
6794 showjobs(FILE *out, int mode)
6798 TRACE(("showjobs(%x) called\n", mode));
6800 /* If not even one one job changed, there is nothing to do */
6801 while (dowait(DOWAIT_NORMAL, NULL) > 0)
6804 for (jp = curjob; jp; jp = jp->prev_job) {
6805 if (!(mode & SHOW_CHANGED) || jp->changed)
6806 showjob(out, jp, mode);
6812 * Mark a job structure as unused.
6816 freejob(struct job *jp)
6818 struct procstat *ps;
6822 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
6823 if (ps->cmd != nullstr)
6826 if (jp->ps != &jp->ps0)
6829 set_curjob(jp, CUR_DELETE);
6835 waitcmd(int argc, char **argv)
6848 /* wait for all jobs */
6853 /* no running procs */
6856 if (jp->state == JOBRUNNING)
6861 dowait(DOWAIT_BLOCK, 0);
6867 if (**argv != '%') {
6868 pid_t pid = number(*argv);
6872 if (job->ps[job->nprocs - 1].pid == pid)
6874 job = job->prev_job;
6880 job = getjob(*argv, 0);
6881 /* loop until process terminated or stopped */
6882 while (job->state == JOBRUNNING)
6883 dowait(DOWAIT_BLOCK, 0);
6885 retval = getstatus(job);
6896 * Convert a job name to a job structure.
6900 getjob(const char *name, int getctl)
6904 const char *err_msg = "No such job: %s";
6908 char *(*match)(const char *, const char *);
6923 if (c == '+' || c == '%') {
6925 err_msg = "No current job";
6927 } else if (c == '-') {
6930 err_msg = "No previous job";
6941 jp = jobtab + num - 1;
6958 if (match(jp->ps[0].cmd, p)) {
6962 err_msg = "%s: ambiguous";
6969 err_msg = "job %s not created under job control";
6970 if (getctl && jp->jobctl == 0)
6975 error(err_msg, name);
6980 * Return a new job structure.
6981 * Called with interrupts off.
6985 makejob(union node *node, int nprocs)
6990 for (i = njobs, jp = jobtab ; ; jp++) {
6997 if (jp->state != JOBDONE || !jp->waited)
7006 memset(jp, 0, sizeof(*jp));
7011 jp->prev_job = curjob;
7016 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
7018 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
7028 struct job *jp, *jq;
7030 len = njobs * sizeof(*jp);
7032 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
7034 offset = (char *)jp - (char *)jq;
7036 /* Relocate pointers */
7039 jq = (struct job *)((char *)jq + l);
7043 #define joff(p) ((struct job *)((char *)(p) + l))
7044 #define jmove(p) (p) = (void *)((char *)(p) + offset)
7045 if (likely(joff(jp)->ps == &jq->ps0))
7046 jmove(joff(jp)->ps);
7047 if (joff(jp)->prev_job)
7048 jmove(joff(jp)->prev_job);
7058 jp = (struct job *)((char *)jp + len);
7062 } while (--jq >= jp);
7068 * Fork off a subshell. If we are doing job control, give the subshell its
7069 * own process group. Jp is a job structure that the job is to be added to.
7070 * N is the command that will be evaluated by the child. Both jp and n may
7071 * be NULL. The mode parameter can be one of the following:
7072 * FORK_FG - Fork off a foreground process.
7073 * FORK_BG - Fork off a background process.
7074 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
7075 * process group even if job control is on.
7077 * When job control is turned off, background processes have their standard
7078 * input redirected to /dev/null (except for the second and later processes
7081 * Called with interrupts off.
7085 forkchild(struct job *jp, union node *n, int mode)
7089 TRACE(("Child shell %d\n", getpid()));
7090 wasroot = rootshell;
7096 /* do job control only in root shell */
7098 if (mode != FORK_NOJOB && jp->jobctl && wasroot) {
7101 if (jp->nprocs == 0)
7104 pgrp = jp->ps[0].pid;
7105 /* This can fail because we are doing it in the parent also */
7106 (void)setpgid(0, pgrp);
7107 if (mode == FORK_FG)
7108 xtcsetpgrp(ttyfd, pgrp);
7113 if (mode == FORK_BG) {
7116 if (jp->nprocs == 0) {
7118 if (open(_PATH_DEVNULL, O_RDONLY) != 0)
7119 error("Can't open %s", _PATH_DEVNULL);
7122 if (wasroot && iflag) {
7127 for (jp = curjob; jp; jp = jp->prev_job)
7133 forkparent(struct job *jp, union node *n, int mode, pid_t pid)
7135 TRACE(("In parent shell: child = %d\n", pid));
7137 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
7142 if (mode != FORK_NOJOB && jp->jobctl) {
7145 if (jp->nprocs == 0)
7148 pgrp = jp->ps[0].pid;
7149 /* This can fail because we are doing it in the child also */
7150 (void)setpgid(pid, pgrp);
7153 if (mode == FORK_BG) {
7154 backgndpid = pid; /* set $! */
7155 set_curjob(jp, CUR_RUNNING);
7158 struct procstat *ps = &jp->ps[jp->nprocs++];
7164 ps->cmd = commandtext(n);
7170 forkshell(struct job *jp, union node *n, int mode)
7174 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
7177 TRACE(("Fork failed, errno=%d", errno));
7180 error("Cannot fork");
7183 forkchild(jp, n, mode);
7185 forkparent(jp, n, mode, pid);
7190 * Wait for job to finish.
7192 * Under job control we have the problem that while a child process is
7193 * running interrupts generated by the user are sent to the child but not
7194 * to the shell. This means that an infinite loop started by an inter-
7195 * active user may be hard to kill. With job control turned off, an
7196 * interactive user may place an interactive program inside a loop. If
7197 * the interactive program catches interrupts, the user doesn't want
7198 * these interrupts to also abort the loop. The approach we take here
7199 * is to have the shell ignore interrupt signals while waiting for a
7200 * forground process to terminate, and then send itself an interrupt
7201 * signal if the child process was terminated by an interrupt signal.
7202 * Unfortunately, some programs want to do a bit of cleanup and then
7203 * exit on interrupt; unless these processes terminate themselves by
7204 * sending a signal to themselves (instead of calling exit) they will
7205 * confuse this approach.
7207 * Called with interrupts off.
7211 waitforjob(struct job *jp)
7215 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
7216 while (jp->state == JOBRUNNING) {
7217 dowait(DOWAIT_BLOCK, jp);
7222 xtcsetpgrp(ttyfd, rootpid);
7224 * This is truly gross.
7225 * If we're doing job control, then we did a TIOCSPGRP which
7226 * caused us (the shell) to no longer be in the controlling
7227 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7228 * intuit from the subprocess exit status whether a SIGINT
7229 * occurred, and if so interrupt ourselves. Yuck. - mycroft
7234 if (jp->state == JOBDONE)
7242 * Do a wait system call. If job control is compiled in, we accept
7243 * stopped processes. If block is zero, we return a value of zero
7244 * rather than blocking.
7246 * System V doesn't have a non-blocking wait system call. It does
7247 * have a SIGCLD signal that is sent to a process when one of it's
7248 * children dies. The obvious way to use SIGCLD would be to install
7249 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7250 * was received, and have waitproc bump another counter when it got
7251 * the status of a process. Waitproc would then know that a wait
7252 * system call would not block if the two counters were different.
7253 * This approach doesn't work because if a process has children that
7254 * have not been waited for, System V will send it a SIGCLD when it
7255 * installs a signal handler for SIGCLD. What this means is that when
7256 * a child exits, the shell will be sent SIGCLD signals continuously
7257 * until is runs out of stack space, unless it does a wait call before
7258 * restoring the signal handler. The code below takes advantage of
7259 * this (mis)feature by installing a signal handler for SIGCLD and
7260 * then checking to see whether it was called. If there are any
7261 * children to be waited for, it will be.
7263 * If neither SYSV nor BSD is defined, we don't implement nonblocking
7264 * waits at all. In this case, the user will not be informed when
7265 * a background process until the next time she runs a real program
7266 * (as opposed to running a builtin command or just typing return),
7267 * and the jobs command may give out of date information.
7271 waitproc(int block, int *status)
7281 return wait3(status, flags, (struct rusage *)NULL);
7285 * Wait for a process to terminate.
7289 dowait(int block, struct job *job)
7294 struct job *thisjob;
7297 TRACE(("dowait(%d) called\n", block));
7298 pid = waitproc(block, &status);
7299 TRACE(("wait returns pid %d, status=%d\n", pid, status));
7304 for (jp = curjob; jp; jp = jp->prev_job) {
7305 struct procstat *sp;
7306 struct procstat *spend;
7307 if (jp->state == JOBDONE)
7310 spend = jp->ps + jp->nprocs;
7313 if (sp->pid == pid) {
7314 TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
7315 sp->status = status;
7318 if (sp->status == -1)
7321 if (state == JOBRUNNING)
7323 if (WIFSTOPPED(sp->status)) {
7324 jp->stopstatus = sp->status;
7328 } while (++sp < spend);
7333 if (!WIFSTOPPED(status))
7340 if (state != JOBRUNNING) {
7341 thisjob->changed = 1;
7343 if (thisjob->state != state) {
7344 TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
7345 thisjob->state = state;
7347 if (state == JOBSTOPPED) {
7348 set_curjob(thisjob, CUR_STOPPED);
7357 if (thisjob && thisjob == job) {
7361 len = sprint_status(s, status, 1);
7373 * return 1 if there are stopped jobs, otherwise 0
7386 if (jp && jp->state == JOBSTOPPED) {
7387 out2str("You have stopped jobs.\n");
7397 * Return a string identifying a command (to be printed by the
7402 static char *cmdnextc;
7405 commandtext(union node *n)
7409 STARTSTACKSTR(cmdnextc);
7411 name = stackblock();
7412 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
7413 name, cmdnextc, cmdnextc));
7414 return savestr(name);
7418 cmdtxt(union node *n)
7421 struct nodelist *lp;
7431 lp = n->npipe.cmdlist;
7449 cmdtxt(n->nbinary.ch1);
7465 cmdtxt(n->nif.test);
7468 if (n->nif.elsepart) {
7471 n = n->nif.elsepart;
7487 cmdtxt(n->nbinary.ch1);
7497 cmdputs(n->nfor.var);
7499 cmdlist(n->nfor.args, 1);
7504 cmdputs(n->narg.text);
7508 cmdlist(n->ncmd.args, 1);
7509 cmdlist(n->ncmd.redirect, 0);
7522 cmdputs(n->ncase.expr->narg.text);
7524 for (np = n->ncase.cases; np; np = np->nclist.next) {
7525 cmdtxt(np->nclist.pattern);
7527 cmdtxt(np->nclist.body);
7553 s[0] = n->nfile.fd + '0';
7557 if (n->type == NTOFD || n->type == NFROMFD) {
7558 s[0] = n->ndup.dupfd + '0';
7569 cmdlist(union node *np, int sep)
7571 for (; np; np = np->narg.next) {
7575 if (sep && np->narg.next)
7581 cmdputs(const char *s)
7583 const char *p, *str;
7584 char c, cc[2] = " ";
7588 static const char *const vstype[16] = {
7589 nullstr, "}", "-", "+", "?", "=",
7590 "#", "##", "%", "%%"
7593 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
7595 while ((c = *p++) != 0) {
7603 if ((subtype & VSTYPE) == VSLENGTH)
7607 if (!(subtype & VSQUOTE) != !(quoted & 1)) {
7625 case CTLBACKQ+CTLQUOTE:
7628 #ifdef CONFIG_ASH_MATH_SUPPORT
7643 str = vstype[subtype & VSTYPE];
7644 if (subtype & VSNUL)
7655 /* These can only happen inside quotes */
7667 while ((c = *str++)) {
7672 USTPUTC('"', nextc);
7680 showpipe(struct job *jp, FILE *out)
7682 struct procstat *sp;
7683 struct procstat *spend;
7685 spend = jp->ps + jp->nprocs;
7686 for (sp = jp->ps + 1; sp < spend; sp++)
7687 fprintf(out, " | %s", sp->cmd);
7688 outcslow('\n', out);
7693 xtcsetpgrp(int fd, pid_t pgrp)
7695 if (tcsetpgrp(fd, pgrp))
7696 error("Cannot set tty process group (%m)");
7701 getstatus(struct job *job) {
7705 status = job->ps[job->nprocs - 1].status;
7706 retval = WEXITSTATUS(status);
7707 if (!WIFEXITED(status)) {
7709 retval = WSTOPSIG(status);
7710 if (!WIFSTOPPED(status))
7713 /* XXX: limits number of signals */
7714 retval = WTERMSIG(status);
7716 if (retval == SIGINT)
7722 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
7723 jobno(job), job->nprocs, status, retval));
7727 #ifdef CONFIG_ASH_MAIL
7728 /* $NetBSD: mail.c,v 1.15 2002/11/24 22:35:40 christos Exp $ */
7731 * Routines to check for mail. (Perhaps make part of main.c?)
7734 #define MAXMBOXES 10
7736 /* times of mailboxes */
7737 static time_t mailtime[MAXMBOXES];
7738 /* Set if MAIL or MAILPATH is changed. */
7739 static int mail_var_path_changed;
7744 * Print appropriate message(s) if mail has arrived.
7745 * If mail_var_path_changed is set,
7746 * then the value of MAIL has mail_var_path_changed,
7747 * so we just update the values.
7757 struct stackmark smark;
7760 setstackmark(&smark);
7761 mpath = mpathset() ? mpathval() : mailval();
7762 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
7763 p = padvance(&mpath, nullstr);
7768 for (q = p ; *q ; q++);
7773 q[-1] = '\0'; /* delete trailing '/' */
7774 if (stat(p, &statb) < 0) {
7778 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
7781 pathopt ? pathopt : "you have mail"
7784 *mtp = statb.st_mtime;
7786 mail_var_path_changed = 0;
7787 popstackmark(&smark);
7792 changemail(const char *val)
7794 mail_var_path_changed++;
7797 #endif /* CONFIG_ASH_MAIL */
7799 /* $NetBSD: main.c,v 1.46 2002/12/11 19:12:18 christos Exp $ */
7803 static short profile_buf[16384];
7807 static int isloginsh;
7809 static void read_profile(const char *);
7812 * Main routine. We initialize things, parse the arguments, execute
7813 * profiles if we're a login shell, and then call cmdloop to execute
7814 * commands. The setjmp call sets up the location to jump to when an
7815 * exception occurs. When an exception occurs the variable "state"
7816 * is used to figure out how far we had gotten.
7820 ash_main(int argc, char **argv)
7824 struct jmploc jmploc;
7825 struct stackmark smark;
7828 dash_errno = __errno_location();
7832 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7835 if (setjmp(jmploc.loc)) {
7842 switch (exception) {
7852 status = exitstatus;
7855 exitstatus = status;
7857 if (e == EXEXIT || state == 0 || iflag == 0 || ! rootshell)
7861 outcslow('\n', stderr);
7863 popstackmark(&smark);
7864 FORCEINTON; /* enable interrupts */
7867 else if (state == 2)
7869 else if (state == 3)
7877 trputs("Shell args: "); trargs(argv);
7882 setstackmark(&smark);
7883 procargs(argc, argv);
7884 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7886 const char *hp = lookupvar("HISTFILE");
7889 hp = lookupvar("HOME");
7891 char *defhp = concat_path_file(hp, ".ash_history");
7892 setvar("HISTFILE", defhp, 0);
7898 if (argv[0] && argv[0][0] == '-')
7902 read_profile("/etc/profile");
7905 read_profile(".profile");
7911 getuid() == geteuid() && getgid() == getegid() &&
7915 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
7916 read_profile(shinit);
7924 if (sflag || minusc == NULL) {
7925 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7927 const char *hp = lookupvar("HISTFILE");
7930 load_history ( hp );
7933 state4: /* XXX ??? - why isn't this before the "if" statement */
7941 extern void _mcleanup(void);
7951 * Read and execute commands. "Top" is nonzero for the top level command
7952 * loop; it turns on prompting if the shell is interactive.
7959 struct stackmark smark;
7963 TRACE(("cmdloop(%d) called\n", top));
7965 setstackmark(&smark);
7970 showjobs(stderr, SHOW_CHANGED);
7975 #ifdef CONFIG_ASH_MAIL
7979 n = parsecmd(inter);
7980 /* showtree(n); DEBUG */
7982 if (!top || numeof >= 50)
7984 if (!stoppedjobs()) {
7987 out2str("\nUse \"exit\" to leave shell.\n");
7990 } else if (n != NULL && nflag == 0) {
7991 job_warning = (job_warning == 2) ? 1 : 0;
7995 popstackmark(&smark);
8005 * Read /etc/profile or .profile. Return on error.
8009 read_profile(const char *name)
8016 if ((fd = open(name, O_RDONLY)) >= 0)
8021 /* -q turns off -x and -v just when executing init files */
8024 xflag = 0, xflag_set = 1;
8026 vflag = 0, vflag_set = 1;
8040 * Read a file containing shell functions.
8044 readcmdfile(char *name)
8049 if ((fd = open(name, O_RDONLY)) >= 0)
8052 error("Can't open %s", name);
8060 * Take commands from a file. To be compatible we should do a path
8061 * search for the file, which is necessary to find sub-commands.
8064 static inline char *
8065 find_dot_file(char *name)
8068 const char *path = pathval();
8071 /* don't try this for absolute or relative paths */
8072 if (strchr(name, '/'))
8075 while ((fullname = padvance(&path, name)) != NULL) {
8076 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
8078 * Don't bother freeing here, since it will
8079 * be freed by the caller.
8083 stunalloc(fullname);
8086 /* not found in the PATH */
8087 error(not_found_msg, name);
8092 dotcmd(int argc, char **argv)
8096 if (argc >= 2) { /* That's what SVR2 does */
8098 struct stackmark smark;
8100 setstackmark(&smark);
8101 fullname = find_dot_file(argv[1]);
8102 setinputfile(fullname, 1);
8103 commandname = fullname;
8106 popstackmark(&smark);
8113 exitcmd(int argc, char **argv)
8118 exitstatus = number(argv[1]);
8123 /* $NetBSD: memalloc.c,v 1.27 2003/01/22 20:36:04 dsl Exp $ */
8126 * Same for malloc, realloc, but returns an error when out of space.
8130 ckrealloc(pointer p, size_t nbytes)
8132 p = realloc(p, nbytes);
8134 error(bb_msg_memory_exhausted);
8139 ckmalloc(size_t nbytes)
8141 return ckrealloc(NULL, nbytes);
8145 * Make a copy of a string in safe storage.
8149 savestr(const char *s)
8151 char *p = strdup(s);
8153 error(bb_msg_memory_exhausted);
8159 * Parse trees for commands are allocated in lifo order, so we use a stack
8160 * to make this more efficient, and also to avoid all sorts of exception
8161 * handling code to handle interrupts in the middle of a parse.
8163 * The size 504 was chosen because the Ultrix malloc handles that size
8169 stalloc(size_t nbytes)
8174 aligned = SHELL_ALIGN(nbytes);
8175 if (aligned > stacknleft) {
8178 struct stack_block *sp;
8180 blocksize = aligned;
8181 if (blocksize < MINSIZE)
8182 blocksize = MINSIZE;
8183 len = sizeof(struct stack_block) - MINSIZE + blocksize;
8184 if (len < blocksize)
8185 error(bb_msg_memory_exhausted);
8189 stacknxt = sp->space;
8190 stacknleft = blocksize;
8191 sstrend = stacknxt + blocksize;
8196 stacknxt += aligned;
8197 stacknleft -= aligned;
8203 stunalloc(pointer p)
8206 if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
8207 write(2, "stunalloc\n", 10);
8211 stacknleft += stacknxt - (char *)p;
8217 setstackmark(struct stackmark *mark)
8219 mark->stackp = stackp;
8220 mark->stacknxt = stacknxt;
8221 mark->stacknleft = stacknleft;
8222 mark->marknext = markp;
8228 popstackmark(struct stackmark *mark)
8230 struct stack_block *sp;
8233 markp = mark->marknext;
8234 while (stackp != mark->stackp) {
8239 stacknxt = mark->stacknxt;
8240 stacknleft = mark->stacknleft;
8241 sstrend = mark->stacknxt + mark->stacknleft;
8247 * When the parser reads in a string, it wants to stick the string on the
8248 * stack and only adjust the stack pointer when it knows how big the
8249 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8250 * of space on top of the stack and stackblocklen returns the length of
8251 * this block. Growstackblock will grow this space by at least one byte,
8252 * possibly moving it (like realloc). Grabstackblock actually allocates the
8253 * part of the block that has been used.
8257 growstackblock(void)
8261 newlen = stacknleft * 2;
8262 if (newlen < stacknleft)
8263 error(bb_msg_memory_exhausted);
8267 if (stacknxt == stackp->space && stackp != &stackbase) {
8268 struct stack_block *oldstackp;
8269 struct stackmark *xmark;
8270 struct stack_block *sp;
8271 struct stack_block *prevstackp;
8277 prevstackp = sp->prev;
8278 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
8279 sp = ckrealloc((pointer)sp, grosslen);
8280 sp->prev = prevstackp;
8282 stacknxt = sp->space;
8283 stacknleft = newlen;
8284 sstrend = sp->space + newlen;
8287 * Stack marks pointing to the start of the old block
8288 * must be relocated to point to the new block
8291 while (xmark != NULL && xmark->stackp == oldstackp) {
8292 xmark->stackp = stackp;
8293 xmark->stacknxt = stacknxt;
8294 xmark->stacknleft = stacknleft;
8295 xmark = xmark->marknext;
8299 char *oldspace = stacknxt;
8300 int oldlen = stacknleft;
8301 char *p = stalloc(newlen);
8303 /* free the space we just allocated */
8304 stacknxt = memcpy(p, oldspace, oldlen);
8305 stacknleft += newlen;
8310 grabstackblock(size_t len)
8312 len = SHELL_ALIGN(len);
8318 * The following routines are somewhat easier to use than the above.
8319 * The user declares a variable of type STACKSTR, which may be declared
8320 * to be a register. The macro STARTSTACKSTR initializes things. Then
8321 * the user uses the macro STPUTC to add characters to the string. In
8322 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8323 * grown as necessary. When the user is done, she can just leave the
8324 * string there and refer to it using stackblock(). Or she can allocate
8325 * the space for it using grabstackstr(). If it is necessary to allow
8326 * someone else to use the stack temporarily and then continue to grow
8327 * the string, the user should use grabstack to allocate the space, and
8328 * then call ungrabstr(p) to return to the previous mode of operation.
8330 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8331 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8332 * is space for at least one character.
8338 size_t len = stackblocksize();
8339 if (herefd >= 0 && len >= 1024) {
8340 xwrite(herefd, stackblock(), len);
8341 return stackblock();
8344 return stackblock() + len;
8348 * Called from CHECKSTRSPACE.
8352 makestrspace(size_t newlen, char *p)
8354 size_t len = p - stacknxt;
8355 size_t size = stackblocksize();
8360 size = stackblocksize();
8362 if (nleft >= newlen)
8366 return stackblock() + len;
8370 stnputs(const char *s, size_t n, char *p)
8372 p = makestrspace(n, p);
8373 p = mempcpy(p, s, n);
8378 stputs(const char *s, char *p)
8380 return stnputs(s, strlen(s), p);
8383 /* $NetBSD: mystring.c,v 1.15 2002/11/24 22:35:42 christos Exp $ */
8388 * number(s) Convert a string of digits to an integer.
8389 * is_number(s) Return true if s is a string of digits.
8393 * prefix -- see if pfx is a prefix of string.
8397 prefix(const char *string, const char *pfx)
8400 if (*pfx++ != *string++)
8403 return (char *) string;
8408 * Convert a string of digits to an integer, printing an error message on
8413 number(const char *s)
8423 * Check for a valid number. This should be elsewhere.
8427 is_number(const char *p)
8432 } while (*++p != '\0');
8438 * Produce a possibly single quoted string suitable as input to the shell.
8439 * The return string is allocated on the stack.
8443 single_quote(const char *s) {
8452 len = strchrnul(s, '\'') - s;
8454 q = p = makestrspace(len + 3, p);
8457 q = mempcpy(q, s, len);
8463 len = strspn(s, "'");
8467 q = p = makestrspace(len + 3, p);
8470 q = mempcpy(q, s, len);
8479 return stackblock();
8483 * Like strdup but works with the ash stack.
8487 sstrdup(const char *p)
8489 size_t len = strlen(p) + 1;
8490 return memcpy(stalloc(len), p, len);
8495 calcsize(union node *n)
8499 funcblocksize += nodesize[n->type];
8502 calcsize(n->ncmd.redirect);
8503 calcsize(n->ncmd.args);
8504 calcsize(n->ncmd.assign);
8507 sizenodelist(n->npipe.cmdlist);
8512 calcsize(n->nredir.redirect);
8513 calcsize(n->nredir.n);
8520 calcsize(n->nbinary.ch2);
8521 calcsize(n->nbinary.ch1);
8524 calcsize(n->nif.elsepart);
8525 calcsize(n->nif.ifpart);
8526 calcsize(n->nif.test);
8529 funcstringsize += strlen(n->nfor.var) + 1;
8530 calcsize(n->nfor.body);
8531 calcsize(n->nfor.args);
8534 calcsize(n->ncase.cases);
8535 calcsize(n->ncase.expr);
8538 calcsize(n->nclist.body);
8539 calcsize(n->nclist.pattern);
8540 calcsize(n->nclist.next);
8544 sizenodelist(n->narg.backquote);
8545 funcstringsize += strlen(n->narg.text) + 1;
8546 calcsize(n->narg.next);
8553 calcsize(n->nfile.fname);
8554 calcsize(n->nfile.next);
8558 calcsize(n->ndup.vname);
8559 calcsize(n->ndup.next);
8563 calcsize(n->nhere.doc);
8564 calcsize(n->nhere.next);
8567 calcsize(n->nnot.com);
8574 sizenodelist(struct nodelist *lp)
8577 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8585 copynode(union node *n)
8592 funcblock = (char *) funcblock + nodesize[n->type];
8595 new->ncmd.redirect = copynode(n->ncmd.redirect);
8596 new->ncmd.args = copynode(n->ncmd.args);
8597 new->ncmd.assign = copynode(n->ncmd.assign);
8600 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8601 new->npipe.backgnd = n->npipe.backgnd;
8606 new->nredir.redirect = copynode(n->nredir.redirect);
8607 new->nredir.n = copynode(n->nredir.n);
8614 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8615 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8618 new->nif.elsepart = copynode(n->nif.elsepart);
8619 new->nif.ifpart = copynode(n->nif.ifpart);
8620 new->nif.test = copynode(n->nif.test);
8623 new->nfor.var = nodesavestr(n->nfor.var);
8624 new->nfor.body = copynode(n->nfor.body);
8625 new->nfor.args = copynode(n->nfor.args);
8628 new->ncase.cases = copynode(n->ncase.cases);
8629 new->ncase.expr = copynode(n->ncase.expr);
8632 new->nclist.body = copynode(n->nclist.body);
8633 new->nclist.pattern = copynode(n->nclist.pattern);
8634 new->nclist.next = copynode(n->nclist.next);
8638 new->narg.backquote = copynodelist(n->narg.backquote);
8639 new->narg.text = nodesavestr(n->narg.text);
8640 new->narg.next = copynode(n->narg.next);
8647 new->nfile.fname = copynode(n->nfile.fname);
8648 new->nfile.fd = n->nfile.fd;
8649 new->nfile.next = copynode(n->nfile.next);
8653 new->ndup.vname = copynode(n->ndup.vname);
8654 new->ndup.dupfd = n->ndup.dupfd;
8655 new->ndup.fd = n->ndup.fd;
8656 new->ndup.next = copynode(n->ndup.next);
8660 new->nhere.doc = copynode(n->nhere.doc);
8661 new->nhere.fd = n->nhere.fd;
8662 new->nhere.next = copynode(n->nhere.next);
8665 new->nnot.com = copynode(n->nnot.com);
8668 new->type = n->type;
8673 static struct nodelist *
8674 copynodelist(struct nodelist *lp)
8676 struct nodelist *start;
8677 struct nodelist **lpp;
8682 funcblock = (char *) funcblock +
8683 SHELL_ALIGN(sizeof(struct nodelist));
8684 (*lpp)->n = copynode(lp->n);
8686 lpp = &(*lpp)->next;
8694 nodesavestr(char *s)
8696 char *rtn = funcstring;
8698 funcstring = stpcpy(funcstring, s) + 1;
8704 * Free a parse tree.
8708 freefunc(struct funcnode *f)
8710 if (f && --f->count < 0)
8715 static void options(int);
8716 static void setoption(int, int);
8720 * Process the shell command line arguments.
8724 procargs(int argc, char **argv)
8727 const char *xminusc;
8734 for (i = 0; i < NOPTS; i++)
8740 if (*xargv == NULL) {
8742 error("-c requires an argument");
8745 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8749 for (i = 0; i < NOPTS; i++)
8750 if (optlist[i] == 2)
8755 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8760 } else if (!sflag) {
8761 setinputfile(*xargv, 0);
8767 shellparam.p = xargv;
8768 #ifdef CONFIG_ASH_GETOPTS
8769 shellparam.optind = 1;
8770 shellparam.optoff = -1;
8772 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
8774 shellparam.nparam++;
8787 setinteractive(iflag);
8792 minus_o(char *name, int val)
8797 out1str("Current option settings\n");
8798 for (i = 0; i < NOPTS; i++)
8799 out1fmt("%-16s%s\n", optnames(i),
8800 optlist[i] ? "on" : "off");
8802 for (i = 0; i < NOPTS; i++)
8803 if (equal(name, optnames(i))) {
8807 error("Illegal option -o %s", name);
8812 * Process shell options. The global variable argptr contains a pointer
8813 * to the argument list; we advance it past the options.
8817 options(int cmdline)
8825 while ((p = *argptr) != NULL) {
8827 if ((c = *p++) == '-') {
8829 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8831 /* "-" means turn off -x and -v */
8834 /* "--" means reset params */
8835 else if (*argptr == NULL)
8838 break; /* "-" or "--" terminates options */
8840 } else if (c == '+') {
8846 while ((c = *p++) != '\0') {
8847 if (c == 'c' && cmdline) {
8848 minusc = p; /* command is after shell args*/
8849 } else if (c == 'o') {
8850 minus_o(*argptr, val);
8853 } else if (cmdline && (c == '-')) { // long options
8854 if (strcmp(p, "login") == 0)
8866 setoption(int flag, int val)
8870 for (i = 0; i < NOPTS; i++)
8871 if (optletters(i) == flag) {
8875 error("Illegal option -%c", flag);
8882 * Set the shell parameters.
8886 setparam(char **argv)
8892 for (nparam = 0 ; argv[nparam] ; nparam++);
8893 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
8895 *ap++ = savestr(*argv++);
8898 freeparam(&shellparam);
8899 shellparam.malloc = 1;
8900 shellparam.nparam = nparam;
8901 shellparam.p = newparam;
8902 #ifdef CONFIG_ASH_GETOPTS
8903 shellparam.optind = 1;
8904 shellparam.optoff = -1;
8910 * Free the list of positional parameters.
8914 freeparam(volatile struct shparam *param)
8918 if (param->malloc) {
8919 for (ap = param->p ; *ap ; ap++)
8928 * The shift builtin command.
8932 shiftcmd(int argc, char **argv)
8939 n = number(argv[1]);
8940 if (n > shellparam.nparam)
8941 error("can't shift that many");
8943 shellparam.nparam -= n;
8944 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
8945 if (shellparam.malloc)
8949 while ((*ap2++ = *ap1++) != NULL);
8950 #ifdef CONFIG_ASH_GETOPTS
8951 shellparam.optind = 1;
8952 shellparam.optoff = -1;
8961 * The set command builtin.
8965 setcmd(int argc, char **argv)
8968 return showvars(nullstr, 0, VUNSET);
8972 if (*argptr != NULL) {
8980 #ifdef CONFIG_ASH_GETOPTS
8985 shellparam.optind = number(value);
8986 shellparam.optoff = -1;
8990 #ifdef CONFIG_LOCALE_SUPPORT
8991 static void change_lc_all(const char *value)
8993 if (value != 0 && *value != 0)
8994 setlocale(LC_ALL, value);
8997 static void change_lc_ctype(const char *value)
8999 if (value != 0 && *value != 0)
9000 setlocale(LC_CTYPE, value);
9005 #ifdef CONFIG_ASH_GETOPTS
9007 getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
9016 if(*param_optind < 1)
9018 optnext = optfirst + *param_optind - 1;
9020 if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff)
9023 p = optnext[-1] + *optoff;
9024 if (p == NULL || *p == '\0') {
9025 /* Current word is done, advance */
9027 if (p == NULL || *p != '-' || *++p == '\0') {
9034 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
9039 for (q = optstr; *q != c; ) {
9041 if (optstr[0] == ':') {
9044 err |= setvarsafe("OPTARG", s, 0);
9046 fprintf(stderr, "Illegal option -%c\n", c);
9047 (void) unsetvar("OPTARG");
9057 if (*p == '\0' && (p = *optnext) == NULL) {
9058 if (optstr[0] == ':') {
9061 err |= setvarsafe("OPTARG", s, 0);
9064 fprintf(stderr, "No arg for -%c option\n", c);
9065 (void) unsetvar("OPTARG");
9073 err |= setvarsafe("OPTARG", p, 0);
9076 err |= setvarsafe("OPTARG", nullstr, 0);
9079 *optoff = p ? p - *(optnext - 1) : -1;
9080 *param_optind = optnext - optfirst + 1;
9081 fmtstr(s, sizeof(s), "%d", *param_optind);
9082 err |= setvarsafe("OPTIND", s, VNOFUNC);
9085 err |= setvarsafe(optvar, s, 0);
9096 * The getopts builtin. Shellparam.optnext points to the next argument
9097 * to be processed. Shellparam.optptr points to the next character to
9098 * be processed in the current argument. If shellparam.optnext is NULL,
9099 * then it's the first time getopts has been called.
9103 getoptscmd(int argc, char **argv)
9108 error("Usage: getopts optstring var [arg]");
9109 else if (argc == 3) {
9110 optbase = shellparam.p;
9111 if (shellparam.optind > shellparam.nparam + 1) {
9112 shellparam.optind = 1;
9113 shellparam.optoff = -1;
9118 if (shellparam.optind > argc - 2) {
9119 shellparam.optind = 1;
9120 shellparam.optoff = -1;
9124 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9125 &shellparam.optoff);
9127 #endif /* CONFIG_ASH_GETOPTS */
9130 * XXX - should get rid of. have all builtins use getopt(3). the
9131 * library getopt must have the BSD extension static variable "optreset"
9132 * otherwise it can't be used within the shell safely.
9134 * Standard option processing (a la getopt) for builtin routines. The
9135 * only argument that is passed to nextopt is the option string; the
9136 * other arguments are unnecessary. It return the character, or '\0' on
9141 nextopt(const char *optstring)
9147 if ((p = optptr) == NULL || *p == '\0') {
9149 if (p == NULL || *p != '-' || *++p == '\0')
9152 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
9156 for (q = optstring ; *q != c ; ) {
9158 error("Illegal option -%c", c);
9163 if (*p == '\0' && (p = *argptr++) == NULL)
9164 error("No arg for -%c option", c);
9173 /* $NetBSD: output.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
9176 outstr(const char *p, FILE *file)
9193 flushout(FILE *dest)
9201 outcslow(int c, FILE *dest)
9211 out1fmt(const char *fmt, ...)
9218 r = vprintf(fmt, ap);
9226 fmtstr(char *outbuf, size_t length, const char *fmt, ...)
9233 ret = vsnprintf(outbuf, length, fmt, ap);
9241 * Version of write which resumes after a signal is caught.
9245 xwrite(int fd, const void *p, size_t n)
9250 i = bb_full_write(fd, p, n);
9251 } while (i < 0 && errno == EINTR);
9255 /* $NetBSD: parser.c,v 1.54 2002/11/24 22:35:42 christos Exp $ */
9259 * Shell command parser.
9262 #define EOFMARKLEN 79
9266 struct heredoc *next; /* next here document in list */
9267 union node *here; /* redirection node */
9268 char *eofmark; /* string indicating end of input */
9269 int striptabs; /* if set, strip leading tabs */
9274 static struct heredoc *heredoclist; /* list of here documents to read */
9277 static union node *list(int);
9278 static union node *andor(void);
9279 static union node *pipeline(void);
9280 static union node *command(void);
9281 static union node *simplecmd(void);
9282 static union node *makename(void);
9283 static void parsefname(void);
9284 static void parseheredoc(void);
9285 static char peektoken(void);
9286 static int readtoken(void);
9287 static int xxreadtoken(void);
9288 static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
9289 static int noexpand(char *);
9290 static void synexpect(int) __attribute__((__noreturn__));
9291 static void synerror(const char *) __attribute__((__noreturn__));
9292 static void setprompt(int);
9296 goodname(const char *p)
9298 return !*endofname(p);
9302 isassignment(const char *p)
9304 const char *q = endofname(p);
9312 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9313 * valid parse tree indicating a blank line.)
9317 parsecmd(int interact)
9322 doprompt = interact;
9324 setprompt(doprompt);
9339 union node *n1, *n2, *n3;
9342 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9343 if (nlflag == 2 && peektoken())
9349 if (tok == TBACKGND) {
9350 if (n2->type == NPIPE) {
9351 n2->npipe.backgnd = 1;
9353 if (n2->type != NREDIR) {
9354 n3 = stalloc(sizeof(struct nredir));
9356 n3->nredir.redirect = NULL;
9359 n2->type = NBACKGND;
9366 n3 = (union node *)stalloc(sizeof (struct nbinary));
9368 n3->nbinary.ch1 = n1;
9369 n3->nbinary.ch2 = n2;
9385 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9393 pungetc(); /* push back EOF on input */
9409 union node *n1, *n2, *n3;
9414 if ((t = readtoken()) == TAND) {
9416 } else if (t == TOR) {
9422 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9424 n3 = (union node *)stalloc(sizeof (struct nbinary));
9426 n3->nbinary.ch1 = n1;
9427 n3->nbinary.ch2 = n2;
9437 union node *n1, *n2, *pipenode;
9438 struct nodelist *lp, *prev;
9442 TRACE(("pipeline: entered\n"));
9443 if (readtoken() == TNOT) {
9445 checkkwd = CHKKWD | CHKALIAS;
9449 if (readtoken() == TPIPE) {
9450 pipenode = (union node *)stalloc(sizeof (struct npipe));
9451 pipenode->type = NPIPE;
9452 pipenode->npipe.backgnd = 0;
9453 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9454 pipenode->npipe.cmdlist = lp;
9458 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9459 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9462 } while (readtoken() == TPIPE);
9468 n2 = (union node *)stalloc(sizeof (struct nnot));
9481 union node *n1, *n2;
9482 union node *ap, **app;
9483 union node *cp, **cpp;
9484 union node *redir, **rpp;
9491 switch (readtoken()) {
9496 n1 = (union node *)stalloc(sizeof (struct nif));
9498 n1->nif.test = list(0);
9499 if (readtoken() != TTHEN)
9501 n1->nif.ifpart = list(0);
9503 while (readtoken() == TELIF) {
9504 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
9505 n2 = n2->nif.elsepart;
9507 n2->nif.test = list(0);
9508 if (readtoken() != TTHEN)
9510 n2->nif.ifpart = list(0);
9512 if (lasttoken == TELSE)
9513 n2->nif.elsepart = list(0);
9515 n2->nif.elsepart = NULL;
9523 n1 = (union node *)stalloc(sizeof (struct nbinary));
9524 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
9525 n1->nbinary.ch1 = list(0);
9526 if ((got=readtoken()) != TDO) {
9527 TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
9530 n1->nbinary.ch2 = list(0);
9535 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9536 synerror("Bad for loop variable");
9537 n1 = (union node *)stalloc(sizeof (struct nfor));
9539 n1->nfor.var = wordtext;
9540 checkkwd = CHKKWD | CHKALIAS;
9541 if (readtoken() == TIN) {
9543 while (readtoken() == TWORD) {
9544 n2 = (union node *)stalloc(sizeof (struct narg));
9546 n2->narg.text = wordtext;
9547 n2->narg.backquote = backquotelist;
9549 app = &n2->narg.next;
9553 if (lasttoken != TNL && lasttoken != TSEMI)
9556 n2 = (union node *)stalloc(sizeof (struct narg));
9558 n2->narg.text = (char *)dolatstr;
9559 n2->narg.backquote = NULL;
9560 n2->narg.next = NULL;
9563 * Newline or semicolon here is optional (but note
9564 * that the original Bourne shell only allowed NL).
9566 if (lasttoken != TNL && lasttoken != TSEMI)
9569 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9570 if (readtoken() != TDO)
9572 n1->nfor.body = list(0);
9576 n1 = (union node *)stalloc(sizeof (struct ncase));
9578 if (readtoken() != TWORD)
9580 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
9582 n2->narg.text = wordtext;
9583 n2->narg.backquote = backquotelist;
9584 n2->narg.next = NULL;
9586 checkkwd = CHKKWD | CHKALIAS;
9587 } while (readtoken() == TNL);
9588 if (lasttoken != TIN)
9590 cpp = &n1->ncase.cases;
9592 checkkwd = CHKNL | CHKKWD;
9595 if (lasttoken == TLP)
9597 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
9599 app = &cp->nclist.pattern;
9601 *app = ap = (union node *)stalloc(sizeof (struct narg));
9603 ap->narg.text = wordtext;
9604 ap->narg.backquote = backquotelist;
9605 if (readtoken() != TPIPE)
9607 app = &ap->narg.next;
9610 ap->narg.next = NULL;
9611 if (lasttoken != TRP)
9613 cp->nclist.body = list(2);
9615 cpp = &cp->nclist.next;
9617 checkkwd = CHKNL | CHKKWD;
9618 if ((t = readtoken()) != TESAC) {
9620 synexpect(TENDCASE);
9628 n1 = (union node *)stalloc(sizeof (struct nredir));
9629 n1->type = NSUBSHELL;
9630 n1->nredir.n = list(0);
9631 n1->nredir.redirect = NULL;
9644 if (readtoken() != t)
9648 /* Now check for redirection which may follow command */
9649 checkkwd = CHKKWD | CHKALIAS;
9651 while (readtoken() == TREDIR) {
9652 *rpp = n2 = redirnode;
9653 rpp = &n2->nfile.next;
9659 if (n1->type != NSUBSHELL) {
9660 n2 = (union node *)stalloc(sizeof (struct nredir));
9665 n1->nredir.redirect = redir;
9674 union node *args, **app;
9675 union node *n = NULL;
9676 union node *vars, **vpp;
9677 union node **rpp, *redir;
9687 savecheckkwd = CHKALIAS;
9689 checkkwd = savecheckkwd;
9690 switch (readtoken()) {
9692 n = (union node *)stalloc(sizeof (struct narg));
9694 n->narg.text = wordtext;
9695 n->narg.backquote = backquotelist;
9696 if (savecheckkwd && isassignment(wordtext)) {
9698 vpp = &n->narg.next;
9701 app = &n->narg.next;
9706 *rpp = n = redirnode;
9707 rpp = &n->nfile.next;
9708 parsefname(); /* read name of redirection file */
9712 args && app == &args->narg.next &&
9715 struct builtincmd *bcmd;
9718 /* We have a function */
9719 if (readtoken() != TRP)
9721 name = n->narg.text;
9723 !goodname(name) || (
9724 (bcmd = find_builtin(name)) &&
9725 IS_BUILTIN_SPECIAL(bcmd)
9728 synerror("Bad function name");
9730 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9731 n->narg.next = command();
9744 n = (union node *)stalloc(sizeof (struct ncmd));
9746 n->ncmd.args = args;
9747 n->ncmd.assign = vars;
9748 n->ncmd.redirect = redir;
9757 n = (union node *)stalloc(sizeof (struct narg));
9759 n->narg.next = NULL;
9760 n->narg.text = wordtext;
9761 n->narg.backquote = backquotelist;
9765 void fixredir(union node *n, const char *text, int err)
9767 TRACE(("Fix redir %s %d\n", text, err));
9769 n->ndup.vname = NULL;
9771 if (is_digit(text[0]) && text[1] == '\0')
9772 n->ndup.dupfd = digit_val(text[0]);
9773 else if (text[0] == '-' && text[1] == '\0')
9778 synerror("Bad fd number");
9780 n->ndup.vname = makename();
9788 union node *n = redirnode;
9790 if (readtoken() != TWORD)
9792 if (n->type == NHERE) {
9793 struct heredoc *here = heredoc;
9799 TRACE(("Here document %d\n", n->type));
9800 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
9801 synerror("Illegal eof marker for << redirection");
9802 rmescapes(wordtext);
9803 here->eofmark = wordtext;
9805 if (heredoclist == NULL)
9808 for (p = heredoclist ; p->next ; p = p->next);
9811 } else if (n->type == NTOFD || n->type == NFROMFD) {
9812 fixredir(n, wordtext, 0);
9814 n->nfile.fname = makename();
9820 * Input any here documents.
9826 struct heredoc *here;
9837 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9838 here->eofmark, here->striptabs);
9839 n = (union node *)stalloc(sizeof (struct narg));
9840 n->narg.type = NARG;
9841 n->narg.next = NULL;
9842 n->narg.text = wordtext;
9843 n->narg.backquote = backquotelist;
9844 here->here->nhere.doc = n;
9849 static char peektoken(void)
9855 return tokname_array[t][0];
9863 int alreadyseen = tokpushback;
9866 #ifdef CONFIG_ASH_ALIAS
9875 if (checkkwd & CHKNL) {
9882 if (t != TWORD || quoteflag) {
9887 * check for keywords
9889 if (checkkwd & CHKKWD) {
9890 const char *const *pp;
9892 if ((pp = findkwd(wordtext))) {
9893 lasttoken = t = pp - tokname_array;
9894 TRACE(("keyword %s recognized\n", tokname(t)));
9899 if (checkkwd & CHKALIAS) {
9900 #ifdef CONFIG_ASH_ALIAS
9902 if ((ap = lookupalias(wordtext, 1)) != NULL) {
9904 pushstring(ap->val, ap);
9914 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
9916 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
9923 * Read the next input token.
9924 * If the token is a word, we set backquotelist to the list of cmds in
9925 * backquotes. We set quoteflag to true if any part of the word was
9927 * If the token is TREDIR, then we set redirnode to a structure containing
9929 * In all cases, the variable startlinno is set to the number of the line
9930 * on which the token starts.
9932 * [Change comment: here documents and internal procedures]
9933 * [Readtoken shouldn't have any arguments. Perhaps we should make the
9934 * word parsing code into a separate routine. In this case, readtoken
9935 * doesn't need to have any internal procedures, but parseword does.
9936 * We could also make parseoperator in essence the main routine, and
9937 * have parseword (readtoken1?) handle both words and redirection.]
9940 #define NEW_xxreadtoken
9941 #ifdef NEW_xxreadtoken
9943 /* singles must be first! */
9944 static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
9946 static const char xxreadtoken_tokens[] = {
9947 TNL, TLP, TRP, /* only single occurrence allowed */
9948 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
9949 TEOF, /* corresponds to trailing nul */
9950 TAND, TOR, TENDCASE, /* if double occurrence */
9953 #define xxreadtoken_doubles \
9954 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
9955 #define xxreadtoken_singles \
9956 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
9958 static int xxreadtoken()
9970 startlinno = plinno;
9971 for (;;) { /* until token or start of word found */
9974 if ((c != ' ') && (c != '\t')
9975 #ifdef CONFIG_ASH_ALIAS
9980 while ((c = pgetc()) != '\n' && c != PEOF);
9982 } else if (c == '\\') {
9983 if (pgetc() != '\n') {
9987 startlinno = ++plinno;
9992 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
9997 needprompt = doprompt;
10000 p = strchr(xxreadtoken_chars, c);
10003 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
10006 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
10007 if (pgetc() == *p) { /* double occurrence? */
10008 p += xxreadtoken_doubles + 1;
10015 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
10023 #define RETURN(token) return lasttoken = token
10038 startlinno = plinno;
10039 for (;;) { /* until token or start of word found */
10042 case ' ': case '\t':
10043 #ifdef CONFIG_ASH_ALIAS
10048 while ((c = pgetc()) != '\n' && c != PEOF);
10052 if (pgetc() == '\n') {
10053 startlinno = ++plinno;
10062 needprompt = doprompt;
10067 if (pgetc() == '&')
10072 if (pgetc() == '|')
10077 if (pgetc() == ';')
10090 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10093 #endif /* NEW_xxreadtoken */
10097 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10098 * is not NULL, read a here document. In the latter case, eofmark is the
10099 * word which marks the end of the document and striptabs is true if
10100 * leading tabs should be stripped from the document. The argument firstc
10101 * is the first character of the input token or document.
10103 * Because C does not have internal subroutines, I have simulated them
10104 * using goto's to implement the subroutine linkage. The following macros
10105 * will run code that appears at the end of readtoken1.
10108 #define CHECKEND() {goto checkend; checkend_return:;}
10109 #define PARSEREDIR() {goto parseredir; parseredir_return:;}
10110 #define PARSESUB() {goto parsesub; parsesub_return:;}
10111 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10112 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10113 #define PARSEARITH() {goto parsearith; parsearith_return:;}
10116 readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
10121 char line[EOFMARKLEN + 1];
10122 struct nodelist *bqlist;
10125 int varnest; /* levels of variables expansion */
10126 int arinest; /* levels of arithmetic expansion */
10127 int parenlevel; /* levels of parens in arithmetic */
10128 int dqvarnest; /* levels of variables expansion within double quotes */
10130 int prevsyntax; /* syntax before arithmetic */
10132 /* Avoid longjmp clobbering */
10138 (void) &parenlevel;
10141 (void) &prevsyntax;
10145 startlinno = plinno;
10147 if (syntax == DQSYNTAX)
10156 STARTSTACKSTR(out);
10157 loop: { /* for each line, until end of word */
10158 CHECKEND(); /* set c to PEOF if at end of here document */
10159 for (;;) { /* until end of line or end of word */
10160 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10161 switch(SIT(c, syntax)) {
10162 case CNL: /* '\n' */
10163 if (syntax == BASESYNTAX)
10164 goto endword; /* exit outer loop */
10170 goto loop; /* continue outer loop */
10175 if (eofmark == NULL || dblquote)
10176 USTPUTC(CTLESC, out);
10179 case CBACK: /* backslash */
10182 USTPUTC(CTLESC, out);
10183 USTPUTC('\\', out);
10185 } else if (c == '\n') {
10191 c != '\\' && c != '`' &&
10197 USTPUTC(CTLESC, out);
10198 USTPUTC('\\', out);
10200 if (SIT(c, SQSYNTAX) == CCTL)
10201 USTPUTC(CTLESC, out);
10209 if (eofmark == NULL) {
10210 USTPUTC(CTLQUOTEMARK, out);
10218 if (eofmark != NULL && arinest == 0 &&
10222 if (dqvarnest == 0) {
10223 syntax = BASESYNTAX;
10230 case CVAR: /* '$' */
10231 PARSESUB(); /* parse substitution */
10233 case CENDVAR: /* '}' */
10236 if (dqvarnest > 0) {
10239 USTPUTC(CTLENDVAR, out);
10244 #ifdef CONFIG_ASH_MATH_SUPPORT
10245 case CLP: /* '(' in arithmetic */
10249 case CRP: /* ')' in arithmetic */
10250 if (parenlevel > 0) {
10254 if (pgetc() == ')') {
10255 if (--arinest == 0) {
10256 USTPUTC(CTLENDARI, out);
10257 syntax = prevsyntax;
10258 if (syntax == DQSYNTAX)
10266 * unbalanced parens
10267 * (don't 2nd guess - no error)
10275 case CBQUOTE: /* '`' */
10279 goto endword; /* exit outer loop */
10284 goto endword; /* exit outer loop */
10285 #ifdef CONFIG_ASH_ALIAS
10295 #ifdef CONFIG_ASH_MATH_SUPPORT
10296 if (syntax == ARISYNTAX)
10297 synerror("Missing '))'");
10299 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10300 synerror("Unterminated quoted string");
10301 if (varnest != 0) {
10302 startlinno = plinno;
10304 synerror("Missing '}'");
10306 USTPUTC('\0', out);
10307 len = out - (char *)stackblock();
10308 out = stackblock();
10309 if (eofmark == NULL) {
10310 if ((c == '>' || c == '<')
10313 && (*out == '\0' || is_digit(*out))) {
10315 return lasttoken = TREDIR;
10320 quoteflag = quotef;
10321 backquotelist = bqlist;
10322 grabstackblock(len);
10324 return lasttoken = TWORD;
10325 /* end of readtoken routine */
10330 * Check to see whether we are at the end of the here document. When this
10331 * is called, c is set to the first character of the next input line. If
10332 * we are at the end of the here document, this routine sets the c to PEOF.
10337 #ifdef CONFIG_ASH_ALIAS
10343 while (c == '\t') {
10347 if (c == *eofmark) {
10348 if (pfgets(line, sizeof line) != NULL) {
10352 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10353 if (*p == '\n' && *q == '\0') {
10356 needprompt = doprompt;
10358 pushstring(line, NULL);
10363 goto checkend_return;
10368 * Parse a redirection operator. The variable "out" points to a string
10369 * specifying the fd to be redirected. The variable "c" contains the
10370 * first character of the redirection operator.
10377 np = (union node *)stalloc(sizeof (struct nfile));
10382 np->type = NAPPEND;
10384 np->type = NCLOBBER;
10391 } else { /* c == '<' */
10393 switch (c = pgetc()) {
10395 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10396 np = (union node *)stalloc(sizeof (struct nhere));
10400 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10401 heredoc->here = np;
10402 if ((c = pgetc()) == '-') {
10403 heredoc->striptabs = 1;
10405 heredoc->striptabs = 0;
10411 np->type = NFROMFD;
10415 np->type = NFROMTO;
10425 np->nfile.fd = digit_val(fd);
10427 goto parseredir_return;
10432 * Parse a substitution. At this point, we have read the dollar sign
10433 * and nothing else.
10441 static const char types[] = "}-+?=";
10445 c <= PEOA_OR_PEOF ||
10446 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10450 } else if (c == '(') { /* $(command) or $((arith)) */
10451 if (pgetc() == '(') {
10452 #ifdef CONFIG_ASH_MATH_SUPPORT
10455 synerror("We unsupport $((arith))");
10462 USTPUTC(CTLVAR, out);
10463 typeloc = out - (char *)stackblock();
10464 USTPUTC(VSNORMAL, out);
10465 subtype = VSNORMAL;
10469 if ((c = pgetc()) == '}')
10472 subtype = VSLENGTH;
10477 if (c > PEOA_OR_PEOF && is_name(c)) {
10481 } while (c > PEOA_OR_PEOF && is_in_name(c));
10482 } else if (is_digit(c)) {
10486 } while (is_digit(c));
10488 else if (is_special(c)) {
10493 badsub: synerror("Bad substitution");
10497 if (subtype == 0) {
10504 p = strchr(types, c);
10507 subtype = p - types + VSNORMAL;
10513 subtype = c == '#' ? VSTRIMLEFT :
10526 if (dblquote || arinest)
10528 *((char *)stackblock() + typeloc) = subtype | flags;
10529 if (subtype != VSNORMAL) {
10531 if (dblquote || arinest) {
10536 goto parsesub_return;
10541 * Called to parse command substitutions. Newstyle is set if the command
10542 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10543 * list of commands (passed by reference), and savelen is the number of
10544 * characters on the top of the stack which must be preserved.
10548 struct nodelist **nlpp;
10551 char *volatile str;
10552 struct jmploc jmploc;
10553 struct jmploc *volatile savehandler;
10557 (void) &saveprompt;
10560 savepbq = parsebackquote;
10561 if (setjmp(jmploc.loc)) {
10564 parsebackquote = 0;
10565 handler = savehandler;
10566 longjmp(handler->loc, 1);
10570 savelen = out - (char *)stackblock();
10572 str = ckmalloc(savelen);
10573 memcpy(str, stackblock(), savelen);
10575 savehandler = handler;
10579 /* We must read until the closing backquote, giving special
10580 treatment to some slashes, and then push the string and
10581 reread it as input, interpreting it normally. */
10588 STARTSTACKSTR(pout);
10594 switch (pc = pgetc()) {
10599 if ((pc = pgetc()) == '\n') {
10604 * If eating a newline, avoid putting
10605 * the newline into the new character
10606 * stream (via the STPUTC after the
10611 if (pc != '\\' && pc != '`' && pc != '$'
10612 && (!dblquote || pc != '"'))
10613 STPUTC('\\', pout);
10614 if (pc > PEOA_OR_PEOF) {
10620 #ifdef CONFIG_ASH_ALIAS
10623 startlinno = plinno;
10624 synerror("EOF in backquote substitution");
10628 needprompt = doprompt;
10637 STPUTC('\0', pout);
10638 psavelen = pout - (char *)stackblock();
10639 if (psavelen > 0) {
10640 pstr = grabstackstr(pout);
10641 setinputstring(pstr);
10646 nlpp = &(*nlpp)->next;
10647 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10648 (*nlpp)->next = NULL;
10649 parsebackquote = oldstyle;
10652 saveprompt = doprompt;
10659 doprompt = saveprompt;
10661 if (readtoken() != TRP)
10668 * Start reading from old file again, ignoring any pushed back
10669 * tokens left from the backquote parsing
10674 while (stackblocksize() <= savelen)
10676 STARTSTACKSTR(out);
10678 memcpy(out, str, savelen);
10679 STADJUST(savelen, out);
10685 parsebackquote = savepbq;
10686 handler = savehandler;
10687 if (arinest || dblquote)
10688 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10690 USTPUTC(CTLBACKQ, out);
10692 goto parsebackq_oldreturn;
10694 goto parsebackq_newreturn;
10697 #ifdef CONFIG_ASH_MATH_SUPPORT
10699 * Parse an arithmetic expansion (indicate start of one and set state)
10703 if (++arinest == 1) {
10704 prevsyntax = syntax;
10705 syntax = ARISYNTAX;
10706 USTPUTC(CTLARI, out);
10713 * we collapse embedded arithmetic expansion to
10714 * parenthesis, which should be equivalent
10718 goto parsearith_return;
10722 } /* end of readtoken */
10727 * Returns true if the text contains nothing to expand (no dollar signs
10732 noexpand(char *text)
10738 while ((c = *p++) != '\0') {
10739 if (c == CTLQUOTEMARK)
10743 else if (SIT(c, BASESYNTAX) == CCTL)
10751 * Return of a legal variable name (a letter or underscore followed by zero or
10752 * more letters, underscores, and digits).
10756 endofname(const char *name)
10764 if (! is_in_name(*p))
10772 * Called when an unexpected token is read during the parse. The argument
10773 * is the token that is expected, or -1 if more than one type of token can
10774 * occur at this point.
10777 static void synexpect(int token)
10782 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10784 sprintf(msg + l, " (expecting %s)", tokname(token));
10790 synerror(const char *msg)
10792 error("Syntax error: %s", msg);
10798 * called by editline -- any expansions to the prompt
10799 * should be added here.
10802 static void setprompt(int whichprompt)
10804 const char *prompt;
10806 switch (whichprompt) {
10820 static const char *const *findkwd(const char *s)
10822 return bsearch(s, tokname_array + KWDOFFSET,
10823 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
10824 sizeof(const char *), pstrcmp);
10827 /* $NetBSD: redir.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
10830 * Code for dealing with input/output redirection.
10833 #define EMPTY -2 /* marks an unused slot in redirtab */
10835 # define PIPESIZE 4096 /* amount of buffering in a pipe */
10837 # define PIPESIZE PIPE_BUF
10841 * Open a file in noclobber mode.
10842 * The code was copied from bash.
10845 noclobberopen(const char *fname)
10848 struct stat finfo, finfo2;
10851 * If the file exists and is a regular file, return an error
10854 r = stat(fname, &finfo);
10855 if (r == 0 && S_ISREG(finfo.st_mode)) {
10861 * If the file was not present (r != 0), make sure we open it
10862 * exclusively so that if it is created before we open it, our open
10863 * will fail. Make sure that we do not truncate an existing file.
10864 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10865 * file was not a regular file, we leave O_EXCL off.
10868 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10869 fd = open(fname, O_WRONLY|O_CREAT, 0666);
10871 /* If the open failed, return the file descriptor right away. */
10876 * OK, the open succeeded, but the file may have been changed from a
10877 * non-regular file to a regular file between the stat and the open.
10878 * We are assuming that the O_EXCL open handles the case where FILENAME
10879 * did not exist and is symlinked to an existing file between the stat
10884 * If we can open it and fstat the file descriptor, and neither check
10885 * revealed that it was a regular file, and the file has not been
10886 * replaced, return the file descriptor.
10888 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10889 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
10892 /* The file has been replaced. badness. */
10899 * Handle here documents. Normally we fork off a process to write the
10900 * data to a pipe. If the document is short, we can stuff the data in
10901 * the pipe without forking.
10905 openhere(union node *redir)
10911 error("Pipe call failed");
10912 if (redir->type == NHERE) {
10913 len = strlen(redir->nhere.doc->narg.text);
10914 if (len <= PIPESIZE) {
10915 xwrite(pip[1], redir->nhere.doc->narg.text, len);
10919 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
10921 signal(SIGINT, SIG_IGN);
10922 signal(SIGQUIT, SIG_IGN);
10923 signal(SIGHUP, SIG_IGN);
10925 signal(SIGTSTP, SIG_IGN);
10927 signal(SIGPIPE, SIG_DFL);
10928 if (redir->type == NHERE)
10929 xwrite(pip[1], redir->nhere.doc->narg.text, len);
10931 expandhere(redir->nhere.doc, pip[1]);
10940 openredirect(union node *redir)
10945 switch (redir->nfile.type) {
10947 fname = redir->nfile.expfname;
10948 if ((f = open(fname, O_RDONLY)) < 0)
10952 fname = redir->nfile.expfname;
10953 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
10957 /* Take care of noclobber mode. */
10959 fname = redir->nfile.expfname;
10960 if ((f = noclobberopen(fname)) < 0)
10966 fname = redir->nfile.expfname;
10967 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
10971 fname = redir->nfile.expfname;
10972 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
10979 /* Fall through to eliminate warning. */
10986 f = openhere(redir);
10992 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
10994 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
10998 dupredirect(union node *redir, int f)
11000 int fd = redir->nfile.fd;
11002 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11003 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
11004 copyfd(redir->ndup.dupfd, fd);
11017 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11018 * old file descriptors are stashed away so that the redirection can be
11019 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11020 * standard output, and the standard error if it becomes a duplicate of
11021 * stdout, is saved in memory.
11025 redirect(union node *redir, int flags)
11028 struct redirtab *sv;
11039 if (flags & REDIR_PUSH) {
11040 struct redirtab *q;
11041 q = ckmalloc(sizeof (struct redirtab));
11042 q->next = redirlist;
11044 q->nullredirs = nullredirs - 1;
11045 for (i = 0 ; i < 10 ; i++)
11046 q->renamed[i] = EMPTY;
11053 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
11054 n->ndup.dupfd == fd)
11055 continue; /* redirect from/to same file descriptor */
11057 newfd = openredirect(n);
11060 if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
11061 i = fcntl(fd, F_DUPFD, 10);
11068 error("%d: %m", fd);
11078 dupredirect(n, newfd);
11079 } while ((n = n->nfile.next));
11081 if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
11082 preverrout_fd = sv->renamed[2];
11087 * Undo the effects of the last redirection.
11093 struct redirtab *rp;
11096 if (--nullredirs >= 0)
11100 for (i = 0 ; i < 10 ; i++) {
11101 if (rp->renamed[i] != EMPTY) {
11104 copyfd(rp->renamed[i], i);
11106 close(rp->renamed[i]);
11109 redirlist = rp->next;
11110 nullredirs = rp->nullredirs;
11116 * Undo all redirections. Called on error or interrupt.
11120 * Discard all saved file descriptors.
11124 clearredir(int drop)
11136 * Copy a file descriptor to be >= to. Returns -1
11137 * if the source file descriptor is closed, EMPTY if there are no unused
11138 * file descriptors left.
11142 copyfd(int from, int to)
11146 newfd = fcntl(from, F_DUPFD, to);
11148 if (errno == EMFILE)
11151 error("%d: %m", from);
11158 redirectsafe(union node *redir, int flags)
11161 volatile int saveint;
11162 struct jmploc *volatile savehandler = handler;
11163 struct jmploc jmploc;
11166 if (!(err = setjmp(jmploc.loc) * 2)) {
11168 redirect(redir, flags);
11170 handler = savehandler;
11171 if (err && exception != EXERROR)
11172 longjmp(handler->loc, 1);
11173 RESTOREINT(saveint);
11177 /* $NetBSD: show.c,v 1.24 2003/01/22 20:36:04 dsl Exp $ */
11180 static void shtree(union node *, int, char *, FILE*);
11181 static void shcmd(union node *, FILE *);
11182 static void sharg(union node *, FILE *);
11183 static void indent(int, char *, FILE *);
11184 static void trstring(char *);
11188 showtree(union node *n)
11190 trputs("showtree called\n");
11191 shtree(n, 1, NULL, stdout);
11196 shtree(union node *n, int ind, char *pfx, FILE *fp)
11198 struct nodelist *lp;
11204 indent(ind, pfx, fp);
11215 shtree(n->nbinary.ch1, ind, NULL, fp);
11218 shtree(n->nbinary.ch2, ind, NULL, fp);
11226 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
11231 if (n->npipe.backgnd)
11237 fprintf(fp, "<node type %d>", n->type);
11246 shcmd(union node *cmd, FILE *fp)
11254 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11260 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11263 switch (np->nfile.type) {
11264 case NTO: s = ">"; dftfd = 1; break;
11265 case NCLOBBER: s = ">|"; dftfd = 1; break;
11266 case NAPPEND: s = ">>"; dftfd = 1; break;
11267 case NTOFD: s = ">&"; dftfd = 1; break;
11268 case NFROM: s = "<"; dftfd = 0; break;
11269 case NFROMFD: s = "<&"; dftfd = 0; break;
11270 case NFROMTO: s = "<>"; dftfd = 0; break;
11271 default: s = "*error*"; dftfd = 0; break;
11273 if (np->nfile.fd != dftfd)
11274 fprintf(fp, "%d", np->nfile.fd);
11276 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11277 fprintf(fp, "%d", np->ndup.dupfd);
11279 sharg(np->nfile.fname, fp);
11288 sharg(union node *arg, FILE *fp)
11291 struct nodelist *bqlist;
11294 if (arg->type != NARG) {
11295 out1fmt("<node type %d>\n", arg->type);
11298 bqlist = arg->narg.backquote;
11299 for (p = arg->narg.text ; *p ; p++) {
11308 if (subtype == VSLENGTH)
11314 if (subtype & VSNUL)
11317 switch (subtype & VSTYPE) {
11336 case VSTRIMLEFTMAX:
11343 case VSTRIMRIGHTMAX:
11350 out1fmt("<subtype %d>", subtype);
11357 case CTLBACKQ|CTLQUOTE:
11360 shtree(bqlist->n, -1, NULL, fp);
11372 indent(int amount, char *pfx, FILE *fp)
11376 for (i = 0 ; i < amount ; i++) {
11377 if (pfx && i == amount - 1)
11398 putc(c, tracefile);
11402 trace(const char *fmt, ...)
11409 (void) vfprintf(tracefile, fmt, va);
11414 tracev(const char *fmt, va_list va)
11418 (void) vfprintf(tracefile, fmt, va);
11423 trputs(const char *s)
11427 fputs(s, tracefile);
11439 putc('"', tracefile);
11440 for (p = s ; *p ; p++) {
11442 case '\n': c = 'n'; goto backslash;
11443 case '\t': c = 't'; goto backslash;
11444 case '\r': c = 'r'; goto backslash;
11445 case '"': c = '"'; goto backslash;
11446 case '\\': c = '\\'; goto backslash;
11447 case CTLESC: c = 'e'; goto backslash;
11448 case CTLVAR: c = 'v'; goto backslash;
11449 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11450 case CTLBACKQ: c = 'q'; goto backslash;
11451 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
11452 backslash: putc('\\', tracefile);
11453 putc(c, tracefile);
11456 if (*p >= ' ' && *p <= '~')
11457 putc(*p, tracefile);
11459 putc('\\', tracefile);
11460 putc(*p >> 6 & 03, tracefile);
11461 putc(*p >> 3 & 07, tracefile);
11462 putc(*p & 07, tracefile);
11467 putc('"', tracefile);
11479 putc(' ', tracefile);
11481 putc('\n', tracefile);
11497 /* leave open because libedit might be using it */
11500 scopy("./trace", s);
11502 if (!freopen(s, "a", tracefile)) {
11503 fprintf(stderr, "Can't re-open %s\n", s);
11508 if ((tracefile = fopen(s, "a")) == NULL) {
11509 fprintf(stderr, "Can't open %s\n", s);
11515 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11516 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11518 setlinebuf(tracefile);
11519 fputs("\nTracing started.\n", tracefile);
11524 /* $NetBSD: trap.c,v 1.28 2002/11/24 22:35:43 christos Exp $ */
11527 * Sigmode records the current value of the signal handlers for the various
11528 * modes. A value of zero means that the current handler is not known.
11529 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
11532 #define S_DFL 1 /* default signal handling (SIG_DFL) */
11533 #define S_CATCH 2 /* signal is caught */
11534 #define S_IGN 3 /* signal is ignored (SIG_IGN) */
11535 #define S_HARD_IGN 4 /* signal is ignored permenantly */
11536 #define S_RESET 5 /* temporary - to reset a hard ignored sig */
11541 * The trap builtin.
11545 trapcmd(int argc, char **argv)
11554 for (signo = 0 ; signo < NSIG ; signo++) {
11555 if (trap[signo] != NULL) {
11558 sn = u_signal_names(0, &signo, 0);
11561 out1fmt("trap -- %s %s\n",
11562 single_quote(trap[signo]), sn);
11572 if ((signo = decode_signal(*ap, 0)) < 0)
11573 error("%s: bad trap", *ap);
11576 if (action[0] == '-' && action[1] == '\0')
11579 action = savestr(action);
11582 ckfree(trap[signo]);
11583 trap[signo] = action;
11594 * Clear traps on a fork.
11602 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
11603 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
11607 if (tp != &trap[0])
11608 setsignal(tp - trap);
11616 * Set the signal handler for the specified signal. The routine figures
11617 * out what it should be set to.
11621 setsignal(int signo)
11625 struct sigaction act;
11627 if ((t = trap[signo]) == NULL)
11629 else if (*t != '\0')
11633 if (rootshell && action == S_DFL) {
11636 if (iflag || minusc || sflag == 0)
11659 t = &sigmode[signo - 1];
11663 * current setting unknown
11665 if (sigaction(signo, 0, &act) == -1) {
11667 * Pretend it worked; maybe we should give a warning
11668 * here, but other shells don't. We don't alter
11669 * sigmode, so that we retry every time.
11673 if (act.sa_handler == SIG_IGN) {
11674 if (mflag && (signo == SIGTSTP ||
11675 signo == SIGTTIN || signo == SIGTTOU)) {
11676 tsig = S_IGN; /* don't hard ignore these */
11680 tsig = S_RESET; /* force to be set */
11683 if (tsig == S_HARD_IGN || tsig == action)
11687 act.sa_handler = onsig;
11690 act.sa_handler = SIG_IGN;
11693 act.sa_handler = SIG_DFL;
11697 sigfillset(&act.sa_mask);
11698 sigaction(signo, &act, 0);
11706 ignoresig(int signo)
11708 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11709 signal(signo, SIG_IGN);
11711 sigmode[signo - 1] = S_HARD_IGN;
11722 gotsig[signo - 1] = 1;
11723 pendingsigs = signo;
11725 if (exsig || (signo == SIGINT && !trap[SIGINT])) {
11734 * Called to execute a trap. Perhaps we should avoid entering new trap
11735 * handlers while we are executing a trap handler.
11745 savestatus = exitstatus;
11747 while (pendingsigs = 0, barrier(), (p = memchr(q, 1, NSIG - 1))) {
11749 p = trap[p - q + 1];
11753 exitstatus = savestatus;
11759 * Controls whether the shell is interactive or not.
11763 setinteractive(int on)
11765 static int is_interactive;
11767 if (++on == is_interactive)
11769 is_interactive = on;
11771 setsignal(SIGQUIT);
11772 setsignal(SIGTERM);
11773 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11774 if(is_interactive > 1) {
11775 /* Looks like they want an interactive shell */
11776 static int do_banner;
11780 "\n\n" BB_BANNER " Built-in shell (ash)\n"
11781 "Enter 'help' for a list of built-in commands.\n\n");
11789 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11790 /*** List the available builtins ***/
11792 static int helpcmd(int argc, char **argv)
11796 out1fmt("\nBuilt-in commands:\n-------------------\n");
11797 for (col = 0, i = 0; i < NUMBUILTINS; i++) {
11798 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11799 builtincmd[i].name + 1);
11805 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
11807 extern const struct BB_applet applets[];
11808 extern const size_t NUM_APPLETS;
11810 for (i = 0; i < NUM_APPLETS; i++) {
11812 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
11821 return EXIT_SUCCESS;
11823 #endif /* CONFIG_FEATURE_SH_EXTRA_QUIET */
11826 * Called to exit the shell.
11836 status = exitstatus;
11837 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
11838 if (setjmp(loc.loc)) {
11842 if ((p = trap[0]) != NULL && *p != '\0') {
11847 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
11848 if (iflag && rootshell) {
11849 const char *hp = lookupvar("HISTFILE");
11852 save_history ( hp );
11860 static int decode_signal(const char *string, int minsig)
11863 const char *name = u_signal_names(string, &signo, minsig);
11865 return name ? signo : -1;
11868 /* $NetBSD: var.c,v 1.32 2003/01/22 20:36:04 dsl Exp $ */
11870 static struct var *vartab[VTABSIZE];
11872 static int vpcmp(const void *, const void *);
11873 static struct var **findvar(struct var **, const char *);
11876 * Initialize the varable symbol tables and import the environment
11880 #ifdef CONFIG_ASH_GETOPTS
11882 * Safe version of setvar, returns 1 on success 0 on failure.
11886 setvarsafe(const char *name, const char *val, int flags)
11889 volatile int saveint;
11890 struct jmploc *volatile savehandler = handler;
11891 struct jmploc jmploc;
11894 if (setjmp(jmploc.loc))
11898 setvar(name, val, flags);
11901 handler = savehandler;
11902 RESTOREINT(saveint);
11908 * Set the value of a variable. The flags argument is ored with the
11909 * flags of the variable. If val is NULL, the variable is unset.
11913 setvar(const char *name, const char *val, int flags)
11920 q = endofname(name);
11921 p = strchrnul(q, '=');
11922 namelen = p - name;
11923 if (!namelen || p != q)
11924 error("%.*s: bad variable name", namelen, name);
11929 vallen = strlen(val);
11932 p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
11936 p = mempcpy(p, val, vallen);
11939 setvareq(nameeq, flags | VNOSAVE);
11945 * Same as setvar except that the variable and value are passed in
11946 * the first argument as name=value. Since the first argument will
11947 * be actually stored in the table, it should not be a string that
11949 * Called with interrupts off.
11953 setvareq(char *s, int flags)
11955 struct var *vp, **vpp;
11958 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
11959 vp = *findvar(vpp, s);
11961 if (vp->flags & VREADONLY) {
11962 if (flags & VNOSAVE)
11964 error("%.*s: is read only", strchrnul(s, '=') - s, s);
11967 if (flags & VNOSET)
11970 if (vp->func && (flags & VNOFUNC) == 0)
11971 (*vp->func)(strchrnul(s, '=') + 1);
11973 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
11976 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
11978 if (flags & VNOSET)
11981 vp = ckmalloc(sizeof (*vp));
11986 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
11994 * Process a linked list of variable assignments.
11998 listsetvar(struct strlist *list_set_var, int flags)
12000 struct strlist *lp = list_set_var;
12006 setvareq(lp->text, flags);
12007 } while ((lp = lp->next));
12013 * Find the value of a variable. Returns NULL if not set.
12017 lookupvar(const char *name)
12021 if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
12022 return strchrnul(v->text, '=') + 1;
12029 * Search the environment of a builtin command.
12033 bltinlookup(const char *name)
12035 struct strlist *sp;
12037 for (sp = cmdenviron ; sp ; sp = sp->next) {
12038 if (varequal(sp->text, name))
12039 return strchrnul(sp->text, '=') + 1;
12041 return lookupvar(name);
12046 * Generate a list of variables satisfying the given conditions.
12050 listvars(int on, int off, char ***end)
12061 for (vp = *vpp ; vp ; vp = vp->next)
12062 if ((vp->flags & mask) == on) {
12063 if (ep == stackstrend())
12064 ep = growstackstr();
12065 *ep++ = (char *) vp->text;
12067 } while (++vpp < vartab + VTABSIZE);
12068 if (ep == stackstrend())
12069 ep = growstackstr();
12073 return grabstackstr(ep);
12078 * POSIX requires that 'set' (but not export or readonly) output the
12079 * variables in lexicographic order - by the locale's collating order (sigh).
12080 * Maybe we could keep them in an ordered balanced binary tree
12081 * instead of hashed lists.
12082 * For now just roll 'em through qsort for printing...
12086 showvars(const char *sep_prefix, int on, int off)
12089 char **ep, **epend;
12091 ep = listvars(on, off, &epend);
12092 qsort(ep, epend - ep, sizeof(char *), vpcmp);
12094 sep = *sep_prefix ? spcstr : sep_prefix;
12096 for (; ep < epend; ep++) {
12100 p = strchrnul(*ep, '=');
12103 q = single_quote(++p);
12105 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
12114 * The export and readonly commands.
12118 exportcmd(int argc, char **argv)
12124 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12127 notp = nextopt("p") - 'p';
12128 if (notp && ((name = *(aptr = argptr)))) {
12130 if ((p = strchr(name, '=')) != NULL) {
12133 if ((vp = *findvar(hashvar(name), name))) {
12138 setvar(name, p, flag);
12139 } while ((name = *++aptr) != NULL);
12141 showvars(argv[0], flag, 0);
12148 * Make a variable a local variable. When a variable is made local, it's
12149 * value and flags are saved in a localvar structure. The saved values
12150 * will be restored when the shell function returns. We handle the name
12151 * "-" as a special case.
12155 mklocal(char *name)
12157 struct localvar *lvp;
12162 lvp = ckmalloc(sizeof (struct localvar));
12163 if (name[0] == '-' && name[1] == '\0') {
12165 p = ckmalloc(sizeof(optlist));
12166 lvp->text = memcpy(p, optlist, sizeof(optlist));
12171 vpp = hashvar(name);
12172 vp = *findvar(vpp, name);
12173 eq = strchr(name, '=');
12176 setvareq(name, VSTRFIXED);
12178 setvar(name, NULL, VSTRFIXED);
12179 vp = *vpp; /* the new variable */
12180 lvp->flags = VUNSET;
12182 lvp->text = vp->text;
12183 lvp->flags = vp->flags;
12184 vp->flags |= VSTRFIXED|VTEXTFIXED;
12190 lvp->next = localvars;
12196 * The "local" command.
12200 localcmd(int argc, char **argv)
12205 while ((name = *argv++) != NULL) {
12213 * Called after a function returns.
12214 * Interrupts must be off.
12220 struct localvar *lvp;
12223 while ((lvp = localvars) != NULL) {
12224 localvars = lvp->next;
12226 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
12227 if (vp == NULL) { /* $- saved */
12228 memcpy(optlist, lvp->text, sizeof(optlist));
12231 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12232 unsetvar(vp->text);
12235 (*vp->func)(strchrnul(lvp->text, '=') + 1);
12236 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12238 vp->flags = lvp->flags;
12239 vp->text = lvp->text;
12247 * The unset builtin command. We unset the function before we unset the
12248 * variable to allow a function to be unset when there is a readonly variable
12249 * with the same name.
12253 unsetcmd(int argc, char **argv)
12260 while ((i = nextopt("vf")) != '\0') {
12264 for (ap = argptr; *ap ; ap++) {
12279 * Unset the specified variable.
12283 unsetvar(const char *s)
12289 vpp = findvar(hashvar(s), s);
12293 int flags = vp->flags;
12296 if (flags & VREADONLY)
12298 if (flags & VUNSET)
12300 if ((flags & VSTRFIXED) == 0) {
12302 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
12309 vp->flags &= ~VEXPORT;
12322 * Find the appropriate entry in the hash table from the name.
12325 static struct var **
12326 hashvar(const char *p)
12328 unsigned int hashval;
12330 hashval = ((unsigned char) *p) << 4;
12331 while (*p && *p != '=')
12332 hashval += (unsigned char) *p++;
12333 return &vartab[hashval % VTABSIZE];
12339 * Compares two strings up to the first = or '\0'. The first
12340 * string must be terminated by '='; the second may be terminated by
12341 * either '=' or '\0'.
12345 varcmp(const char *p, const char *q)
12349 while ((c = *p) == (d = *q)) {
12350 if (!c || c == '=')
12364 vpcmp(const void *a, const void *b)
12366 return varcmp(*(const char **)a, *(const char **)b);
12369 static struct var **
12370 findvar(struct var **vpp, const char *name)
12372 for (; *vpp; vpp = &(*vpp)->next) {
12373 if (varequal((*vpp)->text, name)) {
12379 /* $NetBSD: setmode.c,v 1.29 2003/01/15 23:58:03 kleink Exp $ */
12381 #include <sys/times.h>
12383 static const unsigned char timescmd_str[] = {
12384 ' ', offsetof(struct tms, tms_utime),
12385 '\n', offsetof(struct tms, tms_stime),
12386 ' ', offsetof(struct tms, tms_cutime),
12387 '\n', offsetof(struct tms, tms_cstime),
12391 static int timescmd(int ac, char **av)
12393 long int clk_tck, s, t;
12394 const unsigned char *p;
12397 clk_tck = sysconf(_SC_CLK_TCK);
12402 t = *(clock_t *)(((char *) &buf) + p[1]);
12404 out1fmt("%ldm%ld.%.3lds%c",
12406 ((t - s * clk_tck) * 1000) / clk_tck,
12408 } while (*(p += 2));
12413 #ifdef CONFIG_ASH_MATH_SUPPORT
12415 dash_arith(const char *s)
12421 result = arith(s, &errcode);
12424 error("exponent less than 0");
12425 else if (errcode == -2)
12426 error("divide by zero");
12427 else if (errcode == -5)
12428 error("expression recursion loop detected");
12439 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12440 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12442 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12446 letcmd(int argc, char **argv)
12453 error("expression expected");
12454 for (ap = argv + 1; *ap; ap++) {
12455 i = dash_arith(*ap);
12460 #endif /* CONFIG_ASH_MATH_SUPPORT */
12462 /* $NetBSD: miscbltin.c,v 1.31 2002/11/24 22:35:41 christos Exp $ */
12465 * Miscelaneous builtins.
12471 #if __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
12472 typedef enum __rlimit_resource rlim_t;
12478 * The read builtin. The -e option causes backslashes to escape the
12479 * following character.
12481 * This uses unbuffered input, which may be avoidable in some cases.
12485 readcmd(int argc, char **argv)
12500 while ((i = nextopt("p:r")) != '\0') {
12502 prompt = optionarg;
12506 if (prompt && isatty(0)) {
12509 if (*(ap = argptr) == NULL)
12510 error("arg count");
12511 if ((ifs = bltinlookup("IFS")) == NULL)
12518 if (read(0, &c, 1) != 1) {
12530 if (!rflag && c == '\\') {
12536 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12540 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12542 setvar(*ap, stackblock(), 0);
12552 /* Remove trailing blanks */
12553 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12555 setvar(*ap, stackblock(), 0);
12556 while (*++ap != NULL)
12557 setvar(*ap, nullstr, 0);
12562 static int umaskcmd(int argc, char **argv)
12564 static const char permuser[3] = "ugo";
12565 static const char permmode[3] = "rwx";
12566 static const short int permmask[] = {
12567 S_IRUSR, S_IWUSR, S_IXUSR,
12568 S_IRGRP, S_IWGRP, S_IXGRP,
12569 S_IROTH, S_IWOTH, S_IXOTH
12575 int symbolic_mode = 0;
12577 while (nextopt("S") != '\0') {
12586 if ((ap = *argptr) == NULL) {
12587 if (symbolic_mode) {
12591 for (i = 0; i < 3; i++) {
12594 *p++ = permuser[i];
12596 for (j = 0; j < 3; j++) {
12597 if ((mask & permmask[3 * i + j]) == 0) {
12598 *p++ = permmode[j];
12606 out1fmt("%.4o\n", mask);
12609 if (is_digit((unsigned char) *ap)) {
12612 if (*ap >= '8' || *ap < '0')
12613 error(illnum, argv[1]);
12614 mask = (mask << 3) + (*ap - '0');
12615 } while (*++ap != '\0');
12618 mask = ~mask & 0777;
12619 if (!bb_parse_mode(ap, &mask)) {
12620 error("Illegal mode: %s", ap);
12622 umask(~mask & 0777);
12631 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12632 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12633 * ash by J.T. Conklin.
12641 int factor; /* multiply by to get rlim_{cur,max} values */
12645 static const struct limits limits[] = {
12647 { "time(seconds)", RLIMIT_CPU, 1, 't' },
12649 #ifdef RLIMIT_FSIZE
12650 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
12653 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
12655 #ifdef RLIMIT_STACK
12656 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
12659 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
12662 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
12664 #ifdef RLIMIT_MEMLOCK
12665 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
12667 #ifdef RLIMIT_NPROC
12668 { "process", RLIMIT_NPROC, 1, 'p' },
12670 #ifdef RLIMIT_NOFILE
12671 { "nofiles", RLIMIT_NOFILE, 1, 'n' },
12674 { "vmemory(kbytes)", RLIMIT_AS, 1024, 'v' },
12676 #ifdef RLIMIT_LOCKS
12677 { "locks", RLIMIT_LOCKS, 1, 'w' },
12679 { (char *) 0, 0, 0, '\0' }
12682 enum limtype { SOFT = 0x1, HARD = 0x2 };
12684 static void printlim(enum limtype how, const struct rlimit *limit,
12685 const struct limits *l)
12689 val = limit->rlim_max;
12691 val = limit->rlim_cur;
12693 if (val == RLIM_INFINITY)
12694 out1fmt("unlimited\n");
12697 out1fmt("%lld\n", (long long) val);
12702 ulimitcmd(int argc, char **argv)
12706 enum limtype how = SOFT | HARD;
12707 const struct limits *l;
12710 struct rlimit limit;
12713 while ((optc = nextopt("HSatfdsmcnplvw")) != '\0')
12728 for (l = limits; l->option != what; l++)
12731 set = *argptr ? 1 : 0;
12735 if (all || argptr[1])
12736 error("too many arguments");
12737 if (strncmp(p, "unlimited\n", 9) == 0)
12738 val = RLIM_INFINITY;
12742 while ((c = *p++) >= '0' && c <= '9')
12744 val = (val * 10) + (long)(c - '0');
12745 if (val < (rlim_t) 0)
12749 error("bad number");
12754 for (l = limits; l->name; l++) {
12755 getrlimit(l->cmd, &limit);
12756 out1fmt("%-20s ", l->name);
12757 printlim(how, &limit, l);
12762 getrlimit(l->cmd, &limit);
12765 limit.rlim_max = val;
12767 limit.rlim_cur = val;
12768 if (setrlimit(l->cmd, &limit) < 0)
12769 error("error setting limit (%m)");
12771 printlim(how, &limit, l);
12777 #ifdef CONFIG_ASH_MATH_SUPPORT
12779 /* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
12781 Permission is hereby granted, free of charge, to any person obtaining
12782 a copy of this software and associated documentation files (the
12783 "Software"), to deal in the Software without restriction, including
12784 without limitation the rights to use, copy, modify, merge, publish,
12785 distribute, sublicense, and/or sell copies of the Software, and to
12786 permit persons to whom the Software is furnished to do so, subject to
12787 the following conditions:
12789 The above copyright notice and this permission notice shall be
12790 included in all copies or substantial portions of the Software.
12792 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12793 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12794 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
12795 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
12796 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
12797 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
12798 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12801 /* This is my infix parser/evaluator. It is optimized for size, intended
12802 * as a replacement for yacc-based parsers. However, it may well be faster
12803 * than a comparable parser writen in yacc. The supported operators are
12804 * listed in #defines below. Parens, order of operations, and error handling
12805 * are supported. This code is threadsafe. The exact expression format should
12806 * be that which POSIX specifies for shells. */
12808 /* The code uses a simple two-stack algorithm. See
12809 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
12810 * for a detailed explaination of the infix-to-postfix algorithm on which
12811 * this is based (this code differs in that it applies operators immediately
12812 * to the stack instead of adding them to a queue to end up with an
12815 /* To use the routine, call it with an expression string and error return
12819 * Aug 24, 2001 Manuel Novoa III
12821 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
12823 * 1) In arith_apply():
12824 * a) Cached values of *numptr and &(numptr[-1]).
12825 * b) Removed redundant test for zero denominator.
12828 * a) Eliminated redundant code for processing operator tokens by moving
12829 * to a table-based implementation. Also folded handling of parens
12831 * b) Combined all 3 loops which called arith_apply to reduce generated
12832 * code size at the cost of speed.
12834 * 3) The following expressions were treated as valid by the original code:
12835 * 1() , 0! , 1 ( *3 ) .
12836 * These bugs have been fixed by internally enclosing the expression in
12837 * parens and then checking that all binary ops and right parens are
12838 * preceded by a valid expression (NUM_TOKEN).
12840 * Note: It may be desireable to replace Aaron's test for whitespace with
12841 * ctype's isspace() if it is used by another busybox applet or if additional
12842 * whitespace chars should be considered. Look below the "#include"s for a
12843 * precompiler test.
12847 * Aug 26, 2001 Manuel Novoa III
12849 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
12851 * Merge in Aaron's comments previously posted to the busybox list,
12852 * modified slightly to take account of my changes to the code.
12857 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12859 * - allow access to variable,
12860 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
12861 * - realize assign syntax (VAR=expr, +=, *= etc)
12862 * - realize exponentiation (** operator)
12863 * - realize comma separated - expr, expr
12864 * - realise ++expr --expr expr++ expr--
12865 * - realise expr ? expr : expr (but, second expr calculate always)
12866 * - allow hexdecimal and octal numbers
12867 * - was restored loses XOR operator
12868 * - remove one goto label, added three ;-)
12869 * - protect $((num num)) as true zero expr (Manuel`s error)
12870 * - always use special isspace(), see comment from bash ;-)
12874 #define arith_isspace(arithval) \
12875 (arithval == ' ' || arithval == '\n' || arithval == '\t')
12878 typedef unsigned char operator;
12880 /* An operator's token id is a bit of a bitfield. The lower 5 bits are the
12881 * precedence, and 3 high bits are an ID unique accross operators of that
12882 * precedence. The ID portion is so that multiple operators can have the
12883 * same precedence, ensuring that the leftmost one is evaluated first.
12884 * Consider * and /. */
12886 #define tok_decl(prec,id) (((id)<<5)|(prec))
12887 #define PREC(op) ((op) & 0x1F)
12889 #define TOK_LPAREN tok_decl(0,0)
12891 #define TOK_COMMA tok_decl(1,0)
12893 #define TOK_ASSIGN tok_decl(2,0)
12894 #define TOK_AND_ASSIGN tok_decl(2,1)
12895 #define TOK_OR_ASSIGN tok_decl(2,2)
12896 #define TOK_XOR_ASSIGN tok_decl(2,3)
12897 #define TOK_PLUS_ASSIGN tok_decl(2,4)
12898 #define TOK_MINUS_ASSIGN tok_decl(2,5)
12899 #define TOK_LSHIFT_ASSIGN tok_decl(2,6)
12900 #define TOK_RSHIFT_ASSIGN tok_decl(2,7)
12902 #define TOK_MUL_ASSIGN tok_decl(3,0)
12903 #define TOK_DIV_ASSIGN tok_decl(3,1)
12904 #define TOK_REM_ASSIGN tok_decl(3,2)
12906 /* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
12907 #define convert_prec_is_assing(prec) do { if(prec == 3) prec = 2; } while(0)
12909 /* conditional is right associativity too */
12910 #define TOK_CONDITIONAL tok_decl(4,0)
12911 #define TOK_CONDITIONAL_SEP tok_decl(4,1)
12913 #define TOK_OR tok_decl(5,0)
12915 #define TOK_AND tok_decl(6,0)
12917 #define TOK_BOR tok_decl(7,0)
12919 #define TOK_BXOR tok_decl(8,0)
12921 #define TOK_BAND tok_decl(9,0)
12923 #define TOK_EQ tok_decl(10,0)
12924 #define TOK_NE tok_decl(10,1)
12926 #define TOK_LT tok_decl(11,0)
12927 #define TOK_GT tok_decl(11,1)
12928 #define TOK_GE tok_decl(11,2)
12929 #define TOK_LE tok_decl(11,3)
12931 #define TOK_LSHIFT tok_decl(12,0)
12932 #define TOK_RSHIFT tok_decl(12,1)
12934 #define TOK_ADD tok_decl(13,0)
12935 #define TOK_SUB tok_decl(13,1)
12937 #define TOK_MUL tok_decl(14,0)
12938 #define TOK_DIV tok_decl(14,1)
12939 #define TOK_REM tok_decl(14,2)
12941 /* exponent is right associativity */
12942 #define TOK_EXPONENT tok_decl(15,1)
12944 /* For now unary operators. */
12945 #define UNARYPREC 16
12946 #define TOK_BNOT tok_decl(UNARYPREC,0)
12947 #define TOK_NOT tok_decl(UNARYPREC,1)
12949 #define TOK_UMINUS tok_decl(UNARYPREC+1,0)
12950 #define TOK_UPLUS tok_decl(UNARYPREC+1,1)
12952 #define PREC_PRE (UNARYPREC+2)
12954 #define TOK_PRE_INC tok_decl(PREC_PRE, 0)
12955 #define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
12957 #define PREC_POST (UNARYPREC+3)
12959 #define TOK_POST_INC tok_decl(PREC_POST, 0)
12960 #define TOK_POST_DEC tok_decl(PREC_POST, 1)
12962 #define SPEC_PREC (UNARYPREC+4)
12964 #define TOK_NUM tok_decl(SPEC_PREC, 0)
12965 #define TOK_RPAREN tok_decl(SPEC_PREC, 1)
12967 #define NUMPTR (*numstackptr)
12969 static inline int tok_have_assign(operator op)
12971 operator prec = PREC(op);
12973 convert_prec_is_assing(prec);
12974 return (prec == PREC(TOK_ASSIGN) ||
12975 prec == PREC_PRE || prec == PREC_POST);
12978 static inline int is_right_associativity(operator prec)
12980 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) ||
12981 prec == PREC(TOK_CONDITIONAL));
12985 typedef struct ARITCH_VAR_NUM {
12987 long contidional_second_val;
12988 char contidional_second_val_initialized;
12989 char *var; /* if NULL then is regular number,
12990 else is varable name */
12994 typedef struct CHK_VAR_RECURSIVE_LOOPED {
12996 struct CHK_VAR_RECURSIVE_LOOPED *next;
12997 } chk_var_recursive_looped_t;
12999 static chk_var_recursive_looped_t *prev_chk_var_recursive;
13002 static int arith_lookup_val(v_n_t *t)
13005 const char * p = lookupvar(t->var);
13010 /* recursive try as expression */
13011 chk_var_recursive_looped_t *cur;
13012 chk_var_recursive_looped_t cur_save;
13014 for(cur = prev_chk_var_recursive; cur; cur = cur->next) {
13015 if(strcmp(cur->var, t->var) == 0) {
13016 /* expression recursion loop detected */
13020 /* save current lookuped var name */
13021 cur = prev_chk_var_recursive;
13022 cur_save.var = t->var;
13023 cur_save.next = cur;
13024 prev_chk_var_recursive = &cur_save;
13026 t->val = arith (p, &errcode);
13027 /* restore previous ptr after recursiving */
13028 prev_chk_var_recursive = cur;
13031 /* allow undefined var as 0 */
13038 /* "applying" a token means performing it on the top elements on the integer
13039 * stack. For a unary operator it will only change the top element, but a
13040 * binary operator will pop two arguments and push a result */
13042 arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
13047 int ret_arith_lookup_val;
13049 if (NUMPTR == numstack) goto err; /* There is no operator that can work
13050 without arguments */
13051 numptr_m1 = NUMPTR - 1;
13053 /* check operand is var with noninteger value */
13054 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13055 if(ret_arith_lookup_val)
13056 return ret_arith_lookup_val;
13058 rez = numptr_m1->val;
13059 if (op == TOK_UMINUS)
13061 else if (op == TOK_NOT)
13063 else if (op == TOK_BNOT)
13065 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
13067 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
13069 else if (op != TOK_UPLUS) {
13070 /* Binary operators */
13072 /* check and binary operators need two arguments */
13073 if (numptr_m1 == numstack) goto err;
13075 /* ... and they pop one */
13078 if (op == TOK_CONDITIONAL) {
13079 if(! numptr_m1->contidional_second_val_initialized) {
13080 /* protect $((expr1 ? expr2)) without ": expr" */
13083 rez = numptr_m1->contidional_second_val;
13084 } else if(numptr_m1->contidional_second_val_initialized) {
13085 /* protect $((expr1 : expr2)) without "expr ? " */
13088 numptr_m1 = NUMPTR - 1;
13089 if(op != TOK_ASSIGN) {
13090 /* check operand is var with noninteger value for not '=' */
13091 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13092 if(ret_arith_lookup_val)
13093 return ret_arith_lookup_val;
13095 if (op == TOK_CONDITIONAL) {
13096 numptr_m1->contidional_second_val = rez;
13098 rez = numptr_m1->val;
13099 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
13101 else if (op == TOK_OR)
13102 rez = numptr_val || rez;
13103 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
13105 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
13107 else if (op == TOK_AND)
13108 rez = rez && numptr_val;
13109 else if (op == TOK_EQ)
13110 rez = (rez == numptr_val);
13111 else if (op == TOK_NE)
13112 rez = (rez != numptr_val);
13113 else if (op == TOK_GE)
13114 rez = (rez >= numptr_val);
13115 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
13116 rez >>= numptr_val;
13117 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
13118 rez <<= numptr_val;
13119 else if (op == TOK_GT)
13120 rez = (rez > numptr_val);
13121 else if (op == TOK_LT)
13122 rez = (rez < numptr_val);
13123 else if (op == TOK_LE)
13124 rez = (rez <= numptr_val);
13125 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
13127 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
13129 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
13131 else if (op == TOK_ASSIGN || op == TOK_COMMA)
13133 else if (op == TOK_CONDITIONAL_SEP) {
13134 if (numptr_m1 == numstack) {
13135 /* protect $((expr : expr)) without "expr ? " */
13138 numptr_m1->contidional_second_val_initialized = op;
13139 numptr_m1->contidional_second_val = numptr_val;
13141 else if (op == TOK_CONDITIONAL) {
13143 numptr_val : numptr_m1->contidional_second_val;
13145 else if(op == TOK_EXPONENT) {
13147 return -3; /* exponent less than 0 */
13152 while(numptr_val--)
13157 else if(numptr_val==0) /* zero divisor check */
13159 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
13161 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
13164 if(tok_have_assign(op)) {
13167 if(numptr_m1->var == NULL) {
13171 /* save to shell variable */
13172 sprintf(buf, "%ld", rez);
13173 setvar(numptr_m1->var, buf, 0);
13174 /* after saving, make previous value for v++ or v-- */
13175 if(op == TOK_POST_INC)
13177 else if(op == TOK_POST_DEC)
13180 numptr_m1->val = rez;
13181 /* protect geting var value, is number now */
13182 numptr_m1->var = NULL;
13187 /* longest must first */
13188 static const char op_tokens[] = {
13189 '<','<','=',0, TOK_LSHIFT_ASSIGN,
13190 '>','>','=',0, TOK_RSHIFT_ASSIGN,
13191 '<','<', 0, TOK_LSHIFT,
13192 '>','>', 0, TOK_RSHIFT,
13193 '|','|', 0, TOK_OR,
13194 '&','&', 0, TOK_AND,
13195 '!','=', 0, TOK_NE,
13196 '<','=', 0, TOK_LE,
13197 '>','=', 0, TOK_GE,
13198 '=','=', 0, TOK_EQ,
13199 '|','=', 0, TOK_OR_ASSIGN,
13200 '&','=', 0, TOK_AND_ASSIGN,
13201 '*','=', 0, TOK_MUL_ASSIGN,
13202 '/','=', 0, TOK_DIV_ASSIGN,
13203 '%','=', 0, TOK_REM_ASSIGN,
13204 '+','=', 0, TOK_PLUS_ASSIGN,
13205 '-','=', 0, TOK_MINUS_ASSIGN,
13206 '-','-', 0, TOK_POST_DEC,
13207 '^','=', 0, TOK_XOR_ASSIGN,
13208 '+','+', 0, TOK_POST_INC,
13209 '*','*', 0, TOK_EXPONENT,
13213 '=', 0, TOK_ASSIGN,
13225 '?', 0, TOK_CONDITIONAL,
13226 ':', 0, TOK_CONDITIONAL_SEP,
13227 ')', 0, TOK_RPAREN,
13228 '(', 0, TOK_LPAREN,
13232 #define endexpression &op_tokens[sizeof(op_tokens)-7]
13235 extern long arith (const char *expr, int *perrcode)
13237 register char arithval; /* Current character under analysis */
13238 operator lasttok, op;
13241 const char *p = endexpression;
13244 size_t datasizes = strlen(expr) + 2;
13246 /* Stack of integers */
13247 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
13248 * in any given correct or incorrect expression is left as an excersize to
13250 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
13251 *numstackptr = numstack;
13252 /* Stack of operator tokens */
13253 operator *stack = alloca((datasizes) * sizeof(operator)),
13256 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
13257 *perrcode = errcode = 0;
13260 if ((arithval = *expr) == 0) {
13261 if (p == endexpression) {
13262 /* Null expression. */
13266 /* This is only reached after all tokens have been extracted from the
13267 * input stream. If there are still tokens on the operator stack, they
13268 * are to be applied in order. At the end, there should be a final
13269 * result on the integer stack */
13271 if (expr != endexpression + 1) {
13272 /* If we haven't done so already, */
13273 /* append a closing right paren */
13274 expr = endexpression;
13275 /* and let the loop process it. */
13278 /* At this point, we're done with the expression. */
13279 if (numstackptr != numstack+1) {
13280 /* ... but if there isn't, it's bad */
13282 return (*perrcode = -1);
13284 if(numstack->var) {
13285 /* expression is $((var)) only, lookup now */
13286 errcode = arith_lookup_val(numstack);
13289 *perrcode = errcode;
13290 return numstack->val;
13292 /* Continue processing the expression. */
13293 if (arith_isspace(arithval)) {
13294 /* Skip whitespace */
13297 if((p = endofname(expr)) != expr) {
13298 int var_name_size = (p-expr) + 1; /* trailing zero */
13300 numstackptr->var = alloca(var_name_size);
13301 safe_strncpy(numstackptr->var, expr, var_name_size);
13304 numstackptr->contidional_second_val_initialized = 0;
13308 } else if (is_digit(arithval)) {
13309 numstackptr->var = NULL;
13310 numstackptr->val = strtol(expr, (char **) &expr, 0);
13313 for(p = op_tokens; ; p++) {
13317 /* strange operator not found */
13320 for(o = expr; *p && *o == *p; p++)
13327 /* skip tail uncompared token */
13330 /* skip zero delim */
13335 /* post grammar: a++ reduce to num */
13336 if(lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13339 /* Plus and minus are binary (not unary) _only_ if the last
13340 * token was as number, or a right paren (which pretends to be
13341 * a number, since it evaluates to one). Think about it.
13342 * It makes sense. */
13343 if (lasttok != TOK_NUM) {
13359 /* We don't want a unary operator to cause recursive descent on the
13360 * stack, because there can be many in a row and it could cause an
13361 * operator to be evaluated before its argument is pushed onto the
13362 * integer stack. */
13363 /* But for binary operators, "apply" everything on the operator
13364 * stack until we find an operator with a lesser priority than the
13365 * one we have just extracted. */
13366 /* Left paren is given the lowest priority so it will never be
13367 * "applied" in this way.
13368 * if associativity is right and priority eq, applied also skip
13371 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13372 /* not left paren or unary */
13373 if (lasttok != TOK_NUM) {
13374 /* binary op must be preceded by a num */
13377 while (stackptr != stack) {
13378 if (op == TOK_RPAREN) {
13379 /* The algorithm employed here is simple: while we don't
13380 * hit an open paren nor the bottom of the stack, pop
13381 * tokens and apply them */
13382 if (stackptr[-1] == TOK_LPAREN) {
13384 /* Any operator directly after a */
13386 /* close paren should consider itself binary */
13390 operator prev_prec = PREC(stackptr[-1]);
13392 convert_prec_is_assing(prec);
13393 convert_prec_is_assing(prev_prec);
13394 if (prev_prec < prec)
13396 /* check right assoc */
13397 if(prev_prec == prec && is_right_associativity(prec))
13400 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13401 if(errcode) goto ret;
13403 if (op == TOK_RPAREN) {
13408 /* Push this operator to the stack and remember it. */
13409 *stackptr++ = lasttok = op;
13416 #endif /* CONFIG_ASH_MATH_SUPPORT */
13420 const char *bb_applet_name = "debug stuff usage";
13421 int main(int argc, char **argv)
13423 return ash_main(argc, argv);
13428 * Copyright (c) 1989, 1991, 1993, 1994
13429 * The Regents of the University of California. All rights reserved.
13431 * This code is derived from software contributed to Berkeley by
13432 * Kenneth Almquist.
13434 * Redistribution and use in source and binary forms, with or without
13435 * modification, are permitted provided that the following conditions
13437 * 1. Redistributions of source code must retain the above copyright
13438 * notice, this list of conditions and the following disclaimer.
13439 * 2. Redistributions in binary form must reproduce the above copyright
13440 * notice, this list of conditions and the following disclaimer in the
13441 * documentation and/or other materials provided with the distribution.
13443 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
13444 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
13446 * 4. Neither the name of the University nor the names of its contributors
13447 * may be used to endorse or promote products derived from this software
13448 * without specific prior written permission.
13450 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13451 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13452 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13453 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13454 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13455 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13456 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13457 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13458 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13459 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF