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
28 * Modified by Erik Andersen <andersee@debian.org> and
29 * Vladimir Oleynik <dzo@simtreas.ru> to be used in busybox
32 * Original copyright notice is retained at the end of this file.
36 /* These defines allow you to adjust the feature set to be compiled
37 * into the ash shell. As a rule, enabling these options will make
38 * ash get bigger... With all of these options off, ash adds about
39 * 60k to busybox on an x86 system.*/
42 /* Enable job control. This allows you to run jobs in the background,
43 * which is great when ash is being used as an interactive shell, but
44 * it completely useless for is all you are doing is running scripts.
45 * This adds about 2.5k on an x86 system. */
48 /* This enables alias support in ash. If you want to support things
49 * like "alias ls='ls -l'" with ash, enable this. This is only useful
50 * when ash is used as an intractive shell. This adds about 1.5k */
53 /* If you need ash to act as a full Posix shell, with full math
54 * support, enable this. This adds a bit over 2k an x86 system. */
55 //#undef ASH_MATH_SUPPORT
56 #define ASH_MATH_SUPPORT
58 /* Getopts is used by shell procedures to parse positional parameters.
59 * You probably want to leave this disabled, and use the busybox getopt
60 * applet if you want to do this sort of thing. There are some scripts
61 * out there that use it, so it you need it, enable. Most people will
62 * leave this disabled. This adds 1k on an x86 system. */
65 /* This allows you to override shell builtins and use whatever is on
66 * the filesystem. This is most useful when ash is acting as a
67 * standalone shell. Adds about 272 bytes. */
71 /* Optimize size vs speed as size */
72 #define ASH_OPTIMIZE_FOR_SIZE
74 /* Enable this to compile in extra debugging noise. When debugging is
75 * on, debugging info will be written to $HOME/trace and a quit signal
76 * will generate a core dump. */
79 /* These are here to work with glibc -- Don't change these... */
101 #include <sys/stat.h>
102 #include <sys/cdefs.h>
103 #include <sys/ioctl.h>
104 #include <sys/param.h>
105 #include <sys/resource.h>
106 #include <sys/time.h>
107 #include <sys/times.h>
108 #include <sys/types.h>
109 #include <sys/wait.h>
112 #if !defined(FNMATCH_BROKEN)
115 #if !defined(GLOB_BROKEN)
127 * This file was generated by the mksyntax program.
131 #define CWORD 0 /* character is nothing special */
132 #define CNL 1 /* newline character */
133 #define CBACK 2 /* a backslash character */
134 #define CSQUOTE 3 /* single quote */
135 #define CDQUOTE 4 /* double quote */
136 #define CENDQUOTE 5 /* a terminating quote */
137 #define CBQUOTE 6 /* backwards single quote */
138 #define CVAR 7 /* a dollar sign */
139 #define CENDVAR 8 /* a '}' character */
140 #define CLP 9 /* a left paren in arithmetic */
141 #define CRP 10 /* a right paren in arithmetic */
142 #define CENDFILE 11 /* end of file */
143 #define CCTL 12 /* like CWORD, except it must be escaped */
144 #define CSPCL 13 /* these terminate a word */
145 #define CIGN 14 /* character should be ignored */
165 #define TENDBQUOTE 13
185 /* control characters in argument strings */
186 #define CTLESC '\201'
187 #define CTLVAR '\202'
188 #define CTLENDVAR '\203'
189 #define CTLBACKQ '\204'
190 #define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
191 /* CTLBACKQ | CTLQUOTE == '\205' */
192 #define CTLARI '\206'
193 #define CTLENDARI '\207'
194 #define CTLQUOTEMARK '\210'
197 #define is_digit(c) ((c)>='0' && (c)<='9')
198 #define is_name(c) (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalpha((unsigned char) (c))))
199 #define is_in_name(c) (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalnum((unsigned char) (c))))
202 * is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
203 * (assuming ascii char codes, as the original implementation did)
205 #define is_special(c) \
206 ( (((unsigned int)c) - 33 < 32) \
207 && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
209 #define digit_val(c) ((c) - '0')
212 #define _DIAGASSERT(x)
216 #define S_DFL 1 /* default signal handling (SIG_DFL) */
217 #define S_CATCH 2 /* signal is caught */
218 #define S_IGN 3 /* signal is ignored (SIG_IGN) */
219 #define S_HARD_IGN 4 /* signal is ignored permenantly */
220 #define S_RESET 5 /* temporary - to reset a hard ignored sig */
223 /* variable substitution byte (follows CTLVAR) */
224 #define VSTYPE 0x0f /* type of variable substitution */
225 #define VSNUL 0x10 /* colon--treat the empty string as unset */
226 #define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
228 /* values of VSTYPE field */
229 #define VSNORMAL 0x1 /* normal variable: $var or ${var} */
230 #define VSMINUS 0x2 /* ${var-text} */
231 #define VSPLUS 0x3 /* ${var+text} */
232 #define VSQUESTION 0x4 /* ${var?message} */
233 #define VSASSIGN 0x5 /* ${var=text} */
234 #define VSTRIMLEFT 0x6 /* ${var#pattern} */
235 #define VSTRIMLEFTMAX 0x7 /* ${var##pattern} */
236 #define VSTRIMRIGHT 0x8 /* ${var%pattern} */
237 #define VSTRIMRIGHTMAX 0x9 /* ${var%%pattern} */
238 #define VSLENGTH 0xa /* ${#var} */
240 /* flags passed to redirect */
241 #define REDIR_PUSH 01 /* save previous values of file descriptors */
242 #define REDIR_BACKQ 02 /* save the command output to pipe */
245 * BSD setjmp saves the signal mask, which violates ANSI C and takes time,
246 * so we use _setjmp instead.
250 #define setjmp(jmploc) _setjmp(jmploc)
251 #define longjmp(jmploc, val) _longjmp(jmploc, val)
255 * Most machines require the value returned from malloc to be aligned
256 * in some way. The following macro will get this right on many machines.
265 #define ALIGN(nbytes) (((nbytes) + sizeof(union align) - 1) & ~(sizeof(union align) - 1))
268 #ifdef BB_LOCALE_SUPPORT
270 static void change_lc_all(const char *value);
271 static void change_lc_ctype(const char *value);
275 * These macros allow the user to suspend the handling of interrupt signals
276 * over a period of time. This is similar to SIGHOLD to or sigblock, but
277 * much more efficient and portable. (But hacking the kernel is so much
278 * more fun than worrying about efficiency and portability. :-))
281 static void onint (void);
282 static volatile int suppressint;
283 static volatile int intpending;
285 #define INTOFF suppressint++
286 #ifndef ASH_OPTIMIZE_FOR_SIZE
287 #define INTON { if (--suppressint == 0 && intpending) onint(); }
288 #define FORCEINTON {suppressint = 0; if (intpending) onint();}
290 static void __inton (void);
291 static void forceinton (void);
292 #define INTON __inton()
293 #define FORCEINTON forceinton()
296 #define CLEAR_PENDING_INT intpending = 0
297 #define int_pending() intpending
300 typedef void *pointer;
302 #define NULL (void *)0
305 static inline pointer ckmalloc (int sz) { return xmalloc(sz); }
306 static inline pointer ckrealloc(void *p, int sz) { return xrealloc(p, sz); }
307 static inline char * savestr (const char *s) { return xstrdup(s); }
309 static pointer stalloc (int);
310 static void stunalloc (pointer);
311 static void ungrabstackstr (char *, char *);
312 static char * growstackstr(void);
313 static char * makestrspace(size_t newlen);
314 static char *sstrdup (const char *);
317 * Parse trees for commands are allocated in lifo order, so we use a stack
318 * to make this more efficient, and also to avoid all sorts of exception
319 * handling code to handle interrupts in the middle of a parse.
321 * The size 504 was chosen because the Ultrix malloc handles that size
325 #define MINSIZE 504 /* minimum size of a block */
329 struct stack_block *prev;
333 static struct stack_block stackbase;
334 static struct stack_block *stackp = &stackbase;
335 static struct stackmark *markp;
336 static char *stacknxt = stackbase.space;
337 static int stacknleft = MINSIZE;
340 #define equal(s1, s2) (strcmp(s1, s2) == 0)
342 #define stackblock() stacknxt
343 #define stackblocksize() stacknleft
344 #define STARTSTACKSTR(p) p = stackblock(), sstrnleft = stackblocksize()
346 #define STPUTC(c, p) (--sstrnleft >= 0? (*p++ = (c)) : (p = growstackstr(), *p++ = (c)))
347 #define CHECKSTRSPACE(n, p) { if (sstrnleft < n) p = makestrspace(n); }
348 #define STACKSTRNUL(p) (sstrnleft == 0? (p = growstackstr(), *p = '\0') : (*p = '\0'))
351 #define USTPUTC(c, p) (--sstrnleft, *p++ = (c))
352 #define STUNPUTC(p) (++sstrnleft, --p)
353 #define STTOPC(p) p[-1]
354 #define STADJUST(amount, p) (p += (amount), sstrnleft -= (amount))
355 #define grabstackstr(p) stalloc(stackblocksize() - sstrnleft)
357 #define ckfree(p) free((pointer)(p))
361 #define TRACE(param) trace param
362 static void trace (const char *, ...);
363 static void trargs (char **);
364 static void showtree (union node *);
365 static void trputc (int);
366 static void trputs (const char *);
367 static void opentrace (void);
402 #define EXP_FULL 0x1 /* perform word splitting & file globbing */
403 #define EXP_TILDE 0x2 /* do normal tilde expansion */
404 #define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
405 #define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
406 #define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
407 #define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
412 static char optet_vals[NOPTS];
414 static const char * const optlist[NOPTS] = {
433 #define optent_name(optent) (optent+1)
434 #define optent_letter(optent) optent[0]
435 #define optent_val(optent) optet_vals[optent]
437 #define eflag optent_val(0)
438 #define fflag optent_val(1)
439 #define Iflag optent_val(2)
440 #define iflag optent_val(3)
441 #define mflag optent_val(4)
442 #define nflag optent_val(5)
443 #define sflag optent_val(6)
444 #define xflag optent_val(7)
445 #define vflag optent_val(8)
446 #define Vflag optent_val(9)
447 #define Eflag optent_val(10)
448 #define Cflag optent_val(11)
449 #define aflag optent_val(12)
450 #define bflag optent_val(13)
451 #define uflag optent_val(14)
452 #define qflag optent_val(15)
455 /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
473 union node *redirect;
480 struct nodelist *cmdlist;
487 union node *redirect;
495 union node *elsepart;
526 struct nodelist *backquote;
564 struct nbinary nbinary;
567 struct nredir nredir;
571 struct nclist nclist;
581 struct nodelist *next;
585 struct backcmd { /* result of evalbackcmd */
586 int fd; /* file descriptor to read from */
587 char *buf; /* buffer */
588 int nleft; /* number of chars in buffer */
589 struct job *jp; /* job structure for command */
597 const struct builtincmd *cmd;
602 struct strlist *next;
608 struct strlist *list;
609 struct strlist **lastp;
613 struct strpush *prev; /* preceding string on stack */
617 struct alias *ap; /* if push was associated with an alias */
619 char *string; /* remember the string since it may change */
623 struct parsefile *prev; /* preceding file on stack */
624 int linno; /* current line */
625 int fd; /* file descriptor (or -1 if string) */
626 int nleft; /* number of chars left in this line */
627 int lleft; /* number of chars left in this buffer */
628 char *nextc; /* next char in buffer */
629 char *buf; /* input buffer */
630 struct strpush *strpush; /* for pushing strings at this level */
631 struct strpush basestrpush; /* so pushing one is fast */
635 struct stack_block *stackp;
638 struct stackmark *marknext;
642 int nparam; /* # of positional parameters (without $0) */
643 unsigned char malloc; /* if parameter list dynamically allocated */
644 char **p; /* parameter list */
645 int optind; /* next parameter to be processed by getopts */
646 int optoff; /* used by getopts */
650 * When commands are first encountered, they are entered in a hash table.
651 * This ensures that a full path search will not have to be done for them
652 * on each invocation.
654 * We should investigate converting to a linear search, even though that
655 * would make the command name "hash" a misnomer.
657 #define CMDTABLESIZE 31 /* should be prime */
658 #define ARB 1 /* actual size determined at run time */
663 struct tblentry *next; /* next entry in hash chain */
664 union param param; /* definition of builtin function */
665 short cmdtype; /* index identifying command */
666 char rehash; /* if set, cd done since entry created */
667 char cmdname[ARB]; /* name of command */
671 static struct tblentry *cmdtable[CMDTABLESIZE];
672 static int builtinloc = -1; /* index in path of %builtin, or -1 */
673 static int exerrno = 0; /* Last exec error */
676 static void tryexec (char *, char **, char **);
677 static void printentry (struct tblentry *, int);
678 static void clearcmdentry (int);
679 static struct tblentry *cmdlookup (const char *, int);
680 static void delete_cmd_entry (void);
681 static int path_change (const char *, int *);
684 static void flushall (void);
685 static void out2fmt (const char *, ...)
686 __attribute__((__format__(__printf__,1,2)));
687 static int xwrite (int, const char *, int);
689 static inline void outstr (const char *p, FILE *file) { fputs(p, file); }
690 static void out1str(const char *p) { outstr(p, stdout); }
691 static void out2str(const char *p) { outstr(p, stderr); }
693 #ifndef ASH_OPTIMIZE_FOR_SIZE
694 #define out2c(c) putc((c), stderr)
696 static void out2c(int c) { putc(c, stderr); }
700 #ifdef ASH_OPTIMIZE_FOR_SIZE
701 #define USE_SIT_FUNCTION
704 /* number syntax index */
705 #define BASESYNTAX 0 /* not in quotes */
706 #define DQSYNTAX 1 /* in double quotes */
707 #define SQSYNTAX 2 /* in single quotes */
708 #define ARISYNTAX 3 /* in arithmetic */
710 static const char S_I_T[][4] = {
711 /* 0 */ { CSPCL, CIGN, CIGN, CIGN }, /* PEOA */
712 /* 1 */ { CSPCL, CWORD, CWORD, CWORD }, /* ' ' */
713 /* 2 */ { CNL, CNL, CNL, CNL }, /* \n */
714 /* 3 */ { CWORD, CCTL, CCTL, CWORD }, /* !*-/:=?[]~ */
715 /* 4 */ { CDQUOTE, CENDQUOTE, CWORD, CDQUOTE }, /* '"' */
716 /* 5 */ { CVAR, CVAR, CWORD, CVAR }, /* $ */
717 /* 6 */ { CSQUOTE, CWORD, CENDQUOTE, CSQUOTE }, /* "'" */
718 /* 7 */ { CSPCL, CWORD, CWORD, CLP }, /* ( */
719 /* 8 */ { CSPCL, CWORD, CWORD, CRP }, /* ) */
720 /* 9 */ { CBACK, CBACK, CCTL, CBACK }, /* \ */
721 /* 10 */ { CBQUOTE, CBQUOTE, CWORD, CBQUOTE }, /* ` */
722 /* 11 */ { CENDVAR, CENDVAR, CWORD, CENDVAR }, /* } */
723 #ifndef USE_SIT_FUNCTION
724 /* 12 */ { CENDFILE, CENDFILE, CENDFILE, CENDFILE }, /* PEOF */
725 /* 13 */ { CWORD, CWORD, CWORD, CWORD }, /* 0-9A-Za-z */
726 /* 14 */ { CCTL, CCTL, CCTL, CCTL } /* CTLESC ... */
730 #ifdef USE_SIT_FUNCTION
732 #define U_C(c) ((unsigned char)(c))
734 static int SIT(int c, int syntax)
736 static const char spec_symbls[]="\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
737 static const char syntax_index_table [] = {
738 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
739 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
740 3, 1, 3, 3, 9, 3,10, 1, /* "=>?[\\]`|" */
745 if(c==PEOF) /* 2^8+2 */
747 if(c==PEOA) /* 2^8+1 */
749 else if(U_C(c)>=U_C(CTLESC) && U_C(c)<=U_C(CTLQUOTEMARK))
752 s = strchr(spec_symbls, c);
755 indx = syntax_index_table[(s-spec_symbls)];
757 return S_I_T[indx][syntax];
760 #else /* USE_SIT_FUNCTION */
762 #define SIT(c, syntax) S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax]
764 #define CSPCL_CIGN_CIGN_CIGN 0
765 #define CSPCL_CWORD_CWORD_CWORD 1
766 #define CNL_CNL_CNL_CNL 2
767 #define CWORD_CCTL_CCTL_CWORD 3
768 #define CDQUOTE_CENDQUOTE_CWORD_CDQUOTE 4
769 #define CVAR_CVAR_CWORD_CVAR 5
770 #define CSQUOTE_CWORD_CENDQUOTE_CSQUOTE 6
771 #define CSPCL_CWORD_CWORD_CLP 7
772 #define CSPCL_CWORD_CWORD_CRP 8
773 #define CBACK_CBACK_CCTL_CBACK 9
774 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10
775 #define CENDVAR_CENDVAR_CWORD_CENDVAR 11
776 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12
777 #define CWORD_CWORD_CWORD_CWORD 13
778 #define CCTL_CCTL_CCTL_CCTL 14
780 static const char syntax_index_table[258] = {
781 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
782 /* 0 -130 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
783 /* 1 -129 PEOA */ CSPCL_CIGN_CIGN_CIGN,
784 /* 2 -128 0xff */ CWORD_CWORD_CWORD_CWORD,
785 /* 3 -127 */ CCTL_CCTL_CCTL_CCTL, /* CTLQUOTEMARK */
786 /* 4 -126 */ CCTL_CCTL_CCTL_CCTL,
787 /* 5 -125 */ CCTL_CCTL_CCTL_CCTL,
788 /* 6 -124 */ CCTL_CCTL_CCTL_CCTL,
789 /* 7 -123 */ CCTL_CCTL_CCTL_CCTL,
790 /* 8 -122 */ CCTL_CCTL_CCTL_CCTL,
791 /* 9 -121 */ CCTL_CCTL_CCTL_CCTL,
792 /* 10 -120 */ CCTL_CCTL_CCTL_CCTL, /* CTLESC */
793 /* 11 -119 */ CWORD_CWORD_CWORD_CWORD,
794 /* 12 -118 */ CWORD_CWORD_CWORD_CWORD,
795 /* 13 -117 */ CWORD_CWORD_CWORD_CWORD,
796 /* 14 -116 */ CWORD_CWORD_CWORD_CWORD,
797 /* 15 -115 */ CWORD_CWORD_CWORD_CWORD,
798 /* 16 -114 */ CWORD_CWORD_CWORD_CWORD,
799 /* 17 -113 */ CWORD_CWORD_CWORD_CWORD,
800 /* 18 -112 */ CWORD_CWORD_CWORD_CWORD,
801 /* 19 -111 */ CWORD_CWORD_CWORD_CWORD,
802 /* 20 -110 */ CWORD_CWORD_CWORD_CWORD,
803 /* 21 -109 */ CWORD_CWORD_CWORD_CWORD,
804 /* 22 -108 */ CWORD_CWORD_CWORD_CWORD,
805 /* 23 -107 */ CWORD_CWORD_CWORD_CWORD,
806 /* 24 -106 */ CWORD_CWORD_CWORD_CWORD,
807 /* 25 -105 */ CWORD_CWORD_CWORD_CWORD,
808 /* 26 -104 */ CWORD_CWORD_CWORD_CWORD,
809 /* 27 -103 */ CWORD_CWORD_CWORD_CWORD,
810 /* 28 -102 */ CWORD_CWORD_CWORD_CWORD,
811 /* 29 -101 */ CWORD_CWORD_CWORD_CWORD,
812 /* 30 -100 */ CWORD_CWORD_CWORD_CWORD,
813 /* 31 -99 */ CWORD_CWORD_CWORD_CWORD,
814 /* 32 -98 */ CWORD_CWORD_CWORD_CWORD,
815 /* 33 -97 */ CWORD_CWORD_CWORD_CWORD,
816 /* 34 -96 */ CWORD_CWORD_CWORD_CWORD,
817 /* 35 -95 */ CWORD_CWORD_CWORD_CWORD,
818 /* 36 -94 */ CWORD_CWORD_CWORD_CWORD,
819 /* 37 -93 */ CWORD_CWORD_CWORD_CWORD,
820 /* 38 -92 */ CWORD_CWORD_CWORD_CWORD,
821 /* 39 -91 */ CWORD_CWORD_CWORD_CWORD,
822 /* 40 -90 */ CWORD_CWORD_CWORD_CWORD,
823 /* 41 -89 */ CWORD_CWORD_CWORD_CWORD,
824 /* 42 -88 */ CWORD_CWORD_CWORD_CWORD,
825 /* 43 -87 */ CWORD_CWORD_CWORD_CWORD,
826 /* 44 -86 */ CWORD_CWORD_CWORD_CWORD,
827 /* 45 -85 */ CWORD_CWORD_CWORD_CWORD,
828 /* 46 -84 */ CWORD_CWORD_CWORD_CWORD,
829 /* 47 -83 */ CWORD_CWORD_CWORD_CWORD,
830 /* 48 -82 */ CWORD_CWORD_CWORD_CWORD,
831 /* 49 -81 */ CWORD_CWORD_CWORD_CWORD,
832 /* 50 -80 */ CWORD_CWORD_CWORD_CWORD,
833 /* 51 -79 */ CWORD_CWORD_CWORD_CWORD,
834 /* 52 -78 */ CWORD_CWORD_CWORD_CWORD,
835 /* 53 -77 */ CWORD_CWORD_CWORD_CWORD,
836 /* 54 -76 */ CWORD_CWORD_CWORD_CWORD,
837 /* 55 -75 */ CWORD_CWORD_CWORD_CWORD,
838 /* 56 -74 */ CWORD_CWORD_CWORD_CWORD,
839 /* 57 -73 */ CWORD_CWORD_CWORD_CWORD,
840 /* 58 -72 */ CWORD_CWORD_CWORD_CWORD,
841 /* 59 -71 */ CWORD_CWORD_CWORD_CWORD,
842 /* 60 -70 */ CWORD_CWORD_CWORD_CWORD,
843 /* 61 -69 */ CWORD_CWORD_CWORD_CWORD,
844 /* 62 -68 */ CWORD_CWORD_CWORD_CWORD,
845 /* 63 -67 */ CWORD_CWORD_CWORD_CWORD,
846 /* 64 -66 */ CWORD_CWORD_CWORD_CWORD,
847 /* 65 -65 */ CWORD_CWORD_CWORD_CWORD,
848 /* 66 -64 */ CWORD_CWORD_CWORD_CWORD,
849 /* 67 -63 */ CWORD_CWORD_CWORD_CWORD,
850 /* 68 -62 */ CWORD_CWORD_CWORD_CWORD,
851 /* 69 -61 */ CWORD_CWORD_CWORD_CWORD,
852 /* 70 -60 */ CWORD_CWORD_CWORD_CWORD,
853 /* 71 -59 */ CWORD_CWORD_CWORD_CWORD,
854 /* 72 -58 */ CWORD_CWORD_CWORD_CWORD,
855 /* 73 -57 */ CWORD_CWORD_CWORD_CWORD,
856 /* 74 -56 */ CWORD_CWORD_CWORD_CWORD,
857 /* 75 -55 */ CWORD_CWORD_CWORD_CWORD,
858 /* 76 -54 */ CWORD_CWORD_CWORD_CWORD,
859 /* 77 -53 */ CWORD_CWORD_CWORD_CWORD,
860 /* 78 -52 */ CWORD_CWORD_CWORD_CWORD,
861 /* 79 -51 */ CWORD_CWORD_CWORD_CWORD,
862 /* 80 -50 */ CWORD_CWORD_CWORD_CWORD,
863 /* 81 -49 */ CWORD_CWORD_CWORD_CWORD,
864 /* 82 -48 */ CWORD_CWORD_CWORD_CWORD,
865 /* 83 -47 */ CWORD_CWORD_CWORD_CWORD,
866 /* 84 -46 */ CWORD_CWORD_CWORD_CWORD,
867 /* 85 -45 */ CWORD_CWORD_CWORD_CWORD,
868 /* 86 -44 */ CWORD_CWORD_CWORD_CWORD,
869 /* 87 -43 */ CWORD_CWORD_CWORD_CWORD,
870 /* 88 -42 */ CWORD_CWORD_CWORD_CWORD,
871 /* 89 -41 */ CWORD_CWORD_CWORD_CWORD,
872 /* 90 -40 */ CWORD_CWORD_CWORD_CWORD,
873 /* 91 -39 */ CWORD_CWORD_CWORD_CWORD,
874 /* 92 -38 */ CWORD_CWORD_CWORD_CWORD,
875 /* 93 -37 */ CWORD_CWORD_CWORD_CWORD,
876 /* 94 -36 */ CWORD_CWORD_CWORD_CWORD,
877 /* 95 -35 */ CWORD_CWORD_CWORD_CWORD,
878 /* 96 -34 */ CWORD_CWORD_CWORD_CWORD,
879 /* 97 -33 */ CWORD_CWORD_CWORD_CWORD,
880 /* 98 -32 */ CWORD_CWORD_CWORD_CWORD,
881 /* 99 -31 */ CWORD_CWORD_CWORD_CWORD,
882 /* 100 -30 */ CWORD_CWORD_CWORD_CWORD,
883 /* 101 -29 */ CWORD_CWORD_CWORD_CWORD,
884 /* 102 -28 */ CWORD_CWORD_CWORD_CWORD,
885 /* 103 -27 */ CWORD_CWORD_CWORD_CWORD,
886 /* 104 -26 */ CWORD_CWORD_CWORD_CWORD,
887 /* 105 -25 */ CWORD_CWORD_CWORD_CWORD,
888 /* 106 -24 */ CWORD_CWORD_CWORD_CWORD,
889 /* 107 -23 */ CWORD_CWORD_CWORD_CWORD,
890 /* 108 -22 */ CWORD_CWORD_CWORD_CWORD,
891 /* 109 -21 */ CWORD_CWORD_CWORD_CWORD,
892 /* 110 -20 */ CWORD_CWORD_CWORD_CWORD,
893 /* 111 -19 */ CWORD_CWORD_CWORD_CWORD,
894 /* 112 -18 */ CWORD_CWORD_CWORD_CWORD,
895 /* 113 -17 */ CWORD_CWORD_CWORD_CWORD,
896 /* 114 -16 */ CWORD_CWORD_CWORD_CWORD,
897 /* 115 -15 */ CWORD_CWORD_CWORD_CWORD,
898 /* 116 -14 */ CWORD_CWORD_CWORD_CWORD,
899 /* 117 -13 */ CWORD_CWORD_CWORD_CWORD,
900 /* 118 -12 */ CWORD_CWORD_CWORD_CWORD,
901 /* 119 -11 */ CWORD_CWORD_CWORD_CWORD,
902 /* 120 -10 */ CWORD_CWORD_CWORD_CWORD,
903 /* 121 -9 */ CWORD_CWORD_CWORD_CWORD,
904 /* 122 -8 */ CWORD_CWORD_CWORD_CWORD,
905 /* 123 -7 */ CWORD_CWORD_CWORD_CWORD,
906 /* 124 -6 */ CWORD_CWORD_CWORD_CWORD,
907 /* 125 -5 */ CWORD_CWORD_CWORD_CWORD,
908 /* 126 -4 */ CWORD_CWORD_CWORD_CWORD,
909 /* 127 -3 */ CWORD_CWORD_CWORD_CWORD,
910 /* 128 -2 */ CWORD_CWORD_CWORD_CWORD,
911 /* 129 -1 */ CWORD_CWORD_CWORD_CWORD,
912 /* 130 0 */ CWORD_CWORD_CWORD_CWORD,
913 /* 131 1 */ CWORD_CWORD_CWORD_CWORD,
914 /* 132 2 */ CWORD_CWORD_CWORD_CWORD,
915 /* 133 3 */ CWORD_CWORD_CWORD_CWORD,
916 /* 134 4 */ CWORD_CWORD_CWORD_CWORD,
917 /* 135 5 */ CWORD_CWORD_CWORD_CWORD,
918 /* 136 6 */ CWORD_CWORD_CWORD_CWORD,
919 /* 137 7 */ CWORD_CWORD_CWORD_CWORD,
920 /* 138 8 */ CWORD_CWORD_CWORD_CWORD,
921 /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
922 /* 140 10 "\n" */ CNL_CNL_CNL_CNL,
923 /* 141 11 */ CWORD_CWORD_CWORD_CWORD,
924 /* 142 12 */ CWORD_CWORD_CWORD_CWORD,
925 /* 143 13 */ CWORD_CWORD_CWORD_CWORD,
926 /* 144 14 */ CWORD_CWORD_CWORD_CWORD,
927 /* 145 15 */ CWORD_CWORD_CWORD_CWORD,
928 /* 146 16 */ CWORD_CWORD_CWORD_CWORD,
929 /* 147 17 */ CWORD_CWORD_CWORD_CWORD,
930 /* 148 18 */ CWORD_CWORD_CWORD_CWORD,
931 /* 149 19 */ CWORD_CWORD_CWORD_CWORD,
932 /* 150 20 */ CWORD_CWORD_CWORD_CWORD,
933 /* 151 21 */ CWORD_CWORD_CWORD_CWORD,
934 /* 152 22 */ CWORD_CWORD_CWORD_CWORD,
935 /* 153 23 */ CWORD_CWORD_CWORD_CWORD,
936 /* 154 24 */ CWORD_CWORD_CWORD_CWORD,
937 /* 155 25 */ CWORD_CWORD_CWORD_CWORD,
938 /* 156 26 */ CWORD_CWORD_CWORD_CWORD,
939 /* 157 27 */ CWORD_CWORD_CWORD_CWORD,
940 /* 158 28 */ CWORD_CWORD_CWORD_CWORD,
941 /* 159 29 */ CWORD_CWORD_CWORD_CWORD,
942 /* 160 30 */ CWORD_CWORD_CWORD_CWORD,
943 /* 161 31 */ CWORD_CWORD_CWORD_CWORD,
944 /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD,
945 /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD,
946 /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CDQUOTE,
947 /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD,
948 /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR,
949 /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD,
950 /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
951 /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CSQUOTE,
952 /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP,
953 /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP,
954 /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD,
955 /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD,
956 /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD,
957 /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD,
958 /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD,
959 /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD,
960 /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD,
961 /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD,
962 /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD,
963 /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD,
964 /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD,
965 /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD,
966 /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD,
967 /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD,
968 /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD,
969 /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD,
970 /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD,
971 /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
972 /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
973 /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD,
974 /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
975 /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD,
976 /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD,
977 /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD,
978 /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD,
979 /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD,
980 /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD,
981 /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD,
982 /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD,
983 /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD,
984 /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD,
985 /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD,
986 /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD,
987 /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD,
988 /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD,
989 /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD,
990 /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD,
991 /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD,
992 /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD,
993 /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
994 /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD,
995 /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD,
996 /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD,
997 /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD,
998 /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD,
999 /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD,
1000 /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD,
1001 /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
1002 /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
1003 /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD,
1004 /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK,
1005 /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD,
1006 /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD,
1007 /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD,
1008 /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
1009 /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD,
1010 /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD,
1011 /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD,
1012 /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD,
1013 /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD,
1014 /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD,
1015 /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD,
1016 /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD,
1017 /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD,
1018 /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD,
1019 /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD,
1020 /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD,
1021 /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD,
1022 /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD,
1023 /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD,
1024 /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD,
1025 /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD,
1026 /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD,
1027 /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD,
1028 /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD,
1029 /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD,
1030 /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD,
1031 /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD,
1032 /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD,
1033 /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD,
1034 /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD,
1035 /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD,
1036 /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
1037 /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
1038 /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD,
1039 /* 257 127 */ CWORD_CWORD_CWORD_CWORD,
1042 #endif /* USE_SIT_FUNCTION */
1045 /* first char is indicating which tokens mark the end of a list */
1046 static const char *const tokname_array[] = {
1061 #define KWDOFFSET 14
1062 /* the following are keywords */
1081 static const char *tokname(int tok)
1083 static char buf[16];
1087 sprintf(buf+(tok>=TSEMI), "%s%c",
1088 tokname_array[tok]+1, (tok>=TSEMI ? '"' : 0));
1092 static int plinno = 1; /* input line number */
1094 static int parselleft; /* copy of parsefile->lleft */
1096 static struct parsefile basepf; /* top level input file */
1097 static char basebuf[BUFSIZ]; /* buffer for top level input file */
1098 static struct parsefile *parsefile = &basepf; /* current input file */
1101 * NEOF is returned by parsecmd when it encounters an end of file. It
1102 * must be distinct from NULL, so we use the address of a variable that
1103 * happens to be handy.
1106 static int tokpushback; /* last token pushed back */
1107 #define NEOF ((union node *)&tokpushback)
1108 static int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */
1111 static void error (const char *, ...) __attribute__((__noreturn__));
1112 static void exerror (int, const char *, ...) __attribute__((__noreturn__));
1113 static void shellexec (char **, char **, const char *, int)
1114 __attribute__((noreturn));
1115 static void exitshell (int) __attribute__((noreturn));
1117 static int goodname(const char *);
1118 static void ignoresig (int);
1119 static void onsig (int);
1120 static void dotrap (void);
1121 static int decode_signal (const char *, int);
1123 static void shprocvar(void);
1124 static void deletefuncs(void);
1125 static void setparam (char **);
1126 static void freeparam (volatile struct shparam *);
1128 /* reasons for skipping commands (see comment on breakcmd routine) */
1134 /* values of cmdtype */
1135 #define CMDUNKNOWN -1 /* no entry in table for command */
1136 #define CMDNORMAL 0 /* command is an executable program */
1137 #define CMDBUILTIN 1 /* command is a shell builtin */
1138 #define CMDFUNCTION 2 /* command is a shell function */
1140 #define DO_ERR 1 /* find_command prints errors */
1141 #define DO_ABS 2 /* find_command checks absolute paths */
1142 #define DO_NOFUN 4 /* find_command ignores functions */
1143 #define DO_BRUTE 8 /* find_command ignores hash table */
1150 #define VEXPORT 0x01 /* variable is exported */
1151 #define VREADONLY 0x02 /* variable cannot be modified */
1152 #define VSTRFIXED 0x04 /* variable struct is staticly allocated */
1153 #define VTEXTFIXED 0x08 /* text is staticly allocated */
1154 #define VSTACK 0x10 /* text is allocated on the stack */
1155 #define VUNSET 0x20 /* the variable is not set */
1156 #define VNOFUNC 0x40 /* don't call the callback function */
1160 struct var *next; /* next entry in hash list */
1161 int flags; /* flags are defined above */
1162 char *text; /* name=value */
1163 void (*func) (const char *);
1164 /* function to be called when */
1165 /* the variable gets set/unset */
1169 struct localvar *next; /* next local variable in list */
1170 struct var *vp; /* the variable that was made local */
1171 int flags; /* saved flags */
1172 char *text; /* saved text */
1176 #if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
1177 #define rmescapes(p) _rmescapes((p), 0)
1178 static char *_rmescapes (char *, int);
1180 static void rmescapes (char *);
1183 static int casematch (union node *, const char *);
1184 static void clearredir(void);
1185 static void popstring(void);
1186 static void readcmdfile (const char *);
1188 static int number (const char *);
1189 static int is_number (const char *, int *num);
1190 static char *single_quote (const char *);
1191 static int nextopt (const char *);
1193 static void redirect (union node *, int);
1194 static void popredir (void);
1195 static int dup_as_newfd (int, int);
1197 static void changepath(const char *newval);
1198 static void getoptsreset(const char *value);
1201 static int parsenleft; /* copy of parsefile->nleft */
1202 static char *parsenextc; /* copy of parsefile->nextc */
1203 static int rootpid; /* pid of main shell */
1204 static int rootshell; /* true if we aren't a child of the main shell */
1206 static const char spcstr[] = " ";
1207 static const char snlfmt[] = "%s\n";
1209 static int sstrnleft;
1210 static int herefd = -1;
1212 static struct localvar *localvars;
1214 static struct var vifs;
1215 static struct var vmail;
1216 static struct var vmpath;
1217 static struct var vpath;
1218 static struct var vps1;
1219 static struct var vps2;
1220 static struct var voptind;
1221 #ifdef BB_LOCALE_SUPPORT
1222 static struct var vlc_all;
1223 static struct var vlc_ctype;
1230 void (*func) (const char *);
1233 static const char defpathvar[] =
1234 "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
1235 #define defpath (defpathvar + 5)
1238 static const char defifsvar[] = "IFS= \t\n";
1239 #define defifs (defifsvar + 4)
1241 static const char defifs[] = " \t\n";
1244 static const struct varinit varinit[] = {
1246 { &vifs, VSTRFIXED|VTEXTFIXED, defifsvar,
1248 { &vifs, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS=",
1251 { &vmail, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL=",
1253 { &vmpath, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH=",
1255 { &vpath, VSTRFIXED|VTEXTFIXED, defpathvar,
1258 * vps1 depends on uid
1260 { &vps2, VSTRFIXED|VTEXTFIXED, "PS2=> ",
1262 { &voptind, VSTRFIXED|VTEXTFIXED, "OPTIND=1",
1264 #ifdef BB_LOCALE_SUPPORT
1265 { &vlc_all, VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL=",
1267 { &vlc_ctype, VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE=",
1276 static struct var *vartab[VTABSIZE];
1279 * The following macros access the values of the above variables.
1280 * They have to skip over the name. They return the null string
1281 * for unset variables.
1284 #define ifsval() (vifs.text + 4)
1285 #define ifsset() ((vifs.flags & VUNSET) == 0)
1286 #define mailval() (vmail.text + 5)
1287 #define mpathval() (vmpath.text + 9)
1288 #define pathval() (vpath.text + 5)
1289 #define ps1val() (vps1.text + 4)
1290 #define ps2val() (vps2.text + 4)
1291 #define optindval() (voptind.text + 7)
1293 #define mpathset() ((vmpath.flags & VUNSET) == 0)
1295 static void initvar (void);
1296 static void setvar (const char *, const char *, int);
1297 static void setvareq (char *, int);
1298 static void listsetvar (struct strlist *);
1299 static const char *lookupvar (const char *);
1300 static const char *bltinlookup (const char *);
1301 static char **environment (void);
1302 static int showvarscmd (int, char **);
1303 static void mklocal (char *);
1304 static void poplocalvars (void);
1305 static int unsetvar (const char *);
1306 static int varequal (const char *, const char *);
1309 static char *arg0; /* value of $0 */
1310 static struct shparam shellparam; /* current positional parameters */
1311 static char **argptr; /* argument list for builtin commands */
1312 static char *optionarg; /* set by nextopt (like getopt) */
1313 static char *optptr; /* used by nextopt */
1314 static char *minusc; /* argument to -c option */
1319 #define ALIASINUSE 1
1331 static struct alias *atab[ATABSIZE];
1333 static void setalias (char *, char *);
1334 static struct alias **hashalias (const char *);
1335 static struct alias *freealias (struct alias *);
1336 static struct alias **__lookupalias (const char *);
1342 struct alias *ap, **app;
1344 app = __lookupalias(name);
1348 if (!(ap->flag & ALIASINUSE)) {
1351 ap->val = savestr(val);
1352 ap->flag &= ~ALIASDEAD;
1355 ap = ckmalloc(sizeof (struct alias));
1356 ap->name = savestr(name);
1357 ap->val = savestr(val);
1370 app = __lookupalias(name);
1374 *app = freealias(*app);
1385 struct alias *ap, **app;
1389 for (i = 0; i < ATABSIZE; i++) {
1391 for (ap = *app; ap; ap = *app) {
1392 *app = freealias(*app);
1401 static struct alias *
1402 lookupalias(const char *name, int check)
1404 struct alias *ap = *__lookupalias(name);
1406 if (check && ap && (ap->flag & ALIASINUSE))
1412 printalias(const struct alias *ap) {
1415 p = single_quote(ap->val);
1416 printf("alias %s=%s\n", ap->name, p);
1422 * TODO - sort output
1425 aliascmd(int argc, char **argv)
1434 for (i = 0; i < ATABSIZE; i++)
1435 for (ap = atab[i]; ap; ap = ap->next) {
1440 while ((n = *++argv) != NULL) {
1441 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
1442 if ((ap = *__lookupalias(n)) == NULL) {
1443 out2fmt("%s: %s not found\n", "alias", n);
1458 unaliascmd(int argc, char **argv)
1462 while ((i = nextopt("a")) != '\0') {
1468 for (i = 0; *argptr; argptr++) {
1469 if (unalias(*argptr)) {
1470 out2fmt("%s: %s not found\n", "unalias", *argptr);
1478 static struct alias **
1482 unsigned int hashval;
1487 return &atab[hashval % ATABSIZE];
1490 static struct alias *
1491 freealias(struct alias *ap) {
1494 if (ap->flag & ALIASINUSE) {
1495 ap->flag |= ALIASDEAD;
1507 static struct alias **
1508 __lookupalias(const char *name) {
1509 struct alias **app = hashalias(name);
1511 for (; *app; app = &(*app)->next) {
1512 if (equal(name, (*app)->name)) {
1521 #ifdef ASH_MATH_SUPPORT
1522 /* The generated file arith.c has been replaced with a custom hand
1523 * written implementation written by Aaron Lehmann <aaronl@vitelus.com>.
1524 * This is now part of libbb, so that it can be used by all the shells
1526 static void expari (int);
1529 static char *trap[NSIG]; /* trap handler commands */
1530 static char sigmode[NSIG - 1]; /* current value of signal */
1531 static char gotsig[NSIG - 1]; /* indicates specified signal received */
1532 static int pendingsigs; /* indicates some signal received */
1535 * This file was generated by the mkbuiltins program.
1539 static int bgcmd (int, char **);
1540 static int fgcmd (int, char **);
1541 static int killcmd (int, char **);
1543 static int bltincmd (int, char **);
1544 static int cdcmd (int, char **);
1545 static int breakcmd (int, char **);
1547 static int commandcmd (int, char **);
1549 static int dotcmd (int, char **);
1550 static int evalcmd (int, char **);
1551 static int execcmd (int, char **);
1552 static int exitcmd (int, char **);
1553 static int exportcmd (int, char **);
1554 static int histcmd (int, char **);
1555 static int hashcmd (int, char **);
1556 static int helpcmd (int, char **);
1557 static int jobscmd (int, char **);
1558 static int localcmd (int, char **);
1560 static int pwdcmd (int, char **);
1562 static int readcmd (int, char **);
1563 static int returncmd (int, char **);
1564 static int setcmd (int, char **);
1565 static int setvarcmd (int, char **);
1566 static int shiftcmd (int, char **);
1567 static int trapcmd (int, char **);
1568 static int umaskcmd (int, char **);
1570 static int aliascmd (int, char **);
1571 static int unaliascmd (int, char **);
1573 static int unsetcmd (int, char **);
1574 static int waitcmd (int, char **);
1575 static int ulimitcmd (int, char **);
1576 static int timescmd (int, char **);
1577 #ifdef ASH_MATH_SUPPORT
1578 static int letcmd (int, char **);
1580 static int typecmd (int, char **);
1582 static int getoptscmd (int, char **);
1585 #ifndef BB_TRUE_FALSE
1586 static int true_main (int, char **);
1587 static int false_main (int, char **);
1590 static void setpwd (const char *, int);
1593 #define BUILTIN_NOSPEC "0"
1594 #define BUILTIN_SPECIAL "1"
1595 #define BUILTIN_REGULAR "2"
1596 #define BUILTIN_ASSIGN "4"
1597 #define BUILTIN_SPEC_ASSG "5"
1598 #define BUILTIN_REG_ASSG "6"
1600 #define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1601 #define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
1602 #define IS_BUILTIN_ASSIGN(builtincmd) ((builtincmd)->name[0] & 4)
1606 int (*const builtinfunc) (int, char **);
1611 /* It is CRUCIAL that this listing be kept in ascii order, otherwise
1612 * the binary search in find_builtin() will stop working. If you value
1613 * your kneecaps, you'll be sure to *make sure* that any changes made
1614 * to this array result in the listing remaining in ascii order. You
1617 static const struct builtincmd builtincmds[] = {
1618 { BUILTIN_SPECIAL ".", dotcmd }, /* first, see declare DOTCMD */
1619 { BUILTIN_SPECIAL ":", true_main },
1621 { BUILTIN_REG_ASSG "alias", aliascmd },
1624 { BUILTIN_REGULAR "bg", bgcmd },
1626 { BUILTIN_SPECIAL "break", breakcmd },
1627 { BUILTIN_SPECIAL "builtin", bltincmd },
1628 { BUILTIN_REGULAR "cd", cdcmd },
1629 { BUILTIN_NOSPEC "chdir", cdcmd },
1631 { BUILTIN_REGULAR "command", commandcmd },
1633 { BUILTIN_SPECIAL "continue", breakcmd },
1634 { BUILTIN_SPECIAL "eval", evalcmd },
1635 { BUILTIN_SPECIAL "exec", execcmd },
1636 { BUILTIN_SPECIAL "exit", exitcmd },
1637 { BUILTIN_SPEC_ASSG "export", exportcmd },
1638 { BUILTIN_REGULAR "false", false_main },
1639 { BUILTIN_REGULAR "fc", histcmd },
1641 { BUILTIN_REGULAR "fg", fgcmd },
1644 { BUILTIN_REGULAR "getopts", getoptscmd },
1646 { BUILTIN_NOSPEC "hash", hashcmd },
1647 { BUILTIN_NOSPEC "help", helpcmd },
1648 { BUILTIN_REGULAR "jobs", jobscmd },
1650 { BUILTIN_REGULAR "kill", killcmd },
1652 #ifdef ASH_MATH_SUPPORT
1653 { BUILTIN_REGULAR "let", letcmd },
1655 { BUILTIN_ASSIGN "local", localcmd },
1657 { BUILTIN_NOSPEC "pwd", pwdcmd },
1659 { BUILTIN_REGULAR "read", readcmd },
1660 { BUILTIN_SPEC_ASSG "readonly", exportcmd },
1661 { BUILTIN_SPECIAL "return", returncmd },
1662 { BUILTIN_SPECIAL "set", setcmd },
1663 { BUILTIN_NOSPEC "setvar", setvarcmd },
1664 { BUILTIN_SPECIAL "shift", shiftcmd },
1665 { BUILTIN_SPECIAL "times", timescmd },
1666 { BUILTIN_SPECIAL "trap", trapcmd },
1667 { BUILTIN_REGULAR "true", true_main },
1668 { BUILTIN_NOSPEC "type", typecmd },
1669 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
1670 { BUILTIN_REGULAR "umask", umaskcmd },
1672 { BUILTIN_REGULAR "unalias", unaliascmd },
1674 { BUILTIN_SPECIAL "unset", unsetcmd },
1675 { BUILTIN_REGULAR "wait", waitcmd },
1677 #define NUMBUILTINS (sizeof (builtincmds) / sizeof (struct builtincmd) )
1679 #define DOTCMD &builtincmds[0]
1680 static struct builtincmd *BLTINCMD;
1681 static struct builtincmd *EXECCMD;
1682 static struct builtincmd *EVALCMD;
1685 #define JOBSTOPPED 1 /* all procs are stopped */
1686 #define JOBDONE 2 /* all procs are completed */
1689 * A job structure contains information about a job. A job is either a
1690 * single process or a set of processes contained in a pipeline. In the
1691 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1696 pid_t pid; /* process id */
1697 int status; /* status flags (defined above) */
1698 char *cmd; /* text of command being run */
1702 static int job_warning; /* user was warned about stopped jobs */
1705 static void setjobctl(int enable);
1707 #define setjobctl(on) /* do nothing */
1712 struct procstat ps0; /* status of process */
1713 struct procstat *ps; /* status or processes when more than one */
1714 short nprocs; /* number of processes */
1715 short pgrp; /* process group of this job */
1716 char state; /* true if job is finished */
1717 char used; /* true if this entry is in used */
1718 char changed; /* true if status has changed */
1720 char jobctl; /* job running under job control */
1724 static struct job *jobtab; /* array of jobs */
1725 static int njobs; /* size of array */
1726 static int backgndpid = -1; /* pid of last background process */
1728 static int initialpgrp; /* pgrp of shell on invocation */
1729 static int curjob; /* current job */
1732 static int intreceived;
1734 static struct job *makejob (const union node *, int);
1735 static int forkshell (struct job *, const union node *, int);
1736 static int waitforjob (struct job *);
1738 static int docd (char *, int);
1739 static char *getcomponent (void);
1740 static void updatepwd (const char *);
1741 static void getpwd (void);
1743 static char *padvance (const char **, const char *);
1745 static char nullstr[1]; /* zero length string */
1746 static char *curdir = nullstr; /* current working directory */
1747 static char *cdcomppath;
1761 if ((dest = *argptr) == NULL && (dest = bltinlookup("HOME")) == NULL)
1762 error("HOME not set");
1765 if (dest[0] == '-' && dest[1] == '\0') {
1766 dest = bltinlookup("OLDPWD");
1767 if (!dest || !*dest) {
1776 if (*dest == '/' || (path = bltinlookup("CDPATH")) == NULL)
1778 while ((p = padvance(&path, dest)) != NULL) {
1779 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
1784 if (p[0] == '.' && p[1] == '/' && p[2] != '\0')
1786 print = strcmp(p, dest);
1788 if (docd(p, print) >= 0)
1793 error("can't cd to %s", dest);
1799 * Actually do the chdir. In an interactive shell, print the
1800 * directory name if "print" is nonzero.
1815 TRACE(("docd(\"%s\", %d) called\n", dest, print));
1818 * Check each component of the path. If we find a symlink or
1819 * something we can't stat, clear curdir to force a getcwd()
1820 * next time we get the value of the current directory.
1823 cdcomppath = sstrdup(dest);
1830 while ((q = getcomponent()) != NULL) {
1831 if (q[0] == '\0' || (q[0] == '.' && q[1] == '\0'))
1839 if (equal(component, ".."))
1842 if ((lstat(stackblock(), &statb) < 0)
1843 || (S_ISLNK(statb.st_mode))) {
1851 if (chdir(dest) < 0) {
1855 updatepwd(badstat ? NULL : dest);
1858 printf(snlfmt, curdir);
1864 * Get the next component of the path name pointed to by cdcomppath.
1865 * This routine overwrites the string pointed to by cdcomppath.
1873 if ((p = cdcomppath) == NULL)
1876 while (*p != '/' && *p != '\0')
1890 * Update curdir (the name of the current directory) in response to a
1891 * cd command. We also call hashcd to let the routines in exec.c know
1892 * that the current directory has changed.
1895 static void hashcd (void);
1898 updatepwd(const char *dir)
1904 hashcd(); /* update command hash table */
1907 * If our argument is NULL, we don't know the current directory
1908 * any more because we traversed a symbolic link or something
1909 * we couldn't stat().
1911 if (dir == NULL || curdir == nullstr) {
1916 cdcomppath = sstrdup(dir);
1925 while ((p = getcomponent()) != NULL) {
1926 if (equal(p, "..")) {
1927 while (new > stackblock() && (STUNPUTC(new), *new) != '/');
1928 } else if (*p != '\0' && ! equal(p, ".")) {
1934 if (new == stackblock())
1937 setpwd(stackblock(), 1);
1947 printf(snlfmt, curdir);
1953 * Find out what the current directory is. If we already know the current
1954 * directory, this routine returns immediately.
1959 curdir = xgetcwd(0);
1965 setpwd(const char *val, int setold)
1968 setvar("OLDPWD", curdir, VEXPORT);
1971 if (curdir != nullstr) {
1978 curdir = savestr(val);
1981 setvar("PWD", curdir, VEXPORT);
1985 * Errors and exceptions.
1989 * Code to handle exceptions in C.
1993 * We enclose jmp_buf in a structure so that we can declare pointers to
1994 * jump locations. The global variable handler contains the location to
1995 * jump to when an exception occurs, and the global variable exception
1996 * contains a code identifying the exeception. To implement nested
1997 * exception handlers, the user should save the value of handler on entry
1998 * to an inner scope, set handler to point to a jmploc structure for the
1999 * inner scope, and restore handler on exit from the scope.
2007 #define EXINT 0 /* SIGINT received */
2008 #define EXERROR 1 /* a generic error */
2009 #define EXSHELLPROC 2 /* execute a shell procedure */
2010 #define EXEXEC 3 /* command execution failed */
2012 static struct jmploc *handler;
2013 static int exception;
2015 static void exverror (int, const char *, va_list)
2016 __attribute__((__noreturn__));
2019 * Called to raise an exception. Since C doesn't include exceptions, we
2020 * just do a longjmp to the exception handler. The type of exception is
2021 * stored in the global variable "exception".
2024 static void exraise (int) __attribute__((__noreturn__));
2030 if (handler == NULL)
2035 longjmp(handler->loc, 1);
2040 * Called from trap.c when a SIGINT is received. (If the user specifies
2041 * that SIGINT is to be trapped or ignored using the trap builtin, then
2042 * this routine is not called.) Suppressint is nonzero when interrupts
2043 * are held using the INTOFF macro. The call to _exit is necessary because
2044 * there is a short period after a fork before the signal handlers are
2045 * set to the appropriate value for the child. (The test for iflag is
2046 * just defensive programming.)
2058 sigemptyset(&mysigset);
2059 sigprocmask(SIG_SETMASK, &mysigset, NULL);
2060 if (rootshell && iflag)
2063 signal(SIGINT, SIG_DFL);
2070 static char *commandname; /* currently executing command */
2073 * Exverror is called to raise the error exception. If the first argument
2074 * is not NULL then error prints an error message using printf style
2075 * formatting. It then raises the error exception.
2078 exverror(int cond, const char *msg, va_list ap)
2085 TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid()));
2087 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
2091 out2fmt("%s: ", commandname);
2092 vfprintf(stderr, msg, ap);
2101 error(const char *msg, ...)
2105 exverror(EXERROR, msg, ap);
2112 exerror(int cond, const char *msg, ...)
2116 exverror(cond, msg, ap);
2124 * Table of error messages.
2128 short errcode; /* error number */
2129 char action; /* operation which encountered the error */
2133 * Types of operations (passed to the errmsg routine).
2136 #define E_OPEN 01 /* opening a file */
2137 #define E_CREAT 02 /* creating a file */
2138 #define E_EXEC 04 /* executing a program */
2140 #define ALL (E_OPEN|E_CREAT|E_EXEC)
2142 static const struct errname errormsg[] = {
2147 { ENOENT, E_CREAT },
2149 { ENOTDIR, E_OPEN },
2150 { ENOTDIR, E_CREAT },
2151 { ENOTDIR, E_EXEC },
2153 { EEXIST, E_CREAT },
2192 { ELIBACC, E_EXEC },
2196 #define ERRNAME_SIZE (sizeof(errormsg)/sizeof(struct errname))
2199 * Return a string describing an error. The returned string may be a
2200 * pointer to a static buffer that will be overwritten on the next call.
2201 * Action describes the operation that got the error.
2205 errmsg(int e, int action)
2207 struct errname const *ep;
2208 static char buf[12];
2210 for (ep = errormsg ; ep < errormsg+ERRNAME_SIZE; ep++) {
2211 if (ep->errcode == e && (ep->action & action) != 0)
2215 snprintf(buf, sizeof buf, "error %d", e);
2220 #ifdef ASH_OPTIMIZE_FOR_SIZE
2223 if (--suppressint == 0 && intpending) {
2227 static void forceinton (void) {
2234 /* flags in argument to evaltree */
2235 #define EV_EXIT 01 /* exit after evaluating tree */
2236 #define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2237 #define EV_BACKCMD 04 /* command executing within back quotes */
2239 static int evalskip; /* set if we are skipping commands */
2240 static int skipcount; /* number of levels to skip */
2241 static int loopnest; /* current loop nesting level */
2242 static int funcnest; /* depth of function calls */
2245 static struct strlist *cmdenviron; /* environment for builtin command */
2246 static int exitstatus; /* exit status of last command */
2247 static int oexitstatus; /* saved exit status */
2249 static void evalsubshell (const union node *, int);
2250 static void expredir (union node *);
2251 static void prehash (union node *);
2252 static void eprintlist (struct strlist *);
2254 static union node *parsecmd(int);
2256 * Called to reset things after an exception.
2260 * The eval commmand.
2262 static void evalstring (char *, int);
2276 STARTSTACKSTR(concat);
2280 STPUTC(*p++, concat);
2281 if ((p = *ap++) == NULL)
2283 STPUTC(' ', concat);
2285 STPUTC('\0', concat);
2286 p = grabstackstr(concat);
2288 evalstring(p, EV_TESTED);
2294 * Execute a command or commands contained in a string.
2297 static void evaltree (union node *, int);
2298 static void setinputstring (char *);
2299 static void popfile (void);
2300 static void setstackmark(struct stackmark *mark);
2301 static void popstackmark(struct stackmark *mark);
2305 evalstring(char *s, int flag)
2308 struct stackmark smark;
2310 setstackmark(&smark);
2312 while ((n = parsecmd(0)) != NEOF) {
2314 popstackmark(&smark);
2317 popstackmark(&smark);
2320 static struct builtincmd *find_builtin (const char *);
2321 static void expandarg (union node *, struct arglist *, int);
2322 static void calcsize (const union node *);
2323 static union node *copynode (const union node *);
2326 * Make a copy of a parse tree.
2329 static int funcblocksize; /* size of structures in function */
2330 static int funcstringsize; /* size of strings in node */
2331 static pointer funcblock; /* block to allocate function from */
2332 static char *funcstring; /* block to allocate strings from */
2335 static inline union node *
2336 copyfunc(union node *n)
2343 funcblock = ckmalloc(funcblocksize + funcstringsize);
2344 funcstring = (char *) funcblock + funcblocksize;
2349 * Free a parse tree.
2353 freefunc(union node *n)
2361 * Add a new command entry, replacing any existing command entry for
2366 addcmdentry(char *name, struct cmdentry *entry)
2368 struct tblentry *cmdp;
2371 cmdp = cmdlookup(name, 1);
2372 if (cmdp->cmdtype == CMDFUNCTION) {
2373 freefunc(cmdp->param.func);
2375 cmdp->cmdtype = entry->cmdtype;
2376 cmdp->param = entry->u;
2381 evalloop(const union node *n, int flags)
2388 evaltree(n->nbinary.ch1, EV_TESTED);
2390 skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
2394 if (evalskip == SKIPBREAK && --skipcount <= 0)
2398 if (n->type == NWHILE) {
2399 if (exitstatus != 0)
2402 if (exitstatus == 0)
2405 evaltree(n->nbinary.ch2, flags & EV_TESTED);
2406 status = exitstatus;
2411 exitstatus = status;
2415 evalfor(const union node *n, int flags)
2417 struct arglist arglist;
2420 struct stackmark smark;
2422 setstackmark(&smark);
2423 arglist.lastp = &arglist.list;
2424 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
2425 oexitstatus = exitstatus;
2426 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
2430 *arglist.lastp = NULL;
2434 for (sp = arglist.list ; sp ; sp = sp->next) {
2435 setvar(n->nfor.var, sp->text, 0);
2436 evaltree(n->nfor.body, flags & EV_TESTED);
2438 if (evalskip == SKIPCONT && --skipcount <= 0) {
2442 if (evalskip == SKIPBREAK && --skipcount <= 0)
2449 popstackmark(&smark);
2453 evalcase(const union node *n, int flags)
2457 struct arglist arglist;
2458 struct stackmark smark;
2460 setstackmark(&smark);
2461 arglist.lastp = &arglist.list;
2462 oexitstatus = exitstatus;
2463 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
2464 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2465 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
2466 if (casematch(patp, arglist.list->text)) {
2467 if (evalskip == 0) {
2468 evaltree(cp->nclist.body, flags);
2475 popstackmark(&smark);
2479 * Evaluate a pipeline. All the processes in the pipeline are children
2480 * of the process creating the pipeline. (This differs from some versions
2481 * of the shell, which make the last process in a pipeline the parent
2485 static inline void evalpipe(union node *n)
2488 struct nodelist *lp;
2493 TRACE(("evalpipe(0x%lx) called\n", (long)n));
2495 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
2498 jp = makejob(n, pipelen);
2500 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
2504 if (pipe(pip) < 0) {
2506 error("Pipe call failed");
2509 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
2513 dup_as_newfd(prevfd, 0);
2525 dup_as_newfd(pip[1], 1);
2529 evaltree(lp->n, EV_EXIT);
2537 if (n->npipe.backgnd == 0) {
2539 exitstatus = waitforjob(jp);
2540 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
2545 static void find_command (const char *, struct cmdentry *, int, const char *);
2548 isassignment(const char *word) {
2549 if (!is_name(*word)) {
2554 } while (is_in_name(*word));
2555 return *word == '=';
2560 evalcommand(union node *cmd, int flags)
2562 struct stackmark smark;
2564 struct arglist arglist;
2565 struct arglist varlist;
2571 struct cmdentry cmdentry;
2573 char *volatile savecmdname;
2574 volatile struct shparam saveparam;
2575 struct localvar *volatile savelocalvars;
2579 const struct builtincmd *firstbltin;
2580 struct jmploc *volatile savehandler;
2581 struct jmploc jmploc;
2583 /* Avoid longjmp clobbering */
2590 /* First expand the arguments. */
2591 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
2592 setstackmark(&smark);
2593 arglist.lastp = &arglist.list;
2594 varlist.lastp = &varlist.list;
2596 oexitstatus = exitstatus;
2599 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
2600 expandarg(argp, &varlist, EXP_VARTILDE);
2603 argp = cmd->ncmd.args; argp && !arglist.list;
2604 argp = argp->narg.next
2606 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
2609 struct builtincmd *bcmd;
2611 bcmd = find_builtin(arglist.list->text);
2612 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
2613 for (; argp; argp = argp->narg.next) {
2614 if (pseudovarflag && isassignment(argp->narg.text)) {
2615 expandarg(argp, &arglist, EXP_VARTILDE);
2618 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
2621 *arglist.lastp = NULL;
2622 *varlist.lastp = NULL;
2623 expredir(cmd->ncmd.redirect);
2625 for (sp = arglist.list ; sp ; sp = sp->next)
2627 argv = stalloc(sizeof (char *) * (argc + 1));
2629 for (sp = arglist.list ; sp ; sp = sp->next) {
2630 TRACE(("evalcommand arg: %s\n", sp->text));
2635 if (iflag && funcnest == 0 && argc > 0)
2639 /* Print the command if xflag is set. */
2642 eprintlist(varlist.list);
2643 eprintlist(arglist.list);
2647 /* Now locate the command. */
2649 cmdentry.cmdtype = CMDBUILTIN;
2650 firstbltin = cmdentry.u.cmd = BLTINCMD;
2652 const char *oldpath;
2653 int findflag = DO_ERR;
2657 * Modify the command lookup path, if a PATH= assignment
2660 for (sp = varlist.list ; sp ; sp = sp->next)
2661 if (varequal(sp->text, defpathvar)) {
2662 path = sp->text + 5;
2663 findflag |= DO_BRUTE;
2666 oldfindflag = findflag;
2669 find_command(argv[0], &cmdentry, findflag, path);
2670 if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */
2674 /* implement bltin and command here */
2675 if (cmdentry.cmdtype != CMDBUILTIN) {
2679 firstbltin = cmdentry.u.cmd;
2681 if (cmdentry.u.cmd == BLTINCMD) {
2683 struct builtincmd *bcmd;
2688 if (!(bcmd = find_builtin(*argv))) {
2689 out2fmt("%s: not found\n", *argv);
2693 cmdentry.u.cmd = bcmd;
2694 if (bcmd != BLTINCMD)
2698 if (cmdentry.u.cmd == find_builtin("command")) {
2703 if (*argv[0] == '-') {
2704 if (!equal(argv[0], "-p")) {
2714 findflag |= DO_BRUTE;
2717 findflag = oldfindflag;
2719 findflag |= DO_NOFUN;
2727 /* Fork off a child process if necessary. */
2728 if (cmd->ncmd.backgnd
2729 || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0)
2731 jp = makejob(cmd, 1);
2732 mode = cmd->ncmd.backgnd;
2733 if (forkshell(jp, cmd, mode) != 0)
2734 goto parent; /* at end of routine */
2738 /* This is the child process if a fork occurred. */
2739 /* Execute the command. */
2740 if (cmdentry.cmdtype == CMDFUNCTION) {
2742 trputs("Shell function: "); trargs(argv);
2744 exitstatus = oexitstatus;
2745 redirect(cmd->ncmd.redirect, REDIR_PUSH);
2746 saveparam = shellparam;
2747 shellparam.malloc = 0;
2748 shellparam.nparam = argc - 1;
2749 shellparam.p = argv + 1;
2751 savelocalvars = localvars;
2754 if (setjmp(jmploc.loc)) {
2755 if (exception == EXSHELLPROC) {
2756 freeparam((volatile struct shparam *)
2759 saveparam.optind = shellparam.optind;
2760 saveparam.optoff = shellparam.optoff;
2761 freeparam(&shellparam);
2762 shellparam = saveparam;
2765 localvars = savelocalvars;
2766 handler = savehandler;
2767 longjmp(handler->loc, 1);
2769 savehandler = handler;
2771 for (sp = varlist.list ; sp ; sp = sp->next)
2774 evaltree(cmdentry.u.func, flags & EV_TESTED);
2778 localvars = savelocalvars;
2779 saveparam.optind = shellparam.optind;
2780 saveparam.optoff = shellparam.optoff;
2781 freeparam(&shellparam);
2782 shellparam = saveparam;
2783 handler = savehandler;
2786 if (evalskip == SKIPFUNC) {
2790 if (flags & EV_EXIT)
2791 exitshell(exitstatus);
2792 } else if (cmdentry.cmdtype == CMDBUILTIN) {
2794 trputs("builtin command: "); trargs(argv);
2796 mode = (cmdentry.u.cmd == EXECCMD)? 0 : REDIR_PUSH;
2797 redirect(cmd->ncmd.redirect, mode);
2798 savecmdname = commandname;
2799 if (IS_BUILTIN_SPECIAL(firstbltin)) {
2800 listsetvar(varlist.list);
2802 cmdenviron = varlist.list;
2805 if (setjmp(jmploc.loc)) {
2807 exitstatus = (e == EXINT)? SIGINT+128 : 2;
2810 savehandler = handler;
2812 commandname = argv[0];
2814 optptr = NULL; /* initialize nextopt */
2815 exitstatus = (*cmdentry.u.cmd->builtinfunc)(argc, argv);
2819 if (e != EXSHELLPROC) {
2820 commandname = savecmdname;
2821 if (flags & EV_EXIT)
2822 exitshell(exitstatus);
2824 handler = savehandler;
2826 if ((e != EXERROR && e != EXEXEC)
2827 || cmdentry.u.cmd == BLTINCMD
2828 || cmdentry.u.cmd == DOTCMD
2829 || cmdentry.u.cmd == EVALCMD
2830 || cmdentry.u.cmd == EXECCMD)
2834 if (cmdentry.u.cmd != EXECCMD)
2838 trputs("normal command: "); trargs(argv);
2840 redirect(cmd->ncmd.redirect, 0);
2842 for (sp = varlist.list ; sp ; sp = sp->next)
2843 setvareq(sp->text, VEXPORT|VSTACK);
2844 envp = environment();
2845 shellexec(argv, envp, path, cmdentry.u.index);
2849 parent: /* parent process gets here (if we forked) */
2850 if (mode == 0) { /* argument to fork */
2852 exitstatus = waitforjob(jp);
2858 setvar("_", lastarg, 0);
2859 popstackmark(&smark);
2863 * Evaluate a parse tree. The value is left in the global variable
2873 TRACE(("evaltree(NULL) called\n"));
2876 TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type));
2879 evaltree(n->nbinary.ch1, flags & EV_TESTED);
2882 evaltree(n->nbinary.ch2, flags);
2885 evaltree(n->nbinary.ch1, EV_TESTED);
2886 if (evalskip || exitstatus != 0)
2888 evaltree(n->nbinary.ch2, flags);
2891 evaltree(n->nbinary.ch1, EV_TESTED);
2892 if (evalskip || exitstatus == 0)
2894 evaltree(n->nbinary.ch2, flags);
2897 expredir(n->nredir.redirect);
2898 redirect(n->nredir.redirect, REDIR_PUSH);
2899 evaltree(n->nredir.n, flags);
2903 evalsubshell(n, flags);
2906 evalsubshell(n, flags);
2909 evaltree(n->nif.test, EV_TESTED);
2912 if (exitstatus == 0)
2913 evaltree(n->nif.ifpart, flags);
2914 else if (n->nif.elsepart)
2915 evaltree(n->nif.elsepart, flags);
2931 struct builtincmd *bcmd;
2932 struct cmdentry entry;
2934 (bcmd = find_builtin(n->narg.text)) &&
2935 IS_BUILTIN_SPECIAL(bcmd)
2937 out2fmt("%s is a special built-in\n", n->narg.text);
2941 entry.cmdtype = CMDFUNCTION;
2942 entry.u.func = copyfunc(n->narg.next);
2943 addcmdentry(n->narg.text, &entry);
2948 evaltree(n->nnot.com, EV_TESTED);
2949 exitstatus = !exitstatus;
2957 evalcommand(n, flags);
2962 printf("Node type = %d\n", n->type);
2971 (checkexit && eflag && exitstatus && !(flags & EV_TESTED))
2973 exitshell(exitstatus);
2977 * Kick off a subshell to evaluate a tree.
2981 evalsubshell(const union node *n, int flags)
2984 int backgnd = (n->type == NBACKGND);
2986 expredir(n->nredir.redirect);
2988 if (forkshell(jp, n, backgnd) == 0) {
2990 flags &=~ EV_TESTED;
2991 redirect(n->nredir.redirect, 0);
2992 evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */
2996 exitstatus = waitforjob(jp);
3002 * Compute the names of the files in a redirection list.
3005 static void fixredir(union node *n, const char *text, int err);
3008 expredir(union node *n)
3012 for (redir = n ; redir ; redir = redir->nfile.next) {
3014 fn.lastp = &fn.list;
3015 oexitstatus = exitstatus;
3016 switch (redir->type) {
3022 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
3023 redir->nfile.expfname = fn.list->text;
3027 if (redir->ndup.vname) {
3028 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
3029 fixredir(redir, fn.list->text, 1);
3038 * Execute a command inside back quotes. If it's a builtin command, we
3039 * want to save its output in a block obtained from malloc. Otherwise
3040 * we fork off a subprocess and get the output of the command via a pipe.
3041 * Should be called with interrupts off.
3045 evalbackcmd(union node *n, struct backcmd *result)
3049 struct stackmark smark; /* unnecessary */
3051 setstackmark(&smark);
3062 error("Pipe call failed");
3064 if (forkshell(jp, n, FORK_NOJOB) == 0) {
3069 dup_as_newfd(pip[1], 1);
3073 evaltree(n, EV_EXIT);
3076 result->fd = pip[0];
3079 popstackmark(&smark);
3080 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
3081 result->fd, result->buf, result->nleft, result->jp));
3086 * Execute a simple command.
3090 * Search for a command. This is called before we fork so that the
3091 * location of the command will be available in the parent as well as
3092 * the child. The check for "goodname" is an overly conservative
3093 * check that the name will not be subject to expansion.
3100 struct cmdentry entry;
3102 if (n->type == NCMD && n->ncmd.args)
3103 if (goodname(n->ncmd.args->narg.text))
3104 find_command(n->ncmd.args->narg.text, &entry, 0,
3110 * Builtin commands. Builtin commands whose functions are closely
3111 * tied to evaluation are implemented here.
3115 * No command given, or a bltin command with no arguments. Set the
3116 * specified variables.
3120 bltincmd(argc, argv)
3125 * Preserve exitstatus of a previous possible redirection
3133 * Handle break and continue commands. Break, continue, and return are
3134 * all handled by setting the evalskip flag. The evaluation routines
3135 * above all check this flag, and if it is set they start skipping
3136 * commands rather than executing them. The variable skipcount is
3137 * the number of loops to break/continue, or the number of function
3138 * levels to return. (The latter is always 1.) It should probably
3139 * be an error to break out of more loops than exist, but it isn't
3140 * in the standard shell so we don't make it one here.
3144 breakcmd(argc, argv)
3148 int n = argc > 1 ? number(argv[1]) : 1;
3153 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
3161 * The return command.
3165 returncmd(argc, argv)
3169 int ret = argc > 1 ? number(argv[1]) : oexitstatus;
3172 evalskip = SKIPFUNC;
3177 /* Do what ksh does; skip the rest of the file */
3178 evalskip = SKIPFILE;
3185 #ifndef BB_TRUE_FALSE
3187 false_main(argc, argv)
3196 true_main(argc, argv)
3205 * Controls whether the shell is interactive or not.
3208 static void setsignal(int signo);
3209 static void chkmail(int silent);
3213 setinteractive(int on)
3215 static int is_interactive;
3216 static int do_banner=0;
3218 if (on == is_interactive)
3224 is_interactive = on;
3225 if (do_banner==0 && is_interactive) {
3226 /* Looks like they want an interactive shell */
3227 printf( "\n\n" BB_BANNER " Built-in shell (ash)\n");
3228 printf( "Enter 'help' for a list of built-in commands.\n\n");
3236 setinteractive(iflag);
3249 iflag = 0; /* exit on error */
3252 for (sp = cmdenviron; sp ; sp = sp->next)
3253 setvareq(sp->text, VEXPORT|VSTACK);
3254 shellexec(argv + 1, environment(), pathval(), 0);
3260 eprintlist(struct strlist *sp)
3262 for (; sp; sp = sp->next) {
3263 out2fmt(" %s",sp->text);
3268 * Exec a program. Never returns. If you change this routine, you may
3269 * have to change the find_command routine as well.
3272 static const char *pathopt; /* set by padvance */
3275 shellexec(argv, envp, path, idx)
3276 char **argv, **envp;
3283 if (strchr(argv[0], '/') != NULL) {
3284 tryexec(argv[0], argv, envp);
3288 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3289 if (--idx < 0 && pathopt == NULL) {
3290 tryexec(cmdname, argv, envp);
3291 if (errno != ENOENT && errno != ENOTDIR)
3298 /* Map to POSIX errors */
3310 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3315 * Clear traps on a fork.
3321 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
3322 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
3327 setsignal(tp - trap);
3335 initshellproc(void) {
3361 /* from options.c: */
3365 for (i = 0; i < NOPTS; i++)
3381 for (sm = sigmode ; sm < sigmode + NSIG - 1; sm++) {
3393 static int preadbuffer(void);
3394 static void pushfile (void);
3397 * Read a character from the script, returning PEOF on end of file.
3398 * Nul characters in the input are silently discarded.
3401 #ifndef ASH_OPTIMIZE_FOR_SIZE
3402 #define pgetc_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
3406 return pgetc_macro();
3412 return --parsenleft >= 0? *parsenextc++ : preadbuffer();
3418 return pgetc_macro();
3424 * Undo the last call to pgetc. Only one character may be pushed back.
3425 * PEOF may be pushed back.
3428 static void pungetc(void)
3437 struct parsefile *pf = parsefile;
3446 parsefile = pf->prev;
3448 parsenleft = parsefile->nleft;
3449 parselleft = parsefile->lleft;
3450 parsenextc = parsefile->nextc;
3451 plinno = parsefile->linno;
3457 * Return to top level.
3462 while (parsefile != &basepf)
3467 * Close the file(s) that the shell is reading commands from. Called
3468 * after a fork is done.
3471 static void closescript(void)
3474 if (parsefile->fd > 0) {
3475 close(parsefile->fd);
3482 * Like setinputfile, but takes an open file descriptor. Call this with
3486 static void setinputfd(int fd, int push)
3488 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
3494 while (parsefile->strpush)
3498 if (parsefile->buf == NULL)
3499 parsefile->buf = ckmalloc(BUFSIZ);
3500 parselleft = parsenleft = 0;
3506 * Set the input to take input from a file. If push is set, push the
3507 * old input onto the stack first.
3511 setinputfile(const char *fname, int push)
3517 if ((fd = open(fname, O_RDONLY)) < 0)
3518 error("Can't open %s", fname);
3520 myfileno2 = dup_as_newfd(fd, 10);
3523 error("Out of file descriptors");
3526 setinputfd(fd, push);
3532 tryexec(char *cmd, char **argv, char **envp)
3536 #ifdef BB_FEATURE_SH_STANDALONE_SHELL
3540 #ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN
3541 name = get_last_path_component(name);
3544 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++)
3547 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++)
3549 run_applet_by_name(name, argc_l, argv);
3551 execve(cmd, argv, envp);
3556 setinputfile(cmd, 0);
3557 commandname = arg0 = savestr(argv[0]);
3559 exraise(EXSHELLPROC);
3564 static char *commandtext (const union node *);
3567 * Do a path search. The variable path (passed by reference) should be
3568 * set to the start of the path before the first call; padvance will update
3569 * this value as it proceeds. Successive calls to padvance will return
3570 * the possible path expansions in sequence. If an option (indicated by
3571 * a percent sign) appears in the path entry then the global variable
3572 * pathopt will be set to point to it; otherwise pathopt will be set to
3576 static const char *pathopt;
3578 static void growstackblock(void);
3582 padvance(const char **path, const char *name)
3592 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
3593 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
3594 while (stackblocksize() < len)
3598 memcpy(q, start, p - start);
3606 while (*p && *p != ':') p++;
3612 return stalloc(len);
3616 * Wrapper around strcmp for qsort/bsearch/...
3619 pstrcmp(const void *a, const void *b)
3621 return strcmp((const char *) a, (*(const char *const *) b) + 1);
3625 * Find a keyword is in a sorted array.
3628 static const char *const *
3629 findkwd(const char *s)
3631 return bsearch(s, tokname_array + KWDOFFSET,
3632 (sizeof(tokname_array)/sizeof(const char *)) - KWDOFFSET,
3633 sizeof(const char *), pstrcmp);
3637 /*** Command hashing code ***/
3645 struct tblentry **pp;
3646 struct tblentry *cmdp;
3649 struct cmdentry entry;
3652 const struct alias *ap;
3656 while ((c = nextopt("rvV")) != '\0') {
3660 } else if (c == 'v' || c == 'V') {
3664 if (*argptr == NULL) {
3665 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3666 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3667 if (cmdp->cmdtype != CMDBUILTIN) {
3668 printentry(cmdp, verbose);
3675 while ((name = *argptr++) != NULL) {
3676 if ((cmdp = cmdlookup(name, 0)) != NULL
3677 && (cmdp->cmdtype == CMDNORMAL
3678 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
3681 /* Then look at the aliases */
3682 if ((ap = lookupalias(name, 0)) != NULL) {
3684 printf("%s is an alias for %s\n", name, ap->val);
3690 /* First look at the keywords */
3691 if (findkwd(name)!=0) {
3693 printf("%s is a shell keyword\n", name);
3695 printf(snlfmt, name);
3699 find_command(name, &entry, DO_ERR, pathval());
3700 if (entry.cmdtype == CMDUNKNOWN) c = 1;
3702 cmdp = cmdlookup(name, 0);
3703 if (cmdp) printentry(cmdp, verbose=='v');
3711 printentry(cmdp, verbose)
3712 struct tblentry *cmdp;
3719 printf("%s%s", cmdp->cmdname, (verbose ? " is " : ""));
3720 if (cmdp->cmdtype == CMDNORMAL) {
3721 idx = cmdp->param.index;
3724 name = padvance(&path, cmdp->cmdname);
3726 } while (--idx >= 0);
3729 } else if (cmdp->cmdtype == CMDBUILTIN) {
3731 out1str("a shell builtin");
3732 } else if (cmdp->cmdtype == CMDFUNCTION) {
3735 out1str("a function\n");
3736 name = commandtext(cmdp->param.func);
3737 printf("%s() {\n %s\n}", cmdp->cmdname, name);
3743 error("internal error: cmdtype %d", cmdp->cmdtype);
3746 printf(snlfmt, cmdp->rehash ? "*" : nullstr);
3751 /*** List the available builtins ***/
3754 static int helpcmd(int argc, char** argv)
3758 printf("\nBuilt-in commands:\n-------------------\n");
3759 for (col=0, i=0; i < NUMBUILTINS; i++) {
3760 col += printf("%c%s", ((col == 0) ? '\t' : ' '),
3761 builtincmds[i].name+1);
3767 #ifdef BB_FEATURE_SH_STANDALONE_SHELL
3769 extern const struct BB_applet applets[];
3770 extern const size_t NUM_APPLETS;
3772 for (i=0; i < NUM_APPLETS; i++) {
3774 col += printf("%c%s", ((col == 0) ? '\t' : ' '),
3784 return EXIT_SUCCESS;
3788 * Resolve a command name. If you change this routine, you may have to
3789 * change the shellexec routine as well.
3792 static int prefix (const char *, const char *);
3795 find_command(const char *name, struct cmdentry *entry, int act, const char *path)
3797 struct tblentry *cmdp;
3807 struct builtincmd *bcmd;
3809 /* If name contains a slash, don't use the hash table */
3810 if (strchr(name, '/') != NULL) {
3812 while (stat(name, &statb) < 0) {
3813 if (errno != ENOENT && errno != ENOTDIR)
3815 entry->cmdtype = CMDUNKNOWN;
3816 entry->u.index = -1;
3819 entry->cmdtype = CMDNORMAL;
3820 entry->u.index = -1;
3823 entry->cmdtype = CMDNORMAL;
3829 if (act & DO_BRUTE) {
3830 firstchange = path_change(path, &bltin);
3836 /* If name is in the table, and not invalidated by cd, we're done */
3837 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0) {
3838 if (cmdp->cmdtype == CMDFUNCTION) {
3839 if (act & DO_NOFUN) {
3844 } else if (act & DO_BRUTE) {
3845 if ((cmdp->cmdtype == CMDNORMAL &&
3846 cmdp->param.index >= firstchange) ||
3847 (cmdp->cmdtype == CMDBUILTIN &&
3848 ((builtinloc < 0 && bltin >= 0) ?
3849 bltin : builtinloc) >= firstchange)) {
3850 /* need to recompute the entry */
3859 bcmd = find_builtin(name);
3860 regular = bcmd && IS_BUILTIN_REGULAR(bcmd);
3863 if (cmdp && (cmdp->cmdtype == CMDBUILTIN)) {
3866 } else if (act & DO_BRUTE) {
3867 if (firstchange == 0) {
3872 /* If %builtin not in path, check for builtin next */
3873 if (regular || (bltin < 0 && bcmd)) {
3876 entry->cmdtype = CMDBUILTIN;
3877 entry->u.cmd = bcmd;
3881 cmdp = cmdlookup(name, 1);
3882 cmdp->cmdtype = CMDBUILTIN;
3883 cmdp->param.cmd = bcmd;
3888 /* We have to search path. */
3889 prev = -1; /* where to start */
3890 if (cmdp && cmdp->rehash) { /* doing a rehash */
3891 if (cmdp->cmdtype == CMDBUILTIN)
3894 prev = cmdp->param.index;
3900 while ((fullname = padvance(&path, name)) != NULL) {
3901 stunalloc(fullname);
3903 if (idx >= firstchange) {
3907 if (prefix("builtin", pathopt)) {
3908 if ((bcmd = find_builtin(name))) {
3912 } else if (!(act & DO_NOFUN) &&
3913 prefix("func", pathopt)) {
3916 continue; /* ignore unimplemented options */
3919 /* if rehash, don't redo absolute path names */
3920 if (fullname[0] == '/' && idx <= prev &&
3921 idx < firstchange) {
3924 TRACE(("searchexec \"%s\": no change\n", name));
3927 while (stat(fullname, &statb) < 0) {
3928 if (errno != ENOENT && errno != ENOTDIR)
3932 e = EACCES; /* if we fail, this will be the error */
3933 if (!S_ISREG(statb.st_mode))
3935 if (pathopt) { /* this is a %func directory */
3936 stalloc(strlen(fullname) + 1);
3937 readcmdfile(fullname);
3938 if ((cmdp = cmdlookup(name, 0)) == NULL || cmdp->cmdtype != CMDFUNCTION)
3939 error("%s not defined in %s", name, fullname);
3940 stunalloc(fullname);
3943 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
3944 /* If we aren't called with DO_BRUTE and cmdp is set, it must
3945 be a function and we're being called with DO_NOFUN */
3947 entry->cmdtype = CMDNORMAL;
3948 entry->u.index = idx;
3952 cmdp = cmdlookup(name, 1);
3953 cmdp->cmdtype = CMDNORMAL;
3954 cmdp->param.index = idx;
3959 /* We failed. If there was an entry for this command, delete it */
3960 if (cmdp && updatetbl)
3963 out2fmt("%s: %s\n", name, errmsg(e, E_EXEC));
3964 entry->cmdtype = CMDUNKNOWN;
3969 entry->cmdtype = cmdp->cmdtype;
3970 entry->u = cmdp->param;
3976 * Search the table of builtin commands.
3980 bstrcmp(const void *name, const void *b)
3982 return strcmp((const char *)name, (*(const char *const *) b)+1);
3985 static struct builtincmd *
3986 find_builtin(const char *name)
3988 struct builtincmd *bp;
3990 bp = bsearch(name, builtincmds, NUMBUILTINS, sizeof(struct builtincmd),
3998 * Called when a cd is done. Marks all commands so the next time they
3999 * are executed they will be rehashed.
4004 struct tblentry **pp;
4005 struct tblentry *cmdp;
4007 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4008 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4009 if (cmdp->cmdtype == CMDNORMAL
4010 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
4019 * Called before PATH is changed. The argument is the new value of PATH;
4020 * pathval() still returns the old value at this point. Called with
4025 changepath(const char *newval)
4030 firstchange = path_change(newval, &bltin);
4031 if (builtinloc < 0 && bltin >= 0)
4032 builtinloc = bltin; /* zap builtins */
4033 clearcmdentry(firstchange);
4039 * Clear out command entries. The argument specifies the first entry in
4040 * PATH which has changed.
4044 clearcmdentry(firstchange)
4047 struct tblentry **tblp;
4048 struct tblentry **pp;
4049 struct tblentry *cmdp;
4052 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4054 while ((cmdp = *pp) != NULL) {
4055 if ((cmdp->cmdtype == CMDNORMAL &&
4056 cmdp->param.index >= firstchange)
4057 || (cmdp->cmdtype == CMDBUILTIN &&
4058 builtinloc >= firstchange)) {
4071 * Delete all functions.
4076 struct tblentry **tblp;
4077 struct tblentry **pp;
4078 struct tblentry *cmdp;
4081 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4083 while ((cmdp = *pp) != NULL) {
4084 if (cmdp->cmdtype == CMDFUNCTION) {
4086 freefunc(cmdp->param.func);
4099 * Locate a command in the command hash table. If "add" is nonzero,
4100 * add the command to the table if it is not already present. The
4101 * variable "lastcmdentry" is set to point to the address of the link
4102 * pointing to the entry, so that delete_cmd_entry can delete the
4106 static struct tblentry **lastcmdentry;
4108 static struct tblentry *
4109 cmdlookup(const char *name, int add)
4113 struct tblentry *cmdp;
4114 struct tblentry **pp;
4121 pp = &cmdtable[hashval % CMDTABLESIZE];
4122 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4123 if (equal(cmdp->cmdname, name))
4127 if (add && cmdp == NULL) {
4129 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4130 + strlen(name) + 1);
4132 cmdp->cmdtype = CMDUNKNOWN;
4134 strcpy(cmdp->cmdname, name);
4142 * Delete the command entry returned on the last lookup.
4146 delete_cmd_entry() {
4147 struct tblentry *cmdp;
4150 cmdp = *lastcmdentry;
4151 *lastcmdentry = cmdp->next;
4160 static const unsigned char nodesize[26] = {
4161 ALIGN(sizeof (struct nbinary)),
4162 ALIGN(sizeof (struct ncmd)),
4163 ALIGN(sizeof (struct npipe)),
4164 ALIGN(sizeof (struct nredir)),
4165 ALIGN(sizeof (struct nredir)),
4166 ALIGN(sizeof (struct nredir)),
4167 ALIGN(sizeof (struct nbinary)),
4168 ALIGN(sizeof (struct nbinary)),
4169 ALIGN(sizeof (struct nif)),
4170 ALIGN(sizeof (struct nbinary)),
4171 ALIGN(sizeof (struct nbinary)),
4172 ALIGN(sizeof (struct nfor)),
4173 ALIGN(sizeof (struct ncase)),
4174 ALIGN(sizeof (struct nclist)),
4175 ALIGN(sizeof (struct narg)),
4176 ALIGN(sizeof (struct narg)),
4177 ALIGN(sizeof (struct nfile)),
4178 ALIGN(sizeof (struct nfile)),
4179 ALIGN(sizeof (struct nfile)),
4180 ALIGN(sizeof (struct nfile)),
4181 ALIGN(sizeof (struct nfile)),
4182 ALIGN(sizeof (struct ndup)),
4183 ALIGN(sizeof (struct ndup)),
4184 ALIGN(sizeof (struct nhere)),
4185 ALIGN(sizeof (struct nhere)),
4186 ALIGN(sizeof (struct nnot)),
4192 * Delete a function if it exists.
4196 unsetfunc(char *name)
4198 struct tblentry *cmdp;
4200 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) {
4201 freefunc(cmdp->param.func);
4208 * Locate and print what a word is...
4212 typecmd(int argc, char **argv)
4220 for (i = 1; i < argc; i++) {
4221 argv_a[0] = argv[i];
4224 err |= hashcmd(argc, argv);
4231 commandcmd(argc, argv)
4236 int default_path = 0;
4237 int verify_only = 0;
4238 int verbose_verify_only = 0;
4240 while ((c = nextopt("pvV")) != '\0')
4249 verbose_verify_only = 1;
4253 if (default_path + verify_only + verbose_verify_only > 1 ||
4256 "command [-p] command [arg ...]\n"
4257 "command {-v|-V} command\n");
4261 if (verify_only || verbose_verify_only) {
4265 argv_a[0] = *argptr;
4267 optptr = verbose_verify_only ? "v" : "V"; /* reverse special */
4268 return hashcmd(argc, argv);
4276 path_change(newval, bltin)
4280 const char *old, *new;
4286 firstchange = 9999; /* assume no change */
4292 if ((*old == '\0' && *new == ':')
4293 || (*old == ':' && *new == '\0'))
4295 old = new; /* ignore subsequent differences */
4299 if (*new == '%' && *bltin < 0 && prefix("builtin", new + 1))
4306 if (builtinloc >= 0 && *bltin < 0)
4311 * Routines to expand arguments to commands. We have to deal with
4312 * backquotes, shell variables, and file metacharacters.
4317 #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4318 #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
4321 * Structure specifying which parts of the string should be searched
4322 * for IFS characters.
4326 struct ifsregion *next; /* next region in list */
4327 int begoff; /* offset of start of region */
4328 int endoff; /* offset of end of region */
4329 int nulonly; /* search for nul bytes only */
4333 static char *expdest; /* output of current string */
4334 static struct nodelist *argbackq; /* list of back quote expressions */
4335 static struct ifsregion ifsfirst; /* first struct in list of ifs regions */
4336 static struct ifsregion *ifslastp; /* last struct in list */
4337 static struct arglist exparg; /* holds expanded arg list */
4339 static void argstr (char *, int);
4340 static char *exptilde (char *, int);
4341 static void expbackq (union node *, int, int);
4342 static int subevalvar (char *, char *, int, int, int, int, int);
4343 static int varisset (char *, int);
4344 static void strtodest (const char *, int, int);
4345 static void varvalue (char *, int, int);
4346 static void recordregion (int, int, int);
4347 static void removerecordregions (int);
4348 static void ifsbreakup (char *, struct arglist *);
4349 static void ifsfree (void);
4350 static void expandmeta (struct strlist *, int);
4351 #if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
4352 #define preglob(p) _rmescapes((p), RMESCAPE_ALLOC | RMESCAPE_GLOB)
4353 #if !defined(GLOB_BROKEN)
4354 static void addglob (const glob_t *);
4357 #if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
4358 static void expmeta (char *, char *);
4360 #if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
4361 static struct strlist *expsort (struct strlist *);
4362 static struct strlist *msort (struct strlist *, int);
4364 static int patmatch (char *, char *, int);
4365 #if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
4366 static int patmatch2 (char *, char *, int);
4368 static int pmatch (char *, char *, int);
4369 #define patmatch2 patmatch
4371 static char *cvtnum (int, char *);
4374 * Expand shell variables and backquotes inside a here document.
4377 /* arg: the document, fd: where to write the expanded version */
4379 expandhere(union node *arg, int fd)
4382 expandarg(arg, (struct arglist *)NULL, 0);
4383 xwrite(fd, stackblock(), expdest - stackblock());
4388 * Perform variable substitution and command substitution on an argument,
4389 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4390 * perform splitting and file name expansion. When arglist is NULL, perform
4391 * here document expansion.
4395 expandarg(arg, arglist, flag)
4397 struct arglist *arglist;
4403 argbackq = arg->narg.backquote;
4404 STARTSTACKSTR(expdest);
4405 ifsfirst.next = NULL;
4407 argstr(arg->narg.text, flag);
4408 if (arglist == NULL) {
4409 return; /* here document expanded */
4411 STPUTC('\0', expdest);
4412 p = grabstackstr(expdest);
4413 exparg.lastp = &exparg.list;
4417 if (flag & EXP_FULL) {
4418 ifsbreakup(p, &exparg);
4419 *exparg.lastp = NULL;
4420 exparg.lastp = &exparg.list;
4421 expandmeta(exparg.list, flag);
4423 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
4425 sp = (struct strlist *)stalloc(sizeof (struct strlist));
4428 exparg.lastp = &sp->next;
4431 *exparg.lastp = NULL;
4433 *arglist->lastp = exparg.list;
4434 arglist->lastp = exparg.lastp;
4440 * Expand a variable, and return a pointer to the next character in the
4444 static inline char * evalvar(char *p, int flag)
4457 int quotes = flag & (EXP_FULL | EXP_CASE);
4460 subtype = varflags & VSTYPE;
4465 p = strchr(p, '=') + 1;
4466 again: /* jump here after setting a variable with ${var=text} */
4468 set = varisset(var, varflags & VSNUL);
4471 val = lookupvar(var);
4472 if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
4479 startloc = expdest - stackblock();
4480 if (set && subtype != VSPLUS) {
4481 /* insert the value of the variable */
4483 varvalue(var, varflags & VSQUOTE, flag);
4484 if (subtype == VSLENGTH) {
4485 varlen = expdest - stackblock() - startloc;
4486 STADJUST(-varlen, expdest);
4489 if (subtype == VSLENGTH) {
4490 varlen = strlen(val);
4494 varflags & VSQUOTE ?
4495 DQSYNTAX : BASESYNTAX,
4502 if (subtype == VSPLUS)
4505 easy = ((varflags & VSQUOTE) == 0 ||
4506 (*var == '@' && shellparam.nparam != 1));
4511 expdest = cvtnum(varlen, expdest);
4518 recordregion(startloc, expdest - stackblock(),
4519 varflags & VSQUOTE);
4535 case VSTRIMRIGHTMAX:
4539 * Terminate the string and start recording the pattern
4542 STPUTC('\0', expdest);
4543 patloc = expdest - stackblock();
4544 if (subevalvar(p, NULL, patloc, subtype,
4545 startloc, varflags, quotes) == 0) {
4546 int amount = (expdest - stackblock() - patloc) + 1;
4547 STADJUST(-amount, expdest);
4549 /* Remove any recorded regions beyond start of variable */
4550 removerecordregions(startloc);
4556 if (subevalvar(p, var, 0, subtype, startloc,
4557 varflags, quotes)) {
4560 * Remove any recorded regions beyond
4563 removerecordregions(startloc);
4578 if (subtype != VSNORMAL) { /* skip to end of alternative */
4581 if ((c = *p++) == CTLESC)
4583 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
4585 argbackq = argbackq->next;
4586 } else if (c == CTLVAR) {
4587 if ((*p++ & VSTYPE) != VSNORMAL)
4589 } else if (c == CTLENDVAR) {
4600 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4601 * characters to allow for further processing. Otherwise treat
4602 * $@ like $* since no splitting will be performed.
4611 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
4614 if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
4615 p = exptilde(p, flag);
4619 case CTLENDVAR: /* ??? */
4622 /* "$@" syntax adherence hack */
4623 if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=')
4625 if ((flag & EXP_FULL) != 0)
4635 p = evalvar(p, flag);
4638 case CTLBACKQ|CTLQUOTE:
4639 expbackq(argbackq->n, c & CTLQUOTE, flag);
4640 argbackq = argbackq->next;
4642 #ifdef ASH_MATH_SUPPORT
4650 * sort of a hack - expand tildes in variable
4651 * assignments (after the first '=' and after ':'s).
4654 if (flag & EXP_VARTILDE && *p == '~') {
4661 p = exptilde(p, flag);
4677 char c, *startp = p;
4680 int quotes = flag & (EXP_FULL | EXP_CASE);
4682 while ((c = *p) != '\0') {
4689 if (flag & EXP_VARTILDE)
4699 if (*(startp+1) == '\0') {
4700 if ((home = lookupvar("HOME")) == NULL)
4703 if ((pw = getpwnam(startp+1)) == NULL)
4710 strtodest(home, SQSYNTAX, quotes);
4719 removerecordregions(int endoff)
4721 if (ifslastp == NULL)
4724 if (ifsfirst.endoff > endoff) {
4725 while (ifsfirst.next != NULL) {
4726 struct ifsregion *ifsp;
4728 ifsp = ifsfirst.next->next;
4729 ckfree(ifsfirst.next);
4730 ifsfirst.next = ifsp;
4733 if (ifsfirst.begoff > endoff)
4736 ifslastp = &ifsfirst;
4737 ifsfirst.endoff = endoff;
4742 ifslastp = &ifsfirst;
4743 while (ifslastp->next && ifslastp->next->begoff < endoff)
4744 ifslastp=ifslastp->next;
4745 while (ifslastp->next != NULL) {
4746 struct ifsregion *ifsp;
4748 ifsp = ifslastp->next->next;
4749 ckfree(ifslastp->next);
4750 ifslastp->next = ifsp;
4753 if (ifslastp->endoff > endoff)
4754 ifslastp->endoff = endoff;
4758 #ifdef ASH_MATH_SUPPORT
4760 * Expand arithmetic expression. Backup to start of expression,
4761 * evaluate, place result in (backed up) result, adjust string position.
4770 int quotes = flag & (EXP_FULL | EXP_CASE);
4776 * This routine is slightly over-complicated for
4777 * efficiency. First we make sure there is
4778 * enough space for the result, which may be bigger
4779 * than the expression if we add exponentation. Next we
4780 * scan backwards looking for the start of arithmetic. If the
4781 * next previous character is a CTLESC character, then we
4782 * have to rescan starting from the beginning since CTLESC
4783 * characters have to be processed left to right.
4785 CHECKSTRSPACE(10, expdest);
4786 USTPUTC('\0', expdest);
4787 start = stackblock();
4789 while (*p != CTLARI && p >= start)
4792 error("missing CTLARI (shouldn't happen)");
4793 if (p > start && *(p-1) == CTLESC)
4794 for (p = start; *p != CTLARI; p++)
4803 removerecordregions(begoff);
4806 result = arith(p+2, &errcode);
4809 error("divide by zero");
4811 error("syntax error: \"%s\"\n", p+2);
4813 snprintf(p, 12, "%d", result);
4819 recordregion(begoff, p - 1 - start, 0);
4820 result = expdest - p + 1;
4821 STADJUST(-result, expdest);
4826 * Expand stuff in backwards quotes.
4830 expbackq(cmd, quoted, flag)
4835 volatile struct backcmd in;
4839 char *dest = expdest;
4840 volatile struct ifsregion saveifs;
4841 struct ifsregion *volatile savelastp;
4842 struct nodelist *volatile saveargbackq;
4844 int startloc = dest - stackblock();
4845 int syntax = quoted ? DQSYNTAX : BASESYNTAX;
4846 volatile int saveherefd;
4847 int quotes = flag & (EXP_FULL | EXP_CASE);
4848 struct jmploc jmploc;
4849 struct jmploc *volatile savehandler;
4853 /* Avoid longjmp clobbering */
4864 savelastp = ifslastp;
4865 saveargbackq = argbackq;
4866 saveherefd = herefd;
4868 if ((ex = setjmp(jmploc.loc))) {
4871 savehandler = handler;
4874 p = grabstackstr(dest);
4875 evalbackcmd(cmd, (struct backcmd *) &in);
4876 ungrabstackstr(p, dest);
4880 ifslastp = savelastp;
4881 argbackq = saveargbackq;
4882 herefd = saveherefd;
4890 if (--in.nleft < 0) {
4893 i = safe_read(in.fd, buf, sizeof buf);
4894 TRACE(("expbackq: read returns %d\n", i));
4901 if (lastc != '\0') {
4902 if (quotes && SIT(lastc, syntax) == CCTL)
4903 STPUTC(CTLESC, dest);
4904 STPUTC(lastc, dest);
4908 /* Eat all trailing newlines */
4909 for (; dest > stackblock() && dest[-1] == '\n';)
4918 exitstatus = waitforjob(in.jp);
4919 handler = savehandler;
4921 longjmp(handler->loc, 1);
4924 recordregion(startloc, dest - stackblock(), 0);
4925 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4926 (dest - stackblock()) - startloc,
4927 (dest - stackblock()) - startloc,
4928 stackblock() + startloc));
4934 subevalvar(p, str, strloc, subtype, startloc, varflags, quotes)
4947 int saveherefd = herefd;
4948 struct nodelist *saveargbackq = argbackq;
4952 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
4953 STACKSTRNUL(expdest);
4954 herefd = saveherefd;
4955 argbackq = saveargbackq;
4956 startp = stackblock() + startloc;
4958 str = stackblock() + strloc;
4962 setvar(str, startp, 0);
4963 amount = startp - expdest;
4964 STADJUST(amount, expdest);
4971 if (*p != CTLENDVAR) {
4972 out2fmt(snlfmt, startp);
4973 error((char *)NULL);
4975 error("%.*s: parameter %snot set", p - str - 1,
4976 str, (varflags & VSNUL) ? "null or "
4981 for (loc = startp; loc < str; loc++) {
4984 if (patmatch2(str, startp, quotes))
4987 if (quotes && *loc == CTLESC)
4993 for (loc = str - 1; loc >= startp;) {
4996 if (patmatch2(str, startp, quotes))
5000 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
5001 for (q = startp; q < loc; q++)
5011 for (loc = str - 1; loc >= startp;) {
5012 if (patmatch2(str, loc, quotes))
5015 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
5016 for (q = startp; q < loc; q++)
5025 case VSTRIMRIGHTMAX:
5026 for (loc = startp; loc < str - 1; loc++) {
5027 if (patmatch2(str, loc, quotes))
5029 if (quotes && *loc == CTLESC)
5042 amount = ((str - 1) - (loc - startp)) - expdest;
5043 STADJUST(amount, expdest);
5044 while (loc != str - 1)
5049 amount = loc - expdest;
5050 STADJUST(amount, expdest);
5051 STPUTC('\0', expdest);
5052 STADJUST(-1, expdest);
5058 * Test whether a specialized variable is set.
5062 varisset(name, nulok)
5067 return backgndpid != -1;
5068 else if (*name == '@' || *name == '*') {
5069 if (*shellparam.p == NULL)
5075 for (av = shellparam.p; *av; av++)
5080 } else if (is_digit(*name)) {
5082 int num = atoi(name);
5084 if (num > shellparam.nparam)
5090 ap = shellparam.p[num - 1];
5092 if (nulok && (ap == NULL || *ap == '\0'))
5099 * Put a string on the stack.
5103 strtodest(const char *p, int syntax, int quotes)
5106 if (quotes && SIT(*p,syntax) == CCTL)
5107 STPUTC(CTLESC, expdest);
5108 STPUTC(*p++, expdest);
5113 * Add the value of a specialized variable to the stack string.
5117 varvalue(char *name, int quoted, int flags)
5126 int allow_split = flags & EXP_FULL;
5127 int quotes = flags & (EXP_FULL | EXP_CASE);
5129 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5138 num = shellparam.nparam;
5143 expdest = cvtnum(num, expdest);
5146 for (i = 0 ; i < NOPTS ; i++) {
5148 STPUTC(optent_letter(optlist[i]), expdest);
5152 if (allow_split && quoted) {
5153 sep = 1 << CHAR_BIT;
5158 sep = ifsset() ? ifsval()[0] : ' ';
5160 sepq = SIT(sep,syntax) == CCTL;
5163 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
5164 strtodest(p, syntax, quotes);
5167 STPUTC(CTLESC, expdest);
5168 STPUTC(sep, expdest);
5173 strtodest(arg0, syntax, quotes);
5177 if (num > 0 && num <= shellparam.nparam) {
5178 strtodest(shellparam.p[num - 1], syntax, quotes);
5186 * Record the fact that we have to scan this region of the
5187 * string for IFS characters.
5191 recordregion(start, end, nulonly)
5196 struct ifsregion *ifsp;
5198 if (ifslastp == NULL) {
5202 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
5204 ifslastp->next = ifsp;
5208 ifslastp->begoff = start;
5209 ifslastp->endoff = end;
5210 ifslastp->nulonly = nulonly;
5216 * Break the argument string into pieces based upon IFS and add the
5217 * strings to the argument list. The regions of the string to be
5218 * searched for IFS characters have been stored by recordregion.
5221 ifsbreakup(string, arglist)
5223 struct arglist *arglist;
5225 struct ifsregion *ifsp;
5230 const char *ifs, *realifs;
5238 realifs = ifsset() ? ifsval() : defifs;
5239 if (ifslastp != NULL) {
5242 p = string + ifsp->begoff;
5243 nulonly = ifsp->nulonly;
5244 ifs = nulonly ? nullstr : realifs;
5246 while (p < string + ifsp->endoff) {
5250 if (strchr(ifs, *p)) {
5252 ifsspc = (strchr(defifs, *p) != NULL);
5253 /* Ignore IFS whitespace at start */
5254 if (q == start && ifsspc) {
5260 sp = (struct strlist *)stalloc(sizeof *sp);
5262 *arglist->lastp = sp;
5263 arglist->lastp = &sp->next;
5267 if (p >= string + ifsp->endoff) {
5273 if (strchr(ifs, *p) == NULL ) {
5276 } else if (strchr(defifs, *p) == NULL) {
5292 } while ((ifsp = ifsp->next) != NULL);
5293 if (!(*start || (!ifsspc && start > string && nulonly))) {
5298 sp = (struct strlist *)stalloc(sizeof *sp);
5300 *arglist->lastp = sp;
5301 arglist->lastp = &sp->next;
5307 while (ifsfirst.next != NULL) {
5308 struct ifsregion *ifsp;
5310 ifsp = ifsfirst.next->next;
5311 ckfree(ifsfirst.next);
5312 ifsfirst.next = ifsp;
5316 ifsfirst.next = NULL;
5320 * Add a file name to the list.
5324 addfname(const char *name)
5330 sp = (struct strlist *)stalloc(sizeof *sp);
5333 exparg.lastp = &sp->next;
5337 * Expand shell metacharacters. At this point, the only control characters
5338 * should be escapes. The results are stored in the list exparg.
5341 #if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)
5343 expandmeta(str, flag)
5344 struct strlist *str;
5349 /* TODO - EXP_REDIR */
5354 p = preglob(str->text);
5356 switch (glob(p, 0, 0, &pglob)) {
5358 if(pglob.gl_pathv[1]==0 && !strcmp(p, pglob.gl_pathv[0]))
5369 *exparg.lastp = str;
5370 rmescapes(str->text);
5371 exparg.lastp = &str->next;
5373 default: /* GLOB_NOSPACE */
5374 error("Out of space");
5382 * Add the result of glob(3) to the list.
5387 const glob_t *pglob;
5389 char **p = pglob->gl_pathv;
5397 #else /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
5398 static char *expdir;
5402 expandmeta(str, flag)
5403 struct strlist *str;
5407 struct strlist **savelastp;
5410 /* TODO - EXP_REDIR */
5416 for (;;) { /* fast check for meta chars */
5417 if ((c = *p++) == '\0')
5419 if (c == '*' || c == '?' || c == '[' || c == '!')
5422 savelastp = exparg.lastp;
5424 if (expdir == NULL) {
5425 int i = strlen(str->text);
5426 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5429 expmeta(expdir, str->text);
5433 if (exparg.lastp == savelastp) {
5438 *exparg.lastp = str;
5439 rmescapes(str->text);
5440 exparg.lastp = &str->next;
5442 *exparg.lastp = NULL;
5443 *savelastp = sp = expsort(*savelastp);
5444 while (sp->next != NULL)
5446 exparg.lastp = &sp->next;
5454 * Do metacharacter (i.e. *, ?, [...]) expansion.
5458 expmeta(enddir, name)
5476 for (p = name ; ; p++) {
5477 if (*p == '*' || *p == '?')
5479 else if (*p == '[') {
5484 while (*q == CTLQUOTEMARK)
5488 if (*q == '/' || *q == '\0')
5495 } else if (*p == '!' && p[1] == '!' && (p == name || p[-1] == '/')) {
5497 } else if (*p == '\0')
5499 else if (*p == CTLQUOTEMARK)
5501 else if (*p == CTLESC)
5509 if (metaflag == 0) { /* we've reached the end of the file name */
5510 if (enddir != expdir)
5512 for (p = name ; ; p++) {
5513 if (*p == CTLQUOTEMARK)
5521 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
5526 if (start != name) {
5529 while (*p == CTLQUOTEMARK)
5536 if (enddir == expdir) {
5538 } else if (enddir == expdir + 1 && *expdir == '/') {
5544 if ((dirp = opendir(cp)) == NULL)
5546 if (enddir != expdir)
5548 if (*endname == 0) {
5556 while (*p == CTLQUOTEMARK)
5562 while (! int_pending() && (dp = readdir(dirp)) != NULL) {
5563 if (dp->d_name[0] == '.' && ! matchdot)
5565 if (patmatch(start, dp->d_name, 0)) {
5567 strcpy(enddir, dp->d_name);
5570 for (p = enddir, cp = dp->d_name;
5571 (*p++ = *cp++) != '\0';)
5574 expmeta(p, endname);
5582 #endif /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
5586 #if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
5588 * Sort the results of file name expansion. It calculates the number of
5589 * strings to sort and then calls msort (short for merge sort) to do the
5593 static struct strlist *
5595 struct strlist *str;
5601 for (sp = str ; sp ; sp = sp->next)
5603 return msort(str, len);
5607 static struct strlist *
5609 struct strlist *list;
5612 struct strlist *p, *q = NULL;
5613 struct strlist **lpp;
5621 for (n = half ; --n >= 0 ; ) {
5625 q->next = NULL; /* terminate first half of list */
5626 q = msort(list, half); /* sort first half of list */
5627 p = msort(p, len - half); /* sort second half */
5630 if (strcmp(p->text, q->text) < 0) {
5633 if ((p = *lpp) == NULL) {
5640 if ((q = *lpp) == NULL) {
5653 * Returns true if the pattern matches the string.
5656 #if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
5657 /* squoted: string might have quote chars */
5659 patmatch(char *pattern, char *string, int squoted)
5664 p = preglob(pattern);
5665 q = squoted ? _rmescapes(string, RMESCAPE_ALLOC) : string;
5667 return !fnmatch(p, q, 0);
5672 patmatch2(char *pattern, char *string, int squoted)
5678 p = grabstackstr(expdest);
5679 res = patmatch(pattern, string, squoted);
5680 ungrabstackstr(p, expdest);
5685 patmatch(char *pattern, char *string, int squoted) {
5686 return pmatch(pattern, string, squoted);
5691 pmatch(char *pattern, char *string, int squoted)
5703 if (squoted && *q == CTLESC)
5711 if (squoted && *q == CTLESC)
5718 while (c == CTLQUOTEMARK || c == '*')
5720 if (c != CTLESC && c != CTLQUOTEMARK &&
5721 c != '?' && c != '*' && c != '[') {
5723 if (squoted && *q == CTLESC &&
5728 if (squoted && *q == CTLESC)
5734 if (pmatch(p, q, squoted))
5736 if (squoted && *q == CTLESC)
5738 } while (*q++ != '\0');
5749 while (*endp == CTLQUOTEMARK)
5752 goto dft; /* no matching ] */
5753 if (*endp == CTLESC)
5765 if (squoted && chr == CTLESC)
5771 if (c == CTLQUOTEMARK)
5775 if (*p == '-' && p[1] != ']') {
5777 while (*p == CTLQUOTEMARK)
5781 if (chr >= c && chr <= *p)
5788 } while ((c = *p++) != ']');
5789 if (found == invert)
5794 if (squoted && *q == CTLESC)
5811 * Remove any CTLESC characters from a string.
5814 #if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN)
5816 _rmescapes(char *str, int flag)
5819 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
5821 p = strpbrk(str, qchars);
5827 if (flag & RMESCAPE_ALLOC) {
5828 size_t len = p - str;
5829 q = r = stalloc(strlen(p) + len + 1);
5831 memcpy(q, str, len);
5836 if (*p == CTLQUOTEMARK) {
5842 if (flag & RMESCAPE_GLOB && *p != '/') {
5859 while (*p != CTLESC && *p != CTLQUOTEMARK) {
5865 if (*p == CTLQUOTEMARK) {
5880 * See if a pattern matches in a case statement.
5884 casematch(union node *pattern, const char *val)
5886 struct stackmark smark;
5890 setstackmark(&smark);
5891 argbackq = pattern->narg.backquote;
5892 STARTSTACKSTR(expdest);
5894 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
5895 STPUTC('\0', expdest);
5896 p = grabstackstr(expdest);
5897 result = patmatch(p, (char *)val, 0);
5898 popstackmark(&smark);
5913 CHECKSTRSPACE(32, buf);
5914 len = sprintf(buf, "%d", num);
5919 * Editline and history functions (and glue).
5921 static int histcmd(argc, argv)
5925 error("not compiled with history support");
5931 struct redirtab *next;
5932 short renamed[10]; /* Current ash support only 0-9 descriptors */
5933 /* char on arm (and others) can't be negative */
5936 static struct redirtab *redirlist;
5938 extern char **environ;
5943 * Initialization code.
5956 basepf.nextc = basepf.buf = basebuf;
5965 for (envp = environ ; *envp ; envp++) {
5966 if (strchr(*envp, '=')) {
5967 setvareq(*envp, VEXPORT|VTEXTFIXED);
5971 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
5972 setvar("PPID", ppid, 0);
5979 * This routine is called when an error or an interrupt occurs in an
5980 * interactive shell and control is returned to the main command loop.
5983 /* 1 == check for aliases, 2 == also check for assignments */
5984 static int checkalias; /* also used in no alias mode for check assignments */
5998 if (exception != EXSHELLPROC)
5999 parselleft = parsenleft = 0; /* clear input buffer */
6003 /* from parser.c: */
6021 * This file implements the input routines used by the parser.
6024 #ifdef BB_FEATURE_COMMAND_EDITING
6025 static const char * cmdedit_prompt;
6026 static inline void putprompt(const char *s) {
6030 static inline void putprompt(const char *s) {
6035 #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
6040 * Same as pgetc(), but ignores PEOA.
6050 } while (c == PEOA);
6054 static inline int pgetc2() { return pgetc_macro(); }
6058 * Read a line from the script.
6061 static inline char *
6062 pfgets(char *line, int len)
6068 while (--nleft > 0) {
6087 char *buf = parsefile->buf;
6091 #ifdef BB_FEATURE_COMMAND_EDITING
6093 if (!iflag || parsefile->fd)
6094 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6096 nr = cmdedit_read_input((char*)cmdedit_prompt, buf);
6100 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6104 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6105 int flags = fcntl(0, F_GETFL, 0);
6106 if (flags >= 0 && flags & O_NONBLOCK) {
6107 flags &=~ O_NONBLOCK;
6108 if (fcntl(0, F_SETFL, flags) >= 0) {
6109 out2str("sh: turning off NDELAY mode\n");
6121 struct strpush *sp = parsefile->strpush;
6126 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6131 if (sp->string != sp->ap->val) {
6135 sp->ap->flag &= ~ALIASINUSE;
6136 if (sp->ap->flag & ALIASDEAD) {
6137 unalias(sp->ap->name);
6141 parsenextc = sp->prevstring;
6142 parsenleft = sp->prevnleft;
6143 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6144 parsefile->strpush = sp->prev;
6145 if (sp != &(parsefile->basestrpush))
6152 * Refill the input buffer and return the next input character:
6154 * 1) If a string was pushed back on the input, pop it;
6155 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6156 * from a string so we can't refill the buffer, return EOF.
6157 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6158 * 4) Process input up to the next newline, deleting nul characters.
6168 while (parsefile->strpush) {
6170 if (parsenleft == -1 && parsefile->strpush->ap &&
6171 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
6176 if (--parsenleft >= 0)
6177 return (*parsenextc++);
6179 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6184 if (parselleft <= 0) {
6185 if ((parselleft = preadfd()) <= 0) {
6186 parselleft = parsenleft = EOF_NLEFT;
6193 /* delete nul characters */
6194 for (more = 1; more;) {
6202 parsenleft = q - parsenextc;
6203 more = 0; /* Stop processing here */
6209 if (--parselleft <= 0 && more) {
6210 parsenleft = q - parsenextc - 1;
6221 out2str(parsenextc);
6226 return *parsenextc++;
6231 * Push a string back onto the input at this current parsefile level.
6232 * We handle aliases this way.
6235 pushstring(char *s, int len, void *ap)
6240 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6241 if (parsefile->strpush) {
6242 sp = ckmalloc(sizeof (struct strpush));
6243 sp->prev = parsefile->strpush;
6244 parsefile->strpush = sp;
6246 sp = parsefile->strpush = &(parsefile->basestrpush);
6247 sp->prevstring = parsenextc;
6248 sp->prevnleft = parsenleft;
6250 sp->ap = (struct alias *)ap;
6252 ((struct alias *)ap)->flag |= ALIASINUSE;
6263 * Like setinputfile, but takes input from a string.
6267 setinputstring(char *string)
6271 parsenextc = string;
6272 parsenleft = strlen(string);
6273 parsefile->buf = NULL;
6281 * To handle the "." command, a stack of input files is used. Pushfile
6282 * adds a new entry to the stack and popfile restores the previous level.
6287 struct parsefile *pf;
6289 parsefile->nleft = parsenleft;
6290 parsefile->lleft = parselleft;
6291 parsefile->nextc = parsenextc;
6292 parsefile->linno = plinno;
6293 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
6294 pf->prev = parsefile;
6297 pf->basestrpush.prev = NULL;
6302 static void restartjob (struct job *);
6304 static void freejob (struct job *);
6305 static struct job *getjob (const char *);
6306 static int dowait (int, struct job *);
6307 static void waitonint(int);
6311 * We keep track of whether or not fd0 has been redirected. This is for
6312 * background commands, where we want to redirect fd0 to /dev/null only
6313 * if it hasn't already been redirected.
6315 static int fd0_redirected = 0;
6317 /* Return true if fd 0 has already been redirected at least once. */
6319 fd0_redirected_p (void)
6321 return fd0_redirected != 0;
6324 static void dupredirect (const union node *, int, int fd1dup);
6328 * Turn job control on and off.
6330 * Note: This code assumes that the third arg to ioctl is a character
6331 * pointer, which is true on Berkeley systems but not System V. Since
6332 * System V doesn't have job control yet, this isn't a problem now.
6337 static void setjobctl(int enable)
6339 #ifdef OLD_TTY_DRIVER
6343 if (enable == jobctl || rootshell == 0)
6346 do { /* while we are in the background */
6347 #ifdef OLD_TTY_DRIVER
6348 if (ioctl(2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
6350 initialpgrp = tcgetpgrp(2);
6351 if (initialpgrp < 0) {
6353 out2str("sh: can't access tty; job control turned off\n");
6357 if (initialpgrp == -1)
6358 initialpgrp = getpgrp();
6359 else if (initialpgrp != getpgrp()) {
6360 killpg(initialpgrp, SIGTTIN);
6364 #ifdef OLD_TTY_DRIVER
6365 if (ioctl(2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
6366 out2str("sh: need new tty driver to run job control; job control turned off\n");
6374 setpgid(0, rootpid);
6375 #ifdef OLD_TTY_DRIVER
6376 ioctl(2, TIOCSPGRP, (char *)&rootpid);
6378 tcsetpgrp(2, rootpid);
6380 } else { /* turning job control off */
6381 setpgid(0, initialpgrp);
6382 #ifdef OLD_TTY_DRIVER
6383 ioctl(2, TIOCSPGRP, (char *)&initialpgrp);
6385 tcsetpgrp(2, initialpgrp);
6411 "Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6412 "kill -l [exitstatus]"
6416 if (*argv[1] == '-') {
6417 signo = decode_signal(argv[1] + 1, 1);
6421 while ((c = nextopt("ls:")) != '\0')
6427 signo = decode_signal(optionarg, 1);
6430 "invalid signal number or name: %s",
6438 "nextopt returned character code 0%o", c);
6445 if (!list && signo < 0)
6448 if ((signo < 0 || !*argptr) ^ list) {
6457 for (i = 1; i < NSIG; i++) {
6458 name = u_signal_names(0, &i, 1);
6460 printf(snlfmt, name);
6464 name = u_signal_names(*argptr, &signo, -1);
6466 printf(snlfmt, name);
6468 error("invalid signal number or exit status: %s",
6474 if (**argptr == '%') {
6475 jp = getjob(*argptr);
6476 if (jp->jobctl == 0)
6477 error("job %s not created under job control",
6479 pid = -jp->ps[0].pid;
6481 pid = atoi(*argptr);
6482 if (kill(pid, signo) != 0)
6483 error("%s: %m", *argptr);
6484 } while (*++argptr);
6498 jp = getjob(argv[1]);
6499 if (jp->jobctl == 0)
6500 error("job not created under job control");
6501 pgrp = jp->ps[0].pid;
6502 #ifdef OLD_TTY_DRIVER
6503 ioctl(2, TIOCSPGRP, (char *)&pgrp);
6509 status = waitforjob(jp);
6523 jp = getjob(*++argv);
6524 if (jp->jobctl == 0)
6525 error("job not created under job control");
6527 } while (--argc > 1);
6536 struct procstat *ps;
6539 if (jp->state == JOBDONE)
6542 killpg(jp->ps[0].pid, SIGCONT);
6543 for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
6544 if (WIFSTOPPED(ps->status)) {
6553 static void showjobs(int change);
6567 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6568 * statuses have changed since the last call to showjobs.
6570 * If the shell is interrupted in the process of creating a job, the
6571 * result may be a job structure containing zero processes. Such structures
6572 * will be freed here.
6583 struct procstat *ps;
6587 TRACE(("showjobs(%d) called\n", change));
6588 while (dowait(0, (struct job *)NULL) > 0);
6589 for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
6592 if (jp->nprocs == 0) {
6596 if (change && ! jp->changed)
6598 procno = jp->nprocs;
6599 for (ps = jp->ps ; ; ps++) { /* for each process */
6601 snprintf(s, 64, "[%d] %ld ", jobno,
6604 snprintf(s, 64, " %ld ",
6609 if (ps->status == -1) {
6610 /* don't print anything */
6611 } else if (WIFEXITED(ps->status)) {
6612 snprintf(s, 64, "Exit %d",
6613 WEXITSTATUS(ps->status));
6616 if (WIFSTOPPED(ps->status))
6617 i = WSTOPSIG(ps->status);
6618 else /* WIFSIGNALED(ps->status) */
6620 i = WTERMSIG(ps->status);
6621 if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F])
6622 strcpy(s, sys_siglist[i & 0x7F]);
6624 snprintf(s, 64, "Signal %d", i & 0x7F);
6625 if (WCOREDUMP(ps->status))
6626 strcat(s, " (core dumped)");
6631 "%*c%s\n", 30 - col >= 0 ? 30 - col : 0, ' ',
6638 if (jp->state == JOBDONE) {
6646 * Mark a job structure as unused.
6650 freejob(struct job *jp)
6652 const struct procstat *ps;
6656 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
6657 if (ps->cmd != nullstr)
6660 if (jp->ps != &jp->ps0)
6664 if (curjob == jp - jobtab + 1)
6683 job = getjob(*++argv);
6687 for (;;) { /* loop until process terminated or stopped */
6690 status = job->ps[job->nprocs - 1].status;
6696 if (WIFEXITED(status))
6697 retval = WEXITSTATUS(status);
6699 else if (WIFSTOPPED(status))
6700 retval = WSTOPSIG(status) + 128;
6703 /* XXX: limits number of signals */
6704 retval = WTERMSIG(status) + 128;
6709 for (jp = jobtab ; ; jp++) {
6710 if (jp >= jobtab + njobs) { /* no running procs */
6713 if (jp->used && jp->state == 0)
6717 if (dowait(2, 0) < 0 && errno == EINTR) {
6726 * Convert a job name to a job structure.
6730 getjob(const char *name)
6740 if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0)
6741 error("No current job");
6742 return &jobtab[jobno - 1];
6744 error("No current job");
6746 } else if (name[0] == '%') {
6747 if (is_digit(name[1])) {
6748 jobno = number(name + 1);
6749 if (jobno > 0 && jobno <= njobs
6750 && jobtab[jobno - 1].used != 0)
6751 return &jobtab[jobno - 1];
6753 } else if (name[1] == '%' && name[2] == '\0') {
6757 struct job *found = NULL;
6758 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
6759 if (jp->used && jp->nprocs > 0
6760 && prefix(name + 1, jp->ps[0].cmd)) {
6762 error("%s: ambiguous", name);
6769 } else if (is_number(name, &pid)) {
6770 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
6771 if (jp->used && jp->nprocs > 0
6772 && jp->ps[jp->nprocs - 1].pid == pid)
6776 error("No such job: %s", name);
6783 * Return a new job structure,
6787 makejob(const union node *node, int nprocs)
6792 for (i = njobs, jp = jobtab ; ; jp++) {
6796 jobtab = ckmalloc(4 * sizeof jobtab[0]);
6798 jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
6799 memcpy(jp, jobtab, njobs * sizeof jp[0]);
6800 /* Relocate `ps' pointers */
6801 for (i = 0; i < njobs; i++)
6802 if (jp[i].ps == &jobtab[i].ps0)
6803 jp[i].ps = &jp[i].ps0;
6807 jp = jobtab + njobs;
6808 for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0);
6821 jp->jobctl = jobctl;
6824 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
6829 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
6836 * Fork of a subshell. If we are doing job control, give the subshell its
6837 * own process group. Jp is a job structure that the job is to be added to.
6838 * N is the command that will be evaluated by the child. Both jp and n may
6839 * be NULL. The mode parameter can be one of the following:
6840 * FORK_FG - Fork off a foreground process.
6841 * FORK_BG - Fork off a background process.
6842 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
6843 * process group even if job control is on.
6845 * When job control is turned off, background processes have their standard
6846 * input redirected to /dev/null (except for the second and later processes
6853 forkshell(struct job *jp, const union node *n, int mode)
6859 const char *devnull = _PATH_DEVNULL;
6860 const char *nullerr = "Can't open %s";
6862 TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long)n,
6867 TRACE(("Fork failed, errno=%d\n", errno));
6869 error("Cannot fork");
6876 TRACE(("Child shell %d\n", getpid()));
6877 wasroot = rootshell;
6883 jobctl = 0; /* do job control only in root shell */
6884 if (wasroot && mode != FORK_NOJOB && mflag) {
6885 if (jp == NULL || jp->nprocs == 0)
6888 pgrp = jp->ps[0].pid;
6890 if (mode == FORK_FG) {
6891 /*** this causes superfluous TIOCSPGRPS ***/
6892 #ifdef OLD_TTY_DRIVER
6893 if (ioctl(2, TIOCSPGRP, (char *)&pgrp) < 0)
6894 error("TIOCSPGRP failed, errno=%d", errno);
6896 if (tcsetpgrp(2, pgrp) < 0)
6897 error("tcsetpgrp failed, errno=%d", errno);
6902 } else if (mode == FORK_BG) {
6905 if ((jp == NULL || jp->nprocs == 0) &&
6906 ! fd0_redirected_p ()) {
6908 if (open(devnull, O_RDONLY) != 0)
6909 error(nullerr, devnull);
6913 if (mode == FORK_BG) {
6916 if ((jp == NULL || jp->nprocs == 0) &&
6917 ! fd0_redirected_p ()) {
6919 if (open(devnull, O_RDONLY) != 0)
6920 error(nullerr, devnull);
6924 for (i = njobs, p = jobtab ; --i >= 0 ; p++)
6927 if (wasroot && iflag) {
6935 if (rootshell && mode != FORK_NOJOB && mflag) {
6936 if (jp == NULL || jp->nprocs == 0)
6939 pgrp = jp->ps[0].pid;
6943 if (mode == FORK_BG)
6944 backgndpid = pid; /* set $! */
6946 struct procstat *ps = &jp->ps[jp->nprocs++];
6950 if (iflag && rootshell && n)
6951 ps->cmd = commandtext(n);
6954 TRACE(("In parent shell: child = %d\n", pid));
6961 * Wait for job to finish.
6963 * Under job control we have the problem that while a child process is
6964 * running interrupts generated by the user are sent to the child but not
6965 * to the shell. This means that an infinite loop started by an inter-
6966 * active user may be hard to kill. With job control turned off, an
6967 * interactive user may place an interactive program inside a loop. If
6968 * the interactive program catches interrupts, the user doesn't want
6969 * these interrupts to also abort the loop. The approach we take here
6970 * is to have the shell ignore interrupt signals while waiting for a
6971 * forground process to terminate, and then send itself an interrupt
6972 * signal if the child process was terminated by an interrupt signal.
6973 * Unfortunately, some programs want to do a bit of cleanup and then
6974 * exit on interrupt; unless these processes terminate themselves by
6975 * sending a signal to themselves (instead of calling exit) they will
6976 * confuse this approach.
6980 waitforjob(struct job *jp)
6983 int mypgrp = getpgrp();
6987 struct sigaction act, oact;
6996 sigaction(SIGINT, 0, &act);
6997 act.sa_handler = waitonint;
6998 sigaction(SIGINT, &act, &oact);
7000 TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
7001 while (jp->state == 0) {
7009 sigaction(SIGINT, &oact, 0);
7010 if (intreceived && trap[SIGINT]) kill(getpid(), SIGINT);
7014 #ifdef OLD_TTY_DRIVER
7015 if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0)
7016 error("TIOCSPGRP failed, errno=%d\n", errno);
7018 if (tcsetpgrp(2, mypgrp) < 0)
7019 error("tcsetpgrp failed, errno=%d\n", errno);
7022 if (jp->state == JOBSTOPPED)
7023 curjob = jp - jobtab + 1;
7025 status = jp->ps[jp->nprocs - 1].status;
7026 /* convert to 8 bits */
7027 if (WIFEXITED(status))
7028 st = WEXITSTATUS(status);
7030 else if (WIFSTOPPED(status))
7031 st = WSTOPSIG(status) + 128;
7034 st = WTERMSIG(status) + 128;
7038 * This is truly gross.
7039 * If we're doing job control, then we did a TIOCSPGRP which
7040 * caused us (the shell) to no longer be in the controlling
7041 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7042 * intuit from the subprocess exit status whether a SIGINT
7043 * occured, and if so interrupt ourselves. Yuck. - mycroft
7045 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
7048 if (jp->state == JOBDONE)
7059 * Wait for a process to terminate.
7063 * Do a wait system call. If job control is compiled in, we accept
7064 * stopped processes. If block is zero, we return a value of zero
7065 * rather than blocking.
7067 * System V doesn't have a non-blocking wait system call. It does
7068 * have a SIGCLD signal that is sent to a process when one of it's
7069 * children dies. The obvious way to use SIGCLD would be to install
7070 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7071 * was received, and have waitproc bump another counter when it got
7072 * the status of a process. Waitproc would then know that a wait
7073 * system call would not block if the two counters were different.
7074 * This approach doesn't work because if a process has children that
7075 * have not been waited for, System V will send it a SIGCLD when it
7076 * installs a signal handler for SIGCLD. What this means is that when
7077 * a child exits, the shell will be sent SIGCLD signals continuously
7078 * until is runs out of stack space, unless it does a wait call before
7079 * restoring the signal handler. The code below takes advantage of
7080 * this (mis)feature by installing a signal handler for SIGCLD and
7081 * then checking to see whether it was called. If there are any
7082 * children to be waited for, it will be.
7087 waitproc(int block, int *status)
7098 return wait3(status, flags, (struct rusage *)NULL);
7102 dowait(int block, struct job *job)
7106 struct procstat *sp;
7108 struct job *thisjob;
7114 TRACE(("dowait(%d) called\n", block));
7116 pid = waitproc(block, &status);
7117 TRACE(("wait returns %d, status=%d\n", pid, status));
7118 } while (!(block & 2) && pid == -1 && errno == EINTR);
7123 for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
7127 for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
7130 if (sp->pid == pid) {
7131 TRACE(("Changing status of proc %d from 0x%x to 0x%x\n", pid, sp->status, status));
7132 sp->status = status;
7135 if (sp->status == -1)
7137 else if (WIFSTOPPED(sp->status))
7140 if (stopped) { /* stopped or done */
7141 int state = done? JOBDONE : JOBSTOPPED;
7142 if (jp->state != state) {
7143 TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
7146 if (done && curjob == jp - jobtab + 1)
7147 curjob = 0; /* no current job */
7154 if (! rootshell || ! iflag || (job && thisjob == job)) {
7155 core = WCOREDUMP(status);
7157 if (WIFSTOPPED(status)) sig = WSTOPSIG(status);
7160 if (WIFEXITED(status)) sig = 0;
7161 else sig = WTERMSIG(status);
7163 if (sig != 0 && sig != SIGINT && sig != SIGPIPE) {
7165 out2fmt("%d: ", pid);
7167 if (sig == SIGTSTP && rootshell && iflag)
7169 (long)(job - jobtab + 1));
7171 if (sig < NSIG && sys_siglist[sig])
7172 out2str(sys_siglist[sig]);
7174 out2fmt("Signal %d", sig);
7176 out2str(" - core dumped");
7179 TRACE(("Not printing status: status=%d, sig=%d\n",
7183 TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job));
7185 thisjob->changed = 1;
7194 * return 1 if there are stopped jobs, otherwise 0
7204 for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
7207 if (jp->state == JOBSTOPPED) {
7208 out2str("You have stopped jobs.\n");
7218 * Return a string identifying a command (to be printed by the
7222 static char *cmdnextc;
7223 static int cmdnleft;
7224 #define MAXCMDTEXT 200
7227 cmdputs(const char *s)
7238 while ((c = *p++) != '\0') {
7241 else if (c == CTLVAR) {
7246 } else if (c == '=' && subtype != 0) {
7247 *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
7249 } else if (c == CTLENDVAR) {
7251 } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE)
7252 cmdnleft++; /* ignore it */
7255 if (--cmdnleft <= 0) {
7265 #define CMDTXT_TABLE
7268 * To collect a lot of redundant code in cmdtxt() case statements, we
7269 * implement a mini language here. Each type of node struct has an
7270 * associated instruction sequence that operates on its members via
7271 * their offsets. The instruction are pack in unsigned chars with
7272 * format IIDDDDDE where the bits are
7273 * I : part of the instruction opcode, which are
7274 * 00 : member is a pointer to another node -- process it recursively
7275 * 40 : member is a pointer to a char string -- output it
7276 * 80 : output the string whose index is stored in the data field
7277 * CC : flag signaling that this case needs external processing
7278 * D : data - either the (shifted) index of a fixed string to output or
7279 * the actual offset of the member to operate on in the struct
7280 * (since we assume bit 0 is set, the offset is not shifted)
7281 * E : flag signaling end of instruction sequence
7283 * WARNING: In order to handle larger offsets for 64bit archs, this code
7284 * assumes that no offset can be an odd number and stores the
7285 * end-of-instructions flag in bit 0.
7288 #define CMDTXT_NOMORE 0x01 /* NOTE: no offset should be odd */
7289 #define CMDTXT_CHARPTR 0x40
7290 #define CMDTXT_STRING 0x80
7291 #define CMDTXT_SPECIAL 0xC0
7292 #define CMDTXT_OFFSETMASK 0x3E
7294 static const char * const cmdtxt_strings[] = {
7295 /* 0 1 2 3 4 5 6 7 */
7296 "; ", "(", ")", " && ", " || ", "if ", "; then ", "...",
7297 /* 8 9 10 11 12 13 */
7298 "while ", "; do ", "; done", "until ", "for ", " in ...",
7300 "case ", "???", "() ...", "<<..."
7303 static const char * const redir_strings[] = {
7304 ">", "<", "<>", ">>", ">|", ">&", "<&"
7307 static const unsigned char cmdtxt_ops[] = {
7308 #define CMDTXT_NSEMI 0
7309 offsetof(union node, nbinary.ch1),
7311 offsetof(union node, nbinary.ch2)|CMDTXT_NOMORE,
7312 #define CMDTXT_NCMD (CMDTXT_NSEMI + 3)
7313 #define CMDTXT_NPIPE (CMDTXT_NCMD)
7314 #define CMDTXT_NCASE (CMDTXT_NCMD)
7315 #define CMDTXT_NTO (CMDTXT_NCMD)
7316 #define CMDTXT_NFROM (CMDTXT_NCMD)
7317 #define CMDTXT_NFROMTO (CMDTXT_NCMD)
7318 #define CMDTXT_NAPPEND (CMDTXT_NCMD)
7319 #define CMDTXT_NTOOV (CMDTXT_NCMD)
7320 #define CMDTXT_NTOFD (CMDTXT_NCMD)
7321 #define CMDTXT_NFROMFD (CMDTXT_NCMD)
7323 #define CMDTXT_NREDIR (CMDTXT_NPIPE + 1)
7324 #define CMDTXT_NBACKGND (CMDTXT_NREDIR)
7325 offsetof(union node, nredir.n)|CMDTXT_NOMORE,
7326 #define CMDTXT_NSUBSHELL (CMDTXT_NBACKGND + 1)
7327 (1*2)|CMDTXT_STRING,
7328 offsetof(union node, nredir.n),
7329 (2*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7330 #define CMDTXT_NAND (CMDTXT_NSUBSHELL + 3)
7331 offsetof(union node, nbinary.ch1),
7332 (3*2)|CMDTXT_STRING,
7333 offsetof(union node, nbinary.ch2)|CMDTXT_NOMORE,
7334 #define CMDTXT_NOR (CMDTXT_NAND + 3)
7335 offsetof(union node, nbinary.ch1),
7336 (4*2)|CMDTXT_STRING,
7337 offsetof(union node, nbinary.ch2)|CMDTXT_NOMORE,
7338 #define CMDTXT_NIF (CMDTXT_NOR + 3)
7339 (5*2)|CMDTXT_STRING,
7340 offsetof(union node, nif.test),
7341 (6*2)|CMDTXT_STRING,
7342 offsetof(union node, nif.ifpart),
7343 (7*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7344 #define CMDTXT_NWHILE (CMDTXT_NIF + 5)
7345 (8*2)|CMDTXT_STRING,
7346 offsetof(union node, nbinary.ch1),
7347 (9*2)|CMDTXT_STRING,
7348 offsetof(union node, nbinary.ch2),
7349 (10*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7350 #define CMDTXT_NUNTIL (CMDTXT_NWHILE + 5)
7351 (11*2)|CMDTXT_STRING,
7352 offsetof(union node, nbinary.ch1),
7353 (9*2)|CMDTXT_STRING,
7354 offsetof(union node, nbinary.ch2),
7355 (10*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7356 #define CMDTXT_NFOR (CMDTXT_NUNTIL + 5)
7357 (12*2)|CMDTXT_STRING,
7358 offsetof(union node, nfor.var)|CMDTXT_CHARPTR,
7359 (13*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7360 #define CMDTXT_NCLIST (CMDTXT_NFOR + 3) /* TODO: IS THIS CORRECT??? */
7361 #define CMDTXT_NNOT (CMDTXT_NCLIST) /* TODO: IS THIS CORRECT??? */
7362 (15*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7363 #define CMDTXT_NDEFUN (CMDTXT_NCLIST + 1)
7364 offsetof(union node, narg.text)|CMDTXT_CHARPTR,
7365 (16*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7366 #define CMDTXT_NARG (CMDTXT_NDEFUN + 2)
7367 offsetof(union node, narg.text)|CMDTXT_CHARPTR|CMDTXT_NOMORE,
7368 #define CMDTXT_NHERE (CMDTXT_NARG + 1)
7369 #define CMDTXT_NXHERE (CMDTXT_NHERE)
7370 (17*2)|CMDTXT_STRING|CMDTXT_NOMORE,
7373 #if CMDTXT_NXHERE != 36
7374 #error CMDTXT_NXHERE
7377 static const unsigned char cmdtxt_ops_index[26] = {
7407 cmdtxt(const union node *n)
7414 p = cmdtxt_ops + (int) cmdtxt_ops_index[n->type];
7415 if ((*p & CMDTXT_SPECIAL) != CMDTXT_SPECIAL) { /* normal case */
7417 if (*p & CMDTXT_STRING) { /* output fixed string */
7418 cmdputs(cmdtxt_strings[((int)(*p & CMDTXT_OFFSETMASK) >> 1)]);
7420 const char *pf = ((const char *) n)
7421 + ((int)(*p & CMDTXT_OFFSETMASK));
7422 if (*p & CMDTXT_CHARPTR) { /* output dynamic string */
7423 cmdputs(*((const char **) pf));
7424 } else { /* output field */
7425 cmdtxt(*((const union node **) pf));
7428 } while (!(*p++ & CMDTXT_NOMORE));
7429 } else if (n->type == NCMD) {
7431 for (np = n->ncmd.args ; np ; np = np->narg.next) {
7436 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
7440 } else if (n->type == NPIPE) {
7441 struct nodelist *lp;
7442 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
7447 } else if (n->type == NCASE) {
7448 cmdputs(cmdtxt_strings[14]);
7449 cmdputs(n->ncase.expr->narg.text);
7450 cmdputs(cmdtxt_strings[13]);
7452 #if (NTO != 16) || (NFROM != 17) || (NFROMTO != 18) || (NAPPEND != 19) || (NTOOV != 20) || (NTOFD != 21) || (NFROMFD != 22)
7453 #error Assumption violated regarding range and ordering of NTO ... NFROMFD!
7458 assert((n->type >= NTO) && (n->type <= NFROMFD));
7461 p = redir_strings[n->type - NTO];
7462 if (n->nfile.fd != ('>' == *p)) {
7463 s[0] = n->nfile.fd + '0';
7468 if (n->type >= NTOFD) {
7469 s[0] = n->ndup.dupfd + '0';
7473 cmdtxt(n->nfile.fname);
7477 #else /* CMDTXT_TABLE */
7479 cmdtxt(const union node *n)
7482 struct nodelist *lp;
7491 cmdtxt(n->nbinary.ch1);
7493 cmdtxt(n->nbinary.ch2);
7496 cmdtxt(n->nbinary.ch1);
7498 cmdtxt(n->nbinary.ch2);
7501 cmdtxt(n->nbinary.ch1);
7503 cmdtxt(n->nbinary.ch2);
7506 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
7514 cmdtxt(n->nredir.n);
7519 cmdtxt(n->nredir.n);
7523 cmdtxt(n->nif.test);
7525 cmdtxt(n->nif.ifpart);
7534 cmdtxt(n->nbinary.ch1);
7536 cmdtxt(n->nbinary.ch2);
7541 cmdputs(n->nfor.var);
7546 cmdputs(n->ncase.expr->narg.text);
7550 cmdputs(n->narg.text);
7554 for (np = n->ncmd.args ; np ; np = np->narg.next) {
7559 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
7565 cmdputs(n->narg.text);
7568 p = ">"; i = 1; goto redir;
7570 p = ">>"; i = 1; goto redir;
7572 p = ">&"; i = 1; goto redir;
7574 p = ">|"; i = 1; goto redir;
7576 p = "<"; i = 0; goto redir;
7578 p = "<&"; i = 0; goto redir;
7580 p = "<>"; i = 0; goto redir;
7582 if (n->nfile.fd != i) {
7583 s[0] = n->nfile.fd + '0';
7588 if (n->type == NTOFD || n->type == NFROMFD) {
7589 s[0] = n->ndup.dupfd + '0';
7593 cmdtxt(n->nfile.fname);
7605 #endif /* CMDTXT_TABLE */
7608 commandtext(const union node *n)
7612 cmdnextc = name = ckmalloc(MAXCMDTEXT);
7613 cmdnleft = MAXCMDTEXT - 4;
7620 static void waitonint(int sig) {
7625 * Routines to check for mail. (Perhaps make part of main.c?)
7629 #define MAXMBOXES 10
7632 static int nmboxes; /* number of mailboxes */
7633 static time_t mailtime[MAXMBOXES]; /* times of mailboxes */
7638 * Print appropriate message(s) if mail has arrived. If the argument is
7639 * nozero, then the value of MAIL has changed, so we just update the
7650 struct stackmark smark;
7657 setstackmark(&smark);
7658 mpath = mpathset()? mpathval() : mailval();
7659 for (i = 0 ; i < nmboxes ; i++) {
7660 p = padvance(&mpath, nullstr);
7665 for (q = p ; *q ; q++);
7670 q[-1] = '\0'; /* delete trailing '/' */
7671 if (stat(p, &statb) < 0)
7673 if (statb.st_size > mailtime[i] && ! silent) {
7675 pathopt? pathopt : "you have mail");
7677 mailtime[i] = statb.st_size;
7680 popstackmark(&smark);
7686 static short profile_buf[16384];
7690 static void read_profile (const char *);
7691 static void cmdloop (int);
7692 static void options (int);
7693 static void setoption (int, int);
7694 static void procargs (int, char **);
7698 * Main routine. We initialize things, parse the arguments, execute
7699 * profiles if we're a login shell, and then call cmdloop to execute
7700 * commands. The setjmp call sets up the location to jump to when an
7701 * exception occurs. When an exception occurs the variable "state"
7702 * is used to figure out how far we had gotten.
7706 ash_main(argc, argv)
7710 struct jmploc jmploc;
7711 struct stackmark smark;
7715 BLTINCMD = find_builtin("builtin");
7716 EXECCMD = find_builtin("exec");
7717 EVALCMD = find_builtin("eval");
7719 #ifndef BB_FEATURE_SH_FANCY_PROMPT
7725 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7727 #if defined(linux) || defined(__GNU__)
7728 signal(SIGCHLD, SIG_DFL);
7731 if (setjmp(jmploc.loc)) {
7734 * When a shell procedure is executed, we raise the
7735 * exception EXSHELLPROC to clean up before executing
7736 * the shell procedure.
7738 if (exception == EXSHELLPROC) {
7744 if (exception == EXEXEC) {
7745 exitstatus = exerrno;
7746 } else if (exception == EXERROR) {
7749 if (state == 0 || iflag == 0 || ! rootshell)
7750 exitshell(exitstatus);
7753 if (exception == EXINT) {
7756 popstackmark(&smark);
7757 FORCEINTON; /* enable interrupts */
7760 else if (state == 2)
7762 else if (state == 3)
7770 trputs("Shell args: "); trargs(argv);
7775 setstackmark(&smark);
7776 procargs(argc, argv);
7777 if (argv[0] && argv[0][0] == '-') {
7779 read_profile("/etc/profile");
7782 read_profile(".profile");
7787 if (getuid() == geteuid() && getgid() == getegid()) {
7789 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
7791 read_profile(shinit);
7798 if (sflag == 0 || minusc) {
7799 static const char sigs[] = {
7800 SIGINT, SIGQUIT, SIGHUP,
7806 #define SIGSSIZE ((sizeof(sigs)/sizeof(sigs[0])) - 1) /* trailing nul */
7809 for (i = 0; i < SIGSSIZE; i++)
7814 evalstring(minusc, 0);
7816 if (sflag || minusc == NULL) {
7817 state4: /* XXX ??? - why isn't this before the "if" statement */
7823 exitshell(exitstatus);
7829 * Read and execute commands. "Top" is nonzero for the top level command
7830 * loop; it turns on prompting if the shell is interactive.
7837 struct stackmark smark;
7841 TRACE(("cmdloop(%d) called\n", top));
7842 setstackmark(&smark);
7853 n = parsecmd(inter);
7854 /* showtree(n); DEBUG */
7856 if (!top || numeof >= 50)
7858 if (!stoppedjobs()) {
7861 out2str("\nUse \"exit\" to leave shell.\n");
7864 } else if (n != NULL && nflag == 0) {
7865 job_warning = (job_warning == 2) ? 1 : 0;
7869 popstackmark(&smark);
7870 setstackmark(&smark);
7871 if (evalskip == SKIPFILE) {
7876 popstackmark(&smark);
7882 * Read /etc/profile or .profile. Return on error.
7894 if ((fd = open(name, O_RDONLY)) >= 0)
7899 /* -q turns off -x and -v just when executing init files */
7900 /* Note: Might do a little redundant work, but reduces code size. */
7915 * Read a file containing shell functions.
7919 readcmdfile(const char *name)
7924 if ((fd = open(name, O_RDONLY)) >= 0)
7927 error("Can't open %s", name);
7936 * Take commands from a file. To be compatable we should do a path
7937 * search for the file, which is necessary to find sub-commands.
7941 static inline char *
7942 find_dot_file(char *mybasename)
7945 const char *path = pathval();
7948 /* don't try this for absolute or relative paths */
7949 if (strchr(mybasename, '/'))
7952 while ((fullname = padvance(&path, mybasename)) != NULL) {
7953 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
7955 * Don't bother freeing here, since it will
7956 * be freed by the caller.
7960 stunalloc(fullname);
7963 /* not found in the PATH */
7964 error("%s: not found", mybasename);
7976 for (sp = cmdenviron; sp ; sp = sp->next)
7977 setvareq(savestr(sp->text), VSTRFIXED|VTEXTFIXED);
7979 if (argc >= 2) { /* That's what SVR2 does */
7981 struct stackmark smark;
7983 setstackmark(&smark);
7984 fullname = find_dot_file(argv[1]);
7985 setinputfile(fullname, 1);
7986 commandname = fullname;
7989 popstackmark(&smark);
8003 exitstatus = number(argv[1]);
8005 exitstatus = oexitstatus;
8006 exitshell(exitstatus);
8015 nbytes = ALIGN(nbytes);
8016 if (nbytes > stacknleft) {
8018 struct stack_block *sp;
8021 if (blocksize < MINSIZE)
8022 blocksize = MINSIZE;
8024 sp = ckmalloc(sizeof(struct stack_block) - MINSIZE + blocksize);
8026 stacknxt = sp->space;
8027 stacknleft = blocksize;
8033 stacknleft -= nbytes;
8039 stunalloc(pointer p)
8042 if (p == NULL) { /*DEBUG */
8043 write(2, "stunalloc\n", 10);
8047 if (!(stacknxt >= (char *)p && (char *)p >= stackp->space)) {
8050 stacknleft += stacknxt - (char *)p;
8056 setstackmark(struct stackmark *mark)
8058 mark->stackp = stackp;
8059 mark->stacknxt = stacknxt;
8060 mark->stacknleft = stacknleft;
8061 mark->marknext = markp;
8067 popstackmark(struct stackmark *mark)
8069 struct stack_block *sp;
8072 markp = mark->marknext;
8073 while (stackp != mark->stackp) {
8078 stacknxt = mark->stacknxt;
8079 stacknleft = mark->stacknleft;
8085 * When the parser reads in a string, it wants to stick the string on the
8086 * stack and only adjust the stack pointer when it knows how big the
8087 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8088 * of space on top of the stack and stackblocklen returns the length of
8089 * this block. Growstackblock will grow this space by at least one byte,
8090 * possibly moving it (like realloc). Grabstackblock actually allocates the
8091 * part of the block that has been used.
8095 growstackblock(void) {
8097 int newlen = ALIGN(stacknleft * 2 + 100);
8098 char *oldspace = stacknxt;
8099 int oldlen = stacknleft;
8100 struct stack_block *sp;
8101 struct stack_block *oldstackp;
8103 if (stacknxt == stackp->space && stackp != &stackbase) {
8108 sp = ckrealloc((pointer)sp, sizeof(struct stack_block) - MINSIZE + newlen);
8111 stacknxt = sp->space;
8112 stacknleft = newlen;
8114 /* Stack marks pointing to the start of the old block
8115 * must be relocated to point to the new block
8117 struct stackmark *xmark;
8119 while (xmark != NULL && xmark->stackp == oldstackp) {
8120 xmark->stackp = stackp;
8121 xmark->stacknxt = stacknxt;
8122 xmark->stacknleft = stacknleft;
8123 xmark = xmark->marknext;
8128 p = stalloc(newlen);
8129 memcpy(p, oldspace, oldlen);
8130 stacknxt = p; /* free the space */
8131 stacknleft += newlen; /* we just allocated */
8138 grabstackblock(int len)
8148 * The following routines are somewhat easier to use that the above.
8149 * The user declares a variable of type STACKSTR, which may be declared
8150 * to be a register. The macro STARTSTACKSTR initializes things. Then
8151 * the user uses the macro STPUTC to add characters to the string. In
8152 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8153 * grown as necessary. When the user is done, she can just leave the
8154 * string there and refer to it using stackblock(). Or she can allocate
8155 * the space for it using grabstackstr(). If it is necessary to allow
8156 * someone else to use the stack temporarily and then continue to grow
8157 * the string, the user should use grabstack to allocate the space, and
8158 * then call ungrabstr(p) to return to the previous mode of operation.
8160 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8161 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8162 * is space for at least one character.
8167 growstackstr(void) {
8168 int len = stackblocksize();
8169 if (herefd >= 0 && len >= 1024) {
8170 xwrite(herefd, stackblock(), len);
8171 sstrnleft = len - 1;
8172 return stackblock();
8175 sstrnleft = stackblocksize() - len - 1;
8176 return stackblock() + len;
8181 * Called from CHECKSTRSPACE.
8185 makestrspace(size_t newlen) {
8186 int len = stackblocksize() - sstrnleft;
8189 sstrnleft = stackblocksize() - len;
8190 } while (sstrnleft < newlen);
8191 return stackblock() + len;
8197 ungrabstackstr(char *s, char *p)
8199 stacknleft += stacknxt - s;
8201 sstrnleft = stacknleft - (p - s);
8204 * Miscelaneous builtins.
8210 #if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
8211 typedef long rlim_t;
8217 * The read builtin. The -e option causes backslashes to escape the
8218 * following character.
8220 * This uses unbuffered input, which may be avoidable in some cases.
8224 readcmd(int argc, char **argv)
8239 while ((i = nextopt("p:r")) != '\0') {
8245 if (prompt && isatty(0)) {
8246 out2str(prompt); /* read without cmdedit */
8249 if (*(ap = argptr) == NULL)
8251 if ((ifs = bltinlookup("IFS")) == NULL)
8258 if (read(0, &c, 1) != 1) {
8270 if (!rflag && c == '\\') {
8276 if (startword && *ifs == ' ' && strchr(ifs, c)) {
8280 if (backslash && c == '\\') {
8281 if (read(0, &c, 1) != 1) {
8286 } else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
8288 setvar(*ap, stackblock(), 0);
8297 /* Remove trailing blanks */
8298 while (stackblock() <= --p && strchr(ifs, *p) != NULL)
8300 setvar(*ap, stackblock(), 0);
8301 while (*++ap != NULL)
8302 setvar(*ap, nullstr, 0);
8309 umaskcmd(argc, argv)
8313 static const char permuser[3] = "ugo";
8314 static const char permmode[3] = "rwx";
8315 static const short int permmask[] = {
8316 S_IRUSR, S_IWUSR, S_IXUSR,
8317 S_IRGRP, S_IWGRP, S_IXGRP,
8318 S_IROTH, S_IWOTH, S_IXOTH
8324 int symbolic_mode = 0;
8326 while (nextopt("S") != '\0') {
8335 if ((ap = *argptr) == NULL) {
8336 if (symbolic_mode) {
8339 for (i=0 ; i<3 ; i++) {
8343 for (j=0 ; j<3 ; j++) {
8344 if ((mask & permmask[3*i+j]) == 0) {
8353 printf("%.4o\n", mask);
8356 if (is_digit((unsigned char)*ap)) {
8359 if (*ap >= '8' || *ap < '0')
8360 error("Illegal number: %s", argv[1]);
8361 mask = (mask << 3) + (*ap - '0');
8362 } while (*++ap != '\0');
8365 mask = ~mask & 0777;
8366 if (parse_mode(ap, &mask) == FALSE) {
8367 error("Illegal mode: %s", ap);
8369 umask(~mask & 0777);
8378 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
8379 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
8380 * ash by J.T. Conklin.
8388 short factor; /* multiply by to get rlim_{cur,max} values */
8391 static const struct limits limits[] = {
8393 { "time(seconds)", RLIMIT_CPU, 1 },
8396 { "file(blocks)", RLIMIT_FSIZE, 512 },
8399 { "data(kbytes)", RLIMIT_DATA, 1024 },
8402 { "stack(kbytes)", RLIMIT_STACK, 1024 },
8405 { "coredump(blocks)", RLIMIT_CORE, 512 },
8408 { "memory(kbytes)", RLIMIT_RSS, 1024 },
8410 #ifdef RLIMIT_MEMLOCK
8411 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024 },
8414 { "process(processes)", RLIMIT_NPROC, 1 },
8416 #ifdef RLIMIT_NOFILE
8417 { "nofiles(descriptors)", RLIMIT_NOFILE, 1 },
8420 { "vmemory(kbytes)", RLIMIT_VMEM, 1024 },
8423 { "swap(kbytes)", RLIMIT_SWAP, 1024 },
8429 ulimitcmd(argc, argv)
8433 static const char unlimited_string[] = "unlimited";
8436 enum { SOFT = 0x1, HARD = 0x2 }
8438 const struct limits *l;
8441 struct rlimit limit;
8445 while ((optc = nextopt("HSa"
8464 #ifdef RLIMIT_MEMLOCK
8470 #ifdef RLIMIT_NOFILE
8482 } else if (optc == 'S') {
8484 } else if (optc == 'a') {
8491 for (l = limits; l->name; l++) {
8492 if(l->name[0] == what)
8494 if(l->name[1]=='w' && what=='w')
8498 set = *argptr ? 1 : 0;
8502 if (all || argptr[1])
8503 error("too many arguments");
8504 if (strcmp(p, unlimited_string) == 0)
8505 val = RLIM_INFINITY;
8509 while ((c = *p++) >= '0' && c <= '9')
8511 val = (val * 10) + (long)(c - '0');
8512 if (val < (rlim_t) 0)
8516 error("bad number");
8522 for (l = limits; l->name; l++) {
8523 printf("%-20s ", l->name);
8524 getrlimit(l->cmd, &limit);
8527 val = limit.rlim_cur;
8528 else if (how & HARD)
8529 val = limit.rlim_max;
8531 if (val == RLIM_INFINITY)
8532 puts(unlimited_string);
8536 printf("%lld\n", (long long) val);
8549 getrlimit(l->cmd, &limit);
8551 limit.rlim_max = val;
8553 limit.rlim_cur = val;
8554 if (setrlimit(l->cmd, &limit) < 0)
8555 error("error setting limit (%m)");
8559 * prefix -- see if pfx is a prefix of string.
8563 prefix(char const *pfx, char const *string)
8566 if (*pfx++ != *string++)
8573 * Return true if s is a string of digits, and save munber in intptr
8578 is_number(const char *p, int *intptr)
8586 ret += digit_val(*p);
8588 } while (*p != '\0');
8595 * Convert a string of digits to an integer, printing an error message on
8600 number(const char *s)
8603 if (! is_number(s, &i))
8604 error("Illegal number: %s", s);
8609 * Produce a possibly single quoted string suitable as input to the shell.
8610 * The return string is allocated on the stack.
8614 single_quote(const char *s) {
8621 size_t len1, len1p, len2, len2p;
8623 len1 = strcspn(s, "'");
8624 len2 = strspn(s + len1, "'");
8626 len1p = len1 ? len1 + 2 : len1;
8627 len2p = len2 + ((len2 < 2) ? len2 : 2);
8629 CHECKSTRSPACE(len1p + len2p + 1, p);
8634 memcpy(p + 1, s, len1);
8642 memcpy(q + 1, s, len2);
8645 } else if (len2 == 1) {
8651 STADJUST(len1p + len2p, p);
8656 return grabstackstr(p);
8660 * Like strdup but works with the ash stack.
8664 sstrdup(const char *p)
8666 size_t len = strlen(p) + 1;
8667 return memcpy(stalloc(len), p, len);
8672 * Routine for dealing with parsed shell commands.
8676 static void sizenodelist (const struct nodelist *);
8677 static struct nodelist *copynodelist (const struct nodelist *);
8678 static char *nodesavestr (const char *);
8680 #define CALCSIZE_TABLE
8681 #define COPYNODE_TABLE
8682 #if defined(CALCSIZE_TABLE) || defined(COPYNODE_TABLE)
8684 * To collect a lot of redundant code in case statements for copynode()
8685 * and calcsize(), we implement a mini language here. Each type of node
8686 * struct has an associated instruction sequence that operates on its
8687 * members via their offsets. The instruction are pack in unsigned chars
8688 * with format IIDDDDDE where the bits are
8689 * I : part of the instruction opcode, which are
8690 * 00 : member is a pointer to another node
8691 * 40 : member is an integer
8692 * 80 : member is a pointer to a nodelist
8693 * CC : member is a pointer to a char string
8694 * D : data - the actual offset of the member to operate on in the struct
8695 * (since we assume bit 0 is set, it is not shifted)
8696 * E : flag signaling end of instruction sequence
8698 * WARNING: In order to handle larger offsets for 64bit archs, this code
8699 * assumes that no offset can be an odd number and stores the
8700 * end-of-instructions flag in bit 0.
8703 #define NODE_INTEGER 0x40
8704 #define NODE_NODELIST 0x80
8705 #define NODE_CHARPTR 0xC0
8706 #define NODE_NOMORE 0x01 /* Note: no offset should be odd (aligned)*/
8707 #define NODE_MBRMASK 0xC0
8708 #define NODE_OFFSETMASK 0x3E
8710 static const unsigned char copynode_ops[35] = {
8711 #define COPYNODE_OPS0 0
8712 offsetof(union node, nbinary.ch2),
8713 offsetof(union node, nbinary.ch1)|NODE_NOMORE,
8714 #define COPYNODE_OPS1 (COPYNODE_OPS0 + 2)
8715 offsetof(union node, ncmd.redirect),
8716 offsetof(union node, ncmd.args),
8717 offsetof(union node, ncmd.assign),
8718 offsetof(union node, ncmd.backgnd)|NODE_INTEGER|NODE_NOMORE,
8719 #define COPYNODE_OPS2 (COPYNODE_OPS1 + 4)
8720 offsetof(union node, npipe.cmdlist)|NODE_NODELIST,
8721 offsetof(union node, npipe.backgnd)|NODE_INTEGER|NODE_NOMORE,
8722 #define COPYNODE_OPS3 (COPYNODE_OPS2 + 2)
8723 offsetof(union node, nredir.redirect),
8724 offsetof(union node, nredir.n)|NODE_NOMORE,
8725 #define COPYNODE_OPS4 (COPYNODE_OPS3 + 2)
8726 offsetof(union node, nif.elsepart),
8727 offsetof(union node, nif.ifpart),
8728 offsetof(union node, nif.test)|NODE_NOMORE,
8729 #define COPYNODE_OPS5 (COPYNODE_OPS4 + 3)
8730 offsetof(union node, nfor.var)|NODE_CHARPTR,
8731 offsetof(union node, nfor.body),
8732 offsetof(union node, nfor.args)|NODE_NOMORE,
8733 #define COPYNODE_OPS6 (COPYNODE_OPS5 + 3)
8734 offsetof(union node, ncase.cases),
8735 offsetof(union node, ncase.expr)|NODE_NOMORE,
8736 #define COPYNODE_OPS7 (COPYNODE_OPS6 + 2)
8737 offsetof(union node, nclist.body),
8738 offsetof(union node, nclist.pattern),
8739 offsetof(union node, nclist.next)|NODE_NOMORE,
8740 #define COPYNODE_OPS8 (COPYNODE_OPS7 + 3)
8741 offsetof(union node, narg.backquote)|NODE_NODELIST,
8742 offsetof(union node, narg.text)|NODE_CHARPTR,
8743 offsetof(union node, narg.next)|NODE_NOMORE,
8744 #define COPYNODE_OPS9 (COPYNODE_OPS8 + 3)
8745 offsetof(union node, nfile.fname),
8746 offsetof(union node, nfile.fd)|NODE_INTEGER,
8747 offsetof(union node, nfile.next)|NODE_NOMORE,
8748 #define COPYNODE_OPS10 (COPYNODE_OPS9 + 3)
8749 offsetof(union node, ndup.vname),
8750 offsetof(union node, ndup.dupfd)|NODE_INTEGER,
8751 offsetof(union node, ndup.fd)|NODE_INTEGER,
8752 offsetof(union node, ndup.next)|NODE_NOMORE,
8753 #define COPYNODE_OPS11 (COPYNODE_OPS10 + 4)
8754 offsetof(union node, nhere.doc),
8755 offsetof(union node, nhere.fd)|NODE_INTEGER,
8756 offsetof(union node, nhere.next)|NODE_NOMORE,
8757 #define COPYNODE_OPS12 (COPYNODE_OPS11 + 3)
8758 offsetof(union node, nnot.com)|NODE_NOMORE,
8761 #if COPYNODE_OPS12 != 34
8762 #error COPYNODE_OPS12 is incorrect
8765 static const unsigned char copynode_ops_index[26] = {
8766 COPYNODE_OPS0, /* NSEMI */
8767 COPYNODE_OPS1, /* NCMD */
8768 COPYNODE_OPS2, /* NPIPE */
8769 COPYNODE_OPS3, /* NREDIR */
8770 COPYNODE_OPS3, /* NBACKGND */
8771 COPYNODE_OPS3, /* NSUBSHELL */
8772 COPYNODE_OPS0, /* NAND */
8773 COPYNODE_OPS0, /* NOR */
8774 COPYNODE_OPS4, /* NIF */
8775 COPYNODE_OPS0, /* NWHILE */
8776 COPYNODE_OPS0, /* NUNTIL */
8777 COPYNODE_OPS5, /* NFOR */
8778 COPYNODE_OPS6, /* NCASE */
8779 COPYNODE_OPS7, /* NCLIST */
8780 COPYNODE_OPS8, /* NDEFUN */
8781 COPYNODE_OPS8, /* NARG */
8782 COPYNODE_OPS9, /* NTO */
8783 COPYNODE_OPS9, /* NFROM */
8784 COPYNODE_OPS9, /* NFROMTO */
8785 COPYNODE_OPS9, /* NAPPEND */
8786 COPYNODE_OPS9, /* NTOOV */
8787 COPYNODE_OPS10, /* NTOFD */
8788 COPYNODE_OPS10, /* NFROMFD */
8789 COPYNODE_OPS11, /* NHERE */
8790 COPYNODE_OPS11, /* NXHERE */
8791 COPYNODE_OPS12, /* NNOT */
8794 #if NODE_CHARPTR != NODE_MBRMASK
8795 #error NODE_CHARPTR != NODE_MBRMASK!!!
8797 #endif /* defined(CALCSIZE_TABLE) || defined(COPYNODE_TABLE) */
8799 #ifdef COPYNODE_TABLE
8801 copynode(const union node *n)
8804 const unsigned char *p;
8810 new->type = n->type;
8811 funcblock = (char *) funcblock + (int) nodesize[n->type];
8812 p = copynode_ops + (int) copynode_ops_index[n->type];
8814 char *nn = ((char *) new) + ((int)(*p & NODE_OFFSETMASK));
8815 const char *no = ((const char *) n) + ((int)(*p & NODE_OFFSETMASK));
8817 if (!(*p & NODE_MBRMASK)) { /* standard node */
8818 *((union node **)nn) = copynode(*((const union node **) no));
8819 } else if ((*p & NODE_MBRMASK) == NODE_CHARPTR) { /* string */
8820 *((const char **)nn) = nodesavestr(*((const char **)no));
8821 } else if (*p & NODE_NODELIST) { /* nodelist */
8822 *((struct nodelist **)nn)
8823 = copynodelist(*((const struct nodelist **) no));
8824 } else { /* integer */
8825 *((int *) nn) = *((int *) no);
8827 } while (!(*p++ & NODE_NOMORE));
8830 #else /* COPYNODE_TABLE */
8832 copynode(const union node *n)
8839 funcblock = (char *) funcblock + nodesize[n->type];
8846 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8847 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8850 new->ncmd.redirect = copynode(n->ncmd.redirect);
8851 new->ncmd.args = copynode(n->ncmd.args);
8852 new->ncmd.assign = copynode(n->ncmd.assign);
8853 new->ncmd.backgnd = n->ncmd.backgnd;
8856 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8857 new->npipe.backgnd = n->npipe.backgnd;
8862 new->nredir.redirect = copynode(n->nredir.redirect);
8863 new->nredir.n = copynode(n->nredir.n);
8866 new->nif.elsepart = copynode(n->nif.elsepart);
8867 new->nif.ifpart = copynode(n->nif.ifpart);
8868 new->nif.test = copynode(n->nif.test);
8871 new->nfor.var = nodesavestr(n->nfor.var);
8872 new->nfor.body = copynode(n->nfor.body);
8873 new->nfor.args = copynode(n->nfor.args);
8876 new->ncase.cases = copynode(n->ncase.cases);
8877 new->ncase.expr = copynode(n->ncase.expr);
8880 new->nclist.body = copynode(n->nclist.body);
8881 new->nclist.pattern = copynode(n->nclist.pattern);
8882 new->nclist.next = copynode(n->nclist.next);
8886 new->narg.backquote = copynodelist(n->narg.backquote);
8887 new->narg.text = nodesavestr(n->narg.text);
8888 new->narg.next = copynode(n->narg.next);
8895 new->nfile.fname = copynode(n->nfile.fname);
8896 new->nfile.fd = n->nfile.fd;
8897 new->nfile.next = copynode(n->nfile.next);
8901 new->ndup.vname = copynode(n->ndup.vname);
8902 new->ndup.dupfd = n->ndup.dupfd;
8903 new->ndup.fd = n->ndup.fd;
8904 new->ndup.next = copynode(n->ndup.next);
8908 new->nhere.doc = copynode(n->nhere.doc);
8909 new->nhere.fd = n->nhere.fd;
8910 new->nhere.next = copynode(n->nhere.next);
8913 new->nnot.com = copynode(n->nnot.com);
8916 new->type = n->type;
8919 #endif /* COPYNODE_TABLE */
8921 #ifdef CALCSIZE_TABLE
8923 calcsize(const union node *n)
8925 const unsigned char *p;
8929 funcblocksize += (int) nodesize[n->type];
8931 p = copynode_ops + (int) copynode_ops_index[n->type];
8933 const char *no = ((const char *) n) + ((int)(*p & NODE_OFFSETMASK));
8935 if (!(*p & NODE_MBRMASK)) { /* standard node */
8936 calcsize(*((const union node **) no));
8937 } else if ((*p & NODE_MBRMASK) == NODE_CHARPTR) { /* string */
8938 funcstringsize += strlen(*((const char **)no)) + 1;
8939 } else if (*p & NODE_NODELIST) { /* nodelist */
8940 sizenodelist(*((const struct nodelist **) no));
8941 } /* else integer -- ignore */
8942 } while (!(*p++ & NODE_NOMORE));
8944 #else /* CALCSIZE_TABLE */
8946 calcsize(const union node *n)
8950 funcblocksize += nodesize[n->type];
8957 calcsize(n->nbinary.ch2);
8958 calcsize(n->nbinary.ch1);
8961 calcsize(n->ncmd.redirect);
8962 calcsize(n->ncmd.args);
8963 calcsize(n->ncmd.assign);
8966 sizenodelist(n->npipe.cmdlist);
8971 calcsize(n->nredir.redirect);
8972 calcsize(n->nredir.n);
8975 calcsize(n->nif.elsepart);
8976 calcsize(n->nif.ifpart);
8977 calcsize(n->nif.test);
8980 funcstringsize += strlen(n->nfor.var) + 1;
8981 calcsize(n->nfor.body);
8982 calcsize(n->nfor.args);
8985 calcsize(n->ncase.cases);
8986 calcsize(n->ncase.expr);
8989 calcsize(n->nclist.body);
8990 calcsize(n->nclist.pattern);
8991 calcsize(n->nclist.next);
8995 sizenodelist(n->narg.backquote);
8996 funcstringsize += strlen(n->narg.text) + 1;
8997 calcsize(n->narg.next);
9004 calcsize(n->nfile.fname);
9005 calcsize(n->nfile.next);
9009 calcsize(n->ndup.vname);
9010 calcsize(n->ndup.next);
9014 calcsize(n->nhere.doc);
9015 calcsize(n->nhere.next);
9018 calcsize(n->nnot.com);
9022 #endif /* CALCSIZE_TABLE */
9025 sizenodelist(const struct nodelist *lp)
9028 funcblocksize += ALIGN(sizeof(struct nodelist));
9035 static struct nodelist *
9036 copynodelist(const struct nodelist *lp)
9038 struct nodelist *start;
9039 struct nodelist **lpp;
9044 funcblock = (char *) funcblock + ALIGN(sizeof(struct nodelist));
9045 (*lpp)->n = copynode(lp->n);
9047 lpp = &(*lpp)->next;
9055 nodesavestr(const char *s)
9058 char *q = funcstring;
9059 char *rtn = funcstring;
9061 while ((*q++ = *p++) != '\0')
9068 static int getopts (char *, char *, char **, int *, int *);
9073 * Process the shell command line arguments.
9077 procargs(argc, argv)
9086 for (i = 0; i < NOPTS; i++)
9089 if (*argptr == NULL && minusc == NULL)
9091 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
9095 for (i = 0; i < NOPTS; i++)
9096 if (optent_val(i) == 2)
9099 if (sflag == 0 && minusc == NULL) {
9100 commandname = argv[0];
9102 setinputfile(arg0, 0);
9105 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
9106 if (argptr && minusc && *argptr)
9109 shellparam.p = argptr;
9110 shellparam.optind = 1;
9111 shellparam.optoff = -1;
9112 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
9114 shellparam.nparam++;
9123 * Process shell options. The global variable argptr contains a pointer
9124 * to the argument list; we advance it past the options.
9128 minus_o(const char *name, int val)
9133 out1str("Current option settings\n");
9134 for (i = 0; i < NOPTS; i++)
9135 printf("%-16s%s\n", optent_name(optlist[i]),
9136 optent_val(i) ? "on" : "off");
9138 for (i = 0; i < NOPTS; i++)
9139 if (equal(name, optent_name(optlist[i]))) {
9140 setoption(optent_letter(optlist[i]), val);
9143 error("Illegal option -o %s", name);
9149 options(int cmdline)
9157 while ((p = *argptr) != NULL) {
9159 if ((c = *p++) == '-') {
9161 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
9163 /* "-" means turn off -x and -v */
9166 /* "--" means reset params */
9167 else if (*argptr == NULL)
9170 break; /* "-" or "--" terminates options */
9172 } else if (c == '+') {
9178 while ((c = *p++) != '\0') {
9179 if (c == 'c' && cmdline) {
9181 #ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */
9185 if (q == NULL || minusc != NULL)
9186 error("Bad -c option");
9191 } else if (c == 'o') {
9192 minus_o(*argptr, val);
9204 setoption(int flag, int val)
9208 for (i = 0; i < NOPTS; i++)
9209 if (optent_letter(optlist[i]) == flag) {
9210 optent_val(i) = val;
9212 /* #%$ hack for ksh semantics */
9215 else if (flag == 'E')
9220 error("Illegal option -%c", flag);
9227 * Set the shell parameters.
9231 setparam(char **argv)
9237 for (nparam = 0 ; argv[nparam] ; nparam++);
9238 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
9240 *ap++ = savestr(*argv++);
9243 freeparam(&shellparam);
9244 shellparam.malloc = 1;
9245 shellparam.nparam = nparam;
9246 shellparam.p = newparam;
9247 shellparam.optind = 1;
9248 shellparam.optoff = -1;
9253 * Free the list of positional parameters.
9257 freeparam(volatile struct shparam *param)
9261 if (param->malloc) {
9262 for (ap = param->p ; *ap ; ap++)
9271 * The shift builtin command.
9275 shiftcmd(argc, argv)
9284 n = number(argv[1]);
9285 if (n > shellparam.nparam)
9286 error("can't shift that many");
9288 shellparam.nparam -= n;
9289 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
9290 if (shellparam.malloc)
9294 while ((*ap2++ = *ap1++) != NULL);
9295 shellparam.optind = 1;
9296 shellparam.optoff = -1;
9304 * The set command builtin.
9313 return showvarscmd(argc, argv);
9317 if (*argptr != NULL) {
9326 getoptsreset(const char *value)
9328 shellparam.optind = number(value);
9329 shellparam.optoff = -1;
9332 #ifdef BB_LOCALE_SUPPORT
9333 static void change_lc_all(const char *value)
9335 if(value != 0 && *value != 0)
9336 setlocale(LC_ALL, value);
9339 static void change_lc_ctype(const char *value)
9341 if(value != 0 && *value != 0)
9342 setlocale(LC_CTYPE, value);
9349 * The getopts builtin. Shellparam.optnext points to the next argument
9350 * to be processed. Shellparam.optptr points to the next character to
9351 * be processed in the current argument. If shellparam.optnext is NULL,
9352 * then it's the first time getopts has been called.
9356 getoptscmd(argc, argv)
9363 error("Usage: getopts optstring var [arg]");
9364 else if (argc == 3) {
9365 optbase = shellparam.p;
9366 if (shellparam.optind > shellparam.nparam + 1) {
9367 shellparam.optind = 1;
9368 shellparam.optoff = -1;
9373 if (shellparam.optind > argc - 2) {
9374 shellparam.optind = 1;
9375 shellparam.optoff = -1;
9379 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9380 &shellparam.optoff);
9384 * Safe version of setvar, returns 1 on success 0 on failure.
9388 setvarsafe(name, val, flags)
9389 const char *name, *val;
9392 struct jmploc jmploc;
9393 struct jmploc *volatile savehandler = handler;
9399 if (setjmp(jmploc.loc))
9403 setvar(name, val, flags);
9405 handler = savehandler;
9410 getopts(optstr, optvar, optfirst, myoptind, optoff)
9422 char **optnext = optfirst + *myoptind - 1;
9424 if (*myoptind <= 1 || *optoff < 0 || !(*(optnext - 1)) ||
9425 strlen(*(optnext - 1)) < *optoff)
9428 p = *(optnext - 1) + *optoff;
9429 if (p == NULL || *p == '\0') {
9430 /* Current word is done, advance */
9431 if (optnext == NULL)
9434 if (p == NULL || *p != '-' || *++p == '\0') {
9436 *myoptind = optnext - optfirst + 1;
9442 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
9447 for (q = optstr; *q != c; ) {
9449 if (optstr[0] == ':') {
9452 err |= setvarsafe("OPTARG", s, 0);
9455 out2fmt("Illegal option -%c\n", c);
9456 (void) unsetvar("OPTARG");
9466 if (*p == '\0' && (p = *optnext) == NULL) {
9467 if (optstr[0] == ':') {
9470 err |= setvarsafe("OPTARG", s, 0);
9474 out2fmt("No arg for -%c option\n", c);
9475 (void) unsetvar("OPTARG");
9483 setvarsafe("OPTARG", p, 0);
9487 setvarsafe("OPTARG", "", 0);
9488 *myoptind = optnext - optfirst + 1;
9495 *optoff = p ? p - *(optnext - 1) : -1;
9496 snprintf(s, sizeof(s), "%d", *myoptind);
9497 err |= setvarsafe("OPTIND", s, VNOFUNC);
9500 err |= setvarsafe(optvar, s, 0);
9511 * XXX - should get rid of. have all builtins use getopt(3). the
9512 * library getopt must have the BSD extension static variable "optreset"
9513 * otherwise it can't be used within the shell safely.
9515 * Standard option processing (a la getopt) for builtin routines. The
9516 * only argument that is passed to nextopt is the option string; the
9517 * other arguments are unnecessary. It return the character, or '\0' on
9522 nextopt(const char *optstring)
9528 if ((p = optptr) == NULL || *p == '\0') {
9530 if (p == NULL || *p != '-' || *++p == '\0')
9533 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
9537 for (q = optstring ; *q != c ; ) {
9539 error("Illegal option -%c", c);
9544 if (*p == '\0' && (p = *argptr++) == NULL)
9545 error("No arg for -%c option", c);
9562 out2fmt(const char *fmt, ...)
9566 vfprintf(stderr, fmt, ap);
9571 * Version of write which resumes after a signal is caught.
9575 xwrite(int fd, const char *buf, int nbytes)
9584 i = write(fd, buf, n);
9590 } else if (i == 0) {
9593 } else if (errno != EINTR) {
9601 * Shell command parser.
9604 #define EOFMARKLEN 79
9609 struct heredoc *next; /* next here document in list */
9610 union node *here; /* redirection node */
9611 char *eofmark; /* string indicating end of input */
9612 int striptabs; /* if set, strip leading tabs */
9615 static struct heredoc *heredoclist; /* list of here documents to read */
9616 static int parsebackquote; /* nonzero if we are inside backquotes */
9617 static int doprompt; /* if set, prompt the user */
9618 static int needprompt; /* true if interactive and at start of line */
9619 static int lasttoken; /* last token read */
9621 static char *wordtext; /* text of last word returned by readtoken */
9623 static struct nodelist *backquotelist;
9624 static union node *redirnode;
9625 static struct heredoc *heredoc;
9626 static int quoteflag; /* set if (part of) last token was quoted */
9627 static int startlinno; /* line # where last token started */
9630 static union node *list (int);
9631 static union node *andor (void);
9632 static union node *pipeline (void);
9633 static union node *command (void);
9634 static union node *simplecmd (void);
9635 static void parsefname (void);
9636 static void parseheredoc (void);
9637 static char peektoken (void);
9638 static int readtoken (void);
9639 static int xxreadtoken (void);
9640 static int readtoken1 (int, int, const char *, int);
9641 static int noexpand (char *);
9642 static void synexpect (int) __attribute__((noreturn));
9643 static void synerror (const char *) __attribute__((noreturn));
9644 static void setprompt (int);
9648 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9649 * valid parse tree indicating a blank line.)
9653 parsecmd(int interact)
9658 doprompt = interact;
9678 union node *n1, *n2, *n3;
9682 if (nlflag == 0 && peektoken())
9688 if (tok == TBACKGND) {
9689 if (n2->type == NCMD || n2->type == NPIPE) {
9690 n2->ncmd.backgnd = 1;
9691 } else if (n2->type == NREDIR) {
9692 n2->type = NBACKGND;
9694 n3 = (union node *)stalloc(sizeof (struct nredir));
9695 n3->type = NBACKGND;
9697 n3->nredir.redirect = NULL;
9705 n3 = (union node *)stalloc(sizeof (struct nbinary));
9707 n3->nbinary.ch1 = n1;
9708 n3->nbinary.ch2 = n2;
9732 pungetc(); /* push back EOF on input */
9747 union node *n1, *n2, *n3;
9753 if ((t = readtoken()) == TAND) {
9755 } else if (t == TOR) {
9763 n3 = (union node *)stalloc(sizeof (struct nbinary));
9765 n3->nbinary.ch1 = n1;
9766 n3->nbinary.ch2 = n2;
9775 union node *n1, *n2, *pipenode;
9776 struct nodelist *lp, *prev;
9780 TRACE(("pipeline: entered\n"));
9781 if (readtoken() == TNOT) {
9787 if (readtoken() == TPIPE) {
9788 pipenode = (union node *)stalloc(sizeof (struct npipe));
9789 pipenode->type = NPIPE;
9790 pipenode->npipe.backgnd = 0;
9791 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9792 pipenode->npipe.cmdlist = lp;
9796 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9800 } while (readtoken() == TPIPE);
9806 n2 = (union node *)stalloc(sizeof (struct nnot));
9818 union node *n1, *n2;
9819 union node *ap, **app;
9820 union node *cp, **cpp;
9821 union node *redir, **rpp;
9828 /* Check for redirection which may precede command */
9829 while (readtoken() == TREDIR) {
9830 *rpp = n2 = redirnode;
9831 rpp = &n2->nfile.next;
9836 switch (readtoken()) {
9838 n1 = (union node *)stalloc(sizeof (struct nif));
9840 n1->nif.test = list(0);
9841 if (readtoken() != TTHEN)
9843 n1->nif.ifpart = list(0);
9845 while (readtoken() == TELIF) {
9846 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
9847 n2 = n2->nif.elsepart;
9849 n2->nif.test = list(0);
9850 if (readtoken() != TTHEN)
9852 n2->nif.ifpart = list(0);
9854 if (lasttoken == TELSE)
9855 n2->nif.elsepart = list(0);
9857 n2->nif.elsepart = NULL;
9860 if (readtoken() != TFI)
9867 n1 = (union node *)stalloc(sizeof (struct nbinary));
9868 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
9869 n1->nbinary.ch1 = list(0);
9870 if ((got=readtoken()) != TDO) {
9871 TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
9874 n1->nbinary.ch2 = list(0);
9875 if (readtoken() != TDONE)
9881 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9882 synerror("Bad for loop variable");
9883 n1 = (union node *)stalloc(sizeof (struct nfor));
9885 n1->nfor.var = wordtext;
9887 if (readtoken() == TIN) {
9889 while (readtoken() == TWORD) {
9890 n2 = (union node *)stalloc(sizeof (struct narg));
9892 n2->narg.text = wordtext;
9893 n2->narg.backquote = backquotelist;
9895 app = &n2->narg.next;
9899 if (lasttoken != TNL && lasttoken != TSEMI)
9902 static char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
9904 n2 = (union node *)stalloc(sizeof (struct narg));
9906 n2->narg.text = argvars;
9907 n2->narg.backquote = NULL;
9908 n2->narg.next = NULL;
9911 * Newline or semicolon here is optional (but note
9912 * that the original Bourne shell only allowed NL).
9914 if (lasttoken != TNL && lasttoken != TSEMI)
9918 if (readtoken() != TDO)
9920 n1->nfor.body = list(0);
9921 if (readtoken() != TDONE)
9926 n1 = (union node *)stalloc(sizeof (struct ncase));
9928 if (readtoken() != TWORD)
9930 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
9932 n2->narg.text = wordtext;
9933 n2->narg.backquote = backquotelist;
9934 n2->narg.next = NULL;
9937 } while (readtoken() == TNL);
9938 if (lasttoken != TIN)
9939 synerror("expecting \"in\"");
9940 cpp = &n1->ncase.cases;
9941 checkkwd = 2, readtoken();
9943 if (lasttoken == TLP)
9945 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
9947 app = &cp->nclist.pattern;
9949 *app = ap = (union node *)stalloc(sizeof (struct narg));
9951 ap->narg.text = wordtext;
9952 ap->narg.backquote = backquotelist;
9953 if (checkkwd = 2, readtoken() != TPIPE)
9955 app = &ap->narg.next;
9958 ap->narg.next = NULL;
9959 if (lasttoken != TRP)
9961 cp->nclist.body = list(0);
9964 if ((t = readtoken()) != TESAC) {
9966 synexpect(TENDCASE);
9968 checkkwd = 2, readtoken();
9970 cpp = &cp->nclist.next;
9971 } while(lasttoken != TESAC);
9976 n1 = (union node *)stalloc(sizeof (struct nredir));
9977 n1->type = NSUBSHELL;
9978 n1->nredir.n = list(0);
9979 n1->nredir.redirect = NULL;
9980 if (readtoken() != TRP)
9986 if (readtoken() != TEND)
9990 /* Handle an empty command like other simple commands. */
9999 * An empty command before a ; doesn't make much sense, and
10000 * should certainly be disallowed in the case of `if ;'.
10013 /* Now check for redirection which may follow command */
10014 while (readtoken() == TREDIR) {
10015 *rpp = n2 = redirnode;
10016 rpp = &n2->nfile.next;
10022 if (n1->type != NSUBSHELL) {
10023 n2 = (union node *)stalloc(sizeof (struct nredir));
10028 n1->nredir.redirect = redir;
10035 static union node *
10037 union node *args, **app;
10038 union node *n = NULL;
10039 union node *vars, **vpp;
10040 union node **rpp, *redir;
10051 switch (readtoken()) {
10054 n = (union node *)stalloc(sizeof (struct narg));
10056 n->narg.text = wordtext;
10057 n->narg.backquote = backquotelist;
10058 if (lasttoken == TWORD) {
10060 app = &n->narg.next;
10063 vpp = &n->narg.next;
10067 *rpp = n = redirnode;
10068 rpp = &n->nfile.next;
10069 parsefname(); /* read name of redirection file */
10073 args && app == &args->narg.next &&
10076 /* We have a function */
10077 if (readtoken() != TRP)
10081 n->narg.next = command();
10094 n = (union node *)stalloc(sizeof (struct ncmd));
10096 n->ncmd.backgnd = 0;
10097 n->ncmd.args = args;
10098 n->ncmd.assign = vars;
10099 n->ncmd.redirect = redir;
10103 static union node *
10107 n = (union node *)stalloc(sizeof (struct narg));
10109 n->narg.next = NULL;
10110 n->narg.text = wordtext;
10111 n->narg.backquote = backquotelist;
10115 static void fixredir(union node *n, const char *text, int err)
10117 TRACE(("Fix redir %s %d\n", text, err));
10119 n->ndup.vname = NULL;
10121 if (is_digit(text[0]) && text[1] == '\0')
10122 n->ndup.dupfd = digit_val(text[0]);
10123 else if (text[0] == '-' && text[1] == '\0')
10124 n->ndup.dupfd = -1;
10128 synerror("Bad fd number");
10130 n->ndup.vname = makename();
10137 union node *n = redirnode;
10139 if (readtoken() != TWORD)
10141 if (n->type == NHERE) {
10142 struct heredoc *here = heredoc;
10146 if (quoteflag == 0)
10148 TRACE(("Here document %d\n", n->type));
10149 if (here->striptabs) {
10150 while (*wordtext == '\t')
10153 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
10154 synerror("Illegal eof marker for << redirection");
10155 rmescapes(wordtext);
10156 here->eofmark = wordtext;
10158 if (heredoclist == NULL)
10159 heredoclist = here;
10161 for (p = heredoclist ; p->next ; p = p->next);
10164 } else if (n->type == NTOFD || n->type == NFROMFD) {
10165 fixredir(n, wordtext, 0);
10167 n->nfile.fname = makename();
10173 * Input any here documents.
10178 struct heredoc *here;
10181 while (heredoclist) {
10182 here = heredoclist;
10183 heredoclist = here->next;
10188 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
10189 here->eofmark, here->striptabs);
10190 n = (union node *)stalloc(sizeof (struct narg));
10191 n->narg.type = NARG;
10192 n->narg.next = NULL;
10193 n->narg.text = wordtext;
10194 n->narg.backquote = backquotelist;
10195 here->here->nhere.doc = n;
10205 return tokname_array[t][0];
10213 int savecheckalias = checkalias;
10214 int savecheckkwd = checkkwd;
10219 int alreadyseen = tokpushback;
10229 checkalias = savecheckalias;
10236 if (checkkwd == 2) {
10245 * check for keywords
10247 if (t == TWORD && !quoteflag)
10249 const char *const *pp;
10251 if ((pp = findkwd(wordtext))) {
10252 lasttoken = t = pp - tokname_array;
10253 TRACE(("keyword %s recognized\n", tokname(t)));
10264 } else if (checkalias == 2 && isassignment(wordtext)) {
10265 lasttoken = t = TASSIGN;
10267 } else if (checkalias) {
10268 if (!quoteflag && (ap = lookupalias(wordtext, 1)) != NULL) {
10270 pushstring(ap->val, strlen(ap->val), ap);
10272 checkkwd = savecheckkwd;
10281 TRACE(("token %s %s\n", tokname(t), t == TWORD || t == TASSIGN ? wordtext : ""));
10283 TRACE(("reread token %s %s\n", tokname(t), t == TWORD || t == TASSIGN ? wordtext : ""));
10290 * Read the next input token.
10291 * If the token is a word, we set backquotelist to the list of cmds in
10292 * backquotes. We set quoteflag to true if any part of the word was
10294 * If the token is TREDIR, then we set redirnode to a structure containing
10296 * In all cases, the variable startlinno is set to the number of the line
10297 * on which the token starts.
10299 * [Change comment: here documents and internal procedures]
10300 * [Readtoken shouldn't have any arguments. Perhaps we should make the
10301 * word parsing code into a separate routine. In this case, readtoken
10302 * doesn't need to have any internal procedures, but parseword does.
10303 * We could also make parseoperator in essence the main routine, and
10304 * have parseword (readtoken1?) handle both words and redirection.]
10307 #define NEW_xxreadtoken
10308 #ifdef NEW_xxreadtoken
10310 static const char xxreadtoken_chars[] = "\n()&|;"; /* singles must be first! */
10311 static const char xxreadtoken_tokens[] = {
10312 TNL, TLP, TRP, /* only single occurrence allowed */
10313 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
10314 TEOF, /* corresponds to trailing nul */
10315 TAND, TOR, TENDCASE, /* if double occurrence */
10318 #define xxreadtoken_doubles \
10319 (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
10320 #define xxreadtoken_singles \
10321 (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
10335 startlinno = plinno;
10336 for (;;) { /* until token or start of word found */
10339 if ((c!=' ') && (c!='\t')
10345 while ((c = pgetc()) != '\n' && c != PEOF);
10347 } else if (c=='\\') {
10348 if (pgetc() != '\n') {
10352 startlinno = ++plinno;
10353 setprompt(doprompt ? 2 : 0);
10356 = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10361 needprompt = doprompt;
10364 p = strchr(xxreadtoken_chars, c);
10367 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10370 if (p-xxreadtoken_chars >= xxreadtoken_singles) {
10371 if (pgetc() == *p) { /* double occurrence? */
10372 p += xxreadtoken_doubles + 1;
10379 return lasttoken = xxreadtoken_tokens[p-xxreadtoken_chars];
10387 #define RETURN(token) return lasttoken = token
10401 startlinno = plinno;
10402 for (;;) { /* until token or start of word found */
10405 case ' ': case '\t':
10411 while ((c = pgetc()) != '\n' && c != PEOF);
10415 if (pgetc() == '\n') {
10416 startlinno = ++plinno;
10427 needprompt = doprompt;
10432 if (pgetc() == '&')
10437 if (pgetc() == '|')
10442 if (pgetc() == ';')
10455 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10462 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10463 * is not NULL, read a here document. In the latter case, eofmark is the
10464 * word which marks the end of the document and striptabs is true if
10465 * leading tabs should be stripped from the document. The argument firstc
10466 * is the first character of the input token or document.
10468 * Because C does not have internal subroutines, I have simulated them
10469 * using goto's to implement the subroutine linkage. The following macros
10470 * will run code that appears at the end of readtoken1.
10473 #define CHECKEND() {goto checkend; checkend_return:;}
10474 #define PARSEREDIR() {goto parseredir; parseredir_return:;}
10475 #define PARSESUB() {goto parsesub; parsesub_return:;}
10476 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10477 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10478 #define PARSEARITH() {goto parsearith; parsearith_return:;}
10481 readtoken1(int firstc, int syntax, const char *eofmark, int striptabs)
10486 char line[EOFMARKLEN + 1];
10487 struct nodelist *bqlist;
10490 int varnest; /* levels of variables expansion */
10491 int arinest; /* levels of arithmetic expansion */
10492 int parenlevel; /* levels of parens in arithmetic */
10493 int dqvarnest; /* levels of variables expansion within double quotes */
10495 int prevsyntax; /* syntax before arithmetic */
10497 /* Avoid longjmp clobbering */
10503 (void) &parenlevel;
10506 (void) &prevsyntax;
10510 startlinno = plinno;
10512 if (syntax == DQSYNTAX)
10521 STARTSTACKSTR(out);
10522 loop: { /* for each line, until end of word */
10523 CHECKEND(); /* set c to PEOF if at end of here document */
10524 for (;;) { /* until end of line or end of word */
10525 CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */
10526 switch(SIT(c,syntax)) {
10527 case CNL: /* '\n' */
10528 if (syntax == BASESYNTAX)
10529 goto endword; /* exit outer loop */
10537 goto loop; /* continue outer loop */
10542 if ((eofmark == NULL || dblquote) &&
10544 USTPUTC(CTLESC, out);
10547 case CBACK: /* backslash */
10550 USTPUTC('\\', out);
10552 } else if (c == '\n') {
10558 if (dblquote && c != '\\' && c != '`' && c != '$'
10559 && (c != '"' || eofmark != NULL))
10560 USTPUTC('\\', out);
10561 if (SIT(c,SQSYNTAX) == CCTL)
10562 USTPUTC(CTLESC, out);
10563 else if (eofmark == NULL)
10564 USTPUTC(CTLQUOTEMARK, out);
10570 if (eofmark == NULL)
10571 USTPUTC(CTLQUOTEMARK, out);
10575 if (eofmark == NULL)
10576 USTPUTC(CTLQUOTEMARK, out);
10581 if (eofmark != NULL && arinest == 0 &&
10586 syntax = ARISYNTAX;
10588 } else if (eofmark == NULL &&
10590 syntax = BASESYNTAX;
10596 case CVAR: /* '$' */
10597 PARSESUB(); /* parse substitution */
10599 case CENDVAR: /* '}' */
10602 if (dqvarnest > 0) {
10605 USTPUTC(CTLENDVAR, out);
10610 #ifdef ASH_MATH_SUPPORT
10611 case CLP: /* '(' in arithmetic */
10615 case CRP: /* ')' in arithmetic */
10616 if (parenlevel > 0) {
10620 if (pgetc() == ')') {
10621 if (--arinest == 0) {
10622 USTPUTC(CTLENDARI, out);
10623 syntax = prevsyntax;
10624 if (syntax == DQSYNTAX)
10632 * unbalanced parens
10633 * (don't 2nd guess - no error)
10641 case CBQUOTE: /* '`' */
10645 goto endword; /* exit outer loop */
10650 goto endword; /* exit outer loop */
10661 if (syntax == ARISYNTAX)
10662 synerror("Missing '))'");
10663 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10664 synerror("Unterminated quoted string");
10665 if (varnest != 0) {
10666 startlinno = plinno;
10667 synerror("Missing '}'");
10669 USTPUTC('\0', out);
10670 len = out - stackblock();
10671 out = stackblock();
10672 if (eofmark == NULL) {
10673 if ((c == '>' || c == '<')
10676 && (*out == '\0' || is_digit(*out))) {
10678 return lasttoken = TREDIR;
10683 quoteflag = quotef;
10684 backquotelist = bqlist;
10685 grabstackblock(len);
10687 return lasttoken = TWORD;
10688 /* end of readtoken routine */
10693 * Check to see whether we are at the end of the here document. When this
10694 * is called, c is set to the first character of the next input line. If
10695 * we are at the end of the here document, this routine sets the c to PEOF.
10706 while (c == '\t') {
10710 if (c == *eofmark) {
10711 if (pfgets(line, sizeof line) != NULL) {
10715 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10716 if (*p == '\n' && *q == '\0') {
10719 needprompt = doprompt;
10721 pushstring(line, strlen(line), NULL);
10726 goto checkend_return;
10731 * Parse a redirection operator. The variable "out" points to a string
10732 * specifying the fd to be redirected. The variable "c" contains the
10733 * first character of the redirection operator.
10740 np = (union node *)stalloc(sizeof (struct nfile));
10745 np->type = NAPPEND;
10754 } else { /* c == '<' */
10756 switch (c = pgetc()) {
10758 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10759 np = (union node *)stalloc(sizeof (struct nhere));
10763 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10764 heredoc->here = np;
10765 if ((c = pgetc()) == '-') {
10766 heredoc->striptabs = 1;
10768 heredoc->striptabs = 0;
10774 np->type = NFROMFD;
10778 np->type = NFROMTO;
10788 np->nfile.fd = digit_val(fd);
10790 goto parseredir_return;
10795 * Parse a substitution. At this point, we have read the dollar sign
10796 * and nothing else.
10804 static const char types[] = "}-+?=";
10809 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10813 } else if (c == '(') { /* $(command) or $((arith)) */
10814 if (pgetc() == '(') {
10821 USTPUTC(CTLVAR, out);
10822 typeloc = out - stackblock();
10823 USTPUTC(VSNORMAL, out);
10824 subtype = VSNORMAL;
10828 if ((c = pgetc()) == '}')
10831 subtype = VSLENGTH;
10836 if (c > PEOA && is_name(c)) {
10840 } while (c > PEOA && is_in_name(c));
10841 } else if (is_digit(c)) {
10845 } while (is_digit(c));
10847 else if (is_special(c)) {
10852 badsub: synerror("Bad substitution");
10856 if (subtype == 0) {
10863 p = strchr(types, c);
10866 subtype = p - types + VSNORMAL;
10872 subtype = c == '#' ? VSTRIMLEFT :
10885 if (dblquote || arinest)
10887 *(stackblock() + typeloc) = subtype | flags;
10888 if (subtype != VSNORMAL) {
10895 goto parsesub_return;
10900 * Called to parse command substitutions. Newstyle is set if the command
10901 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10902 * list of commands (passed by reference), and savelen is the number of
10903 * characters on the top of the stack which must be preserved.
10907 struct nodelist **nlpp;
10910 char *volatile str;
10911 struct jmploc jmploc;
10912 struct jmploc *volatile savehandler;
10916 (void) &saveprompt;
10919 savepbq = parsebackquote;
10920 if (setjmp(jmploc.loc)) {
10923 parsebackquote = 0;
10924 handler = savehandler;
10925 longjmp(handler->loc, 1);
10929 savelen = out - stackblock();
10931 str = ckmalloc(savelen);
10932 memcpy(str, stackblock(), savelen);
10934 savehandler = handler;
10938 /* We must read until the closing backquote, giving special
10939 treatment to some slashes, and then push the string and
10940 reread it as input, interpreting it normally. */
10947 STARTSTACKSTR(pout);
10953 switch (pc = pgetc()) {
10958 if ((pc = pgetc()) == '\n') {
10965 * If eating a newline, avoid putting
10966 * the newline into the new character
10967 * stream (via the STPUTC after the
10972 if (pc != '\\' && pc != '`' && pc != '$'
10973 && (!dblquote || pc != '"'))
10974 STPUTC('\\', pout);
10984 startlinno = plinno;
10985 synerror("EOF in backquote substitution");
10989 needprompt = doprompt;
10998 STPUTC('\0', pout);
10999 psavelen = pout - stackblock();
11000 if (psavelen > 0) {
11001 pstr = grabstackstr(pout);
11002 setinputstring(pstr);
11007 nlpp = &(*nlpp)->next;
11008 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
11009 (*nlpp)->next = NULL;
11010 parsebackquote = oldstyle;
11013 saveprompt = doprompt;
11020 doprompt = saveprompt;
11022 if (readtoken() != TRP)
11029 * Start reading from old file again, ignoring any pushed back
11030 * tokens left from the backquote parsing
11035 while (stackblocksize() <= savelen)
11037 STARTSTACKSTR(out);
11039 memcpy(out, str, savelen);
11040 STADJUST(savelen, out);
11046 parsebackquote = savepbq;
11047 handler = savehandler;
11048 if (arinest || dblquote)
11049 USTPUTC(CTLBACKQ | CTLQUOTE, out);
11051 USTPUTC(CTLBACKQ, out);
11053 goto parsebackq_oldreturn;
11055 goto parsebackq_newreturn;
11059 * Parse an arithmetic expansion (indicate start of one and set state)
11063 if (++arinest == 1) {
11064 prevsyntax = syntax;
11065 syntax = ARISYNTAX;
11066 USTPUTC(CTLARI, out);
11073 * we collapse embedded arithmetic expansion to
11074 * parenthesis, which should be equivalent
11078 goto parsearith_return;
11081 } /* end of readtoken */
11085 * Returns true if the text contains nothing to expand (no dollar signs
11097 while ((c = *p++) != '\0') {
11098 if (c == CTLQUOTEMARK)
11102 else if (SIT(c,BASESYNTAX) == CCTL)
11110 * Return true if the argument is a legal variable name (a letter or
11111 * underscore followed by zero or more letters, underscores, and digits).
11115 goodname(const char *name)
11123 if (! is_in_name(*p))
11131 * Called when an unexpected token is read during the parse. The argument
11132 * is the token that is expected, or -1 if more than one type of token can
11133 * occur at this point.
11143 l = sprintf(msg, "%s unexpected", tokname(lasttoken));
11145 sprintf(msg+l, " (expecting %s)", tokname(token));
11152 synerror(const char *msg)
11155 out2fmt("%s: %d: ", commandname, startlinno);
11156 out2fmt("Syntax error: %s\n", msg);
11157 error((char *)NULL);
11163 * called by editline -- any expansions to the prompt
11164 * should be added here.
11167 setprompt(int whichprompt)
11170 switch (whichprompt) {
11185 * Code for dealing with input/output redirection.
11188 #define EMPTY -2 /* marks an unused slot in redirtab */
11190 # define PIPESIZE 4096 /* amount of buffering in a pipe */
11192 # define PIPESIZE PIPE_BUF
11197 * Open a file in noclobber mode.
11198 * The code was copied from bash.
11201 noclobberopen(const char *fname)
11204 struct stat finfo, finfo2;
11207 * If the file exists and is a regular file, return an error
11210 r = stat(fname, &finfo);
11211 if (r == 0 && S_ISREG(finfo.st_mode)) {
11217 * If the file was not present (r != 0), make sure we open it
11218 * exclusively so that if it is created before we open it, our open
11219 * will fail. Make sure that we do not truncate an existing file.
11220 * Note that we don't turn on O_EXCL unless the stat failed -- if the
11221 * file was not a regular file, we leave O_EXCL off.
11224 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
11225 fd = open(fname, O_WRONLY|O_CREAT, 0666);
11227 /* If the open failed, return the file descriptor right away. */
11232 * OK, the open succeeded, but the file may have been changed from a
11233 * non-regular file to a regular file between the stat and the open.
11234 * We are assuming that the O_EXCL open handles the case where FILENAME
11235 * did not exist and is symlinked to an existing file between the stat
11240 * If we can open it and fstat the file descriptor, and neither check
11241 * revealed that it was a regular file, and the file has not been
11242 * replaced, return the file descriptor.
11244 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
11245 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
11248 /* The file has been replaced. badness. */
11255 * Handle here documents. Normally we fork off a process to write the
11256 * data to a pipe. If the document is short, we can stuff the data in
11257 * the pipe without forking.
11261 openhere(const union node *redir)
11267 error("Pipe call failed");
11268 if (redir->type == NHERE) {
11269 len = strlen(redir->nhere.doc->narg.text);
11270 if (len <= PIPESIZE) {
11271 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11275 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
11277 signal(SIGINT, SIG_IGN);
11278 signal(SIGQUIT, SIG_IGN);
11279 signal(SIGHUP, SIG_IGN);
11281 signal(SIGTSTP, SIG_IGN);
11283 signal(SIGPIPE, SIG_DFL);
11284 if (redir->type == NHERE)
11285 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11287 expandhere(redir->nhere.doc, pip[1]);
11297 openredirect(const union node *redir)
11302 switch (redir->nfile.type) {
11304 fname = redir->nfile.expfname;
11305 if ((f = open(fname, O_RDONLY)) < 0)
11309 fname = redir->nfile.expfname;
11310 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
11314 /* Take care of noclobber mode. */
11316 fname = redir->nfile.expfname;
11317 if ((f = noclobberopen(fname)) < 0)
11322 fname = redir->nfile.expfname;
11324 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
11327 if ((f = creat(fname, 0666)) < 0)
11332 fname = redir->nfile.expfname;
11334 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
11337 if ((f = open(fname, O_WRONLY)) < 0
11338 && (f = creat(fname, 0666)) < 0)
11340 lseek(f, (off_t)0, 2);
11347 /* Fall through to eliminate warning. */
11354 f = openhere(redir);
11360 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
11362 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11367 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11368 * old file descriptors are stashed away so that the redirection can be
11369 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11370 * standard output, and the standard error if it becomes a duplicate of
11375 redirect(union node *redir, int flags)
11378 struct redirtab *sv = NULL;
11383 int fd1dup = flags & REDIR_BACKQ;; /* stdout `cmd` redir to pipe */
11385 if (flags & REDIR_PUSH) {
11386 sv = ckmalloc(sizeof (struct redirtab));
11387 for (i = 0 ; i < 10 ; i++)
11388 sv->renamed[i] = EMPTY;
11389 sv->next = redirlist;
11392 for (n = redir ; n ; n = n->nfile.next) {
11395 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
11396 n->ndup.dupfd == fd)
11397 continue; /* redirect from/to same file descriptor */
11400 newfd = openredirect(n);
11401 if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
11404 } else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
11408 dupredirect(n, newfd, fd1dup);
11418 error("%d: %m", fd);
11424 if (flags & REDIR_PUSH) {
11425 sv->renamed[fd] = i;
11428 } else if (fd != newfd) {
11434 dupredirect(n, newfd, fd1dup);
11441 dupredirect(const union node *redir, int f, int fd1dup)
11443 int fd = redir->nfile.fd;
11447 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11448 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
11449 if (redir->ndup.dupfd!=1 || fd1dup!=1)
11450 dup_as_newfd(redir->ndup.dupfd, fd);
11456 dup_as_newfd(f, fd);
11465 * Undo the effects of the last redirection.
11471 struct redirtab *rp = redirlist;
11475 for (i = 0 ; i < 10 ; i++) {
11476 if (rp->renamed[i] != EMPTY) {
11480 if (rp->renamed[i] >= 0) {
11481 dup_as_newfd(rp->renamed[i], i);
11482 close(rp->renamed[i]);
11486 redirlist = rp->next;
11492 * Discard all saved file descriptors.
11497 struct redirtab *rp;
11500 for (rp = redirlist ; rp ; rp = rp->next) {
11501 for (i = 0 ; i < 10 ; i++) {
11502 if (rp->renamed[i] >= 0) {
11503 close(rp->renamed[i]);
11505 rp->renamed[i] = EMPTY;
11512 * Copy a file descriptor to be >= to. Returns -1
11513 * if the source file descriptor is closed, EMPTY if there are no unused
11514 * file descriptors left.
11518 dup_as_newfd(from, to)
11524 newfd = fcntl(from, F_DUPFD, to);
11526 if (errno == EMFILE)
11529 error("%d: %m", from);
11535 static void shtree (union node *, int, char *, FILE*);
11536 static void shcmd (union node *, FILE *);
11537 static void sharg (union node *, FILE *);
11538 static void indent (int, char *, FILE *);
11539 static void trstring (char *);
11546 trputs("showtree called\n");
11547 shtree(n, 1, NULL, stdout);
11552 shtree(n, ind, pfx, fp)
11558 struct nodelist *lp;
11564 indent(ind, pfx, fp);
11575 shtree(n->nbinary.ch1, ind, NULL, fp);
11578 shtree(n->nbinary.ch2, ind, NULL, fp);
11586 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
11591 if (n->npipe.backgnd)
11597 fprintf(fp, "<node type %d>", n->type);
11617 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11623 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11629 if ((np->nfile.type <= NFROMFD) && (np->nfile.type >= NTO)) {
11630 s = redir_strings[np->nfile.type - NTO];
11636 switch (np->nfile.type) {
11637 case NTO: s = ">"; dftfd = 1; break;
11638 case NAPPEND: s = ">>"; dftfd = 1; break;
11639 case NTOFD: s = ">&"; dftfd = 1; break;
11640 case NTOOV: s = ">|"; dftfd = 1; break;
11641 case NFROM: s = "<"; dftfd = 0; break;
11642 case NFROMFD: s = "<&"; dftfd = 0; break;
11643 case NFROMTO: s = "<>"; dftfd = 0; break;
11644 default: s = "*error*"; dftfd = 0; break;
11647 if (np->nfile.fd != dftfd)
11648 fprintf(fp, "%d", np->nfile.fd);
11650 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11651 fprintf(fp, "%d", np->ndup.dupfd);
11653 sharg(np->nfile.fname, fp);
11667 struct nodelist *bqlist;
11670 if (arg->type != NARG) {
11671 printf("<node type %d>\n", arg->type);
11675 bqlist = arg->narg.backquote;
11676 for (p = arg->narg.text ; *p ; p++) {
11685 if (subtype == VSLENGTH)
11691 if (subtype & VSNUL)
11694 switch (subtype & VSTYPE) {
11713 case VSTRIMLEFTMAX:
11720 case VSTRIMRIGHTMAX:
11727 printf("<subtype %d>", subtype);
11734 case CTLBACKQ|CTLQUOTE:
11737 shtree(bqlist->n, -1, NULL, fp);
11749 indent(amount, pfx, fp)
11756 for (i = 0 ; i < amount ; i++) {
11757 if (pfx && i == amount - 1)
11775 static int debug = 1;
11777 static int debug = 0;
11785 if (tracefile == NULL)
11787 putc(c, tracefile);
11793 trace(const char *fmt, ...)
11797 if (tracefile != NULL) {
11798 (void) vfprintf(tracefile, fmt, va);
11799 if (strchr(fmt, '\n'))
11800 (void) fflush(tracefile);
11810 if (tracefile == NULL)
11812 fputs(s, tracefile);
11813 if (strchr(s, '\n'))
11825 if (tracefile == NULL)
11827 putc('"', tracefile);
11828 for (p = s ; *p ; p++) {
11830 case '\n': c = 'n'; goto backslash;
11831 case '\t': c = 't'; goto backslash;
11832 case '\r': c = 'r'; goto backslash;
11833 case '"': c = '"'; goto backslash;
11834 case '\\': c = '\\'; goto backslash;
11835 case CTLESC: c = 'e'; goto backslash;
11836 case CTLVAR: c = 'v'; goto backslash;
11837 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
11838 case CTLBACKQ: c = 'q'; goto backslash;
11839 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
11840 backslash: putc('\\', tracefile);
11841 putc(c, tracefile);
11844 if (*p >= ' ' && *p <= '~')
11845 putc(*p, tracefile);
11847 putc('\\', tracefile);
11848 putc(*p >> 6 & 03, tracefile);
11849 putc(*p >> 3 & 07, tracefile);
11850 putc(*p & 07, tracefile);
11855 putc('"', tracefile);
11863 if (tracefile == NULL)
11868 putc(' ', tracefile);
11870 putc('\n', tracefile);
11885 #ifdef not_this_way
11888 if ((p = getenv("HOME")) == NULL) {
11889 if (geteuid() == 0)
11895 strcat(s, "/trace");
11898 strcpy(s, "./trace");
11899 #endif /* not_this_way */
11900 if ((tracefile = fopen(s, "a")) == NULL) {
11901 fprintf(stderr, "Can't open %s\n", s);
11905 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11906 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11908 fputs("\nTracing started.\n", tracefile);
11915 * The trap builtin.
11919 trapcmd(argc, argv)
11928 for (signo = 0 ; signo < NSIG ; signo++) {
11929 if (trap[signo] != NULL) {
11933 p = single_quote(trap[signo]);
11934 sn = sys_siglist[signo];
11936 sn = u_signal_names(0, &signo, 0);
11939 printf("trap -- %s %s\n", p, sn);
11951 if ((signo = decode_signal(*ap, 0)) < 0)
11952 error("%s: bad trap", *ap);
11955 if (action[0] == '-' && action[1] == '\0')
11958 action = savestr(action);
11961 ckfree(trap[signo]);
11962 trap[signo] = action;
11977 * Set the signal handler for the specified signal. The routine figures
11978 * out what it should be set to.
11982 setsignal(int signo)
11986 struct sigaction act;
11988 if ((t = trap[signo]) == NULL)
11990 else if (*t != '\0')
11994 if (rootshell && action == S_DFL) {
11997 if (iflag || minusc || sflag == 0)
12023 t = &sigmode[signo - 1];
12026 * current setting unknown
12028 if (sigaction(signo, 0, &act) == -1) {
12030 * Pretend it worked; maybe we should give a warning
12031 * here, but other shells don't. We don't alter
12032 * sigmode, so that we retry every time.
12036 if (act.sa_handler == SIG_IGN) {
12037 if (mflag && (signo == SIGTSTP ||
12038 signo == SIGTTIN || signo == SIGTTOU)) {
12039 *t = S_IGN; /* don't hard ignore these */
12043 *t = S_RESET; /* force to be set */
12046 if (*t == S_HARD_IGN || *t == action)
12048 act.sa_handler = ((action == S_CATCH) ? onsig
12049 : ((action == S_IGN) ? SIG_IGN : SIG_DFL));
12052 sigemptyset(&act.sa_mask);
12053 sigaction(signo, &act, 0);
12064 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
12065 signal(signo, SIG_IGN);
12067 sigmode[signo - 1] = S_HARD_IGN;
12078 if (signo == SIGINT && trap[SIGINT] == NULL) {
12082 gotsig[signo - 1] = 1;
12088 * Called to execute a trap. Perhaps we should avoid entering new trap
12089 * handlers while we are executing a trap handler.
12099 for (i = 1 ; ; i++) {
12106 savestatus=exitstatus;
12107 evalstring(trap[i], 0);
12108 exitstatus=savestatus;
12115 * Called to exit the shell.
12119 exitshell(int status)
12121 struct jmploc loc1, loc2;
12124 TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
12125 if (setjmp(loc1.loc)) {
12128 if (setjmp(loc2.loc)) {
12132 if ((p = trap[0]) != NULL && *p != '\0') {
12136 l1: handler = &loc2; /* probably unnecessary */
12145 static int decode_signal(const char *string, int minsig)
12148 const char *name = u_signal_names(string, &signo, minsig);
12150 return name ? signo : -1;
12153 static struct var **hashvar (const char *);
12154 static void showvars (const char *, int, int);
12155 static struct var **findvar (struct var **, const char *);
12158 * Initialize the varable symbol tables and import the environment
12162 * This routine initializes the builtin variables. It is called when the
12163 * shell is initialized and again when a shell procedure is spawned.
12168 const struct varinit *ip;
12172 for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
12173 if ((vp->flags & VEXPORT) == 0) {
12174 vpp = hashvar(ip->text);
12177 vp->text = strdup(ip->text);
12178 vp->flags = ip->flags;
12179 vp->func = ip->func;
12183 * PS1 depends on uid
12185 if ((vps1.flags & VEXPORT) == 0) {
12186 vpp = hashvar("PS1=");
12189 vps1.text = strdup(geteuid() ? "PS1=$ " : "PS1=# ");
12190 vps1.flags = VSTRFIXED|VTEXTFIXED;
12195 * Set the value of a variable. The flags argument is ored with the
12196 * flags of the variable. If val is NULL, the variable is unset.
12200 setvar(name, val, flags)
12201 const char *name, *val;
12217 if (! is_in_name(*p)) {
12218 if (*p == '\0' || *p == '=')
12224 namelen = p - name;
12226 error("%.*s: bad variable name", namelen, name);
12227 len = namelen + 2; /* 2 is space for '=' and '\0' */
12231 len += vallen = strlen(val);
12234 nameeq = ckmalloc(len);
12235 memcpy(nameeq, name, namelen);
12236 nameeq[namelen] = '=';
12238 memcpy(nameeq + namelen + 1, val, vallen + 1);
12240 nameeq[namelen + 1] = '\0';
12242 setvareq(nameeq, flags);
12249 * Same as setvar except that the variable and value are passed in
12250 * the first argument as name=value. Since the first argument will
12251 * be actually stored in the table, it should not be a string that
12260 struct var *vp, **vpp;
12263 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
12264 if ((vp = *findvar(vpp, s))) {
12265 if (vp->flags & VREADONLY) {
12266 size_t len = strchr(s, '=') - s;
12267 error("%.*s: is read only", len, s);
12271 if (vp->func && (flags & VNOFUNC) == 0)
12272 (*vp->func)(strchr(s, '=') + 1);
12274 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12277 vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
12278 vp->flags |= flags;
12282 * We could roll this to a function, to handle it as
12283 * a regular variable function callback, but why bother?
12285 if (iflag && (vp == &vmpath || (vp == &vmail && !mpathset())))
12291 vp = ckmalloc(sizeof (*vp));
12302 * Process a linked list of variable assignments.
12307 struct strlist *mylist;
12309 struct strlist *lp;
12312 for (lp = mylist ; lp ; lp = lp->next) {
12313 setvareq(savestr(lp->text), 0);
12321 * Find the value of a variable. Returns NULL if not set.
12324 static const char *
12330 if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
12331 return strchr(v->text, '=') + 1;
12339 * Search the environment of a builtin command.
12342 static const char *
12343 bltinlookup(const char *name)
12345 const struct strlist *sp;
12347 for (sp = cmdenviron ; sp ; sp = sp->next) {
12348 if (varequal(sp->text, name))
12349 return strchr(sp->text, '=') + 1;
12351 return lookupvar(name);
12357 * Generate a list of exported variables. This routine is used to construct
12358 * the third argument to execve when executing a program.
12370 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12371 for (vp = *vpp ; vp ; vp = vp->next)
12372 if (vp->flags & VEXPORT)
12375 ep = env = stalloc((nenv + 1) * sizeof *env);
12376 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12377 for (vp = *vpp ; vp ; vp = vp->next)
12378 if (vp->flags & VEXPORT)
12387 * Called when a shell procedure is invoked to clear out nonexported
12388 * variables. It is also necessary to reallocate variables of with
12389 * VSTACK set since these are currently allocated on the stack.
12395 struct var *vp, **prev;
12397 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12398 for (prev = vpp ; (vp = *prev) != NULL ; ) {
12399 if ((vp->flags & VEXPORT) == 0) {
12401 if ((vp->flags & VTEXTFIXED) == 0)
12403 if ((vp->flags & VSTRFIXED) == 0)
12406 if (vp->flags & VSTACK) {
12407 vp->text = savestr(vp->text);
12408 vp->flags &=~ VSTACK;
12420 * Command to list all variables which are set. Currently this command
12421 * is invoked from the set command when the set command is called without
12426 showvarscmd(argc, argv)
12430 showvars(nullstr, VUNSET, VUNSET);
12437 * The export and readonly commands.
12441 exportcmd(argc, argv)
12448 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12451 listsetvar(cmdenviron);
12452 pflag = (nextopt("p") == 'p');
12453 if (argc > 1 && !pflag) {
12454 while ((name = *argptr++) != NULL) {
12455 if ((p = strchr(name, '=')) != NULL) {
12458 if ((vp = *findvar(hashvar(name), name))) {
12463 setvar(name, p, flag);
12467 showvars(argv[0], flag, 0);
12474 * The "local" command.
12477 /* funcnest nonzero if we are currently evaluating a function */
12480 localcmd(argc, argv)
12487 error("Not in a function");
12488 while ((name = *argptr++) != NULL) {
12496 * Make a variable a local variable. When a variable is made local, it's
12497 * value and flags are saved in a localvar structure. The saved values
12498 * will be restored when the shell function returns. We handle the name
12499 * "-" as a special case.
12506 struct localvar *lvp;
12511 lvp = ckmalloc(sizeof (struct localvar));
12512 if (name[0] == '-' && name[1] == '\0') {
12514 p = ckmalloc(sizeof optet_vals);
12515 lvp->text = memcpy(p, optet_vals, sizeof optet_vals);
12518 vpp = hashvar(name);
12519 vp = *findvar(vpp, name);
12521 if (strchr(name, '='))
12522 setvareq(savestr(name), VSTRFIXED);
12524 setvar(name, NULL, VSTRFIXED);
12525 vp = *vpp; /* the new variable */
12527 lvp->flags = VUNSET;
12529 lvp->text = vp->text;
12530 lvp->flags = vp->flags;
12531 vp->flags |= VSTRFIXED|VTEXTFIXED;
12532 if (strchr(name, '='))
12533 setvareq(savestr(name), 0);
12537 lvp->next = localvars;
12544 * Called after a function returns.
12549 struct localvar *lvp;
12552 while ((lvp = localvars) != NULL) {
12553 localvars = lvp->next;
12555 if (vp == NULL) { /* $- saved */
12556 memcpy(optet_vals, lvp->text, sizeof optet_vals);
12558 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12559 (void)unsetvar(vp->text);
12561 if ((vp->flags & VTEXTFIXED) == 0)
12563 vp->flags = lvp->flags;
12564 vp->text = lvp->text;
12572 setvarcmd(argc, argv)
12577 return unsetcmd(argc, argv);
12578 else if (argc == 3)
12579 setvar(argv[1], argv[2], 0);
12581 error("List assignment not implemented");
12587 * The unset builtin command. We unset the function before we unset the
12588 * variable to allow a function to be unset when there is a readonly variable
12589 * with the same name.
12593 unsetcmd(argc, argv)
12603 while ((i = nextopt("vf")) != '\0') {
12609 if (flg_func == 0 && flg_var == 0)
12612 for (ap = argptr; *ap ; ap++) {
12616 ret |= unsetvar(*ap);
12623 * Unset the specified variable.
12627 unsetvar(const char *s)
12632 vpp = findvar(hashvar(s), s);
12635 if (vp->flags & VREADONLY)
12638 if (*(strchr(vp->text, '=') + 1) != '\0')
12639 setvar(s, nullstr, 0);
12640 vp->flags &= ~VEXPORT;
12641 vp->flags |= VUNSET;
12642 if ((vp->flags & VSTRFIXED) == 0) {
12643 if ((vp->flags & VTEXTFIXED) == 0)
12658 * Find the appropriate entry in the hash table from the name.
12661 static struct var **
12662 hashvar(const char *p)
12664 unsigned int hashval;
12666 hashval = ((unsigned char) *p) << 4;
12667 while (*p && *p != '=')
12668 hashval += (unsigned char) *p++;
12669 return &vartab[hashval % VTABSIZE];
12675 * Returns true if the two strings specify the same varable. The first
12676 * variable name is terminated by '='; the second may be terminated by
12677 * either '=' or '\0'.
12681 varequal(const char *p, const char *q)
12683 while (*p == *q++) {
12687 if (*p == '=' && *(q - 1) == '\0')
12693 showvars(const char *myprefix, int mask, int xor)
12697 const char *sep = myprefix == nullstr ? myprefix : spcstr;
12699 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12700 for (vp = *vpp ; vp ; vp = vp->next) {
12701 if ((vp->flags & mask) ^ xor) {
12705 p = strchr(vp->text, '=') + 1;
12706 len = p - vp->text;
12707 p = single_quote(p);
12709 printf("%s%s%.*s%s\n", myprefix, sep, len,
12717 static struct var **
12718 findvar(struct var **vpp, const char *name)
12720 for (; *vpp; vpp = &(*vpp)->next) {
12721 if (varequal((*vpp)->text, name)) {
12729 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
12730 * This file contains code for the times builtin.
12731 * $Id: ash.c,v 1.27 2001/10/19 00:08:17 andersen Exp $
12733 static int timescmd (int argc, char **argv)
12736 long int clk_tck = sysconf(_SC_CLK_TCK);
12739 printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
12740 (int) (buf.tms_utime / clk_tck / 60),
12741 ((double) buf.tms_utime) / clk_tck,
12742 (int) (buf.tms_stime / clk_tck / 60),
12743 ((double) buf.tms_stime) / clk_tck,
12744 (int) (buf.tms_cutime / clk_tck / 60),
12745 ((double) buf.tms_cutime) / clk_tck,
12746 (int) (buf.tms_cstime / clk_tck / 60),
12747 ((double) buf.tms_cstime) / clk_tck);
12751 #ifdef ASH_MATH_SUPPORT
12752 /* The let builtin. */
12753 int letcmd(int argc, char **argv)
12758 char *tmp, *expression, p[13];
12759 expression = strchr(argv[1], '=');
12761 /* Cannot use 'error()' here, or the return code
12762 * will be incorrect */
12763 out2fmt("sh: let: syntax error: \"%s\"\n", argv[1]);
12766 *expression = '\0';
12767 tmp = ++expression;
12768 result = arith(tmp, &errcode);
12770 /* Cannot use 'error()' here, or the return code
12771 * will be incorrect */
12772 out2fmt("sh: let: ");
12774 out2fmt("divide by zero");
12776 out2fmt("syntax error: \"%s=%s\"\n", argv[1], expression);
12779 snprintf(p, 12, "%ld", result);
12780 setvar(argv[1], savestr(p), 0);
12781 } else if (argc >= 3)
12782 synerror("invalid operand");
12790 * Copyright (c) 1989, 1991, 1993, 1994
12791 * The Regents of the University of California. All rights reserved.
12793 * This code is derived from software contributed to Berkeley by
12794 * Kenneth Almquist.
12796 * Redistribution and use in source and binary forms, with or without
12797 * modification, are permitted provided that the following conditions
12799 * 1. Redistributions of source code must retain the above copyright
12800 * notice, this list of conditions and the following disclaimer.
12801 * 2. Redistributions in binary form must reproduce the above copyright
12802 * notice, this list of conditions and the following disclaimer in the
12803 * documentation and/or other materials provided with the distribution.
12805 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
12806 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
12808 * 4. Neither the name of the University nor the names of its contributors
12809 * may be used to endorse or promote products derived from this software
12810 * without specific prior written permission.
12812 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
12813 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
12814 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
12815 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
12816 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
12817 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
12818 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
12819 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
12820 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
12821 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF