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 goodname(const char *p)
3482 return !*endofname(p);
3486 * Search for a command. This is called before we fork so that the
3487 * location of the command will be available in the parent as well as
3488 * the child. The check for "goodname" is an overly conservative
3489 * check that the name will not be subject to expansion.
3493 prehash(union node *n)
3495 struct cmdentry entry;
3497 if (n->type == NCMD && n->ncmd.args)
3498 if (goodname(n->ncmd.args->narg.text))
3499 find_command(n->ncmd.args->narg.text, &entry, 0,
3506 * Builtin commands. Builtin commands whose functions are closely
3507 * tied to evaluation are implemented here.
3515 bltincmd(int argc, char **argv)
3518 * Preserve exitstatus of a previous possible redirection
3521 return back_exitstatus;
3526 * Handle break and continue commands. Break, continue, and return are
3527 * all handled by setting the evalskip flag. The evaluation routines
3528 * above all check this flag, and if it is set they start skipping
3529 * commands rather than executing them. The variable skipcount is
3530 * the number of loops to break/continue, or the number of function
3531 * levels to return. (The latter is always 1.) It should probably
3532 * be an error to break out of more loops than exist, but it isn't
3533 * in the standard shell so we don't make it one here.
3537 breakcmd(int argc, char **argv)
3539 int n = argc > 1 ? number(argv[1]) : 1;
3542 error(illnum, argv[1]);
3546 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
3554 * The return command.
3558 returncmd(int argc, char **argv)
3560 int ret = argc > 1 ? number(argv[1]) : exitstatus;
3563 evalskip = SKIPFUNC;
3568 /* Do what ksh does; skip the rest of the file */
3569 evalskip = SKIPFILE;
3577 falsecmd(int argc, char **argv)
3584 truecmd(int argc, char **argv)
3591 execcmd(int argc, char **argv)
3594 iflag = 0; /* exit on error */
3597 shellexec(argv + 1, pathval(), 0);
3603 /* $NetBSD: exec.c,v 1.35 2003/01/22 20:36:04 dsl Exp $ */
3606 * When commands are first encountered, they are entered in a hash table.
3607 * This ensures that a full path search will not have to be done for them
3608 * on each invocation.
3610 * We should investigate converting to a linear search, even though that
3611 * would make the command name "hash" a misnomer.
3614 #define CMDTABLESIZE 31 /* should be prime */
3615 #define ARB 1 /* actual size determined at run time */
3620 struct tblentry *next; /* next entry in hash chain */
3621 union param param; /* definition of builtin function */
3622 short cmdtype; /* index identifying command */
3623 char rehash; /* if set, cd done since entry created */
3624 char cmdname[ARB]; /* name of command */
3628 static struct tblentry *cmdtable[CMDTABLESIZE];
3629 static int builtinloc = -1; /* index in path of %builtin, or -1 */
3632 static void tryexec(char *, char **, char **);
3633 static void clearcmdentry(int);
3634 static struct tblentry *cmdlookup(const char *, int);
3635 static void delete_cmd_entry(void);
3639 * Exec a program. Never returns. If you change this routine, you may
3640 * have to change the find_command routine as well.
3644 shellexec(char **argv, const char *path, int idx)
3651 envp = environment();
3652 if (strchr(argv[0], '/') != NULL
3653 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3654 || find_applet_by_name(argv[0])
3657 tryexec(argv[0], argv, envp);
3661 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3662 if (--idx < 0 && pathopt == NULL) {
3663 tryexec(cmdname, argv, envp);
3664 if (errno != ENOENT && errno != ENOTDIR)
3671 /* Map to POSIX errors */
3683 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
3684 argv[0], e, suppressint ));
3685 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3691 tryexec(char *cmd, char **argv, char **envp)
3694 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3698 #ifdef CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN
3699 name = bb_get_last_path_component(name);
3700 if(find_applet_by_name(name) != NULL)
3703 if(strchr(name, '/') == NULL && find_applet_by_name(name) != NULL) {
3712 if(strcmp(name, "busybox")) {
3713 for (ap = argv; *ap; ap++);
3714 ap = new = xmalloc((ap - argv + 2) * sizeof(char *));
3715 *ap++ = cmd = "/bin/busybox";
3716 while ((*ap++ = *argv++));
3720 cmd = "/bin/busybox";
3728 execve(cmd, argv, envp);
3729 } while (errno == EINTR);
3731 execve(cmd, argv, envp);
3735 } else if (errno == ENOEXEC) {
3739 for (ap = argv; *ap; ap++)
3741 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
3743 *ap = cmd = (char *)DEFAULT_SHELL;
3746 while ((*ap++ = *argv++))
3756 * Do a path search. The variable path (passed by reference) should be
3757 * set to the start of the path before the first call; padvance will update
3758 * this value as it proceeds. Successive calls to padvance will return
3759 * the possible path expansions in sequence. If an option (indicated by
3760 * a percent sign) appears in the path entry then the global variable
3761 * pathopt will be set to point to it; otherwise pathopt will be set to
3766 padvance(const char **path, const char *name)
3776 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
3777 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
3778 while (stackblocksize() < len)
3782 memcpy(q, start, p - start);
3790 while (*p && *p != ':') p++;
3796 return stalloc(len);
3800 /*** Command hashing code ***/
3803 printentry(struct tblentry *cmdp)
3809 idx = cmdp->param.index;
3812 name = padvance(&path, cmdp->cmdname);
3814 } while (--idx >= 0);
3815 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
3820 hashcmd(int argc, char **argv)
3822 struct tblentry **pp;
3823 struct tblentry *cmdp;
3825 struct cmdentry entry;
3828 while ((c = nextopt("r")) != '\0') {
3832 if (*argptr == NULL) {
3833 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3834 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3835 if (cmdp->cmdtype == CMDNORMAL)
3842 while ((name = *argptr) != NULL) {
3843 if ((cmdp = cmdlookup(name, 0)) != NULL
3844 && (cmdp->cmdtype == CMDNORMAL
3845 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
3847 find_command(name, &entry, DO_ERR, pathval());
3848 if (entry.cmdtype == CMDUNKNOWN)
3857 * Resolve a command name. If you change this routine, you may have to
3858 * change the shellexec routine as well.
3862 find_command(char *name, struct cmdentry *entry, int act, const char *path)
3864 struct tblentry *cmdp;
3871 struct builtincmd *bcmd;
3873 /* If name contains a slash, don't use PATH or hash table */
3874 if (strchr(name, '/') != NULL) {
3875 entry->u.index = -1;
3877 while (stat(name, &statb) < 0) {
3882 entry->cmdtype = CMDUNKNOWN;
3886 entry->cmdtype = CMDNORMAL;
3890 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3891 if (find_applet_by_name(name)) {
3892 entry->cmdtype = CMDNORMAL;
3893 entry->u.index = -1;
3898 updatetbl = (path == pathval());
3901 if (strstr(path, "%builtin") != NULL)
3905 /* If name is in the table, check answer will be ok */
3906 if ((cmdp = cmdlookup(name, 0)) != NULL) {
3909 switch (cmdp->cmdtype) {
3927 } else if (cmdp->rehash == 0)
3928 /* if not invalidated by cd, we're done */
3932 /* If %builtin not in path, check for builtin next */
3933 bcmd = find_builtin(name);
3934 if (bcmd && (IS_BUILTIN_REGULAR(bcmd) || (
3935 act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0
3937 goto builtin_success;
3939 /* We have to search path. */
3940 prev = -1; /* where to start */
3941 if (cmdp && cmdp->rehash) { /* doing a rehash */
3942 if (cmdp->cmdtype == CMDBUILTIN)
3945 prev = cmdp->param.index;
3951 while ((fullname = padvance(&path, name)) != NULL) {
3952 stunalloc(fullname);
3955 if (prefix(pathopt, "builtin")) {
3957 goto builtin_success;
3959 } else if (!(act & DO_NOFUNC) &&
3960 prefix(pathopt, "func")) {
3963 /* ignore unimplemented options */
3967 /* if rehash, don't redo absolute path names */
3968 if (fullname[0] == '/' && idx <= prev) {
3971 TRACE(("searchexec \"%s\": no change\n", name));
3974 while (stat(fullname, &statb) < 0) {
3979 if (errno != ENOENT && errno != ENOTDIR)
3983 e = EACCES; /* if we fail, this will be the error */
3984 if (!S_ISREG(statb.st_mode))
3986 if (pathopt) { /* this is a %func directory */
3987 stalloc(strlen(fullname) + 1);
3988 readcmdfile(fullname);
3989 if ((cmdp = cmdlookup(name, 0)) == NULL ||
3990 cmdp->cmdtype != CMDFUNCTION)
3991 error("%s not defined in %s", name, fullname);
3992 stunalloc(fullname);
3995 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
3997 entry->cmdtype = CMDNORMAL;
3998 entry->u.index = idx;
4002 cmdp = cmdlookup(name, 1);
4003 cmdp->cmdtype = CMDNORMAL;
4004 cmdp->param.index = idx;
4009 /* We failed. If there was an entry for this command, delete it */
4010 if (cmdp && updatetbl)
4013 sh_warnx("%s: %s", name, errmsg(e, E_EXEC));
4014 entry->cmdtype = CMDUNKNOWN;
4019 entry->cmdtype = CMDBUILTIN;
4020 entry->u.cmd = bcmd;
4024 cmdp = cmdlookup(name, 1);
4025 cmdp->cmdtype = CMDBUILTIN;
4026 cmdp->param.cmd = bcmd;
4030 entry->cmdtype = cmdp->cmdtype;
4031 entry->u = cmdp->param;
4036 * Wrapper around strcmp for qsort/bsearch/...
4038 static int pstrcmp(const void *a, const void *b)
4040 return strcmp((const char *) a, (*(const char *const *) b) + 1);
4044 * Search the table of builtin commands.
4047 static struct builtincmd *
4048 find_builtin(const char *name)
4050 struct builtincmd *bp;
4053 name, builtincmd, NUMBUILTINS, sizeof(struct builtincmd),
4062 * Called when a cd is done. Marks all commands so the next time they
4063 * are executed they will be rehashed.
4069 struct tblentry **pp;
4070 struct tblentry *cmdp;
4072 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4073 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4074 if (cmdp->cmdtype == CMDNORMAL || (
4075 cmdp->cmdtype == CMDBUILTIN &&
4076 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) &&
4087 * Fix command hash table when PATH changed.
4088 * Called before PATH is changed. The argument is the new value of PATH;
4089 * pathval() still returns the old value at this point.
4090 * Called with interrupts off.
4094 changepath(const char *newval)
4096 const char *old, *new;
4103 firstchange = 9999; /* assume no change */
4109 if ((*old == '\0' && *new == ':')
4110 || (*old == ':' && *new == '\0'))
4112 old = new; /* ignore subsequent differences */
4116 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
4123 if (builtinloc < 0 && idx_bltin >= 0)
4124 builtinloc = idx_bltin; /* zap builtins */
4125 if (builtinloc >= 0 && idx_bltin < 0)
4127 clearcmdentry(firstchange);
4128 builtinloc = idx_bltin;
4129 #ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
4130 cmdedit_path_lookup = newval;
4136 * Clear out command entries. The argument specifies the first entry in
4137 * PATH which has changed.
4141 clearcmdentry(int firstchange)
4143 struct tblentry **tblp;
4144 struct tblentry **pp;
4145 struct tblentry *cmdp;
4148 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4150 while ((cmdp = *pp) != NULL) {
4151 if ((cmdp->cmdtype == CMDNORMAL &&
4152 cmdp->param.index >= firstchange)
4153 || (cmdp->cmdtype == CMDBUILTIN &&
4154 builtinloc >= firstchange)) {
4168 * Locate a command in the command hash table. If "add" is nonzero,
4169 * add the command to the table if it is not already present. The
4170 * variable "lastcmdentry" is set to point to the address of the link
4171 * pointing to the entry, so that delete_cmd_entry can delete the
4174 * Interrupts must be off if called with add != 0.
4177 static struct tblentry **lastcmdentry;
4180 static struct tblentry *
4181 cmdlookup(const char *name, int add)
4183 unsigned int hashval;
4185 struct tblentry *cmdp;
4186 struct tblentry **pp;
4189 hashval = (unsigned char)*p << 4;
4191 hashval += (unsigned char)*p++;
4193 pp = &cmdtable[hashval % CMDTABLESIZE];
4194 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4195 if (equal(cmdp->cmdname, name))
4199 if (add && cmdp == NULL) {
4200 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4201 + strlen(name) + 1);
4203 cmdp->cmdtype = CMDUNKNOWN;
4204 strcpy(cmdp->cmdname, name);
4211 * Delete the command entry returned on the last lookup.
4215 delete_cmd_entry(void)
4217 struct tblentry *cmdp;
4220 cmdp = *lastcmdentry;
4221 *lastcmdentry = cmdp->next;
4222 if (cmdp->cmdtype == CMDFUNCTION)
4223 freefunc(cmdp->param.func);
4230 * Add a new command entry, replacing any existing command entry for
4231 * the same name - except special builtins.
4235 addcmdentry(char *name, struct cmdentry *entry)
4237 struct tblentry *cmdp;
4239 cmdp = cmdlookup(name, 1);
4240 if (cmdp->cmdtype == CMDFUNCTION) {
4241 freefunc(cmdp->param.func);
4243 cmdp->cmdtype = entry->cmdtype;
4244 cmdp->param = entry->u;
4249 * Make a copy of a parse tree.
4252 static inline struct funcnode *
4253 copyfunc(union node *n)
4258 funcblocksize = offsetof(struct funcnode, n);
4261 blocksize = funcblocksize;
4262 f = ckmalloc(blocksize + funcstringsize);
4263 funcblock = (char *) f + offsetof(struct funcnode, n);
4264 funcstring = (char *) f + blocksize;
4271 * Define a shell function.
4275 defun(char *name, union node *func)
4277 struct cmdentry entry;
4280 entry.cmdtype = CMDFUNCTION;
4281 entry.u.func = copyfunc(func);
4282 addcmdentry(name, &entry);
4288 * Delete a function if it exists.
4292 unsetfunc(const char *name)
4294 struct tblentry *cmdp;
4296 if ((cmdp = cmdlookup(name, 0)) != NULL &&
4297 cmdp->cmdtype == CMDFUNCTION)
4302 * Locate and print what a word is...
4306 #ifdef CONFIG_ASH_CMDCMD
4308 describe_command(char *command, int describe_command_verbose)
4310 #define describe_command_verbose 1
4312 describe_command(char *command)
4315 struct cmdentry entry;
4316 struct tblentry *cmdp;
4317 #ifdef CONFIG_ASH_ALIAS
4318 const struct alias *ap;
4320 const char *path = pathval();
4322 if (describe_command_verbose) {
4326 /* First look at the keywords */
4327 if (findkwd(command)) {
4328 out1str(describe_command_verbose ? " is a shell keyword" : command);
4332 #ifdef CONFIG_ASH_ALIAS
4333 /* Then look at the aliases */
4334 if ((ap = lookupalias(command, 0)) != NULL) {
4335 if (describe_command_verbose) {
4336 out1fmt(" is an alias for %s", ap->val);
4345 /* Then check if it is a tracked alias */
4346 if ((cmdp = cmdlookup(command, 0)) != NULL) {
4347 entry.cmdtype = cmdp->cmdtype;
4348 entry.u = cmdp->param;
4350 /* Finally use brute force */
4351 find_command(command, &entry, DO_ABS, path);
4354 switch (entry.cmdtype) {
4356 int j = entry.u.index;
4362 p = padvance(&path, command);
4366 if (describe_command_verbose) {
4368 (cmdp ? " a tracked alias for" : nullstr), p
4377 if (describe_command_verbose) {
4378 out1str(" is a shell function");
4385 if (describe_command_verbose) {
4386 out1fmt(" is a %sshell builtin",
4387 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
4388 "special " : nullstr
4396 if (describe_command_verbose) {
4397 out1str(": not found\n");
4403 outstr("\n", stdout);
4408 typecmd(int argc, char **argv)
4413 for (i = 1; i < argc; i++) {
4414 #ifdef CONFIG_ASH_CMDCMD
4415 err |= describe_command(argv[i], 1);
4417 err |= describe_command(argv[i]);
4423 #ifdef CONFIG_ASH_CMDCMD
4425 commandcmd(int argc, char **argv)
4428 int default_path = 0;
4429 int verify_only = 0;
4430 int verbose_verify_only = 0;
4432 while ((c = nextopt("pvV")) != '\0')
4437 "command: nextopt returned character code 0%o\n", c);
4447 verbose_verify_only = 1;
4451 if (default_path + verify_only + verbose_verify_only > 1 ||
4454 "command [-p] command [arg ...]\n"
4455 "command {-v|-V} command\n");
4459 if (verify_only || verbose_verify_only) {
4460 return describe_command(*argptr, verbose_verify_only);
4467 /* $NetBSD: expand.c,v 1.56 2002/11/24 22:35:39 christos Exp $ */
4470 * Routines to expand arguments to commands. We have to deal with
4471 * backquotes, shell variables, and file metacharacters.
4477 #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4478 #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
4479 #define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
4480 #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
4481 #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
4484 * Structure specifying which parts of the string should be searched
4485 * for IFS characters.
4489 struct ifsregion *next; /* next region in list */
4490 int begoff; /* offset of start of region */
4491 int endoff; /* offset of end of region */
4492 int nulonly; /* search for nul bytes only */
4495 /* output of current string */
4496 static char *expdest;
4497 /* list of back quote expressions */
4498 static struct nodelist *argbackq;
4499 /* first struct in list of ifs regions */
4500 static struct ifsregion ifsfirst;
4501 /* last struct in list */
4502 static struct ifsregion *ifslastp;
4503 /* holds expanded arg list */
4504 static struct arglist exparg;
4506 static void argstr(char *, int);
4507 static char *exptilde(char *, char *, int);
4508 static void expbackq(union node *, int, int);
4509 static const char *subevalvar(char *, char *, int, int, int, int, int);
4510 static char *evalvar(char *, int);
4511 static void strtodest(const char *, int, int);
4512 static void memtodest(const char *p, size_t len, int syntax, int quotes);
4513 static ssize_t varvalue(char *, int, int);
4514 static void recordregion(int, int, int);
4515 static void removerecordregions(int);
4516 static void ifsbreakup(char *, struct arglist *);
4517 static void ifsfree(void);
4518 static void expandmeta(struct strlist *, int);
4519 static int patmatch(char *, const char *);
4521 static int cvtnum(long);
4522 static size_t esclen(const char *, const char *);
4523 static char *scanleft(char *, char *, char *, char *, int, int);
4524 static char *scanright(char *, char *, char *, char *, int, int);
4525 static void varunset(const char *, const char *, const char *, int)
4526 __attribute__((__noreturn__));
4529 #define pmatch(a, b) !fnmatch((a), (b), 0)
4531 * Prepare a pattern for a expmeta (internal glob(3)) call.
4533 * Returns an stalloced string.
4536 static inline char *
4537 preglob(const char *pattern, int quoted, int flag) {
4538 flag |= RMESCAPE_GLOB;
4540 flag |= RMESCAPE_QUOTED;
4542 return _rmescapes((char *)pattern, flag);
4547 esclen(const char *start, const char *p) {
4550 while (p > start && *--p == CTLESC) {
4558 * Expand shell variables and backquotes inside a here document.
4562 expandhere(union node *arg, int fd)
4565 expandarg(arg, (struct arglist *)NULL, 0);
4566 xwrite(fd, stackblock(), expdest - (char *)stackblock());
4571 * Perform variable substitution and command substitution on an argument,
4572 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4573 * perform splitting and file name expansion. When arglist is NULL, perform
4574 * here document expansion.
4578 expandarg(union node *arg, struct arglist *arglist, int flag)
4583 argbackq = arg->narg.backquote;
4584 STARTSTACKSTR(expdest);
4585 ifsfirst.next = NULL;
4587 argstr(arg->narg.text, flag);
4588 if (arglist == NULL) {
4589 return; /* here document expanded */
4591 STPUTC('\0', expdest);
4592 p = grabstackstr(expdest);
4593 exparg.lastp = &exparg.list;
4597 if (flag & EXP_FULL) {
4598 ifsbreakup(p, &exparg);
4599 *exparg.lastp = NULL;
4600 exparg.lastp = &exparg.list;
4601 expandmeta(exparg.list, flag);
4603 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
4605 sp = (struct strlist *)stalloc(sizeof (struct strlist));
4608 exparg.lastp = &sp->next;
4612 *exparg.lastp = NULL;
4614 *arglist->lastp = exparg.list;
4615 arglist->lastp = exparg.lastp;
4621 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4622 * characters to allow for further processing. Otherwise treat
4623 * $@ like $* since no splitting will be performed.
4627 argstr(char *p, int flag)
4629 static const char spclchars[] = {
4637 CTLBACKQ | CTLQUOTE,
4638 #ifdef CONFIG_ASH_MATH_SUPPORT
4643 const char *reject = spclchars;
4645 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
4646 int breakall = flag & EXP_WORD;
4651 if (!(flag & EXP_VARTILDE)) {
4653 } else if (flag & EXP_VARTILDE2) {
4658 if (flag & EXP_TILDE) {
4664 if (*q == CTLESC && (flag & EXP_QWORD))
4667 p = exptilde(p, q, flag);
4670 startloc = expdest - (char *)stackblock();
4672 length += strcspn(p + length, reject);
4674 if (c && (!(c & 0x80)
4675 #ifdef CONFIG_ASH_MATH_SUPPORT
4679 /* c == '=' || c == ':' || c == CTLENDARI */
4684 expdest = stnputs(p, length, expdest);
4685 newloc = expdest - (char *)stackblock();
4686 if (breakall && !inquotes && newloc > startloc) {
4687 recordregion(startloc, newloc, 0);
4698 if (flag & EXP_VARTILDE2) {
4702 flag |= EXP_VARTILDE2;
4707 * sort of a hack - expand tildes in variable
4708 * assignments (after the first '=' and after ':'s).
4717 case CTLENDVAR: /* ??? */
4720 /* "$@" syntax adherence hack */
4723 !memcmp(p, dolatstr, DOLATSTRLEN) &&
4724 (p[4] == CTLQUOTEMARK || (
4725 p[4] == CTLENDVAR &&
4726 p[5] == CTLQUOTEMARK
4729 p = evalvar(p + 1, flag) + 1;
4732 inquotes = !inquotes;
4745 p = evalvar(p, flag);
4749 case CTLBACKQ|CTLQUOTE:
4750 expbackq(argbackq->n, c, quotes);
4751 argbackq = argbackq->next;
4753 #ifdef CONFIG_ASH_MATH_SUPPORT
4766 exptilde(char *startp, char *p, int flag)
4772 int quotes = flag & (EXP_FULL | EXP_CASE);
4777 while ((c = *++p) != '\0') {
4784 if (flag & EXP_VARTILDE)
4794 if (*name == '\0') {
4795 if ((home = lookupvar(homestr)) == NULL)
4798 if ((pw = getpwnam(name)) == NULL)
4805 startloc = expdest - (char *)stackblock();
4806 strtodest(home, SQSYNTAX, quotes);
4807 recordregion(startloc, expdest - (char *)stackblock(), 0);
4816 removerecordregions(int endoff)
4818 if (ifslastp == NULL)
4821 if (ifsfirst.endoff > endoff) {
4822 while (ifsfirst.next != NULL) {
4823 struct ifsregion *ifsp;
4825 ifsp = ifsfirst.next->next;
4826 ckfree(ifsfirst.next);
4827 ifsfirst.next = ifsp;
4830 if (ifsfirst.begoff > endoff)
4833 ifslastp = &ifsfirst;
4834 ifsfirst.endoff = endoff;
4839 ifslastp = &ifsfirst;
4840 while (ifslastp->next && ifslastp->next->begoff < endoff)
4841 ifslastp=ifslastp->next;
4842 while (ifslastp->next != NULL) {
4843 struct ifsregion *ifsp;
4845 ifsp = ifslastp->next->next;
4846 ckfree(ifslastp->next);
4847 ifslastp->next = ifsp;
4850 if (ifslastp->endoff > endoff)
4851 ifslastp->endoff = endoff;
4855 #ifdef CONFIG_ASH_MATH_SUPPORT
4857 * Expand arithmetic expression. Backup to start of expression,
4858 * evaluate, place result in (backed up) result, adjust string position.
4871 * This routine is slightly over-complicated for
4872 * efficiency. Next we scan backwards looking for the
4873 * start of arithmetic.
4875 start = stackblock();
4882 while (*p != CTLARI) {
4886 error("missing CTLARI (shouldn't happen)");
4891 esc = esclen(start, p);
4901 removerecordregions(begoff);
4910 len = cvtnum(dash_arith(p + 2));
4913 recordregion(begoff, begoff + len, 0);
4918 * Expand stuff in backwards quotes.
4922 expbackq(union node *cmd, int quoted, int quotes)
4930 int syntax = quoted? DQSYNTAX : BASESYNTAX;
4931 struct stackmark smark;
4934 setstackmark(&smark);
4936 startloc = dest - (char *)stackblock();
4938 evalbackcmd(cmd, (struct backcmd *) &in);
4939 popstackmark(&smark);
4946 memtodest(p, i, syntax, quotes);
4950 i = safe_read(in.fd, buf, sizeof buf);
4951 TRACE(("expbackq: read returns %d\n", i));
4961 back_exitstatus = waitforjob(in.jp);
4965 /* Eat all trailing newlines */
4967 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
4972 recordregion(startloc, dest - (char *)stackblock(), 0);
4973 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4974 (dest - (char *)stackblock()) - startloc,
4975 (dest - (char *)stackblock()) - startloc,
4976 stackblock() + startloc));
4981 scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
4992 const char *s = loc2;
4998 match = pmatch(str, s);
5002 if (quotes && *loc == CTLESC)
5012 scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5019 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5022 const char *s = loc2;
5027 match = pmatch(str, s);
5034 esc = esclen(startp, loc);
5046 subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
5050 int saveherefd = herefd;
5051 struct nodelist *saveargbackq = argbackq;
5053 char *rmesc, *rmescend;
5055 char *(*scan)(char *, char *, char *, char *, int , int);
5058 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
5059 STPUTC('\0', expdest);
5060 herefd = saveherefd;
5061 argbackq = saveargbackq;
5062 startp = stackblock() + startloc;
5066 setvar(str, startp, 0);
5067 amount = startp - expdest;
5068 STADJUST(amount, expdest);
5072 varunset(p, str, startp, varflags);
5076 subtype -= VSTRIMRIGHT;
5078 if (subtype < 0 || subtype > 3)
5083 rmescend = stackblock() + strloc;
5085 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5086 if (rmesc != startp) {
5088 startp = stackblock() + startloc;
5092 str = stackblock() + strloc;
5093 preglob(str, varflags & VSQUOTE, 0);
5095 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
5096 zero = subtype >> 1;
5097 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
5098 scan = (subtype & 1) ^ zero ? scanleft : scanright;
5100 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
5103 memmove(startp, loc, str - loc);
5104 loc = startp + (str - loc) - 1;
5107 amount = loc - expdest;
5108 STADJUST(amount, expdest);
5115 * Expand a variable, and return a pointer to the next character in the
5119 evalvar(char *p, int flag)
5132 quotes = flag & (EXP_FULL | EXP_CASE);
5134 subtype = varflags & VSTYPE;
5135 quoted = varflags & VSQUOTE;
5137 easy = (!quoted || (*var == '@' && shellparam.nparam));
5138 startloc = expdest - (char *)stackblock();
5139 p = strchr(p, '=') + 1;
5142 varlen = varvalue(var, varflags, flag);
5143 if (varflags & VSNUL)
5146 if (subtype == VSPLUS) {
5147 varlen = -1 - varlen;
5151 if (subtype == VSMINUS) {
5155 p, flag | EXP_TILDE |
5156 (quoted ? EXP_QWORD : EXP_WORD)
5165 if (subtype == VSASSIGN || subtype == VSQUESTION) {
5167 if (subevalvar(p, var, 0, subtype, startloc,
5171 * Remove any recorded regions beyond
5174 removerecordregions(startloc);
5184 if (varlen < 0 && uflag)
5185 varunset(p, var, 0, 0);
5187 if (subtype == VSLENGTH) {
5188 cvtnum(varlen > 0 ? varlen : 0);
5192 if (subtype == VSNORMAL) {
5196 recordregion(startloc, expdest - (char *)stackblock(), quoted);
5205 case VSTRIMRIGHTMAX:
5214 * Terminate the string and start recording the pattern
5217 STPUTC('\0', expdest);
5218 patloc = expdest - (char *)stackblock();
5219 if (subevalvar(p, NULL, patloc, subtype,
5220 startloc, varflags, quotes) == 0) {
5221 int amount = expdest - (
5222 (char *)stackblock() + patloc - 1
5224 STADJUST(-amount, expdest);
5226 /* Remove any recorded regions beyond start of variable */
5227 removerecordregions(startloc);
5232 if (subtype != VSNORMAL) { /* skip to end of alternative */
5235 if ((c = *p++) == CTLESC)
5237 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
5239 argbackq = argbackq->next;
5240 } else if (c == CTLVAR) {
5241 if ((*p++ & VSTYPE) != VSNORMAL)
5243 } else if (c == CTLENDVAR) {
5254 * Put a string on the stack.
5258 memtodest(const char *p, size_t len, int syntax, int quotes) {
5261 q = makestrspace(len * 2, q);
5267 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5277 strtodest(const char *p, int syntax, int quotes)
5279 memtodest(p, strlen(p), syntax, quotes);
5284 * Add the value of a specialized variable to the stack string.
5288 varvalue(char *name, int varflags, int flags)
5298 int quoted = varflags & VSQUOTE;
5299 int subtype = varflags & VSTYPE;
5300 int quotes = flags & (EXP_FULL | EXP_CASE);
5302 if (quoted && (flags & EXP_FULL))
5303 sep = 1 << CHAR_BIT;
5305 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5314 num = shellparam.nparam;
5324 p = makestrspace(NOPTS, expdest);
5325 for (i = NOPTS - 1; i >= 0; i--) {
5327 USTPUTC(optletters(i), p);
5338 sep = ifsset() ? ifsval()[0] : ' ';
5339 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
5342 if (!(ap = shellparam.p))
5344 while ((p = *ap++)) {
5347 partlen = strlen(p);
5350 if (len > partlen && sep) {
5354 if (subtype == VSPLUS || subtype == VSLENGTH) {
5364 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5365 memtodest(p, partlen, syntax, quotes);
5379 if (num < 0 || num > shellparam.nparam)
5381 p = num ? shellparam.p[num - 1] : arg0;
5384 p = lookupvar(name);
5390 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5391 memtodest(p, len, syntax, quotes);
5395 if (subtype == VSPLUS || subtype == VSLENGTH)
5396 STADJUST(-len, expdest);
5402 * Record the fact that we have to scan this region of the
5403 * string for IFS characters.
5407 recordregion(int start, int end, int nulonly)
5409 struct ifsregion *ifsp;
5411 if (ifslastp == NULL) {
5415 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
5417 ifslastp->next = ifsp;
5421 ifslastp->begoff = start;
5422 ifslastp->endoff = end;
5423 ifslastp->nulonly = nulonly;
5428 * Break the argument string into pieces based upon IFS and add the
5429 * strings to the argument list. The regions of the string to be
5430 * searched for IFS characters have been stored by recordregion.
5433 ifsbreakup(char *string, struct arglist *arglist)
5435 struct ifsregion *ifsp;
5440 const char *ifs, *realifs;
5446 if (ifslastp != NULL) {
5449 realifs = ifsset() ? ifsval() : defifs;
5452 p = string + ifsp->begoff;
5453 nulonly = ifsp->nulonly;
5454 ifs = nulonly ? nullstr : realifs;
5456 while (p < string + ifsp->endoff) {
5460 if (strchr(ifs, *p)) {
5462 ifsspc = (strchr(defifs, *p) != NULL);
5463 /* Ignore IFS whitespace at start */
5464 if (q == start && ifsspc) {
5470 sp = (struct strlist *)stalloc(sizeof *sp);
5472 *arglist->lastp = sp;
5473 arglist->lastp = &sp->next;
5477 if (p >= string + ifsp->endoff) {
5483 if (strchr(ifs, *p) == NULL ) {
5486 } else if (strchr(defifs, *p) == NULL) {
5502 } while ((ifsp = ifsp->next) != NULL);
5511 sp = (struct strlist *)stalloc(sizeof *sp);
5513 *arglist->lastp = sp;
5514 arglist->lastp = &sp->next;
5520 struct ifsregion *p;
5525 struct ifsregion *ifsp;
5531 ifsfirst.next = NULL;
5535 static void expmeta(char *, char *);
5536 static struct strlist *expsort(struct strlist *);
5537 static struct strlist *msort(struct strlist *, int);
5539 static char *expdir;
5543 expandmeta(struct strlist *str, int flag)
5545 static const char metachars[] = {
5548 /* TODO - EXP_REDIR */
5551 struct strlist **savelastp;
5557 if (!strpbrk(str->text, metachars))
5559 savelastp = exparg.lastp;
5562 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
5564 int i = strlen(str->text);
5565 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5573 if (exparg.lastp == savelastp) {
5578 *exparg.lastp = str;
5579 rmescapes(str->text);
5580 exparg.lastp = &str->next;
5582 *exparg.lastp = NULL;
5583 *savelastp = sp = expsort(*savelastp);
5584 while (sp->next != NULL)
5586 exparg.lastp = &sp->next;
5593 * Add a file name to the list.
5597 addfname(const char *name)
5601 sp = (struct strlist *)stalloc(sizeof *sp);
5602 sp->text = sstrdup(name);
5604 exparg.lastp = &sp->next;
5609 * Do metacharacter (i.e. *, ?, [...]) expansion.
5613 expmeta(char *enddir, char *name)
5628 for (p = name; *p; p++) {
5629 if (*p == '*' || *p == '?')
5631 else if (*p == '[') {
5638 if (*q == '/' || *q == '\0')
5645 } else if (*p == '\\')
5647 else if (*p == '/') {
5654 if (metaflag == 0) { /* we've reached the end of the file name */
5655 if (enddir != expdir)
5663 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
5674 } while (p < start);
5676 if (enddir == expdir) {
5678 } else if (enddir == expdir + 1 && *expdir == '/') {
5684 if ((dirp = opendir(cp)) == NULL)
5686 if (enddir != expdir)
5688 if (*endname == 0) {
5700 while (! intpending && (dp = readdir(dirp)) != NULL) {
5701 if (dp->d_name[0] == '.' && ! matchdot)
5703 if (pmatch(start, dp->d_name)) {
5705 scopy(dp->d_name, enddir);
5708 for (p = enddir, cp = dp->d_name;
5709 (*p++ = *cp++) != '\0';)
5712 expmeta(p, endname);
5722 * Sort the results of file name expansion. It calculates the number of
5723 * strings to sort and then calls msort (short for merge sort) to do the
5727 static struct strlist *
5728 expsort(struct strlist *str)
5734 for (sp = str ; sp ; sp = sp->next)
5736 return msort(str, len);
5740 static struct strlist *
5741 msort(struct strlist *list, int len)
5743 struct strlist *p, *q = NULL;
5744 struct strlist **lpp;
5752 for (n = half ; --n >= 0 ; ) {
5756 q->next = NULL; /* terminate first half of list */
5757 q = msort(list, half); /* sort first half of list */
5758 p = msort(p, len - half); /* sort second half */
5761 #ifdef CONFIG_LOCALE_SUPPORT
5762 if (strcoll(p->text, q->text) < 0)
5764 if (strcmp(p->text, q->text) < 0)
5769 if ((p = *lpp) == NULL) {
5776 if ((q = *lpp) == NULL) {
5787 * Returns true if the pattern matches the string.
5791 patmatch(char *pattern, const char *string)
5793 return pmatch(preglob(pattern, 0, 0), string);
5798 * Remove any CTLESC characters from a string.
5802 _rmescapes(char *str, int flag)
5805 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
5810 p = strpbrk(str, qchars);
5816 if (flag & RMESCAPE_ALLOC) {
5817 size_t len = p - str;
5818 size_t fulllen = len + strlen(p) + 1;
5820 if (flag & RMESCAPE_GROW) {
5821 r = makestrspace(fulllen, expdest);
5822 } else if (flag & RMESCAPE_HEAP) {
5823 r = ckmalloc(fulllen);
5825 r = stalloc(fulllen);
5829 q = mempcpy(q, str, len);
5832 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5833 globbing = flag & RMESCAPE_GLOB;
5834 notescaped = globbing;
5836 if (*p == CTLQUOTEMARK) {
5837 inquotes = ~inquotes;
5839 notescaped = globbing;
5843 /* naked back slash */
5849 if (notescaped && inquotes && *p != '/') {
5853 notescaped = globbing;
5858 if (flag & RMESCAPE_GROW) {
5860 STADJUST(q - r + 1, expdest);
5867 * See if a pattern matches in a case statement.
5871 casematch(union node *pattern, char *val)
5873 struct stackmark smark;
5876 setstackmark(&smark);
5877 argbackq = pattern->narg.backquote;
5878 STARTSTACKSTR(expdest);
5880 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
5881 STACKSTRNUL(expdest);
5882 result = patmatch(stackblock(), val);
5883 popstackmark(&smark);
5896 expdest = makestrspace(32, expdest);
5897 len = fmtstr(expdest, 32, "%ld", num);
5898 STADJUST(len, expdest);
5903 varunset(const char *end, const char *var, const char *umsg, int varflags)
5909 msg = "parameter not set";
5911 if (*end == CTLENDVAR) {
5912 if (varflags & VSNUL)
5917 error("%.*s: %s%s", end - var - 1, var, msg, tail);
5921 /* $NetBSD: input.c,v 1.37 2002/11/24 22:35:40 christos Exp $ */
5924 * This implements the input routines used by the parser.
5927 #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
5928 #define IBUFSIZ (BUFSIZ + 1)
5930 static void pushfile(void);
5933 * Read a line from the script.
5936 static inline char *
5937 pfgets(char *line, int len)
5943 while (--nleft > 0) {
5960 * Read a character from the script, returning PEOF on end of file.
5961 * Nul characters in the input are silently discarded.
5964 #define pgetc_as_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
5966 #ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
5967 #define pgetc_macro() pgetc()
5971 return pgetc_as_macro();
5974 #define pgetc_macro() pgetc_as_macro()
5978 return pgetc_macro();
5984 * Same as pgetc(), but ignores PEOA.
5986 #ifdef CONFIG_ASH_ALIAS
5987 static int pgetc2(void)
5993 } while (c == PEOA);
5997 static inline int pgetc2(void)
5999 return pgetc_macro();
6004 #ifdef CONFIG_FEATURE_COMMAND_EDITING
6005 static const char *cmdedit_prompt;
6006 static inline void putprompt(const char *s)
6011 static inline void putprompt(const char *s)
6021 char *buf = parsefile->buf;
6025 #ifdef CONFIG_FEATURE_COMMAND_EDITING
6026 if (!iflag || parsefile->fd)
6027 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6029 nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
6031 /* Ctrl+C presend */
6041 /* Ctrl+D presend */
6046 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6050 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6051 int flags = fcntl(0, F_GETFL, 0);
6052 if (flags >= 0 && flags & O_NONBLOCK) {
6053 flags &=~ O_NONBLOCK;
6054 if (fcntl(0, F_SETFL, flags) >= 0) {
6055 out2str("sh: turning off NDELAY mode\n");
6065 * Refill the input buffer and return the next input character:
6067 * 1) If a string was pushed back on the input, pop it;
6068 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6069 * from a string so we can't refill the buffer, return EOF.
6070 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6071 * 4) Process input up to the next newline, deleting nul characters.
6081 while (parsefile->strpush) {
6082 #ifdef CONFIG_ASH_ALIAS
6083 if (parsenleft == -1 && parsefile->strpush->ap &&
6084 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
6089 if (--parsenleft >= 0)
6090 return (*parsenextc++);
6092 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6097 if (parselleft <= 0) {
6098 if ((parselleft = preadfd()) <= 0) {
6099 parselleft = parsenleft = EOF_NLEFT;
6106 /* delete nul characters */
6107 for (more = 1; more;) {
6114 parsenleft = q - parsenextc;
6115 more = 0; /* Stop processing here */
6122 if (--parselleft <= 0 && more) {
6123 parsenleft = q - parsenextc - 1;
6134 out2str(parsenextc);
6139 return *parsenextc++;
6143 * Undo the last call to pgetc. Only one character may be pushed back.
6144 * PEOF may be pushed back.
6155 * Push a string back onto the input at this current parsefile level.
6156 * We handle aliases this way.
6159 pushstring(char *s, void *ap)
6166 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6167 if (parsefile->strpush) {
6168 sp = ckmalloc(sizeof (struct strpush));
6169 sp->prev = parsefile->strpush;
6170 parsefile->strpush = sp;
6172 sp = parsefile->strpush = &(parsefile->basestrpush);
6173 sp->prevstring = parsenextc;
6174 sp->prevnleft = parsenleft;
6175 #ifdef CONFIG_ASH_ALIAS
6176 sp->ap = (struct alias *)ap;
6178 ((struct alias *)ap)->flag |= ALIASINUSE;
6190 struct strpush *sp = parsefile->strpush;
6193 #ifdef CONFIG_ASH_ALIAS
6195 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6196 checkkwd |= CHKALIAS;
6198 if (sp->string != sp->ap->val) {
6201 sp->ap->flag &= ~ALIASINUSE;
6202 if (sp->ap->flag & ALIASDEAD) {
6203 unalias(sp->ap->name);
6207 parsenextc = sp->prevstring;
6208 parsenleft = sp->prevnleft;
6209 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6210 parsefile->strpush = sp->prev;
6211 if (sp != &(parsefile->basestrpush))
6217 * Set the input to take input from a file. If push is set, push the
6218 * old input onto the stack first.
6222 setinputfile(const char *fname, int push)
6228 if ((fd = open(fname, O_RDONLY)) < 0)
6229 error("Can't open %s", fname);
6231 fd2 = copyfd(fd, 10);
6234 error("Out of file descriptors");
6237 setinputfd(fd, push);
6243 * Like setinputfile, but takes an open file descriptor. Call this with
6248 setinputfd(int fd, int push)
6250 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
6256 if (parsefile->buf == NULL)
6257 parsefile->buf = ckmalloc(IBUFSIZ);
6258 parselleft = parsenleft = 0;
6264 * Like setinputfile, but takes input from a string.
6268 setinputstring(char *string)
6272 parsenextc = string;
6273 parsenleft = strlen(string);
6274 parsefile->buf = NULL;
6281 * To handle the "." command, a stack of input files is used. Pushfile
6282 * adds a new entry to the stack and popfile restores the previous level.
6288 struct parsefile *pf;
6290 parsefile->nleft = parsenleft;
6291 parsefile->lleft = parselleft;
6292 parsefile->nextc = parsenextc;
6293 parsefile->linno = plinno;
6294 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
6295 pf->prev = parsefile;
6298 pf->basestrpush.prev = NULL;
6306 struct parsefile *pf = parsefile;
6315 parsefile = pf->prev;
6317 parsenleft = parsefile->nleft;
6318 parselleft = parsefile->lleft;
6319 parsenextc = parsefile->nextc;
6320 plinno = parsefile->linno;
6326 * Return to top level.
6332 while (parsefile != &basepf)
6338 * Close the file(s) that the shell is reading commands from. Called
6339 * after a fork is done.
6346 if (parsefile->fd > 0) {
6347 close(parsefile->fd);
6352 /* $NetBSD: jobs.c,v 1.56 2002/11/25 12:13:03 agc Exp $ */
6354 /* mode flags for set_curjob */
6355 #define CUR_DELETE 2
6356 #define CUR_RUNNING 1
6357 #define CUR_STOPPED 0
6359 /* mode flags for dowait */
6360 #define DOWAIT_NORMAL 0
6361 #define DOWAIT_BLOCK 1
6364 static struct job *jobtab;
6366 static unsigned njobs;
6368 /* pgrp of shell on invocation */
6369 static int initialpgrp;
6370 static int ttyfd = -1;
6373 static struct job *curjob;
6374 /* number of presumed living untracked jobs */
6377 static void set_curjob(struct job *, unsigned);
6379 static int restartjob(struct job *, int);
6380 static void xtcsetpgrp(int, pid_t);
6381 static char *commandtext(union node *);
6382 static void cmdlist(union node *, int);
6383 static void cmdtxt(union node *);
6384 static void cmdputs(const char *);
6385 static void showpipe(struct job *, FILE *);
6387 static int sprint_status(char *, int, int);
6388 static void freejob(struct job *);
6389 static struct job *getjob(const char *, int);
6390 static struct job *growjobtab(void);
6391 static void forkchild(struct job *, union node *, int);
6392 static void forkparent(struct job *, union node *, int, pid_t);
6393 static int dowait(int, struct job *);
6394 static int getstatus(struct job *);
6397 set_curjob(struct job *jp, unsigned mode)
6400 struct job **jpp, **curp;
6402 /* first remove from list */
6403 jpp = curp = &curjob;
6408 jpp = &jp1->prev_job;
6410 *jpp = jp1->prev_job;
6412 /* Then re-insert in correct position */
6420 /* job being deleted */
6423 /* newly created job or backgrounded job,
6424 put after all stopped jobs. */
6428 if (!jp1 || jp1->state != JOBSTOPPED)
6431 jpp = &jp1->prev_job;
6437 /* newly stopped job - becomes curjob */
6438 jp->prev_job = *jpp;
6446 * Turn job control on and off.
6448 * Note: This code assumes that the third arg to ioctl is a character
6449 * pointer, which is true on Berkeley systems but not System V. Since
6450 * System V doesn't have job control yet, this isn't a problem now.
6452 * Called with interrupts off.
6461 if (on == jobctl || rootshell == 0)
6465 ofd = fd = open(_PATH_TTY, O_RDWR);
6468 while (!isatty(fd) && --fd >= 0)
6471 fd = fcntl(fd, F_DUPFD, 10);
6475 fcntl(fd, F_SETFD, FD_CLOEXEC);
6476 do { /* while we are in the background */
6477 if ((pgrp = tcgetpgrp(fd)) < 0) {
6479 sh_warnx("can't access tty; job control turned off");
6483 if (pgrp == getpgrp())
6494 xtcsetpgrp(fd, pgrp);
6496 /* turning job control off */
6499 xtcsetpgrp(fd, pgrp);
6513 killcmd(int argc, char **argv)
6524 "Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6525 "kill -l [exitstatus]"
6529 if (**++argv == '-') {
6530 signo = decode_signal(*argv + 1, 1);
6534 while ((c = nextopt("ls:")) != '\0')
6544 signo = decode_signal(optionarg, 1);
6547 "invalid signal number or name: %s",
6558 if (!list && signo < 0)
6561 if ((signo < 0 || !*argv) ^ list) {
6569 for (i = 1; i < NSIG; i++) {
6570 name = u_signal_names(0, &i, 1);
6572 out1fmt(snlfmt, name);
6576 name = u_signal_names(*argptr, &signo, -1);
6578 out1fmt(snlfmt, name);
6580 error("invalid signal number or exit status: %s", *argptr);
6586 if (**argv == '%') {
6587 jp = getjob(*argv, 0);
6588 pid = -jp->ps[0].pid;
6590 pid = number(*argv);
6591 if (kill(pid, signo) != 0) {
6601 #if defined(JOBS) || defined(DEBUG)
6603 jobno(const struct job *jp)
6605 return jp - jobtab + 1;
6611 fgcmd(int argc, char **argv)
6618 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
6623 jp = getjob(*argv, 1);
6624 if (mode == FORK_BG) {
6625 set_curjob(jp, CUR_RUNNING);
6626 fprintf(out, "[%d] ", jobno(jp));
6628 outstr(jp->ps->cmd, out);
6630 retval = restartjob(jp, mode);
6631 } while (*argv && *++argv);
6635 static int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
6639 restartjob(struct job *jp, int mode)
6641 struct procstat *ps;
6647 if (jp->state == JOBDONE)
6649 jp->state = JOBRUNNING;
6651 if (mode == FORK_FG)
6652 xtcsetpgrp(ttyfd, pgid);
6653 killpg(pgid, SIGCONT);
6657 if (WIFSTOPPED(ps->status)) {
6660 } while (ps++, --i);
6662 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
6669 sprint_status(char *s, int status, int sigonly)
6675 if (!WIFEXITED(status)) {
6677 if (WIFSTOPPED(status))
6678 st = WSTOPSIG(status);
6681 st = WTERMSIG(status);
6683 if (st == SIGINT || st == SIGPIPE)
6686 if (WIFSTOPPED(status))
6691 col = fmtstr(s, 32, strsignal(st));
6692 if (WCOREDUMP(status)) {
6693 col += fmtstr(s + col, 16, " (core dumped)");
6695 } else if (!sigonly) {
6696 st = WEXITSTATUS(status);
6698 col = fmtstr(s, 16, "Done(%d)", st);
6700 col = fmtstr(s, 16, "Done");
6709 showjob(FILE *out, struct job *jp, int mode)
6711 struct procstat *ps;
6712 struct procstat *psend;
6719 if (mode & SHOW_PGID) {
6720 /* just output process (group) id of pipeline */
6721 fprintf(out, "%d\n", ps->pid);
6725 col = fmtstr(s, 16, "[%d] ", jobno(jp));
6730 else if (curjob && jp == curjob->prev_job)
6733 if (mode & SHOW_PID)
6734 col += fmtstr(s + col, 16, "%d ", ps->pid);
6736 psend = ps + jp->nprocs;
6738 if (jp->state == JOBRUNNING) {
6739 scopy("Running", s + col);
6740 col += strlen("Running");
6742 int status = psend[-1].status;
6744 if (jp->state == JOBSTOPPED)
6745 status = jp->stopstatus;
6747 col += sprint_status(s + col, status, 0);
6753 /* for each process */
6754 col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
6757 fprintf(out, "%s%*c%s",
6758 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
6760 if (!(mode & SHOW_PID)) {
6764 if (++ps == psend) {
6765 outcslow('\n', out);
6772 if (jp->state == JOBDONE) {
6773 TRACE(("showjob: freeing job %d\n", jobno(jp)));
6780 jobscmd(int argc, char **argv)
6786 while ((m = nextopt("lp")))
6796 showjob(out, getjob(*argv,0), mode);
6799 showjobs(out, mode);
6806 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6807 * statuses have changed since the last call to showjobs.
6811 showjobs(FILE *out, int mode)
6815 TRACE(("showjobs(%x) called\n", mode));
6817 /* If not even one one job changed, there is nothing to do */
6818 while (dowait(DOWAIT_NORMAL, NULL) > 0)
6821 for (jp = curjob; jp; jp = jp->prev_job) {
6822 if (!(mode & SHOW_CHANGED) || jp->changed)
6823 showjob(out, jp, mode);
6829 * Mark a job structure as unused.
6833 freejob(struct job *jp)
6835 struct procstat *ps;
6839 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
6840 if (ps->cmd != nullstr)
6843 if (jp->ps != &jp->ps0)
6846 set_curjob(jp, CUR_DELETE);
6852 waitcmd(int argc, char **argv)
6865 /* wait for all jobs */
6870 /* no running procs */
6873 if (jp->state == JOBRUNNING)
6878 dowait(DOWAIT_BLOCK, 0);
6884 if (**argv != '%') {
6885 pid_t pid = number(*argv);
6889 if (job->ps[job->nprocs - 1].pid == pid)
6891 job = job->prev_job;
6897 job = getjob(*argv, 0);
6898 /* loop until process terminated or stopped */
6899 while (job->state == JOBRUNNING)
6900 dowait(DOWAIT_BLOCK, 0);
6902 retval = getstatus(job);
6913 * Convert a job name to a job structure.
6917 getjob(const char *name, int getctl)
6921 const char *err_msg = "No such job: %s";
6925 char *(*match)(const char *, const char *);
6940 if (c == '+' || c == '%') {
6942 err_msg = "No current job";
6944 } else if (c == '-') {
6947 err_msg = "No previous job";
6958 jp = jobtab + num - 1;
6975 if (match(jp->ps[0].cmd, p)) {
6979 err_msg = "%s: ambiguous";
6986 err_msg = "job %s not created under job control";
6987 if (getctl && jp->jobctl == 0)
6992 error(err_msg, name);
6997 * Return a new job structure.
6998 * Called with interrupts off.
7002 makejob(union node *node, int nprocs)
7007 for (i = njobs, jp = jobtab ; ; jp++) {
7014 if (jp->state != JOBDONE || !jp->waited)
7023 memset(jp, 0, sizeof(*jp));
7028 jp->prev_job = curjob;
7033 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
7035 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
7045 struct job *jp, *jq;
7047 len = njobs * sizeof(*jp);
7049 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
7051 offset = (char *)jp - (char *)jq;
7053 /* Relocate pointers */
7056 jq = (struct job *)((char *)jq + l);
7060 #define joff(p) ((struct job *)((char *)(p) + l))
7061 #define jmove(p) (p) = (void *)((char *)(p) + offset)
7062 if (likely(joff(jp)->ps == &jq->ps0))
7063 jmove(joff(jp)->ps);
7064 if (joff(jp)->prev_job)
7065 jmove(joff(jp)->prev_job);
7075 jp = (struct job *)((char *)jp + len);
7079 } while (--jq >= jp);
7085 * Fork off a subshell. If we are doing job control, give the subshell its
7086 * own process group. Jp is a job structure that the job is to be added to.
7087 * N is the command that will be evaluated by the child. Both jp and n may
7088 * be NULL. The mode parameter can be one of the following:
7089 * FORK_FG - Fork off a foreground process.
7090 * FORK_BG - Fork off a background process.
7091 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
7092 * process group even if job control is on.
7094 * When job control is turned off, background processes have their standard
7095 * input redirected to /dev/null (except for the second and later processes
7098 * Called with interrupts off.
7102 forkchild(struct job *jp, union node *n, int mode)
7106 TRACE(("Child shell %d\n", getpid()));
7107 wasroot = rootshell;
7113 /* do job control only in root shell */
7115 if (mode != FORK_NOJOB && jp->jobctl && wasroot) {
7118 if (jp->nprocs == 0)
7121 pgrp = jp->ps[0].pid;
7122 /* This can fail because we are doing it in the parent also */
7123 (void)setpgid(0, pgrp);
7124 if (mode == FORK_FG)
7125 xtcsetpgrp(ttyfd, pgrp);
7130 if (mode == FORK_BG) {
7133 if (jp->nprocs == 0) {
7135 if (open(_PATH_DEVNULL, O_RDONLY) != 0)
7136 error("Can't open %s", _PATH_DEVNULL);
7139 if (wasroot && iflag) {
7144 for (jp = curjob; jp; jp = jp->prev_job)
7150 forkparent(struct job *jp, union node *n, int mode, pid_t pid)
7152 TRACE(("In parent shell: child = %d\n", pid));
7154 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
7159 if (mode != FORK_NOJOB && jp->jobctl) {
7162 if (jp->nprocs == 0)
7165 pgrp = jp->ps[0].pid;
7166 /* This can fail because we are doing it in the child also */
7167 (void)setpgid(pid, pgrp);
7170 if (mode == FORK_BG) {
7171 backgndpid = pid; /* set $! */
7172 set_curjob(jp, CUR_RUNNING);
7175 struct procstat *ps = &jp->ps[jp->nprocs++];
7181 ps->cmd = commandtext(n);
7187 forkshell(struct job *jp, union node *n, int mode)
7191 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
7194 TRACE(("Fork failed, errno=%d", errno));
7197 error("Cannot fork");
7200 forkchild(jp, n, mode);
7202 forkparent(jp, n, mode, pid);
7207 * Wait for job to finish.
7209 * Under job control we have the problem that while a child process is
7210 * running interrupts generated by the user are sent to the child but not
7211 * to the shell. This means that an infinite loop started by an inter-
7212 * active user may be hard to kill. With job control turned off, an
7213 * interactive user may place an interactive program inside a loop. If
7214 * the interactive program catches interrupts, the user doesn't want
7215 * these interrupts to also abort the loop. The approach we take here
7216 * is to have the shell ignore interrupt signals while waiting for a
7217 * forground process to terminate, and then send itself an interrupt
7218 * signal if the child process was terminated by an interrupt signal.
7219 * Unfortunately, some programs want to do a bit of cleanup and then
7220 * exit on interrupt; unless these processes terminate themselves by
7221 * sending a signal to themselves (instead of calling exit) they will
7222 * confuse this approach.
7224 * Called with interrupts off.
7228 waitforjob(struct job *jp)
7232 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
7233 while (jp->state == JOBRUNNING) {
7234 dowait(DOWAIT_BLOCK, jp);
7239 xtcsetpgrp(ttyfd, rootpid);
7241 * This is truly gross.
7242 * If we're doing job control, then we did a TIOCSPGRP which
7243 * caused us (the shell) to no longer be in the controlling
7244 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7245 * intuit from the subprocess exit status whether a SIGINT
7246 * occurred, and if so interrupt ourselves. Yuck. - mycroft
7251 if (jp->state == JOBDONE)
7259 * Do a wait system call. If job control is compiled in, we accept
7260 * stopped processes. If block is zero, we return a value of zero
7261 * rather than blocking.
7263 * System V doesn't have a non-blocking wait system call. It does
7264 * have a SIGCLD signal that is sent to a process when one of it's
7265 * children dies. The obvious way to use SIGCLD would be to install
7266 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7267 * was received, and have waitproc bump another counter when it got
7268 * the status of a process. Waitproc would then know that a wait
7269 * system call would not block if the two counters were different.
7270 * This approach doesn't work because if a process has children that
7271 * have not been waited for, System V will send it a SIGCLD when it
7272 * installs a signal handler for SIGCLD. What this means is that when
7273 * a child exits, the shell will be sent SIGCLD signals continuously
7274 * until is runs out of stack space, unless it does a wait call before
7275 * restoring the signal handler. The code below takes advantage of
7276 * this (mis)feature by installing a signal handler for SIGCLD and
7277 * then checking to see whether it was called. If there are any
7278 * children to be waited for, it will be.
7280 * If neither SYSV nor BSD is defined, we don't implement nonblocking
7281 * waits at all. In this case, the user will not be informed when
7282 * a background process until the next time she runs a real program
7283 * (as opposed to running a builtin command or just typing return),
7284 * and the jobs command may give out of date information.
7288 waitproc(int block, int *status)
7298 return wait3(status, flags, (struct rusage *)NULL);
7302 * Wait for a process to terminate.
7306 dowait(int block, struct job *job)
7311 struct job *thisjob;
7314 TRACE(("dowait(%d) called\n", block));
7315 pid = waitproc(block, &status);
7316 TRACE(("wait returns pid %d, status=%d\n", pid, status));
7321 for (jp = curjob; jp; jp = jp->prev_job) {
7322 struct procstat *sp;
7323 struct procstat *spend;
7324 if (jp->state == JOBDONE)
7327 spend = jp->ps + jp->nprocs;
7330 if (sp->pid == pid) {
7331 TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
7332 sp->status = status;
7335 if (sp->status == -1)
7338 if (state == JOBRUNNING)
7340 if (WIFSTOPPED(sp->status)) {
7341 jp->stopstatus = sp->status;
7345 } while (++sp < spend);
7350 if (!WIFSTOPPED(status))
7357 if (state != JOBRUNNING) {
7358 thisjob->changed = 1;
7360 if (thisjob->state != state) {
7361 TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
7362 thisjob->state = state;
7364 if (state == JOBSTOPPED) {
7365 set_curjob(thisjob, CUR_STOPPED);
7374 if (thisjob && thisjob == job) {
7378 len = sprint_status(s, status, 1);
7390 * return 1 if there are stopped jobs, otherwise 0
7403 if (jp && jp->state == JOBSTOPPED) {
7404 out2str("You have stopped jobs.\n");
7414 * Return a string identifying a command (to be printed by the
7419 static char *cmdnextc;
7422 commandtext(union node *n)
7426 STARTSTACKSTR(cmdnextc);
7428 name = stackblock();
7429 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
7430 name, cmdnextc, cmdnextc));
7431 return savestr(name);
7435 cmdtxt(union node *n)
7438 struct nodelist *lp;
7450 lp = n->npipe.cmdlist;
7468 cmdtxt(n->nbinary.ch1);
7484 cmdtxt(n->nif.test);
7487 if (n->nif.elsepart) {
7490 n = n->nif.elsepart;
7506 cmdtxt(n->nbinary.ch1);
7516 cmdputs(n->nfor.var);
7518 cmdlist(n->nfor.args, 1);
7523 cmdputs(n->narg.text);
7527 cmdlist(n->ncmd.args, 1);
7528 cmdlist(n->ncmd.redirect, 0);
7541 cmdputs(n->ncase.expr->narg.text);
7543 for (np = n->ncase.cases; np; np = np->nclist.next) {
7544 cmdtxt(np->nclist.pattern);
7546 cmdtxt(np->nclist.body);
7572 s[0] = n->nfile.fd + '0';
7576 if (n->type == NTOFD || n->type == NFROMFD) {
7577 s[0] = n->ndup.dupfd + '0';
7588 cmdlist(union node *np, int sep)
7590 for (; np; np = np->narg.next) {
7594 if (sep && np->narg.next)
7600 cmdputs(const char *s)
7602 const char *p, *str;
7603 char c, cc[2] = " ";
7607 static const char *const vstype[16] = {
7608 nullstr, "}", "-", "+", "?", "=",
7609 "#", "##", "%", "%%"
7612 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
7614 while ((c = *p++) != 0) {
7622 if ((subtype & VSTYPE) == VSLENGTH)
7626 if (!(subtype & VSQUOTE) != !(quoted & 1)) {
7644 case CTLBACKQ+CTLQUOTE:
7647 #ifdef CONFIG_ASH_MATH_SUPPORT
7662 str = vstype[subtype & VSTYPE];
7663 if (subtype & VSNUL)
7674 /* These can only happen inside quotes */
7686 while ((c = *str++)) {
7691 USTPUTC('"', nextc);
7699 showpipe(struct job *jp, FILE *out)
7701 struct procstat *sp;
7702 struct procstat *spend;
7704 spend = jp->ps + jp->nprocs;
7705 for (sp = jp->ps + 1; sp < spend; sp++)
7706 fprintf(out, " | %s", sp->cmd);
7707 outcslow('\n', out);
7712 xtcsetpgrp(int fd, pid_t pgrp)
7714 if (tcsetpgrp(fd, pgrp))
7715 error("Cannot set tty process group (%m)");
7720 getstatus(struct job *job) {
7724 status = job->ps[job->nprocs - 1].status;
7725 retval = WEXITSTATUS(status);
7726 if (!WIFEXITED(status)) {
7728 retval = WSTOPSIG(status);
7729 if (!WIFSTOPPED(status))
7732 /* XXX: limits number of signals */
7733 retval = WTERMSIG(status);
7735 if (retval == SIGINT)
7741 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
7742 jobno(job), job->nprocs, status, retval));
7746 #ifdef CONFIG_ASH_MAIL
7747 /* $NetBSD: mail.c,v 1.15 2002/11/24 22:35:40 christos Exp $ */
7750 * Routines to check for mail. (Perhaps make part of main.c?)
7753 #define MAXMBOXES 10
7755 /* times of mailboxes */
7756 static time_t mailtime[MAXMBOXES];
7757 /* Set if MAIL or MAILPATH is changed. */
7758 static int mail_var_path_changed;
7763 * Print appropriate message(s) if mail has arrived.
7764 * If mail_var_path_changed is set,
7765 * then the value of MAIL has mail_var_path_changed,
7766 * so we just update the values.
7776 struct stackmark smark;
7779 setstackmark(&smark);
7780 mpath = mpathset() ? mpathval() : mailval();
7781 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
7782 p = padvance(&mpath, nullstr);
7787 for (q = p ; *q ; q++);
7792 q[-1] = '\0'; /* delete trailing '/' */
7793 if (stat(p, &statb) < 0) {
7797 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
7800 pathopt ? pathopt : "you have mail"
7803 *mtp = statb.st_mtime;
7805 mail_var_path_changed = 0;
7806 popstackmark(&smark);
7811 changemail(const char *val)
7813 mail_var_path_changed++;
7816 #endif /* CONFIG_ASH_MAIL */
7818 /* $NetBSD: main.c,v 1.46 2002/12/11 19:12:18 christos Exp $ */
7822 static short profile_buf[16384];
7826 static int isloginsh;
7828 static void read_profile(const char *);
7831 * Main routine. We initialize things, parse the arguments, execute
7832 * profiles if we're a login shell, and then call cmdloop to execute
7833 * commands. The setjmp call sets up the location to jump to when an
7834 * exception occurs. When an exception occurs the variable "state"
7835 * is used to figure out how far we had gotten.
7839 ash_main(int argc, char **argv)
7843 struct jmploc jmploc;
7844 struct stackmark smark;
7847 dash_errno = __errno_location();
7851 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7854 if (setjmp(jmploc.loc)) {
7861 switch (exception) {
7871 status = exitstatus;
7874 exitstatus = status;
7876 if (e == EXEXIT || state == 0 || iflag == 0 || ! rootshell)
7880 outcslow('\n', stderr);
7882 popstackmark(&smark);
7883 FORCEINTON; /* enable interrupts */
7886 else if (state == 2)
7888 else if (state == 3)
7896 trputs("Shell args: "); trargs(argv);
7901 setstackmark(&smark);
7902 procargs(argc, argv);
7903 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7905 const char *hp = lookupvar("HISTFILE");
7908 hp = lookupvar("HOME");
7910 char *defhp = concat_path_file(hp, ".ash_history");
7911 setvar("HISTFILE", defhp, 0);
7917 if (argv[0] && argv[0][0] == '-')
7921 read_profile("/etc/profile");
7924 read_profile(".profile");
7930 getuid() == geteuid() && getgid() == getegid() &&
7934 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
7935 read_profile(shinit);
7943 if (sflag || minusc == NULL) {
7944 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7946 const char *hp = lookupvar("HISTFILE");
7949 load_history ( hp );
7952 state4: /* XXX ??? - why isn't this before the "if" statement */
7960 extern void _mcleanup(void);
7970 * Read and execute commands. "Top" is nonzero for the top level command
7971 * loop; it turns on prompting if the shell is interactive.
7978 struct stackmark smark;
7982 TRACE(("cmdloop(%d) called\n", top));
7984 setstackmark(&smark);
7989 showjobs(stderr, SHOW_CHANGED);
7994 #ifdef CONFIG_ASH_MAIL
7998 n = parsecmd(inter);
7999 /* showtree(n); DEBUG */
8001 if (!top || numeof >= 50)
8003 if (!stoppedjobs()) {
8006 out2str("\nUse \"exit\" to leave shell.\n");
8009 } else if (n != NULL && nflag == 0) {
8010 job_warning = (job_warning == 2) ? 1 : 0;
8014 popstackmark(&smark);
8024 * Read /etc/profile or .profile. Return on error.
8028 read_profile(const char *name)
8035 if ((fd = open(name, O_RDONLY)) >= 0)
8040 /* -q turns off -x and -v just when executing init files */
8043 xflag = 0, xflag_set = 1;
8045 vflag = 0, vflag_set = 1;
8059 * Read a file containing shell functions.
8063 readcmdfile(char *name)
8068 if ((fd = open(name, O_RDONLY)) >= 0)
8071 error("Can't open %s", name);
8079 * Take commands from a file. To be compatible we should do a path
8080 * search for the file, which is necessary to find sub-commands.
8083 static inline char *
8084 find_dot_file(char *name)
8087 const char *path = pathval();
8090 /* don't try this for absolute or relative paths */
8091 if (strchr(name, '/'))
8094 while ((fullname = padvance(&path, name)) != NULL) {
8095 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
8097 * Don't bother freeing here, since it will
8098 * be freed by the caller.
8102 stunalloc(fullname);
8105 /* not found in the PATH */
8106 error(not_found_msg, name);
8111 dotcmd(int argc, char **argv)
8115 if (argc >= 2) { /* That's what SVR2 does */
8117 struct stackmark smark;
8119 setstackmark(&smark);
8120 fullname = find_dot_file(argv[1]);
8121 setinputfile(fullname, 1);
8122 commandname = fullname;
8125 popstackmark(&smark);
8132 exitcmd(int argc, char **argv)
8137 exitstatus = number(argv[1]);
8142 /* $NetBSD: memalloc.c,v 1.27 2003/01/22 20:36:04 dsl Exp $ */
8145 * Same for malloc, realloc, but returns an error when out of space.
8149 ckrealloc(pointer p, size_t nbytes)
8151 p = realloc(p, nbytes);
8153 error(bb_msg_memory_exhausted);
8158 ckmalloc(size_t nbytes)
8160 return ckrealloc(NULL, nbytes);
8164 * Make a copy of a string in safe storage.
8168 savestr(const char *s)
8170 char *p = strdup(s);
8172 error(bb_msg_memory_exhausted);
8178 * Parse trees for commands are allocated in lifo order, so we use a stack
8179 * to make this more efficient, and also to avoid all sorts of exception
8180 * handling code to handle interrupts in the middle of a parse.
8182 * The size 504 was chosen because the Ultrix malloc handles that size
8188 stalloc(size_t nbytes)
8193 aligned = SHELL_ALIGN(nbytes);
8194 if (aligned > stacknleft) {
8197 struct stack_block *sp;
8199 blocksize = aligned;
8200 if (blocksize < MINSIZE)
8201 blocksize = MINSIZE;
8202 len = sizeof(struct stack_block) - MINSIZE + blocksize;
8203 if (len < blocksize)
8204 error(bb_msg_memory_exhausted);
8208 stacknxt = sp->space;
8209 stacknleft = blocksize;
8210 sstrend = stacknxt + blocksize;
8215 stacknxt += aligned;
8216 stacknleft -= aligned;
8222 stunalloc(pointer p)
8225 if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
8226 write(2, "stunalloc\n", 10);
8230 stacknleft += stacknxt - (char *)p;
8236 setstackmark(struct stackmark *mark)
8238 mark->stackp = stackp;
8239 mark->stacknxt = stacknxt;
8240 mark->stacknleft = stacknleft;
8241 mark->marknext = markp;
8247 popstackmark(struct stackmark *mark)
8249 struct stack_block *sp;
8252 markp = mark->marknext;
8253 while (stackp != mark->stackp) {
8258 stacknxt = mark->stacknxt;
8259 stacknleft = mark->stacknleft;
8260 sstrend = mark->stacknxt + mark->stacknleft;
8266 * When the parser reads in a string, it wants to stick the string on the
8267 * stack and only adjust the stack pointer when it knows how big the
8268 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8269 * of space on top of the stack and stackblocklen returns the length of
8270 * this block. Growstackblock will grow this space by at least one byte,
8271 * possibly moving it (like realloc). Grabstackblock actually allocates the
8272 * part of the block that has been used.
8276 growstackblock(void)
8280 newlen = stacknleft * 2;
8281 if (newlen < stacknleft)
8282 error(bb_msg_memory_exhausted);
8286 if (stacknxt == stackp->space && stackp != &stackbase) {
8287 struct stack_block *oldstackp;
8288 struct stackmark *xmark;
8289 struct stack_block *sp;
8290 struct stack_block *prevstackp;
8296 prevstackp = sp->prev;
8297 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
8298 sp = ckrealloc((pointer)sp, grosslen);
8299 sp->prev = prevstackp;
8301 stacknxt = sp->space;
8302 stacknleft = newlen;
8303 sstrend = sp->space + newlen;
8306 * Stack marks pointing to the start of the old block
8307 * must be relocated to point to the new block
8310 while (xmark != NULL && xmark->stackp == oldstackp) {
8311 xmark->stackp = stackp;
8312 xmark->stacknxt = stacknxt;
8313 xmark->stacknleft = stacknleft;
8314 xmark = xmark->marknext;
8318 char *oldspace = stacknxt;
8319 int oldlen = stacknleft;
8320 char *p = stalloc(newlen);
8322 /* free the space we just allocated */
8323 stacknxt = memcpy(p, oldspace, oldlen);
8324 stacknleft += newlen;
8329 grabstackblock(size_t len)
8331 len = SHELL_ALIGN(len);
8337 * The following routines are somewhat easier to use than the above.
8338 * The user declares a variable of type STACKSTR, which may be declared
8339 * to be a register. The macro STARTSTACKSTR initializes things. Then
8340 * the user uses the macro STPUTC to add characters to the string. In
8341 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8342 * grown as necessary. When the user is done, she can just leave the
8343 * string there and refer to it using stackblock(). Or she can allocate
8344 * the space for it using grabstackstr(). If it is necessary to allow
8345 * someone else to use the stack temporarily and then continue to grow
8346 * the string, the user should use grabstack to allocate the space, and
8347 * then call ungrabstr(p) to return to the previous mode of operation.
8349 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8350 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8351 * is space for at least one character.
8357 size_t len = stackblocksize();
8358 if (herefd >= 0 && len >= 1024) {
8359 xwrite(herefd, stackblock(), len);
8360 return stackblock();
8363 return stackblock() + len;
8367 * Called from CHECKSTRSPACE.
8371 makestrspace(size_t newlen, char *p)
8373 size_t len = p - stacknxt;
8374 size_t size = stackblocksize();
8379 size = stackblocksize();
8381 if (nleft >= newlen)
8385 return stackblock() + len;
8389 stnputs(const char *s, size_t n, char *p)
8391 p = makestrspace(n, p);
8392 p = mempcpy(p, s, n);
8397 stputs(const char *s, char *p)
8399 return stnputs(s, strlen(s), p);
8402 /* $NetBSD: mystring.c,v 1.15 2002/11/24 22:35:42 christos Exp $ */
8407 * number(s) Convert a string of digits to an integer.
8408 * is_number(s) Return true if s is a string of digits.
8412 * prefix -- see if pfx is a prefix of string.
8416 prefix(const char *string, const char *pfx)
8419 if (*pfx++ != *string++)
8422 return (char *) string;
8427 * Convert a string of digits to an integer, printing an error message on
8432 number(const char *s)
8442 * Check for a valid number. This should be elsewhere.
8446 is_number(const char *p)
8451 } while (*++p != '\0');
8457 * Produce a possibly single quoted string suitable as input to the shell.
8458 * The return string is allocated on the stack.
8462 single_quote(const char *s) {
8471 len = strchrnul(s, '\'') - s;
8473 q = p = makestrspace(len + 3, p);
8476 q = mempcpy(q, s, len);
8482 len = strspn(s, "'");
8486 q = p = makestrspace(len + 3, p);
8489 q = mempcpy(q, s, len);
8498 return stackblock();
8502 * Like strdup but works with the ash stack.
8506 sstrdup(const char *p)
8508 size_t len = strlen(p) + 1;
8509 return memcpy(stalloc(len), p, len);
8514 calcsize(union node *n)
8518 funcblocksize += nodesize[n->type];
8521 calcsize(n->ncmd.redirect);
8522 calcsize(n->ncmd.args);
8523 calcsize(n->ncmd.assign);
8526 sizenodelist(n->npipe.cmdlist);
8531 calcsize(n->nredir.redirect);
8532 calcsize(n->nredir.n);
8539 calcsize(n->nbinary.ch2);
8540 calcsize(n->nbinary.ch1);
8543 calcsize(n->nif.elsepart);
8544 calcsize(n->nif.ifpart);
8545 calcsize(n->nif.test);
8548 funcstringsize += strlen(n->nfor.var) + 1;
8549 calcsize(n->nfor.body);
8550 calcsize(n->nfor.args);
8553 calcsize(n->ncase.cases);
8554 calcsize(n->ncase.expr);
8557 calcsize(n->nclist.body);
8558 calcsize(n->nclist.pattern);
8559 calcsize(n->nclist.next);
8563 sizenodelist(n->narg.backquote);
8564 funcstringsize += strlen(n->narg.text) + 1;
8565 calcsize(n->narg.next);
8572 calcsize(n->nfile.fname);
8573 calcsize(n->nfile.next);
8577 calcsize(n->ndup.vname);
8578 calcsize(n->ndup.next);
8582 calcsize(n->nhere.doc);
8583 calcsize(n->nhere.next);
8586 calcsize(n->nnot.com);
8593 sizenodelist(struct nodelist *lp)
8596 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8604 copynode(union node *n)
8611 funcblock = (char *) funcblock + nodesize[n->type];
8614 new->ncmd.redirect = copynode(n->ncmd.redirect);
8615 new->ncmd.args = copynode(n->ncmd.args);
8616 new->ncmd.assign = copynode(n->ncmd.assign);
8619 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8620 new->npipe.backgnd = n->npipe.backgnd;
8625 new->nredir.redirect = copynode(n->nredir.redirect);
8626 new->nredir.n = copynode(n->nredir.n);
8633 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8634 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8637 new->nif.elsepart = copynode(n->nif.elsepart);
8638 new->nif.ifpart = copynode(n->nif.ifpart);
8639 new->nif.test = copynode(n->nif.test);
8642 new->nfor.var = nodesavestr(n->nfor.var);
8643 new->nfor.body = copynode(n->nfor.body);
8644 new->nfor.args = copynode(n->nfor.args);
8647 new->ncase.cases = copynode(n->ncase.cases);
8648 new->ncase.expr = copynode(n->ncase.expr);
8651 new->nclist.body = copynode(n->nclist.body);
8652 new->nclist.pattern = copynode(n->nclist.pattern);
8653 new->nclist.next = copynode(n->nclist.next);
8657 new->narg.backquote = copynodelist(n->narg.backquote);
8658 new->narg.text = nodesavestr(n->narg.text);
8659 new->narg.next = copynode(n->narg.next);
8666 new->nfile.fname = copynode(n->nfile.fname);
8667 new->nfile.fd = n->nfile.fd;
8668 new->nfile.next = copynode(n->nfile.next);
8672 new->ndup.vname = copynode(n->ndup.vname);
8673 new->ndup.dupfd = n->ndup.dupfd;
8674 new->ndup.fd = n->ndup.fd;
8675 new->ndup.next = copynode(n->ndup.next);
8679 new->nhere.doc = copynode(n->nhere.doc);
8680 new->nhere.fd = n->nhere.fd;
8681 new->nhere.next = copynode(n->nhere.next);
8684 new->nnot.com = copynode(n->nnot.com);
8687 new->type = n->type;
8692 static struct nodelist *
8693 copynodelist(struct nodelist *lp)
8695 struct nodelist *start;
8696 struct nodelist **lpp;
8701 funcblock = (char *) funcblock +
8702 SHELL_ALIGN(sizeof(struct nodelist));
8703 (*lpp)->n = copynode(lp->n);
8705 lpp = &(*lpp)->next;
8713 nodesavestr(char *s)
8715 char *rtn = funcstring;
8717 funcstring = stpcpy(funcstring, s) + 1;
8723 * Free a parse tree.
8727 freefunc(struct funcnode *f)
8729 if (f && --f->count < 0)
8734 static void options(int);
8735 static void setoption(int, int);
8739 * Process the shell command line arguments.
8743 procargs(int argc, char **argv)
8746 const char *xminusc;
8753 for (i = 0; i < NOPTS; i++)
8759 if (*xargv == NULL) {
8761 error("-c requires an argument");
8764 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8768 for (i = 0; i < NOPTS; i++)
8769 if (optlist[i] == 2)
8774 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8779 } else if (!sflag) {
8780 setinputfile(*xargv, 0);
8786 shellparam.p = xargv;
8787 #ifdef CONFIG_ASH_GETOPTS
8788 shellparam.optind = 1;
8789 shellparam.optoff = -1;
8791 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
8793 shellparam.nparam++;
8806 setinteractive(iflag);
8811 minus_o(char *name, int val)
8816 out1str("Current option settings\n");
8817 for (i = 0; i < NOPTS; i++)
8818 out1fmt("%-16s%s\n", optnames(i),
8819 optlist[i] ? "on" : "off");
8821 for (i = 0; i < NOPTS; i++)
8822 if (equal(name, optnames(i))) {
8826 error("Illegal option -o %s", name);
8831 * Process shell options. The global variable argptr contains a pointer
8832 * to the argument list; we advance it past the options.
8836 options(int cmdline)
8844 while ((p = *argptr) != NULL) {
8846 if ((c = *p++) == '-') {
8848 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8850 /* "-" means turn off -x and -v */
8853 /* "--" means reset params */
8854 else if (*argptr == NULL)
8857 break; /* "-" or "--" terminates options */
8859 } else if (c == '+') {
8865 while ((c = *p++) != '\0') {
8866 if (c == 'c' && cmdline) {
8867 minusc = p; /* command is after shell args*/
8868 } else if (c == 'o') {
8869 minus_o(*argptr, val);
8872 } else if (cmdline && (c == '-')) { // long options
8873 if (strcmp(p, "login") == 0)
8885 setoption(int flag, int val)
8889 for (i = 0; i < NOPTS; i++)
8890 if (optletters(i) == flag) {
8894 error("Illegal option -%c", flag);
8901 * Set the shell parameters.
8905 setparam(char **argv)
8911 for (nparam = 0 ; argv[nparam] ; nparam++);
8912 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
8914 *ap++ = savestr(*argv++);
8917 freeparam(&shellparam);
8918 shellparam.malloc = 1;
8919 shellparam.nparam = nparam;
8920 shellparam.p = newparam;
8921 #ifdef CONFIG_ASH_GETOPTS
8922 shellparam.optind = 1;
8923 shellparam.optoff = -1;
8929 * Free the list of positional parameters.
8933 freeparam(volatile struct shparam *param)
8937 if (param->malloc) {
8938 for (ap = param->p ; *ap ; ap++)
8947 * The shift builtin command.
8951 shiftcmd(int argc, char **argv)
8958 n = number(argv[1]);
8959 if (n > shellparam.nparam)
8960 error("can't shift that many");
8962 shellparam.nparam -= n;
8963 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
8964 if (shellparam.malloc)
8968 while ((*ap2++ = *ap1++) != NULL);
8969 #ifdef CONFIG_ASH_GETOPTS
8970 shellparam.optind = 1;
8971 shellparam.optoff = -1;
8980 * The set command builtin.
8984 setcmd(int argc, char **argv)
8987 return showvars(nullstr, 0, VUNSET);
8991 if (*argptr != NULL) {
8999 #ifdef CONFIG_ASH_GETOPTS
9004 shellparam.optind = number(value);
9005 shellparam.optoff = -1;
9009 #ifdef CONFIG_LOCALE_SUPPORT
9010 static void change_lc_all(const char *value)
9012 if (value != 0 && *value != 0)
9013 setlocale(LC_ALL, value);
9016 static void change_lc_ctype(const char *value)
9018 if (value != 0 && *value != 0)
9019 setlocale(LC_CTYPE, value);
9024 #ifdef CONFIG_ASH_GETOPTS
9026 getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
9035 if(*param_optind < 1)
9037 optnext = optfirst + *param_optind - 1;
9039 if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff)
9042 p = optnext[-1] + *optoff;
9043 if (p == NULL || *p == '\0') {
9044 /* Current word is done, advance */
9046 if (p == NULL || *p != '-' || *++p == '\0') {
9053 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
9058 for (q = optstr; *q != c; ) {
9060 if (optstr[0] == ':') {
9063 err |= setvarsafe("OPTARG", s, 0);
9065 fprintf(stderr, "Illegal option -%c\n", c);
9066 (void) unsetvar("OPTARG");
9076 if (*p == '\0' && (p = *optnext) == NULL) {
9077 if (optstr[0] == ':') {
9080 err |= setvarsafe("OPTARG", s, 0);
9083 fprintf(stderr, "No arg for -%c option\n", c);
9084 (void) unsetvar("OPTARG");
9092 err |= setvarsafe("OPTARG", p, 0);
9095 err |= setvarsafe("OPTARG", nullstr, 0);
9098 *optoff = p ? p - *(optnext - 1) : -1;
9099 *param_optind = optnext - optfirst + 1;
9100 fmtstr(s, sizeof(s), "%d", *param_optind);
9101 err |= setvarsafe("OPTIND", s, VNOFUNC);
9104 err |= setvarsafe(optvar, s, 0);
9115 * The getopts builtin. Shellparam.optnext points to the next argument
9116 * to be processed. Shellparam.optptr points to the next character to
9117 * be processed in the current argument. If shellparam.optnext is NULL,
9118 * then it's the first time getopts has been called.
9122 getoptscmd(int argc, char **argv)
9127 error("Usage: getopts optstring var [arg]");
9128 else if (argc == 3) {
9129 optbase = shellparam.p;
9130 if (shellparam.optind > shellparam.nparam + 1) {
9131 shellparam.optind = 1;
9132 shellparam.optoff = -1;
9137 if (shellparam.optind > argc - 2) {
9138 shellparam.optind = 1;
9139 shellparam.optoff = -1;
9143 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9144 &shellparam.optoff);
9146 #endif /* CONFIG_ASH_GETOPTS */
9149 * XXX - should get rid of. have all builtins use getopt(3). the
9150 * library getopt must have the BSD extension static variable "optreset"
9151 * otherwise it can't be used within the shell safely.
9153 * Standard option processing (a la getopt) for builtin routines. The
9154 * only argument that is passed to nextopt is the option string; the
9155 * other arguments are unnecessary. It return the character, or '\0' on
9160 nextopt(const char *optstring)
9166 if ((p = optptr) == NULL || *p == '\0') {
9168 if (p == NULL || *p != '-' || *++p == '\0')
9171 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
9175 for (q = optstring ; *q != c ; ) {
9177 error("Illegal option -%c", c);
9182 if (*p == '\0' && (p = *argptr++) == NULL)
9183 error("No arg for -%c option", c);
9192 /* $NetBSD: output.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
9195 outstr(const char *p, FILE *file)
9212 flushout(FILE *dest)
9220 outcslow(int c, FILE *dest)
9230 out1fmt(const char *fmt, ...)
9237 r = vprintf(fmt, ap);
9245 fmtstr(char *outbuf, size_t length, const char *fmt, ...)
9252 ret = vsnprintf(outbuf, length, fmt, ap);
9260 * Version of write which resumes after a signal is caught.
9264 xwrite(int fd, const void *p, size_t n)
9269 i = bb_full_write(fd, p, n);
9270 } while (i < 0 && errno == EINTR);
9274 /* $NetBSD: parser.c,v 1.54 2002/11/24 22:35:42 christos Exp $ */
9278 * Shell command parser.
9281 #define EOFMARKLEN 79
9285 struct heredoc *next; /* next here document in list */
9286 union node *here; /* redirection node */
9287 char *eofmark; /* string indicating end of input */
9288 int striptabs; /* if set, strip leading tabs */
9293 static struct heredoc *heredoclist; /* list of here documents to read */
9296 static union node *list(int);
9297 static union node *andor(void);
9298 static union node *pipeline(void);
9299 static union node *command(void);
9300 static union node *simplecmd(void);
9301 static union node *makename(void);
9302 static void parsefname(void);
9303 static void parseheredoc(void);
9304 static char peektoken(void);
9305 static int readtoken(void);
9306 static int xxreadtoken(void);
9307 static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
9308 static int noexpand(char *);
9309 static void synexpect(int) __attribute__((__noreturn__));
9310 static void synerror(const char *) __attribute__((__noreturn__));
9311 static void setprompt(int);
9316 isassignment(const char *p)
9318 const char *q = endofname(p);
9326 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9327 * valid parse tree indicating a blank line.)
9331 parsecmd(int interact)
9336 doprompt = interact;
9338 setprompt(doprompt);
9353 union node *n1, *n2, *n3;
9356 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9357 if (nlflag == 2 && peektoken())
9363 if (tok == TBACKGND) {
9364 if (n2->type == NPIPE) {
9365 n2->npipe.backgnd = 1;
9367 if (n2->type != NREDIR) {
9368 n3 = stalloc(sizeof(struct nredir));
9370 n3->nredir.redirect = NULL;
9373 n2->type = NBACKGND;
9380 n3 = (union node *)stalloc(sizeof (struct nbinary));
9382 n3->nbinary.ch1 = n1;
9383 n3->nbinary.ch2 = n2;
9399 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9407 pungetc(); /* push back EOF on input */
9423 union node *n1, *n2, *n3;
9428 if ((t = readtoken()) == TAND) {
9430 } else if (t == TOR) {
9436 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9438 n3 = (union node *)stalloc(sizeof (struct nbinary));
9440 n3->nbinary.ch1 = n1;
9441 n3->nbinary.ch2 = n2;
9451 union node *n1, *n2, *pipenode;
9452 struct nodelist *lp, *prev;
9456 TRACE(("pipeline: entered\n"));
9457 if (readtoken() == TNOT) {
9459 checkkwd = CHKKWD | CHKALIAS;
9463 if (readtoken() == TPIPE) {
9464 pipenode = (union node *)stalloc(sizeof (struct npipe));
9465 pipenode->type = NPIPE;
9466 pipenode->npipe.backgnd = 0;
9467 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9468 pipenode->npipe.cmdlist = lp;
9472 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9473 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9476 } while (readtoken() == TPIPE);
9482 n2 = (union node *)stalloc(sizeof (struct nnot));
9495 union node *n1, *n2;
9496 union node *ap, **app;
9497 union node *cp, **cpp;
9498 union node *redir, **rpp;
9505 switch (readtoken()) {
9510 n1 = (union node *)stalloc(sizeof (struct nif));
9512 n1->nif.test = list(0);
9513 if (readtoken() != TTHEN)
9515 n1->nif.ifpart = list(0);
9517 while (readtoken() == TELIF) {
9518 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
9519 n2 = n2->nif.elsepart;
9521 n2->nif.test = list(0);
9522 if (readtoken() != TTHEN)
9524 n2->nif.ifpart = list(0);
9526 if (lasttoken == TELSE)
9527 n2->nif.elsepart = list(0);
9529 n2->nif.elsepart = NULL;
9537 n1 = (union node *)stalloc(sizeof (struct nbinary));
9538 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
9539 n1->nbinary.ch1 = list(0);
9540 if ((got=readtoken()) != TDO) {
9541 TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
9544 n1->nbinary.ch2 = list(0);
9549 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9550 synerror("Bad for loop variable");
9551 n1 = (union node *)stalloc(sizeof (struct nfor));
9553 n1->nfor.var = wordtext;
9554 checkkwd = CHKKWD | CHKALIAS;
9555 if (readtoken() == TIN) {
9557 while (readtoken() == TWORD) {
9558 n2 = (union node *)stalloc(sizeof (struct narg));
9560 n2->narg.text = wordtext;
9561 n2->narg.backquote = backquotelist;
9563 app = &n2->narg.next;
9567 if (lasttoken != TNL && lasttoken != TSEMI)
9570 n2 = (union node *)stalloc(sizeof (struct narg));
9572 n2->narg.text = (char *)dolatstr;
9573 n2->narg.backquote = NULL;
9574 n2->narg.next = NULL;
9577 * Newline or semicolon here is optional (but note
9578 * that the original Bourne shell only allowed NL).
9580 if (lasttoken != TNL && lasttoken != TSEMI)
9583 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9584 if (readtoken() != TDO)
9586 n1->nfor.body = list(0);
9590 n1 = (union node *)stalloc(sizeof (struct ncase));
9592 if (readtoken() != TWORD)
9594 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
9596 n2->narg.text = wordtext;
9597 n2->narg.backquote = backquotelist;
9598 n2->narg.next = NULL;
9600 checkkwd = CHKKWD | CHKALIAS;
9601 } while (readtoken() == TNL);
9602 if (lasttoken != TIN)
9604 cpp = &n1->ncase.cases;
9606 checkkwd = CHKNL | CHKKWD;
9609 if (lasttoken == TLP)
9611 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
9613 app = &cp->nclist.pattern;
9615 *app = ap = (union node *)stalloc(sizeof (struct narg));
9617 ap->narg.text = wordtext;
9618 ap->narg.backquote = backquotelist;
9619 if (readtoken() != TPIPE)
9621 app = &ap->narg.next;
9624 ap->narg.next = NULL;
9625 if (lasttoken != TRP)
9627 cp->nclist.body = list(2);
9629 cpp = &cp->nclist.next;
9631 checkkwd = CHKNL | CHKKWD;
9632 if ((t = readtoken()) != TESAC) {
9634 synexpect(TENDCASE);
9642 n1 = (union node *)stalloc(sizeof (struct nredir));
9643 n1->type = NSUBSHELL;
9644 n1->nredir.n = list(0);
9645 n1->nredir.redirect = NULL;
9658 if (readtoken() != t)
9662 /* Now check for redirection which may follow command */
9663 checkkwd = CHKKWD | CHKALIAS;
9665 while (readtoken() == TREDIR) {
9666 *rpp = n2 = redirnode;
9667 rpp = &n2->nfile.next;
9673 if (n1->type != NSUBSHELL) {
9674 n2 = (union node *)stalloc(sizeof (struct nredir));
9679 n1->nredir.redirect = redir;
9688 union node *args, **app;
9689 union node *n = NULL;
9690 union node *vars, **vpp;
9691 union node **rpp, *redir;
9701 savecheckkwd = CHKALIAS;
9703 checkkwd = savecheckkwd;
9704 switch (readtoken()) {
9706 n = (union node *)stalloc(sizeof (struct narg));
9708 n->narg.text = wordtext;
9709 n->narg.backquote = backquotelist;
9710 if (savecheckkwd && isassignment(wordtext)) {
9712 vpp = &n->narg.next;
9715 app = &n->narg.next;
9720 *rpp = n = redirnode;
9721 rpp = &n->nfile.next;
9722 parsefname(); /* read name of redirection file */
9726 args && app == &args->narg.next &&
9729 struct builtincmd *bcmd;
9732 /* We have a function */
9733 if (readtoken() != TRP)
9735 name = n->narg.text;
9737 !goodname(name) || (
9738 (bcmd = find_builtin(name)) &&
9739 IS_BUILTIN_SPECIAL(bcmd)
9742 synerror("Bad function name");
9744 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9745 n->narg.next = command();
9758 n = (union node *)stalloc(sizeof (struct ncmd));
9760 n->ncmd.args = args;
9761 n->ncmd.assign = vars;
9762 n->ncmd.redirect = redir;
9771 n = (union node *)stalloc(sizeof (struct narg));
9773 n->narg.next = NULL;
9774 n->narg.text = wordtext;
9775 n->narg.backquote = backquotelist;
9779 void fixredir(union node *n, const char *text, int err)
9781 TRACE(("Fix redir %s %d\n", text, err));
9783 n->ndup.vname = NULL;
9785 if (is_digit(text[0]) && text[1] == '\0')
9786 n->ndup.dupfd = digit_val(text[0]);
9787 else if (text[0] == '-' && text[1] == '\0')
9792 synerror("Bad fd number");
9794 n->ndup.vname = makename();
9802 union node *n = redirnode;
9804 if (readtoken() != TWORD)
9806 if (n->type == NHERE) {
9807 struct heredoc *here = heredoc;
9813 TRACE(("Here document %d\n", n->type));
9814 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
9815 synerror("Illegal eof marker for << redirection");
9816 rmescapes(wordtext);
9817 here->eofmark = wordtext;
9819 if (heredoclist == NULL)
9822 for (p = heredoclist ; p->next ; p = p->next);
9825 } else if (n->type == NTOFD || n->type == NFROMFD) {
9826 fixredir(n, wordtext, 0);
9828 n->nfile.fname = makename();
9834 * Input any here documents.
9840 struct heredoc *here;
9851 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9852 here->eofmark, here->striptabs);
9853 n = (union node *)stalloc(sizeof (struct narg));
9854 n->narg.type = NARG;
9855 n->narg.next = NULL;
9856 n->narg.text = wordtext;
9857 n->narg.backquote = backquotelist;
9858 here->here->nhere.doc = n;
9863 static char peektoken(void)
9869 return tokname_array[t][0];
9877 int alreadyseen = tokpushback;
9880 #ifdef CONFIG_ASH_ALIAS
9889 if (checkkwd & CHKNL) {
9896 if (t != TWORD || quoteflag) {
9901 * check for keywords
9903 if (checkkwd & CHKKWD) {
9904 const char *const *pp;
9906 if ((pp = findkwd(wordtext))) {
9907 lasttoken = t = pp - tokname_array;
9908 TRACE(("keyword %s recognized\n", tokname(t)));
9913 if (checkkwd & CHKALIAS) {
9914 #ifdef CONFIG_ASH_ALIAS
9916 if ((ap = lookupalias(wordtext, 1)) != NULL) {
9918 pushstring(ap->val, ap);
9928 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
9930 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
9937 * Read the next input token.
9938 * If the token is a word, we set backquotelist to the list of cmds in
9939 * backquotes. We set quoteflag to true if any part of the word was
9941 * If the token is TREDIR, then we set redirnode to a structure containing
9943 * In all cases, the variable startlinno is set to the number of the line
9944 * on which the token starts.
9946 * [Change comment: here documents and internal procedures]
9947 * [Readtoken shouldn't have any arguments. Perhaps we should make the
9948 * word parsing code into a separate routine. In this case, readtoken
9949 * doesn't need to have any internal procedures, but parseword does.
9950 * We could also make parseoperator in essence the main routine, and
9951 * have parseword (readtoken1?) handle both words and redirection.]
9954 #define NEW_xxreadtoken
9955 #ifdef NEW_xxreadtoken
9957 /* singles must be first! */
9958 static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
9960 static const char xxreadtoken_tokens[] = {
9961 TNL, TLP, TRP, /* only single occurrence allowed */
9962 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
9963 TEOF, /* corresponds to trailing nul */
9964 TAND, TOR, TENDCASE, /* if double occurrence */
9967 #define xxreadtoken_doubles \
9968 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
9969 #define xxreadtoken_singles \
9970 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
9972 static int xxreadtoken()
9984 startlinno = plinno;
9985 for (;;) { /* until token or start of word found */
9988 if ((c != ' ') && (c != '\t')
9989 #ifdef CONFIG_ASH_ALIAS
9994 while ((c = pgetc()) != '\n' && c != PEOF);
9996 } else if (c == '\\') {
9997 if (pgetc() != '\n') {
10001 startlinno = ++plinno;
10006 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10011 needprompt = doprompt;
10014 p = strchr(xxreadtoken_chars, c);
10017 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
10020 if (p - xxreadtoken_chars >= xxreadtoken_singles) {
10021 if (pgetc() == *p) { /* double occurrence? */
10022 p += xxreadtoken_doubles + 1;
10029 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
10037 #define RETURN(token) return lasttoken = token
10052 startlinno = plinno;
10053 for (;;) { /* until token or start of word found */
10056 case ' ': case '\t':
10057 #ifdef CONFIG_ASH_ALIAS
10062 while ((c = pgetc()) != '\n' && c != PEOF);
10066 if (pgetc() == '\n') {
10067 startlinno = ++plinno;
10076 needprompt = doprompt;
10081 if (pgetc() == '&')
10086 if (pgetc() == '|')
10091 if (pgetc() == ';')
10104 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10107 #endif /* NEW_xxreadtoken */
10111 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10112 * is not NULL, read a here document. In the latter case, eofmark is the
10113 * word which marks the end of the document and striptabs is true if
10114 * leading tabs should be stripped from the document. The argument firstc
10115 * is the first character of the input token or document.
10117 * Because C does not have internal subroutines, I have simulated them
10118 * using goto's to implement the subroutine linkage. The following macros
10119 * will run code that appears at the end of readtoken1.
10122 #define CHECKEND() {goto checkend; checkend_return:;}
10123 #define PARSEREDIR() {goto parseredir; parseredir_return:;}
10124 #define PARSESUB() {goto parsesub; parsesub_return:;}
10125 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10126 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10127 #define PARSEARITH() {goto parsearith; parsearith_return:;}
10130 readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
10135 char line[EOFMARKLEN + 1];
10136 struct nodelist *bqlist;
10139 int varnest; /* levels of variables expansion */
10140 int arinest; /* levels of arithmetic expansion */
10141 int parenlevel; /* levels of parens in arithmetic */
10142 int dqvarnest; /* levels of variables expansion within double quotes */
10144 int prevsyntax; /* syntax before arithmetic */
10146 /* Avoid longjmp clobbering */
10152 (void) &parenlevel;
10155 (void) &prevsyntax;
10159 startlinno = plinno;
10161 if (syntax == DQSYNTAX)
10170 STARTSTACKSTR(out);
10171 loop: { /* for each line, until end of word */
10172 CHECKEND(); /* set c to PEOF if at end of here document */
10173 for (;;) { /* until end of line or end of word */
10174 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
10175 switch(SIT(c, syntax)) {
10176 case CNL: /* '\n' */
10177 if (syntax == BASESYNTAX)
10178 goto endword; /* exit outer loop */
10184 goto loop; /* continue outer loop */
10189 if (eofmark == NULL || dblquote)
10190 USTPUTC(CTLESC, out);
10193 case CBACK: /* backslash */
10196 USTPUTC(CTLESC, out);
10197 USTPUTC('\\', out);
10199 } else if (c == '\n') {
10205 c != '\\' && c != '`' &&
10211 USTPUTC(CTLESC, out);
10212 USTPUTC('\\', out);
10214 if (SIT(c, SQSYNTAX) == CCTL)
10215 USTPUTC(CTLESC, out);
10223 if (eofmark == NULL) {
10224 USTPUTC(CTLQUOTEMARK, out);
10232 if (eofmark != NULL && arinest == 0 &&
10236 if (dqvarnest == 0) {
10237 syntax = BASESYNTAX;
10244 case CVAR: /* '$' */
10245 PARSESUB(); /* parse substitution */
10247 case CENDVAR: /* '}' */
10250 if (dqvarnest > 0) {
10253 USTPUTC(CTLENDVAR, out);
10258 #ifdef CONFIG_ASH_MATH_SUPPORT
10259 case CLP: /* '(' in arithmetic */
10263 case CRP: /* ')' in arithmetic */
10264 if (parenlevel > 0) {
10268 if (pgetc() == ')') {
10269 if (--arinest == 0) {
10270 USTPUTC(CTLENDARI, out);
10271 syntax = prevsyntax;
10272 if (syntax == DQSYNTAX)
10280 * unbalanced parens
10281 * (don't 2nd guess - no error)
10289 case CBQUOTE: /* '`' */
10293 goto endword; /* exit outer loop */
10298 goto endword; /* exit outer loop */
10299 #ifdef CONFIG_ASH_ALIAS
10309 #ifdef CONFIG_ASH_MATH_SUPPORT
10310 if (syntax == ARISYNTAX)
10311 synerror("Missing '))'");
10313 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10314 synerror("Unterminated quoted string");
10315 if (varnest != 0) {
10316 startlinno = plinno;
10318 synerror("Missing '}'");
10320 USTPUTC('\0', out);
10321 len = out - (char *)stackblock();
10322 out = stackblock();
10323 if (eofmark == NULL) {
10324 if ((c == '>' || c == '<')
10327 && (*out == '\0' || is_digit(*out))) {
10329 return lasttoken = TREDIR;
10334 quoteflag = quotef;
10335 backquotelist = bqlist;
10336 grabstackblock(len);
10338 return lasttoken = TWORD;
10339 /* end of readtoken routine */
10344 * Check to see whether we are at the end of the here document. When this
10345 * is called, c is set to the first character of the next input line. If
10346 * we are at the end of the here document, this routine sets the c to PEOF.
10351 #ifdef CONFIG_ASH_ALIAS
10357 while (c == '\t') {
10361 if (c == *eofmark) {
10362 if (pfgets(line, sizeof line) != NULL) {
10366 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10367 if (*p == '\n' && *q == '\0') {
10370 needprompt = doprompt;
10372 pushstring(line, NULL);
10377 goto checkend_return;
10382 * Parse a redirection operator. The variable "out" points to a string
10383 * specifying the fd to be redirected. The variable "c" contains the
10384 * first character of the redirection operator.
10391 np = (union node *)stalloc(sizeof (struct nfile));
10396 np->type = NAPPEND;
10398 np->type = NCLOBBER;
10405 } else { /* c == '<' */
10407 switch (c = pgetc()) {
10409 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10410 np = (union node *)stalloc(sizeof (struct nhere));
10414 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10415 heredoc->here = np;
10416 if ((c = pgetc()) == '-') {
10417 heredoc->striptabs = 1;
10419 heredoc->striptabs = 0;
10425 np->type = NFROMFD;
10429 np->type = NFROMTO;
10439 np->nfile.fd = digit_val(fd);
10441 goto parseredir_return;
10446 * Parse a substitution. At this point, we have read the dollar sign
10447 * and nothing else.
10455 static const char types[] = "}-+?=";
10459 c <= PEOA_OR_PEOF ||
10460 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10464 } else if (c == '(') { /* $(command) or $((arith)) */
10465 if (pgetc() == '(') {
10466 #ifdef CONFIG_ASH_MATH_SUPPORT
10469 synerror("We unsupport $((arith))");
10476 USTPUTC(CTLVAR, out);
10477 typeloc = out - (char *)stackblock();
10478 USTPUTC(VSNORMAL, out);
10479 subtype = VSNORMAL;
10483 if ((c = pgetc()) == '}')
10486 subtype = VSLENGTH;
10491 if (c > PEOA_OR_PEOF && is_name(c)) {
10495 } while (c > PEOA_OR_PEOF && is_in_name(c));
10496 } else if (is_digit(c)) {
10500 } while (is_digit(c));
10502 else if (is_special(c)) {
10507 badsub: synerror("Bad substitution");
10511 if (subtype == 0) {
10518 p = strchr(types, c);
10521 subtype = p - types + VSNORMAL;
10527 subtype = c == '#' ? VSTRIMLEFT :
10540 if (dblquote || arinest)
10542 *((char *)stackblock() + typeloc) = subtype | flags;
10543 if (subtype != VSNORMAL) {
10545 if (dblquote || arinest) {
10550 goto parsesub_return;
10555 * Called to parse command substitutions. Newstyle is set if the command
10556 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10557 * list of commands (passed by reference), and savelen is the number of
10558 * characters on the top of the stack which must be preserved.
10562 struct nodelist **nlpp;
10565 char *volatile str;
10566 struct jmploc jmploc;
10567 struct jmploc *volatile savehandler;
10571 (void) &saveprompt;
10574 savepbq = parsebackquote;
10575 if (setjmp(jmploc.loc)) {
10578 parsebackquote = 0;
10579 handler = savehandler;
10580 longjmp(handler->loc, 1);
10584 savelen = out - (char *)stackblock();
10586 str = ckmalloc(savelen);
10587 memcpy(str, stackblock(), savelen);
10589 savehandler = handler;
10593 /* We must read until the closing backquote, giving special
10594 treatment to some slashes, and then push the string and
10595 reread it as input, interpreting it normally. */
10602 STARTSTACKSTR(pout);
10608 switch (pc = pgetc()) {
10613 if ((pc = pgetc()) == '\n') {
10618 * If eating a newline, avoid putting
10619 * the newline into the new character
10620 * stream (via the STPUTC after the
10625 if (pc != '\\' && pc != '`' && pc != '$'
10626 && (!dblquote || pc != '"'))
10627 STPUTC('\\', pout);
10628 if (pc > PEOA_OR_PEOF) {
10634 #ifdef CONFIG_ASH_ALIAS
10637 startlinno = plinno;
10638 synerror("EOF in backquote substitution");
10642 needprompt = doprompt;
10651 STPUTC('\0', pout);
10652 psavelen = pout - (char *)stackblock();
10653 if (psavelen > 0) {
10654 pstr = grabstackstr(pout);
10655 setinputstring(pstr);
10660 nlpp = &(*nlpp)->next;
10661 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10662 (*nlpp)->next = NULL;
10663 parsebackquote = oldstyle;
10666 saveprompt = doprompt;
10673 doprompt = saveprompt;
10675 if (readtoken() != TRP)
10682 * Start reading from old file again, ignoring any pushed back
10683 * tokens left from the backquote parsing
10688 while (stackblocksize() <= savelen)
10690 STARTSTACKSTR(out);
10692 memcpy(out, str, savelen);
10693 STADJUST(savelen, out);
10699 parsebackquote = savepbq;
10700 handler = savehandler;
10701 if (arinest || dblquote)
10702 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10704 USTPUTC(CTLBACKQ, out);
10706 goto parsebackq_oldreturn;
10708 goto parsebackq_newreturn;
10711 #ifdef CONFIG_ASH_MATH_SUPPORT
10713 * Parse an arithmetic expansion (indicate start of one and set state)
10717 if (++arinest == 1) {
10718 prevsyntax = syntax;
10719 syntax = ARISYNTAX;
10720 USTPUTC(CTLARI, out);
10727 * we collapse embedded arithmetic expansion to
10728 * parenthesis, which should be equivalent
10732 goto parsearith_return;
10736 } /* end of readtoken */
10741 * Returns true if the text contains nothing to expand (no dollar signs
10746 noexpand(char *text)
10752 while ((c = *p++) != '\0') {
10753 if (c == CTLQUOTEMARK)
10757 else if (SIT(c, BASESYNTAX) == CCTL)
10765 * Return of a legal variable name (a letter or underscore followed by zero or
10766 * more letters, underscores, and digits).
10770 endofname(const char *name)
10778 if (! is_in_name(*p))
10786 * Called when an unexpected token is read during the parse. The argument
10787 * is the token that is expected, or -1 if more than one type of token can
10788 * occur at this point.
10791 static void synexpect(int token)
10796 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10798 sprintf(msg + l, " (expecting %s)", tokname(token));
10804 synerror(const char *msg)
10806 error("Syntax error: %s", msg);
10812 * called by editline -- any expansions to the prompt
10813 * should be added here.
10816 static void setprompt(int whichprompt)
10818 const char *prompt;
10820 switch (whichprompt) {
10834 static const char *const *findkwd(const char *s)
10836 return bsearch(s, tokname_array + KWDOFFSET,
10837 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
10838 sizeof(const char *), pstrcmp);
10841 /* $NetBSD: redir.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
10844 * Code for dealing with input/output redirection.
10847 #define EMPTY -2 /* marks an unused slot in redirtab */
10849 # define PIPESIZE 4096 /* amount of buffering in a pipe */
10851 # define PIPESIZE PIPE_BUF
10855 * Open a file in noclobber mode.
10856 * The code was copied from bash.
10859 noclobberopen(const char *fname)
10862 struct stat finfo, finfo2;
10865 * If the file exists and is a regular file, return an error
10868 r = stat(fname, &finfo);
10869 if (r == 0 && S_ISREG(finfo.st_mode)) {
10875 * If the file was not present (r != 0), make sure we open it
10876 * exclusively so that if it is created before we open it, our open
10877 * will fail. Make sure that we do not truncate an existing file.
10878 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10879 * file was not a regular file, we leave O_EXCL off.
10882 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10883 fd = open(fname, O_WRONLY|O_CREAT, 0666);
10885 /* If the open failed, return the file descriptor right away. */
10890 * OK, the open succeeded, but the file may have been changed from a
10891 * non-regular file to a regular file between the stat and the open.
10892 * We are assuming that the O_EXCL open handles the case where FILENAME
10893 * did not exist and is symlinked to an existing file between the stat
10898 * If we can open it and fstat the file descriptor, and neither check
10899 * revealed that it was a regular file, and the file has not been
10900 * replaced, return the file descriptor.
10902 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10903 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
10906 /* The file has been replaced. badness. */
10913 * Handle here documents. Normally we fork off a process to write the
10914 * data to a pipe. If the document is short, we can stuff the data in
10915 * the pipe without forking.
10919 openhere(union node *redir)
10925 error("Pipe call failed");
10926 if (redir->type == NHERE) {
10927 len = strlen(redir->nhere.doc->narg.text);
10928 if (len <= PIPESIZE) {
10929 xwrite(pip[1], redir->nhere.doc->narg.text, len);
10933 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
10935 signal(SIGINT, SIG_IGN);
10936 signal(SIGQUIT, SIG_IGN);
10937 signal(SIGHUP, SIG_IGN);
10939 signal(SIGTSTP, SIG_IGN);
10941 signal(SIGPIPE, SIG_DFL);
10942 if (redir->type == NHERE)
10943 xwrite(pip[1], redir->nhere.doc->narg.text, len);
10945 expandhere(redir->nhere.doc, pip[1]);
10954 openredirect(union node *redir)
10959 switch (redir->nfile.type) {
10961 fname = redir->nfile.expfname;
10962 if ((f = open(fname, O_RDONLY)) < 0)
10966 fname = redir->nfile.expfname;
10967 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
10971 /* Take care of noclobber mode. */
10973 fname = redir->nfile.expfname;
10974 if ((f = noclobberopen(fname)) < 0)
10980 fname = redir->nfile.expfname;
10981 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
10985 fname = redir->nfile.expfname;
10986 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
10993 /* Fall through to eliminate warning. */
11000 f = openhere(redir);
11006 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
11008 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11012 dupredirect(union node *redir, int f)
11014 int fd = redir->nfile.fd;
11016 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11017 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
11018 copyfd(redir->ndup.dupfd, fd);
11031 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11032 * old file descriptors are stashed away so that the redirection can be
11033 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11034 * standard output, and the standard error if it becomes a duplicate of
11035 * stdout, is saved in memory.
11039 redirect(union node *redir, int flags)
11042 struct redirtab *sv;
11053 if (flags & REDIR_PUSH) {
11054 struct redirtab *q;
11055 q = ckmalloc(sizeof (struct redirtab));
11056 q->next = redirlist;
11058 q->nullredirs = nullredirs - 1;
11059 for (i = 0 ; i < 10 ; i++)
11060 q->renamed[i] = EMPTY;
11067 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
11068 n->ndup.dupfd == fd)
11069 continue; /* redirect from/to same file descriptor */
11071 newfd = openredirect(n);
11074 if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
11075 i = fcntl(fd, F_DUPFD, 10);
11082 error("%d: %m", fd);
11092 dupredirect(n, newfd);
11093 } while ((n = n->nfile.next));
11095 if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
11096 preverrout_fd = sv->renamed[2];
11101 * Undo the effects of the last redirection.
11107 struct redirtab *rp;
11110 if (--nullredirs >= 0)
11114 for (i = 0 ; i < 10 ; i++) {
11115 if (rp->renamed[i] != EMPTY) {
11118 copyfd(rp->renamed[i], i);
11120 close(rp->renamed[i]);
11123 redirlist = rp->next;
11124 nullredirs = rp->nullredirs;
11130 * Undo all redirections. Called on error or interrupt.
11134 * Discard all saved file descriptors.
11138 clearredir(int drop)
11150 * Copy a file descriptor to be >= to. Returns -1
11151 * if the source file descriptor is closed, EMPTY if there are no unused
11152 * file descriptors left.
11156 copyfd(int from, int to)
11160 newfd = fcntl(from, F_DUPFD, to);
11162 if (errno == EMFILE)
11165 error("%d: %m", from);
11172 redirectsafe(union node *redir, int flags)
11175 volatile int saveint;
11176 struct jmploc *volatile savehandler = handler;
11177 struct jmploc jmploc;
11180 if (!(err = setjmp(jmploc.loc) * 2)) {
11182 redirect(redir, flags);
11184 handler = savehandler;
11185 if (err && exception != EXERROR)
11186 longjmp(handler->loc, 1);
11187 RESTOREINT(saveint);
11191 /* $NetBSD: show.c,v 1.24 2003/01/22 20:36:04 dsl Exp $ */
11194 static void shtree(union node *, int, char *, FILE*);
11195 static void shcmd(union node *, FILE *);
11196 static void sharg(union node *, FILE *);
11197 static void indent(int, char *, FILE *);
11198 static void trstring(char *);
11202 showtree(union node *n)
11204 trputs("showtree called\n");
11205 shtree(n, 1, NULL, stdout);
11210 shtree(union node *n, int ind, char *pfx, FILE *fp)
11212 struct nodelist *lp;
11218 indent(ind, pfx, fp);
11229 shtree(n->nbinary.ch1, ind, NULL, fp);
11232 shtree(n->nbinary.ch2, ind, NULL, fp);
11240 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
11245 if (n->npipe.backgnd)
11251 fprintf(fp, "<node type %d>", n->type);
11260 shcmd(union node *cmd, FILE *fp)
11268 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11274 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11277 switch (np->nfile.type) {
11278 case NTO: s = ">"; dftfd = 1; break;
11279 case NCLOBBER: s = ">|"; dftfd = 1; break;
11280 case NAPPEND: s = ">>"; dftfd = 1; break;
11281 case NTOFD: s = ">&"; dftfd = 1; break;
11282 case NFROM: s = "<"; dftfd = 0; break;
11283 case NFROMFD: s = "<&"; dftfd = 0; break;
11284 case NFROMTO: s = "<>"; dftfd = 0; break;
11285 default: s = "*error*"; dftfd = 0; break;
11287 if (np->nfile.fd != dftfd)
11288 fprintf(fp, "%d", np->nfile.fd);
11290 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11291 fprintf(fp, "%d", np->ndup.dupfd);
11293 sharg(np->nfile.fname, fp);
11302 sharg(union node *arg, FILE *fp)
11305 struct nodelist *bqlist;
11308 if (arg->type != NARG) {
11309 out1fmt("<node type %d>\n", arg->type);
11312 bqlist = arg->narg.backquote;
11313 for (p = arg->narg.text ; *p ; p++) {
11322 if (subtype == VSLENGTH)
11328 if (subtype & VSNUL)
11331 switch (subtype & VSTYPE) {
11350 case VSTRIMLEFTMAX:
11357 case VSTRIMRIGHTMAX:
11364 out1fmt("<subtype %d>", subtype);
11371 case CTLBACKQ|CTLQUOTE:
11374 shtree(bqlist->n, -1, NULL, fp);
11386 indent(int amount, char *pfx, FILE *fp)
11390 for (i = 0 ; i < amount ; i++) {
11391 if (pfx && i == amount - 1)
11412 putc(c, tracefile);
11416 trace(const char *fmt, ...)
11423 (void) vfprintf(tracefile, fmt, va);
11428 tracev(const char *fmt, va_list va)
11432 (void) vfprintf(tracefile, fmt, va);
11437 trputs(const char *s)
11441 fputs(s, tracefile);
11453 putc('"', tracefile);
11454 for (p = s ; *p ; p++) {
11456 case '\n': c = 'n'; goto backslash;
11457 case '\t': c = 't'; goto backslash;
11458 case '\r': c = 'r'; goto backslash;
11459 case '"': c = '"'; goto backslash;
11460 case '\\': c = '\\'; goto backslash;
11461 case CTLESC: c = 'e'; goto backslash;
11462 case CTLVAR: c = 'v'; goto backslash;
11463 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11464 case CTLBACKQ: c = 'q'; goto backslash;
11465 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
11466 backslash: putc('\\', tracefile);
11467 putc(c, tracefile);
11470 if (*p >= ' ' && *p <= '~')
11471 putc(*p, tracefile);
11473 putc('\\', tracefile);
11474 putc(*p >> 6 & 03, tracefile);
11475 putc(*p >> 3 & 07, tracefile);
11476 putc(*p & 07, tracefile);
11481 putc('"', tracefile);
11493 putc(' ', tracefile);
11495 putc('\n', tracefile);
11511 /* leave open because libedit might be using it */
11514 scopy("./trace", s);
11516 if (!freopen(s, "a", tracefile)) {
11517 fprintf(stderr, "Can't re-open %s\n", s);
11522 if ((tracefile = fopen(s, "a")) == NULL) {
11523 fprintf(stderr, "Can't open %s\n", s);
11529 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11530 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11532 setlinebuf(tracefile);
11533 fputs("\nTracing started.\n", tracefile);
11538 /* $NetBSD: trap.c,v 1.28 2002/11/24 22:35:43 christos Exp $ */
11541 * Sigmode records the current value of the signal handlers for the various
11542 * modes. A value of zero means that the current handler is not known.
11543 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
11546 #define S_DFL 1 /* default signal handling (SIG_DFL) */
11547 #define S_CATCH 2 /* signal is caught */
11548 #define S_IGN 3 /* signal is ignored (SIG_IGN) */
11549 #define S_HARD_IGN 4 /* signal is ignored permenantly */
11550 #define S_RESET 5 /* temporary - to reset a hard ignored sig */
11555 * The trap builtin.
11559 trapcmd(int argc, char **argv)
11568 for (signo = 0 ; signo < NSIG ; signo++) {
11569 if (trap[signo] != NULL) {
11572 sn = u_signal_names(0, &signo, 0);
11575 out1fmt("trap -- %s %s\n",
11576 single_quote(trap[signo]), sn);
11586 if ((signo = decode_signal(*ap, 0)) < 0)
11587 error("%s: bad trap", *ap);
11590 if (action[0] == '-' && action[1] == '\0')
11593 action = savestr(action);
11596 ckfree(trap[signo]);
11597 trap[signo] = action;
11608 * Clear traps on a fork.
11616 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
11617 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
11621 if (tp != &trap[0])
11622 setsignal(tp - trap);
11630 * Set the signal handler for the specified signal. The routine figures
11631 * out what it should be set to.
11635 setsignal(int signo)
11639 struct sigaction act;
11641 if ((t = trap[signo]) == NULL)
11643 else if (*t != '\0')
11647 if (rootshell && action == S_DFL) {
11650 if (iflag || minusc || sflag == 0)
11673 t = &sigmode[signo - 1];
11677 * current setting unknown
11679 if (sigaction(signo, 0, &act) == -1) {
11681 * Pretend it worked; maybe we should give a warning
11682 * here, but other shells don't. We don't alter
11683 * sigmode, so that we retry every time.
11687 if (act.sa_handler == SIG_IGN) {
11688 if (mflag && (signo == SIGTSTP ||
11689 signo == SIGTTIN || signo == SIGTTOU)) {
11690 tsig = S_IGN; /* don't hard ignore these */
11694 tsig = S_RESET; /* force to be set */
11697 if (tsig == S_HARD_IGN || tsig == action)
11701 act.sa_handler = onsig;
11704 act.sa_handler = SIG_IGN;
11707 act.sa_handler = SIG_DFL;
11711 sigfillset(&act.sa_mask);
11712 sigaction(signo, &act, 0);
11720 ignoresig(int signo)
11722 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11723 signal(signo, SIG_IGN);
11725 sigmode[signo - 1] = S_HARD_IGN;
11736 gotsig[signo - 1] = 1;
11737 pendingsigs = signo;
11739 if (exsig || (signo == SIGINT && !trap[SIGINT])) {
11748 * Called to execute a trap. Perhaps we should avoid entering new trap
11749 * handlers while we are executing a trap handler.
11759 savestatus = exitstatus;
11761 while (pendingsigs = 0, barrier(), (p = memchr(q, 1, NSIG - 1))) {
11763 p = trap[p - q + 1];
11767 exitstatus = savestatus;
11773 * Controls whether the shell is interactive or not.
11777 setinteractive(int on)
11779 static int is_interactive;
11781 if (++on == is_interactive)
11783 is_interactive = on;
11785 setsignal(SIGQUIT);
11786 setsignal(SIGTERM);
11787 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11788 if(is_interactive > 1) {
11789 /* Looks like they want an interactive shell */
11790 static int do_banner;
11794 "\n\n" BB_BANNER " Built-in shell (ash)\n"
11795 "Enter 'help' for a list of built-in commands.\n\n");
11803 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11804 /*** List the available builtins ***/
11806 static int helpcmd(int argc, char **argv)
11810 out1fmt("\nBuilt-in commands:\n-------------------\n");
11811 for (col = 0, i = 0; i < NUMBUILTINS; i++) {
11812 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11813 builtincmd[i].name + 1);
11819 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
11821 extern const struct BB_applet applets[];
11822 extern const size_t NUM_APPLETS;
11824 for (i = 0; i < NUM_APPLETS; i++) {
11826 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
11835 return EXIT_SUCCESS;
11837 #endif /* CONFIG_FEATURE_SH_EXTRA_QUIET */
11840 * Called to exit the shell.
11851 jmp = setjmp(loc.loc);
11852 status = exitstatus;
11853 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
11857 if ((p = trap[0]) != NULL && *p != '\0') {
11862 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
11863 if (iflag && rootshell) {
11864 const char *hp = lookupvar("HISTFILE");
11867 save_history ( hp );
11875 static int decode_signal(const char *string, int minsig)
11878 const char *name = u_signal_names(string, &signo, minsig);
11880 return name ? signo : -1;
11883 /* $NetBSD: var.c,v 1.32 2003/01/22 20:36:04 dsl Exp $ */
11885 static struct var *vartab[VTABSIZE];
11887 static int vpcmp(const void *, const void *);
11888 static struct var **findvar(struct var **, const char *);
11891 * Initialize the varable symbol tables and import the environment
11895 #ifdef CONFIG_ASH_GETOPTS
11897 * Safe version of setvar, returns 1 on success 0 on failure.
11901 setvarsafe(const char *name, const char *val, int flags)
11904 volatile int saveint;
11905 struct jmploc *volatile savehandler = handler;
11906 struct jmploc jmploc;
11909 if (setjmp(jmploc.loc))
11913 setvar(name, val, flags);
11916 handler = savehandler;
11917 RESTOREINT(saveint);
11923 * Set the value of a variable. The flags argument is ored with the
11924 * flags of the variable. If val is NULL, the variable is unset.
11928 setvar(const char *name, const char *val, int flags)
11935 q = endofname(name);
11936 p = strchrnul(q, '=');
11937 namelen = p - name;
11938 if (!namelen || p != q)
11939 error("%.*s: bad variable name", namelen, name);
11944 vallen = strlen(val);
11947 p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
11951 p = mempcpy(p, val, vallen);
11954 setvareq(nameeq, flags | VNOSAVE);
11960 * Same as setvar except that the variable and value are passed in
11961 * the first argument as name=value. Since the first argument will
11962 * be actually stored in the table, it should not be a string that
11964 * Called with interrupts off.
11968 setvareq(char *s, int flags)
11970 struct var *vp, **vpp;
11973 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
11974 vp = *findvar(vpp, s);
11976 if (vp->flags & VREADONLY) {
11977 if (flags & VNOSAVE)
11979 error("%.*s: is read only", strchrnul(s, '=') - s, s);
11982 if (flags & VNOSET)
11985 if (vp->func && (flags & VNOFUNC) == 0)
11986 (*vp->func)(strchrnul(s, '=') + 1);
11988 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
11991 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
11993 if (flags & VNOSET)
11996 vp = ckmalloc(sizeof (*vp));
12001 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
12009 * Process a linked list of variable assignments.
12013 listsetvar(struct strlist *list_set_var, int flags)
12015 struct strlist *lp = list_set_var;
12021 setvareq(lp->text, flags);
12022 } while ((lp = lp->next));
12028 * Find the value of a variable. Returns NULL if not set.
12032 lookupvar(const char *name)
12036 if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
12037 return strchrnul(v->text, '=') + 1;
12044 * Search the environment of a builtin command.
12048 bltinlookup(const char *name)
12050 struct strlist *sp;
12052 for (sp = cmdenviron ; sp ; sp = sp->next) {
12053 if (varequal(sp->text, name))
12054 return strchrnul(sp->text, '=') + 1;
12056 return lookupvar(name);
12061 * Generate a list of variables satisfying the given conditions.
12065 listvars(int on, int off, char ***end)
12076 for (vp = *vpp ; vp ; vp = vp->next)
12077 if ((vp->flags & mask) == on) {
12078 if (ep == stackstrend())
12079 ep = growstackstr();
12080 *ep++ = (char *) vp->text;
12082 } while (++vpp < vartab + VTABSIZE);
12083 if (ep == stackstrend())
12084 ep = growstackstr();
12088 return grabstackstr(ep);
12093 * POSIX requires that 'set' (but not export or readonly) output the
12094 * variables in lexicographic order - by the locale's collating order (sigh).
12095 * Maybe we could keep them in an ordered balanced binary tree
12096 * instead of hashed lists.
12097 * For now just roll 'em through qsort for printing...
12101 showvars(const char *sep_prefix, int on, int off)
12104 char **ep, **epend;
12106 ep = listvars(on, off, &epend);
12107 qsort(ep, epend - ep, sizeof(char *), vpcmp);
12109 sep = *sep_prefix ? spcstr : sep_prefix;
12111 for (; ep < epend; ep++) {
12115 p = strchrnul(*ep, '=');
12118 q = single_quote(++p);
12120 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
12129 * The export and readonly commands.
12133 exportcmd(int argc, char **argv)
12139 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12142 notp = nextopt("p") - 'p';
12143 if (notp && ((name = *(aptr = argptr)))) {
12145 if ((p = strchr(name, '=')) != NULL) {
12148 if ((vp = *findvar(hashvar(name), name))) {
12153 setvar(name, p, flag);
12154 } while ((name = *++aptr) != NULL);
12156 showvars(argv[0], flag, 0);
12163 * Make a variable a local variable. When a variable is made local, it's
12164 * value and flags are saved in a localvar structure. The saved values
12165 * will be restored when the shell function returns. We handle the name
12166 * "-" as a special case.
12170 mklocal(char *name)
12172 struct localvar *lvp;
12177 lvp = ckmalloc(sizeof (struct localvar));
12178 if (name[0] == '-' && name[1] == '\0') {
12180 p = ckmalloc(sizeof(optlist));
12181 lvp->text = memcpy(p, optlist, sizeof(optlist));
12186 vpp = hashvar(name);
12187 vp = *findvar(vpp, name);
12188 eq = strchr(name, '=');
12191 setvareq(name, VSTRFIXED);
12193 setvar(name, NULL, VSTRFIXED);
12194 vp = *vpp; /* the new variable */
12195 lvp->flags = VUNSET;
12197 lvp->text = vp->text;
12198 lvp->flags = vp->flags;
12199 vp->flags |= VSTRFIXED|VTEXTFIXED;
12205 lvp->next = localvars;
12211 * The "local" command.
12215 localcmd(int argc, char **argv)
12220 while ((name = *argv++) != NULL) {
12228 * Called after a function returns.
12229 * Interrupts must be off.
12235 struct localvar *lvp;
12238 while ((lvp = localvars) != NULL) {
12239 localvars = lvp->next;
12241 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
12242 if (vp == NULL) { /* $- saved */
12243 memcpy(optlist, lvp->text, sizeof(optlist));
12246 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12247 unsetvar(vp->text);
12250 (*vp->func)(strchrnul(lvp->text, '=') + 1);
12251 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12253 vp->flags = lvp->flags;
12254 vp->text = lvp->text;
12262 * The unset builtin command. We unset the function before we unset the
12263 * variable to allow a function to be unset when there is a readonly variable
12264 * with the same name.
12268 unsetcmd(int argc, char **argv)
12275 while ((i = nextopt("vf")) != '\0') {
12279 for (ap = argptr; *ap ; ap++) {
12294 * Unset the specified variable.
12298 unsetvar(const char *s)
12304 vpp = findvar(hashvar(s), s);
12308 int flags = vp->flags;
12311 if (flags & VREADONLY)
12313 if (flags & VUNSET)
12315 if ((flags & VSTRFIXED) == 0) {
12317 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
12324 vp->flags &= ~VEXPORT;
12337 * Find the appropriate entry in the hash table from the name.
12340 static struct var **
12341 hashvar(const char *p)
12343 unsigned int hashval;
12345 hashval = ((unsigned char) *p) << 4;
12346 while (*p && *p != '=')
12347 hashval += (unsigned char) *p++;
12348 return &vartab[hashval % VTABSIZE];
12354 * Compares two strings up to the first = or '\0'. The first
12355 * string must be terminated by '='; the second may be terminated by
12356 * either '=' or '\0'.
12360 varcmp(const char *p, const char *q)
12364 while ((c = *p) == (d = *q)) {
12365 if (!c || c == '=')
12379 vpcmp(const void *a, const void *b)
12381 return varcmp(*(const char **)a, *(const char **)b);
12384 static struct var **
12385 findvar(struct var **vpp, const char *name)
12387 for (; *vpp; vpp = &(*vpp)->next) {
12388 if (varequal((*vpp)->text, name)) {
12394 /* $NetBSD: setmode.c,v 1.29 2003/01/15 23:58:03 kleink Exp $ */
12396 #include <sys/times.h>
12398 static const unsigned char timescmd_str[] = {
12399 ' ', offsetof(struct tms, tms_utime),
12400 '\n', offsetof(struct tms, tms_stime),
12401 ' ', offsetof(struct tms, tms_cutime),
12402 '\n', offsetof(struct tms, tms_cstime),
12406 static int timescmd(int ac, char **av)
12408 long int clk_tck, s, t;
12409 const unsigned char *p;
12412 clk_tck = sysconf(_SC_CLK_TCK);
12417 t = *(clock_t *)(((char *) &buf) + p[1]);
12419 out1fmt("%ldm%ld.%.3lds%c",
12421 ((t - s * clk_tck) * 1000) / clk_tck,
12423 } while (*(p += 2));
12428 #ifdef CONFIG_ASH_MATH_SUPPORT
12430 dash_arith(const char *s)
12436 result = arith(s, &errcode);
12439 error("exponent less than 0");
12440 else if (errcode == -2)
12441 error("divide by zero");
12442 else if (errcode == -5)
12443 error("expression recursion loop detected");
12454 * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12455 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12457 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12461 letcmd(int argc, char **argv)
12468 error("expression expected");
12469 for (ap = argv + 1; *ap; ap++) {
12470 i = dash_arith(*ap);
12475 #endif /* CONFIG_ASH_MATH_SUPPORT */
12477 /* $NetBSD: miscbltin.c,v 1.31 2002/11/24 22:35:41 christos Exp $ */
12480 * Miscelaneous builtins.
12486 #if __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
12487 typedef enum __rlimit_resource rlim_t;
12493 * The read builtin. The -e option causes backslashes to escape the
12494 * following character.
12496 * This uses unbuffered input, which may be avoidable in some cases.
12500 readcmd(int argc, char **argv)
12515 while ((i = nextopt("p:r")) != '\0') {
12517 prompt = optionarg;
12521 if (prompt && isatty(0)) {
12524 if (*(ap = argptr) == NULL)
12525 error("arg count");
12526 if ((ifs = bltinlookup("IFS")) == NULL)
12533 if (read(0, &c, 1) != 1) {
12545 if (!rflag && c == '\\') {
12551 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12555 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12557 setvar(*ap, stackblock(), 0);
12567 /* Remove trailing blanks */
12568 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12570 setvar(*ap, stackblock(), 0);
12571 while (*++ap != NULL)
12572 setvar(*ap, nullstr, 0);
12577 static int umaskcmd(int argc, char **argv)
12579 static const char permuser[3] = "ugo";
12580 static const char permmode[3] = "rwx";
12581 static const short int permmask[] = {
12582 S_IRUSR, S_IWUSR, S_IXUSR,
12583 S_IRGRP, S_IWGRP, S_IXGRP,
12584 S_IROTH, S_IWOTH, S_IXOTH
12590 int symbolic_mode = 0;
12592 while (nextopt("S") != '\0') {
12601 if ((ap = *argptr) == NULL) {
12602 if (symbolic_mode) {
12606 for (i = 0; i < 3; i++) {
12609 *p++ = permuser[i];
12611 for (j = 0; j < 3; j++) {
12612 if ((mask & permmask[3 * i + j]) == 0) {
12613 *p++ = permmode[j];
12621 out1fmt("%.4o\n", mask);
12624 if (is_digit((unsigned char) *ap)) {
12627 if (*ap >= '8' || *ap < '0')
12628 error(illnum, argv[1]);
12629 mask = (mask << 3) + (*ap - '0');
12630 } while (*++ap != '\0');
12633 mask = ~mask & 0777;
12634 if (!bb_parse_mode(ap, &mask)) {
12635 error("Illegal mode: %s", ap);
12637 umask(~mask & 0777);
12646 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12647 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12648 * ash by J.T. Conklin.
12656 int factor; /* multiply by to get rlim_{cur,max} values */
12660 static const struct limits limits[] = {
12662 { "time(seconds)", RLIMIT_CPU, 1, 't' },
12664 #ifdef RLIMIT_FSIZE
12665 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
12668 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
12670 #ifdef RLIMIT_STACK
12671 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
12674 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
12677 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
12679 #ifdef RLIMIT_MEMLOCK
12680 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
12682 #ifdef RLIMIT_NPROC
12683 { "process", RLIMIT_NPROC, 1, 'p' },
12685 #ifdef RLIMIT_NOFILE
12686 { "nofiles", RLIMIT_NOFILE, 1, 'n' },
12689 { "vmemory(kbytes)", RLIMIT_AS, 1024, 'v' },
12691 #ifdef RLIMIT_LOCKS
12692 { "locks", RLIMIT_LOCKS, 1, 'w' },
12694 { (char *) 0, 0, 0, '\0' }
12697 enum limtype { SOFT = 0x1, HARD = 0x2 };
12699 static void printlim(enum limtype how, const struct rlimit *limit,
12700 const struct limits *l)
12704 val = limit->rlim_max;
12706 val = limit->rlim_cur;
12708 if (val == RLIM_INFINITY)
12709 out1fmt("unlimited\n");
12712 out1fmt("%lld\n", (long long) val);
12717 ulimitcmd(int argc, char **argv)
12721 enum limtype how = SOFT | HARD;
12722 const struct limits *l;
12725 struct rlimit limit;
12728 while ((optc = nextopt("HSa"
12732 #ifdef RLIMIT_FSIZE
12738 #ifdef RLIMIT_STACK
12747 #ifdef RLIMIT_MEMLOCK
12750 #ifdef RLIMIT_NPROC
12753 #ifdef RLIMIT_NOFILE
12759 #ifdef RLIMIT_LOCKS
12777 for (l = limits; l->option != what; l++)
12780 set = *argptr ? 1 : 0;
12784 if (all || argptr[1])
12785 error("too many arguments");
12786 if (strncmp(p, "unlimited\n", 9) == 0)
12787 val = RLIM_INFINITY;
12791 while ((c = *p++) >= '0' && c <= '9')
12793 val = (val * 10) + (long)(c - '0');
12794 if (val < (rlim_t) 0)
12798 error("bad number");
12803 for (l = limits; l->name; l++) {
12804 getrlimit(l->cmd, &limit);
12805 out1fmt("%-20s ", l->name);
12806 printlim(how, &limit, l);
12811 getrlimit(l->cmd, &limit);
12814 limit.rlim_max = val;
12816 limit.rlim_cur = val;
12817 if (setrlimit(l->cmd, &limit) < 0)
12818 error("error setting limit (%m)");
12820 printlim(how, &limit, l);
12826 #ifdef CONFIG_ASH_MATH_SUPPORT
12828 /* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
12830 Permission is hereby granted, free of charge, to any person obtaining
12831 a copy of this software and associated documentation files (the
12832 "Software"), to deal in the Software without restriction, including
12833 without limitation the rights to use, copy, modify, merge, publish,
12834 distribute, sublicense, and/or sell copies of the Software, and to
12835 permit persons to whom the Software is furnished to do so, subject to
12836 the following conditions:
12838 The above copyright notice and this permission notice shall be
12839 included in all copies or substantial portions of the Software.
12841 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12842 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12843 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
12844 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
12845 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
12846 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
12847 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12850 /* This is my infix parser/evaluator. It is optimized for size, intended
12851 * as a replacement for yacc-based parsers. However, it may well be faster
12852 * than a comparable parser writen in yacc. The supported operators are
12853 * listed in #defines below. Parens, order of operations, and error handling
12854 * are supported. This code is threadsafe. The exact expression format should
12855 * be that which POSIX specifies for shells. */
12857 /* The code uses a simple two-stack algorithm. See
12858 * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
12859 * for a detailed explaination of the infix-to-postfix algorithm on which
12860 * this is based (this code differs in that it applies operators immediately
12861 * to the stack instead of adding them to a queue to end up with an
12864 /* To use the routine, call it with an expression string and error return
12868 * Aug 24, 2001 Manuel Novoa III
12870 * Reduced the generated code size by about 30% (i386) and fixed several bugs.
12872 * 1) In arith_apply():
12873 * a) Cached values of *numptr and &(numptr[-1]).
12874 * b) Removed redundant test for zero denominator.
12877 * a) Eliminated redundant code for processing operator tokens by moving
12878 * to a table-based implementation. Also folded handling of parens
12880 * b) Combined all 3 loops which called arith_apply to reduce generated
12881 * code size at the cost of speed.
12883 * 3) The following expressions were treated as valid by the original code:
12884 * 1() , 0! , 1 ( *3 ) .
12885 * These bugs have been fixed by internally enclosing the expression in
12886 * parens and then checking that all binary ops and right parens are
12887 * preceded by a valid expression (NUM_TOKEN).
12889 * Note: It may be desireable to replace Aaron's test for whitespace with
12890 * ctype's isspace() if it is used by another busybox applet or if additional
12891 * whitespace chars should be considered. Look below the "#include"s for a
12892 * precompiler test.
12896 * Aug 26, 2001 Manuel Novoa III
12898 * Return 0 for null expressions. Pointed out by Vladimir Oleynik.
12900 * Merge in Aaron's comments previously posted to the busybox list,
12901 * modified slightly to take account of my changes to the code.
12906 * (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12908 * - allow access to variable,
12909 * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
12910 * - realize assign syntax (VAR=expr, +=, *= etc)
12911 * - realize exponentiation (** operator)
12912 * - realize comma separated - expr, expr
12913 * - realise ++expr --expr expr++ expr--
12914 * - realise expr ? expr : expr (but, second expr calculate always)
12915 * - allow hexdecimal and octal numbers
12916 * - was restored loses XOR operator
12917 * - remove one goto label, added three ;-)
12918 * - protect $((num num)) as true zero expr (Manuel`s error)
12919 * - always use special isspace(), see comment from bash ;-)
12923 #define arith_isspace(arithval) \
12924 (arithval == ' ' || arithval == '\n' || arithval == '\t')
12927 typedef unsigned char operator;
12929 /* An operator's token id is a bit of a bitfield. The lower 5 bits are the
12930 * precedence, and 3 high bits are an ID unique accross operators of that
12931 * precedence. The ID portion is so that multiple operators can have the
12932 * same precedence, ensuring that the leftmost one is evaluated first.
12933 * Consider * and /. */
12935 #define tok_decl(prec,id) (((id)<<5)|(prec))
12936 #define PREC(op) ((op) & 0x1F)
12938 #define TOK_LPAREN tok_decl(0,0)
12940 #define TOK_COMMA tok_decl(1,0)
12942 #define TOK_ASSIGN tok_decl(2,0)
12943 #define TOK_AND_ASSIGN tok_decl(2,1)
12944 #define TOK_OR_ASSIGN tok_decl(2,2)
12945 #define TOK_XOR_ASSIGN tok_decl(2,3)
12946 #define TOK_PLUS_ASSIGN tok_decl(2,4)
12947 #define TOK_MINUS_ASSIGN tok_decl(2,5)
12948 #define TOK_LSHIFT_ASSIGN tok_decl(2,6)
12949 #define TOK_RSHIFT_ASSIGN tok_decl(2,7)
12951 #define TOK_MUL_ASSIGN tok_decl(3,0)
12952 #define TOK_DIV_ASSIGN tok_decl(3,1)
12953 #define TOK_REM_ASSIGN tok_decl(3,2)
12955 /* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
12956 #define convert_prec_is_assing(prec) do { if(prec == 3) prec = 2; } while(0)
12958 /* conditional is right associativity too */
12959 #define TOK_CONDITIONAL tok_decl(4,0)
12960 #define TOK_CONDITIONAL_SEP tok_decl(4,1)
12962 #define TOK_OR tok_decl(5,0)
12964 #define TOK_AND tok_decl(6,0)
12966 #define TOK_BOR tok_decl(7,0)
12968 #define TOK_BXOR tok_decl(8,0)
12970 #define TOK_BAND tok_decl(9,0)
12972 #define TOK_EQ tok_decl(10,0)
12973 #define TOK_NE tok_decl(10,1)
12975 #define TOK_LT tok_decl(11,0)
12976 #define TOK_GT tok_decl(11,1)
12977 #define TOK_GE tok_decl(11,2)
12978 #define TOK_LE tok_decl(11,3)
12980 #define TOK_LSHIFT tok_decl(12,0)
12981 #define TOK_RSHIFT tok_decl(12,1)
12983 #define TOK_ADD tok_decl(13,0)
12984 #define TOK_SUB tok_decl(13,1)
12986 #define TOK_MUL tok_decl(14,0)
12987 #define TOK_DIV tok_decl(14,1)
12988 #define TOK_REM tok_decl(14,2)
12990 /* exponent is right associativity */
12991 #define TOK_EXPONENT tok_decl(15,1)
12993 /* For now unary operators. */
12994 #define UNARYPREC 16
12995 #define TOK_BNOT tok_decl(UNARYPREC,0)
12996 #define TOK_NOT tok_decl(UNARYPREC,1)
12998 #define TOK_UMINUS tok_decl(UNARYPREC+1,0)
12999 #define TOK_UPLUS tok_decl(UNARYPREC+1,1)
13001 #define PREC_PRE (UNARYPREC+2)
13003 #define TOK_PRE_INC tok_decl(PREC_PRE, 0)
13004 #define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
13006 #define PREC_POST (UNARYPREC+3)
13008 #define TOK_POST_INC tok_decl(PREC_POST, 0)
13009 #define TOK_POST_DEC tok_decl(PREC_POST, 1)
13011 #define SPEC_PREC (UNARYPREC+4)
13013 #define TOK_NUM tok_decl(SPEC_PREC, 0)
13014 #define TOK_RPAREN tok_decl(SPEC_PREC, 1)
13016 #define NUMPTR (*numstackptr)
13018 static inline int tok_have_assign(operator op)
13020 operator prec = PREC(op);
13022 convert_prec_is_assing(prec);
13023 return (prec == PREC(TOK_ASSIGN) ||
13024 prec == PREC_PRE || prec == PREC_POST);
13027 static inline int is_right_associativity(operator prec)
13029 return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) ||
13030 prec == PREC(TOK_CONDITIONAL));
13034 typedef struct ARITCH_VAR_NUM {
13036 long contidional_second_val;
13037 char contidional_second_val_initialized;
13038 char *var; /* if NULL then is regular number,
13039 else is varable name */
13043 typedef struct CHK_VAR_RECURSIVE_LOOPED {
13045 struct CHK_VAR_RECURSIVE_LOOPED *next;
13046 } chk_var_recursive_looped_t;
13048 static chk_var_recursive_looped_t *prev_chk_var_recursive;
13051 static int arith_lookup_val(v_n_t *t)
13054 const char * p = lookupvar(t->var);
13059 /* recursive try as expression */
13060 chk_var_recursive_looped_t *cur;
13061 chk_var_recursive_looped_t cur_save;
13063 for(cur = prev_chk_var_recursive; cur; cur = cur->next) {
13064 if(strcmp(cur->var, t->var) == 0) {
13065 /* expression recursion loop detected */
13069 /* save current lookuped var name */
13070 cur = prev_chk_var_recursive;
13071 cur_save.var = t->var;
13072 cur_save.next = cur;
13073 prev_chk_var_recursive = &cur_save;
13075 t->val = arith (p, &errcode);
13076 /* restore previous ptr after recursiving */
13077 prev_chk_var_recursive = cur;
13080 /* allow undefined var as 0 */
13087 /* "applying" a token means performing it on the top elements on the integer
13088 * stack. For a unary operator it will only change the top element, but a
13089 * binary operator will pop two arguments and push a result */
13091 arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
13096 int ret_arith_lookup_val;
13098 if (NUMPTR == numstack) goto err; /* There is no operator that can work
13099 without arguments */
13100 numptr_m1 = NUMPTR - 1;
13102 /* check operand is var with noninteger value */
13103 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13104 if(ret_arith_lookup_val)
13105 return ret_arith_lookup_val;
13107 rez = numptr_m1->val;
13108 if (op == TOK_UMINUS)
13110 else if (op == TOK_NOT)
13112 else if (op == TOK_BNOT)
13114 else if (op == TOK_POST_INC || op == TOK_PRE_INC)
13116 else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
13118 else if (op != TOK_UPLUS) {
13119 /* Binary operators */
13121 /* check and binary operators need two arguments */
13122 if (numptr_m1 == numstack) goto err;
13124 /* ... and they pop one */
13127 if (op == TOK_CONDITIONAL) {
13128 if(! numptr_m1->contidional_second_val_initialized) {
13129 /* protect $((expr1 ? expr2)) without ": expr" */
13132 rez = numptr_m1->contidional_second_val;
13133 } else if(numptr_m1->contidional_second_val_initialized) {
13134 /* protect $((expr1 : expr2)) without "expr ? " */
13137 numptr_m1 = NUMPTR - 1;
13138 if(op != TOK_ASSIGN) {
13139 /* check operand is var with noninteger value for not '=' */
13140 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13141 if(ret_arith_lookup_val)
13142 return ret_arith_lookup_val;
13144 if (op == TOK_CONDITIONAL) {
13145 numptr_m1->contidional_second_val = rez;
13147 rez = numptr_m1->val;
13148 if (op == TOK_BOR || op == TOK_OR_ASSIGN)
13150 else if (op == TOK_OR)
13151 rez = numptr_val || rez;
13152 else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
13154 else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
13156 else if (op == TOK_AND)
13157 rez = rez && numptr_val;
13158 else if (op == TOK_EQ)
13159 rez = (rez == numptr_val);
13160 else if (op == TOK_NE)
13161 rez = (rez != numptr_val);
13162 else if (op == TOK_GE)
13163 rez = (rez >= numptr_val);
13164 else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
13165 rez >>= numptr_val;
13166 else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
13167 rez <<= numptr_val;
13168 else if (op == TOK_GT)
13169 rez = (rez > numptr_val);
13170 else if (op == TOK_LT)
13171 rez = (rez < numptr_val);
13172 else if (op == TOK_LE)
13173 rez = (rez <= numptr_val);
13174 else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
13176 else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
13178 else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
13180 else if (op == TOK_ASSIGN || op == TOK_COMMA)
13182 else if (op == TOK_CONDITIONAL_SEP) {
13183 if (numptr_m1 == numstack) {
13184 /* protect $((expr : expr)) without "expr ? " */
13187 numptr_m1->contidional_second_val_initialized = op;
13188 numptr_m1->contidional_second_val = numptr_val;
13190 else if (op == TOK_CONDITIONAL) {
13192 numptr_val : numptr_m1->contidional_second_val;
13194 else if(op == TOK_EXPONENT) {
13196 return -3; /* exponent less than 0 */
13201 while(numptr_val--)
13206 else if(numptr_val==0) /* zero divisor check */
13208 else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
13210 else if (op == TOK_REM || op == TOK_REM_ASSIGN)
13213 if(tok_have_assign(op)) {
13216 if(numptr_m1->var == NULL) {
13220 /* save to shell variable */
13221 sprintf(buf, "%ld", rez);
13222 setvar(numptr_m1->var, buf, 0);
13223 /* after saving, make previous value for v++ or v-- */
13224 if(op == TOK_POST_INC)
13226 else if(op == TOK_POST_DEC)
13229 numptr_m1->val = rez;
13230 /* protect geting var value, is number now */
13231 numptr_m1->var = NULL;
13236 /* longest must first */
13237 static const char op_tokens[] = {
13238 '<','<','=',0, TOK_LSHIFT_ASSIGN,
13239 '>','>','=',0, TOK_RSHIFT_ASSIGN,
13240 '<','<', 0, TOK_LSHIFT,
13241 '>','>', 0, TOK_RSHIFT,
13242 '|','|', 0, TOK_OR,
13243 '&','&', 0, TOK_AND,
13244 '!','=', 0, TOK_NE,
13245 '<','=', 0, TOK_LE,
13246 '>','=', 0, TOK_GE,
13247 '=','=', 0, TOK_EQ,
13248 '|','=', 0, TOK_OR_ASSIGN,
13249 '&','=', 0, TOK_AND_ASSIGN,
13250 '*','=', 0, TOK_MUL_ASSIGN,
13251 '/','=', 0, TOK_DIV_ASSIGN,
13252 '%','=', 0, TOK_REM_ASSIGN,
13253 '+','=', 0, TOK_PLUS_ASSIGN,
13254 '-','=', 0, TOK_MINUS_ASSIGN,
13255 '-','-', 0, TOK_POST_DEC,
13256 '^','=', 0, TOK_XOR_ASSIGN,
13257 '+','+', 0, TOK_POST_INC,
13258 '*','*', 0, TOK_EXPONENT,
13262 '=', 0, TOK_ASSIGN,
13274 '?', 0, TOK_CONDITIONAL,
13275 ':', 0, TOK_CONDITIONAL_SEP,
13276 ')', 0, TOK_RPAREN,
13277 '(', 0, TOK_LPAREN,
13281 #define endexpression &op_tokens[sizeof(op_tokens)-7]
13284 extern long arith (const char *expr, int *perrcode)
13286 register char arithval; /* Current character under analysis */
13287 operator lasttok, op;
13290 const char *p = endexpression;
13293 size_t datasizes = strlen(expr) + 2;
13295 /* Stack of integers */
13296 /* The proof that there can be no more than strlen(startbuf)/2+1 integers
13297 * in any given correct or incorrect expression is left as an excersize to
13299 v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
13300 *numstackptr = numstack;
13301 /* Stack of operator tokens */
13302 operator *stack = alloca((datasizes) * sizeof(operator)),
13305 *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */
13306 *perrcode = errcode = 0;
13309 if ((arithval = *expr) == 0) {
13310 if (p == endexpression) {
13311 /* Null expression. */
13315 /* This is only reached after all tokens have been extracted from the
13316 * input stream. If there are still tokens on the operator stack, they
13317 * are to be applied in order. At the end, there should be a final
13318 * result on the integer stack */
13320 if (expr != endexpression + 1) {
13321 /* If we haven't done so already, */
13322 /* append a closing right paren */
13323 expr = endexpression;
13324 /* and let the loop process it. */
13327 /* At this point, we're done with the expression. */
13328 if (numstackptr != numstack+1) {
13329 /* ... but if there isn't, it's bad */
13331 return (*perrcode = -1);
13333 if(numstack->var) {
13334 /* expression is $((var)) only, lookup now */
13335 errcode = arith_lookup_val(numstack);
13338 *perrcode = errcode;
13339 return numstack->val;
13341 /* Continue processing the expression. */
13342 if (arith_isspace(arithval)) {
13343 /* Skip whitespace */
13346 if((p = endofname(expr)) != expr) {
13347 int var_name_size = (p-expr) + 1; /* trailing zero */
13349 numstackptr->var = alloca(var_name_size);
13350 safe_strncpy(numstackptr->var, expr, var_name_size);
13353 numstackptr->contidional_second_val_initialized = 0;
13357 } else if (is_digit(arithval)) {
13358 numstackptr->var = NULL;
13359 numstackptr->val = strtol(expr, (char **) &expr, 0);
13362 for(p = op_tokens; ; p++) {
13366 /* strange operator not found */
13369 for(o = expr; *p && *o == *p; p++)
13376 /* skip tail uncompared token */
13379 /* skip zero delim */
13384 /* post grammar: a++ reduce to num */
13385 if(lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13388 /* Plus and minus are binary (not unary) _only_ if the last
13389 * token was as number, or a right paren (which pretends to be
13390 * a number, since it evaluates to one). Think about it.
13391 * It makes sense. */
13392 if (lasttok != TOK_NUM) {
13408 /* We don't want a unary operator to cause recursive descent on the
13409 * stack, because there can be many in a row and it could cause an
13410 * operator to be evaluated before its argument is pushed onto the
13411 * integer stack. */
13412 /* But for binary operators, "apply" everything on the operator
13413 * stack until we find an operator with a lesser priority than the
13414 * one we have just extracted. */
13415 /* Left paren is given the lowest priority so it will never be
13416 * "applied" in this way.
13417 * if associativity is right and priority eq, applied also skip
13420 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13421 /* not left paren or unary */
13422 if (lasttok != TOK_NUM) {
13423 /* binary op must be preceded by a num */
13426 while (stackptr != stack) {
13427 if (op == TOK_RPAREN) {
13428 /* The algorithm employed here is simple: while we don't
13429 * hit an open paren nor the bottom of the stack, pop
13430 * tokens and apply them */
13431 if (stackptr[-1] == TOK_LPAREN) {
13433 /* Any operator directly after a */
13435 /* close paren should consider itself binary */
13439 operator prev_prec = PREC(stackptr[-1]);
13441 convert_prec_is_assing(prec);
13442 convert_prec_is_assing(prev_prec);
13443 if (prev_prec < prec)
13445 /* check right assoc */
13446 if(prev_prec == prec && is_right_associativity(prec))
13449 errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13450 if(errcode) goto ret;
13452 if (op == TOK_RPAREN) {
13457 /* Push this operator to the stack and remember it. */
13458 *stackptr++ = lasttok = op;
13465 #endif /* CONFIG_ASH_MATH_SUPPORT */
13469 const char *bb_applet_name = "debug stuff usage";
13470 int main(int argc, char **argv)
13472 return ash_main(argc, argv);
13477 * Copyright (c) 1989, 1991, 1993, 1994
13478 * The Regents of the University of California. All rights reserved.
13480 * This code is derived from software contributed to Berkeley by
13481 * Kenneth Almquist.
13483 * Redistribution and use in source and binary forms, with or without
13484 * modification, are permitted provided that the following conditions
13486 * 1. Redistributions of source code must retain the above copyright
13487 * notice, this list of conditions and the following disclaimer.
13488 * 2. Redistributions in binary form must reproduce the above copyright
13489 * notice, this list of conditions and the following disclaimer in the
13490 * documentation and/or other materials provided with the distribution.
13492 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
13493 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
13495 * 4. Neither the name of the University nor the names of its contributors
13496 * may be used to endorse or promote products derived from this software
13497 * without specific prior written permission.
13499 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13500 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13501 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13502 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13503 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13504 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13505 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13506 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13507 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13508 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF