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 * This code is derived from software contributed to Berkeley by
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 * This version of ash is adapted from the source in Debian's ash 0.3.8-5
27 * Maintainer Herbert Xu <herbert@debian.org> (C) 1997-2002
29 * Modified by Vladimir Oleynik <dzo@simtreas.ru> to be used in busybox
32 * Original copyright notice is retained at the end of this file.
36 * The follow should be set to reflect the type of system you have:
37 * JOBS -> 1 if you have Berkeley job control, 0 otherwise.
38 * define SYSV if you are running under System V.
39 * define DEBUG=1 to compile in debugging ('set -o debug' to turn on)
40 * define DEBUG=2 to compile in and turn on debugging.
42 * When debugging is on, debugging info will be written to ./trace and
43 * a quit signal will generate a core dump.
56 #include <sys/types.h>
57 #include <sys/cdefs.h>
58 #include <sys/ioctl.h>
59 #include <sys/param.h>
60 #include <sys/resource.h>
92 #ifdef CONFIG_ASH_JOB_CONTROL
106 static int *dash_errno;
108 #define errno (*dash_errno)
111 #if defined(__uClinux__)
112 #error "Do not even bother, ash will not run on uClinux"
116 #define _DIAGASSERT(assert_expr) assert(assert_expr)
118 #define _DIAGASSERT(assert_expr)
122 #ifdef CONFIG_ASH_ALIAS
123 /* $NetBSD: alias.h,v 1.5 2002/11/24 22:35:38 christos Exp $ */
135 static struct alias *lookupalias(const char *, int);
136 static int aliascmd(int, char **);
137 static int unaliascmd(int, char **);
138 static void rmaliases(void);
139 static int unalias(const char *);
140 static void printalias(const struct alias *);
143 /* $NetBSD: cd.h,v 1.3 2002/11/24 22:35:39 christos Exp $ */
146 static void setpwd(const char *, int);
148 /* $NetBSD: error.h,v 1.15 2002/11/24 22:35:39 christos Exp $ */
152 * Types of operations (passed to the errmsg routine).
156 static const char not_found_msg[] = "%s: not found";
159 #define E_OPEN "No such file" /* opening a file */
160 #define E_CREAT "Directory nonexistent" /* creating a file */
161 #define E_EXEC not_found_msg+4 /* executing a program */
164 * We enclose jmp_buf in a structure so that we can declare pointers to
165 * jump locations. The global variable handler contains the location to
166 * jump to when an exception occurs, and the global variable exception
167 * contains a code identifying the exeception. To implement nested
168 * exception handlers, the user should save the value of handler on entry
169 * to an inner scope, set handler to point to a jmploc structure for the
170 * inner scope, and restore handler on exit from the scope.
177 static struct jmploc *handler;
178 static int exception;
179 static volatile int suppressint;
180 static volatile sig_atomic_t intpending;
182 static int exerrno; /* Last exec error, error for EXEXEC */
185 #define EXINT 0 /* SIGINT received */
186 #define EXERROR 1 /* a generic error */
187 #define EXSHELLPROC 2 /* execute a shell procedure */
188 #define EXEXEC 3 /* command execution failed */
189 #define EXEXIT 4 /* exit the shell */
190 #define EXSIG 5 /* trapped signal in wait(1) */
193 /* do we generate EXSIG events */
195 /* last pending signal */
196 static volatile sig_atomic_t pendingsigs;
199 * These macros allow the user to suspend the handling of interrupt signals
200 * over a period of time. This is similar to SIGHOLD to or sigblock, but
201 * much more efficient and portable. (But hacking the kernel is so much
202 * more fun than worrying about efficiency and portability. :-))
205 #define barrier() ({ __asm__ __volatile__ ("": : :"memory"); })
212 #define SAVEINT(v) ((v) = suppressint)
213 #define RESTOREINT(v) \
216 if ((suppressint = (v)) == 0 && intpending) onint(); \
227 /* EXSIG is turned off by evalbltin(). */
230 static void exraise(int) __attribute__((__noreturn__));
231 static void onint(void) __attribute__((__noreturn__));
233 static void error(const char *, ...) __attribute__((__noreturn__));
234 static void exerror(int, const char *, ...) __attribute__((__noreturn__));
236 static void sh_warnx(const char *, ...);
238 #ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
241 if (--suppressint == 0 && intpending) {
245 #define INTON inton()
246 static void forceinton(void)
252 #define FORCEINTON forceinton()
257 if (--suppressint == 0 && intpending) onint(); \
264 if (intpending) onint(); \
267 #endif /* CONFIG_ASH_OPTIMIZE_FOR_SIZE */
270 * BSD setjmp saves the signal mask, which violates ANSI C and takes time,
271 * so we use _setjmp instead.
274 #if defined(BSD) && !defined(__SVR4) && !defined(__GLIBC__)
275 #define setjmp(jmploc) _setjmp(jmploc)
276 #define longjmp(jmploc, val) _longjmp(jmploc, val)
279 /* $NetBSD: expand.h,v 1.13 2002/11/24 22:35:40 christos Exp $ */
282 struct strlist *next;
288 struct strlist *list;
289 struct strlist **lastp;
295 #define EXP_FULL 0x1 /* perform word splitting & file globbing */
296 #define EXP_TILDE 0x2 /* do normal tilde expansion */
297 #define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
298 #define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
299 #define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
300 #define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
301 #define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
302 #define EXP_WORD 0x80 /* expand word in parameter expansion */
303 #define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */
307 static void expandarg(union node *, struct arglist *, int);
308 #define rmescapes(p) _rmescapes((p), 0)
309 static char *_rmescapes(char *, int);
310 static int casematch(union node *, char *);
312 #ifdef CONFIG_ASH_MATH_SUPPORT
313 static void expari(int);
316 /* $NetBSD: eval.h,v 1.13 2002/11/24 22:35:39 christos Exp $ */
318 static char *commandname; /* currently executing command */
319 static struct strlist *cmdenviron; /* environment for builtin command */
320 static int exitstatus; /* exit status of last command */
321 static int back_exitstatus; /* exit status of backquoted command */
324 struct backcmd { /* result of evalbackcmd */
325 int fd; /* file descriptor to read from */
326 char *buf; /* buffer */
327 int nleft; /* number of chars in buffer */
328 struct job *jp; /* job structure for command */
332 * This file was generated by the mknodes program.
368 union node *redirect;
375 struct nodelist *cmdlist;
382 union node *redirect;
397 union node *elsepart;
428 struct nodelist *backquote;
468 struct nredir nredir;
469 struct nbinary nbinary;
473 struct nclist nclist;
483 struct nodelist *next;
494 static void freefunc(struct funcnode *);
495 /* $NetBSD: parser.h,v 1.15 2002/11/24 22:35:42 christos Exp $ */
497 /* control characters in argument strings */
498 #define CTL_FIRST '\201' /* first 'special' character */
499 #define CTLESC '\201' /* escape next character */
500 #define CTLVAR '\202' /* variable defn */
501 #define CTLENDVAR '\203'
502 #define CTLBACKQ '\204'
503 #define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
504 /* CTLBACKQ | CTLQUOTE == '\205' */
505 #define CTLARI '\206' /* arithmetic expression */
506 #define CTLENDARI '\207'
507 #define CTLQUOTEMARK '\210'
508 #define CTL_LAST '\210' /* last 'special' character */
510 /* variable substitution byte (follows CTLVAR) */
511 #define VSTYPE 0x0f /* type of variable substitution */
512 #define VSNUL 0x10 /* colon--treat the empty string as unset */
513 #define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
515 /* values of VSTYPE field */
516 #define VSNORMAL 0x1 /* normal variable: $var or ${var} */
517 #define VSMINUS 0x2 /* ${var-text} */
518 #define VSPLUS 0x3 /* ${var+text} */
519 #define VSQUESTION 0x4 /* ${var?message} */
520 #define VSASSIGN 0x5 /* ${var=text} */
521 #define VSTRIMRIGHT 0x6 /* ${var%pattern} */
522 #define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
523 #define VSTRIMLEFT 0x8 /* ${var#pattern} */
524 #define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
525 #define VSLENGTH 0xa /* ${#var} */
527 /* values of checkkwd variable */
532 #define IBUFSIZ (BUFSIZ + 1)
535 * NEOF is returned by parsecmd when it encounters an end of file. It
536 * must be distinct from NULL, so we use the address of a variable that
537 * happens to be handy.
539 static int plinno = 1; /* input line number */
541 /* number of characters left in input buffer */
542 static int parsenleft; /* copy of parsefile->nleft */
543 static int parselleft; /* copy of parsefile->lleft */
545 /* next character in input buffer */
546 static char *parsenextc; /* copy of parsefile->nextc */
547 static struct parsefile basepf; /* top level input file */
548 static char basebuf[IBUFSIZ]; /* buffer for top level input file */
549 static struct parsefile *parsefile = &basepf; /* current input file */
552 static int tokpushback; /* last token pushed back */
553 #define NEOF ((union node *)&tokpushback)
554 static int parsebackquote; /* nonzero if we are inside backquotes */
555 static int doprompt; /* if set, prompt the user */
556 static int needprompt; /* true if interactive and at start of line */
557 static int lasttoken; /* last token read */
558 static char *wordtext; /* text of last word returned by readtoken */
560 static struct nodelist *backquotelist;
561 static union node *redirnode;
562 static struct heredoc *heredoc;
563 static int quoteflag; /* set if (part of) last token was quoted */
564 static int startlinno; /* line # where last token started */
566 static union node *parsecmd(int);
567 static void fixredir(union node *, const char *, int);
568 static const char *const *findkwd(const char *);
569 static char *endofname(const char *);
571 /* $NetBSD: shell.h,v 1.16 2003/01/22 20:36:04 dsl Exp $ */
573 typedef void *pointer;
575 static char nullstr[1]; /* zero length string */
576 static const char spcstr[] = " ";
577 static const char snlfmt[] = "%s\n";
578 static const char dolatstr[] = { CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' };
579 static const char illnum[] = "Illegal number: %s";
580 static const char homestr[] = "HOME";
583 #define TRACE(param) trace param
584 #define TRACEV(param) tracev param
587 #define TRACEV(param)
590 #if defined(__GNUC__) && __GNUC__ < 3
591 #define va_copy __va_copy
594 #if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
595 #define __builtin_expect(x, expected_value) (x)
598 #define likely(x) __builtin_expect((x),1)
599 #define unlikely(x) __builtin_expect((x),0)
613 #define TENDBQUOTE 12
631 /* first char is indicating which tokens mark the end of a list */
632 static const char *const tokname_array[] = {
647 /* the following are keywords */
666 static const char *tokname(int tok)
672 sprintf(buf + (tok >= TSEMI), "%s%c",
673 tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));
677 /* $NetBSD: machdep.h,v 1.10 2002/10/07 14:26:08 christos Exp $ */
680 * Most machines require the value returned from malloc to be aligned
681 * in some way. The following macro will get this right on many machines.
684 #define SHELL_SIZE (sizeof(union {int i; char *cp; double d; }) - 1)
686 * It appears that grabstackstr() will barf with such alignments
687 * because stalloc() will return a string allocated in a new stackblock.
689 #define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
692 * This file was generated by the mksyntax program.
697 #define CWORD 0 /* character is nothing special */
698 #define CNL 1 /* newline character */
699 #define CBACK 2 /* a backslash character */
700 #define CSQUOTE 3 /* single quote */
701 #define CDQUOTE 4 /* double quote */
702 #define CENDQUOTE 5 /* a terminating quote */
703 #define CBQUOTE 6 /* backwards single quote */
704 #define CVAR 7 /* a dollar sign */
705 #define CENDVAR 8 /* a '}' character */
706 #define CLP 9 /* a left paren in arithmetic */
707 #define CRP 10 /* a right paren in arithmetic */
708 #define CENDFILE 11 /* end of file */
709 #define CCTL 12 /* like CWORD, except it must be escaped */
710 #define CSPCL 13 /* these terminate a word */
711 #define CIGN 14 /* character should be ignored */
713 #ifdef CONFIG_ASH_ALIAS
717 #define PEOA_OR_PEOF PEOA
721 #define PEOA_OR_PEOF PEOF
724 #define is_digit(c) ((unsigned)((c) - '0') <= 9)
725 #define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
726 #define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
729 * is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
730 * (assuming ascii char codes, as the original implementation did)
732 #define is_special(c) \
733 ( (((unsigned int)c) - 33 < 32) \
734 && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
736 #define digit_val(c) ((c) - '0')
739 * This file was generated by the mksyntax program.
742 #ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
743 #define USE_SIT_FUNCTION
746 /* number syntax index */
747 #define BASESYNTAX 0 /* not in quotes */
748 #define DQSYNTAX 1 /* in double quotes */
749 #define SQSYNTAX 2 /* in single quotes */
750 #define ARISYNTAX 3 /* in arithmetic */
752 #ifdef CONFIG_ASH_MATH_SUPPORT
753 static const char S_I_T[][4] = {
754 #ifdef CONFIG_ASH_ALIAS
755 {CSPCL, CIGN, CIGN, CIGN}, /* 0, PEOA */
757 {CSPCL, CWORD, CWORD, CWORD}, /* 1, ' ' */
758 {CNL, CNL, CNL, CNL}, /* 2, \n */
759 {CWORD, CCTL, CCTL, CWORD}, /* 3, !*-/:=?[]~ */
760 {CDQUOTE, CENDQUOTE, CWORD, CWORD}, /* 4, '"' */
761 {CVAR, CVAR, CWORD, CVAR}, /* 5, $ */
762 {CSQUOTE, CWORD, CENDQUOTE, CWORD}, /* 6, "'" */
763 {CSPCL, CWORD, CWORD, CLP}, /* 7, ( */
764 {CSPCL, CWORD, CWORD, CRP}, /* 8, ) */
765 {CBACK, CBACK, CCTL, CBACK}, /* 9, \ */
766 {CBQUOTE, CBQUOTE, CWORD, CBQUOTE}, /* 10, ` */
767 {CENDVAR, CENDVAR, CWORD, CENDVAR}, /* 11, } */
768 #ifndef USE_SIT_FUNCTION
769 {CENDFILE, CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */
770 {CWORD, CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */
771 {CCTL, CCTL, CCTL, CCTL} /* 14, CTLESC ... */
775 static const char S_I_T[][3] = {
776 #ifdef CONFIG_ASH_ALIAS
777 {CSPCL, CIGN, CIGN}, /* 0, PEOA */
779 {CSPCL, CWORD, CWORD}, /* 1, ' ' */
780 {CNL, CNL, CNL}, /* 2, \n */
781 {CWORD, CCTL, CCTL}, /* 3, !*-/:=?[]~ */
782 {CDQUOTE, CENDQUOTE, CWORD}, /* 4, '"' */
783 {CVAR, CVAR, CWORD}, /* 5, $ */
784 {CSQUOTE, CWORD, CENDQUOTE}, /* 6, "'" */
785 {CSPCL, CWORD, CWORD}, /* 7, ( */
786 {CSPCL, CWORD, CWORD}, /* 8, ) */
787 {CBACK, CBACK, CCTL}, /* 9, \ */
788 {CBQUOTE, CBQUOTE, CWORD}, /* 10, ` */
789 {CENDVAR, CENDVAR, CWORD}, /* 11, } */
790 #ifndef USE_SIT_FUNCTION
791 {CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */
792 {CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */
793 {CCTL, CCTL, CCTL} /* 14, CTLESC ... */
796 #endif /* CONFIG_ASH_MATH_SUPPORT */
798 #ifdef USE_SIT_FUNCTION
800 #define U_C(c) ((unsigned char)(c))
802 static int SIT(int c, int syntax)
804 static const char spec_symbls[] = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
805 #ifdef CONFIG_ASH_ALIAS
806 static const char syntax_index_table[] = {
807 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
808 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
809 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
813 static const char syntax_index_table[] = {
814 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
815 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */
816 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
823 if (c == PEOF) /* 2^8+2 */
825 #ifdef CONFIG_ASH_ALIAS
826 if (c == PEOA) /* 2^8+1 */
830 if (U_C(c) >= U_C(CTLESC) && U_C(c) <= U_C(CTLQUOTEMARK))
833 s = strchr(spec_symbls, c);
834 if (s == 0 || *s == 0)
836 indx = syntax_index_table[(s - spec_symbls)];
838 return S_I_T[indx][syntax];
841 #else /* USE_SIT_FUNCTION */
843 #define SIT(c, syntax) S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax]
845 #ifdef CONFIG_ASH_ALIAS
846 #define CSPCL_CIGN_CIGN_CIGN 0
847 #define CSPCL_CWORD_CWORD_CWORD 1
848 #define CNL_CNL_CNL_CNL 2
849 #define CWORD_CCTL_CCTL_CWORD 3
850 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 4
851 #define CVAR_CVAR_CWORD_CVAR 5
852 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 6
853 #define CSPCL_CWORD_CWORD_CLP 7
854 #define CSPCL_CWORD_CWORD_CRP 8
855 #define CBACK_CBACK_CCTL_CBACK 9
856 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10
857 #define CENDVAR_CENDVAR_CWORD_CENDVAR 11
858 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
859 #define CWORD_CWORD_CWORD_CWORD 13
860 #define CCTL_CCTL_CCTL_CCTL 14
862 #define CSPCL_CWORD_CWORD_CWORD 0
863 #define CNL_CNL_CNL_CNL 1
864 #define CWORD_CCTL_CCTL_CWORD 2
865 #define CDQUOTE_CENDQUOTE_CWORD_CWORD 3
866 #define CVAR_CVAR_CWORD_CVAR 4
867 #define CSQUOTE_CWORD_CENDQUOTE_CWORD 5
868 #define CSPCL_CWORD_CWORD_CLP 6
869 #define CSPCL_CWORD_CWORD_CRP 7
870 #define CBACK_CBACK_CCTL_CBACK 8
871 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 9
872 #define CENDVAR_CENDVAR_CWORD_CENDVAR 10
873 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 11
874 #define CWORD_CWORD_CWORD_CWORD 12
875 #define CCTL_CCTL_CCTL_CCTL 13
878 static const char syntax_index_table[258] = {
879 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
880 /* 0 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
881 #ifdef CONFIG_ASH_ALIAS
882 /* 1 PEOA */ CSPCL_CIGN_CIGN_CIGN,
884 /* 2 -128 0x80 */ CWORD_CWORD_CWORD_CWORD,
885 /* 3 -127 CTLESC */ CCTL_CCTL_CCTL_CCTL,
886 /* 4 -126 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
887 /* 5 -125 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
888 /* 6 -124 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
889 /* 7 -123 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
890 /* 8 -122 CTLARI */ CCTL_CCTL_CCTL_CCTL,
891 /* 9 -121 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
892 /* 10 -120 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
893 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD,
894 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD,
895 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD,
896 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD,
897 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD,
898 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD,
899 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD,
900 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD,
901 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,
902 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD,
903 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD,
904 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD,
905 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD,
906 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD,
907 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD,
908 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD,
909 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD,
910 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD,
911 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,
912 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD,
913 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD,
914 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD,
915 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD,
916 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD,
917 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD,
918 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD,
919 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD,
920 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,
921 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,
922 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD,
923 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD,
924 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD,
925 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD,
926 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD,
927 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD,
928 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD,
929 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD,
930 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD,
931 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD,
932 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD,
933 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD,
934 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD,
935 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD,
936 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD,
937 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD,
938 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD,
939 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD,
940 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,
941 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,
942 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD,
943 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD,
944 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD,
945 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD,
946 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD,
947 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD,
948 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD,
949 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD,
950 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD,
951 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD,
952 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD,
953 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD,
954 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD,
955 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD,
956 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD,
957 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD,
958 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD,
959 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD,
960 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD,
961 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD,
962 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD,
963 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD,
964 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD,
965 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD,
966 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD,
967 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD,
968 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD,
969 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD,
970 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD,
971 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,
972 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD,
973 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD,
974 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD,
975 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD,
976 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD,
977 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD,
978 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD,
979 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD,
980 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD,
981 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD,
982 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD,
983 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD,
984 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD,
985 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD,
986 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD,
987 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD,
988 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD,
989 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD,
990 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD,
991 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD,
992 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD,
993 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD,
994 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD,
995 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD,
996 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD,
997 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD,
998 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD,
999 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD,
1000 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD,
1001 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD,
1002 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD,
1003 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD,
1004 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD,
1005 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD,
1006 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD,
1007 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD,
1008 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD,
1009 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD,
1010 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD,
1011 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD,
1012 /* 130 0 */ CWORD_CWORD_CWORD_CWORD,
1013 /* 131 1 */ CWORD_CWORD_CWORD_CWORD,
1014 /* 132 2 */ CWORD_CWORD_CWORD_CWORD,
1015 /* 133 3 */ CWORD_CWORD_CWORD_CWORD,
1016 /* 134 4 */ CWORD_CWORD_CWORD_CWORD,
1017 /* 135 5 */ CWORD_CWORD_CWORD_CWORD,
1018 /* 136 6 */ CWORD_CWORD_CWORD_CWORD,
1019 /* 137 7 */ CWORD_CWORD_CWORD_CWORD,
1020 /* 138 8 */ CWORD_CWORD_CWORD_CWORD,
1021 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
1022 /* 140 10 "\n" */ CNL_CNL_CNL_CNL,
1023 /* 141 11 */ CWORD_CWORD_CWORD_CWORD,
1024 /* 142 12 */ CWORD_CWORD_CWORD_CWORD,
1025 /* 143 13 */ CWORD_CWORD_CWORD_CWORD,
1026 /* 144 14 */ CWORD_CWORD_CWORD_CWORD,
1027 /* 145 15 */ CWORD_CWORD_CWORD_CWORD,
1028 /* 146 16 */ CWORD_CWORD_CWORD_CWORD,
1029 /* 147 17 */ CWORD_CWORD_CWORD_CWORD,
1030 /* 148 18 */ CWORD_CWORD_CWORD_CWORD,
1031 /* 149 19 */ CWORD_CWORD_CWORD_CWORD,
1032 /* 150 20 */ CWORD_CWORD_CWORD_CWORD,
1033 /* 151 21 */ CWORD_CWORD_CWORD_CWORD,
1034 /* 152 22 */ CWORD_CWORD_CWORD_CWORD,
1035 /* 153 23 */ CWORD_CWORD_CWORD_CWORD,
1036 /* 154 24 */ CWORD_CWORD_CWORD_CWORD,
1037 /* 155 25 */ CWORD_CWORD_CWORD_CWORD,
1038 /* 156 26 */ CWORD_CWORD_CWORD_CWORD,
1039 /* 157 27 */ CWORD_CWORD_CWORD_CWORD,
1040 /* 158 28 */ CWORD_CWORD_CWORD_CWORD,
1041 /* 159 29 */ CWORD_CWORD_CWORD_CWORD,
1042 /* 160 30 */ CWORD_CWORD_CWORD_CWORD,
1043 /* 161 31 */ CWORD_CWORD_CWORD_CWORD,
1044 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD,
1045 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD,
1046 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
1047 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD,
1048 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR,
1049 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD,
1050 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
1051 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
1052 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP,
1053 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP,
1054 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD,
1055 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD,
1056 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD,
1057 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD,
1058 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD,
1059 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD,
1060 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD,
1061 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD,
1062 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD,
1063 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD,
1064 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD,
1065 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD,
1066 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD,
1067 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD,
1068 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD,
1069 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD,
1070 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD,
1071 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
1072 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
1073 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD,
1074 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
1075 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD,
1076 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD,
1077 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD,
1078 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD,
1079 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD,
1080 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD,
1081 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD,
1082 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD,
1083 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD,
1084 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD,
1085 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD,
1086 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD,
1087 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD,
1088 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD,
1089 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD,
1090 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD,
1091 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD,
1092 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD,
1093 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
1094 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD,
1095 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD,
1096 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD,
1097 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD,
1098 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD,
1099 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD,
1100 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD,
1101 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
1102 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
1103 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD,
1104 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK,
1105 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD,
1106 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD,
1107 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD,
1108 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
1109 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD,
1110 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD,
1111 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD,
1112 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD,
1113 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD,
1114 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD,
1115 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD,
1116 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD,
1117 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD,
1118 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD,
1119 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD,
1120 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD,
1121 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD,
1122 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD,
1123 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD,
1124 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD,
1125 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD,
1126 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD,
1127 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD,
1128 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD,
1129 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD,
1130 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD,
1131 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD,
1132 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD,
1133 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD,
1134 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD,
1135 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD,
1136 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
1137 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
1138 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,
1139 /* 257 127 */ CWORD_CWORD_CWORD_CWORD,
1142 #endif /* USE_SIT_FUNCTION */
1144 /* $NetBSD: alias.c,v 1.11 2002/11/24 22:35:38 christos Exp $ */
1149 static int funcblocksize; /* size of structures in function */
1150 static int funcstringsize; /* size of strings in node */
1151 static pointer funcblock; /* block to allocate function from */
1152 static char *funcstring; /* block to allocate strings from */
1154 static const short nodesize[26] = {
1155 SHELL_ALIGN(sizeof (struct ncmd)),
1156 SHELL_ALIGN(sizeof (struct npipe)),
1157 SHELL_ALIGN(sizeof (struct nredir)),
1158 SHELL_ALIGN(sizeof (struct nredir)),
1159 SHELL_ALIGN(sizeof (struct nredir)),
1160 SHELL_ALIGN(sizeof (struct nbinary)),
1161 SHELL_ALIGN(sizeof (struct nbinary)),
1162 SHELL_ALIGN(sizeof (struct nbinary)),
1163 SHELL_ALIGN(sizeof (struct nif)),
1164 SHELL_ALIGN(sizeof (struct nbinary)),
1165 SHELL_ALIGN(sizeof (struct nbinary)),
1166 SHELL_ALIGN(sizeof (struct nfor)),
1167 SHELL_ALIGN(sizeof (struct ncase)),
1168 SHELL_ALIGN(sizeof (struct nclist)),
1169 SHELL_ALIGN(sizeof (struct narg)),
1170 SHELL_ALIGN(sizeof (struct narg)),
1171 SHELL_ALIGN(sizeof (struct nfile)),
1172 SHELL_ALIGN(sizeof (struct nfile)),
1173 SHELL_ALIGN(sizeof (struct nfile)),
1174 SHELL_ALIGN(sizeof (struct nfile)),
1175 SHELL_ALIGN(sizeof (struct nfile)),
1176 SHELL_ALIGN(sizeof (struct ndup)),
1177 SHELL_ALIGN(sizeof (struct ndup)),
1178 SHELL_ALIGN(sizeof (struct nhere)),
1179 SHELL_ALIGN(sizeof (struct nhere)),
1180 SHELL_ALIGN(sizeof (struct nnot)),
1184 static void calcsize(union node *);
1185 static void sizenodelist(struct nodelist *);
1186 static union node *copynode(union node *);
1187 static struct nodelist *copynodelist(struct nodelist *);
1188 static char *nodesavestr(char *);
1192 static void evalstring(char *, int);
1193 union node; /* BLETCH for ansi C */
1194 static void evaltree(union node *, int);
1195 static void evalbackcmd(union node *, struct backcmd *);
1197 /* in_function returns nonzero if we are currently evaluating a function */
1198 #define in_function() funcnest
1199 static int evalskip; /* set if we are skipping commands */
1200 static int skipcount; /* number of levels to skip */
1201 static int funcnest; /* depth of function calls */
1203 /* reasons for skipping commands (see comment on breakcmd routine) */
1210 * This file was generated by the mkbuiltins program.
1214 static int bgcmd(int, char **);
1216 static int breakcmd(int, char **);
1217 static int cdcmd(int, char **);
1218 #ifdef CONFIG_ASH_CMDCMD
1219 static int commandcmd(int, char **);
1221 static int dotcmd(int, char **);
1222 static int evalcmd(int, char **);
1223 static int execcmd(int, char **);
1224 static int exitcmd(int, char **);
1225 #ifdef CONFIG_ASH_MATH_SUPPORT
1226 static int expcmd(int, char **);
1228 static int exportcmd(int, char **);
1229 static int falsecmd(int, char **);
1231 static int fgcmd(int, char **);
1233 #ifdef CONFIG_ASH_GETOPTS
1234 static int getoptscmd(int, char **);
1236 static int hashcmd(int, char **);
1237 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1238 static int helpcmd(int argc, char **argv);
1241 static int jobscmd(int, char **);
1243 static int localcmd(int, char **);
1244 static int pwdcmd(int, char **);
1245 static int readcmd(int, char **);
1246 static int returncmd(int, char **);
1247 static int setcmd(int, char **);
1248 static int shiftcmd(int, char **);
1249 static int timescmd(int, char **);
1250 static int trapcmd(int, char **);
1251 static int truecmd(int, char **);
1252 static int typecmd(int, char **);
1253 static int umaskcmd(int, char **);
1254 static int unsetcmd(int, char **);
1255 static int waitcmd(int, char **);
1256 static int ulimitcmd(int, char **);
1258 static int killcmd(int, char **);
1261 /* $NetBSD: mail.h,v 1.9 2002/11/24 22:35:40 christos Exp $ */
1263 #ifdef CONFIG_ASH_MAIL
1264 static void chkmail(void);
1265 static void changemail(const char *);
1268 /* $NetBSD: exec.h,v 1.20 2003/01/22 20:36:04 dsl Exp $ */
1270 /* values of cmdtype */
1271 #define CMDUNKNOWN -1 /* no entry in table for command */
1272 #define CMDNORMAL 0 /* command is an executable program */
1273 #define CMDFUNCTION 1 /* command is a shell function */
1274 #define CMDBUILTIN 2 /* command is a shell builtin */
1278 int (*builtin)(int, char **);
1279 /* unsigned flags; */
1282 #ifdef CONFIG_ASH_CMDCMD
1284 # ifdef CONFIG_ASH_ALIAS
1285 # define COMMANDCMD (builtincmd + 7)
1286 # define EXECCMD (builtincmd + 10)
1288 # define COMMANDCMD (builtincmd + 6)
1289 # define EXECCMD (builtincmd + 9)
1292 # ifdef CONFIG_ASH_ALIAS
1293 # define COMMANDCMD (builtincmd + 6)
1294 # define EXECCMD (builtincmd + 9)
1296 # define COMMANDCMD (builtincmd + 5)
1297 # define EXECCMD (builtincmd + 8)
1300 #else /* ! CONFIG_ASH_CMDCMD */
1302 # ifdef CONFIG_ASH_ALIAS
1303 # define EXECCMD (builtincmd + 9)
1305 # define EXECCMD (builtincmd + 8)
1308 # ifdef CONFIG_ASH_ALIAS
1309 # define EXECCMD (builtincmd + 8)
1311 # define EXECCMD (builtincmd + 7)
1314 #endif /* CONFIG_ASH_CMDCMD */
1316 #define BUILTIN_NOSPEC "0"
1317 #define BUILTIN_SPECIAL "1"
1318 #define BUILTIN_REGULAR "2"
1319 #define BUILTIN_SPEC_REG "3"
1320 #define BUILTIN_ASSIGN "4"
1321 #define BUILTIN_SPEC_ASSG "5"
1322 #define BUILTIN_REG_ASSG "6"
1323 #define BUILTIN_SPEC_REG_ASSG "7"
1325 #define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1326 #define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
1328 static const struct builtincmd builtincmd[] = {
1329 { BUILTIN_SPEC_REG ".", dotcmd },
1330 { BUILTIN_SPEC_REG ":", truecmd },
1331 #ifdef CONFIG_ASH_ALIAS
1332 { BUILTIN_REG_ASSG "alias", aliascmd },
1335 { BUILTIN_REGULAR "bg", bgcmd },
1337 { BUILTIN_SPEC_REG "break", breakcmd },
1338 { BUILTIN_REGULAR "cd", cdcmd },
1339 { BUILTIN_NOSPEC "chdir", cdcmd },
1340 #ifdef CONFIG_ASH_CMDCMD
1341 { BUILTIN_REGULAR "command", commandcmd },
1343 { BUILTIN_SPEC_REG "continue", breakcmd },
1344 { BUILTIN_SPEC_REG "eval", evalcmd },
1345 { BUILTIN_SPEC_REG "exec", execcmd },
1346 { BUILTIN_SPEC_REG "exit", exitcmd },
1347 #ifdef CONFIG_ASH_MATH_SUPPORT
1348 { BUILTIN_NOSPEC "exp", expcmd },
1350 { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
1351 { BUILTIN_REGULAR "false", falsecmd },
1353 { BUILTIN_REGULAR "fg", fgcmd },
1355 #ifdef CONFIG_ASH_GETOPTS
1356 { BUILTIN_REGULAR "getopts", getoptscmd },
1358 { BUILTIN_NOSPEC "hash", hashcmd },
1359 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1360 { BUILTIN_NOSPEC "help", helpcmd },
1363 { BUILTIN_REGULAR "jobs", jobscmd },
1364 { BUILTIN_REGULAR "kill", killcmd },
1366 #ifdef CONFIG_ASH_MATH_SUPPORT
1367 { BUILTIN_NOSPEC "let", expcmd },
1369 { BUILTIN_ASSIGN "local", localcmd },
1370 { BUILTIN_NOSPEC "pwd", pwdcmd },
1371 { BUILTIN_REGULAR "read", readcmd },
1372 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
1373 { BUILTIN_SPEC_REG "return", returncmd },
1374 { BUILTIN_SPEC_REG "set", setcmd },
1375 { BUILTIN_SPEC_REG "shift", shiftcmd },
1376 { BUILTIN_SPEC_REG "times", timescmd },
1377 { BUILTIN_SPEC_REG "trap", trapcmd },
1378 { BUILTIN_REGULAR "true", truecmd },
1379 { BUILTIN_NOSPEC "type", typecmd },
1380 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
1381 { BUILTIN_REGULAR "umask", umaskcmd },
1382 #ifdef CONFIG_ASH_ALIAS
1383 { BUILTIN_REGULAR "unalias", unaliascmd },
1385 { BUILTIN_SPEC_REG "unset", unsetcmd },
1386 { BUILTIN_REGULAR "wait", waitcmd },
1389 #define NUMBUILTINS (sizeof (builtincmd) / sizeof (struct builtincmd) )
1397 const struct builtincmd *cmd;
1398 struct funcnode *func;
1403 /* action to find_command() */
1404 #define DO_ERR 0x01 /* prints errors */
1405 #define DO_ABS 0x02 /* checks absolute paths */
1406 #define DO_NOFUNC 0x04 /* don't return shell functions, for command */
1407 #define DO_ALTPATH 0x08 /* using alternate path */
1408 #define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
1410 static const char *pathopt; /* set by padvance */
1412 static void shellexec(char **, const char *, int)
1413 __attribute__((__noreturn__));
1414 static char *padvance(const char **, const char *);
1415 static void find_command(char *, struct cmdentry *, int, const char *);
1416 static struct builtincmd *find_builtin(const char *);
1417 static void hashcd(void);
1418 static void changepath(const char *);
1419 static void defun(char *, union node *);
1420 static void unsetfunc(const char *);
1422 #ifdef CONFIG_ASH_MATH_SUPPORT
1424 static int dash_arith(const char *);
1427 /* $NetBSD: init.h,v 1.9 2002/11/24 22:35:40 christos Exp $ */
1429 static void reset(void);
1431 /* $NetBSD: var.h,v 1.21 2003/01/22 20:36:04 dsl Exp $ */
1438 #define VEXPORT 0x01 /* variable is exported */
1439 #define VREADONLY 0x02 /* variable cannot be modified */
1440 #define VSTRFIXED 0x04 /* variable struct is statically allocated */
1441 #define VTEXTFIXED 0x08 /* text is statically allocated */
1442 #define VSTACK 0x10 /* text is allocated on the stack */
1443 #define VUNSET 0x20 /* the variable is not set */
1444 #define VNOFUNC 0x40 /* don't call the callback function */
1445 #define VNOSET 0x80 /* do not set variable - just readonly test */
1446 #define VNOSAVE 0x100 /* when text is on the heap before setvareq */
1450 struct var *next; /* next entry in hash list */
1451 int flags; /* flags are defined above */
1452 const char *text; /* name=value */
1453 void (*func)(const char *);
1454 /* function to be called when */
1455 /* the variable gets set/unset */
1459 struct localvar *next; /* next local variable in list */
1460 struct var *vp; /* the variable that was made local */
1461 int flags; /* saved flags */
1462 const char *text; /* saved text */
1466 static struct localvar *localvars;
1472 #ifdef CONFIG_ASH_GETOPTS
1473 static void getoptsreset(const char *);
1476 #ifdef CONFIG_LOCALE_SUPPORT
1478 static void change_lc_all(const char *value);
1479 static void change_lc_ctype(const char *value);
1484 static const char defpathvar[] =
1485 "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
1487 static const char defifsvar[] = "IFS= \t\n";
1489 static const char defifs[] = " \t\n";
1491 static struct var varinit[] = {
1493 { 0, VSTRFIXED|VTEXTFIXED, defifsvar, 0 },
1495 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", 0 },
1498 #ifdef CONFIG_ASH_MAIL
1499 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail },
1500 { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail },
1503 { 0, VSTRFIXED|VTEXTFIXED, defpathvar, changepath },
1504 { 0, VSTRFIXED|VTEXTFIXED, "PS1=$ ", 0 },
1505 { 0, VSTRFIXED|VTEXTFIXED, "PS2=> ", 0 },
1506 { 0, VSTRFIXED|VTEXTFIXED, "PS4=+ ", 0 },
1507 #ifdef CONFIG_ASH_GETOPTS
1508 { 0, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset },
1510 #ifdef CONFIG_LOCALE_SUPPORT
1511 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL=", change_lc_all},
1512 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE=", change_lc_ctype},
1514 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
1515 {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE=", NULL},
1519 #define vifs varinit[0]
1520 #ifdef CONFIG_ASH_MAIL
1521 #define vmail (&vifs)[1]
1522 #define vmpath (&vmail)[1]
1526 #define vpath (&vmpath)[1]
1527 #define vps1 (&vpath)[1]
1528 #define vps2 (&vps1)[1]
1529 #define vps4 (&vps2)[1]
1530 #define voptind (&vps4)[1]
1532 #define defpath (defpathvar + 5)
1535 * The following macros access the values of the above variables.
1536 * They have to skip over the name. They return the null string
1537 * for unset variables.
1540 #define ifsval() (vifs.text + 4)
1541 #define ifsset() ((vifs.flags & VUNSET) == 0)
1542 #define mailval() (vmail.text + 5)
1543 #define mpathval() (vmpath.text + 9)
1544 #define pathval() (vpath.text + 5)
1545 #define ps1val() (vps1.text + 4)
1546 #define ps2val() (vps2.text + 4)
1547 #define ps4val() (vps4.text + 4)
1548 #define optindval() (voptind.text + 7)
1550 #define mpathset() ((vmpath.flags & VUNSET) == 0)
1552 static void setvar(const char *, const char *, int);
1553 static void setvareq(char *, int);
1554 static void listsetvar(struct strlist *, int);
1555 static char *lookupvar(const char *);
1556 static char *bltinlookup(const char *);
1557 static char **listvars(int, int, char ***);
1558 #define environment() listvars(VEXPORT, VUNSET, 0)
1559 static int showvars(const char *, int, int);
1560 static void poplocalvars(void);
1561 static int unsetvar(const char *);
1562 #ifdef CONFIG_ASH_GETOPTS
1563 static int setvarsafe(const char *, const char *, int);
1565 static int varcmp(const char *, const char *);
1566 static struct var **hashvar(const char *);
1569 static inline int varequal(const char *a, const char *b) {
1570 return !varcmp(a, b);
1574 static int loopnest; /* current loop nesting level */
1577 struct strpush *prev; /* preceding string on stack */
1580 #ifdef CONFIG_ASH_ALIAS
1581 struct alias *ap; /* if push was associated with an alias */
1583 char *string; /* remember the string since it may change */
1587 struct parsefile *prev; /* preceding file on stack */
1588 int linno; /* current line */
1589 int fd; /* file descriptor (or -1 if string) */
1590 int nleft; /* number of chars left in this line */
1591 int lleft; /* number of chars left in this buffer */
1592 char *nextc; /* next char in buffer */
1593 char *buf; /* input buffer */
1594 struct strpush *strpush; /* for pushing strings at this level */
1595 struct strpush basestrpush; /* so pushing one is fast */
1599 * The parsefile structure pointed to by the global variable parsefile
1600 * contains information about the current file being read.
1605 struct redirtab *next;
1610 static struct redirtab *redirlist;
1611 static int nullredirs;
1613 extern char **environ;
1615 /* $NetBSD: output.h,v 1.16 2002/11/24 22:35:42 christos Exp $ */
1618 static void outstr(const char *, FILE *);
1619 static void outcslow(int, FILE *);
1620 static void flushall(void);
1621 static void flushout(FILE *);
1622 static int out1fmt(const char *, ...)
1623 __attribute__((__format__(__printf__,1,2)));
1624 static int fmtstr(char *, size_t, const char *, ...)
1625 __attribute__((__format__(__printf__,3,4)));
1626 static void xwrite(int, const void *, size_t);
1629 #define outerr(f) ferror(f)
1630 #define out2c(c) outcslow((c), stderr)
1632 static void out1str(const char *p)
1637 static void out2str(const char *p)
1642 static void out1c(char c)
1652 * Initialization code.
1656 * This routine initializes the builtin variables.
1667 * PS1 depends on uid
1669 #if defined(CONFIG_FEATURE_COMMAND_EDITING) && defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
1670 vps1.text = "PS1=\\w \\$ ";
1673 vps1.text = "PS1=# ";
1676 end = vp + sizeof(varinit) / sizeof(varinit[0]);
1678 vpp = hashvar(vp->text);
1681 } while (++vp < end);
1690 basepf.nextc = basepf.buf = basebuf;
1695 signal(SIGCHLD, SIG_DFL);
1704 for (envp = environ ; *envp ; envp++) {
1705 if (strchr(*envp, '=')) {
1706 setvareq(*envp, VEXPORT|VTEXTFIXED);
1710 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
1711 setvar("PPID", ppid, 0);
1716 /* PEOF (the end of file marker) */
1719 * The input line number. Input.c just defines this variable, and saves
1720 * and restores it when files are pushed and popped. The user of this
1721 * package must set its value.
1724 static int pgetc(void);
1725 static int pgetc2(void);
1726 static int preadbuffer(void);
1727 static void pungetc(void);
1728 static void pushstring(char *, void *);
1729 static void popstring(void);
1730 static void setinputfile(const char *, int);
1731 static void setinputfd(int, int);
1732 static void setinputstring(char *);
1733 static void popfile(void);
1734 static void popallfiles(void);
1735 static void closescript(void);
1738 /* $NetBSD: jobs.h,v 1.17 2003/01/22 20:36:04 dsl Exp $ */
1741 /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
1744 #define FORK_NOJOB 2
1746 /* mode flags for showjob(s) */
1747 #define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
1748 #define SHOW_PID 0x04 /* include process pid */
1749 #define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
1753 * A job structure contains information about a job. A job is either a
1754 * single process or a set of processes contained in a pipeline. In the
1755 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1760 pid_t pid; /* process id */
1761 int status; /* last process status from wait() */
1762 char *cmd; /* text of command being run */
1766 struct procstat ps0; /* status of process */
1767 struct procstat *ps; /* status or processes when more than one */
1769 int stopstatus; /* status of a stopped job */
1772 nprocs: 16, /* number of processes */
1774 #define JOBRUNNING 0 /* at least one proc running */
1775 #define JOBSTOPPED 1 /* all procs are stopped */
1776 #define JOBDONE 2 /* all procs are completed */
1778 sigint: 1, /* job was killed by SIGINT */
1779 jobctl: 1, /* job running under job control */
1781 waited: 1, /* true if this entry has been waited for */
1782 used: 1, /* true if this entry is in used */
1783 changed: 1; /* true if status has changed */
1784 struct job *prev_job; /* previous job */
1787 static pid_t backgndpid; /* pid of last background process */
1788 static int job_warning; /* user was warned about stopped jobs */
1790 static int jobctl; /* true if doing job control */
1793 static struct job *makejob(union node *, int);
1794 static int forkshell(struct job *, union node *, int);
1795 static int waitforjob(struct job *);
1796 static int stoppedjobs(void);
1799 #define setjobctl(on) /* do nothing */
1801 static void setjobctl(int);
1802 static void showjobs(FILE *, int);
1805 /* $NetBSD: main.h,v 1.9 2002/11/24 22:35:41 christos Exp $ */
1808 /* pid of main shell */
1810 /* true if we aren't a child of the main shell */
1811 static int rootshell;
1813 static void readcmdfile(char *);
1814 static void cmdloop(int);
1816 /* $NetBSD: memalloc.h,v 1.13 2003/01/22 20:36:04 dsl Exp $ */
1820 struct stack_block *stackp;
1823 struct stackmark *marknext;
1826 /* minimum size of a block */
1827 #define MINSIZE SHELL_ALIGN(504)
1829 struct stack_block {
1830 struct stack_block *prev;
1831 char space[MINSIZE];
1834 static struct stack_block stackbase;
1835 static struct stack_block *stackp = &stackbase;
1836 static struct stackmark *markp;
1837 static char *stacknxt = stackbase.space;
1838 static size_t stacknleft = MINSIZE;
1839 static char *sstrend = stackbase.space + MINSIZE;
1840 static int herefd = -1;
1843 static pointer ckmalloc(size_t);
1844 static pointer ckrealloc(pointer, size_t);
1845 static char *savestr(const char *);
1846 static pointer stalloc(size_t);
1847 static void stunalloc(pointer);
1848 static void setstackmark(struct stackmark *);
1849 static void popstackmark(struct stackmark *);
1850 static void growstackblock(void);
1851 static void *growstackstr(void);
1852 static char *makestrspace(size_t, char *);
1853 static char *stnputs(const char *, size_t, char *);
1854 static char *stputs(const char *, char *);
1857 static inline char *_STPUTC(char c, char *p) {
1864 #define stackblock() ((void *)stacknxt)
1865 #define stackblocksize() stacknleft
1866 #define STARTSTACKSTR(p) ((p) = stackblock())
1867 #define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1868 #define CHECKSTRSPACE(n, p) \
1872 size_t m = sstrend - q; \
1874 (p) = makestrspace(l, q); \
1877 #define USTPUTC(c, p) (*p++ = (c))
1878 #define STACKSTRNUL(p) ((p) == sstrend? (p = growstackstr(), *p = '\0') : (*p = '\0'))
1879 #define STUNPUTC(p) (--p)
1880 #define STTOPC(p) p[-1]
1881 #define STADJUST(amount, p) (p += (amount))
1883 #define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1884 #define ungrabstackstr(s, p) stunalloc((s))
1885 #define stackstrend() ((void *)sstrend)
1887 #define ckfree(p) free((pointer)(p))
1889 /* $NetBSD: mystring.h,v 1.10 2002/11/24 22:35:42 christos Exp $ */
1892 #define DOLATSTRLEN 4
1894 static char *prefix(const char *, const char *);
1895 static int number(const char *);
1896 static int is_number(const char *);
1897 static char *single_quote(const char *);
1898 static char *sstrdup(const char *);
1900 #define equal(s1, s2) (strcmp(s1, s2) == 0)
1901 #define scopy(s1, s2) ((void)strcpy(s2, s1))
1903 /* $NetBSD: options.h,v 1.16 2003/01/22 20:36:04 dsl Exp $ */
1906 int nparam; /* # of positional parameters (without $0) */
1907 unsigned char malloc; /* if parameter list dynamically allocated */
1908 char **p; /* parameter list */
1909 #ifdef CONFIG_ASH_GETOPTS
1910 int optind; /* next parameter to be processed by getopts */
1911 int optoff; /* used by getopts */
1916 #define eflag optlist[0]
1917 #define fflag optlist[1]
1918 #define Iflag optlist[2]
1919 #define iflag optlist[3]
1920 #define mflag optlist[4]
1921 #define nflag optlist[5]
1922 #define sflag optlist[6]
1923 #define xflag optlist[7]
1924 #define vflag optlist[8]
1925 #define Cflag optlist[9]
1926 #define aflag optlist[10]
1927 #define bflag optlist[11]
1928 #define uflag optlist[12]
1929 #define qflag optlist[13]
1932 #define nolog optlist[14]
1933 #define debug optlist[15]
1939 /* $NetBSD: options.c,v 1.33 2003/01/22 20:36:04 dsl Exp $ */
1942 static const char *const optletters_optnames[NOPTS] = {
1963 #define optletters(n) optletters_optnames[(n)][0]
1964 #define optnames(n) (&optletters_optnames[(n)][1])
1967 static char optlist[NOPTS];
1970 static char *arg0; /* value of $0 */
1971 static struct shparam shellparam; /* $@ current positional parameters */
1972 static char **argptr; /* argument list for builtin commands */
1973 static char *optionarg; /* set by nextopt (like getopt) */
1974 static char *optptr; /* used by nextopt */
1976 static char *minusc; /* argument to -c option */
1979 static void procargs(int, char **);
1980 static void optschanged(void);
1981 static void setparam(char **);
1982 static void freeparam(volatile struct shparam *);
1983 static int shiftcmd(int, char **);
1984 static int setcmd(int, char **);
1985 static int nextopt(const char *);
1987 /* $NetBSD: redir.h,v 1.14 2002/11/24 22:35:43 christos Exp $ */
1989 /* flags passed to redirect */
1990 #define REDIR_PUSH 01 /* save previous values of file descriptors */
1993 static void redirect(union node *, int);
1994 static void popredir(int);
1995 static void clearredir(int);
1996 static int copyfd(int, int);
1997 static int redirectsafe(union node *, int);
1999 /* $NetBSD: show.h,v 1.6 2003/01/22 20:36:04 dsl Exp $ */
2003 static void showtree(union node *);
2004 static void trace(const char *, ...);
2005 static void tracev(const char *, va_list);
2006 static void trargs(char **);
2007 static void trputc(int);
2008 static void trputs(const char *);
2009 static void opentrace(void);
2012 /* $NetBSD: trap.h,v 1.16 2002/11/24 22:35:43 christos Exp $ */
2015 /* trap handler commands */
2016 static char *trap[NSIG];
2017 /* current value of signal */
2018 static char sigmode[NSIG - 1];
2019 /* indicates specified signal received */
2020 static char gotsig[NSIG - 1];
2022 static void clear_traps(void);
2023 static void setsignal(int);
2024 static void ignoresig(int);
2025 static void onsig(int);
2026 static void dotrap(void);
2027 static void setinteractive(int);
2028 static void exitshell(void) __attribute__((__noreturn__));
2029 static int decode_signal(const char *, int);
2032 * This routine is called when an error or an interrupt occurs in an
2033 * interactive shell and control is returned to the main command loop.
2048 parselleft = parsenleft = 0; /* clear input buffer */
2052 /* from parser.c: */
2065 #ifdef CONFIG_ASH_ALIAS
2066 static struct alias *atab[ATABSIZE];
2068 static void setalias(const char *, const char *);
2069 static struct alias *freealias(struct alias *);
2070 static struct alias **__lookupalias(const char *);
2073 setalias(const char *name, const char *val)
2075 struct alias *ap, **app;
2077 app = __lookupalias(name);
2081 if (!(ap->flag & ALIASINUSE)) {
2084 ap->val = savestr(val);
2085 ap->flag &= ~ALIASDEAD;
2088 ap = ckmalloc(sizeof (struct alias));
2089 ap->name = savestr(name);
2090 ap->val = savestr(val);
2099 unalias(const char *name)
2103 app = __lookupalias(name);
2107 *app = freealias(*app);
2118 struct alias *ap, **app;
2122 for (i = 0; i < ATABSIZE; i++) {
2124 for (ap = *app; ap; ap = *app) {
2125 *app = freealias(*app);
2134 static struct alias *
2135 lookupalias(const char *name, int check)
2137 struct alias *ap = *__lookupalias(name);
2139 if (check && ap && (ap->flag & ALIASINUSE))
2145 * TODO - sort output
2148 aliascmd(int argc, char **argv)
2157 for (i = 0; i < ATABSIZE; i++)
2158 for (ap = atab[i]; ap; ap = ap->next) {
2163 while ((n = *++argv) != NULL) {
2164 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
2165 if ((ap = *__lookupalias(n)) == NULL) {
2166 fprintf(stderr, "%s: %s not found\n", "alias", n);
2180 unaliascmd(int argc, char **argv)
2184 while ((i = nextopt("a")) != '\0') {
2190 for (i = 0; *argptr; argptr++) {
2191 if (unalias(*argptr)) {
2192 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
2200 static struct alias *
2201 freealias(struct alias *ap) {
2204 if (ap->flag & ALIASINUSE) {
2205 ap->flag |= ALIASDEAD;
2217 printalias(const struct alias *ap) {
2218 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
2221 static struct alias **
2222 __lookupalias(const char *name) {
2223 unsigned int hashval;
2230 ch = (unsigned char)*p;
2234 ch = (unsigned char)*++p;
2236 app = &atab[hashval % ATABSIZE];
2238 for (; *app; app = &(*app)->next) {
2239 if (equal(name, (*app)->name)) {
2246 #endif /* CONFIG_ASH_ALIAS */
2249 /* $NetBSD: cd.c,v 1.30 2003/01/22 20:36:03 dsl Exp $ */
2252 * The cd and pwd commands.
2255 #define CD_PHYSICAL 1
2258 static int docd(const char *, int);
2259 static int cdopt(void);
2261 static char *curdir = nullstr; /* current working directory */
2262 static char *physdir = nullstr; /* physical working directory */
2271 while ((i = nextopt("LP"))) {
2273 flags ^= CD_PHYSICAL;
2282 cdcmd(int argc, char **argv)
2294 dest = bltinlookup(homestr);
2295 else if (dest[0] == '-' && dest[1] == '\0') {
2296 dest = bltinlookup("OLDPWD");
2319 if (!(path = bltinlookup("CDPATH"))) {
2327 p = padvance(&path, dest);
2328 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2332 if (!docd(p, flags))
2337 error("can't cd to %s", dest);
2340 if (flags & CD_PRINT)
2341 out1fmt(snlfmt, curdir);
2347 * Update curdir (the name of the current directory) in response to a
2351 static inline const char *
2352 updatepwd(const char *dir)
2359 cdcomppath = sstrdup(dir);
2362 if (curdir == nullstr)
2364 new = stputs(curdir, new);
2366 new = makestrspace(strlen(dir) + 2, new);
2367 lim = stackblock() + 1;
2371 if (new > lim && *lim == '/')
2376 if (dir[1] == '/' && dir[2] != '/') {
2382 p = strtok(cdcomppath, "/");
2386 if (p[1] == '.' && p[2] == '\0') {
2393 } else if (p[1] == '\0')
2397 new = stputs(p, new);
2405 return stackblock();
2409 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2410 * know that the current directory has changed.
2414 docd(const char *dest, int flags)
2416 const char *dir = 0;
2419 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2422 if (!(flags & CD_PHYSICAL)) {
2423 dir = updatepwd(dest);
2438 * Find out what the current directory is. If we already know the current
2439 * directory, this routine returns immediately.
2441 static inline char *
2444 char *dir = getcwd(0, 0);
2445 return dir ? dir : nullstr;
2449 pwdcmd(int argc, char **argv)
2452 const char *dir = curdir;
2456 if (physdir == nullstr)
2460 out1fmt(snlfmt, dir);
2465 setpwd(const char *val, int setold)
2469 oldcur = dir = curdir;
2472 setvar("OLDPWD", oldcur, VEXPORT);
2475 if (physdir != nullstr) {
2476 if (physdir != oldcur)
2480 if (oldcur == val || !val) {
2487 if (oldcur != dir && oldcur != nullstr) {
2492 setvar("PWD", dir, VEXPORT);
2495 /* $NetBSD: error.c,v 1.30 2003/01/22 20:36:03 dsl Exp $ */
2498 * Errors and exceptions.
2502 * Code to handle exceptions in C.
2507 static void exverror(int, const char *, va_list)
2508 __attribute__((__noreturn__));
2511 * Called to raise an exception. Since C doesn't include exceptions, we
2512 * just do a longjmp to the exception handler. The type of exception is
2513 * stored in the global variable "exception".
2520 if (handler == NULL)
2526 longjmp(handler->loc, 1);
2531 * Called from trap.c when a SIGINT is received. (If the user specifies
2532 * that SIGINT is to be trapped or ignored using the trap builtin, then
2533 * this routine is not called.) Suppressint is nonzero when interrupts
2534 * are held using the INTOFF macro. (The test for iflag is just
2535 * defensive programming.)
2545 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
2546 if (!(rootshell && iflag)) {
2547 signal(SIGINT, SIG_DFL);
2557 exvwarning(const char *msg, va_list ap)
2570 fprintf(errs, fmt, name, startlinno);
2571 vfprintf(errs, msg, ap);
2572 outcslow('\n', errs);
2576 * Exverror is called to raise the error exception. If the second argument
2577 * is not NULL then error prints an error message using printf style
2578 * formatting. It then raises the error exception.
2581 exverror(int cond, const char *msg, va_list ap)
2585 TRACE(("exverror(%d, \"", cond));
2587 TRACE(("\") pid=%d\n", getpid()));
2589 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
2592 exvwarning(msg, ap);
2601 error(const char *msg, ...)
2606 exverror(EXERROR, msg, ap);
2613 exerror(int cond, const char *msg, ...)
2618 exverror(cond, msg, ap);
2624 * error/warning routines for external builtins
2628 sh_warnx(const char *fmt, ...)
2633 exvwarning(fmt, ap);
2639 * Return a string describing an error. The returned string may be a
2640 * pointer to a static buffer that will be overwritten on the next call.
2641 * Action describes the operation that got the error.
2645 errmsg(int e, const char *em)
2647 if(e == ENOENT || e == ENOTDIR) {
2655 /* $NetBSD: eval.c,v 1.71 2003/01/23 03:33:16 rafal Exp $ */
2658 * Evaluate a command.
2661 /* flags in argument to evaltree */
2662 #define EV_EXIT 01 /* exit after evaluating tree */
2663 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2664 #define EV_BACKCMD 04 /* command executing within back quotes */
2667 static void evalloop(union node *, int);
2668 static void evalfor(union node *, int);
2669 static void evalcase(union node *, int);
2670 static void evalsubshell(union node *, int);
2671 static void expredir(union node *);
2672 static void evalpipe(union node *, int);
2673 static void evalcommand(union node *, int);
2674 static int evalbltin(const struct builtincmd *, int, char **);
2675 static int evalfun(struct funcnode *, int, char **, int);
2676 static void prehash(union node *);
2677 static int eprintlist(struct strlist *, int);
2678 static int bltincmd(int, char **);
2681 static const struct builtincmd bltin = {
2687 * Called to reset things after an exception.
2691 * The eval commmand.
2695 evalcmd(int argc, char **argv)
2704 STARTSTACKSTR(concat);
2707 concat = stputs(p, concat);
2708 if ((p = *ap++) == NULL)
2710 STPUTC(' ', concat);
2712 STPUTC('\0', concat);
2713 p = grabstackstr(concat);
2715 evalstring(p, EV_TESTED);
2722 * Execute a command or commands contained in a string.
2726 evalstring(char *s, int flag)
2729 struct stackmark smark;
2731 setstackmark(&smark);
2734 while ((n = parsecmd(0)) != NEOF) {
2736 popstackmark(&smark);
2741 popstackmark(&smark);
2747 * Evaluate a parse tree. The value is left in the global variable
2752 evaltree(union node *n, int flags)
2755 void (*evalfn)(union node *, int);
2759 TRACE(("evaltree(NULL) called\n"));
2762 TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
2763 getpid(), n, n->type, flags));
2767 out1fmt("Node type = %d\n", n->type);
2772 evaltree(n->nnot.com, EV_TESTED);
2773 status = !exitstatus;
2776 expredir(n->nredir.redirect);
2777 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
2779 evaltree(n->nredir.n, flags & EV_TESTED);
2780 status = exitstatus;
2785 evalfn = evalcommand;
2787 if (eflag && !(flags & EV_TESTED))
2799 evalfn = evalsubshell;
2811 #error NAND + 1 != NOR
2813 #if NOR + 1 != NSEMI
2814 #error NOR + 1 != NSEMI
2816 isor = n->type - NAND;
2819 (flags | ((isor >> 1) - 1)) & EV_TESTED
2821 if (!exitstatus == isor)
2833 evaltree(n->nif.test, EV_TESTED);
2836 if (exitstatus == 0) {
2839 } else if (n->nif.elsepart) {
2840 n = n->nif.elsepart;
2845 defun(n->narg.text, n->narg.next);
2849 exitstatus = status;
2855 if (flags & EV_EXIT || checkexit & exitstatus)
2860 #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
2863 void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
2867 evalloop(union node *n, int flags)
2877 evaltree(n->nbinary.ch1, EV_TESTED);
2879 skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
2883 if (evalskip == SKIPBREAK && --skipcount <= 0)
2888 if (n->type != NWHILE)
2892 evaltree(n->nbinary.ch2, flags);
2893 status = exitstatus;
2898 exitstatus = status;
2904 evalfor(union node *n, int flags)
2906 struct arglist arglist;
2909 struct stackmark smark;
2911 setstackmark(&smark);
2912 arglist.lastp = &arglist.list;
2913 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
2914 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
2919 *arglist.lastp = NULL;
2924 for (sp = arglist.list ; sp ; sp = sp->next) {
2925 setvar(n->nfor.var, sp->text, 0);
2926 evaltree(n->nfor.body, flags);
2928 if (evalskip == SKIPCONT && --skipcount <= 0) {
2932 if (evalskip == SKIPBREAK && --skipcount <= 0)
2939 popstackmark(&smark);
2945 evalcase(union node *n, int flags)
2949 struct arglist arglist;
2950 struct stackmark smark;
2952 setstackmark(&smark);
2953 arglist.lastp = &arglist.list;
2954 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
2956 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2957 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
2958 if (casematch(patp, arglist.list->text)) {
2959 if (evalskip == 0) {
2960 evaltree(cp->nclist.body, flags);
2967 popstackmark(&smark);
2973 * Kick off a subshell to evaluate a tree.
2977 evalsubshell(union node *n, int flags)
2980 int backgnd = (n->type == NBACKGND);
2983 expredir(n->nredir.redirect);
2984 if (!backgnd && flags & EV_EXIT && !trap[0])
2988 if (forkshell(jp, n, backgnd) == 0) {
2992 flags &=~ EV_TESTED;
2994 redirect(n->nredir.redirect, 0);
2995 evaltreenr(n->nredir.n, flags);
3000 status = waitforjob(jp);
3001 exitstatus = status;
3008 * Compute the names of the files in a redirection list.
3012 expredir(union node *n)
3016 for (redir = n ; redir ; redir = redir->nfile.next) {
3018 fn.lastp = &fn.list;
3019 switch (redir->type) {
3025 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
3026 redir->nfile.expfname = fn.list->text;
3030 if (redir->ndup.vname) {
3031 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
3032 fixredir(redir, fn.list->text, 1);
3042 * Evaluate a pipeline. All the processes in the pipeline are children
3043 * of the process creating the pipeline. (This differs from some versions
3044 * of the shell, which make the last process in a pipeline the parent
3049 evalpipe(union node *n, int flags)
3052 struct nodelist *lp;
3057 TRACE(("evalpipe(0x%lx) called\n", (long)n));
3059 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
3063 jp = makejob(n, pipelen);
3065 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
3069 if (pipe(pip) < 0) {
3071 error("Pipe call failed");
3074 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
3087 evaltreenr(lp->n, flags);
3095 if (n->npipe.backgnd == 0) {
3096 exitstatus = waitforjob(jp);
3097 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
3105 * Execute a command inside back quotes. If it's a builtin command, we
3106 * want to save its output in a block obtained from malloc. Otherwise
3107 * we fork off a subprocess and get the output of the command via a pipe.
3108 * Should be called with interrupts off.
3112 evalbackcmd(union node *n, struct backcmd *result)
3124 saveherefd = herefd;
3132 error("Pipe call failed");
3134 if (forkshell(jp, n, FORK_NOJOB) == 0) {
3143 evaltreenr(n, EV_EXIT);
3147 result->fd = pip[0];
3150 herefd = saveherefd;
3152 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
3153 result->fd, result->buf, result->nleft, result->jp));
3156 #ifdef CONFIG_ASH_CMDCMD
3157 static inline char **
3158 parse_command_args(char **argv, const char **path)
3170 if (c == '-' && !*cp) {
3180 /* run 'typecmd' for other options */
3183 } while ((c = *cp++));
3192 * Execute a simple command.
3196 evalcommand(union node *cmd, int flags)
3198 struct stackmark smark;
3200 struct arglist arglist;
3201 struct arglist varlist;
3205 struct cmdentry cmdentry;
3214 /* First expand the arguments. */
3215 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
3216 setstackmark(&smark);
3217 back_exitstatus = 0;
3219 cmdentry.cmdtype = CMDBUILTIN;
3220 cmdentry.u.cmd = &bltin;
3221 varlist.lastp = &varlist.list;
3222 *varlist.lastp = NULL;
3223 arglist.lastp = &arglist.list;
3224 *arglist.lastp = NULL;
3227 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
3228 struct strlist **spp;
3230 spp = arglist.lastp;
3231 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
3232 for (sp = *spp; sp; sp = sp->next)
3236 argv = nargv = stalloc(sizeof (char *) * (argc + 1));
3237 for (sp = arglist.list ; sp ; sp = sp->next) {
3238 TRACE(("evalcommand arg: %s\n", sp->text));
3239 *nargv++ = sp->text;
3244 if (iflag && funcnest == 0 && argc > 0)
3245 lastarg = nargv[-1];
3247 expredir(cmd->ncmd.redirect);
3248 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH);
3251 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
3252 struct strlist **spp;
3255 spp = varlist.lastp;
3256 expandarg(argp, &varlist, EXP_VARTILDE);
3259 * Modify the command lookup path, if a PATH= assignment
3263 if (varequal(p, path))
3267 /* Print the command if xflag is set. */
3273 sep = eprintlist(varlist.list, sep);
3274 eprintlist(arglist.list, sep);
3282 /* Now locate the command. */
3284 const char *oldpath;
3285 int cmd_flag = DO_ERR;
3290 find_command(argv[0], &cmdentry, cmd_flag, path);
3291 if (cmdentry.cmdtype == CMDUNKNOWN) {
3297 /* implement bltin and command here */
3298 if (cmdentry.cmdtype != CMDBUILTIN)
3301 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
3302 if (cmdentry.u.cmd == EXECCMD)
3304 #ifdef CONFIG_ASH_CMDCMD
3305 if (cmdentry.u.cmd == COMMANDCMD) {
3308 nargv = parse_command_args(argv, &path);
3311 argc -= nargv - argv;
3313 cmd_flag |= DO_NOFUNC;
3321 /* We have a redirection error. */
3325 exitstatus = status;
3329 /* Execute the command. */
3330 switch (cmdentry.cmdtype) {
3332 /* Fork off a child process if necessary. */
3333 if (!(flags & EV_EXIT) || trap[0]) {
3335 jp = makejob(cmd, 1);
3336 if (forkshell(jp, cmd, FORK_FG) != 0) {
3337 exitstatus = waitforjob(jp);
3343 listsetvar(varlist.list, VEXPORT|VSTACK);
3344 shellexec(argv, path, cmdentry.u.index);
3348 cmdenviron = varlist.list;
3350 struct strlist *list = cmdenviron;
3352 if (spclbltin > 0 || argc == 0) {
3354 if (cmd_is_exec && argc > 1)
3357 listsetvar(list, i);
3359 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
3374 exit_status = j + 128;
3375 exitstatus = exit_status;
3377 if (i == EXINT || spclbltin > 0) {
3379 longjmp(handler->loc, 1);
3386 listsetvar(varlist.list, 0);
3387 if (evalfun(cmdentry.u.func, argc, argv, flags))
3393 popredir(cmd_is_exec);
3395 /* dsl: I think this is intended to be used to support
3396 * '_' in 'vi' command mode during line editing...
3397 * However I implemented that within libedit itself.
3399 setvar("_", lastarg, 0);
3400 popstackmark(&smark);
3404 evalbltin(const struct builtincmd *cmd, int argc, char **argv) {
3405 char *volatile savecmdname;
3406 struct jmploc *volatile savehandler;
3407 struct jmploc jmploc;
3410 savecmdname = commandname;
3411 if ((i = setjmp(jmploc.loc)))
3413 savehandler = handler;
3415 commandname = argv[0];
3417 optptr = NULL; /* initialize nextopt */
3418 exitstatus = (*cmd->builtin)(argc, argv);
3421 exitstatus |= outerr(stdout);
3422 commandname = savecmdname;
3424 handler = savehandler;
3430 evalfun(struct funcnode *func, int argc, char **argv, int flags)
3432 volatile struct shparam saveparam;
3433 struct localvar *volatile savelocalvars;
3434 struct jmploc *volatile savehandler;
3435 struct jmploc jmploc;
3438 saveparam = shellparam;
3439 savelocalvars = localvars;
3440 if ((e = setjmp(jmploc.loc))) {
3444 savehandler = handler;
3447 shellparam.malloc = 0;
3450 shellparam.nparam = argc - 1;
3451 shellparam.p = argv + 1;
3452 #ifdef CONFIG_ASH_GETOPTS
3453 shellparam.optind = 1;
3454 shellparam.optoff = -1;
3457 evaltree(&func->n, flags & EV_TESTED);
3463 localvars = savelocalvars;
3464 freeparam(&shellparam);
3465 shellparam = saveparam;
3466 handler = savehandler;
3468 if (evalskip == SKIPFUNC) {
3477 * Search for a command. This is called before we fork so that the
3478 * location of the command will be available in the parent as well as
3483 prehash(union node *n)
3485 struct cmdentry entry;
3487 if (n->type == NCMD && n->ncmd.args)
3488 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
3494 * Builtin commands. Builtin commands whose functions are closely
3495 * tied to evaluation are implemented here.
3503 bltincmd(int argc, char **argv)
3506 * Preserve exitstatus of a previous possible redirection
3509 return back_exitstatus;
3514 * Handle break and continue commands. Break, continue, and return are
3515 * all handled by setting the evalskip flag. The evaluation routines
3516 * above all check this flag, and if it is set they start skipping
3517 * commands rather than executing them. The variable skipcount is
3518 * the number of loops to break/continue, or the number of function
3519 * levels to return. (The latter is always 1.) It should probably
3520 * be an error to break out of more loops than exist, but it isn't
3521 * in the standard shell so we don't make it one here.
3525 breakcmd(int argc, char **argv)
3527 int n = argc > 1 ? number(argv[1]) : 1;
3530 error(illnum, argv[1]);
3534 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
3542 * The return command.
3546 returncmd(int argc, char **argv)
3548 int ret = argc > 1 ? number(argv[1]) : exitstatus;
3551 evalskip = SKIPFUNC;
3556 /* Do what ksh does; skip the rest of the file */
3557 evalskip = SKIPFILE;
3565 falsecmd(int argc, char **argv)
3572 truecmd(int argc, char **argv)
3579 execcmd(int argc, char **argv)
3582 iflag = 0; /* exit on error */
3585 shellexec(argv + 1, pathval(), 0);
3592 eprintlist(struct strlist *sp, int sep)
3597 p = " %s" + (1 - sep);
3599 fprintf(stderr, p, sp->text);
3605 /* $NetBSD: exec.c,v 1.35 2003/01/22 20:36:04 dsl Exp $ */
3608 * When commands are first encountered, they are entered in a hash table.
3609 * This ensures that a full path search will not have to be done for them
3610 * on each invocation.
3612 * We should investigate converting to a linear search, even though that
3613 * would make the command name "hash" a misnomer.
3616 #define CMDTABLESIZE 31 /* should be prime */
3617 #define ARB 1 /* actual size determined at run time */
3622 struct tblentry *next; /* next entry in hash chain */
3623 union param param; /* definition of builtin function */
3624 short cmdtype; /* index identifying command */
3625 char rehash; /* if set, cd done since entry created */
3626 char cmdname[ARB]; /* name of command */
3630 static struct tblentry *cmdtable[CMDTABLESIZE];
3631 static int builtinloc = -1; /* index in path of %builtin, or -1 */
3634 static void tryexec(char *, char **, char **);
3635 static void printentry(struct tblentry *);
3636 static void clearcmdentry(int);
3637 static struct tblentry *cmdlookup(const char *, int);
3638 static void delete_cmd_entry(void);
3642 * Exec a program. Never returns. If you change this routine, you may
3643 * have to change the find_command routine as well.
3647 shellexec(char **argv, const char *path, int idx)
3654 envp = environment();
3655 if (strchr(argv[0], '/') != NULL
3656 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3657 || find_applet_by_name(argv[0])
3660 tryexec(argv[0], argv, envp);
3664 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3665 if (--idx < 0 && pathopt == NULL) {
3666 tryexec(cmdname, argv, envp);
3667 if (errno != ENOENT && errno != ENOTDIR)
3674 /* Map to POSIX errors */
3686 TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
3687 argv[0], e, suppressint ));
3688 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3694 tryexec(char *cmd, char **argv, char **envp)
3697 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3701 #ifdef CONFIG_FEATURE_SH_APPLETS_ALWAYS_WIN
3702 name = bb_get_last_path_component(name);
3703 if(find_applet_by_name(name) != NULL)
3706 if(strchr(name, '/') == NULL && find_applet_by_name(name) != NULL) {
3715 if(strcmp(name, "busybox")) {
3716 for (ap = argv; *ap; ap++);
3717 ap = new = xmalloc((ap - argv + 2) * sizeof(char *));
3718 *ap++ = cmd = "/bin/busybox";
3719 while ((*ap++ = *argv++));
3723 cmd = "/bin/busybox";
3731 execve(cmd, argv, envp);
3732 } while (errno == EINTR);
3734 execve(cmd, argv, envp);
3738 } else if (errno == ENOEXEC) {
3742 for (ap = argv; *ap; ap++)
3744 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
3745 *ap++ = cmd = "/bin/sh";
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);
3801 /*** Command hashing code ***/
3805 hashcmd(int argc, char **argv)
3807 struct tblentry **pp;
3808 struct tblentry *cmdp;
3810 struct cmdentry entry;
3813 while ((c = nextopt("r")) != '\0') {
3817 if (*argptr == NULL) {
3818 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3819 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3820 if (cmdp->cmdtype == CMDNORMAL)
3827 while ((name = *argptr) != NULL) {
3828 if ((cmdp = cmdlookup(name, 0)) != NULL
3829 && (cmdp->cmdtype == CMDNORMAL
3830 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
3832 find_command(name, &entry, DO_ERR, pathval());
3833 if (entry.cmdtype == CMDUNKNOWN)
3842 printentry(struct tblentry *cmdp)
3848 idx = cmdp->param.index;
3851 name = padvance(&path, cmdp->cmdname);
3853 } while (--idx >= 0);
3855 out1fmt(snlfmt, cmdp->rehash ? "*" : nullstr);
3861 * Resolve a command name. If you change this routine, you may have to
3862 * change the shellexec routine as well.
3866 find_command(char *name, struct cmdentry *entry, int act, const char *path)
3868 struct tblentry *cmdp;
3875 struct builtincmd *bcmd;
3877 /* If name contains a slash, don't use PATH or hash table */
3878 if (strchr(name, '/') != NULL) {
3879 entry->u.index = -1;
3881 while (stat(name, &statb) < 0) {
3886 entry->cmdtype = CMDUNKNOWN;
3890 entry->cmdtype = CMDNORMAL;
3894 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3895 if (find_applet_by_name(name)) {
3896 entry->cmdtype = CMDNORMAL;
3897 entry->u.index = -1;
3902 updatetbl = (path == pathval());
3905 if (strstr(path, "%builtin") != NULL)
3909 /* If name is in the table, check answer will be ok */
3910 if ((cmdp = cmdlookup(name, 0)) != NULL) {
3913 switch (cmdp->cmdtype) {
3931 } else if (cmdp->rehash == 0)
3932 /* if not invalidated by cd, we're done */
3936 /* If %builtin not in path, check for builtin next */
3937 bcmd = find_builtin(name);
3938 if (bcmd && (IS_BUILTIN_REGULAR(bcmd) || (
3939 act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0
3941 goto builtin_success;
3943 /* We have to search path. */
3944 prev = -1; /* where to start */
3945 if (cmdp && cmdp->rehash) { /* doing a rehash */
3946 if (cmdp->cmdtype == CMDBUILTIN)
3949 prev = cmdp->param.index;
3955 while ((fullname = padvance(&path, name)) != NULL) {
3956 stunalloc(fullname);
3959 if (prefix(pathopt, "builtin")) {
3961 goto builtin_success;
3963 } else if (!(act & DO_NOFUNC) &&
3964 prefix(pathopt, "func")) {
3967 /* ignore unimplemented options */
3971 /* if rehash, don't redo absolute path names */
3972 if (fullname[0] == '/' && idx <= prev) {
3975 TRACE(("searchexec \"%s\": no change\n", name));
3978 while (stat(fullname, &statb) < 0) {
3983 if (errno != ENOENT && errno != ENOTDIR)
3987 e = EACCES; /* if we fail, this will be the error */
3988 if (!S_ISREG(statb.st_mode))
3990 if (pathopt) { /* this is a %func directory */
3991 stalloc(strlen(fullname) + 1);
3992 readcmdfile(fullname);
3993 if ((cmdp = cmdlookup(name, 0)) == NULL ||
3994 cmdp->cmdtype != CMDFUNCTION)
3995 error("%s not defined in %s", name, fullname);
3996 stunalloc(fullname);
3999 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
4001 entry->cmdtype = CMDNORMAL;
4002 entry->u.index = idx;
4006 cmdp = cmdlookup(name, 1);
4007 cmdp->cmdtype = CMDNORMAL;
4008 cmdp->param.index = idx;
4013 /* We failed. If there was an entry for this command, delete it */
4014 if (cmdp && updatetbl)
4017 sh_warnx("%s: %s", name, errmsg(e, E_EXEC));
4018 entry->cmdtype = CMDUNKNOWN;
4023 entry->cmdtype = CMDBUILTIN;
4024 entry->u.cmd = bcmd;
4028 cmdp = cmdlookup(name, 1);
4029 cmdp->cmdtype = CMDBUILTIN;
4030 cmdp->param.cmd = bcmd;
4034 entry->cmdtype = cmdp->cmdtype;
4035 entry->u = cmdp->param;
4040 * Wrapper around strcmp for qsort/bsearch/...
4042 static int pstrcmp(const void *a, const void *b)
4044 return strcmp((const char *) a, (*(const char *const *) b) + 1);
4048 * Search the table of builtin commands.
4051 static struct builtincmd *
4052 find_builtin(const char *name)
4054 struct builtincmd *bp;
4057 name, builtincmd, NUMBUILTINS, sizeof(struct builtincmd),
4066 * Called when a cd is done. Marks all commands so the next time they
4067 * are executed they will be rehashed.
4073 struct tblentry **pp;
4074 struct tblentry *cmdp;
4076 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4077 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4078 if (cmdp->cmdtype == CMDNORMAL || (
4079 cmdp->cmdtype == CMDBUILTIN &&
4080 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) &&
4091 * Fix command hash table when PATH changed.
4092 * Called before PATH is changed. The argument is the new value of PATH;
4093 * pathval() still returns the old value at this point.
4094 * Called with interrupts off.
4098 changepath(const char *newval)
4100 const char *old, *new;
4107 firstchange = 9999; /* assume no change */
4113 if ((*old == '\0' && *new == ':')
4114 || (*old == ':' && *new == '\0'))
4116 old = new; /* ignore subsequent differences */
4120 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
4127 if (builtinloc < 0 && idx_bltin >= 0)
4128 builtinloc = idx_bltin; /* zap builtins */
4129 if (builtinloc >= 0 && idx_bltin < 0)
4131 clearcmdentry(firstchange);
4132 builtinloc = idx_bltin;
4137 * Clear out command entries. The argument specifies the first entry in
4138 * PATH which has changed.
4142 clearcmdentry(int firstchange)
4144 struct tblentry **tblp;
4145 struct tblentry **pp;
4146 struct tblentry *cmdp;
4149 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4151 while ((cmdp = *pp) != NULL) {
4152 if ((cmdp->cmdtype == CMDNORMAL &&
4153 cmdp->param.index >= firstchange)
4154 || (cmdp->cmdtype == CMDBUILTIN &&
4155 builtinloc >= firstchange)) {
4169 * Locate a command in the command hash table. If "add" is nonzero,
4170 * add the command to the table if it is not already present. The
4171 * variable "lastcmdentry" is set to point to the address of the link
4172 * pointing to the entry, so that delete_cmd_entry can delete the
4175 * Interrupts must be off if called with add != 0.
4178 static struct tblentry **lastcmdentry;
4181 static struct tblentry *
4182 cmdlookup(const char *name, int add)
4184 unsigned int hashval;
4186 struct tblentry *cmdp;
4187 struct tblentry **pp;
4190 hashval = (unsigned char)*p << 4;
4192 hashval += (unsigned char)*p++;
4194 pp = &cmdtable[hashval % CMDTABLESIZE];
4195 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4196 if (equal(cmdp->cmdname, name))
4200 if (add && cmdp == NULL) {
4201 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4202 + strlen(name) + 1);
4204 cmdp->cmdtype = CMDUNKNOWN;
4205 strcpy(cmdp->cmdname, name);
4212 * Delete the command entry returned on the last lookup.
4216 delete_cmd_entry(void)
4218 struct tblentry *cmdp;
4221 cmdp = *lastcmdentry;
4222 *lastcmdentry = cmdp->next;
4223 if (cmdp->cmdtype == CMDFUNCTION)
4224 freefunc(cmdp->param.func);
4231 * Add a new command entry, replacing any existing command entry for
4232 * the same name - except special builtins.
4236 addcmdentry(char *name, struct cmdentry *entry)
4238 struct tblentry *cmdp;
4240 cmdp = cmdlookup(name, 1);
4241 if (cmdp->cmdtype == CMDFUNCTION) {
4242 freefunc(cmdp->param.func);
4244 cmdp->cmdtype = entry->cmdtype;
4245 cmdp->param = entry->u;
4250 * Make a copy of a parse tree.
4253 static inline struct funcnode *
4254 copyfunc(union node *n)
4259 funcblocksize = offsetof(struct funcnode, n);
4262 blocksize = funcblocksize;
4263 f = ckmalloc(blocksize + funcstringsize);
4264 funcblock = (char *) f + offsetof(struct funcnode, n);
4265 funcstring = (char *) f + blocksize;
4272 * Define a shell function.
4276 defun(char *name, union node *func)
4278 struct cmdentry entry;
4281 entry.cmdtype = CMDFUNCTION;
4282 entry.u.func = copyfunc(func);
4283 addcmdentry(name, &entry);
4289 * Delete a function if it exists.
4293 unsetfunc(const char *name)
4295 struct tblentry *cmdp;
4297 if ((cmdp = cmdlookup(name, 0)) != NULL &&
4298 cmdp->cmdtype == CMDFUNCTION)
4303 * Locate and print what a word is...
4307 #ifdef CONFIG_ASH_CMDCMD
4309 describe_command(char *command, int describe_command_verbose)
4311 #define describe_command_verbose 1
4313 describe_command(char *command)
4316 struct cmdentry entry;
4317 struct tblentry *cmdp;
4318 #ifdef CONFIG_ASH_ALIAS
4319 const struct alias *ap;
4321 const char *path = pathval();
4323 if (describe_command_verbose) {
4327 /* First look at the keywords */
4328 if (findkwd(command)) {
4329 out1str(describe_command_verbose ? " is a shell keyword" : command);
4333 #ifdef CONFIG_ASH_ALIAS
4334 /* Then look at the aliases */
4335 if ((ap = lookupalias(command, 0)) != NULL) {
4336 if (describe_command_verbose) {
4337 out1fmt(" is an alias for %s", ap->val);
4346 /* Then check if it is a tracked alias */
4347 if ((cmdp = cmdlookup(command, 0)) != NULL) {
4348 entry.cmdtype = cmdp->cmdtype;
4349 entry.u = cmdp->param;
4351 /* Finally use brute force */
4352 find_command(command, &entry, DO_ABS, path);
4355 switch (entry.cmdtype) {
4357 int j = entry.u.index;
4363 p = padvance(&path, command);
4367 if (describe_command_verbose) {
4369 (cmdp ? " a tracked alias for" : nullstr), p
4378 if (describe_command_verbose) {
4379 out1str(" is a shell function");
4386 if (describe_command_verbose) {
4387 out1fmt(" is a %sshell builtin",
4388 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
4389 "special " : nullstr
4397 if (describe_command_verbose) {
4398 out1str(": not found\n");
4409 typecmd(int argc, char **argv)
4414 for (i = 1; i < argc; i++) {
4415 #ifdef CONFIG_ASH_CMDCMD
4416 err |= describe_command(argv[i], 1);
4418 err |= describe_command(argv[i]);
4424 #ifdef CONFIG_ASH_CMDCMD
4426 commandcmd(int argc, char **argv)
4429 int default_path = 0;
4430 int verify_only = 0;
4431 int verbose_verify_only = 0;
4433 while ((c = nextopt("pvV")) != '\0')
4438 "command: nextopt returned character code 0%o\n", c);
4448 verbose_verify_only = 1;
4452 if (default_path + verify_only + verbose_verify_only > 1 ||
4455 "command [-p] command [arg ...]\n"
4456 "command {-v|-V} command\n");
4460 if (verify_only || verbose_verify_only) {
4461 return describe_command(*argptr, verbose_verify_only);
4468 /* $NetBSD: expand.c,v 1.56 2002/11/24 22:35:39 christos Exp $ */
4471 * Routines to expand arguments to commands. We have to deal with
4472 * backquotes, shell variables, and file metacharacters.
4478 #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4479 #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
4480 #define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
4481 #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
4482 #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
4485 * Structure specifying which parts of the string should be searched
4486 * for IFS characters.
4490 struct ifsregion *next; /* next region in list */
4491 int begoff; /* offset of start of region */
4492 int endoff; /* offset of end of region */
4493 int nulonly; /* search for nul bytes only */
4496 /* output of current string */
4497 static char *expdest;
4498 /* list of back quote expressions */
4499 static struct nodelist *argbackq;
4500 /* first struct in list of ifs regions */
4501 static struct ifsregion ifsfirst;
4502 /* last struct in list */
4503 static struct ifsregion *ifslastp;
4504 /* holds expanded arg list */
4505 static struct arglist exparg;
4507 static void argstr(char *, int);
4508 static char *exptilde(char *, char *, int);
4509 static void expbackq(union node *, int, int);
4510 static const char *subevalvar(char *, char *, int, int, int, int, int);
4511 static char *evalvar(char *, int);
4512 static int varisset(char *, int);
4513 static void strtodest(const char *, int, int);
4514 static void memtodest(const char *p, size_t len, int syntax, int quotes);
4515 static void varvalue(char *, int, int);
4516 static void recordregion(int, int, int);
4517 static void removerecordregions(int);
4518 static void ifsbreakup(char *, struct arglist *);
4519 static void ifsfree(void);
4520 static void expandmeta(struct strlist *, int);
4521 static void addglob(const glob_t *);
4522 static void addfname(char *);
4523 static int patmatch(char *, const char *);
4525 static int cvtnum(long);
4526 static size_t esclen(const char *, const char *);
4527 static char *scanleft(char *, char *, char *, char *, int, int);
4528 static char *scanright(char *, char *, char *, char *, int, int);
4529 static void varunset(const char *, const char *, const char *, int)
4530 __attribute__((__noreturn__));
4533 #define pmatch(a, b) !fnmatch((a), (b), 0)
4535 * Prepare a pattern for a glob(3) call.
4537 * Returns an stalloced string.
4540 static inline char *
4541 preglob(const char *pattern, int quoted, int flag) {
4542 flag |= RMESCAPE_GLOB;
4544 flag |= RMESCAPE_QUOTED;
4546 return _rmescapes((char *)pattern, flag);
4551 esclen(const char *start, const char *p) {
4554 while (p > start && *--p == CTLESC) {
4562 * Expand shell variables and backquotes inside a here document.
4566 expandhere(union node *arg, int fd)
4569 expandarg(arg, (struct arglist *)NULL, 0);
4570 xwrite(fd, stackblock(), expdest - (char *)stackblock());
4575 * Perform variable substitution and command substitution on an argument,
4576 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4577 * perform splitting and file name expansion. When arglist is NULL, perform
4578 * here document expansion.
4582 expandarg(union node *arg, struct arglist *arglist, int flag)
4587 argbackq = arg->narg.backquote;
4588 STARTSTACKSTR(expdest);
4589 ifsfirst.next = NULL;
4591 argstr(arg->narg.text, flag);
4592 if (arglist == NULL) {
4593 return; /* here document expanded */
4595 STPUTC('\0', expdest);
4596 p = grabstackstr(expdest);
4597 exparg.lastp = &exparg.list;
4601 if (flag & EXP_FULL) {
4602 ifsbreakup(p, &exparg);
4603 *exparg.lastp = NULL;
4604 exparg.lastp = &exparg.list;
4605 expandmeta(exparg.list, flag);
4607 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
4609 sp = (struct strlist *)stalloc(sizeof (struct strlist));
4612 exparg.lastp = &sp->next;
4616 *exparg.lastp = NULL;
4618 *arglist->lastp = exparg.list;
4619 arglist->lastp = exparg.lastp;
4626 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4627 * characters to allow for further processing. Otherwise treat
4628 * $@ like $* since no splitting will be performed.
4632 argstr(char *p, int flag)
4634 static const char spclchars[] = {
4642 CTLBACKQ | CTLQUOTE,
4643 #ifdef CONFIG_ASH_MATH_SUPPORT
4648 const char *reject = spclchars;
4650 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
4651 int breakall = flag & EXP_WORD;
4656 if (!(flag & EXP_VARTILDE)) {
4658 } else if (flag & EXP_VARTILDE2) {
4663 if (flag & EXP_TILDE) {
4669 if (*q == CTLESC && (flag & EXP_QWORD))
4672 p = exptilde(p, q, flag);
4675 startloc = expdest - (char *)stackblock();
4677 length += strcspn(p + length, reject);
4679 if (c && (!(c & 0x80)
4680 #ifdef CONFIG_ASH_MATH_SUPPORT
4684 /* c == '=' || c == ':' || c == CTLENDARI */
4689 expdest = stnputs(p, length, expdest);
4690 newloc = expdest - (char *)stackblock();
4691 if (breakall && !inquotes && newloc > startloc) {
4692 recordregion(startloc, newloc, 0);
4703 if (flag & EXP_VARTILDE2) {
4707 flag |= EXP_VARTILDE2;
4712 * sort of a hack - expand tildes in variable
4713 * assignments (after the first '=' and after ':'s).
4722 case CTLENDVAR: /* ??? */
4725 /* "$@" syntax adherence hack */
4728 !memcmp(p, dolatstr, DOLATSTRLEN) &&
4729 (p[4] == CTLQUOTEMARK || (
4730 p[4] == CTLENDVAR &&
4731 p[5] == CTLQUOTEMARK
4734 p = evalvar(p + 1, flag) + 1;
4737 inquotes = !inquotes;
4750 p = evalvar(p, flag);
4754 case CTLBACKQ|CTLQUOTE:
4755 expbackq(argbackq->n, c, quotes);
4756 argbackq = argbackq->next;
4758 #ifdef CONFIG_ASH_MATH_SUPPORT
4771 exptilde(char *startp, char *p, int flag)
4777 int quotes = flag & (EXP_FULL | EXP_CASE);
4782 while ((c = *++p) != '\0') {
4789 if (flag & EXP_VARTILDE)
4799 if (*name == '\0') {
4800 if ((home = lookupvar(homestr)) == NULL)
4803 if ((pw = getpwnam(name)) == NULL)
4810 startloc = expdest - (char *)stackblock();
4811 strtodest(home, SQSYNTAX, quotes);
4812 recordregion(startloc, expdest - (char *)stackblock(), 0);
4821 removerecordregions(int endoff)
4823 if (ifslastp == NULL)
4826 if (ifsfirst.endoff > endoff) {
4827 while (ifsfirst.next != NULL) {
4828 struct ifsregion *ifsp;
4830 ifsp = ifsfirst.next->next;
4831 ckfree(ifsfirst.next);
4832 ifsfirst.next = ifsp;
4835 if (ifsfirst.begoff > endoff)
4838 ifslastp = &ifsfirst;
4839 ifsfirst.endoff = endoff;
4844 ifslastp = &ifsfirst;
4845 while (ifslastp->next && ifslastp->next->begoff < endoff)
4846 ifslastp=ifslastp->next;
4847 while (ifslastp->next != NULL) {
4848 struct ifsregion *ifsp;
4850 ifsp = ifslastp->next->next;
4851 ckfree(ifslastp->next);
4852 ifslastp->next = ifsp;
4855 if (ifslastp->endoff > endoff)
4856 ifslastp->endoff = endoff;
4860 #ifdef CONFIG_ASH_MATH_SUPPORT
4862 * Expand arithmetic expression. Backup to start of expression,
4863 * evaluate, place result in (backed up) result, adjust string position.
4876 * This routine is slightly over-complicated for
4877 * efficiency. Next we scan backwards looking for the
4878 * start of arithmetic.
4880 start = stackblock();
4887 while (*p != CTLARI) {
4891 error("missing CTLARI (shouldn't happen)");
4896 esc = esclen(start, p);
4906 removerecordregions(begoff);
4915 len = cvtnum(dash_arith(p + 2));
4918 recordregion(begoff, begoff + len, 0);
4923 * Expand stuff in backwards quotes.
4927 expbackq(union node *cmd, int quoted, int quotes)
4935 int syntax = quoted? DQSYNTAX : BASESYNTAX;
4936 struct stackmark smark;
4939 setstackmark(&smark);
4941 startloc = dest - (char *)stackblock();
4943 evalbackcmd(cmd, (struct backcmd *) &in);
4944 popstackmark(&smark);
4951 memtodest(p, i, syntax, quotes);
4955 i = safe_read(in.fd, buf, sizeof buf);
4956 TRACE(("expbackq: read returns %d\n", i));
4966 back_exitstatus = waitforjob(in.jp);
4970 /* Eat all trailing newlines */
4972 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
4977 recordregion(startloc, dest - (char *)stackblock(), 0);
4978 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4979 (dest - (char *)stackblock()) - startloc,
4980 (dest - (char *)stackblock()) - startloc,
4981 stackblock() + startloc));
4987 char *startp, char *rmesc, char *rmescend, char *str, int quotes,
4998 const char *s = loc2;
5004 match = pmatch(str, s);
5008 if (quotes && *loc == CTLESC)
5019 char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5026 for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5029 const char *s = loc2;
5034 match = pmatch(str, s);
5041 esc = esclen(startp, loc);
5053 subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
5057 int saveherefd = herefd;
5058 struct nodelist *saveargbackq = argbackq;
5060 char *rmesc, *rmescend;
5062 char *(*scan)(char *, char *, char *, char *, int , int);
5065 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
5066 STPUTC('\0', expdest);
5067 herefd = saveherefd;
5068 argbackq = saveargbackq;
5069 startp = stackblock() + startloc;
5073 setvar(str, startp, 0);
5074 amount = startp - expdest;
5075 STADJUST(amount, expdest);
5079 varunset(p, str, startp, varflags);
5083 subtype -= VSTRIMRIGHT;
5085 if (subtype < 0 || subtype > 3)
5090 rmescend = stackblock() + strloc;
5092 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5093 if (rmesc != startp) {
5095 startp = stackblock() + startloc;
5099 str = stackblock() + strloc;
5100 preglob(str, varflags & VSQUOTE, 0);
5102 /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
5103 zero = subtype >> 1;
5104 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
5105 scan = (subtype & 1) ^ zero ? scanleft : scanright;
5107 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
5110 memmove(startp, loc, str - loc);
5111 loc = startp + (str - loc) - 1;
5114 amount = loc - expdest;
5115 STADJUST(amount, expdest);
5122 * Expand a variable, and return a pointer to the next character in the
5126 evalvar(char *p, int flag)
5140 quotes = flag & (EXP_FULL | EXP_CASE);
5142 subtype = varflags & VSTYPE;
5143 quoted = varflags & VSQUOTE;
5145 easy = (!quoted || (*var == '@' && shellparam.nparam));
5147 startloc = expdest - (char *)stackblock();
5148 p = strchr(p, '=') + 1;
5150 if (!is_name(*var)) {
5151 set = varisset(var, varflags & VSNUL);
5153 if (subtype == VSPLUS)
5156 varvalue(var, quoted, flag);
5157 if (subtype == VSLENGTH) {
5159 expdest - (char *)stackblock() -
5161 STADJUST(-varlen, expdest);
5168 /* jump here after setting a variable with ${var=text} */
5169 val = lookupvar(var);
5170 set = !val || ((varflags & VSNUL) && !*val);
5171 if (subtype == VSPLUS)
5174 varlen = strlen(val);
5175 if (subtype == VSLENGTH)
5178 val, varlen, quoted ? DQSYNTAX : BASESYNTAX,
5185 if (subtype == VSMINUS) {
5189 p, flag | EXP_TILDE |
5190 (quoted ? EXP_QWORD : EXP_WORD)
5199 if (subtype == VSASSIGN || subtype == VSQUESTION) {
5201 if (subevalvar(p, var, 0, subtype, startloc,
5205 * Remove any recorded regions beyond
5208 removerecordregions(startloc);
5219 varunset(p, var, 0, 0);
5221 if (subtype == VSLENGTH) {
5227 if (subtype == VSNORMAL) {
5231 recordregion(startloc, expdest - (char *)stackblock(), quoted);
5240 case VSTRIMRIGHTMAX:
5249 * Terminate the string and start recording the pattern
5252 STPUTC('\0', expdest);
5253 patloc = expdest - (char *)stackblock();
5254 if (subevalvar(p, NULL, patloc, subtype,
5255 startloc, varflags, quotes) == 0) {
5256 int amount = expdest - (
5257 (char *)stackblock() + patloc - 1
5259 STADJUST(-amount, expdest);
5261 /* Remove any recorded regions beyond start of variable */
5262 removerecordregions(startloc);
5267 if (subtype != VSNORMAL) { /* skip to end of alternative */
5270 if ((c = *p++) == CTLESC)
5272 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
5274 argbackq = argbackq->next;
5275 } else if (c == CTLVAR) {
5276 if ((*p++ & VSTYPE) != VSNORMAL)
5278 } else if (c == CTLENDVAR) {
5290 * Test whether a specialized variable is set.
5294 varisset(char *name, int nulok)
5297 return backgndpid != 0;
5298 else if (*name == '@' || *name == '*') {
5299 if (*shellparam.p == NULL)
5305 for (av = shellparam.p; *av; av++)
5310 } else if (is_digit(*name)) {
5312 int num = atoi(name);
5314 if (num > shellparam.nparam)
5320 ap = shellparam.p[num - 1];
5322 if (nulok && (ap == NULL || *ap == '\0'))
5331 * Put a string on the stack.
5335 memtodest(const char *p, size_t len, int syntax, int quotes) {
5338 q = makestrspace(len * 2, q);
5344 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5354 strtodest(const char *p, int syntax, int quotes)
5356 memtodest(p, strlen(p), syntax, quotes);
5362 * Add the value of a specialized variable to the stack string.
5366 varvalue(char *name, int quoted, int flags)
5375 int allow_split = flags & EXP_FULL;
5376 int quotes = flags & (EXP_FULL | EXP_CASE);
5378 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5387 num = shellparam.nparam;
5395 for (i = 0 ; i < NOPTS ; i++) {
5397 STPUTC(optletters(i), expdest);
5401 if (allow_split && quoted) {
5402 sep = 1 << CHAR_BIT;
5407 sep = ifsset() ? ifsval()[0] : ' ';
5409 sepq = (SIT(sep, syntax) == CCTL) || (SIT(sep, syntax) == CBACK);
5412 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
5413 strtodest(p, syntax, quotes);
5424 strtodest(arg0, syntax, quotes);
5428 if (num > 0 && num <= shellparam.nparam) {
5429 strtodest(shellparam.p[num - 1], syntax, quotes);
5438 * Record the fact that we have to scan this region of the
5439 * string for IFS characters.
5443 recordregion(int start, int end, int nulonly)
5445 struct ifsregion *ifsp;
5447 if (ifslastp == NULL) {
5451 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
5453 ifslastp->next = ifsp;
5457 ifslastp->begoff = start;
5458 ifslastp->endoff = end;
5459 ifslastp->nulonly = nulonly;
5465 * Break the argument string into pieces based upon IFS and add the
5466 * strings to the argument list. The regions of the string to be
5467 * searched for IFS characters have been stored by recordregion.
5470 ifsbreakup(char *string, struct arglist *arglist)
5472 struct ifsregion *ifsp;
5477 const char *ifs, *realifs;
5483 if (ifslastp != NULL) {
5486 realifs = ifsset() ? ifsval() : defifs;
5489 p = string + ifsp->begoff;
5490 nulonly = ifsp->nulonly;
5491 ifs = nulonly ? nullstr : realifs;
5493 while (p < string + ifsp->endoff) {
5497 if (strchr(ifs, *p)) {
5499 ifsspc = (strchr(defifs, *p) != NULL);
5500 /* Ignore IFS whitespace at start */
5501 if (q == start && ifsspc) {
5507 sp = (struct strlist *)stalloc(sizeof *sp);
5509 *arglist->lastp = sp;
5510 arglist->lastp = &sp->next;
5514 if (p >= string + ifsp->endoff) {
5520 if (strchr(ifs, *p) == NULL ) {
5523 } else if (strchr(defifs, *p) == NULL) {
5539 } while ((ifsp = ifsp->next) != NULL);
5548 sp = (struct strlist *)stalloc(sizeof *sp);
5550 *arglist->lastp = sp;
5551 arglist->lastp = &sp->next;
5557 struct ifsregion *p;
5562 struct ifsregion *ifsp;
5568 ifsfirst.next = NULL;
5575 * Expand shell metacharacters. At this point, the only control characters
5576 * should be escapes. The results are stored in the list exparg.
5580 expandmeta(str, flag)
5581 struct strlist *str;
5584 /* TODO - EXP_REDIR */
5594 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
5595 i = glob(p, GLOB_NOMAGIC, 0, &pglob);
5600 if (!(pglob.gl_flags & GLOB_MAGCHAR))
5611 *exparg.lastp = str;
5612 rmescapes(str->text);
5613 exparg.lastp = &str->next;
5615 default: /* GLOB_NOSPACE */
5616 error(bb_msg_memory_exhausted);
5624 * Add the result of glob(3) to the list.
5629 const glob_t *pglob;
5631 char **p = pglob->gl_pathv;
5640 * Add a file name to the list.
5644 addfname(char *name)
5648 sp = (struct strlist *)stalloc(sizeof *sp);
5649 sp->text = sstrdup(name);
5651 exparg.lastp = &sp->next;
5656 * Returns true if the pattern matches the string.
5660 patmatch(char *pattern, const char *string)
5662 return pmatch(preglob(pattern, 0, 0), string);
5667 * Remove any CTLESC characters from a string.
5671 _rmescapes(char *str, int flag)
5674 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
5679 p = strpbrk(str, qchars);
5685 if (flag & RMESCAPE_ALLOC) {
5686 size_t len = p - str;
5687 size_t fulllen = len + strlen(p) + 1;
5689 if (flag & RMESCAPE_GROW) {
5690 r = makestrspace(fulllen, expdest);
5691 } else if (flag & RMESCAPE_HEAP) {
5692 r = ckmalloc(fulllen);
5694 r = stalloc(fulllen);
5698 q = mempcpy(q, str, len);
5701 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5702 globbing = flag & RMESCAPE_GLOB;
5703 notescaped = globbing;
5705 if (*p == CTLQUOTEMARK) {
5706 inquotes = ~inquotes;
5708 notescaped = globbing;
5712 /* naked back slash */
5718 if (notescaped && inquotes && *p != '/') {
5722 notescaped = globbing;
5727 if (flag & RMESCAPE_GROW) {
5729 STADJUST(q - r + 1, expdest);
5737 * See if a pattern matches in a case statement.
5741 casematch(union node *pattern, char *val)
5743 struct stackmark smark;
5746 setstackmark(&smark);
5747 argbackq = pattern->narg.backquote;
5748 STARTSTACKSTR(expdest);
5750 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
5751 STACKSTRNUL(expdest);
5752 result = patmatch(stackblock(), val);
5753 popstackmark(&smark);
5766 expdest = makestrspace(32, expdest);
5767 len = fmtstr(expdest, 32, "%ld", num);
5768 STADJUST(len, expdest);
5773 varunset(const char *end, const char *var, const char *umsg, int varflags)
5779 msg = "parameter not set";
5781 if (*end == CTLENDVAR) {
5782 if (varflags & VSNUL)
5787 error("%.*s: %s%s", end - var - 1, var, msg, tail);
5789 /* $NetBSD: input.c,v 1.37 2002/11/24 22:35:40 christos Exp $ */
5794 * This file implements the input routines used by the parser.
5797 #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
5798 #define IBUFSIZ (BUFSIZ + 1)
5800 static void pushfile(void);
5803 * Read a line from the script.
5806 static inline char *
5807 pfgets(char *line, int len)
5813 while (--nleft > 0) {
5830 * Read a character from the script, returning PEOF on end of file.
5831 * Nul characters in the input are silently discarded.
5834 #define pgetc_as_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
5836 #ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
5837 #define pgetc_macro() pgetc()
5841 return pgetc_as_macro();
5844 #define pgetc_macro() pgetc_as_macro()
5848 return pgetc_macro();
5854 * Same as pgetc(), but ignores PEOA.
5856 #ifdef CONFIG_ASH_ALIAS
5857 static int pgetc2(void)
5863 } while (c == PEOA);
5867 static inline int pgetc2(void)
5869 return pgetc_macro();
5874 #ifdef CONFIG_FEATURE_COMMAND_EDITING
5875 static const char *cmdedit_prompt;
5876 static inline void putprompt(const char *s)
5881 static inline void putprompt(const char *s)
5891 char *buf = parsefile->buf;
5895 #ifdef CONFIG_FEATURE_COMMAND_EDITING
5896 if (!iflag || parsefile->fd)
5897 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
5899 nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
5901 /* Ctrl+C presend */
5906 /* Ctrl+D presend */
5911 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
5915 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
5916 int flags = fcntl(0, F_GETFL, 0);
5917 if (flags >= 0 && flags & O_NONBLOCK) {
5918 flags &=~ O_NONBLOCK;
5919 if (fcntl(0, F_SETFL, flags) >= 0) {
5920 out2str("sh: turning off NDELAY mode\n");
5930 * Refill the input buffer and return the next input character:
5932 * 1) If a string was pushed back on the input, pop it;
5933 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
5934 * from a string so we can't refill the buffer, return EOF.
5935 * 3) If the is more stuff in this buffer, use it else call read to fill it.
5936 * 4) Process input up to the next newline, deleting nul characters.
5946 while (parsefile->strpush) {
5947 #ifdef CONFIG_ASH_ALIAS
5948 if (parsenleft == -1 && parsefile->strpush->ap &&
5949 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
5954 if (--parsenleft >= 0)
5955 return (*parsenextc++);
5957 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
5962 if (parselleft <= 0) {
5963 if ((parselleft = preadfd()) <= 0) {
5964 parselleft = parsenleft = EOF_NLEFT;
5971 /* delete nul characters */
5972 for (more = 1; more;) {
5979 parsenleft = q - parsenextc;
5980 more = 0; /* Stop processing here */
5987 if (--parselleft <= 0 && more) {
5988 parsenleft = q - parsenextc - 1;
5999 out2str(parsenextc);
6005 return *parsenextc++;
6009 * Undo the last call to pgetc. Only one character may be pushed back.
6010 * PEOF may be pushed back.
6021 * Push a string back onto the input at this current parsefile level.
6022 * We handle aliases this way.
6025 pushstring(char *s, void *ap)
6032 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6033 if (parsefile->strpush) {
6034 sp = ckmalloc(sizeof (struct strpush));
6035 sp->prev = parsefile->strpush;
6036 parsefile->strpush = sp;
6038 sp = parsefile->strpush = &(parsefile->basestrpush);
6039 sp->prevstring = parsenextc;
6040 sp->prevnleft = parsenleft;
6041 #ifdef CONFIG_ASH_ALIAS
6042 sp->ap = (struct alias *)ap;
6044 ((struct alias *)ap)->flag |= ALIASINUSE;
6056 struct strpush *sp = parsefile->strpush;
6059 #ifdef CONFIG_ASH_ALIAS
6061 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6062 checkkwd |= CHKALIAS;
6064 if (sp->string != sp->ap->val) {
6067 sp->ap->flag &= ~ALIASINUSE;
6068 if (sp->ap->flag & ALIASDEAD) {
6069 unalias(sp->ap->name);
6073 parsenextc = sp->prevstring;
6074 parsenleft = sp->prevnleft;
6075 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6076 parsefile->strpush = sp->prev;
6077 if (sp != &(parsefile->basestrpush))
6083 * Set the input to take input from a file. If push is set, push the
6084 * old input onto the stack first.
6088 setinputfile(const char *fname, int push)
6094 if ((fd = open(fname, O_RDONLY)) < 0)
6095 error("Can't open %s", fname);
6097 fd2 = copyfd(fd, 10);
6100 error("Out of file descriptors");
6103 setinputfd(fd, push);
6109 * Like setinputfile, but takes an open file descriptor. Call this with
6114 setinputfd(int fd, int push)
6116 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
6122 if (parsefile->buf == NULL)
6123 parsefile->buf = ckmalloc(IBUFSIZ);
6124 parselleft = parsenleft = 0;
6130 * Like setinputfile, but takes input from a string.
6134 setinputstring(char *string)
6138 parsenextc = string;
6139 parsenleft = strlen(string);
6140 parsefile->buf = NULL;
6148 * To handle the "." command, a stack of input files is used. Pushfile
6149 * adds a new entry to the stack and popfile restores the previous level.
6155 struct parsefile *pf;
6157 parsefile->nleft = parsenleft;
6158 parsefile->lleft = parselleft;
6159 parsefile->nextc = parsenextc;
6160 parsefile->linno = plinno;
6161 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
6162 pf->prev = parsefile;
6165 pf->basestrpush.prev = NULL;
6173 struct parsefile *pf = parsefile;
6182 parsefile = pf->prev;
6184 parsenleft = parsefile->nleft;
6185 parselleft = parsefile->lleft;
6186 parsenextc = parsefile->nextc;
6187 plinno = parsefile->linno;
6193 * Return to top level.
6199 while (parsefile != &basepf)
6206 * Close the file(s) that the shell is reading commands from. Called
6207 * after a fork is done.
6214 if (parsefile->fd > 0) {
6215 close(parsefile->fd);
6219 /* $NetBSD: jobs.c,v 1.56 2002/11/25 12:13:03 agc Exp $ */
6222 /* mode flags for set_curjob */
6223 #define CUR_DELETE 2
6224 #define CUR_RUNNING 1
6225 #define CUR_STOPPED 0
6227 /* mode flags for dowait */
6228 #define DOWAIT_NORMAL 0
6229 #define DOWAIT_BLOCK 1
6232 static struct job *jobtab;
6234 static unsigned njobs;
6236 /* pgrp of shell on invocation */
6237 static int initialpgrp;
6238 static int ttyfd = -1;
6241 static struct job *curjob;
6242 /* number of presumed living untracked jobs */
6245 static void set_curjob(struct job *, unsigned);
6247 static int restartjob(struct job *, int);
6248 static void xtcsetpgrp(int, pid_t);
6249 static char *commandtext(union node *);
6250 static void cmdlist(union node *, int);
6251 static void cmdtxt(union node *);
6252 static void cmdputs(const char *);
6253 static void showpipe(struct job *, FILE *);
6255 static int sprint_status(char *, int, int);
6256 static void freejob(struct job *);
6257 static struct job *getjob(const char *, int);
6258 static struct job *growjobtab(void);
6259 static void forkchild(struct job *, union node *, int);
6260 static void forkparent(struct job *, union node *, int, pid_t);
6261 static int dowait(int, struct job *);
6262 static int getstatus(struct job *);
6265 set_curjob(struct job *jp, unsigned mode)
6268 struct job **jpp, **curp;
6270 /* first remove from list */
6271 jpp = curp = &curjob;
6276 jpp = &jp1->prev_job;
6278 *jpp = jp1->prev_job;
6280 /* Then re-insert in correct position */
6288 /* job being deleted */
6291 /* newly created job or backgrounded job,
6292 put after all stopped jobs. */
6296 if (!jp1 || jp1->state != JOBSTOPPED)
6299 jpp = &jp1->prev_job;
6305 /* newly stopped job - becomes curjob */
6306 jp->prev_job = *jpp;
6314 * Turn job control on and off.
6316 * Note: This code assumes that the third arg to ioctl is a character
6317 * pointer, which is true on Berkeley systems but not System V. Since
6318 * System V doesn't have job control yet, this isn't a problem now.
6320 * Called with interrupts off.
6329 if (on == jobctl || rootshell == 0)
6333 ofd = fd = open(_PATH_TTY, O_RDWR);
6336 while (!isatty(fd) && --fd >= 0)
6339 fd = fcntl(fd, F_DUPFD, 10);
6343 fcntl(fd, F_SETFD, FD_CLOEXEC);
6344 do { /* while we are in the background */
6345 if ((pgrp = tcgetpgrp(fd)) < 0) {
6347 sh_warnx("can't access tty; job control turned off");
6351 if (pgrp == getpgrp())
6362 xtcsetpgrp(fd, pgrp);
6364 /* turning job control off */
6367 xtcsetpgrp(fd, pgrp);
6394 "Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6395 "kill -l [exitstatus]"
6399 if (**++argv == '-') {
6400 signo = decode_signal(*argv + 1, 1);
6404 while ((c = nextopt("ls:")) != '\0')
6414 signo = decode_signal(optionarg, 1);
6417 "invalid signal number or name: %s",
6428 if (!list && signo < 0)
6431 if ((signo < 0 || !*argv) ^ list) {
6439 for (i = 1; i < NSIG; i++) {
6440 name = u_signal_names(0, &i, 1);
6442 out1fmt(snlfmt, name);
6446 name = u_signal_names(*argptr, &signo, -1);
6448 out1fmt(snlfmt, name);
6450 error("invalid signal number or exit status: %s", *argptr);
6456 if (**argv == '%') {
6457 jp = getjob(*argv, 0);
6458 pid = -jp->ps[0].pid;
6460 pid = number(*argv);
6461 if (kill(pid, signo) != 0) {
6471 #if defined(JOBS) || defined(DEBUG)
6473 jobno(const struct job *jp)
6475 return jp - jobtab + 1;
6481 fgcmd(int argc, char **argv)
6488 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
6493 jp = getjob(*argv, 1);
6494 if (mode == FORK_BG) {
6495 set_curjob(jp, CUR_RUNNING);
6496 fprintf(out, "[%d] ", jobno(jp));
6498 outstr(jp->ps->cmd, out);
6500 retval = restartjob(jp, mode);
6501 } while (*argv && *++argv);
6505 static int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
6509 restartjob(struct job *jp, int mode)
6511 struct procstat *ps;
6517 if (jp->state == JOBDONE)
6519 jp->state = JOBRUNNING;
6521 if (mode == FORK_FG)
6522 xtcsetpgrp(ttyfd, pgid);
6523 killpg(pgid, SIGCONT);
6527 if (WIFSTOPPED(ps->status)) {
6530 } while (ps++, --i);
6532 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
6539 sprint_status(char *s, int status, int sigonly)
6545 st = WEXITSTATUS(status);
6546 if (!WIFEXITED(status)) {
6547 st = WSTOPSIG(status);
6549 if (!WIFSTOPPED(status))
6550 st = WTERMSIG(status);
6553 if (st == SIGINT || st == SIGPIPE)
6555 if (WIFSTOPPED(status))
6559 col = fmtstr(s, 32, u_signal_names(NULL, &st, 0));
6560 if (WCOREDUMP(status)) {
6561 col += fmtstr(s + col, 16, " (core dumped)");
6563 } else if (!sigonly) {
6565 col = fmtstr(s, 16, "Done(%d)", st);
6567 col = fmtstr(s, 16, "Done");
6576 showjob(FILE *out, struct job *jp, int mode)
6578 struct procstat *ps;
6579 struct procstat *psend;
6586 if (mode & SHOW_PGID) {
6587 /* just output process (group) id of pipeline */
6588 fprintf(out, "%d\n", ps->pid);
6592 col = fmtstr(s, 16, "[%d] ", jobno(jp));
6597 else if (curjob && jp == curjob->prev_job)
6600 if (mode & SHOW_PID)
6601 col += fmtstr(s + col, 16, "%d ", ps->pid);
6603 psend = ps + jp->nprocs;
6605 if (jp->state == JOBRUNNING) {
6606 scopy("Running", s + col);
6607 col += strlen("Running");
6609 int status = psend[-1].status;
6611 if (jp->state == JOBSTOPPED)
6612 status = jp->stopstatus;
6614 col += sprint_status(s + col, status, 0);
6620 /* for each process */
6621 col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
6626 s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
6628 if (!(mode & SHOW_PID)) {
6632 if (++ps == psend) {
6633 outcslow('\n', out);
6640 if (jp->state == JOBDONE) {
6641 TRACE(("showjob: freeing job %d\n", jobno(jp)));
6648 jobscmd(int argc, char **argv)
6654 while ((m = nextopt("lp")))
6664 showjob(out, getjob(*argv,0), mode);
6667 showjobs(out, mode);
6674 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6675 * statuses have changed since the last call to showjobs.
6679 showjobs(FILE *out, int mode)
6683 TRACE(("showjobs(%x) called\n", mode));
6685 /* If not even one one job changed, there is nothing to do */
6686 while (dowait(DOWAIT_NORMAL, NULL) > 0)
6689 for (jp = curjob; jp; jp = jp->prev_job) {
6690 if (!(mode & SHOW_CHANGED) || jp->changed)
6691 showjob(out, jp, mode);
6697 * Mark a job structure as unused.
6701 freejob(struct job *jp)
6703 struct procstat *ps;
6707 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
6708 if (ps->cmd != nullstr)
6711 if (jp->ps != &jp->ps0)
6714 set_curjob(jp, CUR_DELETE);
6720 waitcmd(int argc, char **argv)
6733 /* wait for all jobs */
6738 /* no running procs */
6741 if (jp->state == JOBRUNNING)
6746 dowait(DOWAIT_BLOCK, 0);
6752 if (**argv != '%') {
6753 pid_t pid = number(*argv);
6757 if (job->ps[job->nprocs - 1].pid == pid)
6759 job = job->prev_job;
6765 job = getjob(*argv, 0);
6766 /* loop until process terminated or stopped */
6767 while (job->state == JOBRUNNING)
6768 dowait(DOWAIT_BLOCK, 0);
6770 retval = getstatus(job);
6782 * Convert a job name to a job structure.
6786 getjob(const char *name, int getctl)
6790 const char *err_msg = "No such job: %s";
6794 char *(*match)(const char *, const char *);
6809 if (c == '+' || c == '%') {
6811 err_msg = "No current job";
6813 } else if (c == '-') {
6816 err_msg = "No previous job";
6827 jp = jobtab + num - 1;
6844 if (match(jp->ps[0].cmd, p)) {
6848 err_msg = "%s: ambiguous";
6855 err_msg = "job %s not created under job control";
6856 if (getctl && jp->jobctl == 0)
6861 error(err_msg, name);
6867 * Return a new job structure.
6868 * Called with interrupts off.
6872 makejob(union node *node, int nprocs)
6877 for (i = njobs, jp = jobtab ; ; jp++) {
6884 if (jp->state != JOBDONE || !jp->waited)
6893 memset(jp, 0, sizeof(*jp));
6898 jp->prev_job = curjob;
6903 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
6905 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
6915 struct job *jp, *jq;
6917 len = njobs * sizeof(*jp);
6919 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
6921 offset = (char *)jp - (char *)jq;
6923 /* Relocate pointers */
6926 jq = (struct job *)((char *)jq + l);
6930 #define joff(p) ((struct job *)((char *)(p) + l))
6931 #define jmove(p) (p) = (void *)((char *)(p) + offset)
6932 if (likely(joff(jp)->ps == &jq->ps0))
6933 jmove(joff(jp)->ps);
6934 if (joff(jp)->prev_job)
6935 jmove(joff(jp)->prev_job);
6945 jp = (struct job *)((char *)jp + len);
6949 } while (--jq >= jp);
6955 * Fork off a subshell. If we are doing job control, give the subshell its
6956 * own process group. Jp is a job structure that the job is to be added to.
6957 * N is the command that will be evaluated by the child. Both jp and n may
6958 * be NULL. The mode parameter can be one of the following:
6959 * FORK_FG - Fork off a foreground process.
6960 * FORK_BG - Fork off a background process.
6961 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
6962 * process group even if job control is on.
6964 * When job control is turned off, background processes have their standard
6965 * input redirected to /dev/null (except for the second and later processes
6968 * Called with interrupts off.
6972 forkchild(struct job *jp, union node *n, int mode)
6976 TRACE(("Child shell %d\n", getpid()));
6977 wasroot = rootshell;
6983 /* do job control only in root shell */
6985 if (mode != FORK_NOJOB && jp->jobctl && wasroot) {
6988 if (jp->nprocs == 0)
6991 pgrp = jp->ps[0].pid;
6992 /* This can fail because we are doing it in the parent also */
6993 (void)setpgid(0, pgrp);
6994 if (mode == FORK_FG)
6995 xtcsetpgrp(ttyfd, pgrp);
7000 if (mode == FORK_BG) {
7003 if (jp->nprocs == 0) {
7005 if (open(_PATH_DEVNULL, O_RDONLY) != 0)
7006 error("Can't open %s", _PATH_DEVNULL);
7009 if (wasroot && iflag) {
7014 for (jp = curjob; jp; jp = jp->prev_job)
7020 forkparent(struct job *jp, union node *n, int mode, pid_t pid)
7022 TRACE(("In parent shell: child = %d\n", pid));
7024 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
7029 if (mode != FORK_NOJOB && jp->jobctl) {
7032 if (jp->nprocs == 0)
7035 pgrp = jp->ps[0].pid;
7036 /* This can fail because we are doing it in the child also */
7037 (void)setpgid(pid, pgrp);
7040 if (mode == FORK_BG) {
7041 backgndpid = pid; /* set $! */
7042 set_curjob(jp, CUR_RUNNING);
7045 struct procstat *ps = &jp->ps[jp->nprocs++];
7051 ps->cmd = commandtext(n);
7057 forkshell(struct job *jp, union node *n, int mode)
7061 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
7064 TRACE(("Fork failed, errno=%d", errno));
7067 error("Cannot fork");
7070 forkchild(jp, n, mode);
7072 forkparent(jp, n, mode, pid);
7077 * Wait for job to finish.
7079 * Under job control we have the problem that while a child process is
7080 * running interrupts generated by the user are sent to the child but not
7081 * to the shell. This means that an infinite loop started by an inter-
7082 * active user may be hard to kill. With job control turned off, an
7083 * interactive user may place an interactive program inside a loop. If
7084 * the interactive program catches interrupts, the user doesn't want
7085 * these interrupts to also abort the loop. The approach we take here
7086 * is to have the shell ignore interrupt signals while waiting for a
7087 * forground process to terminate, and then send itself an interrupt
7088 * signal if the child process was terminated by an interrupt signal.
7089 * Unfortunately, some programs want to do a bit of cleanup and then
7090 * exit on interrupt; unless these processes terminate themselves by
7091 * sending a signal to themselves (instead of calling exit) they will
7092 * confuse this approach.
7094 * Called with interrupts off.
7098 waitforjob(struct job *jp)
7102 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
7103 while (jp->state == JOBRUNNING) {
7104 dowait(DOWAIT_BLOCK, jp);
7109 xtcsetpgrp(ttyfd, rootpid);
7111 * This is truly gross.
7112 * If we're doing job control, then we did a TIOCSPGRP which
7113 * caused us (the shell) to no longer be in the controlling
7114 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7115 * intuit from the subprocess exit status whether a SIGINT
7116 * occurred, and if so interrupt ourselves. Yuck. - mycroft
7121 if (jp->state == JOBDONE)
7129 * Do a wait system call. If job control is compiled in, we accept
7130 * stopped processes. If block is zero, we return a value of zero
7131 * rather than blocking.
7133 * System V doesn't have a non-blocking wait system call. It does
7134 * have a SIGCLD signal that is sent to a process when one of it's
7135 * children dies. The obvious way to use SIGCLD would be to install
7136 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7137 * was received, and have waitproc bump another counter when it got
7138 * the status of a process. Waitproc would then know that a wait
7139 * system call would not block if the two counters were different.
7140 * This approach doesn't work because if a process has children that
7141 * have not been waited for, System V will send it a SIGCLD when it
7142 * installs a signal handler for SIGCLD. What this means is that when
7143 * a child exits, the shell will be sent SIGCLD signals continuously
7144 * until is runs out of stack space, unless it does a wait call before
7145 * restoring the signal handler. The code below takes advantage of
7146 * this (mis)feature by installing a signal handler for SIGCLD and
7147 * then checking to see whether it was called. If there are any
7148 * children to be waited for, it will be.
7150 * If neither SYSV nor BSD is defined, we don't implement nonblocking
7151 * waits at all. In this case, the user will not be informed when
7152 * a background process until the next time she runs a real program
7153 * (as opposed to running a builtin command or just typing return),
7154 * and the jobs command may give out of date information.
7158 waitproc(int block, int *status)
7168 return wait3(status, flags, (struct rusage *)NULL);
7172 * Wait for a process to terminate.
7176 dowait(int block, struct job *job)
7181 struct job *thisjob;
7184 TRACE(("dowait(%d) called\n", block));
7185 pid = waitproc(block, &status);
7186 TRACE(("wait returns pid %d, status=%d\n", pid, status));
7191 for (jp = curjob; jp; jp = jp->prev_job) {
7192 struct procstat *sp;
7193 struct procstat *spend;
7194 if (jp->state == JOBDONE)
7197 spend = jp->ps + jp->nprocs;
7200 if (sp->pid == pid) {
7201 TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
7202 sp->status = status;
7205 if (sp->status == -1)
7208 if (state == JOBRUNNING)
7210 if (WIFSTOPPED(sp->status)) {
7211 jp->stopstatus = sp->status;
7215 } while (++sp < spend);
7220 if (!WIFSTOPPED(status))
7227 if (state != JOBRUNNING) {
7228 thisjob->changed = 1;
7230 if (thisjob->state != state) {
7231 TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
7232 thisjob->state = state;
7234 if (state == JOBSTOPPED) {
7235 set_curjob(thisjob, CUR_STOPPED);
7244 if (thisjob && thisjob == job) {
7248 len = sprint_status(s, status, 1);
7261 * return 1 if there are stopped jobs, otherwise 0
7273 if (jp && jp->state == JOBSTOPPED) {
7274 out2str("You have stopped jobs.\n");
7284 * Return a string identifying a command (to be printed by the
7289 static char *cmdnextc;
7292 commandtext(union node *n)
7296 STARTSTACKSTR(cmdnextc);
7298 name = stackblock();
7299 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
7300 name, cmdnextc, cmdnextc));
7301 return savestr(name);
7305 cmdtxt(union node *n)
7308 struct nodelist *lp;
7318 lp = n->npipe.cmdlist;
7336 cmdtxt(n->nbinary.ch1);
7352 cmdtxt(n->nif.test);
7355 if (n->nif.elsepart) {
7358 n = n->nif.elsepart;
7374 cmdtxt(n->nbinary.ch1);
7384 cmdputs(n->nfor.var);
7386 cmdlist(n->nfor.args, 1);
7391 cmdputs(n->narg.text);
7395 cmdlist(n->ncmd.args, 1);
7396 cmdlist(n->ncmd.redirect, 0);
7409 cmdputs(n->ncase.expr->narg.text);
7411 for (np = n->ncase.cases; np; np = np->nclist.next) {
7412 cmdtxt(np->nclist.pattern);
7414 cmdtxt(np->nclist.body);
7440 s[0] = n->nfile.fd + '0';
7444 if (n->type == NTOFD || n->type == NFROMFD) {
7445 s[0] = n->ndup.dupfd + '0';
7456 cmdlist(union node *np, int sep)
7458 for (; np; np = np->narg.next) {
7462 if (sep && np->narg.next)
7469 cmdputs(const char *s)
7471 const char *p, *str;
7472 char c, cc[2] = " ";
7476 static const char *const vstype[16] = {
7477 nullstr, "}", "-", "+", "?", "=",
7478 "#", "##", "%", "%%"
7481 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
7483 while ((c = *p++) != 0) {
7491 if ((subtype & VSTYPE) == VSLENGTH)
7495 if (!(subtype & VSQUOTE) != !(quoted & 1)) {
7513 case CTLBACKQ+CTLQUOTE:
7516 #ifdef CONFIG_ASH_MATH_SUPPORT
7531 str = vstype[subtype & VSTYPE];
7532 if (subtype & VSNUL)
7543 /* These can only happen inside quotes */
7555 while ((c = *str++)) {
7560 USTPUTC('"', nextc);
7568 showpipe(struct job *jp, FILE *out)
7570 struct procstat *sp;
7571 struct procstat *spend;
7573 spend = jp->ps + jp->nprocs;
7574 for (sp = jp->ps + 1; sp < spend; sp++)
7575 fprintf(out, " | %s", sp->cmd);
7576 outcslow('\n', out);
7581 xtcsetpgrp(int fd, pid_t pgrp)
7583 if (tcsetpgrp(fd, pgrp))
7584 error("Cannot set tty process group (%m)");
7589 getstatus(struct job *job) {
7593 status = job->ps[job->nprocs - 1].status;
7594 retval = WEXITSTATUS(status);
7595 if (!WIFEXITED(status)) {
7597 retval = WSTOPSIG(status);
7598 if (!WIFSTOPPED(status))
7601 /* XXX: limits number of signals */
7602 retval = WTERMSIG(status);
7604 if (retval == SIGINT)
7610 TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
7611 jobno(job), job->nprocs, status, retval));
7615 #ifdef CONFIG_ASH_MAIL
7616 /* $NetBSD: mail.c,v 1.15 2002/11/24 22:35:40 christos Exp $ */
7619 * Routines to check for mail. (Perhaps make part of main.c?)
7622 #define MAXMBOXES 10
7624 /* times of mailboxes */
7625 static time_t mailtime[MAXMBOXES];
7626 /* Set if MAIL or MAILPATH is changed. */
7627 static int mail_var_path_changed;
7632 * Print appropriate message(s) if mail has arrived.
7633 * If mail_var_path_changed is set,
7634 * then the value of MAIL has mail_var_path_changed,
7635 * so we just update the values.
7645 struct stackmark smark;
7648 setstackmark(&smark);
7649 mpath = mpathset() ? mpathval() : mailval();
7650 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
7651 p = padvance(&mpath, nullstr);
7656 for (q = p ; *q ; q++);
7661 q[-1] = '\0'; /* delete trailing '/' */
7662 if (stat(p, &statb) < 0) {
7666 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
7669 pathopt ? pathopt : "you have mail"
7672 *mtp = statb.st_mtime;
7674 mail_var_path_changed = 0;
7675 popstackmark(&smark);
7680 changemail(const char *val)
7682 mail_var_path_changed++;
7685 #endif /* CONFIG_ASH_MAIL */
7687 /* $NetBSD: main.c,v 1.46 2002/12/11 19:12:18 christos Exp $ */
7691 static short profile_buf[16384];
7695 static int isloginsh;
7697 static void read_profile(const char *);
7700 * Main routine. We initialize things, parse the arguments, execute
7701 * profiles if we're a login shell, and then call cmdloop to execute
7702 * commands. The setjmp call sets up the location to jump to when an
7703 * exception occurs. When an exception occurs the variable "state"
7704 * is used to figure out how far we had gotten.
7708 ash_main(int argc, char **argv)
7712 struct jmploc jmploc;
7713 struct stackmark smark;
7716 dash_errno = __errno_location();
7720 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7723 if (setjmp(jmploc.loc)) {
7730 switch (exception) {
7740 status = exitstatus;
7743 exitstatus = status;
7745 if (e == EXEXIT || state == 0 || iflag == 0 || ! rootshell)
7749 outcslow('\n', stderr);
7751 popstackmark(&smark);
7752 FORCEINTON; /* enable interrupts */
7755 else if (state == 2)
7757 else if (state == 3)
7765 trputs("Shell args: "); trargs(argv);
7770 setstackmark(&smark);
7771 procargs(argc, argv);
7772 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7774 const char *hp = lookupvar("HISTFILE");
7777 hp = lookupvar("HOME");
7779 char *defhp = concat_path_file(hp, ".ash_history");
7780 setvar("HISTFILE", defhp, 0);
7786 if (argv[0] && argv[0][0] == '-')
7790 read_profile("/etc/profile");
7793 read_profile(".profile");
7799 getuid() == geteuid() && getgid() == getegid() &&
7803 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
7804 read_profile(shinit);
7810 evalstring(minusc, 0);
7812 if (sflag || minusc == NULL) {
7813 state4: /* XXX ??? - why isn't this before the "if" statement */
7814 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7816 const char *hp = lookupvar("HISTFILE");
7819 load_history ( hp );
7829 extern void _mcleanup(void);
7839 * Read and execute commands. "Top" is nonzero for the top level command
7840 * loop; it turns on prompting if the shell is interactive.
7847 struct stackmark smark;
7851 TRACE(("cmdloop(%d) called\n", top));
7852 setstackmark(&smark);
7858 showjobs(stderr, SHOW_CHANGED);
7863 #ifdef CONFIG_ASH_MAIL
7867 n = parsecmd(inter);
7868 /* showtree(n); DEBUG */
7870 if (!top || numeof >= 50)
7872 if (!stoppedjobs()) {
7875 out2str("\nUse \"exit\" to leave shell.\n");
7878 } else if (n != NULL && nflag == 0) {
7879 job_warning = (job_warning == 2) ? 1 : 0;
7883 popstackmark(&smark);
7884 setstackmark(&smark);
7885 if (evalskip == SKIPFILE) {
7890 popstackmark(&smark);
7896 * Read /etc/profile or .profile. Return on error.
7900 read_profile(const char *name)
7907 if ((fd = open(name, O_RDONLY)) >= 0)
7912 /* -q turns off -x and -v just when executing init files */
7915 xflag = 0, xflag_set = 1;
7917 vflag = 0, vflag_set = 1;
7932 * Read a file containing shell functions.
7936 readcmdfile(char *name)
7941 if ((fd = open(name, O_RDONLY)) >= 0)
7944 error("Can't open %s", name);
7952 * Take commands from a file. To be compatible we should do a path
7953 * search for the file, which is necessary to find sub-commands.
7956 static inline char *
7957 find_dot_file(char *name)
7960 const char *path = pathval();
7963 /* don't try this for absolute or relative paths */
7964 if (strchr(name, '/'))
7967 while ((fullname = padvance(&path, name)) != NULL) {
7968 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
7970 * Don't bother freeing here, since it will
7971 * be freed by the caller.
7975 stunalloc(fullname);
7978 /* not found in the PATH */
7979 error(not_found_msg, name);
7984 dotcmd(int argc, char **argv)
7988 if (argc >= 2) { /* That's what SVR2 does */
7990 struct stackmark smark;
7992 setstackmark(&smark);
7993 fullname = find_dot_file(argv[1]);
7994 setinputfile(fullname, 1);
7995 commandname = fullname;
7998 popstackmark(&smark);
8005 exitcmd(int argc, char **argv)
8010 exitstatus = number(argv[1]);
8015 /* $NetBSD: memalloc.c,v 1.27 2003/01/22 20:36:04 dsl Exp $ */
8018 * Like malloc, but returns an error when out of space.
8022 ckmalloc(size_t nbytes)
8028 error(bb_msg_memory_exhausted);
8038 ckrealloc(pointer p, size_t nbytes)
8040 p = realloc(p, nbytes);
8042 error(bb_msg_memory_exhausted);
8048 * Make a copy of a string in safe storage.
8052 savestr(const char *s)
8054 char *p = strdup(s);
8056 error(bb_msg_memory_exhausted);
8062 * Parse trees for commands are allocated in lifo order, so we use a stack
8063 * to make this more efficient, and also to avoid all sorts of exception
8064 * handling code to handle interrupts in the middle of a parse.
8066 * The size 504 was chosen because the Ultrix malloc handles that size
8072 stalloc(size_t nbytes)
8077 aligned = SHELL_ALIGN(nbytes);
8078 if (aligned > stacknleft) {
8081 struct stack_block *sp;
8083 blocksize = aligned;
8084 if (blocksize < MINSIZE)
8085 blocksize = MINSIZE;
8086 len = sizeof(struct stack_block) - MINSIZE + blocksize;
8087 if (len < blocksize)
8088 error(bb_msg_memory_exhausted);
8092 stacknxt = sp->space;
8093 stacknleft = blocksize;
8094 sstrend = stacknxt + blocksize;
8099 stacknxt += aligned;
8100 stacknleft -= aligned;
8106 stunalloc(pointer p)
8109 if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
8110 write(2, "stunalloc\n", 10);
8114 stacknleft += stacknxt - (char *)p;
8121 setstackmark(struct stackmark *mark)
8123 mark->stackp = stackp;
8124 mark->stacknxt = stacknxt;
8125 mark->stacknleft = stacknleft;
8126 mark->marknext = markp;
8132 popstackmark(struct stackmark *mark)
8134 struct stack_block *sp;
8137 markp = mark->marknext;
8138 while (stackp != mark->stackp) {
8143 stacknxt = mark->stacknxt;
8144 stacknleft = mark->stacknleft;
8145 sstrend = mark->stacknxt + mark->stacknleft;
8151 * When the parser reads in a string, it wants to stick the string on the
8152 * stack and only adjust the stack pointer when it knows how big the
8153 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8154 * of space on top of the stack and stackblocklen returns the length of
8155 * this block. Growstackblock will grow this space by at least one byte,
8156 * possibly moving it (like realloc). Grabstackblock actually allocates the
8157 * part of the block that has been used.
8161 growstackblock(void)
8165 newlen = stacknleft * 2;
8166 if (newlen < stacknleft)
8167 error(bb_msg_memory_exhausted);
8171 if (stacknxt == stackp->space && stackp != &stackbase) {
8172 struct stack_block *oldstackp;
8173 struct stackmark *xmark;
8174 struct stack_block *sp;
8175 struct stack_block *prevstackp;
8181 prevstackp = sp->prev;
8182 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
8183 sp = ckrealloc((pointer)sp, grosslen);
8184 sp->prev = prevstackp;
8186 stacknxt = sp->space;
8187 stacknleft = newlen;
8188 sstrend = sp->space + newlen;
8191 * Stack marks pointing to the start of the old block
8192 * must be relocated to point to the new block
8195 while (xmark != NULL && xmark->stackp == oldstackp) {
8196 xmark->stackp = stackp;
8197 xmark->stacknxt = stacknxt;
8198 xmark->stacknleft = stacknleft;
8199 xmark = xmark->marknext;
8203 char *oldspace = stacknxt;
8204 int oldlen = stacknleft;
8205 char *p = stalloc(newlen);
8207 /* free the space we just allocated */
8208 stacknxt = memcpy(p, oldspace, oldlen);
8209 stacknleft += newlen;
8214 grabstackblock(size_t len)
8216 len = SHELL_ALIGN(len);
8222 * The following routines are somewhat easier to use than the above.
8223 * The user declares a variable of type STACKSTR, which may be declared
8224 * to be a register. The macro STARTSTACKSTR initializes things. Then
8225 * the user uses the macro STPUTC to add characters to the string. In
8226 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8227 * grown as necessary. When the user is done, she can just leave the
8228 * string there and refer to it using stackblock(). Or she can allocate
8229 * the space for it using grabstackstr(). If it is necessary to allow
8230 * someone else to use the stack temporarily and then continue to grow
8231 * the string, the user should use grabstack to allocate the space, and
8232 * then call ungrabstr(p) to return to the previous mode of operation.
8234 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8235 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8236 * is space for at least one character.
8242 size_t len = stackblocksize();
8243 if (herefd >= 0 && len >= 1024) {
8244 xwrite(herefd, stackblock(), len);
8245 return stackblock();
8248 return stackblock() + len;
8252 * Called from CHECKSTRSPACE.
8256 makestrspace(size_t newlen, char *p)
8258 size_t len = p - stacknxt;
8259 size_t size = stackblocksize();
8264 size = stackblocksize();
8266 if (nleft >= newlen)
8270 return stackblock() + len;
8274 stnputs(const char *s, size_t n, char *p)
8276 p = makestrspace(n, p);
8277 p = mempcpy(p, s, n);
8282 stputs(const char *s, char *p)
8284 return stnputs(s, strlen(s), p);
8287 /* $NetBSD: mystring.c,v 1.15 2002/11/24 22:35:42 christos Exp $ */
8292 * number(s) Convert a string of digits to an integer.
8293 * is_number(s) Return true if s is a string of digits.
8297 * prefix -- see if pfx is a prefix of string.
8301 prefix(const char *string, const char *pfx)
8304 if (*pfx++ != *string++)
8307 return (char *) string;
8312 * Convert a string of digits to an integer, printing an error message on
8317 number(const char *s)
8328 * Check for a valid number. This should be elsewhere.
8332 is_number(const char *p)
8337 } while (*++p != '\0');
8343 * Produce a possibly single quoted string suitable as input to the shell.
8344 * The return string is allocated on the stack.
8348 single_quote(const char *s) {
8357 len = strchrnul(s, '\'') - s;
8359 q = p = makestrspace(len + 3, p);
8362 q = mempcpy(q, s, len);
8368 len = strspn(s, "'");
8372 q = p = makestrspace(len + 3, p);
8375 q = mempcpy(q, s, len);
8384 return stackblock();
8388 * Like strdup but works with the ash stack.
8392 sstrdup(const char *p)
8394 size_t len = strlen(p) + 1;
8395 return memcpy(stalloc(len), p, len);
8400 calcsize(union node *n)
8404 funcblocksize += nodesize[n->type];
8407 calcsize(n->ncmd.redirect);
8408 calcsize(n->ncmd.args);
8409 calcsize(n->ncmd.assign);
8412 sizenodelist(n->npipe.cmdlist);
8417 calcsize(n->nredir.redirect);
8418 calcsize(n->nredir.n);
8425 calcsize(n->nbinary.ch2);
8426 calcsize(n->nbinary.ch1);
8429 calcsize(n->nif.elsepart);
8430 calcsize(n->nif.ifpart);
8431 calcsize(n->nif.test);
8434 funcstringsize += strlen(n->nfor.var) + 1;
8435 calcsize(n->nfor.body);
8436 calcsize(n->nfor.args);
8439 calcsize(n->ncase.cases);
8440 calcsize(n->ncase.expr);
8443 calcsize(n->nclist.body);
8444 calcsize(n->nclist.pattern);
8445 calcsize(n->nclist.next);
8449 sizenodelist(n->narg.backquote);
8450 funcstringsize += strlen(n->narg.text) + 1;
8451 calcsize(n->narg.next);
8458 calcsize(n->nfile.fname);
8459 calcsize(n->nfile.next);
8463 calcsize(n->ndup.vname);
8464 calcsize(n->ndup.next);
8468 calcsize(n->nhere.doc);
8469 calcsize(n->nhere.next);
8472 calcsize(n->nnot.com);
8480 sizenodelist(struct nodelist *lp)
8483 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8492 copynode(union node *n)
8499 funcblock = (char *) funcblock + nodesize[n->type];
8502 new->ncmd.redirect = copynode(n->ncmd.redirect);
8503 new->ncmd.args = copynode(n->ncmd.args);
8504 new->ncmd.assign = copynode(n->ncmd.assign);
8507 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8508 new->npipe.backgnd = n->npipe.backgnd;
8513 new->nredir.redirect = copynode(n->nredir.redirect);
8514 new->nredir.n = copynode(n->nredir.n);
8521 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8522 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8525 new->nif.elsepart = copynode(n->nif.elsepart);
8526 new->nif.ifpart = copynode(n->nif.ifpart);
8527 new->nif.test = copynode(n->nif.test);
8530 new->nfor.var = nodesavestr(n->nfor.var);
8531 new->nfor.body = copynode(n->nfor.body);
8532 new->nfor.args = copynode(n->nfor.args);
8535 new->ncase.cases = copynode(n->ncase.cases);
8536 new->ncase.expr = copynode(n->ncase.expr);
8539 new->nclist.body = copynode(n->nclist.body);
8540 new->nclist.pattern = copynode(n->nclist.pattern);
8541 new->nclist.next = copynode(n->nclist.next);
8545 new->narg.backquote = copynodelist(n->narg.backquote);
8546 new->narg.text = nodesavestr(n->narg.text);
8547 new->narg.next = copynode(n->narg.next);
8554 new->nfile.fname = copynode(n->nfile.fname);
8555 new->nfile.fd = n->nfile.fd;
8556 new->nfile.next = copynode(n->nfile.next);
8560 new->ndup.vname = copynode(n->ndup.vname);
8561 new->ndup.dupfd = n->ndup.dupfd;
8562 new->ndup.fd = n->ndup.fd;
8563 new->ndup.next = copynode(n->ndup.next);
8567 new->nhere.doc = copynode(n->nhere.doc);
8568 new->nhere.fd = n->nhere.fd;
8569 new->nhere.next = copynode(n->nhere.next);
8572 new->nnot.com = copynode(n->nnot.com);
8575 new->type = n->type;
8580 static struct nodelist *
8581 copynodelist(struct nodelist *lp)
8583 struct nodelist *start;
8584 struct nodelist **lpp;
8589 funcblock = (char *) funcblock +
8590 SHELL_ALIGN(sizeof(struct nodelist));
8591 (*lpp)->n = copynode(lp->n);
8593 lpp = &(*lpp)->next;
8602 nodesavestr(char *s)
8604 char *rtn = funcstring;
8606 funcstring = stpcpy(funcstring, s) + 1;
8613 * Free a parse tree.
8617 freefunc(struct funcnode *f)
8619 if (f && --f->count < 0)
8624 static void options(int);
8625 static void setoption(int, int);
8629 * Process the shell command line arguments.
8633 procargs(int argc, char **argv)
8636 const char *xminusc;
8643 for (i = 0; i < NOPTS; i++)
8649 if (*xargv == NULL) {
8651 error("-c requires an argument");
8654 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8658 for (i = 0; i < NOPTS; i++)
8659 if (optlist[i] == 2)
8664 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8669 } else if (!sflag) {
8670 setinputfile(*xargv, 0);
8676 shellparam.p = xargv;
8677 #ifdef CONFIG_ASH_GETOPTS
8678 shellparam.optind = 1;
8679 shellparam.optoff = -1;
8681 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
8683 shellparam.nparam++;
8696 setinteractive(iflag);
8701 minus_o(char *name, int val)
8706 out1str("Current option settings\n");
8707 for (i = 0; i < NOPTS; i++)
8708 out1fmt("%-16s%s\n", optnames(i),
8709 optlist[i] ? "on" : "off");
8711 for (i = 0; i < NOPTS; i++)
8712 if (equal(name, optnames(i))) {
8716 error("Illegal option -o %s", name);
8721 * Process shell options. The global variable argptr contains a pointer
8722 * to the argument list; we advance it past the options.
8726 options(int cmdline)
8734 while ((p = *argptr) != NULL) {
8736 if ((c = *p++) == '-') {
8738 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8740 /* "-" means turn off -x and -v */
8743 /* "--" means reset params */
8744 else if (*argptr == NULL)
8747 break; /* "-" or "--" terminates options */
8749 } else if (c == '+') {
8755 while ((c = *p++) != '\0') {
8756 if (c == 'c' && cmdline) {
8757 minusc = p; /* command is after shell args*/
8758 } else if (c == 'o') {
8759 minus_o(*argptr, val);
8762 } else if (cmdline && (c == '-')) { // long options
8763 if (strcmp(p, "login") == 0)
8776 setoption(int flag, int val)
8780 for (i = 0; i < NOPTS; i++)
8781 if (optletters(i) == flag) {
8785 error("Illegal option -%c", flag);
8792 * Set the shell parameters.
8796 setparam(char **argv)
8802 for (nparam = 0 ; argv[nparam] ; nparam++);
8803 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
8805 *ap++ = savestr(*argv++);
8808 freeparam(&shellparam);
8809 shellparam.malloc = 1;
8810 shellparam.nparam = nparam;
8811 shellparam.p = newparam;
8812 #ifdef CONFIG_ASH_GETOPTS
8813 shellparam.optind = 1;
8814 shellparam.optoff = -1;
8820 * Free the list of positional parameters.
8824 freeparam(volatile struct shparam *param)
8828 if (param->malloc) {
8829 for (ap = param->p ; *ap ; ap++)
8838 * The shift builtin command.
8842 shiftcmd(int argc, char **argv)
8849 n = number(argv[1]);
8850 if (n > shellparam.nparam)
8851 error("can't shift that many");
8853 shellparam.nparam -= n;
8854 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
8855 if (shellparam.malloc)
8859 while ((*ap2++ = *ap1++) != NULL);
8860 #ifdef CONFIG_ASH_GETOPTS
8861 shellparam.optind = 1;
8862 shellparam.optoff = -1;
8871 * The set command builtin.
8875 setcmd(int argc, char **argv)
8878 return showvars(nullstr, 0, VUNSET);
8882 if (*argptr != NULL) {
8890 #ifdef CONFIG_ASH_GETOPTS
8895 shellparam.optind = number(value);
8896 shellparam.optoff = -1;
8900 #ifdef CONFIG_LOCALE_SUPPORT
8901 static void change_lc_all(const char *value)
8903 if (value != 0 && *value != 0)
8904 setlocale(LC_ALL, value);
8907 static void change_lc_ctype(const char *value)
8909 if (value != 0 && *value != 0)
8910 setlocale(LC_CTYPE, value);
8915 #ifdef CONFIG_ASH_GETOPTS
8917 getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
8924 char **optnext = optfirst + *param_optind - 1;
8926 if (*param_optind <= 1 || *optoff < 0 || !(*(optnext - 1)) ||
8927 strlen(*(optnext - 1)) < *optoff)
8930 p = *(optnext - 1) + *optoff;
8931 if (p == NULL || *p == '\0') {
8932 /* Current word is done, advance */
8933 if (optnext == NULL)
8936 if (p == NULL || *p != '-' || *++p == '\0') {
8943 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
8948 for (q = optstr; *q != c; ) {
8950 if (optstr[0] == ':') {
8953 err |= setvarsafe("OPTARG", s, 0);
8955 fprintf(stderr, "Illegal option -%c\n", c);
8956 (void) unsetvar("OPTARG");
8966 if (*p == '\0' && (p = *optnext) == NULL) {
8967 if (optstr[0] == ':') {
8970 err |= setvarsafe("OPTARG", s, 0);
8973 fprintf(stderr, "No arg for -%c option\n", c);
8974 (void) unsetvar("OPTARG");
8982 err |= setvarsafe("OPTARG", p, 0);
8985 err |= setvarsafe("OPTARG", nullstr, 0);
8988 *optoff = p ? p - *(optnext - 1) : -1;
8989 *param_optind = optnext - optfirst + 1;
8990 fmtstr(s, sizeof(s), "%d", *param_optind);
8991 err |= setvarsafe("OPTIND", s, VNOFUNC);
8994 err |= setvarsafe(optvar, s, 0);
9005 * The getopts builtin. Shellparam.optnext points to the next argument
9006 * to be processed. Shellparam.optptr points to the next character to
9007 * be processed in the current argument. If shellparam.optnext is NULL,
9008 * then it's the first time getopts has been called.
9012 getoptscmd(int argc, char **argv)
9017 error("Usage: getopts optstring var [arg]");
9018 else if (argc == 3) {
9019 optbase = shellparam.p;
9020 if (shellparam.optind > shellparam.nparam + 1) {
9021 shellparam.optind = 1;
9022 shellparam.optoff = -1;
9027 if (shellparam.optind > argc - 2) {
9028 shellparam.optind = 1;
9029 shellparam.optoff = -1;
9033 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9034 &shellparam.optoff);
9036 #endif /* CONFIG_ASH_GETOPTS */
9039 * XXX - should get rid of. have all builtins use getopt(3). the
9040 * library getopt must have the BSD extension static variable "optreset"
9041 * otherwise it can't be used within the shell safely.
9043 * Standard option processing (a la getopt) for builtin routines. The
9044 * only argument that is passed to nextopt is the option string; the
9045 * other arguments are unnecessary. It return the character, or '\0' on
9050 nextopt(const char *optstring)
9056 if ((p = optptr) == NULL || *p == '\0') {
9058 if (p == NULL || *p != '-' || *++p == '\0')
9061 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
9065 for (q = optstring ; *q != c ; ) {
9067 error("Illegal option -%c", c);
9072 if (*p == '\0' && (p = *argptr++) == NULL)
9073 error("No arg for -%c option", c);
9081 /* $NetBSD: output.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
9086 outstr(const char *p, FILE *file)
9104 flushout(FILE *dest)
9112 outcslow(int c, FILE *dest)
9122 out1fmt(const char *fmt, ...)
9129 r = vprintf(fmt, ap);
9137 fmtstr(char *outbuf, size_t length, const char *fmt, ...)
9144 ret = vsnprintf(outbuf, length, fmt, ap);
9152 * Version of write which resumes after a signal is caught.
9156 xwrite(int fd, const void *p, size_t n)
9161 i = bb_full_write(fd, p, n);
9162 } while (i < 0 && errno == EINTR);
9166 /* $NetBSD: parser.c,v 1.54 2002/11/24 22:35:42 christos Exp $ */
9170 * Shell command parser.
9173 #define EOFMARKLEN 79
9177 struct heredoc *next; /* next here document in list */
9178 union node *here; /* redirection node */
9179 char *eofmark; /* string indicating end of input */
9180 int striptabs; /* if set, strip leading tabs */
9185 static struct heredoc *heredoclist; /* list of here documents to read */
9188 static union node *list(int);
9189 static union node *andor(void);
9190 static union node *pipeline(void);
9191 static union node *command(void);
9192 static union node *simplecmd(void);
9193 static union node *makename(void);
9194 static void parsefname(void);
9195 static void parseheredoc(void);
9196 static char peektoken(void);
9197 static int readtoken(void);
9198 static int xxreadtoken(void);
9199 static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
9200 static int noexpand(char *);
9201 static void synexpect(int) __attribute__((__noreturn__));
9202 static void synerror(const char *) __attribute__((__noreturn__));
9203 static void setprompt(int);
9207 goodname(const char *p)
9209 return !*endofname(p);
9213 isassignment(const char *p)
9215 const char *q = endofname(p);
9223 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9224 * valid parse tree indicating a blank line.)
9228 parsecmd(int interact)
9233 doprompt = interact;
9235 setprompt(doprompt);
9250 union node *n1, *n2, *n3;
9253 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9254 if (nlflag == 2 && peektoken())
9260 if (tok == TBACKGND) {
9261 if (n2->type == NPIPE) {
9262 n2->npipe.backgnd = 1;
9264 if (n2->type != NREDIR) {
9265 n3 = stalloc(sizeof(struct nredir));
9267 n3->nredir.redirect = NULL;
9270 n2->type = NBACKGND;
9277 n3 = (union node *)stalloc(sizeof (struct nbinary));
9279 n3->nbinary.ch1 = n1;
9280 n3->nbinary.ch2 = n2;
9296 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9304 pungetc(); /* push back EOF on input */
9320 union node *n1, *n2, *n3;
9325 if ((t = readtoken()) == TAND) {
9327 } else if (t == TOR) {
9333 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9335 n3 = (union node *)stalloc(sizeof (struct nbinary));
9337 n3->nbinary.ch1 = n1;
9338 n3->nbinary.ch2 = n2;
9348 union node *n1, *n2, *pipenode;
9349 struct nodelist *lp, *prev;
9353 TRACE(("pipeline: entered\n"));
9354 if (readtoken() == TNOT) {
9356 checkkwd = CHKKWD | CHKALIAS;
9360 if (readtoken() == TPIPE) {
9361 pipenode = (union node *)stalloc(sizeof (struct npipe));
9362 pipenode->type = NPIPE;
9363 pipenode->npipe.backgnd = 0;
9364 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9365 pipenode->npipe.cmdlist = lp;
9369 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9370 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9373 } while (readtoken() == TPIPE);
9379 n2 = (union node *)stalloc(sizeof (struct nnot));
9392 union node *n1, *n2;
9393 union node *ap, **app;
9394 union node *cp, **cpp;
9395 union node *redir, **rpp;
9402 switch (readtoken()) {
9407 n1 = (union node *)stalloc(sizeof (struct nif));
9409 n1->nif.test = list(0);
9410 if (readtoken() != TTHEN)
9412 n1->nif.ifpart = list(0);
9414 while (readtoken() == TELIF) {
9415 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
9416 n2 = n2->nif.elsepart;
9418 n2->nif.test = list(0);
9419 if (readtoken() != TTHEN)
9421 n2->nif.ifpart = list(0);
9423 if (lasttoken == TELSE)
9424 n2->nif.elsepart = list(0);
9426 n2->nif.elsepart = NULL;
9434 n1 = (union node *)stalloc(sizeof (struct nbinary));
9435 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
9436 n1->nbinary.ch1 = list(0);
9437 if ((got=readtoken()) != TDO) {
9438 TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
9441 n1->nbinary.ch2 = list(0);
9446 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9447 synerror("Bad for loop variable");
9448 n1 = (union node *)stalloc(sizeof (struct nfor));
9450 n1->nfor.var = wordtext;
9451 checkkwd = CHKKWD | CHKALIAS;
9452 if (readtoken() == TIN) {
9454 while (readtoken() == TWORD) {
9455 n2 = (union node *)stalloc(sizeof (struct narg));
9457 n2->narg.text = wordtext;
9458 n2->narg.backquote = backquotelist;
9460 app = &n2->narg.next;
9464 if (lasttoken != TNL && lasttoken != TSEMI)
9467 n2 = (union node *)stalloc(sizeof (struct narg));
9469 n2->narg.text = (char *)dolatstr;
9470 n2->narg.backquote = NULL;
9471 n2->narg.next = NULL;
9474 * Newline or semicolon here is optional (but note
9475 * that the original Bourne shell only allowed NL).
9477 if (lasttoken != TNL && lasttoken != TSEMI)
9480 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9481 if (readtoken() != TDO)
9483 n1->nfor.body = list(0);
9487 n1 = (union node *)stalloc(sizeof (struct ncase));
9489 if (readtoken() != TWORD)
9491 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
9493 n2->narg.text = wordtext;
9494 n2->narg.backquote = backquotelist;
9495 n2->narg.next = NULL;
9497 checkkwd = CHKKWD | CHKALIAS;
9498 } while (readtoken() == TNL);
9499 if (lasttoken != TIN)
9501 cpp = &n1->ncase.cases;
9503 checkkwd = CHKNL | CHKKWD;
9506 if (lasttoken == TLP)
9508 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
9510 app = &cp->nclist.pattern;
9512 *app = ap = (union node *)stalloc(sizeof (struct narg));
9514 ap->narg.text = wordtext;
9515 ap->narg.backquote = backquotelist;
9516 if (readtoken() != TPIPE)
9518 app = &ap->narg.next;
9521 ap->narg.next = NULL;
9522 if (lasttoken != TRP)
9524 cp->nclist.body = list(2);
9526 cpp = &cp->nclist.next;
9528 checkkwd = CHKNL | CHKKWD;
9529 if ((t = readtoken()) != TESAC) {
9531 synexpect(TENDCASE);
9539 n1 = (union node *)stalloc(sizeof (struct nredir));
9540 n1->type = NSUBSHELL;
9541 n1->nredir.n = list(0);
9542 n1->nredir.redirect = NULL;
9555 if (readtoken() != t)
9559 /* Now check for redirection which may follow command */
9560 checkkwd = CHKKWD | CHKALIAS;
9562 while (readtoken() == TREDIR) {
9563 *rpp = n2 = redirnode;
9564 rpp = &n2->nfile.next;
9570 if (n1->type != NSUBSHELL) {
9571 n2 = (union node *)stalloc(sizeof (struct nredir));
9576 n1->nredir.redirect = redir;
9585 union node *args, **app;
9586 union node *n = NULL;
9587 union node *vars, **vpp;
9588 union node **rpp, *redir;
9598 savecheckkwd = CHKALIAS;
9600 checkkwd = savecheckkwd;
9601 switch (readtoken()) {
9603 n = (union node *)stalloc(sizeof (struct narg));
9605 n->narg.text = wordtext;
9606 n->narg.backquote = backquotelist;
9607 if (savecheckkwd && isassignment(wordtext)) {
9609 vpp = &n->narg.next;
9612 app = &n->narg.next;
9617 *rpp = n = redirnode;
9618 rpp = &n->nfile.next;
9619 parsefname(); /* read name of redirection file */
9623 args && app == &args->narg.next &&
9626 struct builtincmd *bcmd;
9629 /* We have a function */
9630 if (readtoken() != TRP)
9632 name = n->narg.text;
9634 !goodname(name) || (
9635 (bcmd = find_builtin(name)) &&
9636 IS_BUILTIN_SPECIAL(bcmd)
9639 synerror("Bad function name");
9641 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9642 n->narg.next = command();
9655 n = (union node *)stalloc(sizeof (struct ncmd));
9657 n->ncmd.args = args;
9658 n->ncmd.assign = vars;
9659 n->ncmd.redirect = redir;
9668 n = (union node *)stalloc(sizeof (struct narg));
9670 n->narg.next = NULL;
9671 n->narg.text = wordtext;
9672 n->narg.backquote = backquotelist;
9676 void fixredir(union node *n, const char *text, int err)
9678 TRACE(("Fix redir %s %d\n", text, err));
9680 n->ndup.vname = NULL;
9682 if (is_digit(text[0]) && text[1] == '\0')
9683 n->ndup.dupfd = digit_val(text[0]);
9684 else if (text[0] == '-' && text[1] == '\0')
9689 synerror("Bad fd number");
9691 n->ndup.vname = makename();
9699 union node *n = redirnode;
9701 if (readtoken() != TWORD)
9703 if (n->type == NHERE) {
9704 struct heredoc *here = heredoc;
9710 TRACE(("Here document %d\n", n->type));
9711 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
9712 synerror("Illegal eof marker for << redirection");
9713 rmescapes(wordtext);
9714 here->eofmark = wordtext;
9716 if (heredoclist == NULL)
9719 for (p = heredoclist ; p->next ; p = p->next);
9722 } else if (n->type == NTOFD || n->type == NFROMFD) {
9723 fixredir(n, wordtext, 0);
9725 n->nfile.fname = makename();
9731 * Input any here documents.
9737 struct heredoc *here;
9748 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9749 here->eofmark, here->striptabs);
9750 n = (union node *)stalloc(sizeof (struct narg));
9751 n->narg.type = NARG;
9752 n->narg.next = NULL;
9753 n->narg.text = wordtext;
9754 n->narg.backquote = backquotelist;
9755 here->here->nhere.doc = n;
9760 static char peektoken(void)
9766 return tokname_array[t][0];
9774 int alreadyseen = tokpushback;
9777 #ifdef CONFIG_ASH_ALIAS
9786 if (checkkwd & CHKNL) {
9793 if (t != TWORD || quoteflag) {
9798 * check for keywords
9800 if (checkkwd & CHKKWD) {
9801 const char *const *pp;
9803 if ((pp = findkwd(wordtext))) {
9804 lasttoken = t = pp - tokname_array;
9805 TRACE(("keyword %s recognized\n", tokname(t)));
9810 if (checkkwd & CHKALIAS) {
9811 #ifdef CONFIG_ASH_ALIAS
9813 if ((ap = lookupalias(wordtext, 1)) != NULL) {
9815 pushstring(ap->val, ap);
9825 TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
9827 TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
9834 * Read the next input token.
9835 * If the token is a word, we set backquotelist to the list of cmds in
9836 * backquotes. We set quoteflag to true if any part of the word was
9838 * If the token is TREDIR, then we set redirnode to a structure containing
9840 * In all cases, the variable startlinno is set to the number of the line
9841 * on which the token starts.
9843 * [Change comment: here documents and internal procedures]
9844 * [Readtoken shouldn't have any arguments. Perhaps we should make the
9845 * word parsing code into a separate routine. In this case, readtoken
9846 * doesn't need to have any internal procedures, but parseword does.
9847 * We could also make parseoperator in essence the main routine, and
9848 * have parseword (readtoken1?) handle both words and redirection.]
9851 #define RETURN(token) return lasttoken = token
9866 startlinno = plinno;
9867 for (;;) { /* until token or start of word found */
9870 case ' ': case '\t':
9871 #ifdef CONFIG_ASH_ALIAS
9876 while ((c = pgetc()) != '\n' && c != PEOF);
9880 if (pgetc() == '\n') {
9881 startlinno = ++plinno;
9890 needprompt = doprompt;
9918 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
9925 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
9926 * is not NULL, read a here document. In the latter case, eofmark is the
9927 * word which marks the end of the document and striptabs is true if
9928 * leading tabs should be stripped from the document. The argument firstc
9929 * is the first character of the input token or document.
9931 * Because C does not have internal subroutines, I have simulated them
9932 * using goto's to implement the subroutine linkage. The following macros
9933 * will run code that appears at the end of readtoken1.
9936 #define CHECKEND() {goto checkend; checkend_return:;}
9937 #define PARSEREDIR() {goto parseredir; parseredir_return:;}
9938 #define PARSESUB() {goto parsesub; parsesub_return:;}
9939 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
9940 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
9941 #define PARSEARITH() {goto parsearith; parsearith_return:;}
9944 readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
9949 char line[EOFMARKLEN + 1];
9950 struct nodelist *bqlist;
9953 int varnest; /* levels of variables expansion */
9954 int arinest; /* levels of arithmetic expansion */
9955 int parenlevel; /* levels of parens in arithmetic */
9956 int dqvarnest; /* levels of variables expansion within double quotes */
9958 int prevsyntax; /* syntax before arithmetic */
9960 /* Avoid longjmp clobbering */
9973 startlinno = plinno;
9975 if (syntax == DQSYNTAX)
9985 loop: { /* for each line, until end of word */
9986 CHECKEND(); /* set c to PEOF if at end of here document */
9987 for (;;) { /* until end of line or end of word */
9988 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
9989 switch(SIT(c, syntax)) {
9990 case CNL: /* '\n' */
9991 if (syntax == BASESYNTAX)
9992 goto endword; /* exit outer loop */
9998 goto loop; /* continue outer loop */
10003 if (eofmark == NULL || dblquote)
10004 USTPUTC(CTLESC, out);
10007 case CBACK: /* backslash */
10010 USTPUTC(CTLESC, out);
10011 USTPUTC('\\', out);
10013 } else if (c == '\n') {
10019 c != '\\' && c != '`' &&
10025 USTPUTC(CTLESC, out);
10026 USTPUTC('\\', out);
10028 if (SIT(c, SQSYNTAX) == CCTL)
10029 USTPUTC(CTLESC, out);
10037 if (eofmark == NULL) {
10038 USTPUTC(CTLQUOTEMARK, out);
10046 if (eofmark != NULL && arinest == 0 &&
10050 if (dqvarnest == 0) {
10051 syntax = BASESYNTAX;
10058 case CVAR: /* '$' */
10059 PARSESUB(); /* parse substitution */
10061 case CENDVAR: /* '}' */
10064 if (dqvarnest > 0) {
10067 USTPUTC(CTLENDVAR, out);
10072 #ifdef CONFIG_ASH_MATH_SUPPORT
10073 case CLP: /* '(' in arithmetic */
10077 case CRP: /* ')' in arithmetic */
10078 if (parenlevel > 0) {
10082 if (pgetc() == ')') {
10083 if (--arinest == 0) {
10084 USTPUTC(CTLENDARI, out);
10085 syntax = prevsyntax;
10086 if (syntax == DQSYNTAX)
10094 * unbalanced parens
10095 * (don't 2nd guess - no error)
10103 case CBQUOTE: /* '`' */
10107 goto endword; /* exit outer loop */
10112 goto endword; /* exit outer loop */
10113 #ifdef CONFIG_ASH_ALIAS
10123 #ifdef CONFIG_ASH_MATH_SUPPORT
10124 if (syntax == ARISYNTAX)
10125 synerror("Missing '))'");
10127 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10128 synerror("Unterminated quoted string");
10129 if (varnest != 0) {
10130 startlinno = plinno;
10132 synerror("Missing '}'");
10134 USTPUTC('\0', out);
10135 len = out - (char *)stackblock();
10136 out = stackblock();
10137 if (eofmark == NULL) {
10138 if ((c == '>' || c == '<')
10141 && (*out == '\0' || is_digit(*out))) {
10143 return lasttoken = TREDIR;
10148 quoteflag = quotef;
10149 backquotelist = bqlist;
10150 grabstackblock(len);
10152 return lasttoken = TWORD;
10153 /* end of readtoken routine */
10158 * Check to see whether we are at the end of the here document. When this
10159 * is called, c is set to the first character of the next input line. If
10160 * we are at the end of the here document, this routine sets the c to PEOF.
10165 #ifdef CONFIG_ASH_ALIAS
10171 while (c == '\t') {
10175 if (c == *eofmark) {
10176 if (pfgets(line, sizeof line) != NULL) {
10180 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10181 if (*p == '\n' && *q == '\0') {
10184 needprompt = doprompt;
10186 pushstring(line, NULL);
10191 goto checkend_return;
10196 * Parse a redirection operator. The variable "out" points to a string
10197 * specifying the fd to be redirected. The variable "c" contains the
10198 * first character of the redirection operator.
10205 np = (union node *)stalloc(sizeof (struct nfile));
10210 np->type = NAPPEND;
10212 np->type = NCLOBBER;
10219 } else { /* c == '<' */
10221 switch (c = pgetc()) {
10223 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10224 np = (union node *)stalloc(sizeof (struct nhere));
10228 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10229 heredoc->here = np;
10230 if ((c = pgetc()) == '-') {
10231 heredoc->striptabs = 1;
10233 heredoc->striptabs = 0;
10239 np->type = NFROMFD;
10243 np->type = NFROMTO;
10253 np->nfile.fd = digit_val(fd);
10255 goto parseredir_return;
10260 * Parse a substitution. At this point, we have read the dollar sign
10261 * and nothing else.
10269 static const char types[] = "}-+?=";
10273 c <= PEOA_OR_PEOF ||
10274 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10278 } else if (c == '(') { /* $(command) or $((arith)) */
10279 if (pgetc() == '(') {
10280 #ifdef CONFIG_ASH_MATH_SUPPORT
10283 synerror("We unsupport $((arith))");
10290 USTPUTC(CTLVAR, out);
10291 typeloc = out - (char *)stackblock();
10292 USTPUTC(VSNORMAL, out);
10293 subtype = VSNORMAL;
10297 if ((c = pgetc()) == '}')
10300 subtype = VSLENGTH;
10305 if (c > PEOA_OR_PEOF && is_name(c)) {
10309 } while (c > PEOA_OR_PEOF && is_in_name(c));
10310 } else if (is_digit(c)) {
10314 } while (is_digit(c));
10316 else if (is_special(c)) {
10321 badsub: synerror("Bad substitution");
10325 if (subtype == 0) {
10332 p = strchr(types, c);
10335 subtype = p - types + VSNORMAL;
10341 subtype = c == '#' ? VSTRIMLEFT :
10354 if (dblquote || arinest)
10356 *((char *)stackblock() + typeloc) = subtype | flags;
10357 if (subtype != VSNORMAL) {
10359 if (dblquote || arinest) {
10364 goto parsesub_return;
10369 * Called to parse command substitutions. Newstyle is set if the command
10370 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10371 * list of commands (passed by reference), and savelen is the number of
10372 * characters on the top of the stack which must be preserved.
10376 struct nodelist **nlpp;
10379 char *volatile str;
10380 struct jmploc jmploc;
10381 struct jmploc *volatile savehandler;
10385 (void) &saveprompt;
10388 savepbq = parsebackquote;
10389 if (setjmp(jmploc.loc)) {
10392 parsebackquote = 0;
10393 handler = savehandler;
10394 longjmp(handler->loc, 1);
10398 savelen = out - (char *)stackblock();
10400 str = ckmalloc(savelen);
10401 memcpy(str, stackblock(), savelen);
10403 savehandler = handler;
10407 /* We must read until the closing backquote, giving special
10408 treatment to some slashes, and then push the string and
10409 reread it as input, interpreting it normally. */
10416 STARTSTACKSTR(pout);
10422 switch (pc = pgetc()) {
10427 if ((pc = pgetc()) == '\n') {
10432 * If eating a newline, avoid putting
10433 * the newline into the new character
10434 * stream (via the STPUTC after the
10439 if (pc != '\\' && pc != '`' && pc != '$'
10440 && (!dblquote || pc != '"'))
10441 STPUTC('\\', pout);
10442 if (pc > PEOA_OR_PEOF) {
10448 #ifdef CONFIG_ASH_ALIAS
10451 startlinno = plinno;
10452 synerror("EOF in backquote substitution");
10456 needprompt = doprompt;
10465 STPUTC('\0', pout);
10466 psavelen = pout - (char *)stackblock();
10467 if (psavelen > 0) {
10468 pstr = grabstackstr(pout);
10469 setinputstring(pstr);
10474 nlpp = &(*nlpp)->next;
10475 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10476 (*nlpp)->next = NULL;
10477 parsebackquote = oldstyle;
10480 saveprompt = doprompt;
10487 doprompt = saveprompt;
10489 if (readtoken() != TRP)
10496 * Start reading from old file again, ignoring any pushed back
10497 * tokens left from the backquote parsing
10502 while (stackblocksize() <= savelen)
10504 STARTSTACKSTR(out);
10506 memcpy(out, str, savelen);
10507 STADJUST(savelen, out);
10513 parsebackquote = savepbq;
10514 handler = savehandler;
10515 if (arinest || dblquote)
10516 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10518 USTPUTC(CTLBACKQ, out);
10520 goto parsebackq_oldreturn;
10522 goto parsebackq_newreturn;
10525 #ifdef CONFIG_ASH_MATH_SUPPORT
10527 * Parse an arithmetic expansion (indicate start of one and set state)
10531 if (++arinest == 1) {
10532 prevsyntax = syntax;
10533 syntax = ARISYNTAX;
10534 USTPUTC(CTLARI, out);
10541 * we collapse embedded arithmetic expansion to
10542 * parenthesis, which should be equivalent
10546 goto parsearith_return;
10550 } /* end of readtoken */
10555 * Returns true if the text contains nothing to expand (no dollar signs
10560 noexpand(char *text)
10566 while ((c = *p++) != '\0') {
10567 if (c == CTLQUOTEMARK)
10571 else if (SIT(c, BASESYNTAX) == CCTL)
10579 * Return of a legal variable name (a letter or underscore followed by zero or
10580 * more letters, underscores, and digits).
10584 endofname(const char *name)
10592 if (! is_in_name(*p))
10600 * Called when an unexpected token is read during the parse. The argument
10601 * is the token that is expected, or -1 if more than one type of token can
10602 * occur at this point.
10605 static void synexpect(int token)
10610 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10612 sprintf(msg + l, " (expecting %s)", tokname(token));
10618 synerror(const char *msg)
10620 error("Syntax error: %s", msg);
10626 * called by editline -- any expansions to the prompt
10627 * should be added here.
10630 static void setprompt(int whichprompt)
10632 const char *prompt;
10634 switch (whichprompt) {
10648 static const char *const *findkwd(const char *s)
10650 return bsearch(s, tokname_array + KWDOFFSET,
10651 (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
10652 sizeof(const char *), pstrcmp);
10655 /* $NetBSD: redir.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */
10658 * Code for dealing with input/output redirection.
10661 #define EMPTY -2 /* marks an unused slot in redirtab */
10663 # define PIPESIZE 4096 /* amount of buffering in a pipe */
10665 # define PIPESIZE PIPE_BUF
10669 * Open a file in noclobber mode.
10670 * The code was copied from bash.
10673 noclobberopen(const char *fname)
10676 struct stat finfo, finfo2;
10679 * If the file exists and is a regular file, return an error
10682 r = stat(fname, &finfo);
10683 if (r == 0 && S_ISREG(finfo.st_mode)) {
10689 * If the file was not present (r != 0), make sure we open it
10690 * exclusively so that if it is created before we open it, our open
10691 * will fail. Make sure that we do not truncate an existing file.
10692 * Note that we don't turn on O_EXCL unless the stat failed -- if the
10693 * file was not a regular file, we leave O_EXCL off.
10696 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10697 fd = open(fname, O_WRONLY|O_CREAT, 0666);
10699 /* If the open failed, return the file descriptor right away. */
10704 * OK, the open succeeded, but the file may have been changed from a
10705 * non-regular file to a regular file between the stat and the open.
10706 * We are assuming that the O_EXCL open handles the case where FILENAME
10707 * did not exist and is symlinked to an existing file between the stat
10712 * If we can open it and fstat the file descriptor, and neither check
10713 * revealed that it was a regular file, and the file has not been
10714 * replaced, return the file descriptor.
10716 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10717 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
10720 /* The file has been replaced. badness. */
10727 * Handle here documents. Normally we fork off a process to write the
10728 * data to a pipe. If the document is short, we can stuff the data in
10729 * the pipe without forking.
10733 openhere(union node *redir)
10739 error("Pipe call failed");
10740 if (redir->type == NHERE) {
10741 len = strlen(redir->nhere.doc->narg.text);
10742 if (len <= PIPESIZE) {
10743 xwrite(pip[1], redir->nhere.doc->narg.text, len);
10747 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
10749 signal(SIGINT, SIG_IGN);
10750 signal(SIGQUIT, SIG_IGN);
10751 signal(SIGHUP, SIG_IGN);
10753 signal(SIGTSTP, SIG_IGN);
10755 signal(SIGPIPE, SIG_DFL);
10756 if (redir->type == NHERE)
10757 xwrite(pip[1], redir->nhere.doc->narg.text, len);
10759 expandhere(redir->nhere.doc, pip[1]);
10768 openredirect(union node *redir)
10773 switch (redir->nfile.type) {
10775 fname = redir->nfile.expfname;
10776 if ((f = open(fname, O_RDONLY)) < 0)
10780 fname = redir->nfile.expfname;
10781 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
10785 /* Take care of noclobber mode. */
10787 fname = redir->nfile.expfname;
10788 if ((f = noclobberopen(fname)) < 0)
10794 fname = redir->nfile.expfname;
10795 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
10799 fname = redir->nfile.expfname;
10800 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
10807 /* Fall through to eliminate warning. */
10814 f = openhere(redir);
10820 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
10822 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
10826 dupredirect(union node *redir, int f)
10828 int fd = redir->nfile.fd;
10830 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
10831 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
10832 copyfd(redir->ndup.dupfd, fd);
10845 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
10846 * old file descriptors are stashed away so that the redirection can be
10847 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
10848 * standard output, and the standard error if it becomes a duplicate of
10849 * stdout, is saved in memory.
10853 redirect(union node *redir, int flags)
10856 struct redirtab *sv;
10867 if (flags & REDIR_PUSH) {
10868 struct redirtab *q;
10869 q = ckmalloc(sizeof (struct redirtab));
10870 q->next = redirlist;
10872 q->nullredirs = nullredirs - 1;
10873 for (i = 0 ; i < 10 ; i++)
10874 q->renamed[i] = EMPTY;
10881 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
10882 n->ndup.dupfd == fd)
10883 continue; /* redirect from/to same file descriptor */
10885 newfd = openredirect(n);
10888 if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
10889 i = fcntl(fd, F_DUPFD, 10);
10896 error("%d: %m", fd);
10906 dupredirect(n, newfd);
10907 } while ((n = n->nfile.next));
10917 * Undo the effects of the last redirection.
10923 struct redirtab *rp;
10926 if (--nullredirs >= 0)
10930 for (i = 0 ; i < 10 ; i++) {
10931 if (rp->renamed[i] != EMPTY) {
10934 copyfd(rp->renamed[i], i);
10936 close(rp->renamed[i]);
10939 redirlist = rp->next;
10940 nullredirs = rp->nullredirs;
10946 * Undo all redirections. Called on error or interrupt.
10950 * Discard all saved file descriptors.
10954 clearredir(int drop)
10967 * Copy a file descriptor to be >= to. Returns -1
10968 * if the source file descriptor is closed, EMPTY if there are no unused
10969 * file descriptors left.
10973 copyfd(int from, int to)
10977 newfd = fcntl(from, F_DUPFD, to);
10979 if (errno == EMFILE)
10982 error("%d: %m", from);
10989 redirectsafe(union node *redir, int flags)
10992 volatile int saveint;
10993 struct jmploc *volatile savehandler = handler;
10994 struct jmploc jmploc;
10997 if (!(err = setjmp(jmploc.loc) * 2)) {
10999 redirect(redir, flags);
11001 handler = savehandler;
11002 if (err && exception != EXERROR)
11003 longjmp(handler->loc, 1);
11004 RESTOREINT(saveint);
11008 /* $NetBSD: show.c,v 1.24 2003/01/22 20:36:04 dsl Exp $ */
11011 static void shtree(union node *, int, char *, FILE*);
11012 static void shcmd(union node *, FILE *);
11013 static void sharg(union node *, FILE *);
11014 static void indent(int, char *, FILE *);
11015 static void trstring(char *);
11019 showtree(union node *n)
11021 trputs("showtree called\n");
11022 shtree(n, 1, NULL, stdout);
11027 shtree(union node *n, int ind, char *pfx, FILE *fp)
11029 struct nodelist *lp;
11035 indent(ind, pfx, fp);
11046 shtree(n->nbinary.ch1, ind, NULL, fp);
11049 shtree(n->nbinary.ch2, ind, NULL, fp);
11057 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
11062 if (n->npipe.backgnd)
11068 fprintf(fp, "<node type %d>", n->type);
11078 shcmd(union node *cmd, FILE *fp)
11086 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11092 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11095 switch (np->nfile.type) {
11096 case NTO: s = ">"; dftfd = 1; break;
11097 case NCLOBBER: s = ">|"; dftfd = 1; break;
11098 case NAPPEND: s = ">>"; dftfd = 1; break;
11099 case NTOFD: s = ">&"; dftfd = 1; break;
11100 case NFROM: s = "<"; dftfd = 0; break;
11101 case NFROMFD: s = "<&"; dftfd = 0; break;
11102 case NFROMTO: s = "<>"; dftfd = 0; break;
11103 default: s = "*error*"; dftfd = 0; break;
11105 if (np->nfile.fd != dftfd)
11106 fprintf(fp, "%d", np->nfile.fd);
11108 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11109 fprintf(fp, "%d", np->ndup.dupfd);
11111 sharg(np->nfile.fname, fp);
11120 sharg(union node *arg, FILE *fp)
11123 struct nodelist *bqlist;
11126 if (arg->type != NARG) {
11127 out1fmt("<node type %d>\n", arg->type);
11130 bqlist = arg->narg.backquote;
11131 for (p = arg->narg.text ; *p ; p++) {
11140 if (subtype == VSLENGTH)
11146 if (subtype & VSNUL)
11149 switch (subtype & VSTYPE) {
11168 case VSTRIMLEFTMAX:
11175 case VSTRIMRIGHTMAX:
11182 out1fmt("<subtype %d>", subtype);
11189 case CTLBACKQ|CTLQUOTE:
11192 shtree(bqlist->n, -1, NULL, fp);
11204 indent(int amount, char *pfx, FILE *fp)
11208 for (i = 0 ; i < amount ; i++) {
11209 if (pfx && i == amount - 1)
11230 putc(c, tracefile);
11234 trace(const char *fmt, ...)
11241 (void) vfprintf(tracefile, fmt, va);
11246 tracev(const char *fmt, va_list va)
11250 (void) vfprintf(tracefile, fmt, va);
11255 trputs(const char *s)
11259 fputs(s, tracefile);
11271 putc('"', tracefile);
11272 for (p = s ; *p ; p++) {
11274 case '\n': c = 'n'; goto backslash;
11275 case '\t': c = 't'; goto backslash;
11276 case '\r': c = 'r'; goto backslash;
11277 case '"': c = '"'; goto backslash;
11278 case '\\': c = '\\'; goto backslash;
11279 case CTLESC: c = 'e'; goto backslash;
11280 case CTLVAR: c = 'v'; goto backslash;
11281 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11282 case CTLBACKQ: c = 'q'; goto backslash;
11283 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
11284 backslash: putc('\\', tracefile);
11285 putc(c, tracefile);
11288 if (*p >= ' ' && *p <= '~')
11289 putc(*p, tracefile);
11291 putc('\\', tracefile);
11292 putc(*p >> 6 & 03, tracefile);
11293 putc(*p >> 3 & 07, tracefile);
11294 putc(*p & 07, tracefile);
11299 putc('"', tracefile);
11311 putc(' ', tracefile);
11313 putc('\n', tracefile);
11329 /* leave open because libedit might be using it */
11332 scopy("./trace", s);
11334 if (!freopen(s, "a", tracefile)) {
11335 fprintf(stderr, "Can't re-open %s\n", s);
11340 if ((tracefile = fopen(s, "a")) == NULL) {
11341 fprintf(stderr, "Can't open %s\n", s);
11347 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11348 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11350 setlinebuf(tracefile);
11351 fputs("\nTracing started.\n", tracefile);
11356 /* $NetBSD: trap.c,v 1.28 2002/11/24 22:35:43 christos Exp $ */
11359 * Sigmode records the current value of the signal handlers for the various
11360 * modes. A value of zero means that the current handler is not known.
11361 * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
11364 #define S_DFL 1 /* default signal handling (SIG_DFL) */
11365 #define S_CATCH 2 /* signal is caught */
11366 #define S_IGN 3 /* signal is ignored (SIG_IGN) */
11367 #define S_HARD_IGN 4 /* signal is ignored permenantly */
11368 #define S_RESET 5 /* temporary - to reset a hard ignored sig */
11373 * The trap builtin.
11377 trapcmd(int argc, char **argv)
11386 for (signo = 0 ; signo < NSIG ; signo++) {
11387 if (trap[signo] != NULL) {
11390 sn = u_signal_names(0, &signo, 0);
11393 out1fmt("trap -- %s %s\n",
11394 single_quote(trap[signo]), sn);
11404 if ((signo = decode_signal(*ap, 0)) < 0)
11405 error("%s: bad trap", *ap);
11408 if (action[0] == '-' && action[1] == '\0')
11411 action = savestr(action);
11414 ckfree(trap[signo]);
11415 trap[signo] = action;
11427 * Clear traps on a fork.
11435 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
11436 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
11440 if (tp != &trap[0])
11441 setsignal(tp - trap);
11450 * Set the signal handler for the specified signal. The routine figures
11451 * out what it should be set to.
11455 setsignal(int signo)
11459 struct sigaction act;
11461 if ((t = trap[signo]) == NULL)
11463 else if (*t != '\0')
11467 if (rootshell && action == S_DFL) {
11470 if (iflag || minusc || sflag == 0)
11493 t = &sigmode[signo - 1];
11497 * current setting unknown
11499 if (sigaction(signo, 0, &act) == -1) {
11501 * Pretend it worked; maybe we should give a warning
11502 * here, but other shells don't. We don't alter
11503 * sigmode, so that we retry every time.
11507 if (act.sa_handler == SIG_IGN) {
11508 if (mflag && (signo == SIGTSTP ||
11509 signo == SIGTTIN || signo == SIGTTOU)) {
11510 tsig = S_IGN; /* don't hard ignore these */
11514 tsig = S_RESET; /* force to be set */
11517 if (tsig == S_HARD_IGN || tsig == action)
11521 act.sa_handler = onsig;
11524 act.sa_handler = SIG_IGN;
11527 act.sa_handler = SIG_DFL;
11531 sigfillset(&act.sa_mask);
11532 sigaction(signo, &act, 0);
11540 ignoresig(int signo)
11542 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11543 signal(signo, SIG_IGN);
11545 sigmode[signo - 1] = S_HARD_IGN;
11557 gotsig[signo - 1] = 1;
11558 pendingsigs = signo;
11560 if (exsig || (signo == SIGINT && !trap[SIGINT])) {
11570 * Called to execute a trap. Perhaps we should avoid entering new trap
11571 * handlers while we are executing a trap handler.
11581 savestatus = exitstatus;
11583 while (pendingsigs = 0, barrier(), (p = memchr(q, 1, NSIG - 1))) {
11585 p = trap[p - q + 1];
11589 exitstatus = savestatus;
11596 * Controls whether the shell is interactive or not.
11601 setinteractive(int on)
11603 static int is_interactive;
11605 if (++on == is_interactive)
11607 is_interactive = on;
11609 setsignal(SIGQUIT);
11610 setsignal(SIGTERM);
11611 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11612 if(is_interactive > 1) {
11613 /* Looks like they want an interactive shell */
11614 static int do_banner;
11618 "\n\n" BB_BANNER " Built-in shell (ash)\n"
11619 "Enter 'help' for a list of built-in commands.\n\n");
11627 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11628 /*** List the available builtins ***/
11630 static int helpcmd(int argc, char **argv)
11634 out1fmt("\nBuilt-in commands:\n-------------------\n");
11635 for (col = 0, i = 0; i < NUMBUILTINS; i++) {
11636 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11637 builtincmd[i].name + 1);
11643 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
11645 extern const struct BB_applet applets[];
11646 extern const size_t NUM_APPLETS;
11648 for (i = 0; i < NUM_APPLETS; i++) {
11650 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
11659 return EXIT_SUCCESS;
11661 #endif /* CONFIG_FEATURE_SH_EXTRA_QUIET */
11664 * Called to exit the shell.
11674 status = exitstatus;
11675 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
11676 if (setjmp(loc.loc)) {
11680 if ((p = trap[0]) != NULL && *p != '\0') {
11685 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
11686 if (iflag && rootshell) {
11687 const char *hp = lookupvar("HISTFILE");
11690 save_history ( hp );
11699 static int decode_signal(const char *string, int minsig)
11702 const char *name = u_signal_names(string, &signo, minsig);
11704 return name ? signo : -1;
11707 /* $NetBSD: var.c,v 1.32 2003/01/22 20:36:04 dsl Exp $ */
11709 static struct var *vartab[VTABSIZE];
11711 static int vpcmp(const void *, const void *);
11712 static struct var **findvar(struct var **, const char *);
11715 * Initialize the varable symbol tables and import the environment
11719 #ifdef CONFIG_ASH_GETOPTS
11721 * Safe version of setvar, returns 1 on success 0 on failure.
11725 setvarsafe(const char *name, const char *val, int flags)
11728 volatile int saveint;
11729 struct jmploc *volatile savehandler = handler;
11730 struct jmploc jmploc;
11733 if (setjmp(jmploc.loc))
11737 setvar(name, val, flags);
11740 handler = savehandler;
11741 RESTOREINT(saveint);
11747 * Set the value of a variable. The flags argument is ored with the
11748 * flags of the variable. If val is NULL, the variable is unset.
11752 setvar(const char *name, const char *val, int flags)
11759 q = endofname(name);
11760 p = strchrnul(q, '=');
11761 namelen = p - name;
11762 if (!namelen || p != q)
11763 error("%.*s: bad variable name", namelen, name);
11768 vallen = strlen(val);
11771 p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
11775 p = mempcpy(p, val, vallen);
11778 setvareq(nameeq, flags | VNOSAVE);
11785 * Same as setvar except that the variable and value are passed in
11786 * the first argument as name=value. Since the first argument will
11787 * be actually stored in the table, it should not be a string that
11789 * Called with interrupts off.
11793 setvareq(char *s, int flags)
11795 struct var *vp, **vpp;
11798 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
11799 vp = *findvar(vpp, s);
11801 if (vp->flags & VREADONLY) {
11802 if (flags & VNOSAVE)
11804 error("%.*s: is read only", strchrnul(s, '=') - s, s);
11807 if (flags & VNOSET)
11810 if (vp->func && (flags & VNOFUNC) == 0)
11811 (*vp->func)(strchrnul(s, '=') + 1);
11813 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
11816 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
11818 if (flags & VNOSET)
11821 vp = ckmalloc(sizeof (*vp));
11826 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
11835 * Process a linked list of variable assignments.
11839 listsetvar(struct strlist *list_set_var, int flags)
11841 struct strlist *lp = list_set_var;
11847 setvareq(lp->text, flags);
11848 } while ((lp = lp->next));
11854 * Find the value of a variable. Returns NULL if not set.
11858 lookupvar(const char *name)
11862 if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
11863 return strchrnul(v->text, '=') + 1;
11871 * Search the environment of a builtin command.
11875 bltinlookup(const char *name)
11877 struct strlist *sp;
11879 for (sp = cmdenviron ; sp ; sp = sp->next) {
11880 if (varequal(sp->text, name))
11881 return strchrnul(sp->text, '=') + 1;
11883 return lookupvar(name);
11889 * Generate a list of variables satisfying the given conditions.
11893 listvars(int on, int off, char ***end)
11904 for (vp = *vpp ; vp ; vp = vp->next)
11905 if ((vp->flags & mask) == on) {
11906 if (ep == stackstrend())
11907 ep = growstackstr();
11908 *ep++ = (char *) vp->text;
11910 } while (++vpp < vartab + VTABSIZE);
11911 if (ep == stackstrend())
11912 ep = growstackstr();
11916 return grabstackstr(ep);
11922 * POSIX requires that 'set' (but not export or readonly) output the
11923 * variables in lexicographic order - by the locale's collating order (sigh).
11924 * Maybe we could keep them in an ordered balanced binary tree
11925 * instead of hashed lists.
11926 * For now just roll 'em through qsort for printing...
11930 showvars(const char *sep_prefix, int on, int off)
11933 char **ep, **epend;
11935 ep = listvars(on, off, &epend);
11936 qsort(ep, epend - ep, sizeof(char *), vpcmp);
11938 sep = *sep_prefix ? spcstr : sep_prefix;
11940 for (; ep < epend; ep++) {
11944 p = strchrnul(*ep, '=');
11947 q = single_quote(++p);
11949 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
11958 * The export and readonly commands.
11962 exportcmd(int argc, char **argv)
11968 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
11971 notp = nextopt("p") - 'p';
11972 if (notp && ((name = *(aptr = argptr)))) {
11974 if ((p = strchr(name, '=')) != NULL) {
11977 if ((vp = *findvar(hashvar(name), name))) {
11982 setvar(name, p, flag);
11983 } while ((name = *++aptr) != NULL);
11985 showvars(argv[0], flag, 0);
11992 * Make a variable a local variable. When a variable is made local, it's
11993 * value and flags are saved in a localvar structure. The saved values
11994 * will be restored when the shell function returns. We handle the name
11995 * "-" as a special case.
11999 mklocal(char *name)
12001 struct localvar *lvp;
12006 lvp = ckmalloc(sizeof (struct localvar));
12007 if (name[0] == '-' && name[1] == '\0') {
12009 p = ckmalloc(sizeof(optlist));
12010 lvp->text = memcpy(p, optlist, sizeof(optlist));
12015 vpp = hashvar(name);
12016 vp = *findvar(vpp, name);
12017 eq = strchr(name, '=');
12020 setvareq(name, VSTRFIXED);
12022 setvar(name, NULL, VSTRFIXED);
12023 vp = *vpp; /* the new variable */
12024 lvp->flags = VUNSET;
12026 lvp->text = vp->text;
12027 lvp->flags = vp->flags;
12028 vp->flags |= VSTRFIXED|VTEXTFIXED;
12034 lvp->next = localvars;
12040 * The "local" command.
12044 localcmd(int argc, char **argv)
12049 while ((name = *argv++) != NULL) {
12059 * Called after a function returns.
12060 * Interrupts must be off.
12066 struct localvar *lvp;
12069 while ((lvp = localvars) != NULL) {
12070 localvars = lvp->next;
12072 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
12073 if (vp == NULL) { /* $- saved */
12074 memcpy(optlist, lvp->text, sizeof(optlist));
12077 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12078 unsetvar(vp->text);
12081 (*vp->func)(strchrnul(lvp->text, '=') + 1);
12082 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12084 vp->flags = lvp->flags;
12085 vp->text = lvp->text;
12093 * The unset builtin command. We unset the function before we unset the
12094 * variable to allow a function to be unset when there is a readonly variable
12095 * with the same name.
12099 unsetcmd(int argc, char **argv)
12106 while ((i = nextopt("vf")) != '\0') {
12110 for (ap = argptr; *ap ; ap++) {
12125 * Unset the specified variable.
12129 unsetvar(const char *s)
12135 vpp = findvar(hashvar(s), s);
12139 int flags = vp->flags;
12142 if (flags & VREADONLY)
12144 if (flags & VUNSET)
12146 if ((flags & VSTRFIXED) == 0) {
12148 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
12155 vp->flags &= ~VEXPORT;
12168 * Find the appropriate entry in the hash table from the name.
12171 static struct var **
12172 hashvar(const char *p)
12174 unsigned int hashval;
12176 hashval = ((unsigned char) *p) << 4;
12177 while (*p && *p != '=')
12178 hashval += (unsigned char) *p++;
12179 return &vartab[hashval % VTABSIZE];
12185 * Compares two strings up to the first = or '\0'. The first
12186 * string must be terminated by '='; the second may be terminated by
12187 * either '=' or '\0'.
12191 varcmp(const char *p, const char *q)
12195 while ((c = *p) == (d = *q)) {
12196 if (!c || c == '=')
12210 vpcmp(const void *a, const void *b)
12212 return varcmp(*(const char **)a, *(const char **)b);
12215 static struct var **
12216 findvar(struct var **vpp, const char *name)
12218 for (; *vpp; vpp = &(*vpp)->next) {
12219 if (varequal((*vpp)->text, name)) {
12225 /* $NetBSD: setmode.c,v 1.29 2003/01/15 23:58:03 kleink Exp $ */
12228 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
12229 * This code for the times builtin.
12232 #include <sys/times.h>
12234 int timescmd(int ac, char **av) {
12236 long int clk_tck = sysconf(_SC_CLK_TCK);
12239 out1fmt("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
12240 (int) (buf.tms_utime / clk_tck / 60),
12241 ((double) buf.tms_utime) / clk_tck,
12242 (int) (buf.tms_stime / clk_tck / 60),
12243 ((double) buf.tms_stime) / clk_tck,
12244 (int) (buf.tms_cutime / clk_tck / 60),
12245 ((double) buf.tms_cutime) / clk_tck,
12246 (int) (buf.tms_cstime / clk_tck / 60),
12247 ((double) buf.tms_cstime) / clk_tck);
12251 #ifdef CONFIG_ASH_MATH_SUPPORT
12253 dash_arith(const char *s)
12259 result = arith(s, &errcode);
12262 error("divide by zero");
12273 * The exp(1) builtin.
12276 expcmd(int argc, char **argv)
12287 * concatenate arguments
12289 STARTSTACKSTR(concat);
12293 STPUTC(*p++, concat);
12294 if ((p = *ap++) == NULL)
12296 STPUTC(' ', concat);
12298 STPUTC('\0', concat);
12299 p = grabstackstr(concat);
12306 out1fmt("%ld\n", i);
12309 #endif /* CONFIG_ASH_MATH_SUPPORT */
12311 /* $NetBSD: miscbltin.c,v 1.31 2002/11/24 22:35:41 christos Exp $ */
12314 * Miscelaneous builtins.
12320 #if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
12321 typedef enum __rlimit_resource rlim_t;
12327 * The read builtin. The -e option causes backslashes to escape the
12328 * following character.
12330 * This uses unbuffered input, which may be avoidable in some cases.
12334 readcmd(int argc, char **argv)
12349 while ((i = nextopt("p:r")) != '\0') {
12351 prompt = optionarg;
12355 if (prompt && isatty(0)) {
12359 if (*(ap = argptr) == NULL)
12360 error("arg count");
12361 if ((ifs = bltinlookup("IFS")) == NULL)
12368 if (read(0, &c, 1) != 1) {
12380 if (!rflag && c == '\\') {
12386 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12390 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12392 setvar(*ap, stackblock(), 0);
12402 /* Remove trailing blanks */
12403 while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12405 setvar(*ap, stackblock(), 0);
12406 while (*++ap != NULL)
12407 setvar(*ap, nullstr, 0);
12412 static int umaskcmd(int argc, char **argv)
12414 static const char permuser[3] = "ugo";
12415 static const char permmode[3] = "rwx";
12416 static const short int permmask[] = {
12417 S_IRUSR, S_IWUSR, S_IXUSR,
12418 S_IRGRP, S_IWGRP, S_IXGRP,
12419 S_IROTH, S_IWOTH, S_IXOTH
12425 int symbolic_mode = 0;
12427 while (nextopt("S") != '\0') {
12436 if ((ap = *argptr) == NULL) {
12437 if (symbolic_mode) {
12441 for (i = 0; i < 3; i++) {
12444 *p++ = permuser[i];
12446 for (j = 0; j < 3; j++) {
12447 if ((mask & permmask[3 * i + j]) == 0) {
12448 *p++ = permmode[j];
12456 out1fmt("%.4o\n", mask);
12459 if (is_digit((unsigned char) *ap)) {
12462 if (*ap >= '8' || *ap < '0')
12463 error(illnum, argv[1]);
12464 mask = (mask << 3) + (*ap - '0');
12465 } while (*++ap != '\0');
12468 mask = ~mask & 0777;
12469 if (!bb_parse_mode(ap, &mask)) {
12470 error("Illegal mode: %s", ap);
12472 umask(~mask & 0777);
12481 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12482 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12483 * ash by J.T. Conklin.
12491 int factor; /* multiply by to get rlim_{cur,max} values */
12495 static const struct limits limits[] = {
12497 { "time(seconds)", RLIMIT_CPU, 1, 't' },
12499 #ifdef RLIMIT_FSIZE
12500 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
12503 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
12505 #ifdef RLIMIT_STACK
12506 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
12509 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
12512 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
12514 #ifdef RLIMIT_MEMLOCK
12515 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
12517 #ifdef RLIMIT_NPROC
12518 { "process(processes)", RLIMIT_NPROC, 1, 'p' },
12520 #ifdef RLIMIT_NOFILE
12521 { "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' },
12524 { "vmemory(kbytes)", RLIMIT_VMEM, 1024, 'v' },
12527 { "swap(kbytes)", RLIMIT_SWAP, 1024, 'w' },
12529 { (char *) 0, 0, 0, '\0' }
12533 ulimitcmd(int argc, char **argv)
12537 enum { SOFT = 0x1, HARD = 0x2 }
12539 const struct limits *l;
12542 struct rlimit limit;
12545 while ((optc = nextopt("HSatfdsmcnpl")) != '\0')
12560 for (l = limits; l->name && l->option != what; l++)
12563 error("internal error (%c)", what);
12565 set = *argptr ? 1 : 0;
12569 if (all || argptr[1])
12570 error("too many arguments");
12571 if (strcmp(p, "unlimited") == 0)
12572 val = RLIM_INFINITY;
12576 while ((c = *p++) >= '0' && c <= '9')
12578 val = (val * 10) + (long)(c - '0');
12579 if (val < (rlim_t) 0)
12583 error("bad number");
12588 for (l = limits; l->name; l++) {
12589 getrlimit(l->cmd, &limit);
12591 val = limit.rlim_cur;
12592 else if (how & HARD)
12593 val = limit.rlim_max;
12595 out1fmt("%-20s ", l->name);
12596 if (val == RLIM_INFINITY)
12597 out1fmt("unlimited\n");
12601 out1fmt("%lld\n", (long long) val);
12607 getrlimit(l->cmd, &limit);
12610 limit.rlim_max = val;
12612 limit.rlim_cur = val;
12613 if (setrlimit(l->cmd, &limit) < 0)
12614 error("error setting limit (%m)");
12617 val = limit.rlim_cur;
12618 else if (how & HARD)
12619 val = limit.rlim_max;
12621 if (val == RLIM_INFINITY)
12622 out1fmt("unlimited\n");
12626 out1fmt("%lld\n", (long long) val);
12633 const char *bb_applet_name = "debug stuff usage";
12634 int main(int argc, char **argv)
12636 return ash_main(argc, argv);
12641 * Copyright (c) 1989, 1991, 1993, 1994
12642 * The Regents of the University of California. All rights reserved.
12644 * This code is derived from software contributed to Berkeley by
12645 * Kenneth Almquist.
12647 * Redistribution and use in source and binary forms, with or without
12648 * modification, are permitted provided that the following conditions
12650 * 1. Redistributions of source code must retain the above copyright
12651 * notice, this list of conditions and the following disclaimer.
12652 * 2. Redistributions in binary form must reproduce the above copyright
12653 * notice, this list of conditions and the following disclaimer in the
12654 * documentation and/or other materials provided with the distribution.
12656 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
12657 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
12659 * 4. Neither the name of the University nor the names of its contributors
12660 * may be used to endorse or promote products derived from this software
12661 * without specific prior written permission.
12663 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
12664 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
12665 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
12666 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
12667 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
12668 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
12669 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
12670 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
12671 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
12672 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF