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;
4120 #ifdef CONFIG_FEATURE_COMMAND_EDITING
4121 cmdedit_path_lookup = newval;
4127 * Clear out command entries. The argument specifies the first entry in
4128 * PATH which has changed.
4132 clearcmdentry(int firstchange)
4134 struct tblentry **tblp;
4135 struct tblentry **pp;
4136 struct tblentry *cmdp;
4139 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4141 while ((cmdp = *pp) != NULL) {
4142 if ((cmdp->cmdtype == CMDNORMAL &&
4143 cmdp->param.index >= firstchange)
4144 || (cmdp->cmdtype == CMDBUILTIN &&
4145 builtinloc >= firstchange)) {
4159 * Locate a command in the command hash table. If "add" is nonzero,
4160 * add the command to the table if it is not already present. The
4161 * variable "lastcmdentry" is set to point to the address of the link
4162 * pointing to the entry, so that delete_cmd_entry can delete the
4165 * Interrupts must be off if called with add != 0.
4168 static struct tblentry **lastcmdentry;
4171 static struct tblentry *
4172 cmdlookup(const char *name, int add)
4174 unsigned int hashval;
4176 struct tblentry *cmdp;
4177 struct tblentry **pp;
4180 hashval = (unsigned char)*p << 4;
4182 hashval += (unsigned char)*p++;
4184 pp = &cmdtable[hashval % CMDTABLESIZE];
4185 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4186 if (equal(cmdp->cmdname, name))
4190 if (add && cmdp == NULL) {
4191 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4192 + strlen(name) + 1);
4194 cmdp->cmdtype = CMDUNKNOWN;
4195 strcpy(cmdp->cmdname, name);
4202 * Delete the command entry returned on the last lookup.
4206 delete_cmd_entry(void)
4208 struct tblentry *cmdp;
4211 cmdp = *lastcmdentry;
4212 *lastcmdentry = cmdp->next;
4213 if (cmdp->cmdtype == CMDFUNCTION)
4214 freefunc(cmdp->param.func);
4221 * Add a new command entry, replacing any existing command entry for
4222 * the same name - except special builtins.
4226 addcmdentry(char *name, struct cmdentry *entry)
4228 struct tblentry *cmdp;
4230 cmdp = cmdlookup(name, 1);
4231 if (cmdp->cmdtype == CMDFUNCTION) {
4232 freefunc(cmdp->param.func);
4234 cmdp->cmdtype = entry->cmdtype;
4235 cmdp->param = entry->u;
4240 * Make a copy of a parse tree.
4243 static inline struct funcnode *
4244 copyfunc(union node *n)
4249 funcblocksize = offsetof(struct funcnode, n);
4252 blocksize = funcblocksize;
4253 f = ckmalloc(blocksize + funcstringsize);
4254 funcblock = (char *) f + offsetof(struct funcnode, n);
4255 funcstring = (char *) f + blocksize;
4262 * Define a shell function.
4266 defun(char *name, union node *func)
4268 struct cmdentry entry;
4271 entry.cmdtype = CMDFUNCTION;
4272 entry.u.func = copyfunc(func);
4273 addcmdentry(name, &entry);
4279 * Delete a function if it exists.
4283 unsetfunc(const char *name)
4285 struct tblentry *cmdp;
4287 if ((cmdp = cmdlookup(name, 0)) != NULL &&
4288 cmdp->cmdtype == CMDFUNCTION)
4293 * Locate and print what a word is...
4297 #ifdef CONFIG_ASH_CMDCMD
4299 describe_command(char *command, int describe_command_verbose)
4301 #define describe_command_verbose 1
4303 describe_command(char *command)
4306 struct cmdentry entry;
4307 struct tblentry *cmdp;
4308 #ifdef CONFIG_ASH_ALIAS
4309 const struct alias *ap;
4311 const char *path = pathval();
4313 if (describe_command_verbose) {
4317 /* First look at the keywords */
4318 if (findkwd(command)) {
4319 out1str(describe_command_verbose ? " is a shell keyword" : command);
4323 #ifdef CONFIG_ASH_ALIAS
4324 /* Then look at the aliases */
4325 if ((ap = lookupalias(command, 0)) != NULL) {
4326 if (describe_command_verbose) {
4327 out1fmt(" is an alias for %s", ap->val);
4336 /* Then check if it is a tracked alias */
4337 if ((cmdp = cmdlookup(command, 0)) != NULL) {
4338 entry.cmdtype = cmdp->cmdtype;
4339 entry.u = cmdp->param;
4341 /* Finally use brute force */
4342 find_command(command, &entry, DO_ABS, path);
4345 switch (entry.cmdtype) {
4347 int j = entry.u.index;
4353 p = padvance(&path, command);
4357 if (describe_command_verbose) {
4359 (cmdp ? " a tracked alias for" : nullstr), p
4368 if (describe_command_verbose) {
4369 out1str(" is a shell function");
4376 if (describe_command_verbose) {
4377 out1fmt(" is a %sshell builtin",
4378 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
4379 "special " : nullstr
4387 if (describe_command_verbose) {
4388 out1str(": not found\n");
4394 outstr("\n", stdout);
4399 typecmd(int argc, char **argv)
4404 for (i = 1; i < argc; i++) {
4405 #ifdef CONFIG_ASH_CMDCMD
4406 err |= describe_command(argv[i], 1);
4408 err |= describe_command(argv[i]);
4414 #ifdef CONFIG_ASH_CMDCMD
4416 commandcmd(int argc, char **argv)
4419 int default_path = 0;
4420 int verify_only = 0;
4421 int verbose_verify_only = 0;
4423 while ((c = nextopt("pvV")) != '\0')
4428 "command: nextopt returned character code 0%o\n", c);
4438 verbose_verify_only = 1;
4442 if (default_path + verify_only + verbose_verify_only > 1 ||
4445 "command [-p] command [arg ...]\n"
4446 "command {-v|-V} command\n");
4450 if (verify_only || verbose_verify_only) {
4451 return describe_command(*argptr, verbose_verify_only);
4458 /* $NetBSD: expand.c,v 1.56 2002/11/24 22:35:39 christos Exp $ */
4461 * Routines to expand arguments to commands. We have to deal with
4462 * backquotes, shell variables, and file metacharacters.
4468 #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4469 #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
4470 #define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
4471 #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
4472 #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
4475 * Structure specifying which parts of the string should be searched
4476 * for IFS characters.
4480 struct ifsregion *next; /* next region in list */
4481 int begoff; /* offset of start of region */
4482 int endoff; /* offset of end of region */
4483 int nulonly; /* search for nul bytes only */
4486 /* output of current string */
4487 static char *expdest;
4488 /* list of back quote expressions */
4489 static struct nodelist *argbackq;
4490 /* first struct in list of ifs regions */
4491 static struct ifsregion ifsfirst;
4492 /* last struct in list */
4493 static struct ifsregion *ifslastp;
4494 /* holds expanded arg list */
4495 static struct arglist exparg;
4497 static void argstr(char *, int);
4498 static char *exptilde(char *, char *, int);
4499 static void expbackq(union node *, int, int);
4500 static const char *subevalvar(char *, char *, int, int, int, int, int);
4501 static char *evalvar(char *, int);
4502 static void strtodest(const char *, int, int);
4503 static void memtodest(const char *p, size_t len, int syntax, int quotes);
4504 static ssize_t varvalue(char *, int, int);
4505 static void recordregion(int, int, int);
4506 static void removerecordregions(int);
4507 static void ifsbreakup(char *, struct arglist *);
4508 static void ifsfree(void);
4509 static void expandmeta(struct strlist *, int);
4510 static int patmatch(char *, const char *);
4512 static int cvtnum(long);
4513 static size_t esclen(const char *, const char *);
4514 static char *scanleft(char *, char *, char *, char *, int, int);
4515 static char *scanright(char *, char *, char *, char *, int, int);
4516 static void varunset(const char *, const char *, const char *, int)
4517 __attribute__((__noreturn__));
4520 #define pmatch(a, b) !fnmatch((a), (b), 0)
4522 * Prepare a pattern for a expmeta (internal glob(3)) call.
4524 * Returns an stalloced string.
4527 static inline char *
4528 preglob(const char *pattern, int quoted, int flag) {
4529 flag |= RMESCAPE_GLOB;
4531 flag |= RMESCAPE_QUOTED;
4533 return _rmescapes((char *)pattern, flag);
4538 esclen(const char *start, const char *p) {
4541 while (p > start && *--p == CTLESC) {
4549 * Expand shell variables and backquotes inside a here document.
4553 expandhere(union node *arg, int fd)
4556 expandarg(arg, (struct arglist *)NULL, 0);
4557 xwrite(fd, stackblock(), expdest - (char *)stackblock());
4562 * Perform variable substitution and command substitution on an argument,
4563 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4564 * perform splitting and file name expansion. When arglist is NULL, perform
4565 * here document expansion.
4569 expandarg(union node *arg, struct arglist *arglist, int flag)
4574 argbackq = arg->narg.backquote;
4575 STARTSTACKSTR(expdest);
4576 ifsfirst.next = NULL;
4578 argstr(arg->narg.text, flag);
4579 if (arglist == NULL) {
4580 return; /* here document expanded */
4582 STPUTC('\0', expdest);
4583 p = grabstackstr(expdest);
4584 exparg.lastp = &exparg.list;
4588 if (flag & EXP_FULL) {
4589 ifsbreakup(p, &exparg);
4590 *exparg.lastp = NULL;
4591 exparg.lastp = &exparg.list;
4592 expandmeta(exparg.list, flag);
4594 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
4596 sp = (struct strlist *)stalloc(sizeof (struct strlist));
4599 exparg.lastp = &sp->next;
4603 *exparg.lastp = NULL;
4605 *arglist->lastp = exparg.list;
4606 arglist->lastp = exparg.lastp;
4612 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4613 * characters to allow for further processing. Otherwise treat
4614 * $@ like $* since no splitting will be performed.
4618 argstr(char *p, int flag)
4620 static const char spclchars[] = {
4628 CTLBACKQ | CTLQUOTE,
4629 #ifdef CONFIG_ASH_MATH_SUPPORT
4634 const char *reject = spclchars;
4636 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
4637 int breakall = flag & EXP_WORD;
4642 if (!(flag & EXP_VARTILDE)) {
4644 } else if (flag & EXP_VARTILDE2) {
4649 if (flag & EXP_TILDE) {
4655 if (*q == CTLESC && (flag & EXP_QWORD))
4658 p = exptilde(p, q, flag);
4661 startloc = expdest - (char *)stackblock();
4663 length += strcspn(p + length, reject);
4665 if (c && (!(c & 0x80)
4666 #ifdef CONFIG_ASH_MATH_SUPPORT
4670 /* c == '=' || c == ':' || c == CTLENDARI */
4675 expdest = stnputs(p, length, expdest);
4676 newloc = expdest - (char *)stackblock();
4677 if (breakall && !inquotes && newloc > startloc) {
4678 recordregion(startloc, newloc, 0);
4689 if (flag & EXP_VARTILDE2) {
4693 flag |= EXP_VARTILDE2;
4698 * sort of a hack - expand tildes in variable
4699 * assignments (after the first '=' and after ':'s).
4708 case CTLENDVAR: /* ??? */
4711 /* "$@" syntax adherence hack */
4714 !memcmp(p, dolatstr, DOLATSTRLEN) &&
4715 (p[4] == CTLQUOTEMARK || (
4716 p[4] == CTLENDVAR &&
4717 p[5] == CTLQUOTEMARK
4720 p = evalvar(p + 1, flag) + 1;
4723 inquotes = !inquotes;
4736 p = evalvar(p, flag);
4740 case CTLBACKQ|CTLQUOTE:
4741 expbackq(argbackq->n, c, quotes);
4742 argbackq = argbackq->next;
4744 #ifdef CONFIG_ASH_MATH_SUPPORT
4757 exptilde(char *startp, char *p, int flag)
4763 int quotes = flag & (EXP_FULL | EXP_CASE);
4768 while ((c = *++p) != '\0') {
4775 if (flag & EXP_VARTILDE)
4785 if (*name == '\0') {
4786 if ((home = lookupvar(homestr)) == NULL)
4789 if ((pw = getpwnam(name)) == NULL)
4796 startloc = expdest - (char *)stackblock();
4797 strtodest(home, SQSYNTAX, quotes);
4798 recordregion(startloc, expdest - (char *)stackblock(), 0);
4807 removerecordregions(int endoff)
4809 if (ifslastp == NULL)
4812 if (ifsfirst.endoff > endoff) {
4813 while (ifsfirst.next != NULL) {
4814 struct ifsregion *ifsp;
4816 ifsp = ifsfirst.next->next;
4817 ckfree(ifsfirst.next);
4818 ifsfirst.next = ifsp;
4821 if (ifsfirst.begoff > endoff)
4824 ifslastp = &ifsfirst;
4825 ifsfirst.endoff = endoff;
4830 ifslastp = &ifsfirst;
4831 while (ifslastp->next && ifslastp->next->begoff < endoff)
4832 ifslastp=ifslastp->next;
4833 while (ifslastp->next != NULL) {
4834 struct ifsregion *ifsp;
4836 ifsp = ifslastp->next->next;
4837 ckfree(ifslastp->next);
4838 ifslastp->next = ifsp;
4841 if (ifslastp->endoff > endoff)
4842 ifslastp->endoff = endoff;
4846 #ifdef CONFIG_ASH_MATH_SUPPORT
4848 * Expand arithmetic expression. Backup to start of expression,
4849 * evaluate, place result in (backed up) result, adjust string position.
4862 * This routine is slightly over-complicated for
4863 * efficiency. Next we scan backwards looking for the
4864 * start of arithmetic.
4866 start = stackblock();
4873 while (*p != CTLARI) {
4877 error("missing CTLARI (shouldn't happen)");
4882 esc = esclen(start, p);
4892 removerecordregions(begoff);
4901 len = cvtnum(dash_arith(p + 2));
4904 recordregion(begoff, begoff + len, 0);
4909 * Expand stuff in backwards quotes.
4913 expbackq(union node *cmd, int quoted, int quotes)
4921 int syntax = quoted? DQSYNTAX : BASESYNTAX;
4922 struct stackmark smark;
4925 setstackmark(&smark);
4927 startloc = dest - (char *)stackblock();
4929 evalbackcmd(cmd, (struct backcmd *) &in);
4930 popstackmark(&smark);
4937 memtodest(p, i, syntax, quotes);
4941 i = safe_read(in.fd, buf, sizeof buf);
4942 TRACE(("expbackq: read returns %d\n", i));
4952 back_exitstatus = waitforjob(in.jp);
4956 /* Eat all trailing newlines */
4958 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
4963 recordregion(startloc, dest - (char *)stackblock(), 0);
4964 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4965 (dest - (char *)stackblock()) - startloc,
4966 (dest - (char *)stackblock()) - startloc,
4967 stackblock() + startloc));
4972 scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
4983 const char *s = loc2;
4989 match = pmatch(str, s);
4993 if (quotes && *loc == CTLESC)
5003 scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5010 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5013 const char *s = loc2;
5018 match = pmatch(str, s);
5025 esc = esclen(startp, loc);
5037 subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
5041 int saveherefd = herefd;
5042 struct nodelist *saveargbackq = argbackq;
5044 char *rmesc, *rmescend;
5046 char *(*scan)(char *, char *, char *, char *, int , int);
5049 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
5050 STPUTC('\0', expdest);
5051 herefd = saveherefd;
5052 argbackq = saveargbackq;
5053 startp = stackblock() + startloc;
5057 setvar(str, startp, 0);
5058 amount = startp - expdest;
5059 STADJUST(amount, expdest);
5063 varunset(p, str, startp, varflags);
5067 subtype -= VSTRIMRIGHT;
5069 if (subtype < 0 || subtype > 3)
5074 rmescend = stackblock() + strloc;
5076 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5077 if (rmesc != startp) {
5079 startp = stackblock() + startloc;
5083 str = stackblock() + strloc;
5084 preglob(str, varflags & VSQUOTE, 0);
5086 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
5087 zero = subtype >> 1;
5088 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
5089 scan = (subtype & 1) ^ zero ? scanleft : scanright;
5091 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
5094 memmove(startp, loc, str - loc);
5095 loc = startp + (str - loc) - 1;
5098 amount = loc - expdest;
5099 STADJUST(amount, expdest);
5106 * Expand a variable, and return a pointer to the next character in the
5110 evalvar(char *p, int flag)
5123 quotes = flag & (EXP_FULL | EXP_CASE);
5125 subtype = varflags & VSTYPE;
5126 quoted = varflags & VSQUOTE;
5128 easy = (!quoted || (*var == '@' && shellparam.nparam));
5129 startloc = expdest - (char *)stackblock();
5130 p = strchr(p, '=') + 1;
5133 varlen = varvalue(var, varflags, flag);
5134 if (varflags & VSNUL)
5137 if (subtype == VSPLUS) {
5138 varlen = -1 - varlen;
5142 if (subtype == VSMINUS) {
5146 p, flag | EXP_TILDE |
5147 (quoted ? EXP_QWORD : EXP_WORD)
5156 if (subtype == VSASSIGN || subtype == VSQUESTION) {
5158 if (subevalvar(p, var, 0, subtype, startloc,
5162 * Remove any recorded regions beyond
5165 removerecordregions(startloc);
5175 if (varlen < 0 && uflag)
5176 varunset(p, var, 0, 0);
5178 if (subtype == VSLENGTH) {
5179 cvtnum(varlen > 0 ? varlen : 0);
5183 if (subtype == VSNORMAL) {
5187 recordregion(startloc, expdest - (char *)stackblock(), quoted);
5196 case VSTRIMRIGHTMAX:
5205 * Terminate the string and start recording the pattern
5208 STPUTC('\0', expdest);
5209 patloc = expdest - (char *)stackblock();
5210 if (subevalvar(p, NULL, patloc, subtype,
5211 startloc, varflags, quotes) == 0) {
5212 int amount = expdest - (
5213 (char *)stackblock() + patloc - 1
5215 STADJUST(-amount, expdest);
5217 /* Remove any recorded regions beyond start of variable */
5218 removerecordregions(startloc);
5223 if (subtype != VSNORMAL) { /* skip to end of alternative */
5226 if ((c = *p++) == CTLESC)
5228 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
5230 argbackq = argbackq->next;
5231 } else if (c == CTLVAR) {
5232 if ((*p++ & VSTYPE) != VSNORMAL)
5234 } else if (c == CTLENDVAR) {
5245 * Put a string on the stack.
5249 memtodest(const char *p, size_t len, int syntax, int quotes) {
5252 q = makestrspace(len * 2, q);
5258 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5268 strtodest(const char *p, int syntax, int quotes)
5270 memtodest(p, strlen(p), syntax, quotes);
5275 * Add the value of a specialized variable to the stack string.
5279 varvalue(char *name, int varflags, int flags)
5289 int quoted = varflags & VSQUOTE;
5290 int subtype = varflags & VSTYPE;
5291 int quotes = flags & (EXP_FULL | EXP_CASE);
5293 if (quoted && (flags & EXP_FULL))
5294 sep = 1 << CHAR_BIT;
5296 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5305 num = shellparam.nparam;
5315 p = makestrspace(NOPTS, expdest);
5316 for (i = NOPTS - 1; i >= 0; i--) {
5318 USTPUTC(optletters(i), p);
5329 sep = ifsset() ? ifsval()[0] : ' ';
5330 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
5333 if (!(ap = shellparam.p))
5335 while ((p = *ap++)) {
5338 partlen = strlen(p);
5341 if (len > partlen && sep) {
5345 if (subtype == VSPLUS || subtype == VSLENGTH) {
5355 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5356 memtodest(p, partlen, syntax, quotes);
5370 if (num < 0 || num > shellparam.nparam)
5372 p = num ? shellparam.p[num - 1] : arg0;
5375 p = lookupvar(name);
5381 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5382 memtodest(p, len, syntax, quotes);
5386 if (subtype == VSPLUS || subtype == VSLENGTH)
5387 STADJUST(-len, expdest);
5393 * Record the fact that we have to scan this region of the
5394 * string for IFS characters.
5398 recordregion(int start, int end, int nulonly)
5400 struct ifsregion *ifsp;
5402 if (ifslastp == NULL) {
5406 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
5408 ifslastp->next = ifsp;
5412 ifslastp->begoff = start;
5413 ifslastp->endoff = end;
5414 ifslastp->nulonly = nulonly;
5419 * Break the argument string into pieces based upon IFS and add the
5420 * strings to the argument list. The regions of the string to be
5421 * searched for IFS characters have been stored by recordregion.
5424 ifsbreakup(char *string, struct arglist *arglist)
5426 struct ifsregion *ifsp;
5431 const char *ifs, *realifs;
5437 if (ifslastp != NULL) {
5440 realifs = ifsset() ? ifsval() : defifs;
5443 p = string + ifsp->begoff;
5444 nulonly = ifsp->nulonly;
5445 ifs = nulonly ? nullstr : realifs;
5447 while (p < string + ifsp->endoff) {
5451 if (strchr(ifs, *p)) {
5453 ifsspc = (strchr(defifs, *p) != NULL);
5454 /* Ignore IFS whitespace at start */
5455 if (q == start && ifsspc) {
5461 sp = (struct strlist *)stalloc(sizeof *sp);
5463 *arglist->lastp = sp;
5464 arglist->lastp = &sp->next;
5468 if (p >= string + ifsp->endoff) {
5474 if (strchr(ifs, *p) == NULL ) {
5477 } else if (strchr(defifs, *p) == NULL) {
5493 } while ((ifsp = ifsp->next) != NULL);
5502 sp = (struct strlist *)stalloc(sizeof *sp);
5504 *arglist->lastp = sp;
5505 arglist->lastp = &sp->next;
5511 struct ifsregion *p;
5516 struct ifsregion *ifsp;
5522 ifsfirst.next = NULL;
5526 static void expmeta(char *, char *);
5527 static struct strlist *expsort(struct strlist *);
5528 static struct strlist *msort(struct strlist *, int);
5530 static char *expdir;
5534 expandmeta(struct strlist *str, int flag)
5536 static const char metachars[] = {
5539 /* TODO - EXP_REDIR */
5542 struct strlist **savelastp;
5548 if (!strpbrk(str->text, metachars))
5550 savelastp = exparg.lastp;
5553 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
5555 int i = strlen(str->text);
5556 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5564 if (exparg.lastp == savelastp) {
5569 *exparg.lastp = str;
5570 rmescapes(str->text);
5571 exparg.lastp = &str->next;
5573 *exparg.lastp = NULL;
5574 *savelastp = sp = expsort(*savelastp);
5575 while (sp->next != NULL)
5577 exparg.lastp = &sp->next;
5584 * Add a file name to the list.
5588 addfname(const char *name)
5592 sp = (struct strlist *)stalloc(sizeof *sp);
5593 sp->text = sstrdup(name);
5595 exparg.lastp = &sp->next;
5600 * Do metacharacter (i.e. *, ?, [...]) expansion.
5604 expmeta(char *enddir, char *name)
5619 for (p = name; *p; p++) {
5620 if (*p == '*' || *p == '?')
5622 else if (*p == '[') {
5629 if (*q == '/' || *q == '\0')
5636 } else if (*p == '\\')
5638 else if (*p == '/') {
5645 if (metaflag == 0) { /* we've reached the end of the file name */
5646 if (enddir != expdir)
5654 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
5665 } while (p < start);
5667 if (enddir == expdir) {
5669 } else if (enddir == expdir + 1 && *expdir == '/') {
5675 if ((dirp = opendir(cp)) == NULL)
5677 if (enddir != expdir)
5679 if (*endname == 0) {
5691 while (! intpending && (dp = readdir(dirp)) != NULL) {
5692 if (dp->d_name[0] == '.' && ! matchdot)
5694 if (pmatch(start, dp->d_name)) {
5696 scopy(dp->d_name, enddir);
5699 for (p = enddir, cp = dp->d_name;
5700 (*p++ = *cp++) != '\0';)
5703 expmeta(p, endname);
5713 * Sort the results of file name expansion. It calculates the number of
5714 * strings to sort and then calls msort (short for merge sort) to do the
5718 static struct strlist *
5719 expsort(struct strlist *str)
5725 for (sp = str ; sp ; sp = sp->next)
5727 return msort(str, len);
5731 static struct strlist *
5732 msort(struct strlist *list, int len)
5734 struct strlist *p, *q = NULL;
5735 struct strlist **lpp;
5743 for (n = half ; --n >= 0 ; ) {
5747 q->next = NULL; /* terminate first half of list */
5748 q = msort(list, half); /* sort first half of list */
5749 p = msort(p, len - half); /* sort second half */
5752 #ifdef CONFIG_LOCALE_SUPPORT
5753 if (strcoll(p->text, q->text) < 0)
5755 if (strcmp(p->text, q->text) < 0)
5760 if ((p = *lpp) == NULL) {
5767 if ((q = *lpp) == NULL) {
5778 * Returns true if the pattern matches the string.
5782 patmatch(char *pattern, const char *string)
5784 return pmatch(preglob(pattern, 0, 0), string);
5789 * Remove any CTLESC characters from a string.
5793 _rmescapes(char *str, int flag)
5796 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
5801 p = strpbrk(str, qchars);
5807 if (flag & RMESCAPE_ALLOC) {
5808 size_t len = p - str;
5809 size_t fulllen = len + strlen(p) + 1;
5811 if (flag & RMESCAPE_GROW) {
5812 r = makestrspace(fulllen, expdest);
5813 } else if (flag & RMESCAPE_HEAP) {
5814 r = ckmalloc(fulllen);
5816 r = stalloc(fulllen);
5820 q = mempcpy(q, str, len);
5823 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5824 globbing = flag & RMESCAPE_GLOB;
5825 notescaped = globbing;
5827 if (*p == CTLQUOTEMARK) {
5828 inquotes = ~inquotes;
5830 notescaped = globbing;
5834 /* naked back slash */
5840 if (notescaped && inquotes && *p != '/') {
5844 notescaped = globbing;
5849 if (flag & RMESCAPE_GROW) {
5851 STADJUST(q - r + 1, expdest);
5858 * See if a pattern matches in a case statement.
5862 casematch(union node *pattern, char *val)
5864 struct stackmark smark;
5867 setstackmark(&smark);
5868 argbackq = pattern->narg.backquote;
5869 STARTSTACKSTR(expdest);
5871 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
5872 STACKSTRNUL(expdest);
5873 result = patmatch(stackblock(), val);
5874 popstackmark(&smark);
5887 expdest = makestrspace(32, expdest);
5888 len = fmtstr(expdest, 32, "%ld", num);
5889 STADJUST(len, expdest);
5894 varunset(const char *end, const char *var, const char *umsg, int varflags)
5900 msg = "parameter not set";
5902 if (*end == CTLENDVAR) {
5903 if (varflags & VSNUL)
5908 error("%.*s: %s%s", end - var - 1, var, msg, tail);
5912 /* $NetBSD: input.c,v 1.37 2002/11/24 22:35:40 christos Exp $ */
5915 * This implements the input routines used by the parser.
5918 #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
5919 #define IBUFSIZ (BUFSIZ + 1)
5921 static void pushfile(void);
5924 * Read a line from the script.
5927 static inline char *
5928 pfgets(char *line, int len)
5934 while (--nleft > 0) {
5951 * Read a character from the script, returning PEOF on end of file.
5952 * Nul characters in the input are silently discarded.
5955 #define pgetc_as_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
5957 #ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
5958 #define pgetc_macro() pgetc()
5962 return pgetc_as_macro();
5965 #define pgetc_macro() pgetc_as_macro()
5969 return pgetc_macro();
5975 * Same as pgetc(), but ignores PEOA.
5977 #ifdef CONFIG_ASH_ALIAS
5978 static int pgetc2(void)
5984 } while (c == PEOA);
5988 static inline int pgetc2(void)
5990 return pgetc_macro();
5995 #ifdef CONFIG_FEATURE_COMMAND_EDITING
5996 static const char *cmdedit_prompt;
5997 static inline void putprompt(const char *s)
6002 static inline void putprompt(const char *s)
6012 char *buf = parsefile->buf;
6016 #ifdef CONFIG_FEATURE_COMMAND_EDITING
6017 if (!iflag || parsefile->fd)
6018 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6020 nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
6022 /* Ctrl+C presend */
6027 /* Ctrl+D presend */
6032 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6036 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6037 int flags = fcntl(0, F_GETFL, 0);
6038 if (flags >= 0 && flags & O_NONBLOCK) {
6039 flags &=~ O_NONBLOCK;
6040 if (fcntl(0, F_SETFL, flags) >= 0) {
6041 out2str("sh: turning off NDELAY mode\n");
6051 * Refill the input buffer and return the next input character:
6053 * 1) If a string was pushed back on the input, pop it;
6054 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6055 * from a string so we can't refill the buffer, return EOF.
6056 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6057 * 4) Process input up to the next newline, deleting nul characters.
6067 while (parsefile->strpush) {
6068 #ifdef CONFIG_ASH_ALIAS
6069 if (parsenleft == -1 && parsefile->strpush->ap &&
6070 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
6075 if (--parsenleft >= 0)
6076 return (*parsenextc++);
6078 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6083 if (parselleft <= 0) {
6084 if ((parselleft = preadfd()) <= 0) {
6085 parselleft = parsenleft = EOF_NLEFT;
6092 /* delete nul characters */
6093 for (more = 1; more;) {
6100 parsenleft = q - parsenextc;
6101 more = 0; /* Stop processing here */
6108 if (--parselleft <= 0 && more) {
6109 parsenleft = q - parsenextc - 1;
6120 out2str(parsenextc);
6125 return *parsenextc++;
6129 * Undo the last call to pgetc. Only one character may be pushed back.
6130 * PEOF may be pushed back.
6141 * Push a string back onto the input at this current parsefile level.
6142 * We handle aliases this way.
6145 pushstring(char *s, void *ap)
6152 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6153 if (parsefile->strpush) {
6154 sp = ckmalloc(sizeof (struct strpush));
6155 sp->prev = parsefile->strpush;
6156 parsefile->strpush = sp;
6158 sp = parsefile->strpush = &(parsefile->basestrpush);
6159 sp->prevstring = parsenextc;
6160 sp->prevnleft = parsenleft;
6161 #ifdef CONFIG_ASH_ALIAS
6162 sp->ap = (struct alias *)ap;
6164 ((struct alias *)ap)->flag |= ALIASINUSE;
6176 struct strpush *sp = parsefile->strpush;
6179 #ifdef CONFIG_ASH_ALIAS
6181 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6182 checkkwd |= CHKALIAS;
6184 if (sp->string != sp->ap->val) {
6187 sp->ap->flag &= ~ALIASINUSE;
6188 if (sp->ap->flag & ALIASDEAD) {
6189 unalias(sp->ap->name);
6193 parsenextc = sp->prevstring;
6194 parsenleft = sp->prevnleft;
6195 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6196 parsefile->strpush = sp->prev;
6197 if (sp != &(parsefile->basestrpush))
6203 * Set the input to take input from a file. If push is set, push the
6204 * old input onto the stack first.
6208 setinputfile(const char *fname, int push)
6214 if ((fd = open(fname, O_RDONLY)) < 0)
6215 error("Can't open %s", fname);
6217 fd2 = copyfd(fd, 10);
6220 error("Out of file descriptors");
6223 setinputfd(fd, push);
6229 * Like setinputfile, but takes an open file descriptor. Call this with
6234 setinputfd(int fd, int push)
6236 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
6242 if (parsefile->buf == NULL)
6243 parsefile->buf = ckmalloc(IBUFSIZ);
6244 parselleft = parsenleft = 0;
6250 * Like setinputfile, but takes input from a string.
6254 setinputstring(char *string)
6258 parsenextc = string;
6259 parsenleft = strlen(string);
6260 parsefile->buf = NULL;
6267 * To handle the "." command, a stack of input files is used. Pushfile
6268 * adds a new entry to the stack and popfile restores the previous level.
6274 struct parsefile *pf;
6276 parsefile->nleft = parsenleft;
6277 parsefile->lleft = parselleft;
6278 parsefile->nextc = parsenextc;
6279 parsefile->linno = plinno;
6280 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
6281 pf->prev = parsefile;
6284 pf->basestrpush.prev = NULL;
6292 struct parsefile *pf = parsefile;
6301 parsefile = pf->prev;
6303 parsenleft = parsefile->nleft;
6304 parselleft = parsefile->lleft;
6305 parsenextc = parsefile->nextc;
6306 plinno = parsefile->linno;
6312 * Return to top level.
6318 while (parsefile != &basepf)
6324 * Close the file(s) that the shell is reading commands from. Called
6325 * after a fork is done.
6332 if (parsefile->fd > 0) {
6333 close(parsefile->fd);
6338 /* $NetBSD: jobs.c,v 1.56 2002/11/25 12:13:03 agc Exp $ */
6340 /* mode flags for set_curjob */
6341 #define CUR_DELETE 2
6342 #define CUR_RUNNING 1
6343 #define CUR_STOPPED 0
6345 /* mode flags for dowait */
6346 #define DOWAIT_NORMAL 0
6347 #define DOWAIT_BLOCK 1
6350 static struct job *jobtab;
6352 static unsigned njobs;
6354 /* pgrp of shell on invocation */
6355 static int initialpgrp;
6356 static int ttyfd = -1;
6359 static struct job *curjob;
6360 /* number of presumed living untracked jobs */
6363 static void set_curjob(struct job *, unsigned);
6365 static int restartjob(struct job *, int);
6366 static void xtcsetpgrp(int, pid_t);
6367 static char *commandtext(union node *);
6368 static void cmdlist(union node *, int);
6369 static void cmdtxt(union node *);
6370 static void cmdputs(const char *);
6371 static void showpipe(struct job *, FILE *);
6373 static int sprint_status(char *, int, int);
6374 static void freejob(struct job *);
6375 static struct job *getjob(const char *, int);
6376 static struct job *growjobtab(void);
6377 static void forkchild(struct job *, union node *, int);
6378 static void forkparent(struct job *, union node *, int, pid_t);
6379 static int dowait(int, struct job *);
6380 static int getstatus(struct job *);
6383 set_curjob(struct job *jp, unsigned mode)
6386 struct job **jpp, **curp;
6388 /* first remove from list */
6389 jpp = curp = &curjob;
6394 jpp = &jp1->prev_job;
6396 *jpp = jp1->prev_job;
6398 /* Then re-insert in correct position */
6406 /* job being deleted */
6409 /* newly created job or backgrounded job,
6410 put after all stopped jobs. */
6414 if (!jp1 || jp1->state != JOBSTOPPED)
6417 jpp = &jp1->prev_job;
6423 /* newly stopped job - becomes curjob */
6424 jp->prev_job = *jpp;
6432 * Turn job control on and off.
6434 * Note: This code assumes that the third arg to ioctl is a character
6435 * pointer, which is true on Berkeley systems but not System V. Since
6436 * System V doesn't have job control yet, this isn't a problem now.
6438 * Called with interrupts off.
6447 if (on == jobctl || rootshell == 0)
6451 ofd = fd = open(_PATH_TTY, O_RDWR);
6454 while (!isatty(fd) && --fd >= 0)
6457 fd = fcntl(fd, F_DUPFD, 10);
6461 fcntl(fd, F_SETFD, FD_CLOEXEC);
6462 do { /* while we are in the background */
6463 if ((pgrp = tcgetpgrp(fd)) < 0) {
6465 sh_warnx("can't access tty; job control turned off");
6469 if (pgrp == getpgrp())
6480 xtcsetpgrp(fd, pgrp);
6482 /* turning job control off */
6485 xtcsetpgrp(fd, pgrp);
6499 killcmd(int argc, char **argv)
6510 "Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6511 "kill -l [exitstatus]"
6515 if (**++argv == '-') {
6516 signo = decode_signal(*argv + 1, 1);
6520 while ((c = nextopt("ls:")) != '\0')
6530 signo = decode_signal(optionarg, 1);
6533 "invalid signal number or name: %s",
6544 if (!list && signo < 0)
6547 if ((signo < 0 || !*argv) ^ list) {
6555 for (i = 1; i < NSIG; i++) {
6556 name = u_signal_names(0, &i, 1);
6558 out1fmt(snlfmt, name);
6562 name = u_signal_names(*argptr, &signo, -1);
6564 out1fmt(snlfmt, name);
6566 error("invalid signal number or exit status: %s", *argptr);
6572 if (**argv == '%') {
6573 jp = getjob(*argv, 0);
6574 pid = -jp->ps[0].pid;
6576 pid = number(*argv);
6577 if (kill(pid, signo) != 0) {
6587 #if defined(JOBS) || defined(DEBUG)
6589 jobno(const struct job *jp)
6591 return jp - jobtab + 1;
6597 fgcmd(int argc, char **argv)
6604 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
6609 jp = getjob(*argv, 1);
6610 if (mode == FORK_BG) {
6611 set_curjob(jp, CUR_RUNNING);
6612 fprintf(out, "[%d] ", jobno(jp));
6614 outstr(jp->ps->cmd, out);
6616 retval = restartjob(jp, mode);
6617 } while (*argv && *++argv);
6621 static int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
6625 restartjob(struct job *jp, int mode)
6627 struct procstat *ps;
6633 if (jp->state == JOBDONE)
6635 jp->state = JOBRUNNING;
6637 if (mode == FORK_FG)
6638 xtcsetpgrp(ttyfd, pgid);
6639 killpg(pgid, SIGCONT);
6643 if (WIFSTOPPED(ps->status)) {
6646 } while (ps++, --i);
6648 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
6655 sprint_status(char *s, int status, int sigonly)
6661 if (!WIFEXITED(status)) {
6663 if (WIFSTOPPED(status))
6664 st = WSTOPSIG(status);
6667 st = WTERMSIG(status);
6669 if (st == SIGINT || st == SIGPIPE)
6672 if (WIFSTOPPED(status))
6677 col = fmtstr(s, 32, strsignal(st));
6678 if (WCOREDUMP(status)) {
6679 col += fmtstr(s + col, 16, " (core dumped)");
6681 } else if (!sigonly) {
6682 st = WEXITSTATUS(status);
6684 col = fmtstr(s, 16, "Done(%d)", st);
6686 col = fmtstr(s, 16, "Done");
6695 showjob(FILE *out, struct job *jp, int mode)
6697 struct procstat *ps;
6698 struct procstat *psend;
6705 if (mode & SHOW_PGID) {
6706 /* just output process (group) id of pipeline */
6707 fprintf(out, "%d\n", ps->pid);
6711 col = fmtstr(s, 16, "[%d] ", jobno(jp));
6716 else if (curjob && jp == curjob->prev_job)
6719 if (mode & SHOW_PID)
6720 col += fmtstr(s + col, 16, "%d ", ps->pid);
6722 psend = ps + jp->nprocs;
6724 if (jp->state == JOBRUNNING) {
6725 scopy("Running", s + col);
6726 col += strlen("Running");
6728 int status = psend[-1].status;
6730 if (jp->state == JOBSTOPPED)
6731 status = jp->stopstatus;
6733 col += sprint_status(s + col, status, 0);
6739 /* for each process */
6740 col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
6743 fprintf(out, "%s%*c%s",
6744 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
6746 if (!(mode & SHOW_PID)) {
6750 if (++ps == psend) {
6751 outcslow('\n', out);
6758 if (jp->state == JOBDONE) {
6759 TRACE(("showjob: freeing job %d\n", jobno(jp)));
6766 jobscmd(int argc, char **argv)
6772 while ((m = nextopt("lp")))
6782 showjob(out, getjob(*argv,0), mode);
6785 showjobs(out, mode);
6792 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6793 * statuses have changed since the last call to showjobs.
6797 showjobs(FILE *out, int mode)
6801 TRACE(("showjobs(%x) called\n", mode));
6803 /* If not even one one job changed, there is nothing to do */
6804 while (dowait(DOWAIT_NORMAL, NULL) > 0)
6807 for (jp = curjob; jp; jp = jp->prev_job) {
6808 if (!(mode & SHOW_CHANGED) || jp->changed)
6809 showjob(out, jp, mode);
6815 * Mark a job structure as unused.
6819 freejob(struct job *jp)
6821 struct procstat *ps;
6825 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
6826 if (ps->cmd != nullstr)
6829 if (jp->ps != &jp->ps0)
6832 set_curjob(jp, CUR_DELETE);
6838 waitcmd(int argc, char **argv)
6851 /* wait for all jobs */
6856 /* no running procs */
6859 if (jp->state == JOBRUNNING)
6864 dowait(DOWAIT_BLOCK, 0);
6870 if (**argv != '%') {
6871 pid_t pid = number(*argv);
6875 if (job->ps[job->nprocs - 1].pid == pid)
6877 job = job->prev_job;
6883 job = getjob(*argv, 0);
6884 /* loop until process terminated or stopped */
6885 while (job->state == JOBRUNNING)
6886 dowait(DOWAIT_BLOCK, 0);
6888 retval = getstatus(job);
6899 * Convert a job name to a job structure.
6903 getjob(const char *name, int getctl)
6907 const char *err_msg = "No such job: %s";
6911 char *(*match)(const char *, const char *);
6926 if (c == '+' || c == '%') {
6928 err_msg = "No current job";
6930 } else if (c == '-') {
6933 err_msg = "No previous job";
6944 jp = jobtab + num - 1;
6961 if (match(jp->ps[0].cmd, p)) {
6965 err_msg = "%s: ambiguous";
6972 err_msg = "job %s not created under job control";
6973 if (getctl && jp->jobctl == 0)
6978 error(err_msg, name);
6983 * Return a new job structure.
6984 * Called with interrupts off.
6988 makejob(union node *node, int nprocs)
6993 for (i = njobs, jp = jobtab ; ; jp++) {
7000 if (jp->state != JOBDONE || !jp->waited)
7009 memset(jp, 0, sizeof(*jp));
7014 jp->prev_job = curjob;
7019 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
7021 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
7031 struct job *jp, *jq;
7033 len = njobs * sizeof(*jp);
7035 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
7037 offset = (char *)jp - (char *)jq;
7039 /* Relocate pointers */
7042 jq = (struct job *)((char *)jq + l);
7046 #define joff(p) ((struct job *)((char *)(p) + l))
7047 #define jmove(p) (p) = (void *)((char *)(p) + offset)
7048 if (likely(joff(jp)->ps == &jq->ps0))
7049 jmove(joff(jp)->ps);
7050 if (joff(jp)->prev_job)
7051 jmove(joff(jp)->prev_job);
7061 jp = (struct job *)((char *)jp + len);
7065 } while (--jq >= jp);
7071 * Fork off a subshell. If we are doing job control, give the subshell its
7072 * own process group. Jp is a job structure that the job is to be added to.
7073 * N is the command that will be evaluated by the child. Both jp and n may
7074 * be NULL. The mode parameter can be one of the following:
7075 * FORK_FG - Fork off a foreground process.
7076 * FORK_BG - Fork off a background process.
7077 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
7078 * process group even if job control is on.
7080 * When job control is turned off, background processes have their standard
7081 * input redirected to /dev/null (except for the second and later processes
7084 * Called with interrupts off.
7088 forkchild(struct job *jp, union node *n, int mode)
7092 TRACE(("Child shell %d\n", getpid()));
7093 wasroot = rootshell;
7099 /* do job control only in root shell */
7101 if (mode != FORK_NOJOB && jp->jobctl && wasroot) {
7104 if (jp->nprocs == 0)
7107 pgrp = jp->ps[0].pid;
7108 /* This can fail because we are doing it in the parent also */
7109 (void)setpgid(0, pgrp);
7110 if (mode == FORK_FG)
7111 xtcsetpgrp(ttyfd, pgrp);
7116 if (mode == FORK_BG) {
7119 if (jp->nprocs == 0) {
7121 if (open(_PATH_DEVNULL, O_RDONLY) != 0)
7122 error("Can't open %s", _PATH_DEVNULL);
7125 if (wasroot && iflag) {
7130 for (jp = curjob; jp; jp = jp->prev_job)
7136 forkparent(struct job *jp, union node *n, int mode, pid_t pid)
7138 TRACE(("In parent shell: child = %d\n", pid));
7140 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
7145 if (mode != FORK_NOJOB && jp->jobctl) {
7148 if (jp->nprocs == 0)
7151 pgrp = jp->ps[0].pid;
7152 /* This can fail because we are doing it in the child also */
7153 (void)setpgid(pid, pgrp);
7156 if (mode == FORK_BG) {
7157 backgndpid = pid; /* set $! */
7158 set_curjob(jp, CUR_RUNNING);
7161 struct procstat *ps = &jp->ps[jp->nprocs++];
7167 ps->cmd = commandtext(n);
7173 forkshell(struct job *jp, union node *n, int mode)
7177 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
7180 TRACE(("Fork failed, errno=%d", errno));
7183 error("Cannot fork");
7186 forkchild(jp, n, mode);
7188 forkparent(jp, n, mode, pid);
7193 * Wait for job to finish.
7195 * Under job control we have the problem that while a child process is
7196 * running interrupts generated by the user are sent to the child but not
7197 * to the shell. This means that an infinite loop started by an inter-
7198 * active user may be hard to kill. With job control turned off, an
7199 * interactive user may place an interactive program inside a loop. If
7200 * the interactive program catches interrupts, the user doesn't want
7201 * these interrupts to also abort the loop. The approach we take here
7202 * is to have the shell ignore interrupt signals while waiting for a
7203 * forground process to terminate, and then send itself an interrupt
7204 * signal if the child process was terminated by an interrupt signal.
7205 * Unfortunately, some programs want to do a bit of cleanup and then
7206 * exit on interrupt; unless these processes terminate themselves by
7207 * sending a signal to themselves (instead of calling exit) they will
7208 * confuse this approach.
7210 * Called with interrupts off.
7214 waitforjob(struct job *jp)
7218 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
7219 while (jp->state == JOBRUNNING) {
7220 dowait(DOWAIT_BLOCK, jp);
7225 xtcsetpgrp(ttyfd, rootpid);
7227 * This is truly gross.
7228 * If we're doing job control, then we did a TIOCSPGRP which
7229 * caused us (the shell) to no longer be in the controlling
7230 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7231 * intuit from the subprocess exit status whether a SIGINT
7232 * occurred, and if so interrupt ourselves. Yuck. - mycroft
7237 if (jp->state == JOBDONE)
7245 * Do a wait system call. If job control is compiled in, we accept
7246 * stopped processes. If block is zero, we return a value of zero
7247 * rather than blocking.
7249 * System V doesn't have a non-blocking wait system call. It does
7250 * have a SIGCLD signal that is sent to a process when one of it's
7251 * children dies. The obvious way to use SIGCLD would be to install
7252 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7253 * was received, and have waitproc bump another counter when it got
7254 * the status of a process. Waitproc would then know that a wait
7255 * system call would not block if the two counters were different.
7256 * This approach doesn't work because if a process has children that
7257 * have not been waited for, System V will send it a SIGCLD when it
7258 * installs a signal handler for SIGCLD. What this means is that when
7259 * a child exits, the shell will be sent SIGCLD signals continuously
7260 * until is runs out of stack space, unless it does a wait call before
7261 * restoring the signal handler. The code below takes advantage of
7262 * this (mis)feature by installing a signal handler for SIGCLD and
7263 * then checking to see whether it was called. If there are any
7264 * children to be waited for, it will be.
7266 * If neither SYSV nor BSD is defined, we don't implement nonblocking
7267 * waits at all. In this case, the user will not be informed when
7268 * a background process until the next time she runs a real program
7269 * (as opposed to running a builtin command or just typing return),
7270 * and the jobs command may give out of date information.
7274 waitproc(int block, int *status)
7284 return wait3(status, flags, (struct rusage *)NULL);
7288 * Wait for a process to terminate.
7292 dowait(int block, struct job *job)
7297 struct job *thisjob;
7300 TRACE(("dowait(%d) called\n", block));
7301 pid = waitproc(block, &status);
7302 TRACE(("wait returns pid %d, status=%d\n", pid, status));
7307 for (jp = curjob; jp; jp = jp->prev_job) {
7308 struct procstat *sp;
7309 struct procstat *spend;
7310 if (jp->state == JOBDONE)
7313 spend = jp->ps + jp->nprocs;
7316 if (sp->pid == pid) {
7317 TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
7318 sp->status = status;
7321 if (sp->status == -1)
7324 if (state == JOBRUNNING)
7326 if (WIFSTOPPED(sp->status)) {
7327 jp->stopstatus = sp->status;
7331 } while (++sp < spend);
7336 if (!WIFSTOPPED(status))
7343 if (state != JOBRUNNING) {
7344 thisjob->changed = 1;
7346 if (thisjob->state != state) {
7347 TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
7348 thisjob->state = state;
7350 if (state == JOBSTOPPED) {
7351 set_curjob(thisjob, CUR_STOPPED);
7360 if (thisjob && thisjob == job) {
7364 len = sprint_status(s, status, 1);
7376 * return 1 if there are stopped jobs, otherwise 0
7389 if (jp && jp->state == JOBSTOPPED) {
7390 out2str("You have stopped jobs.\n");
7400 * Return a string identifying a command (to be printed by the
7405 static char *cmdnextc;
7408 commandtext(union node *n)
7412 STARTSTACKSTR(cmdnextc);
7414 name = stackblock();
7415 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
7416 name, cmdnextc, cmdnextc));
7417 return savestr(name);
7421 cmdtxt(union node *n)
7424 struct nodelist *lp;
7434 lp = n->npipe.cmdlist;
7452 cmdtxt(n->nbinary.ch1);
7468 cmdtxt(n->nif.test);
7471 if (n->nif.elsepart) {
7474 n = n->nif.elsepart;
7490 cmdtxt(n->nbinary.ch1);
7500 cmdputs(n->nfor.var);
7502 cmdlist(n->nfor.args, 1);
7507 cmdputs(n->narg.text);
7511 cmdlist(n->ncmd.args, 1);
7512 cmdlist(n->ncmd.redirect, 0);
7525 cmdputs(n->ncase.expr->narg.text);
7527 for (np = n->ncase.cases; np; np = np->nclist.next) {
7528 cmdtxt(np->nclist.pattern);
7530 cmdtxt(np->nclist.body);
7556 s[0] = n->nfile.fd + '0';
7560 if (n->type == NTOFD || n->type == NFROMFD) {
7561 s[0] = n->ndup.dupfd + '0';
7572 cmdlist(union node *np, int sep)
7574 for (; np; np = np->narg.next) {
7578 if (sep && np->narg.next)
7584 cmdputs(const char *s)
7586 const char *p, *str;
7587 char c, cc[2] = " ";
7591 static const char *const vstype[16] = {
7592 nullstr, "}", "-", "+", "?", "=",
7593 "#", "##", "%", "%%"
7596 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
7598 while ((c = *p++) != 0) {
7606 if ((subtype & VSTYPE) == VSLENGTH)
7610 if (!(subtype & VSQUOTE) != !(quoted & 1)) {
7628 case CTLBACKQ+CTLQUOTE:
7631 #ifdef CONFIG_ASH_MATH_SUPPORT
7646 str = vstype[subtype & VSTYPE];
7647 if (subtype & VSNUL)
7658 /* These can only happen inside quotes */
7670 while ((c = *str++)) {
7675 USTPUTC('"', nextc);
7683 showpipe(struct job *jp, FILE *out)
7685 struct procstat *sp;
7686 struct procstat *spend;
7688 spend = jp->ps + jp->nprocs;
7689 for (sp = jp->ps + 1; sp < spend; sp++)
7690 fprintf(out, " | %s", sp->cmd);
7691 outcslow('\n', out);
7696 xtcsetpgrp(int fd, pid_t pgrp)
7698 if (tcsetpgrp(fd, pgrp))
7699 error("Cannot set tty process group (%m)");
7704 getstatus(struct job *job) {
7708 status = job->ps[job->nprocs - 1].status;
7709 retval = WEXITSTATUS(status);
7710 if (!WIFEXITED(status)) {
7712 retval = WSTOPSIG(status);
7713 if (!WIFSTOPPED(status))
7716 /* XXX: limits number of signals */
7717 retval = WTERMSIG(status);
7719 if (retval == SIGINT)
7725 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
7726 jobno(job), job->nprocs, status, retval));
7730 #ifdef CONFIG_ASH_MAIL
7731 /* $NetBSD: mail.c,v 1.15 2002/11/24 22:35:40 christos Exp $ */
7734 * Routines to check for mail. (Perhaps make part of main.c?)
7737 #define MAXMBOXES 10
7739 /* times of mailboxes */
7740 static time_t mailtime[MAXMBOXES];
7741 /* Set if MAIL or MAILPATH is changed. */
7742 static int mail_var_path_changed;
7747 * Print appropriate message(s) if mail has arrived.
7748 * If mail_var_path_changed is set,
7749 * then the value of MAIL has mail_var_path_changed,
7750 * so we just update the values.
7760 struct stackmark smark;
7763 setstackmark(&smark);
7764 mpath = mpathset() ? mpathval() : mailval();
7765 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
7766 p = padvance(&mpath, nullstr);
7771 for (q = p ; *q ; q++);
7776 q[-1] = '\0'; /* delete trailing '/' */
7777 if (stat(p, &statb) < 0) {
7781 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
7784 pathopt ? pathopt : "you have mail"
7787 *mtp = statb.st_mtime;
7789 mail_var_path_changed = 0;
7790 popstackmark(&smark);
7795 changemail(const char *val)
7797 mail_var_path_changed++;
7800 #endif /* CONFIG_ASH_MAIL */
7802 /* $NetBSD: main.c,v 1.46 2002/12/11 19:12:18 christos Exp $ */
7806 static short profile_buf[16384];
7810 static int isloginsh;
7812 static void read_profile(const char *);
7815 * Main routine. We initialize things, parse the arguments, execute
7816 * profiles if we're a login shell, and then call cmdloop to execute
7817 * commands. The setjmp call sets up the location to jump to when an
7818 * exception occurs. When an exception occurs the variable "state"
7819 * is used to figure out how far we had gotten.
7823 ash_main(int argc, char **argv)
7827 struct jmploc jmploc;
7828 struct stackmark smark;
7831 dash_errno = __errno_location();
7835 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7838 if (setjmp(jmploc.loc)) {
7845 switch (exception) {
7855 status = exitstatus;
7858 exitstatus = status;
7860 if (e == EXEXIT || state == 0 || iflag == 0 || ! rootshell)
7864 outcslow('\n', stderr);
7866 popstackmark(&smark);
7867 FORCEINTON; /* enable interrupts */
7870 else if (state == 2)
7872 else if (state == 3)
7880 trputs("Shell args: "); trargs(argv);
7885 setstackmark(&smark);
7886 procargs(argc, argv);
7887 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7889 const char *hp = lookupvar("HISTFILE");
7892 hp = lookupvar("HOME");
7894 char *defhp = concat_path_file(hp, ".ash_history");
7895 setvar("HISTFILE", defhp, 0);
7901 if (argv[0] && argv[0][0] == '-')
7905 read_profile("/etc/profile");
7908 read_profile(".profile");
7914 getuid() == geteuid() && getgid() == getegid() &&
7918 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
7919 read_profile(shinit);
7927 if (sflag || minusc == NULL) {
7928 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7930 const char *hp = lookupvar("HISTFILE");
7933 load_history ( hp );
7936 state4: /* XXX ??? - why isn't this before the "if" statement */
7944 extern void _mcleanup(void);
7954 * Read and execute commands. "Top" is nonzero for the top level command
7955 * loop; it turns on prompting if the shell is interactive.
7962 struct stackmark smark;
7966 TRACE(("cmdloop(%d) called\n", top));
7968 setstackmark(&smark);
7973 showjobs(stderr, SHOW_CHANGED);
7978 #ifdef CONFIG_ASH_MAIL
7982 n = parsecmd(inter);
7983 /* showtree(n); DEBUG */
7985 if (!top || numeof >= 50)
7987 if (!stoppedjobs()) {
7990 out2str("\nUse \"exit\" to leave shell.\n");
7993 } else if (n != NULL && nflag == 0) {
7994 job_warning = (job_warning == 2) ? 1 : 0;
7998 popstackmark(&smark);
8008 * Read /etc/profile or .profile. Return on error.
8012 read_profile(const char *name)
8019 if ((fd = open(name, O_RDONLY)) >= 0)
8024 /* -q turns off -x and -v just when executing init files */
8027 xflag = 0, xflag_set = 1;
8029 vflag = 0, vflag_set = 1;
8043 * Read a file containing shell functions.
8047 readcmdfile(char *name)
8052 if ((fd = open(name, O_RDONLY)) >= 0)
8055 error("Can't open %s", name);
8063 * Take commands from a file. To be compatible we should do a path
8064 * search for the file, which is necessary to find sub-commands.
8067 static inline char *
8068 find_dot_file(char *name)
8071 const char *path = pathval();
8074 /* don't try this for absolute or relative paths */
8075 if (strchr(name, '/'))
8078 while ((fullname = padvance(&path, name)) != NULL) {
8079 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
8081 * Don't bother freeing here, since it will
8082 * be freed by the caller.
8086 stunalloc(fullname);
8089 /* not found in the PATH */
8090 error(not_found_msg, name);
8095 dotcmd(int argc, char **argv)
8099 if (argc >= 2) { /* That's what SVR2 does */
8101 struct stackmark smark;
8103 setstackmark(&smark);
8104 fullname = find_dot_file(argv[1]);
8105 setinputfile(fullname, 1);
8106 commandname = fullname;
8109 popstackmark(&smark);
8116 exitcmd(int argc, char **argv)
8121 exitstatus = number(argv[1]);
8126 /* $NetBSD: memalloc.c,v 1.27 2003/01/22 20:36:04 dsl Exp $ */
8129 * Same for malloc, realloc, but returns an error when out of space.
8133 ckrealloc(pointer p, size_t nbytes)
8135 p = realloc(p, nbytes);
8137 error(bb_msg_memory_exhausted);
8142 ckmalloc(size_t nbytes)
8144 return ckrealloc(NULL, nbytes);
8148 * Make a copy of a string in safe storage.
8152 savestr(const char *s)
8154 char *p = strdup(s);
8156 error(bb_msg_memory_exhausted);
8162 * Parse trees for commands are allocated in lifo order, so we use a stack
8163 * to make this more efficient, and also to avoid all sorts of exception
8164 * handling code to handle interrupts in the middle of a parse.
8166 * The size 504 was chosen because the Ultrix malloc handles that size
8172 stalloc(size_t nbytes)
8177 aligned = SHELL_ALIGN(nbytes);
8178 if (aligned > stacknleft) {
8181 struct stack_block *sp;
8183 blocksize = aligned;
8184 if (blocksize < MINSIZE)
8185 blocksize = MINSIZE;
8186 len = sizeof(struct stack_block) - MINSIZE + blocksize;
8187 if (len < blocksize)
8188 error(bb_msg_memory_exhausted);
8192 stacknxt = sp->space;
8193 stacknleft = blocksize;
8194 sstrend = stacknxt + blocksize;
8199 stacknxt += aligned;
8200 stacknleft -= aligned;
8206 stunalloc(pointer p)
8209 if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
8210 write(2, "stunalloc\n", 10);
8214 stacknleft += stacknxt - (char *)p;
8220 setstackmark(struct stackmark *mark)
8222 mark->stackp = stackp;
8223 mark->stacknxt = stacknxt;
8224 mark->stacknleft = stacknleft;
8225 mark->marknext = markp;
8231 popstackmark(struct stackmark *mark)
8233 struct stack_block *sp;
8236 markp = mark->marknext;
8237 while (stackp != mark->stackp) {
8242 stacknxt = mark->stacknxt;
8243 stacknleft = mark->stacknleft;
8244 sstrend = mark->stacknxt + mark->stacknleft;
8250 * When the parser reads in a string, it wants to stick the string on the
8251 * stack and only adjust the stack pointer when it knows how big the
8252 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8253 * of space on top of the stack and stackblocklen returns the length of
8254 * this block. Growstackblock will grow this space by at least one byte,
8255 * possibly moving it (like realloc). Grabstackblock actually allocates the
8256 * part of the block that has been used.
8260 growstackblock(void)
8264 newlen = stacknleft * 2;
8265 if (newlen < stacknleft)
8266 error(bb_msg_memory_exhausted);
8270 if (stacknxt == stackp->space && stackp != &stackbase) {
8271 struct stack_block *oldstackp;
8272 struct stackmark *xmark;
8273 struct stack_block *sp;
8274 struct stack_block *prevstackp;
8280 prevstackp = sp->prev;
8281 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
8282 sp = ckrealloc((pointer)sp, grosslen);
8283 sp->prev = prevstackp;
8285 stacknxt = sp->space;
8286 stacknleft = newlen;
8287 sstrend = sp->space + newlen;
8290 * Stack marks pointing to the start of the old block
8291 * must be relocated to point to the new block
8294 while (xmark != NULL && xmark->stackp == oldstackp) {
8295 xmark->stackp = stackp;
8296 xmark->stacknxt = stacknxt;
8297 xmark->stacknleft = stacknleft;
8298 xmark = xmark->marknext;
8302 char *oldspace = stacknxt;
8303 int oldlen = stacknleft;
8304 char *p = stalloc(newlen);
8306 /* free the space we just allocated */
8307 stacknxt = memcpy(p, oldspace, oldlen);
8308 stacknleft += newlen;
8313 grabstackblock(size_t len)
8315 len = SHELL_ALIGN(len);
8321 * The following routines are somewhat easier to use than the above.
8322 * The user declares a variable of type STACKSTR, which may be declared
8323 * to be a register. The macro STARTSTACKSTR initializes things. Then
8324 * the user uses the macro STPUTC to add characters to the string. In
8325 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8326 * grown as necessary. When the user is done, she can just leave the
8327 * string there and refer to it using stackblock(). Or she can allocate
8328 * the space for it using grabstackstr(). If it is necessary to allow
8329 * someone else to use the stack temporarily and then continue to grow
8330 * the string, the user should use grabstack to allocate the space, and
8331 * then call ungrabstr(p) to return to the previous mode of operation.
8333 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8334 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8335 * is space for at least one character.
8341 size_t len = stackblocksize();
8342 if (herefd >= 0 && len >= 1024) {
8343 xwrite(herefd, stackblock(), len);
8344 return stackblock();
8347 return stackblock() + len;
8351 * Called from CHECKSTRSPACE.
8355 makestrspace(size_t newlen, char *p)
8357 size_t len = p - stacknxt;
8358 size_t size = stackblocksize();
8363 size = stackblocksize();
8365 if (nleft >= newlen)
8369 return stackblock() + len;
8373 stnputs(const char *s, size_t n, char *p)
8375 p = makestrspace(n, p);
8376 p = mempcpy(p, s, n);
8381 stputs(const char *s, char *p)
8383 return stnputs(s, strlen(s), p);
8386 /* $NetBSD: mystring.c,v 1.15 2002/11/24 22:35:42 christos Exp $ */
8391 * number(s) Convert a string of digits to an integer.
8392 * is_number(s) Return true if s is a string of digits.
8396 * prefix -- see if pfx is a prefix of string.
8400 prefix(const char *string, const char *pfx)
8403 if (*pfx++ != *string++)
8406 return (char *) string;
8411 * Convert a string of digits to an integer, printing an error message on
8416 number(const char *s)
8426 * Check for a valid number. This should be elsewhere.
8430 is_number(const char *p)
8435 } while (*++p != '\0');
8441 * Produce a possibly single quoted string suitable as input to the shell.
8442 * The return string is allocated on the stack.
8446 single_quote(const char *s) {
8455 len = strchrnul(s, '\'') - s;
8457 q = p = makestrspace(len + 3, p);
8460 q = mempcpy(q, s, len);
8466 len = strspn(s, "'");
8470 q = p = makestrspace(len + 3, p);
8473 q = mempcpy(q, s, len);
8482 return stackblock();
8486 * Like strdup but works with the ash stack.
8490 sstrdup(const char *p)
8492 size_t len = strlen(p) + 1;
8493 return memcpy(stalloc(len), p, len);
8498 calcsize(union node *n)
8502 funcblocksize += nodesize[n->type];
8505 calcsize(n->ncmd.redirect);
8506 calcsize(n->ncmd.args);
8507 calcsize(n->ncmd.assign);
8510 sizenodelist(n->npipe.cmdlist);
8515 calcsize(n->nredir.redirect);
8516 calcsize(n->nredir.n);
8523 calcsize(n->nbinary.ch2);
8524 calcsize(n->nbinary.ch1);
8527 calcsize(n->nif.elsepart);
8528 calcsize(n->nif.ifpart);
8529 calcsize(n->nif.test);
8532 funcstringsize += strlen(n->nfor.var) + 1;
8533 calcsize(n->nfor.body);
8534 calcsize(n->nfor.args);
8537 calcsize(n->ncase.cases);
8538 calcsize(n->ncase.expr);
8541 calcsize(n->nclist.body);
8542 calcsize(n->nclist.pattern);
8543 calcsize(n->nclist.next);
8547 sizenodelist(n->narg.backquote);
8548 funcstringsize += strlen(n->narg.text) + 1;
8549 calcsize(n->narg.next);
8556 calcsize(n->nfile.fname);
8557 calcsize(n->nfile.next);
8561 calcsize(n->ndup.vname);
8562 calcsize(n->ndup.next);
8566 calcsize(n->nhere.doc);
8567 calcsize(n->nhere.next);
8570 calcsize(n->nnot.com);
8577 sizenodelist(struct nodelist *lp)
8580 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8588 copynode(union node *n)
8595 funcblock = (char *) funcblock + nodesize[n->type];
8598 new->ncmd.redirect = copynode(n->ncmd.redirect);
8599 new->ncmd.args = copynode(n->ncmd.args);
8600 new->ncmd.assign = copynode(n->ncmd.assign);
8603 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8604 new->npipe.backgnd = n->npipe.backgnd;
8609 new->nredir.redirect = copynode(n->nredir.redirect);
8610 new->nredir.n = copynode(n->nredir.n);
8617 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8618 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8621 new->nif.elsepart = copynode(n->nif.elsepart);
8622 new->nif.ifpart = copynode(n->nif.ifpart);
8623 new->nif.test = copynode(n->nif.test);
8626 new->nfor.var = nodesavestr(n->nfor.var);
8627 new->nfor.body = copynode(n->nfor.body);
8628 new->nfor.args = copynode(n->nfor.args);
8631 new->ncase.cases = copynode(n->ncase.cases);
8632 new->ncase.expr = copynode(n->ncase.expr);
8635 new->nclist.body = copynode(n->nclist.body);
8636 new->nclist.pattern = copynode(n->nclist.pattern);
8637 new->nclist.next = copynode(n->nclist.next);
8641 new->narg.backquote = copynodelist(n->narg.backquote);
8642 new->narg.text = nodesavestr(n->narg.text);
8643 new->narg.next = copynode(n->narg.next);
8650 new->nfile.fname = copynode(n->nfile.fname);
8651 new->nfile.fd = n->nfile.fd;
8652 new->nfile.next = copynode(n->nfile.next);
8656 new->ndup.vname = copynode(n->ndup.vname);
8657 new->ndup.dupfd = n->ndup.dupfd;
8658 new->ndup.fd = n->ndup.fd;
8659 new->ndup.next = copynode(n->ndup.next);
8663 new->nhere.doc = copynode(n->nhere.doc);
8664 new->nhere.fd = n->nhere.fd;
8665 new->nhere.next = copynode(n->nhere.next);
8668 new->nnot.com = copynode(n->nnot.com);
8671 new->type = n->type;
8676 static struct nodelist *
8677 copynodelist(struct nodelist *lp)
8679 struct nodelist *start;
8680 struct nodelist **lpp;
8685 funcblock = (char *) funcblock +
8686 SHELL_ALIGN(sizeof(struct nodelist));
8687 (*lpp)->n = copynode(lp->n);
8689 lpp = &(*lpp)->next;
8697 nodesavestr(char *s)
8699 char *rtn = funcstring;
8701 funcstring = stpcpy(funcstring, s) + 1;
8707 * Free a parse tree.
8711 freefunc(struct funcnode *f)
8713 if (f && --f->count < 0)
8718 static void options(int);
8719 static void setoption(int, int);
8723 * Process the shell command line arguments.
8727 procargs(int argc, char **argv)
8730 const char *xminusc;
8737 for (i = 0; i < NOPTS; i++)
8743 if (*xargv == NULL) {
8745 error("-c requires an argument");
8748 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8752 for (i = 0; i < NOPTS; i++)
8753 if (optlist[i] == 2)
8758 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8763 } else if (!sflag) {
8764 setinputfile(*xargv, 0);
8770 shellparam.p = xargv;
8771 #ifdef CONFIG_ASH_GETOPTS
8772 shellparam.optind = 1;
8773 shellparam.optoff = -1;
8775 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
8777 shellparam.nparam++;
8790 setinteractive(iflag);
8795 minus_o(char *name, int val)
8800 out1str("Current option settings\n");
8801 for (i = 0; i < NOPTS; i++)
8802 out1fmt("%-16s%s\n", optnames(i),
8803 optlist[i] ? "on" : "off");
8805 for (i = 0; i < NOPTS; i++)
8806 if (equal(name, optnames(i))) {
8810 error("Illegal option -o %s", name);
8815 * Process shell options. The global variable argptr contains a pointer
8816 * to the argument list; we advance it past the options.
8820 options(int cmdline)
8828 while ((p = *argptr) != NULL) {
8830 if ((c = *p++) == '-') {
8832 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8834 /* "-" means turn off -x and -v */
8837 /* "--" means reset params */
8838 else if (*argptr == NULL)
8841 break; /* "-" or "--" terminates options */
8843 } else if (c == '+') {
8849 while ((c = *p++) != '\0') {
8850 if (c == 'c' && cmdline) {
8851 minusc = p; /* command is after shell args*/
8852 } else if (c == 'o') {
8853 minus_o(*argptr, val);
8856 } else if (cmdline && (c == '-')) { // long options
8857 if (strcmp(p, "login") == 0)
8869 setoption(int flag, int val)
8873 for (i = 0; i < NOPTS; i++)
8874 if (optletters(i) == flag) {
8878 error("Illegal option -%c", flag);
8885 * Set the shell parameters.
8889 setparam(char **argv)
8895 for (nparam = 0 ; argv[nparam] ; nparam++);
8896 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
8898 *ap++ = savestr(*argv++);
8901 freeparam(&shellparam);
8902 shellparam.malloc = 1;
8903 shellparam.nparam = nparam;
8904 shellparam.p = newparam;
8905 #ifdef CONFIG_ASH_GETOPTS
8906 shellparam.optind = 1;
8907 shellparam.optoff = -1;
8913 * Free the list of positional parameters.
8917 freeparam(volatile struct shparam *param)
8921 if (param->malloc) {
8922 for (ap = param->p ; *ap ; ap++)
8931 * The shift builtin command.
8935 shiftcmd(int argc, char **argv)
8942 n = number(argv[1]);
8943 if (n > shellparam.nparam)
8944 error("can't shift that many");
8946 shellparam.nparam -= n;
8947 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
8948 if (shellparam.malloc)
8952 while ((*ap2++ = *ap1++) != NULL);
8953 #ifdef CONFIG_ASH_GETOPTS
8954 shellparam.optind = 1;
8955 shellparam.optoff = -1;
8964 * The set command builtin.
8968 setcmd(int argc, char **argv)
8971 return showvars(nullstr, 0, VUNSET);
8975 if (*argptr != NULL) {
8983 #ifdef CONFIG_ASH_GETOPTS
8988 shellparam.optind = number(value);
8989 shellparam.optoff = -1;
8993 #ifdef CONFIG_LOCALE_SUPPORT
8994 static void change_lc_all(const char *value)
8996 if (value != 0 && *value != 0)
8997 setlocale(LC_ALL, value);
9000 static void change_lc_ctype(const char *value)
9002 if (value != 0 && *value != 0)
9003 setlocale(LC_CTYPE, value);
9008 #ifdef CONFIG_ASH_GETOPTS
9010 getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
9019 if(*param_optind < 1)
9021 optnext = optfirst + *param_optind - 1;
9023 if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff)
9026 p = optnext[-1] + *optoff;
9027 if (p == NULL || *p == '\0') {
9028 /* Current word is done, advance */
9030 if (p == NULL || *p != '-' || *++p == '\0') {
9037 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
9042 for (q = optstr; *q != c; ) {
9044 if (optstr[0] == ':') {
9047 err |= setvarsafe("OPTARG", s, 0);
9049 fprintf(stderr, "Illegal option -%c\n", c);
9050 (void) unsetvar("OPTARG");
9060 if (*p == '\0' && (p = *optnext) == NULL) {
9061 if (optstr[0] == ':') {
9064 err |= setvarsafe("OPTARG", s, 0);
9067 fprintf(stderr, "No arg for -%c option\n", c);
9068 (void) unsetvar("OPTARG");
9076 err |= setvarsafe("OPTARG", p, 0);
9079 err |= setvarsafe("OPTARG", nullstr, 0);
9082 *optoff = p ? p - *(optnext - 1) : -1;
9083 *param_optind = optnext - optfirst + 1;
9084 fmtstr(s, sizeof(s), "%d", *param_optind);
9085 err |= setvarsafe("OPTIND", s, VNOFUNC);
9088 err |= setvarsafe(optvar, s, 0);
9099 * The getopts builtin. Shellparam.optnext points to the next argument
9100 * to be processed. Shellparam.optptr points to the next character to
9101 * be processed in the current argument. If shellparam.optnext is NULL,
9102 * then it's the first time getopts has been called.
9106 getoptscmd(int argc, char **argv)
9111 error("Usage: getopts optstring var [arg]");
9112 else if (argc == 3) {
9113 optbase = shellparam.p;
9114 if (shellparam.optind > shellparam.nparam + 1) {
9115 shellparam.optind = 1;
9116 shellparam.optoff = -1;
9121 if (shellparam.optind > argc - 2) {
9122 shellparam.optind = 1;
9123 shellparam.optoff = -1;
9127 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9128 &shellparam.optoff);
9130 #endif /* CONFIG_ASH_GETOPTS */
9133 * XXX - should get rid of. have all builtins use getopt(3). the
9134 * library getopt must have the BSD extension static variable "optreset"
9135 * otherwise it can't be used within the shell safely.
9137 * Standard option processing (a la getopt) for builtin routines. The
9138 * only argument that is passed to nextopt is the option string; the
9139 * other arguments are unnecessary. It return the character, or '\0' on
9144 nextopt(const char *optstring)
9150 if ((p = optptr) == NULL || *p == '\0') {
9152 if (p == NULL || *p != '-' || *++p == '\0')
9155 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
9159 for (q = optstring ; *q != c ; ) {
9161 error("Illegal option -%c", c);
9166 if (*p == '\0' && (p = *argptr++) == NULL)
9167 error("No arg for -%c option", c);
9176 /* $NetBSD: output.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
9179 outstr(const char *p, FILE *file)
9196 flushout(FILE *dest)
9204 outcslow(int c, FILE *dest)
9214 out1fmt(const char *fmt, ...)
9221 r = vprintf(fmt, ap);
9229 fmtstr(char *outbuf, size_t length, const char *fmt, ...)
9236 ret = vsnprintf(outbuf, length, fmt, ap);
9244 * Version of write which resumes after a signal is caught.
9248 xwrite(int fd, const void *p, size_t n)
9253 i = bb_full_write(fd, p, n);
9254 } while (i < 0 && errno == EINTR);
9258 /* $NetBSD: parser.c,v 1.54 2002/11/24 22:35:42 christos Exp $ */
9262 * Shell command parser.
9265 #define EOFMARKLEN 79
9269 struct heredoc *next; /* next here document in list */
9270 union node *here; /* redirection node */
9271 char *eofmark; /* string indicating end of input */
9272 int striptabs; /* if set, strip leading tabs */
9277 static struct heredoc *heredoclist; /* list of here documents to read */
9280 static union node *list(int);
9281 static union node *andor(void);
9282 static union node *pipeline(void);
9283 static union node *command(void);
9284 static union node *simplecmd(void);
9285 static union node *makename(void);
9286 static void parsefname(void);
9287 static void parseheredoc(void);
9288 static char peektoken(void);
9289 static int readtoken(void);
9290 static int xxreadtoken(void);
9291 static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
9292 static int noexpand(char *);
9293 static void synexpect(int) __attribute__((__noreturn__));
9294 static void synerror(const char *) __attribute__((__noreturn__));
9295 static void setprompt(int);
9299 goodname(const char *p)
9301 return !*endofname(p);
9305 isassignment(const char *p)
9307 const char *q = endofname(p);
9315 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9316 * valid parse tree indicating a blank line.)
9320 parsecmd(int interact)
9325 doprompt = interact;
9327 setprompt(doprompt);
9342 union node *n1, *n2, *n3;
9345 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9346 if (nlflag == 2 && peektoken())
9352 if (tok == TBACKGND) {
9353 if (n2->type == NPIPE) {
9354 n2->npipe.backgnd = 1;
9356 if (n2->type != NREDIR) {
9357 n3 = stalloc(sizeof(struct nredir));
9359 n3->nredir.redirect = NULL;
9362 n2->type = NBACKGND;
9369 n3 = (union node *)stalloc(sizeof (struct nbinary));
9371 n3->nbinary.ch1 = n1;
9372 n3->nbinary.ch2 = n2;
9388 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9396 pungetc(); /* push back EOF on input */
9412 union node *n1, *n2, *n3;
9417 if ((t = readtoken()) == TAND) {
9419 } else if (t == TOR) {
9425 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9427 n3 = (union node *)stalloc(sizeof (struct nbinary));
9429 n3->nbinary.ch1 = n1;
9430 n3->nbinary.ch2 = n2;
9440 union node *n1, *n2, *pipenode;
9441 struct nodelist *lp, *prev;
9445 TRACE(("pipeline: entered\n"));
9446 if (readtoken() == TNOT) {
9448 checkkwd = CHKKWD | CHKALIAS;
9452 if (readtoken() == TPIPE) {
9453 pipenode = (union node *)stalloc(sizeof (struct npipe));
9454 pipenode->type = NPIPE;
9455 pipenode->npipe.backgnd = 0;
9456 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9457 pipenode->npipe.cmdlist = lp;
9461 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9462 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9465 } while (readtoken() == TPIPE);
9471 n2 = (union node *)stalloc(sizeof (struct nnot));
9484 union node *n1, *n2;
9485 union node *ap, **app;
9486 union node *cp, **cpp;
9487 union node *redir, **rpp;
9494 switch (readtoken()) {
9499 n1 = (union node *)stalloc(sizeof (struct nif));
9501 n1->nif.test = list(0);
9502 if (readtoken() != TTHEN)
9504 n1->nif.ifpart = list(0);
9506 while (readtoken() == TELIF) {
9507 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
9508 n2 = n2->nif.elsepart;
9510 n2->nif.test = list(0);
9511 if (readtoken() != TTHEN)
9513 n2->nif.ifpart = list(0);
9515 if (lasttoken == TELSE)
9516 n2->nif.elsepart = list(0);
9518 n2->nif.elsepart = NULL;
9526 n1 = (union node *)stalloc(sizeof (struct nbinary));
9527 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
9528 n1->nbinary.ch1 = list(0);
9529 if ((got=readtoken()) != TDO) {
9530 TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
9533 n1->nbinary.ch2 = list(0);
9538 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9539 synerror("Bad for loop variable");
9540 n1 = (union node *)stalloc(sizeof (struct nfor));
9542 n1->nfor.var = wordtext;
9543 checkkwd = CHKKWD | CHKALIAS;
9544 if (readtoken() == TIN) {
9546 while (readtoken() == TWORD) {
9547 n2 = (union node *)stalloc(sizeof (struct narg));
9549 n2->narg.text = wordtext;
9550 n2->narg.backquote = backquotelist;
9552 app = &n2->narg.next;
9556 if (lasttoken != TNL && lasttoken != TSEMI)
9559 n2 = (union node *)stalloc(sizeof (struct narg));
9561 n2->narg.text = (char *)dolatstr;
9562 n2->narg.backquote = NULL;
9563 n2->narg.next = NULL;
9566 * Newline or semicolon here is optional (but note
9567 * that the original Bourne shell only allowed NL).
9569 if (lasttoken != TNL && lasttoken != TSEMI)
9572 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9573 if (readtoken() != TDO)
9575 n1->nfor.body = list(0);
9579 n1 = (union node *)stalloc(sizeof (struct ncase));
9581 if (readtoken() != TWORD)
9583 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
9585 n2->narg.text = wordtext;
9586 n2->narg.backquote = backquotelist;
9587 n2->narg.next = NULL;
9589 checkkwd = CHKKWD | CHKALIAS;
9590 } while (readtoken() == TNL);
9591 if (lasttoken != TIN)
9593 cpp = &n1->ncase.cases;
9595 checkkwd = CHKNL | CHKKWD;
9598 if (lasttoken == TLP)
9600 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
9602 app = &cp->nclist.pattern;
9604 *app = ap = (union node *)stalloc(sizeof (struct narg));
9606 ap->narg.text = wordtext;
9607 ap->narg.backquote = backquotelist;
9608 if (readtoken() != TPIPE)
9610 app = &ap->narg.next;
9613 ap->narg.next = NULL;
9614 if (lasttoken != TRP)
9616 cp->nclist.body = list(2);
9618 cpp = &cp->nclist.next;
9620 checkkwd = CHKNL | CHKKWD;
9621 if ((t = readtoken()) != TESAC) {
9623 synexpect(TENDCASE);
9631 n1 = (union node *)stalloc(sizeof (struct nredir));
9632 n1->type = NSUBSHELL;
9633 n1->nredir.n = list(0);
9634 n1->nredir.redirect = NULL;
9647 if (readtoken() != t)
9651 /* Now check for redirection which may follow command */
9652 checkkwd = CHKKWD | CHKALIAS;
9654 while (readtoken() == TREDIR) {
9655 *rpp = n2 = redirnode;
9656 rpp = &n2->nfile.next;
9662 if (n1->type != NSUBSHELL) {
9663 n2 = (union node *)stalloc(sizeof (struct nredir));
9668 n1->nredir.redirect = redir;
9677 union node *args, **app;
9678 union node *n = NULL;
9679 union node *vars, **vpp;
9680 union node **rpp, *redir;
9690 savecheckkwd = CHKALIAS;
9692 checkkwd = savecheckkwd;
9693 switch (readtoken()) {
9695 n = (union node *)stalloc(sizeof (struct narg));
9697 n->narg.text = wordtext;
9698 n->narg.backquote = backquotelist;
9699 if (savecheckkwd && isassignment(wordtext)) {
9701 vpp = &n->narg.next;
9704 app = &n->narg.next;
9709 *rpp = n = redirnode;
9710 rpp = &n->nfile.next;
9711 parsefname(); /* read name of redirection file */
9715 args && app == &args->narg.next &&
9718 struct builtincmd *bcmd;
9721 /* We have a function */
9722 if (readtoken() != TRP)
9724 name = n->narg.text;
9726 !goodname(name) || (
9727 (bcmd = find_builtin(name)) &&
9728 IS_BUILTIN_SPECIAL(bcmd)
9731 synerror("Bad function name");
9733 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9734 n->narg.next = command();
9747 n = (union node *)stalloc(sizeof (struct ncmd));
9749 n->ncmd.args = args;
9750 n->ncmd.assign = vars;
9751 n->ncmd.redirect = redir;
9760 n = (union node *)stalloc(sizeof (struct narg));
9762 n->narg.next = NULL;
9763 n->narg.text = wordtext;
9764 n->narg.backquote = backquotelist;
9768 void fixredir(union node *n, const char *text, int err)
9770 TRACE(("Fix redir %s %d\n", text, err));
9772 n->ndup.vname = NULL;
9774 if (is_digit(text[0]) && text[1] == '\0')
9775 n->ndup.dupfd = digit_val(text[0]);
9776 else if (text[0] == '-' && text[1] == '\0')
9781 synerror("Bad fd number");
9783 n->ndup.vname = makename();
9791 union node *n = redirnode;
9793 if (readtoken() != TWORD)
9795 if (n->type == NHERE) {
9796 struct heredoc *here = heredoc;
9802 TRACE(("Here document %d\n", n->type));
9803 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
9804 synerror("Illegal eof marker for << redirection");
9805 rmescapes(wordtext);
9806 here->eofmark = wordtext;
9808 if (heredoclist == NULL)
9811 for (p = heredoclist ; p->next ; p = p->next);
9814 } else if (n->type == NTOFD || n->type == NFROMFD) {
9815 fixredir(n, wordtext, 0);
9817 n->nfile.fname = makename();
9823 * Input any here documents.
9829 struct heredoc *here;
9840 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9841 here->eofmark, here->striptabs);
9842 n = (union node *)stalloc(sizeof (struct narg));
9843 n->narg.type = NARG;
9844 n->narg.next = NULL;
9845 n->narg.text = wordtext;
9846 n->narg.backquote = backquotelist;
9847 here->here->nhere.doc = n;
9852 static char peektoken(void)
9858 return tokname_array[t][0];
9866 int alreadyseen = tokpushback;
9869 #ifdef CONFIG_ASH_ALIAS
9878 if (checkkwd & CHKNL) {
9885 if (t != TWORD || quoteflag) {
9890 * check for keywords
9892 if (checkkwd & CHKKWD) {
9893 const char *const *pp;
9895 if ((pp = findkwd(wordtext))) {
9896 lasttoken = t = pp - tokname_array;
9897 TRACE(("keyword %s recognized\n", tokname(t)));
9902 if (checkkwd & CHKALIAS) {
9903 #ifdef CONFIG_ASH_ALIAS
9905 if ((ap = lookupalias(wordtext, 1)) != NULL) {
9907 pushstring(ap->val, ap);
9917 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
9919 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
9926 * Read the next input token.
9927 * If the token is a word, we set backquotelist to the list of cmds in
9928 * backquotes. We set quoteflag to true if any part of the word was
9930 * If the token is TREDIR, then we set redirnode to a structure containing
9932 * In all cases, the variable startlinno is set to the number of the line
9933 * on which the token starts.
9935 * [Change comment: here documents and internal procedures]
9936 * [Readtoken shouldn't have any arguments. Perhaps we should make the
9937 * word parsing code into a separate routine. In this case, readtoken
9938 * doesn't need to have any internal procedures, but parseword does.
9939 * We could also make parseoperator in essence the main routine, and
9940 * have parseword (readtoken1?) handle both words and redirection.]
9943 #define NEW_xxreadtoken
9944 #ifdef NEW_xxreadtoken
9946 /* singles must be first! */
9947 static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
9949 static const char xxreadtoken_tokens[] = {
9950 TNL, TLP, TRP, /* only single occurrence allowed */
9951 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
9952 TEOF, /* corresponds to trailing nul */
9953 TAND, TOR, TENDCASE, /* if double occurrence */
9956 #define xxreadtoken_doubles \
9957 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
9958 #define xxreadtoken_singles \
9959 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
9961 static int xxreadtoken()
9973 startlinno = plinno;
9974 for (;;) { /* until token or start of word found */
9977 if ((c != ' ') && (c != '\t')
9978 #ifdef CONFIG_ASH_ALIAS
9983 while ((c = pgetc()) != '\n' && c != PEOF);
9985 } else if (c == '\\') {
9986 if (pgetc() != '\n') {
9990 startlinno = ++plinno;
9995 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10000 needprompt = doprompt;
10003 p = strchr(xxreadtoken_chars, c);
10006 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
10009 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
10010 if (pgetc() == *p) { /* double occurrence? */
10011 p += xxreadtoken_doubles + 1;
10018 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
10026 #define RETURN(token) return lasttoken = token
10041 startlinno = plinno;
10042 for (;;) { /* until token or start of word found */
10045 case ' ': case '\t':
10046 #ifdef CONFIG_ASH_ALIAS
10051 while ((c = pgetc()) != '\n' && c != PEOF);
10055 if (pgetc() == '\n') {
10056 startlinno = ++plinno;
10065 needprompt = doprompt;
10070 if (pgetc() == '&')
10075 if (pgetc() == '|')
10080 if (pgetc() == ';')
10093 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10096 #endif /* NEW_xxreadtoken */
10100 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10101 * is not NULL, read a here document. In the latter case, eofmark is the
10102 * word which marks the end of the document and striptabs is true if
10103 * leading tabs should be stripped from the document. The argument firstc
10104 * is the first character of the input token or document.
10106 * Because C does not have internal subroutines, I have simulated them
10107 * using goto's to implement the subroutine linkage. The following macros
10108 * will run code that appears at the end of readtoken1.
10111 #define CHECKEND() {goto checkend; checkend_return:;}
10112 #define PARSEREDIR() {goto parseredir; parseredir_return:;}
10113 #define PARSESUB() {goto parsesub; parsesub_return:;}
10114 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10115 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10116 #define PARSEARITH() {goto parsearith; parsearith_return:;}
10119 readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
10124 char line[EOFMARKLEN + 1];
10125 struct nodelist *bqlist;
10128 int varnest; /* levels of variables expansion */
10129 int arinest; /* levels of arithmetic expansion */
10130 int parenlevel; /* levels of parens in arithmetic */
10131 int dqvarnest; /* levels of variables expansion within double quotes */
10133 int prevsyntax; /* syntax before arithmetic */
10135 /* Avoid longjmp clobbering */
10141 (void) &parenlevel;
10144 (void) &prevsyntax;
10148 startlinno = plinno;
10150 if (syntax == DQSYNTAX)
10159 STARTSTACKSTR(out);
10160 loop: { /* for each line, until end of word */
10161 CHECKEND(); /* set c to PEOF if at end of here document */
10162 for (;;) { /* until end of line or end of word */
10163 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10164 switch(SIT(c, syntax)) {
10165 case CNL: /* '\n' */
10166 if (syntax == BASESYNTAX)
10167 goto endword; /* exit outer loop */
10173 goto loop; /* continue outer loop */
10178 if (eofmark == NULL || dblquote)
10179 USTPUTC(CTLESC, out);
10182 case CBACK: /* backslash */
10185 USTPUTC(CTLESC, out);
10186 USTPUTC('\\', out);
10188 } else if (c == '\n') {
10194 c != '\\' && c != '`' &&
10200 USTPUTC(CTLESC, out);
10201 USTPUTC('\\', out);
10203 if (SIT(c, SQSYNTAX) == CCTL)
10204 USTPUTC(CTLESC, out);
10212 if (eofmark == NULL) {
10213 USTPUTC(CTLQUOTEMARK, out);
10221 if (eofmark != NULL && arinest == 0 &&
10225 if (dqvarnest == 0) {
10226 syntax = BASESYNTAX;
10233 case CVAR: /* '$' */
10234 PARSESUB(); /* parse substitution */
10236 case CENDVAR: /* '}' */
10239 if (dqvarnest > 0) {
10242 USTPUTC(CTLENDVAR, out);
10247 #ifdef CONFIG_ASH_MATH_SUPPORT
10248 case CLP: /* '(' in arithmetic */
10252 case CRP: /* ')' in arithmetic */
10253 if (parenlevel > 0) {
10257 if (pgetc() == ')') {
10258 if (--arinest == 0) {
10259 USTPUTC(CTLENDARI, out);
10260 syntax = prevsyntax;
10261 if (syntax == DQSYNTAX)
10269 * unbalanced parens
10270 * (don't 2nd guess - no error)
10278 case CBQUOTE: /* '`' */
10282 goto endword; /* exit outer loop */
10287 goto endword; /* exit outer loop */
10288 #ifdef CONFIG_ASH_ALIAS
10298 #ifdef CONFIG_ASH_MATH_SUPPORT
10299 if (syntax == ARISYNTAX)
10300 synerror("Missing '))'");
10302 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10303 synerror("Unterminated quoted string");
10304 if (varnest != 0) {
10305 startlinno = plinno;
10307 synerror("Missing '}'");
10309 USTPUTC('\0', out);
10310 len = out - (char *)stackblock();
10311 out = stackblock();
10312 if (eofmark == NULL) {
10313 if ((c == '>' || c == '<')
10316 && (*out == '\0' || is_digit(*out))) {
10318 return lasttoken = TREDIR;
10323 quoteflag = quotef;
10324 backquotelist = bqlist;
10325 grabstackblock(len);
10327 return lasttoken = TWORD;
10328 /* end of readtoken routine */
10333 * Check to see whether we are at the end of the here document. When this
10334 * is called, c is set to the first character of the next input line. If
10335 * we are at the end of the here document, this routine sets the c to PEOF.
10340 #ifdef CONFIG_ASH_ALIAS
10346 while (c == '\t') {
10350 if (c == *eofmark) {
10351 if (pfgets(line, sizeof line) != NULL) {
10355 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10356 if (*p == '\n' && *q == '\0') {
10359 needprompt = doprompt;
10361 pushstring(line, NULL);
10366 goto checkend_return;
10371 * Parse a redirection operator. The variable "out" points to a string
10372 * specifying the fd to be redirected. The variable "c" contains the
10373 * first character of the redirection operator.
10380 np = (union node *)stalloc(sizeof (struct nfile));
10385 np->type = NAPPEND;
10387 np->type = NCLOBBER;
10394 } else { /* c == '<' */
10396 switch (c = pgetc()) {
10398 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10399 np = (union node *)stalloc(sizeof (struct nhere));
10403 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10404 heredoc->here = np;
10405 if ((c = pgetc()) == '-') {
10406 heredoc->striptabs = 1;
10408 heredoc->striptabs = 0;
10414 np->type = NFROMFD;
10418 np->type = NFROMTO;
10428 np->nfile.fd = digit_val(fd);
10430 goto parseredir_return;
10435 * Parse a substitution. At this point, we have read the dollar sign
10436 * and nothing else.
10444 static const char types[] = "}-+?=";
10448 c <= PEOA_OR_PEOF ||
10449 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10453 } else if (c == '(') { /* $(command) or $((arith)) */
10454 if (pgetc() == '(') {
10455 #ifdef CONFIG_ASH_MATH_SUPPORT
10458 synerror("We unsupport $((arith))");
10465 USTPUTC(CTLVAR, out);
10466 typeloc = out - (char *)stackblock();
10467 USTPUTC(VSNORMAL, out);
10468 subtype = VSNORMAL;
10472 if ((c = pgetc()) == '}')
10475 subtype = VSLENGTH;
10480 if (c > PEOA_OR_PEOF && is_name(c)) {
10484 } while (c > PEOA_OR_PEOF && is_in_name(c));
10485 } else if (is_digit(c)) {
10489 } while (is_digit(c));
10491 else if (is_special(c)) {
10496 badsub: synerror("Bad substitution");
10500 if (subtype == 0) {
10507 p = strchr(types, c);
10510 subtype = p - types + VSNORMAL;
10516 subtype = c == '#' ? VSTRIMLEFT :
10529 if (dblquote || arinest)
10531 *((char *)stackblock() + typeloc) = subtype | flags;
10532 if (subtype != VSNORMAL) {
10534 if (dblquote || arinest) {
10539 goto parsesub_return;
10544 * Called to parse command substitutions. Newstyle is set if the command
10545 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10546 * list of commands (passed by reference), and savelen is the number of
10547 * characters on the top of the stack which must be preserved.
10551 struct nodelist **nlpp;
10554 char *volatile str;
10555 struct jmploc jmploc;
10556 struct jmploc *volatile savehandler;
10560 (void) &saveprompt;
10563 savepbq = parsebackquote;
10564 if (setjmp(jmploc.loc)) {
10567 parsebackquote = 0;
10568 handler = savehandler;
10569 longjmp(handler->loc, 1);
10573 savelen = out - (char *)stackblock();
10575 str = ckmalloc(savelen);
10576 memcpy(str, stackblock(), savelen);
10578 savehandler = handler;
10582 /* We must read until the closing backquote, giving special
10583 treatment to some slashes, and then push the string and
10584 reread it as input, interpreting it normally. */
10591 STARTSTACKSTR(pout);
10597 switch (pc = pgetc()) {
10602 if ((pc = pgetc()) == '\n') {
10607 * If eating a newline, avoid putting
10608 * the newline into the new character
10609 * stream (via the STPUTC after the
10614 if (pc != '\\' && pc != '`' && pc != '$'
10615 && (!dblquote || pc != '"'))
10616 STPUTC('\\', pout);
10617 if (pc > PEOA_OR_PEOF) {
10623 #ifdef CONFIG_ASH_ALIAS
10626 startlinno = plinno;
10627 synerror("EOF in backquote substitution");
10631 needprompt = doprompt;
10640 STPUTC('\0', pout);
10641 psavelen = pout - (char *)stackblock();
10642 if (psavelen > 0) {
10643 pstr = grabstackstr(pout);
10644 setinputstring(pstr);
10649 nlpp = &(*nlpp)->next;
10650 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10651 (*nlpp)->next = NULL;
10652 parsebackquote = oldstyle;
10655 saveprompt = doprompt;
10662 doprompt = saveprompt;
10664 if (readtoken() != TRP)
10671 * Start reading from old file again, ignoring any pushed back
10672 * tokens left from the backquote parsing
10677 while (stackblocksize() <= savelen)
10679 STARTSTACKSTR(out);
10681 memcpy(out, str, savelen);
10682 STADJUST(savelen, out);
10688 parsebackquote = savepbq;
10689 handler = savehandler;
10690 if (arinest || dblquote)
10691 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10693 USTPUTC(CTLBACKQ, out);
10695 goto parsebackq_oldreturn;
10697 goto parsebackq_newreturn;
10700 #ifdef CONFIG_ASH_MATH_SUPPORT
10702 * Parse an arithmetic expansion (indicate start of one and set state)
10706 if (++arinest == 1) {
10707 prevsyntax = syntax;
10708 syntax = ARISYNTAX;
10709 USTPUTC(CTLARI, out);
10716 * we collapse embedded arithmetic expansion to
10717 * parenthesis, which should be equivalent
10721 goto parsearith_return;
10725 } /* end of readtoken */
10730 * Returns true if the text contains nothing to expand (no dollar signs
10735 noexpand(char *text)
10741 while ((c = *p++) != '\0') {
10742 if (c == CTLQUOTEMARK)
10746 else if (SIT(c, BASESYNTAX) == CCTL)
10754 * Return of a legal variable name (a letter or underscore followed by zero or
10755 * more letters, underscores, and digits).
10759 endofname(const char *name)
10767 if (! is_in_name(*p))
10775 * Called when an unexpected token is read during the parse. The argument
10776 * is the token that is expected, or -1 if more than one type of token can
10777 * occur at this point.
10780 static void synexpect(int token)
10785 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10787 sprintf(msg + l, " (expecting %s)", tokname(token));
10793 synerror(const char *msg)
10795 error("Syntax error: %s", msg);
10801 * called by editline -- any expansions to the prompt
10802 * should be added here.
10805 static void setprompt(int whichprompt)
10807 const char *prompt;
10809 switch (whichprompt) {
10823 static const char *const *findkwd(const char *s)
10825 return bsearch(s, tokname_array + KWDOFFSET,
10826 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
10827 sizeof(const char *), pstrcmp);
10830 /* $NetBSD: redir.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
10833 * Code for dealing with input/output redirection.
10836 #define EMPTY -2 /* marks an unused slot in redirtab */
10838 # define PIPESIZE 4096 /* amount of buffering in a pipe */
10840 # define PIPESIZE PIPE_BUF
10844 * Open a file in noclobber mode.
10845 * The code was copied from bash.
10848 noclobberopen(const char *fname)
10851 struct stat finfo, finfo2;
10854 * If the file exists and is a regular file, return an error
10857 r = stat(fname, &finfo);
10858 if (r == 0 && S_ISREG(finfo.st_mode)) {
10864 * If the file was not present (r != 0), make sure we open it
10865 * exclusively so that if it is created before we open it, our open
10866 * will fail. Make sure that we do not truncate an existing file.
10867 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10868 * file was not a regular file, we leave O_EXCL off.
10871 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10872 fd = open(fname, O_WRONLY|O_CREAT, 0666);
10874 /* If the open failed, return the file descriptor right away. */
10879 * OK, the open succeeded, but the file may have been changed from a
10880 * non-regular file to a regular file between the stat and the open.
10881 * We are assuming that the O_EXCL open handles the case where FILENAME
10882 * did not exist and is symlinked to an existing file between the stat
10887 * If we can open it and fstat the file descriptor, and neither check
10888 * revealed that it was a regular file, and the file has not been
10889 * replaced, return the file descriptor.
10891 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10892 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
10895 /* The file has been replaced. badness. */
10902 * Handle here documents. Normally we fork off a process to write the
10903 * data to a pipe. If the document is short, we can stuff the data in
10904 * the pipe without forking.
10908 openhere(union node *redir)
10914 error("Pipe call failed");
10915 if (redir->type == NHERE) {
10916 len = strlen(redir->nhere.doc->narg.text);
10917 if (len <= PIPESIZE) {
10918 xwrite(pip[1], redir->nhere.doc->narg.text, len);
10922 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
10924 signal(SIGINT, SIG_IGN);
10925 signal(SIGQUIT, SIG_IGN);
10926 signal(SIGHUP, SIG_IGN);
10928 signal(SIGTSTP, SIG_IGN);
10930 signal(SIGPIPE, SIG_DFL);
10931 if (redir->type == NHERE)
10932 xwrite(pip[1], redir->nhere.doc->narg.text, len);
10934 expandhere(redir->nhere.doc, pip[1]);
10943 openredirect(union node *redir)
10948 switch (redir->nfile.type) {
10950 fname = redir->nfile.expfname;
10951 if ((f = open(fname, O_RDONLY)) < 0)
10955 fname = redir->nfile.expfname;
10956 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
10960 /* Take care of noclobber mode. */
10962 fname = redir->nfile.expfname;
10963 if ((f = noclobberopen(fname)) < 0)
10969 fname = redir->nfile.expfname;
10970 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
10974 fname = redir->nfile.expfname;
10975 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
10982 /* Fall through to eliminate warning. */
10989 f = openhere(redir);
10995 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
10997 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11001 dupredirect(union node *redir, int f)
11003 int fd = redir->nfile.fd;
11005 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11006 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
11007 copyfd(redir->ndup.dupfd, fd);
11020 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11021 * old file descriptors are stashed away so that the redirection can be
11022 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11023 * standard output, and the standard error if it becomes a duplicate of
11024 * stdout, is saved in memory.
11028 redirect(union node *redir, int flags)
11031 struct redirtab *sv;
11042 if (flags & REDIR_PUSH) {
11043 struct redirtab *q;
11044 q = ckmalloc(sizeof (struct redirtab));
11045 q->next = redirlist;
11047 q->nullredirs = nullredirs - 1;
11048 for (i = 0 ; i < 10 ; i++)
11049 q->renamed[i] = EMPTY;
11056 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
11057 n->ndup.dupfd == fd)
11058 continue; /* redirect from/to same file descriptor */
11060 newfd = openredirect(n);
11063 if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
11064 i = fcntl(fd, F_DUPFD, 10);
11071 error("%d: %m", fd);
11081 dupredirect(n, newfd);
11082 } while ((n = n->nfile.next));
11084 if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
11085 preverrout_fd = sv->renamed[2];
11090 * Undo the effects of the last redirection.
11096 struct redirtab *rp;
11099 if (--nullredirs >= 0)
11103 for (i = 0 ; i < 10 ; i++) {
11104 if (rp->renamed[i] != EMPTY) {
11107 copyfd(rp->renamed[i], i);
11109 close(rp->renamed[i]);
11112 redirlist = rp->next;
11113 nullredirs = rp->nullredirs;
11119 * Undo all redirections. Called on error or interrupt.
11123 * Discard all saved file descriptors.
11127 clearredir(int drop)
11139 * Copy a file descriptor to be >= to. Returns -1
11140 * if the source file descriptor is closed, EMPTY if there are no unused
11141 * file descriptors left.
11145 copyfd(int from, int to)
11149 newfd = fcntl(from, F_DUPFD, to);
11151 if (errno == EMFILE)
11154 error("%d: %m", from);
11161 redirectsafe(union node *redir, int flags)
11164 volatile int saveint;
11165 struct jmploc *volatile savehandler = handler;
11166 struct jmploc jmploc;
11169 if (!(err = setjmp(jmploc.loc) * 2)) {
11171 redirect(redir, flags);
11173 handler = savehandler;
11174 if (err && exception != EXERROR)
11175 longjmp(handler->loc, 1);
11176 RESTOREINT(saveint);
11180 /* $NetBSD: show.c,v 1.24 2003/01/22 20:36:04 dsl Exp $ */
11183 static void shtree(union node *, int, char *, FILE*);
11184 static void shcmd(union node *, FILE *);
11185 static void sharg(union node *, FILE *);
11186 static void indent(int, char *, FILE *);
11187 static void trstring(char *);
11191 showtree(union node *n)
11193 trputs("showtree called\n");
11194 shtree(n, 1, NULL, stdout);
11199 shtree(union node *n, int ind, char *pfx, FILE *fp)
11201 struct nodelist *lp;
11207 indent(ind, pfx, fp);
11218 shtree(n->nbinary.ch1, ind, NULL, fp);
11221 shtree(n->nbinary.ch2, ind, NULL, fp);
11229 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
11234 if (n->npipe.backgnd)
11240 fprintf(fp, "<node type %d>", n->type);
11249 shcmd(union node *cmd, FILE *fp)
11257 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11263 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11266 switch (np->nfile.type) {
11267 case NTO: s = ">"; dftfd = 1; break;
11268 case NCLOBBER: s = ">|"; dftfd = 1; break;
11269 case NAPPEND: s = ">>"; dftfd = 1; break;
11270 case NTOFD: s = ">&"; dftfd = 1; break;
11271 case NFROM: s = "<"; dftfd = 0; break;
11272 case NFROMFD: s = "<&"; dftfd = 0; break;
11273 case NFROMTO: s = "<>"; dftfd = 0; break;
11274 default: s = "*error*"; dftfd = 0; break;
11276 if (np->nfile.fd != dftfd)
11277 fprintf(fp, "%d", np->nfile.fd);
11279 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11280 fprintf(fp, "%d", np->ndup.dupfd);
11282 sharg(np->nfile.fname, fp);
11291 sharg(union node *arg, FILE *fp)
11294 struct nodelist *bqlist;
11297 if (arg->type != NARG) {
11298 out1fmt("<node type %d>\n", arg->type);
11301 bqlist = arg->narg.backquote;
11302 for (p = arg->narg.text ; *p ; p++) {
11311 if (subtype == VSLENGTH)
11317 if (subtype & VSNUL)
11320 switch (subtype & VSTYPE) {
11339 case VSTRIMLEFTMAX:
11346 case VSTRIMRIGHTMAX:
11353 out1fmt("<subtype %d>", subtype);
11360 case CTLBACKQ|CTLQUOTE:
11363 shtree(bqlist->n, -1, NULL, fp);
11375 indent(int amount, char *pfx, FILE *fp)
11379 for (i = 0 ; i < amount ; i++) {
11380 if (pfx && i == amount - 1)
11401 putc(c, tracefile);
11405 trace(const char *fmt, ...)
11412 (void) vfprintf(tracefile, fmt, va);
11417 tracev(const char *fmt, va_list va)
11421 (void) vfprintf(tracefile, fmt, va);
11426 trputs(const char *s)
11430 fputs(s, tracefile);
11442 putc('"', tracefile);
11443 for (p = s ; *p ; p++) {
11445 case '\n': c = 'n'; goto backslash;
11446 case '\t': c = 't'; goto backslash;
11447 case '\r': c = 'r'; goto backslash;
11448 case '"': c = '"'; goto backslash;
11449 case '\\': c = '\\'; goto backslash;
11450 case CTLESC: c = 'e'; goto backslash;
11451 case CTLVAR: c = 'v'; goto backslash;
11452 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11453 case CTLBACKQ: c = 'q'; goto backslash;
11454 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
11455 backslash: putc('\\', tracefile);
11456 putc(c, tracefile);
11459 if (*p >= ' ' && *p <= '~')
11460 putc(*p, tracefile);
11462 putc('\\', tracefile);
11463 putc(*p >> 6 & 03, tracefile);
11464 putc(*p >> 3 & 07, tracefile);
11465 putc(*p & 07, tracefile);
11470 putc('"', tracefile);
11482 putc(' ', tracefile);
11484 putc('\n', tracefile);
11500 /* leave open because libedit might be using it */
11503 scopy("./trace", s);
11505 if (!freopen(s, "a", tracefile)) {
11506 fprintf(stderr, "Can't re-open %s\n", s);
11511 if ((tracefile = fopen(s, "a")) == NULL) {
11512 fprintf(stderr, "Can't open %s\n", s);
11518 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11519 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11521 setlinebuf(tracefile);
11522 fputs("\nTracing started.\n", tracefile);
11527 /* $NetBSD: trap.c,v 1.28 2002/11/24 22:35:43 christos Exp $ */
11530 * Sigmode records the current value of the signal handlers for the various
11531 * modes. A value of zero means that the current handler is not known.
11532 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
11535 #define S_DFL 1 /* default signal handling (SIG_DFL) */
11536 #define S_CATCH 2 /* signal is caught */
11537 #define S_IGN 3 /* signal is ignored (SIG_IGN) */
11538 #define S_HARD_IGN 4 /* signal is ignored permenantly */
11539 #define S_RESET 5 /* temporary - to reset a hard ignored sig */
11544 * The trap builtin.
11548 trapcmd(int argc, char **argv)
11557 for (signo = 0 ; signo < NSIG ; signo++) {
11558 if (trap[signo] != NULL) {
11561 sn = u_signal_names(0, &signo, 0);
11564 out1fmt("trap -- %s %s\n",
11565 single_quote(trap[signo]), sn);
11575 if ((signo = decode_signal(*ap, 0)) < 0)
11576 error("%s: bad trap", *ap);
11579 if (action[0] == '-' && action[1] == '\0')
11582 action = savestr(action);
11585 ckfree(trap[signo]);
11586 trap[signo] = action;
11597 * Clear traps on a fork.
11605 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
11606 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
11610 if (tp != &trap[0])
11611 setsignal(tp - trap);
11619 * Set the signal handler for the specified signal. The routine figures
11620 * out what it should be set to.
11624 setsignal(int signo)
11628 struct sigaction act;
11630 if ((t = trap[signo]) == NULL)
11632 else if (*t != '\0')
11636 if (rootshell && action == S_DFL) {
11639 if (iflag || minusc || sflag == 0)
11662 t = &sigmode[signo - 1];
11666 * current setting unknown
11668 if (sigaction(signo, 0, &act) == -1) {
11670 * Pretend it worked; maybe we should give a warning
11671 * here, but other shells don't. We don't alter
11672 * sigmode, so that we retry every time.
11676 if (act.sa_handler == SIG_IGN) {
11677 if (mflag && (signo == SIGTSTP ||
11678 signo == SIGTTIN || signo == SIGTTOU)) {
11679 tsig = S_IGN; /* don't hard ignore these */
11683 tsig = S_RESET; /* force to be set */
11686 if (tsig == S_HARD_IGN || tsig == action)
11690 act.sa_handler = onsig;
11693 act.sa_handler = SIG_IGN;
11696 act.sa_handler = SIG_DFL;
11700 sigfillset(&act.sa_mask);
11701 sigaction(signo, &act, 0);
11709 ignoresig(int signo)
11711 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11712 signal(signo, SIG_IGN);
11714 sigmode[signo - 1] = S_HARD_IGN;
11725 gotsig[signo - 1] = 1;
11726 pendingsigs = signo;
11728 if (exsig || (signo == SIGINT && !trap[SIGINT])) {
11737 * Called to execute a trap. Perhaps we should avoid entering new trap
11738 * handlers while we are executing a trap handler.
11748 savestatus = exitstatus;
11750 while (pendingsigs = 0, barrier(), (p = memchr(q, 1, NSIG - 1))) {
11752 p = trap[p - q + 1];
11756 exitstatus = savestatus;
11762 * Controls whether the shell is interactive or not.
11766 setinteractive(int on)
11768 static int is_interactive;
11770 if (++on == is_interactive)
11772 is_interactive = on;
11774 setsignal(SIGQUIT);
11775 setsignal(SIGTERM);
11776 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11777 if(is_interactive > 1) {
11778 /* Looks like they want an interactive shell */
11779 static int do_banner;
11783 "\n\n" BB_BANNER " Built-in shell (ash)\n"
11784 "Enter 'help' for a list of built-in commands.\n\n");
11792 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11793 /*** List the available builtins ***/
11795 static int helpcmd(int argc, char **argv)
11799 out1fmt("\nBuilt-in commands:\n-------------------\n");
11800 for (col = 0, i = 0; i < NUMBUILTINS; i++) {
11801 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11802 builtincmd[i].name + 1);
11808 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
11810 extern const struct BB_applet applets[];
11811 extern const size_t NUM_APPLETS;
11813 for (i = 0; i < NUM_APPLETS; i++) {
11815 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
11824 return EXIT_SUCCESS;
11826 #endif /* CONFIG_FEATURE_SH_EXTRA_QUIET */
11829 * Called to exit the shell.
11839 status = exitstatus;
11840 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
11841 if (setjmp(loc.loc)) {
11845 if ((p = trap[0]) != NULL && *p != '\0') {
11850 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
11851 if (iflag && rootshell) {
11852 const char *hp = lookupvar("HISTFILE");
11855 save_history ( hp );
11863 static int decode_signal(const char *string, int minsig)
11866 const char *name = u_signal_names(string, &signo, minsig);
11868 return name ? signo : -1;
11871 /* $NetBSD: var.c,v 1.32 2003/01/22 20:36:04 dsl Exp $ */
11873 static struct var *vartab[VTABSIZE];
11875 static int vpcmp(const void *, const void *);
11876 static struct var **findvar(struct var **, const char *);
11879 * Initialize the varable symbol tables and import the environment
11883 #ifdef CONFIG_ASH_GETOPTS
11885 * Safe version of setvar, returns 1 on success 0 on failure.
11889 setvarsafe(const char *name, const char *val, int flags)
11892 volatile int saveint;
11893 struct jmploc *volatile savehandler = handler;
11894 struct jmploc jmploc;
11897 if (setjmp(jmploc.loc))
11901 setvar(name, val, flags);
11904 handler = savehandler;
11905 RESTOREINT(saveint);
11911 * Set the value of a variable. The flags argument is ored with the
11912 * flags of the variable. If val is NULL, the variable is unset.
11916 setvar(const char *name, const char *val, int flags)
11923 q = endofname(name);
11924 p = strchrnul(q, '=');
11925 namelen = p - name;
11926 if (!namelen || p != q)
11927 error("%.*s: bad variable name", namelen, name);
11932 vallen = strlen(val);
11935 p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
11939 p = mempcpy(p, val, vallen);
11942 setvareq(nameeq, flags | VNOSAVE);
11948 * Same as setvar except that the variable and value are passed in
11949 * the first argument as name=value. Since the first argument will
11950 * be actually stored in the table, it should not be a string that
11952 * Called with interrupts off.
11956 setvareq(char *s, int flags)
11958 struct var *vp, **vpp;
11961 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
11962 vp = *findvar(vpp, s);
11964 if (vp->flags & VREADONLY) {
11965 if (flags & VNOSAVE)
11967 error("%.*s: is read only", strchrnul(s, '=') - s, s);
11970 if (flags & VNOSET)
11973 if (vp->func && (flags & VNOFUNC) == 0)
11974 (*vp->func)(strchrnul(s, '=') + 1);
11976 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
11979 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
11981 if (flags & VNOSET)
11984 vp = ckmalloc(sizeof (*vp));
11989 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
11997 * Process a linked list of variable assignments.
12001 listsetvar(struct strlist *list_set_var, int flags)
12003 struct strlist *lp = list_set_var;
12009 setvareq(lp->text, flags);
12010 } while ((lp = lp->next));
12016 * Find the value of a variable. Returns NULL if not set.
12020 lookupvar(const char *name)
12024 if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
12025 return strchrnul(v->text, '=') + 1;
12032 * Search the environment of a builtin command.
12036 bltinlookup(const char *name)
12038 struct strlist *sp;
12040 for (sp = cmdenviron ; sp ; sp = sp->next) {
12041 if (varequal(sp->text, name))
12042 return strchrnul(sp->text, '=') + 1;
12044 return lookupvar(name);
12049 * Generate a list of variables satisfying the given conditions.
12053 listvars(int on, int off, char ***end)
12064 for (vp = *vpp ; vp ; vp = vp->next)
12065 if ((vp->flags & mask) == on) {
12066 if (ep == stackstrend())
12067 ep = growstackstr();
12068 *ep++ = (char *) vp->text;
12070 } while (++vpp < vartab + VTABSIZE);
12071 if (ep == stackstrend())
12072 ep = growstackstr();
12076 return grabstackstr(ep);
12081 * POSIX requires that 'set' (but not export or readonly) output the
12082 * variables in lexicographic order - by the locale's collating order (sigh).
12083 * Maybe we could keep them in an ordered balanced binary tree
12084 * instead of hashed lists.
12085 * For now just roll 'em through qsort for printing...
12089 showvars(const char *sep_prefix, int on, int off)
12092 char **ep, **epend;
12094 ep = listvars(on, off, &epend);
12095 qsort(ep, epend - ep, sizeof(char *), vpcmp);
12097 sep = *sep_prefix ? spcstr : sep_prefix;
12099 for (; ep < epend; ep++) {
12103 p = strchrnul(*ep, '=');
12106 q = single_quote(++p);
12108 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
12117 * The export and readonly commands.
12121 exportcmd(int argc, char **argv)
12127 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12130 notp = nextopt("p") - 'p';
12131 if (notp && ((name = *(aptr = argptr)))) {
12133 if ((p = strchr(name, '=')) != NULL) {
12136 if ((vp = *findvar(hashvar(name), name))) {
12141 setvar(name, p, flag);
12142 } while ((name = *++aptr) != NULL);
12144 showvars(argv[0], flag, 0);
12151 * Make a variable a local variable. When a variable is made local, it's
12152 * value and flags are saved in a localvar structure. The saved values
12153 * will be restored when the shell function returns. We handle the name
12154 * "-" as a special case.
12158 mklocal(char *name)
12160 struct localvar *lvp;
12165 lvp = ckmalloc(sizeof (struct localvar));
12166 if (name[0] == '-' && name[1] == '\0') {
12168 p = ckmalloc(sizeof(optlist));
12169 lvp->text = memcpy(p, optlist, sizeof(optlist));
12174 vpp = hashvar(name);
12175 vp = *findvar(vpp, name);
12176 eq = strchr(name, '=');
12179 setvareq(name, VSTRFIXED);
12181 setvar(name, NULL, VSTRFIXED);
12182 vp = *vpp; /* the new variable */
12183 lvp->flags = VUNSET;
12185 lvp->text = vp->text;
12186 lvp->flags = vp->flags;
12187 vp->flags |= VSTRFIXED|VTEXTFIXED;
12193 lvp->next = localvars;
12199 * The "local" command.
12203 localcmd(int argc, char **argv)
12208 while ((name = *argv++) != NULL) {
12216 * Called after a function returns.
12217 * Interrupts must be off.
12223 struct localvar *lvp;
12226 while ((lvp = localvars) != NULL) {
12227 localvars = lvp->next;
12229 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
12230 if (vp == NULL) { /* $- saved */
12231 memcpy(optlist, lvp->text, sizeof(optlist));
12234 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12235 unsetvar(vp->text);
12238 (*vp->func)(strchrnul(lvp->text, '=') + 1);
12239 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12241 vp->flags = lvp->flags;
12242 vp->text = lvp->text;
12250 * The unset builtin command. We unset the function before we unset the
12251 * variable to allow a function to be unset when there is a readonly variable
12252 * with the same name.
12256 unsetcmd(int argc, char **argv)
12263 while ((i = nextopt("vf")) != '\0') {
12267 for (ap = argptr; *ap ; ap++) {
12282 * Unset the specified variable.
12286 unsetvar(const char *s)
12292 vpp = findvar(hashvar(s), s);
12296 int flags = vp->flags;
12299 if (flags & VREADONLY)
12301 if (flags & VUNSET)
12303 if ((flags & VSTRFIXED) == 0) {
12305 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
12312 vp->flags &= ~VEXPORT;
12325 * Find the appropriate entry in the hash table from the name.
12328 static struct var **
12329 hashvar(const char *p)
12331 unsigned int hashval;
12333 hashval = ((unsigned char) *p) << 4;
12334 while (*p && *p != '=')
12335 hashval += (unsigned char) *p++;
12336 return &vartab[hashval % VTABSIZE];
12342 * Compares two strings up to the first = or '\0'. The first
12343 * string must be terminated by '='; the second may be terminated by
12344 * either '=' or '\0'.
12348 varcmp(const char *p, const char *q)
12352 while ((c = *p) == (d = *q)) {
12353 if (!c || c == '=')
12367 vpcmp(const void *a, const void *b)
12369 return varcmp(*(const char **)a, *(const char **)b);
12372 static struct var **
12373 findvar(struct var **vpp, const char *name)
12375 for (; *vpp; vpp = &(*vpp)->next) {
12376 if (varequal((*vpp)->text, name)) {
12382 /* $NetBSD: setmode.c,v 1.29 2003/01/15 23:58:03 kleink Exp $ */
12384 #include <sys/times.h>
12386 static const unsigned char timescmd_str[] = {
12387 ' ', offsetof(struct tms, tms_utime),
12388 '\n', offsetof(struct tms, tms_stime),
12389 ' ', offsetof(struct tms, tms_cutime),
12390 '\n', offsetof(struct tms, tms_cstime),
12394 static int timescmd(int ac, char **av)
12396 long int clk_tck, s, t;
12397 const unsigned char *p;
12400 clk_tck = sysconf(_SC_CLK_TCK);
12405 t = *(clock_t *)(((char *) &buf) + p[1]);
12407 out1fmt("%ldm%ld.%.3lds%c",
12409 ((t - s * clk_tck) * 1000) / clk_tck,
12411 } while (*(p += 2));
12416 #ifdef CONFIG_ASH_MATH_SUPPORT
12418 dash_arith(const char *s)
12424 result = arith(s, &errcode);
12427 error("exponent less than 0");
12428 else if (errcode == -2)
12429 error("divide by zero");
12430 else if (errcode == -5)
12431 error("expression recursion loop detected");
12442 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12443 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12445 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12449 letcmd(int argc, char **argv)
12456 error("expression expected");
12457 for (ap = argv + 1; *ap; ap++) {
12458 i = dash_arith(*ap);
12463 #endif /* CONFIG_ASH_MATH_SUPPORT */
12465 /* $NetBSD: miscbltin.c,v 1.31 2002/11/24 22:35:41 christos Exp $ */
12468 * Miscelaneous builtins.
12474 #if __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
12475 typedef enum __rlimit_resource rlim_t;
12481 * The read builtin. The -e option causes backslashes to escape the
12482 * following character.
12484 * This uses unbuffered input, which may be avoidable in some cases.
12488 readcmd(int argc, char **argv)
12503 while ((i = nextopt("p:r")) != '\0') {
12505 prompt = optionarg;
12509 if (prompt && isatty(0)) {
12512 if (*(ap = argptr) == NULL)
12513 error("arg count");
12514 if ((ifs = bltinlookup("IFS")) == NULL)
12521 if (read(0, &c, 1) != 1) {
12533 if (!rflag && c == '\\') {
12539 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12543 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12545 setvar(*ap, stackblock(), 0);
12555 /* Remove trailing blanks */
12556 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12558 setvar(*ap, stackblock(), 0);
12559 while (*++ap != NULL)
12560 setvar(*ap, nullstr, 0);
12565 static int umaskcmd(int argc, char **argv)
12567 static const char permuser[3] = "ugo";
12568 static const char permmode[3] = "rwx";
12569 static const short int permmask[] = {
12570 S_IRUSR, S_IWUSR, S_IXUSR,
12571 S_IRGRP, S_IWGRP, S_IXGRP,
12572 S_IROTH, S_IWOTH, S_IXOTH
12578 int symbolic_mode = 0;
12580 while (nextopt("S") != '\0') {
12589 if ((ap = *argptr) == NULL) {
12590 if (symbolic_mode) {
12594 for (i = 0; i < 3; i++) {
12597 *p++ = permuser[i];
12599 for (j = 0; j < 3; j++) {
12600 if ((mask & permmask[3 * i + j]) == 0) {
12601 *p++ = permmode[j];
12609 out1fmt("%.4o\n", mask);
12612 if (is_digit((unsigned char) *ap)) {
12615 if (*ap >= '8' || *ap < '0')
12616 error(illnum, argv[1]);
12617 mask = (mask << 3) + (*ap - '0');
12618 } while (*++ap != '\0');
12621 mask = ~mask & 0777;
12622 if (!bb_parse_mode(ap, &mask)) {
12623 error("Illegal mode: %s", ap);
12625 umask(~mask & 0777);
12634 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12635 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12636 * ash by J.T. Conklin.
12644 int factor; /* multiply by to get rlim_{cur,max} values */
12648 static const struct limits limits[] = {
12650 { "time(seconds)", RLIMIT_CPU, 1, 't' },
12652 #ifdef RLIMIT_FSIZE
12653 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
12656 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
12658 #ifdef RLIMIT_STACK
12659 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
12662 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
12665 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
12667 #ifdef RLIMIT_MEMLOCK
12668 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
12670 #ifdef RLIMIT_NPROC
12671 { "process", RLIMIT_NPROC, 1, 'p' },
12673 #ifdef RLIMIT_NOFILE
12674 { "nofiles", RLIMIT_NOFILE, 1, 'n' },
12677 { "vmemory(kbytes)", RLIMIT_AS, 1024, 'v' },
12679 #ifdef RLIMIT_LOCKS
12680 { "locks", RLIMIT_LOCKS, 1, 'w' },
12682 { (char *) 0, 0, 0, '\0' }
12685 enum limtype { SOFT = 0x1, HARD = 0x2 };
12687 static void printlim(enum limtype how, const struct rlimit *limit,
12688 const struct limits *l)
12692 val = limit->rlim_max;
12694 val = limit->rlim_cur;
12696 if (val == RLIM_INFINITY)
12697 out1fmt("unlimited\n");
12700 out1fmt("%lld\n", (long long) val);
12705 ulimitcmd(int argc, char **argv)
12709 enum limtype how = SOFT | HARD;
12710 const struct limits *l;
12713 struct rlimit limit;
12716 while ((optc = nextopt("HSatfdsmcnplvw")) != '\0')
12731 for (l = limits; l->option != what; l++)
12734 set = *argptr ? 1 : 0;
12738 if (all || argptr[1])
12739 error("too many arguments");
12740 if (strncmp(p, "unlimited\n", 9) == 0)
12741 val = RLIM_INFINITY;
12745 while ((c = *p++) >= '0' && c <= '9')
12747 val = (val * 10) + (long)(c - '0');
12748 if (val < (rlim_t) 0)
12752 error("bad number");
12757 for (l = limits; l->name; l++) {
12758 getrlimit(l->cmd, &limit);
12759 out1fmt("%-20s ", l->name);
12760 printlim(how, &limit, l);
12765 getrlimit(l->cmd, &limit);
12768 limit.rlim_max = val;
12770 limit.rlim_cur = val;
12771 if (setrlimit(l->cmd, &limit) < 0)
12772 error("error setting limit (%m)");
12774 printlim(how, &limit, l);
12780 #ifdef CONFIG_ASH_MATH_SUPPORT
12782 /* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
12784 Permission is hereby granted, free of charge, to any person obtaining
12785 a copy of this software and associated documentation files (the
12786 "Software"), to deal in the Software without restriction, including
12787 without limitation the rights to use, copy, modify, merge, publish,
12788 distribute, sublicense, and/or sell copies of the Software, and to
12789 permit persons to whom the Software is furnished to do so, subject to
12790 the following conditions:
12792 The above copyright notice and this permission notice shall be
12793 included in all copies or substantial portions of the Software.
12795 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12796 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12797 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
12798 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
12799 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
12800 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
12801 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12804 /* This is my infix parser/evaluator. It is optimized for size, intended
12805 * as a replacement for yacc-based parsers. However, it may well be faster
12806 * than a comparable parser writen in yacc. The supported operators are
12807 * listed in #defines below. Parens, order of operations, and error handling
12808 * are supported. This code is threadsafe. The exact expression format should
12809 * be that which POSIX specifies for shells. */
12811 /* The code uses a simple two-stack algorithm. See
12812 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
12813 * for a detailed explaination of the infix-to-postfix algorithm on which
12814 * this is based (this code differs in that it applies operators immediately
12815 * to the stack instead of adding them to a queue to end up with an
12818 /* To use the routine, call it with an expression string and error return
12822 * Aug 24, 2001 Manuel Novoa III
12824 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
12826 * 1) In arith_apply():
12827 * a) Cached values of *numptr and &(numptr[-1]).
12828 * b) Removed redundant test for zero denominator.
12831 * a) Eliminated redundant code for processing operator tokens by moving
12832 * to a table-based implementation. Also folded handling of parens
12834 * b) Combined all 3 loops which called arith_apply to reduce generated
12835 * code size at the cost of speed.
12837 * 3) The following expressions were treated as valid by the original code:
12838 * 1() , 0! , 1 ( *3 ) .
12839 * These bugs have been fixed by internally enclosing the expression in
12840 * parens and then checking that all binary ops and right parens are
12841 * preceded by a valid expression (NUM_TOKEN).
12843 * Note: It may be desireable to replace Aaron's test for whitespace with
12844 * ctype's isspace() if it is used by another busybox applet or if additional
12845 * whitespace chars should be considered. Look below the "#include"s for a
12846 * precompiler test.
12850 * Aug 26, 2001 Manuel Novoa III
12852 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
12854 * Merge in Aaron's comments previously posted to the busybox list,
12855 * modified slightly to take account of my changes to the code.
12860 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12862 * - allow access to variable,
12863 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
12864 * - realize assign syntax (VAR=expr, +=, *= etc)
12865 * - realize exponentiation (** operator)
12866 * - realize comma separated - expr, expr
12867 * - realise ++expr --expr expr++ expr--
12868 * - realise expr ? expr : expr (but, second expr calculate always)
12869 * - allow hexdecimal and octal numbers
12870 * - was restored loses XOR operator
12871 * - remove one goto label, added three ;-)
12872 * - protect $((num num)) as true zero expr (Manuel`s error)
12873 * - always use special isspace(), see comment from bash ;-)
12877 #define arith_isspace(arithval) \
12878 (arithval == ' ' || arithval == '\n' || arithval == '\t')
12881 typedef unsigned char operator;
12883 /* An operator's token id is a bit of a bitfield. The lower 5 bits are the
12884 * precedence, and 3 high bits are an ID unique accross operators of that
12885 * precedence. The ID portion is so that multiple operators can have the
12886 * same precedence, ensuring that the leftmost one is evaluated first.
12887 * Consider * and /. */
12889 #define tok_decl(prec,id) (((id)<<5)|(prec))
12890 #define PREC(op) ((op) & 0x1F)
12892 #define TOK_LPAREN tok_decl(0,0)
12894 #define TOK_COMMA tok_decl(1,0)
12896 #define TOK_ASSIGN tok_decl(2,0)
12897 #define TOK_AND_ASSIGN tok_decl(2,1)
12898 #define TOK_OR_ASSIGN tok_decl(2,2)
12899 #define TOK_XOR_ASSIGN tok_decl(2,3)
12900 #define TOK_PLUS_ASSIGN tok_decl(2,4)
12901 #define TOK_MINUS_ASSIGN tok_decl(2,5)
12902 #define TOK_LSHIFT_ASSIGN tok_decl(2,6)
12903 #define TOK_RSHIFT_ASSIGN tok_decl(2,7)
12905 #define TOK_MUL_ASSIGN tok_decl(3,0)
12906 #define TOK_DIV_ASSIGN tok_decl(3,1)
12907 #define TOK_REM_ASSIGN tok_decl(3,2)
12909 /* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
12910 #define convert_prec_is_assing(prec) do { if(prec == 3) prec = 2; } while(0)
12912 /* conditional is right associativity too */
12913 #define TOK_CONDITIONAL tok_decl(4,0)
12914 #define TOK_CONDITIONAL_SEP tok_decl(4,1)
12916 #define TOK_OR tok_decl(5,0)
12918 #define TOK_AND tok_decl(6,0)
12920 #define TOK_BOR tok_decl(7,0)
12922 #define TOK_BXOR tok_decl(8,0)
12924 #define TOK_BAND tok_decl(9,0)
12926 #define TOK_EQ tok_decl(10,0)
12927 #define TOK_NE tok_decl(10,1)
12929 #define TOK_LT tok_decl(11,0)
12930 #define TOK_GT tok_decl(11,1)
12931 #define TOK_GE tok_decl(11,2)
12932 #define TOK_LE tok_decl(11,3)
12934 #define TOK_LSHIFT tok_decl(12,0)
12935 #define TOK_RSHIFT tok_decl(12,1)
12937 #define TOK_ADD tok_decl(13,0)
12938 #define TOK_SUB tok_decl(13,1)
12940 #define TOK_MUL tok_decl(14,0)
12941 #define TOK_DIV tok_decl(14,1)
12942 #define TOK_REM tok_decl(14,2)
12944 /* exponent is right associativity */
12945 #define TOK_EXPONENT tok_decl(15,1)
12947 /* For now unary operators. */
12948 #define UNARYPREC 16
12949 #define TOK_BNOT tok_decl(UNARYPREC,0)
12950 #define TOK_NOT tok_decl(UNARYPREC,1)
12952 #define TOK_UMINUS tok_decl(UNARYPREC+1,0)
12953 #define TOK_UPLUS tok_decl(UNARYPREC+1,1)
12955 #define PREC_PRE (UNARYPREC+2)
12957 #define TOK_PRE_INC tok_decl(PREC_PRE, 0)
12958 #define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
12960 #define PREC_POST (UNARYPREC+3)
12962 #define TOK_POST_INC tok_decl(PREC_POST, 0)
12963 #define TOK_POST_DEC tok_decl(PREC_POST, 1)
12965 #define SPEC_PREC (UNARYPREC+4)
12967 #define TOK_NUM tok_decl(SPEC_PREC, 0)
12968 #define TOK_RPAREN tok_decl(SPEC_PREC, 1)
12970 #define NUMPTR (*numstackptr)
12972 static inline int tok_have_assign(operator op)
12974 operator prec = PREC(op);
12976 convert_prec_is_assing(prec);
12977 return (prec == PREC(TOK_ASSIGN) ||
12978 prec == PREC_PRE || prec == PREC_POST);
12981 static inline int is_right_associativity(operator prec)
12983 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) ||
12984 prec == PREC(TOK_CONDITIONAL));
12988 typedef struct ARITCH_VAR_NUM {
12990 long contidional_second_val;
12991 char contidional_second_val_initialized;
12992 char *var; /* if NULL then is regular number,
12993 else is varable name */
12997 typedef struct CHK_VAR_RECURSIVE_LOOPED {
12999 struct CHK_VAR_RECURSIVE_LOOPED *next;
13000 } chk_var_recursive_looped_t;
13002 static chk_var_recursive_looped_t *prev_chk_var_recursive;
13005 static int arith_lookup_val(v_n_t *t)
13008 const char * p = lookupvar(t->var);
13013 /* recursive try as expression */
13014 chk_var_recursive_looped_t *cur;
13015 chk_var_recursive_looped_t cur_save;
13017 for(cur = prev_chk_var_recursive; cur; cur = cur->next) {
13018 if(strcmp(cur->var, t->var) == 0) {
13019 /* expression recursion loop detected */
13023 /* save current lookuped var name */
13024 cur = prev_chk_var_recursive;
13025 cur_save.var = t->var;
13026 cur_save.next = cur;
13027 prev_chk_var_recursive = &cur_save;
13029 t->val = arith (p, &errcode);
13030 /* restore previous ptr after recursiving */
13031 prev_chk_var_recursive = cur;
13034 /* allow undefined var as 0 */
13041 /* "applying" a token means performing it on the top elements on the integer
13042 * stack. For a unary operator it will only change the top element, but a
13043 * binary operator will pop two arguments and push a result */
13045 arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
13050 int ret_arith_lookup_val;
13052 if (NUMPTR == numstack) goto err; /* There is no operator that can work
13053 without arguments */
13054 numptr_m1 = NUMPTR - 1;
13056 /* check operand is var with noninteger value */
13057 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13058 if(ret_arith_lookup_val)
13059 return ret_arith_lookup_val;
13061 rez = numptr_m1->val;
13062 if (op == TOK_UMINUS)
13064 else if (op == TOK_NOT)
13066 else if (op == TOK_BNOT)
13068 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
13070 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
13072 else if (op != TOK_UPLUS) {
13073 /* Binary operators */
13075 /* check and binary operators need two arguments */
13076 if (numptr_m1 == numstack) goto err;
13078 /* ... and they pop one */
13081 if (op == TOK_CONDITIONAL) {
13082 if(! numptr_m1->contidional_second_val_initialized) {
13083 /* protect $((expr1 ? expr2)) without ": expr" */
13086 rez = numptr_m1->contidional_second_val;
13087 } else if(numptr_m1->contidional_second_val_initialized) {
13088 /* protect $((expr1 : expr2)) without "expr ? " */
13091 numptr_m1 = NUMPTR - 1;
13092 if(op != TOK_ASSIGN) {
13093 /* check operand is var with noninteger value for not '=' */
13094 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13095 if(ret_arith_lookup_val)
13096 return ret_arith_lookup_val;
13098 if (op == TOK_CONDITIONAL) {
13099 numptr_m1->contidional_second_val = rez;
13101 rez = numptr_m1->val;
13102 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
13104 else if (op == TOK_OR)
13105 rez = numptr_val || rez;
13106 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
13108 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
13110 else if (op == TOK_AND)
13111 rez = rez && numptr_val;
13112 else if (op == TOK_EQ)
13113 rez = (rez == numptr_val);
13114 else if (op == TOK_NE)
13115 rez = (rez != numptr_val);
13116 else if (op == TOK_GE)
13117 rez = (rez >= numptr_val);
13118 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
13119 rez >>= numptr_val;
13120 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
13121 rez <<= numptr_val;
13122 else if (op == TOK_GT)
13123 rez = (rez > numptr_val);
13124 else if (op == TOK_LT)
13125 rez = (rez < numptr_val);
13126 else if (op == TOK_LE)
13127 rez = (rez <= numptr_val);
13128 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
13130 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
13132 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
13134 else if (op == TOK_ASSIGN || op == TOK_COMMA)
13136 else if (op == TOK_CONDITIONAL_SEP) {
13137 if (numptr_m1 == numstack) {
13138 /* protect $((expr : expr)) without "expr ? " */
13141 numptr_m1->contidional_second_val_initialized = op;
13142 numptr_m1->contidional_second_val = numptr_val;
13144 else if (op == TOK_CONDITIONAL) {
13146 numptr_val : numptr_m1->contidional_second_val;
13148 else if(op == TOK_EXPONENT) {
13150 return -3; /* exponent less than 0 */
13155 while(numptr_val--)
13160 else if(numptr_val==0) /* zero divisor check */
13162 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
13164 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
13167 if(tok_have_assign(op)) {
13170 if(numptr_m1->var == NULL) {
13174 /* save to shell variable */
13175 sprintf(buf, "%ld", rez);
13176 setvar(numptr_m1->var, buf, 0);
13177 /* after saving, make previous value for v++ or v-- */
13178 if(op == TOK_POST_INC)
13180 else if(op == TOK_POST_DEC)
13183 numptr_m1->val = rez;
13184 /* protect geting var value, is number now */
13185 numptr_m1->var = NULL;
13190 /* longest must first */
13191 static const char op_tokens[] = {
13192 '<','<','=',0, TOK_LSHIFT_ASSIGN,
13193 '>','>','=',0, TOK_RSHIFT_ASSIGN,
13194 '<','<', 0, TOK_LSHIFT,
13195 '>','>', 0, TOK_RSHIFT,
13196 '|','|', 0, TOK_OR,
13197 '&','&', 0, TOK_AND,
13198 '!','=', 0, TOK_NE,
13199 '<','=', 0, TOK_LE,
13200 '>','=', 0, TOK_GE,
13201 '=','=', 0, TOK_EQ,
13202 '|','=', 0, TOK_OR_ASSIGN,
13203 '&','=', 0, TOK_AND_ASSIGN,
13204 '*','=', 0, TOK_MUL_ASSIGN,
13205 '/','=', 0, TOK_DIV_ASSIGN,
13206 '%','=', 0, TOK_REM_ASSIGN,
13207 '+','=', 0, TOK_PLUS_ASSIGN,
13208 '-','=', 0, TOK_MINUS_ASSIGN,
13209 '-','-', 0, TOK_POST_DEC,
13210 '^','=', 0, TOK_XOR_ASSIGN,
13211 '+','+', 0, TOK_POST_INC,
13212 '*','*', 0, TOK_EXPONENT,
13216 '=', 0, TOK_ASSIGN,
13228 '?', 0, TOK_CONDITIONAL,
13229 ':', 0, TOK_CONDITIONAL_SEP,
13230 ')', 0, TOK_RPAREN,
13231 '(', 0, TOK_LPAREN,
13235 #define endexpression &op_tokens[sizeof(op_tokens)-7]
13238 extern long arith (const char *expr, int *perrcode)
13240 register char arithval; /* Current character under analysis */
13241 operator lasttok, op;
13244 const char *p = endexpression;
13247 size_t datasizes = strlen(expr) + 2;
13249 /* Stack of integers */
13250 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
13251 * in any given correct or incorrect expression is left as an excersize to
13253 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
13254 *numstackptr = numstack;
13255 /* Stack of operator tokens */
13256 operator *stack = alloca((datasizes) * sizeof(operator)),
13259 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
13260 *perrcode = errcode = 0;
13263 if ((arithval = *expr) == 0) {
13264 if (p == endexpression) {
13265 /* Null expression. */
13269 /* This is only reached after all tokens have been extracted from the
13270 * input stream. If there are still tokens on the operator stack, they
13271 * are to be applied in order. At the end, there should be a final
13272 * result on the integer stack */
13274 if (expr != endexpression + 1) {
13275 /* If we haven't done so already, */
13276 /* append a closing right paren */
13277 expr = endexpression;
13278 /* and let the loop process it. */
13281 /* At this point, we're done with the expression. */
13282 if (numstackptr != numstack+1) {
13283 /* ... but if there isn't, it's bad */
13285 return (*perrcode = -1);
13287 if(numstack->var) {
13288 /* expression is $((var)) only, lookup now */
13289 errcode = arith_lookup_val(numstack);
13292 *perrcode = errcode;
13293 return numstack->val;
13295 /* Continue processing the expression. */
13296 if (arith_isspace(arithval)) {
13297 /* Skip whitespace */
13300 if((p = endofname(expr)) != expr) {
13301 int var_name_size = (p-expr) + 1; /* trailing zero */
13303 numstackptr->var = alloca(var_name_size);
13304 safe_strncpy(numstackptr->var, expr, var_name_size);
13307 numstackptr->contidional_second_val_initialized = 0;
13311 } else if (is_digit(arithval)) {
13312 numstackptr->var = NULL;
13313 numstackptr->val = strtol(expr, (char **) &expr, 0);
13316 for(p = op_tokens; ; p++) {
13320 /* strange operator not found */
13323 for(o = expr; *p && *o == *p; p++)
13330 /* skip tail uncompared token */
13333 /* skip zero delim */
13338 /* post grammar: a++ reduce to num */
13339 if(lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13342 /* Plus and minus are binary (not unary) _only_ if the last
13343 * token was as number, or a right paren (which pretends to be
13344 * a number, since it evaluates to one). Think about it.
13345 * It makes sense. */
13346 if (lasttok != TOK_NUM) {
13362 /* We don't want a unary operator to cause recursive descent on the
13363 * stack, because there can be many in a row and it could cause an
13364 * operator to be evaluated before its argument is pushed onto the
13365 * integer stack. */
13366 /* But for binary operators, "apply" everything on the operator
13367 * stack until we find an operator with a lesser priority than the
13368 * one we have just extracted. */
13369 /* Left paren is given the lowest priority so it will never be
13370 * "applied" in this way.
13371 * if associativity is right and priority eq, applied also skip
13374 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13375 /* not left paren or unary */
13376 if (lasttok != TOK_NUM) {
13377 /* binary op must be preceded by a num */
13380 while (stackptr != stack) {
13381 if (op == TOK_RPAREN) {
13382 /* The algorithm employed here is simple: while we don't
13383 * hit an open paren nor the bottom of the stack, pop
13384 * tokens and apply them */
13385 if (stackptr[-1] == TOK_LPAREN) {
13387 /* Any operator directly after a */
13389 /* close paren should consider itself binary */
13393 operator prev_prec = PREC(stackptr[-1]);
13395 convert_prec_is_assing(prec);
13396 convert_prec_is_assing(prev_prec);
13397 if (prev_prec < prec)
13399 /* check right assoc */
13400 if(prev_prec == prec && is_right_associativity(prec))
13403 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13404 if(errcode) goto ret;
13406 if (op == TOK_RPAREN) {
13411 /* Push this operator to the stack and remember it. */
13412 *stackptr++ = lasttok = op;
13419 #endif /* CONFIG_ASH_MATH_SUPPORT */
13423 const char *bb_applet_name = "debug stuff usage";
13424 int main(int argc, char **argv)
13426 return ash_main(argc, argv);
13431 * Copyright (c) 1989, 1991, 1993, 1994
13432 * The Regents of the University of California. All rights reserved.
13434 * This code is derived from software contributed to Berkeley by
13435 * Kenneth Almquist.
13437 * Redistribution and use in source and binary forms, with or without
13438 * modification, are permitted provided that the following conditions
13440 * 1. Redistributions of source code must retain the above copyright
13441 * notice, this list of conditions and the following disclaimer.
13442 * 2. Redistributions in binary form must reproduce the above copyright
13443 * notice, this list of conditions and the following disclaimer in the
13444 * documentation and/or other materials provided with the distribution.
13446 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
13447 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
13449 * 4. Neither the name of the University nor the names of its contributors
13450 * may be used to endorse or promote products derived from this software
13451 * without specific prior written permission.
13453 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13454 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13455 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13456 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13457 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13458 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13459 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13460 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13461 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13462 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF