applying fix for:
[people/mcb30/busybox.git] / shell / ash.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * ash shell port for busybox
4  *
5  * Copyright (c) 1989, 1991, 1993, 1994
6  *      The Regents of the University of California.  All rights reserved.
7  *
8  * Copyright (c) 1997-2003 Herbert Xu <herbert@debian.org>
9  * was re-ported from NetBSD and debianized.
10  *
11  *
12  * This code is derived from software contributed to Berkeley by
13  * Kenneth Almquist.
14  *
15  * This program is free software; you can redistribute it and/or modify
16  * it under the terms of the GNU General Public License as published by
17  * the Free Software Foundation; either version 2 of the License, or
18  * (at your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23  * General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, write to the Free Software
27  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28  *
29  * Original BSD copyright notice is retained at the end of this file.
30  */
31
32 /*
33  * rewrite arith.y to micro stack based cryptic algorithm by
34  * Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
35  *
36  * Modified by Paul Mundt <lethal@linux-sh.org> (c) 2004 to support
37  * dynamic variables.
38  *
39  * Modified by Vladimir Oleynik <dzo@simtreas.ru> (c) 2001-2004 to be
40  * used in busybox and size optimizations,
41  * rewrote arith (see notes to this), added locale support,
42  * rewrote dynamic variables.
43  *
44  */
45
46
47 /*
48  * The follow should be set to reflect the type of system you have:
49  *      JOBS -> 1 if you have Berkeley job control, 0 otherwise.
50  *      define SYSV if you are running under System V.
51  *      define DEBUG=1 to compile in debugging ('set -o debug' to turn on)
52  *      define DEBUG=2 to compile in and turn on debugging.
53  *
54  * When debugging is on, debugging info will be written to ./trace and
55  * a quit signal will generate a core dump.
56  */
57
58
59
60 #define IFS_BROKEN
61
62 #define PROFILE 0
63
64 #ifdef DEBUG
65 #define _GNU_SOURCE
66 #endif
67
68 #include <sys/types.h>
69 #include <sys/cdefs.h>
70 #include <sys/ioctl.h>
71 #include <sys/param.h>
72 #include <sys/resource.h>
73 #include <sys/stat.h>
74 #include <sys/time.h>
75 #include <sys/wait.h>
76
77 #include <stdio.h>
78 #include <stdlib.h>
79 #include <string.h>
80 #include <unistd.h>
81
82 #include <stdarg.h>
83 #include <stddef.h>
84 #include <assert.h>
85 #include <ctype.h>
86 #include <dirent.h>
87 #include <errno.h>
88 #include <fcntl.h>
89 #include <limits.h>
90 #include <paths.h>
91 #include <setjmp.h>
92 #include <signal.h>
93 #include <stdint.h>
94 #include <sysexits.h>
95 #include <time.h>
96 #include <fnmatch.h>
97
98
99 #include "busybox.h"
100 #include "pwd_.h"
101
102 #ifdef CONFIG_ASH_JOB_CONTROL
103 #define JOBS 1
104 #else
105 #undef JOBS
106 #endif
107
108 #if JOBS
109 #include <termios.h>
110 #endif
111
112 #include "cmdedit.h"
113
114 #ifdef __GLIBC__
115 /* glibc sucks */
116 static int *dash_errno;
117 #undef errno
118 #define errno (*dash_errno)
119 #endif
120
121 #if defined(__uClinux__)
122 #error "Do not even bother, ash will not run on uClinux"
123 #endif
124
125 #ifdef DEBUG
126 #define _DIAGASSERT(assert_expr) assert(assert_expr)
127 #else
128 #define _DIAGASSERT(assert_expr)
129 #endif
130
131
132 #ifdef CONFIG_ASH_ALIAS
133 /*      $NetBSD: alias.h,v 1.5 2002/11/24 22:35:38 christos Exp $       */
134
135 #define ALIASINUSE      1
136 #define ALIASDEAD       2
137
138 struct alias {
139         struct alias *next;
140         char *name;
141         char *val;
142         int flag;
143 };
144
145 static struct alias *lookupalias(const char *, int);
146 static int aliascmd(int, char **);
147 static int unaliascmd(int, char **);
148 static void rmaliases(void);
149 static int unalias(const char *);
150 static void printalias(const struct alias *);
151 #endif
152
153 /*      $NetBSD: cd.h,v 1.3 2002/11/24 22:35:39 christos Exp $  */
154
155
156 static void    setpwd(const char *, int);
157
158 /*      $NetBSD: error.h,v 1.15 2002/11/24 22:35:39 christos Exp $      */
159
160
161 /*
162  * Types of operations (passed to the errmsg routine).
163  */
164
165
166 static const char not_found_msg[] = "%s: not found";
167
168
169 #define E_OPEN  "No such file"          /* opening a file */
170 #define E_CREAT "Directory nonexistent" /* creating a file */
171 #define E_EXEC  not_found_msg+4         /* executing a program */
172
173 /*
174  * We enclose jmp_buf in a structure so that we can declare pointers to
175  * jump locations.  The global variable handler contains the location to
176  * jump to when an exception occurs, and the global variable exception
177  * contains a code identifying the exception.  To implement nested
178  * exception handlers, the user should save the value of handler on entry
179  * to an inner scope, set handler to point to a jmploc structure for the
180  * inner scope, and restore handler on exit from the scope.
181  */
182
183 struct jmploc {
184         jmp_buf loc;
185 };
186
187 static struct jmploc *handler;
188 static int exception;
189 static volatile int suppressint;
190 static volatile sig_atomic_t intpending;
191
192 static int exerrno;            /* Last exec error, error for EXEXEC */
193
194 /* exceptions */
195 #define EXINT 0         /* SIGINT received */
196 #define EXERROR 1       /* a generic error */
197 #define EXSHELLPROC 2   /* execute a shell procedure */
198 #define EXEXEC 3        /* command execution failed */
199 #define EXEXIT 4        /* exit the shell */
200 #define EXSIG 5         /* trapped signal in wait(1) */
201
202
203 /* do we generate EXSIG events */
204 static int exsig;
205 /* last pending signal */
206 static volatile sig_atomic_t pendingsigs;
207
208 /*
209  * These macros allow the user to suspend the handling of interrupt signals
210  * over a period of time.  This is similar to SIGHOLD to or sigblock, but
211  * much more efficient and portable.  (But hacking the kernel is so much
212  * more fun than worrying about efficiency and portability. :-))
213  */
214
215 #define xbarrier() ({ __asm__ __volatile__ ("": : :"memory"); })
216 #define INTOFF \
217         ({ \
218                 suppressint++; \
219                 xbarrier(); \
220                 0; \
221         })
222 #define SAVEINT(v) ((v) = suppressint)
223 #define RESTOREINT(v) \
224         ({ \
225                 xbarrier(); \
226                 if ((suppressint = (v)) == 0 && intpending) onint(); \
227                 0; \
228         })
229 #define EXSIGON() \
230         ({ \
231                 exsig++; \
232                 xbarrier(); \
233                 if (pendingsigs) \
234                         exraise(EXSIG); \
235                 0; \
236         })
237 /* EXSIG is turned off by evalbltin(). */
238
239
240 static void exraise(int) __attribute__((__noreturn__));
241 static void onint(void) __attribute__((__noreturn__));
242
243 static void error(const char *, ...) __attribute__((__noreturn__));
244 static void exerror(int, const char *, ...) __attribute__((__noreturn__));
245
246 static void sh_warnx(const char *, ...);
247
248 #ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
249 static void
250 inton(void) {
251         if (--suppressint == 0 && intpending) {
252                 onint();
253         }
254 }
255 #define INTON inton()
256 static void forceinton(void)
257 {
258         suppressint = 0;
259         if (intpending)
260                 onint();
261 }
262 #define FORCEINTON forceinton()
263 #else
264 #define INTON \
265         ({ \
266                 xbarrier(); \
267                 if (--suppressint == 0 && intpending) onint(); \
268                 0; \
269         })
270 #define FORCEINTON \
271         ({ \
272                 xbarrier(); \
273                 suppressint = 0; \
274                 if (intpending) onint(); \
275                 0; \
276         })
277 #endif /* CONFIG_ASH_OPTIMIZE_FOR_SIZE */
278
279 /*
280  * BSD setjmp saves the signal mask, which violates ANSI C and takes time,
281  * so we use _setjmp instead.
282  */
283
284 #if defined(BSD) && !defined(__SVR4) && !defined(__GLIBC__)
285 #define setjmp(jmploc)  _setjmp(jmploc)
286 #define longjmp(jmploc, val)    _longjmp(jmploc, val)
287 #endif
288
289 /*      $NetBSD: expand.h,v 1.13 2002/11/24 22:35:40 christos Exp $     */
290
291 struct strlist {
292         struct strlist *next;
293         char *text;
294 };
295
296
297 struct arglist {
298         struct strlist *list;
299         struct strlist **lastp;
300 };
301
302 /*
303  * expandarg() flags
304  */
305 #define EXP_FULL        0x1     /* perform word splitting & file globbing */
306 #define EXP_TILDE       0x2     /* do normal tilde expansion */
307 #define EXP_VARTILDE    0x4     /* expand tildes in an assignment */
308 #define EXP_REDIR       0x8     /* file glob for a redirection (1 match only) */
309 #define EXP_CASE        0x10    /* keeps quotes around for CASE pattern */
310 #define EXP_RECORD      0x20    /* need to record arguments for ifs breakup */
311 #define EXP_VARTILDE2   0x40    /* expand tildes after colons only */
312 #define EXP_WORD        0x80    /* expand word in parameter expansion */
313 #define EXP_QWORD       0x100   /* expand word in quoted parameter expansion */
314
315
316 union node;
317 static void expandarg(union node *, struct arglist *, int);
318 #define rmescapes(p) _rmescapes((p), 0)
319 static char *_rmescapes(char *, int);
320 static int casematch(union node *, char *);
321
322 #ifdef CONFIG_ASH_MATH_SUPPORT
323 static void expari(int);
324 #endif
325
326 /*      $NetBSD: eval.h,v 1.13 2002/11/24 22:35:39 christos Exp $       */
327
328 static char *commandname;              /* currently executing command */
329 static struct strlist *cmdenviron;     /* environment for builtin command */
330 static int exitstatus;                 /* exit status of last command */
331 static int back_exitstatus;            /* exit status of backquoted command */
332
333
334 struct backcmd {                /* result of evalbackcmd */
335         int fd;                 /* file descriptor to read from */
336         char *buf;              /* buffer */
337         int nleft;              /* number of chars in buffer */
338         struct job *jp;         /* job structure for command */
339 };
340
341 /*
342  * This file was generated by the mknodes program.
343  */
344
345 #define NCMD 0
346 #define NPIPE 1
347 #define NREDIR 2
348 #define NBACKGND 3
349 #define NSUBSHELL 4
350 #define NAND 5
351 #define NOR 6
352 #define NSEMI 7
353 #define NIF 8
354 #define NWHILE 9
355 #define NUNTIL 10
356 #define NFOR 11
357 #define NCASE 12
358 #define NCLIST 13
359 #define NDEFUN 14
360 #define NARG 15
361 #define NTO 16
362 #define NCLOBBER 17
363 #define NFROM 18
364 #define NFROMTO 19
365 #define NAPPEND 20
366 #define NTOFD 21
367 #define NFROMFD 22
368 #define NHERE 23
369 #define NXHERE 24
370 #define NNOT 25
371
372
373
374 struct ncmd {
375       int type;
376       union node *assign;
377       union node *args;
378       union node *redirect;
379 };
380
381
382 struct npipe {
383       int type;
384       int backgnd;
385       struct nodelist *cmdlist;
386 };
387
388
389 struct nredir {
390       int type;
391       union node *n;
392       union node *redirect;
393 };
394
395
396 struct nbinary {
397       int type;
398       union node *ch1;
399       union node *ch2;
400 };
401
402
403 struct nif {
404       int type;
405       union node *test;
406       union node *ifpart;
407       union node *elsepart;
408 };
409
410
411 struct nfor {
412       int type;
413       union node *args;
414       union node *body;
415       char *var;
416 };
417
418
419 struct ncase {
420       int type;
421       union node *expr;
422       union node *cases;
423 };
424
425
426 struct nclist {
427       int type;
428       union node *next;
429       union node *pattern;
430       union node *body;
431 };
432
433
434 struct narg {
435       int type;
436       union node *next;
437       char *text;
438       struct nodelist *backquote;
439 };
440
441
442 struct nfile {
443       int type;
444       union node *next;
445       int fd;
446       union node *fname;
447       char *expfname;
448 };
449
450
451 struct ndup {
452       int type;
453       union node *next;
454       int fd;
455       int dupfd;
456       union node *vname;
457 };
458
459
460 struct nhere {
461       int type;
462       union node *next;
463       int fd;
464       union node *doc;
465 };
466
467
468 struct nnot {
469       int type;
470       union node *com;
471 };
472
473
474 union node {
475       int type;
476       struct ncmd ncmd;
477       struct npipe npipe;
478       struct nredir nredir;
479       struct nbinary nbinary;
480       struct nif nif;
481       struct nfor nfor;
482       struct ncase ncase;
483       struct nclist nclist;
484       struct narg narg;
485       struct nfile nfile;
486       struct ndup ndup;
487       struct nhere nhere;
488       struct nnot nnot;
489 };
490
491
492 struct nodelist {
493         struct nodelist *next;
494         union node *n;
495 };
496
497
498 struct funcnode {
499         int count;
500         union node n;
501 };
502
503
504 static void freefunc(struct funcnode *);
505 /*      $NetBSD: parser.h,v 1.15 2002/11/24 22:35:42 christos Exp $     */
506
507 /* control characters in argument strings */
508 #define CTL_FIRST '\201'        /* first 'special' character */
509 #define CTLESC '\201'           /* escape next character */
510 #define CTLVAR '\202'           /* variable defn */
511 #define CTLENDVAR '\203'
512 #define CTLBACKQ '\204'
513 #define CTLQUOTE 01             /* ored with CTLBACKQ code if in quotes */
514 /*      CTLBACKQ | CTLQUOTE == '\205' */
515 #define CTLARI  '\206'          /* arithmetic expression */
516 #define CTLENDARI '\207'
517 #define CTLQUOTEMARK '\210'
518 #define CTL_LAST '\210'         /* last 'special' character */
519
520 /* variable substitution byte (follows CTLVAR) */
521 #define VSTYPE  0x0f            /* type of variable substitution */
522 #define VSNUL   0x10            /* colon--treat the empty string as unset */
523 #define VSQUOTE 0x80            /* inside double quotes--suppress splitting */
524
525 /* values of VSTYPE field */
526 #define VSNORMAL        0x1             /* normal variable:  $var or ${var} */
527 #define VSMINUS         0x2             /* ${var-text} */
528 #define VSPLUS          0x3             /* ${var+text} */
529 #define VSQUESTION      0x4             /* ${var?message} */
530 #define VSASSIGN        0x5             /* ${var=text} */
531 #define VSTRIMRIGHT     0x6             /* ${var%pattern} */
532 #define VSTRIMRIGHTMAX  0x7             /* ${var%%pattern} */
533 #define VSTRIMLEFT      0x8             /* ${var#pattern} */
534 #define VSTRIMLEFTMAX   0x9             /* ${var##pattern} */
535 #define VSLENGTH        0xa             /* ${#var} */
536
537 /* values of checkkwd variable */
538 #define CHKALIAS        0x1
539 #define CHKKWD          0x2
540 #define CHKNL           0x4
541
542 #define IBUFSIZ (BUFSIZ + 1)
543
544 /*
545  * NEOF is returned by parsecmd when it encounters an end of file.  It
546  * must be distinct from NULL, so we use the address of a variable that
547  * happens to be handy.
548  */
549 static int plinno = 1;                  /* input line number */
550
551 /* number of characters left in input buffer */
552 static int parsenleft;                  /* copy of parsefile->nleft */
553 static int parselleft;                  /* copy of parsefile->lleft */
554
555 /* next character in input buffer */
556 static char *parsenextc;                /* copy of parsefile->nextc */
557
558 struct strpush {
559         struct strpush *prev;   /* preceding string on stack */
560         char *prevstring;
561         int prevnleft;
562 #ifdef CONFIG_ASH_ALIAS
563         struct alias *ap;       /* if push was associated with an alias */
564 #endif
565         char *string;           /* remember the string since it may change */
566 };
567
568 struct parsefile {
569         struct parsefile *prev; /* preceding file on stack */
570         int linno;              /* current line */
571         int fd;                 /* file descriptor (or -1 if string) */
572         int nleft;              /* number of chars left in this line */
573         int lleft;              /* number of chars left in this buffer */
574         char *nextc;            /* next char in buffer */
575         char *buf;              /* input buffer */
576         struct strpush *strpush; /* for pushing strings at this level */
577         struct strpush basestrpush; /* so pushing one is fast */
578 };
579
580 static struct parsefile basepf;         /* top level input file */
581 static char basebuf[IBUFSIZ];           /* buffer for top level input file */
582 static struct parsefile *parsefile = &basepf;  /* current input file */
583
584
585 static int tokpushback;                 /* last token pushed back */
586 #define NEOF ((union node *)&tokpushback)
587 static int parsebackquote;             /* nonzero if we are inside backquotes */
588 static int doprompt;                   /* if set, prompt the user */
589 static int needprompt;                 /* true if interactive and at start of line */
590 static int lasttoken;                  /* last token read */
591 static char *wordtext;                 /* text of last word returned by readtoken */
592 static int checkkwd;
593 static struct nodelist *backquotelist;
594 static union node *redirnode;
595 static struct heredoc *heredoc;
596 static int quoteflag;                  /* set if (part of) last token was quoted */
597 static int startlinno;                 /* line # where last token started */
598
599 static union node *parsecmd(int);
600 static void fixredir(union node *, const char *, int);
601 static const char *const *findkwd(const char *);
602 static char *endofname(const char *);
603
604 /*      $NetBSD: shell.h,v 1.16 2003/01/22 20:36:04 dsl Exp $   */
605
606 typedef void *pointer;
607
608 static char nullstr[1];                /* zero length string */
609 static const char spcstr[] = " ";
610 static const char snlfmt[] = "%s\n";
611 static const char dolatstr[] = { CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' };
612 static const char illnum[] = "Illegal number: %s";
613 static const char homestr[] = "HOME";
614
615 #ifdef DEBUG
616 #define TRACE(param)    trace param
617 #define TRACEV(param)   tracev param
618 #else
619 #define TRACE(param)
620 #define TRACEV(param)
621 #endif
622
623 #if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
624 #define __builtin_expect(x, expected_value) (x)
625 #endif
626
627 #define xlikely(x)       __builtin_expect((x),1)
628
629
630 #define TEOF 0
631 #define TNL 1
632 #define TREDIR 2
633 #define TWORD 3
634 #define TSEMI 4
635 #define TBACKGND 5
636 #define TAND 6
637 #define TOR 7
638 #define TPIPE 8
639 #define TLP 9
640 #define TRP 10
641 #define TENDCASE 11
642 #define TENDBQUOTE 12
643 #define TNOT 13
644 #define TCASE 14
645 #define TDO 15
646 #define TDONE 16
647 #define TELIF 17
648 #define TELSE 18
649 #define TESAC 19
650 #define TFI 20
651 #define TFOR 21
652 #define TIF 22
653 #define TIN 23
654 #define TTHEN 24
655 #define TUNTIL 25
656 #define TWHILE 26
657 #define TBEGIN 27
658 #define TEND 28
659
660 /* first char is indicating which tokens mark the end of a list */
661 static const char *const tokname_array[] = {
662         "\1end of file",
663         "\0newline",
664         "\0redirection",
665         "\0word",
666         "\0;",
667         "\0&",
668         "\0&&",
669         "\0||",
670         "\0|",
671         "\0(",
672         "\1)",
673         "\1;;",
674         "\1`",
675 #define KWDOFFSET 13
676         /* the following are keywords */
677         "\0!",
678         "\0case",
679         "\1do",
680         "\1done",
681         "\1elif",
682         "\1else",
683         "\1esac",
684         "\1fi",
685         "\0for",
686         "\0if",
687         "\0in",
688         "\1then",
689         "\0until",
690         "\0while",
691         "\0{",
692         "\1}",
693 };
694
695 static const char *tokname(int tok)
696 {
697         static char buf[16];
698
699         if (tok >= TSEMI)
700                 buf[0] = '"';
701         sprintf(buf + (tok >= TSEMI), "%s%c",
702                         tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0));
703         return buf;
704 }
705
706 /*      $NetBSD: machdep.h,v 1.10 2002/10/07 14:26:08 christos Exp $    */
707
708 /*
709  * Most machines require the value returned from malloc to be aligned
710  * in some way.  The following macro will get this right on many machines.
711  */
712
713 #define SHELL_SIZE (sizeof(union {int i; char *cp; double d; }) - 1)
714 /*
715  * It appears that grabstackstr() will barf with such alignments
716  * because stalloc() will return a string allocated in a new stackblock.
717  */
718 #define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
719
720 /*
721  * This file was generated by the mksyntax program.
722  */
723
724
725 /* Syntax classes */
726 #define CWORD 0                 /* character is nothing special */
727 #define CNL 1                   /* newline character */
728 #define CBACK 2                 /* a backslash character */
729 #define CSQUOTE 3               /* single quote */
730 #define CDQUOTE 4               /* double quote */
731 #define CENDQUOTE 5             /* a terminating quote */
732 #define CBQUOTE 6               /* backwards single quote */
733 #define CVAR 7                  /* a dollar sign */
734 #define CENDVAR 8               /* a '}' character */
735 #define CLP 9                   /* a left paren in arithmetic */
736 #define CRP 10                  /* a right paren in arithmetic */
737 #define CENDFILE 11             /* end of file */
738 #define CCTL 12                 /* like CWORD, except it must be escaped */
739 #define CSPCL 13                /* these terminate a word */
740 #define CIGN 14                 /* character should be ignored */
741
742 #ifdef CONFIG_ASH_ALIAS
743 #define SYNBASE 130
744 #define PEOF -130
745 #define PEOA -129
746 #define PEOA_OR_PEOF PEOA
747 #else
748 #define SYNBASE 129
749 #define PEOF -129
750 #define PEOA_OR_PEOF PEOF
751 #endif
752
753 #define is_digit(c)     ((unsigned)((c) - '0') <= 9)
754 #define is_name(c)      ((c) == '_' || isalpha((unsigned char)(c)))
755 #define is_in_name(c)   ((c) == '_' || isalnum((unsigned char)(c)))
756
757 /*
758  * is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
759  * (assuming ascii char codes, as the original implementation did)
760  */
761 #define is_special(c) \
762     ( (((unsigned int)c) - 33 < 32) \
763                          && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1))
764
765 #define digit_val(c)    ((c) - '0')
766
767 /*
768  * This file was generated by the mksyntax program.
769  */
770
771 #ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
772 #define USE_SIT_FUNCTION
773 #endif
774
775 /* number syntax index */
776 #define  BASESYNTAX  0  /* not in quotes */
777 #define  DQSYNTAX    1  /* in double quotes */
778 #define  SQSYNTAX    2  /* in single quotes */
779 #define  ARISYNTAX   3  /* in arithmetic */
780
781 #ifdef CONFIG_ASH_MATH_SUPPORT
782 static const char S_I_T[][4] = {
783 #ifdef CONFIG_ASH_ALIAS
784         {CSPCL, CIGN, CIGN, CIGN},              /* 0, PEOA */
785 #endif
786         {CSPCL, CWORD, CWORD, CWORD},           /* 1, ' ' */
787         {CNL, CNL, CNL, CNL},                   /* 2, \n */
788         {CWORD, CCTL, CCTL, CWORD},             /* 3, !*-/:=?[]~ */
789         {CDQUOTE, CENDQUOTE, CWORD, CWORD},     /* 4, '"' */
790         {CVAR, CVAR, CWORD, CVAR},              /* 5, $ */
791         {CSQUOTE, CWORD, CENDQUOTE, CWORD},     /* 6, "'" */
792         {CSPCL, CWORD, CWORD, CLP},             /* 7, ( */
793         {CSPCL, CWORD, CWORD, CRP},             /* 8, ) */
794         {CBACK, CBACK, CCTL, CBACK},            /* 9, \ */
795         {CBQUOTE, CBQUOTE, CWORD, CBQUOTE},     /* 10, ` */
796         {CENDVAR, CENDVAR, CWORD, CENDVAR},     /* 11, } */
797 #ifndef USE_SIT_FUNCTION
798         {CENDFILE, CENDFILE, CENDFILE, CENDFILE},       /* 12, PEOF */
799         {CWORD, CWORD, CWORD, CWORD},           /* 13, 0-9A-Za-z */
800         {CCTL, CCTL, CCTL, CCTL}                /* 14, CTLESC ... */
801 #endif
802 };
803 #else
804 static const char S_I_T[][3] = {
805 #ifdef CONFIG_ASH_ALIAS
806         {CSPCL, CIGN, CIGN},                    /* 0, PEOA */
807 #endif
808         {CSPCL, CWORD, CWORD},                  /* 1, ' ' */
809         {CNL, CNL, CNL},                        /* 2, \n */
810         {CWORD, CCTL, CCTL},                    /* 3, !*-/:=?[]~ */
811         {CDQUOTE, CENDQUOTE, CWORD},            /* 4, '"' */
812         {CVAR, CVAR, CWORD},                    /* 5, $ */
813         {CSQUOTE, CWORD, CENDQUOTE},            /* 6, "'" */
814         {CSPCL, CWORD, CWORD},                  /* 7, ( */
815         {CSPCL, CWORD, CWORD},                  /* 8, ) */
816         {CBACK, CBACK, CCTL},                   /* 9, \ */
817         {CBQUOTE, CBQUOTE, CWORD},              /* 10, ` */
818         {CENDVAR, CENDVAR, CWORD},              /* 11, } */
819 #ifndef USE_SIT_FUNCTION
820         {CENDFILE, CENDFILE, CENDFILE},         /* 12, PEOF */
821         {CWORD, CWORD, CWORD},                  /* 13, 0-9A-Za-z */
822         {CCTL, CCTL, CCTL}                      /* 14, CTLESC ... */
823 #endif
824 };
825 #endif /* CONFIG_ASH_MATH_SUPPORT */
826
827 #ifdef USE_SIT_FUNCTION
828
829 #define U_C(c) ((unsigned char)(c))
830
831 static int SIT(int c, int syntax)
832 {
833         static const char spec_symbls[] = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
834 #ifdef CONFIG_ASH_ALIAS
835         static const char syntax_index_table[] = {
836                 1, 2, 1, 3, 4, 5, 1, 6,         /* "\t\n !\"$&'" */
837                 7, 8, 3, 3, 3, 3, 1, 1,         /* "()*-/:;<" */
838                 3, 1, 3, 3, 9, 3, 10, 1,        /* "=>?[\\]`|" */
839                 11, 3                           /* "}~" */
840         };
841 #else
842         static const char syntax_index_table[] = {
843                 0, 1, 0, 2, 3, 4, 0, 5,         /* "\t\n !\"$&'" */
844                 6, 7, 2, 2, 2, 2, 0, 0,         /* "()*-/:;<" */
845                 2, 0, 2, 2, 8, 2, 9, 0,         /* "=>?[\\]`|" */
846                 10, 2                           /* "}~" */
847         };
848 #endif
849         const char *s;
850         int indx;
851
852         if (c == PEOF)          /* 2^8+2 */
853                 return CENDFILE;
854 #ifdef CONFIG_ASH_ALIAS
855         if (c == PEOA)          /* 2^8+1 */
856                 indx = 0;
857         else
858 #endif
859                 if (U_C(c) >= U_C(CTLESC) && U_C(c) <= U_C(CTLQUOTEMARK))
860                         return CCTL;
861         else {
862                 s = strchr(spec_symbls, c);
863                 if (s == 0 || *s == 0)
864                         return CWORD;
865                 indx = syntax_index_table[(s - spec_symbls)];
866         }
867         return S_I_T[indx][syntax];
868 }
869
870 #else                                                   /* USE_SIT_FUNCTION */
871
872 #define SIT(c, syntax) S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax]
873
874 #ifdef CONFIG_ASH_ALIAS
875 #define CSPCL_CIGN_CIGN_CIGN                           0
876 #define CSPCL_CWORD_CWORD_CWORD                        1
877 #define CNL_CNL_CNL_CNL                                2
878 #define CWORD_CCTL_CCTL_CWORD                          3
879 #define CDQUOTE_CENDQUOTE_CWORD_CWORD                  4
880 #define CVAR_CVAR_CWORD_CVAR                           5
881 #define CSQUOTE_CWORD_CENDQUOTE_CWORD                  6
882 #define CSPCL_CWORD_CWORD_CLP                          7
883 #define CSPCL_CWORD_CWORD_CRP                          8
884 #define CBACK_CBACK_CCTL_CBACK                         9
885 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE                 10
886 #define CENDVAR_CENDVAR_CWORD_CENDVAR                 11
887 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE           12
888 #define CWORD_CWORD_CWORD_CWORD                       13
889 #define CCTL_CCTL_CCTL_CCTL                           14
890 #else
891 #define CSPCL_CWORD_CWORD_CWORD                        0
892 #define CNL_CNL_CNL_CNL                                1
893 #define CWORD_CCTL_CCTL_CWORD                          2
894 #define CDQUOTE_CENDQUOTE_CWORD_CWORD                  3
895 #define CVAR_CVAR_CWORD_CVAR                           4
896 #define CSQUOTE_CWORD_CENDQUOTE_CWORD                  5
897 #define CSPCL_CWORD_CWORD_CLP                          6
898 #define CSPCL_CWORD_CWORD_CRP                          7
899 #define CBACK_CBACK_CCTL_CBACK                         8
900 #define CBQUOTE_CBQUOTE_CWORD_CBQUOTE                  9
901 #define CENDVAR_CENDVAR_CWORD_CENDVAR                 10
902 #define CENDFILE_CENDFILE_CENDFILE_CENDFILE           11
903 #define CWORD_CWORD_CWORD_CWORD                       12
904 #define CCTL_CCTL_CCTL_CCTL                           13
905 #endif
906
907 static const char syntax_index_table[258] = {
908         /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
909         /*   0  PEOF */      CENDFILE_CENDFILE_CENDFILE_CENDFILE,
910 #ifdef CONFIG_ASH_ALIAS
911         /*   1  PEOA */      CSPCL_CIGN_CIGN_CIGN,
912 #endif
913         /*   2  -128 0x80 */ CWORD_CWORD_CWORD_CWORD,
914         /*   3  -127 CTLESC       */ CCTL_CCTL_CCTL_CCTL,
915         /*   4  -126 CTLVAR       */ CCTL_CCTL_CCTL_CCTL,
916         /*   5  -125 CTLENDVAR    */ CCTL_CCTL_CCTL_CCTL,
917         /*   6  -124 CTLBACKQ     */ CCTL_CCTL_CCTL_CCTL,
918         /*   7  -123 CTLQUOTE     */ CCTL_CCTL_CCTL_CCTL,
919         /*   8  -122 CTLARI       */ CCTL_CCTL_CCTL_CCTL,
920         /*   9  -121 CTLENDARI    */ CCTL_CCTL_CCTL_CCTL,
921         /*  10  -120 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
922         /*  11  -119      */ CWORD_CWORD_CWORD_CWORD,
923         /*  12  -118      */ CWORD_CWORD_CWORD_CWORD,
924         /*  13  -117      */ CWORD_CWORD_CWORD_CWORD,
925         /*  14  -116      */ CWORD_CWORD_CWORD_CWORD,
926         /*  15  -115      */ CWORD_CWORD_CWORD_CWORD,
927         /*  16  -114      */ CWORD_CWORD_CWORD_CWORD,
928         /*  17  -113      */ CWORD_CWORD_CWORD_CWORD,
929         /*  18  -112      */ CWORD_CWORD_CWORD_CWORD,
930         /*  19  -111      */ CWORD_CWORD_CWORD_CWORD,
931         /*  20  -110      */ CWORD_CWORD_CWORD_CWORD,
932         /*  21  -109      */ CWORD_CWORD_CWORD_CWORD,
933         /*  22  -108      */ CWORD_CWORD_CWORD_CWORD,
934         /*  23  -107      */ CWORD_CWORD_CWORD_CWORD,
935         /*  24  -106      */ CWORD_CWORD_CWORD_CWORD,
936         /*  25  -105      */ CWORD_CWORD_CWORD_CWORD,
937         /*  26  -104      */ CWORD_CWORD_CWORD_CWORD,
938         /*  27  -103      */ CWORD_CWORD_CWORD_CWORD,
939         /*  28  -102      */ CWORD_CWORD_CWORD_CWORD,
940         /*  29  -101      */ CWORD_CWORD_CWORD_CWORD,
941         /*  30  -100      */ CWORD_CWORD_CWORD_CWORD,
942         /*  31   -99      */ CWORD_CWORD_CWORD_CWORD,
943         /*  32   -98      */ CWORD_CWORD_CWORD_CWORD,
944         /*  33   -97      */ CWORD_CWORD_CWORD_CWORD,
945         /*  34   -96      */ CWORD_CWORD_CWORD_CWORD,
946         /*  35   -95      */ CWORD_CWORD_CWORD_CWORD,
947         /*  36   -94      */ CWORD_CWORD_CWORD_CWORD,
948         /*  37   -93      */ CWORD_CWORD_CWORD_CWORD,
949         /*  38   -92      */ CWORD_CWORD_CWORD_CWORD,
950         /*  39   -91      */ CWORD_CWORD_CWORD_CWORD,
951         /*  40   -90      */ CWORD_CWORD_CWORD_CWORD,
952         /*  41   -89      */ CWORD_CWORD_CWORD_CWORD,
953         /*  42   -88      */ CWORD_CWORD_CWORD_CWORD,
954         /*  43   -87      */ CWORD_CWORD_CWORD_CWORD,
955         /*  44   -86      */ CWORD_CWORD_CWORD_CWORD,
956         /*  45   -85      */ CWORD_CWORD_CWORD_CWORD,
957         /*  46   -84      */ CWORD_CWORD_CWORD_CWORD,
958         /*  47   -83      */ CWORD_CWORD_CWORD_CWORD,
959         /*  48   -82      */ CWORD_CWORD_CWORD_CWORD,
960         /*  49   -81      */ CWORD_CWORD_CWORD_CWORD,
961         /*  50   -80      */ CWORD_CWORD_CWORD_CWORD,
962         /*  51   -79      */ CWORD_CWORD_CWORD_CWORD,
963         /*  52   -78      */ CWORD_CWORD_CWORD_CWORD,
964         /*  53   -77      */ CWORD_CWORD_CWORD_CWORD,
965         /*  54   -76      */ CWORD_CWORD_CWORD_CWORD,
966         /*  55   -75      */ CWORD_CWORD_CWORD_CWORD,
967         /*  56   -74      */ CWORD_CWORD_CWORD_CWORD,
968         /*  57   -73      */ CWORD_CWORD_CWORD_CWORD,
969         /*  58   -72      */ CWORD_CWORD_CWORD_CWORD,
970         /*  59   -71      */ CWORD_CWORD_CWORD_CWORD,
971         /*  60   -70      */ CWORD_CWORD_CWORD_CWORD,
972         /*  61   -69      */ CWORD_CWORD_CWORD_CWORD,
973         /*  62   -68      */ CWORD_CWORD_CWORD_CWORD,
974         /*  63   -67      */ CWORD_CWORD_CWORD_CWORD,
975         /*  64   -66      */ CWORD_CWORD_CWORD_CWORD,
976         /*  65   -65      */ CWORD_CWORD_CWORD_CWORD,
977         /*  66   -64      */ CWORD_CWORD_CWORD_CWORD,
978         /*  67   -63      */ CWORD_CWORD_CWORD_CWORD,
979         /*  68   -62      */ CWORD_CWORD_CWORD_CWORD,
980         /*  69   -61      */ CWORD_CWORD_CWORD_CWORD,
981         /*  70   -60      */ CWORD_CWORD_CWORD_CWORD,
982         /*  71   -59      */ CWORD_CWORD_CWORD_CWORD,
983         /*  72   -58      */ CWORD_CWORD_CWORD_CWORD,
984         /*  73   -57      */ CWORD_CWORD_CWORD_CWORD,
985         /*  74   -56      */ CWORD_CWORD_CWORD_CWORD,
986         /*  75   -55      */ CWORD_CWORD_CWORD_CWORD,
987         /*  76   -54      */ CWORD_CWORD_CWORD_CWORD,
988         /*  77   -53      */ CWORD_CWORD_CWORD_CWORD,
989         /*  78   -52      */ CWORD_CWORD_CWORD_CWORD,
990         /*  79   -51      */ CWORD_CWORD_CWORD_CWORD,
991         /*  80   -50      */ CWORD_CWORD_CWORD_CWORD,
992         /*  81   -49      */ CWORD_CWORD_CWORD_CWORD,
993         /*  82   -48      */ CWORD_CWORD_CWORD_CWORD,
994         /*  83   -47      */ CWORD_CWORD_CWORD_CWORD,
995         /*  84   -46      */ CWORD_CWORD_CWORD_CWORD,
996         /*  85   -45      */ CWORD_CWORD_CWORD_CWORD,
997         /*  86   -44      */ CWORD_CWORD_CWORD_CWORD,
998         /*  87   -43      */ CWORD_CWORD_CWORD_CWORD,
999         /*  88   -42      */ CWORD_CWORD_CWORD_CWORD,
1000         /*  89   -41      */ CWORD_CWORD_CWORD_CWORD,
1001         /*  90   -40      */ CWORD_CWORD_CWORD_CWORD,
1002         /*  91   -39      */ CWORD_CWORD_CWORD_CWORD,
1003         /*  92   -38      */ CWORD_CWORD_CWORD_CWORD,
1004         /*  93   -37      */ CWORD_CWORD_CWORD_CWORD,
1005         /*  94   -36      */ CWORD_CWORD_CWORD_CWORD,
1006         /*  95   -35      */ CWORD_CWORD_CWORD_CWORD,
1007         /*  96   -34      */ CWORD_CWORD_CWORD_CWORD,
1008         /*  97   -33      */ CWORD_CWORD_CWORD_CWORD,
1009         /*  98   -32      */ CWORD_CWORD_CWORD_CWORD,
1010         /*  99   -31      */ CWORD_CWORD_CWORD_CWORD,
1011         /* 100   -30      */ CWORD_CWORD_CWORD_CWORD,
1012         /* 101   -29      */ CWORD_CWORD_CWORD_CWORD,
1013         /* 102   -28      */ CWORD_CWORD_CWORD_CWORD,
1014         /* 103   -27      */ CWORD_CWORD_CWORD_CWORD,
1015         /* 104   -26      */ CWORD_CWORD_CWORD_CWORD,
1016         /* 105   -25      */ CWORD_CWORD_CWORD_CWORD,
1017         /* 106   -24      */ CWORD_CWORD_CWORD_CWORD,
1018         /* 107   -23      */ CWORD_CWORD_CWORD_CWORD,
1019         /* 108   -22      */ CWORD_CWORD_CWORD_CWORD,
1020         /* 109   -21      */ CWORD_CWORD_CWORD_CWORD,
1021         /* 110   -20      */ CWORD_CWORD_CWORD_CWORD,
1022         /* 111   -19      */ CWORD_CWORD_CWORD_CWORD,
1023         /* 112   -18      */ CWORD_CWORD_CWORD_CWORD,
1024         /* 113   -17      */ CWORD_CWORD_CWORD_CWORD,
1025         /* 114   -16      */ CWORD_CWORD_CWORD_CWORD,
1026         /* 115   -15      */ CWORD_CWORD_CWORD_CWORD,
1027         /* 116   -14      */ CWORD_CWORD_CWORD_CWORD,
1028         /* 117   -13      */ CWORD_CWORD_CWORD_CWORD,
1029         /* 118   -12      */ CWORD_CWORD_CWORD_CWORD,
1030         /* 119   -11      */ CWORD_CWORD_CWORD_CWORD,
1031         /* 120   -10      */ CWORD_CWORD_CWORD_CWORD,
1032         /* 121    -9      */ CWORD_CWORD_CWORD_CWORD,
1033         /* 122    -8      */ CWORD_CWORD_CWORD_CWORD,
1034         /* 123    -7      */ CWORD_CWORD_CWORD_CWORD,
1035         /* 124    -6      */ CWORD_CWORD_CWORD_CWORD,
1036         /* 125    -5      */ CWORD_CWORD_CWORD_CWORD,
1037         /* 126    -4      */ CWORD_CWORD_CWORD_CWORD,
1038         /* 127    -3      */ CWORD_CWORD_CWORD_CWORD,
1039         /* 128    -2      */ CWORD_CWORD_CWORD_CWORD,
1040         /* 129    -1      */ CWORD_CWORD_CWORD_CWORD,
1041         /* 130     0      */ CWORD_CWORD_CWORD_CWORD,
1042         /* 131     1      */ CWORD_CWORD_CWORD_CWORD,
1043         /* 132     2      */ CWORD_CWORD_CWORD_CWORD,
1044         /* 133     3      */ CWORD_CWORD_CWORD_CWORD,
1045         /* 134     4      */ CWORD_CWORD_CWORD_CWORD,
1046         /* 135     5      */ CWORD_CWORD_CWORD_CWORD,
1047         /* 136     6      */ CWORD_CWORD_CWORD_CWORD,
1048         /* 137     7      */ CWORD_CWORD_CWORD_CWORD,
1049         /* 138     8      */ CWORD_CWORD_CWORD_CWORD,
1050         /* 139     9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
1051         /* 140    10 "\n" */ CNL_CNL_CNL_CNL,
1052         /* 141    11      */ CWORD_CWORD_CWORD_CWORD,
1053         /* 142    12      */ CWORD_CWORD_CWORD_CWORD,
1054         /* 143    13      */ CWORD_CWORD_CWORD_CWORD,
1055         /* 144    14      */ CWORD_CWORD_CWORD_CWORD,
1056         /* 145    15      */ CWORD_CWORD_CWORD_CWORD,
1057         /* 146    16      */ CWORD_CWORD_CWORD_CWORD,
1058         /* 147    17      */ CWORD_CWORD_CWORD_CWORD,
1059         /* 148    18      */ CWORD_CWORD_CWORD_CWORD,
1060         /* 149    19      */ CWORD_CWORD_CWORD_CWORD,
1061         /* 150    20      */ CWORD_CWORD_CWORD_CWORD,
1062         /* 151    21      */ CWORD_CWORD_CWORD_CWORD,
1063         /* 152    22      */ CWORD_CWORD_CWORD_CWORD,
1064         /* 153    23      */ CWORD_CWORD_CWORD_CWORD,
1065         /* 154    24      */ CWORD_CWORD_CWORD_CWORD,
1066         /* 155    25      */ CWORD_CWORD_CWORD_CWORD,
1067         /* 156    26      */ CWORD_CWORD_CWORD_CWORD,
1068         /* 157    27      */ CWORD_CWORD_CWORD_CWORD,
1069         /* 158    28      */ CWORD_CWORD_CWORD_CWORD,
1070         /* 159    29      */ CWORD_CWORD_CWORD_CWORD,
1071         /* 160    30      */ CWORD_CWORD_CWORD_CWORD,
1072         /* 161    31      */ CWORD_CWORD_CWORD_CWORD,
1073         /* 162    32  " " */ CSPCL_CWORD_CWORD_CWORD,
1074         /* 163    33  "!" */ CWORD_CCTL_CCTL_CWORD,
1075         /* 164    34  """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
1076         /* 165    35  "#" */ CWORD_CWORD_CWORD_CWORD,
1077         /* 166    36  "$" */ CVAR_CVAR_CWORD_CVAR,
1078         /* 167    37  "%" */ CWORD_CWORD_CWORD_CWORD,
1079         /* 168    38  "&" */ CSPCL_CWORD_CWORD_CWORD,
1080         /* 169    39  "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
1081         /* 170    40  "(" */ CSPCL_CWORD_CWORD_CLP,
1082         /* 171    41  ")" */ CSPCL_CWORD_CWORD_CRP,
1083         /* 172    42  "*" */ CWORD_CCTL_CCTL_CWORD,
1084         /* 173    43  "+" */ CWORD_CWORD_CWORD_CWORD,
1085         /* 174    44  "," */ CWORD_CWORD_CWORD_CWORD,
1086         /* 175    45  "-" */ CWORD_CCTL_CCTL_CWORD,
1087         /* 176    46  "." */ CWORD_CWORD_CWORD_CWORD,
1088         /* 177    47  "/" */ CWORD_CCTL_CCTL_CWORD,
1089         /* 178    48  "0" */ CWORD_CWORD_CWORD_CWORD,
1090         /* 179    49  "1" */ CWORD_CWORD_CWORD_CWORD,
1091         /* 180    50  "2" */ CWORD_CWORD_CWORD_CWORD,
1092         /* 181    51  "3" */ CWORD_CWORD_CWORD_CWORD,
1093         /* 182    52  "4" */ CWORD_CWORD_CWORD_CWORD,
1094         /* 183    53  "5" */ CWORD_CWORD_CWORD_CWORD,
1095         /* 184    54  "6" */ CWORD_CWORD_CWORD_CWORD,
1096         /* 185    55  "7" */ CWORD_CWORD_CWORD_CWORD,
1097         /* 186    56  "8" */ CWORD_CWORD_CWORD_CWORD,
1098         /* 187    57  "9" */ CWORD_CWORD_CWORD_CWORD,
1099         /* 188    58  ":" */ CWORD_CCTL_CCTL_CWORD,
1100         /* 189    59  ";" */ CSPCL_CWORD_CWORD_CWORD,
1101         /* 190    60  "<" */ CSPCL_CWORD_CWORD_CWORD,
1102         /* 191    61  "=" */ CWORD_CCTL_CCTL_CWORD,
1103         /* 192    62  ">" */ CSPCL_CWORD_CWORD_CWORD,
1104         /* 193    63  "?" */ CWORD_CCTL_CCTL_CWORD,
1105         /* 194    64  "@" */ CWORD_CWORD_CWORD_CWORD,
1106         /* 195    65  "A" */ CWORD_CWORD_CWORD_CWORD,
1107         /* 196    66  "B" */ CWORD_CWORD_CWORD_CWORD,
1108         /* 197    67  "C" */ CWORD_CWORD_CWORD_CWORD,
1109         /* 198    68  "D" */ CWORD_CWORD_CWORD_CWORD,
1110         /* 199    69  "E" */ CWORD_CWORD_CWORD_CWORD,
1111         /* 200    70  "F" */ CWORD_CWORD_CWORD_CWORD,
1112         /* 201    71  "G" */ CWORD_CWORD_CWORD_CWORD,
1113         /* 202    72  "H" */ CWORD_CWORD_CWORD_CWORD,
1114         /* 203    73  "I" */ CWORD_CWORD_CWORD_CWORD,
1115         /* 204    74  "J" */ CWORD_CWORD_CWORD_CWORD,
1116         /* 205    75  "K" */ CWORD_CWORD_CWORD_CWORD,
1117         /* 206    76  "L" */ CWORD_CWORD_CWORD_CWORD,
1118         /* 207    77  "M" */ CWORD_CWORD_CWORD_CWORD,
1119         /* 208    78  "N" */ CWORD_CWORD_CWORD_CWORD,
1120         /* 209    79  "O" */ CWORD_CWORD_CWORD_CWORD,
1121         /* 210    80  "P" */ CWORD_CWORD_CWORD_CWORD,
1122         /* 211    81  "Q" */ CWORD_CWORD_CWORD_CWORD,
1123         /* 212    82  "R" */ CWORD_CWORD_CWORD_CWORD,
1124         /* 213    83  "S" */ CWORD_CWORD_CWORD_CWORD,
1125         /* 214    84  "T" */ CWORD_CWORD_CWORD_CWORD,
1126         /* 215    85  "U" */ CWORD_CWORD_CWORD_CWORD,
1127         /* 216    86  "V" */ CWORD_CWORD_CWORD_CWORD,
1128         /* 217    87  "W" */ CWORD_CWORD_CWORD_CWORD,
1129         /* 218    88  "X" */ CWORD_CWORD_CWORD_CWORD,
1130         /* 219    89  "Y" */ CWORD_CWORD_CWORD_CWORD,
1131         /* 220    90  "Z" */ CWORD_CWORD_CWORD_CWORD,
1132         /* 221    91  "[" */ CWORD_CCTL_CCTL_CWORD,
1133         /* 222    92  "\" */ CBACK_CBACK_CCTL_CBACK,
1134         /* 223    93  "]" */ CWORD_CCTL_CCTL_CWORD,
1135         /* 224    94  "^" */ CWORD_CWORD_CWORD_CWORD,
1136         /* 225    95  "_" */ CWORD_CWORD_CWORD_CWORD,
1137         /* 226    96  "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
1138         /* 227    97  "a" */ CWORD_CWORD_CWORD_CWORD,
1139         /* 228    98  "b" */ CWORD_CWORD_CWORD_CWORD,
1140         /* 229    99  "c" */ CWORD_CWORD_CWORD_CWORD,
1141         /* 230   100  "d" */ CWORD_CWORD_CWORD_CWORD,
1142         /* 231   101  "e" */ CWORD_CWORD_CWORD_CWORD,
1143         /* 232   102  "f" */ CWORD_CWORD_CWORD_CWORD,
1144         /* 233   103  "g" */ CWORD_CWORD_CWORD_CWORD,
1145         /* 234   104  "h" */ CWORD_CWORD_CWORD_CWORD,
1146         /* 235   105  "i" */ CWORD_CWORD_CWORD_CWORD,
1147         /* 236   106  "j" */ CWORD_CWORD_CWORD_CWORD,
1148         /* 237   107  "k" */ CWORD_CWORD_CWORD_CWORD,
1149         /* 238   108  "l" */ CWORD_CWORD_CWORD_CWORD,
1150         /* 239   109  "m" */ CWORD_CWORD_CWORD_CWORD,
1151         /* 240   110  "n" */ CWORD_CWORD_CWORD_CWORD,
1152         /* 241   111  "o" */ CWORD_CWORD_CWORD_CWORD,
1153         /* 242   112  "p" */ CWORD_CWORD_CWORD_CWORD,
1154         /* 243   113  "q" */ CWORD_CWORD_CWORD_CWORD,
1155         /* 244   114  "r" */ CWORD_CWORD_CWORD_CWORD,
1156         /* 245   115  "s" */ CWORD_CWORD_CWORD_CWORD,
1157         /* 246   116  "t" */ CWORD_CWORD_CWORD_CWORD,
1158         /* 247   117  "u" */ CWORD_CWORD_CWORD_CWORD,
1159         /* 248   118  "v" */ CWORD_CWORD_CWORD_CWORD,
1160         /* 249   119  "w" */ CWORD_CWORD_CWORD_CWORD,
1161         /* 250   120  "x" */ CWORD_CWORD_CWORD_CWORD,
1162         /* 251   121  "y" */ CWORD_CWORD_CWORD_CWORD,
1163         /* 252   122  "z" */ CWORD_CWORD_CWORD_CWORD,
1164         /* 253   123  "{" */ CWORD_CWORD_CWORD_CWORD,
1165         /* 254   124  "|" */ CSPCL_CWORD_CWORD_CWORD,
1166         /* 255   125  "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
1167         /* 256   126  "~" */ CWORD_CCTL_CCTL_CWORD,
1168         /* 257   127      */ CWORD_CWORD_CWORD_CWORD,
1169 };
1170
1171 #endif                                                  /* USE_SIT_FUNCTION */
1172
1173 /*      $NetBSD: alias.c,v 1.11 2002/11/24 22:35:38 christos Exp $      */
1174
1175
1176 #define ATABSIZE 39
1177
1178 static int     funcblocksize;          /* size of structures in function */
1179 static int     funcstringsize;         /* size of strings in node */
1180 static pointer funcblock;              /* block to allocate function from */
1181 static char   *funcstring;             /* block to allocate strings from */
1182
1183 static const short nodesize[26] = {
1184       SHELL_ALIGN(sizeof (struct ncmd)),
1185       SHELL_ALIGN(sizeof (struct npipe)),
1186       SHELL_ALIGN(sizeof (struct nredir)),
1187       SHELL_ALIGN(sizeof (struct nredir)),
1188       SHELL_ALIGN(sizeof (struct nredir)),
1189       SHELL_ALIGN(sizeof (struct nbinary)),
1190       SHELL_ALIGN(sizeof (struct nbinary)),
1191       SHELL_ALIGN(sizeof (struct nbinary)),
1192       SHELL_ALIGN(sizeof (struct nif)),
1193       SHELL_ALIGN(sizeof (struct nbinary)),
1194       SHELL_ALIGN(sizeof (struct nbinary)),
1195       SHELL_ALIGN(sizeof (struct nfor)),
1196       SHELL_ALIGN(sizeof (struct ncase)),
1197       SHELL_ALIGN(sizeof (struct nclist)),
1198       SHELL_ALIGN(sizeof (struct narg)),
1199       SHELL_ALIGN(sizeof (struct narg)),
1200       SHELL_ALIGN(sizeof (struct nfile)),
1201       SHELL_ALIGN(sizeof (struct nfile)),
1202       SHELL_ALIGN(sizeof (struct nfile)),
1203       SHELL_ALIGN(sizeof (struct nfile)),
1204       SHELL_ALIGN(sizeof (struct nfile)),
1205       SHELL_ALIGN(sizeof (struct ndup)),
1206       SHELL_ALIGN(sizeof (struct ndup)),
1207       SHELL_ALIGN(sizeof (struct nhere)),
1208       SHELL_ALIGN(sizeof (struct nhere)),
1209       SHELL_ALIGN(sizeof (struct nnot)),
1210 };
1211
1212
1213 static void calcsize(union node *);
1214 static void sizenodelist(struct nodelist *);
1215 static union node *copynode(union node *);
1216 static struct nodelist *copynodelist(struct nodelist *);
1217 static char *nodesavestr(char *);
1218
1219
1220
1221 static void evalstring(char *);
1222 union node;     /* BLETCH for ansi C */
1223 static void evaltree(union node *, int);
1224 static void evalbackcmd(union node *, struct backcmd *);
1225
1226 /* in_function returns nonzero if we are currently evaluating a function */
1227 #define in_function()   funcnest
1228 static int evalskip;                   /* set if we are skipping commands */
1229 static int skipcount;           /* number of levels to skip */
1230 static int funcnest;                   /* depth of function calls */
1231
1232 /* reasons for skipping commands (see comment on breakcmd routine) */
1233 #define SKIPBREAK       1
1234 #define SKIPCONT        2
1235 #define SKIPFUNC        3
1236 #define SKIPFILE        4
1237
1238 /*
1239  * This file was generated by the mkbuiltins program.
1240  */
1241
1242 #ifdef JOBS
1243 static int bgcmd(int, char **);
1244 #endif
1245 static int breakcmd(int, char **);
1246 static int cdcmd(int, char **);
1247 #ifdef CONFIG_ASH_CMDCMD
1248 static int commandcmd(int, char **);
1249 #endif
1250 static int dotcmd(int, char **);
1251 static int evalcmd(int, char **);
1252 static int execcmd(int, char **);
1253 static int exitcmd(int, char **);
1254 static int exportcmd(int, char **);
1255 static int falsecmd(int, char **);
1256 #ifdef JOBS
1257 static int fgcmd(int, char **);
1258 #endif
1259 #ifdef CONFIG_ASH_GETOPTS
1260 static int getoptscmd(int, char **);
1261 #endif
1262 static int hashcmd(int, char **);
1263 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1264 static int helpcmd(int argc, char **argv);
1265 #endif
1266 #ifdef JOBS
1267 static int jobscmd(int, char **);
1268 #endif
1269 #ifdef CONFIG_ASH_MATH_SUPPORT
1270 static int letcmd(int, char **);
1271 #endif
1272 static int localcmd(int, char **);
1273 static int pwdcmd(int, char **);
1274 static int readcmd(int, char **);
1275 static int returncmd(int, char **);
1276 static int setcmd(int, char **);
1277 static int shiftcmd(int, char **);
1278 static int timescmd(int, char **);
1279 static int trapcmd(int, char **);
1280 static int truecmd(int, char **);
1281 static int typecmd(int, char **);
1282 static int umaskcmd(int, char **);
1283 static int unsetcmd(int, char **);
1284 static int waitcmd(int, char **);
1285 static int ulimitcmd(int, char **);
1286 #ifdef JOBS
1287 static int killcmd(int, char **);
1288 #endif
1289
1290 /*      $NetBSD: mail.h,v 1.9 2002/11/24 22:35:40 christos Exp $        */
1291
1292 #ifdef CONFIG_ASH_MAIL
1293 static void chkmail(void);
1294 static void changemail(const char *);
1295 #endif
1296
1297 /*      $NetBSD: exec.h,v 1.20 2003/01/22 20:36:04 dsl Exp $    */
1298
1299 /* values of cmdtype */
1300 #define CMDUNKNOWN      -1      /* no entry in table for command */
1301 #define CMDNORMAL       0       /* command is an executable program */
1302 #define CMDFUNCTION     1       /* command is a shell function */
1303 #define CMDBUILTIN      2       /* command is a shell builtin */
1304
1305 struct builtincmd {
1306         const char *name;
1307         int (*builtin)(int, char **);
1308         /* unsigned flags; */
1309 };
1310
1311 #ifdef CONFIG_ASH_CMDCMD
1312 # ifdef JOBS
1313 #  ifdef CONFIG_ASH_ALIAS
1314 #    define COMMANDCMD (builtincmd + 7)
1315 #    define EXECCMD (builtincmd + 10)
1316 #  else
1317 #    define COMMANDCMD (builtincmd + 6)
1318 #    define EXECCMD (builtincmd + 9)
1319 #  endif
1320 # else /* ! JOBS */
1321 #  ifdef CONFIG_ASH_ALIAS
1322 #    define COMMANDCMD (builtincmd + 6)
1323 #    define EXECCMD (builtincmd + 9)
1324 #  else
1325 #    define COMMANDCMD (builtincmd + 5)
1326 #    define EXECCMD (builtincmd + 8)
1327 #  endif
1328 # endif /* JOBS */
1329 #else   /* ! CONFIG_ASH_CMDCMD */
1330 # ifdef JOBS
1331 #  ifdef CONFIG_ASH_ALIAS
1332 #    define EXECCMD (builtincmd + 9)
1333 #  else
1334 #    define EXECCMD (builtincmd + 8)
1335 #  endif
1336 # else /* ! JOBS */
1337 #  ifdef CONFIG_ASH_ALIAS
1338 #    define EXECCMD (builtincmd + 8)
1339 #  else
1340 #    define EXECCMD (builtincmd + 7)
1341 #  endif
1342 # endif /* JOBS */
1343 #endif /* CONFIG_ASH_CMDCMD */
1344
1345 #define BUILTIN_NOSPEC  "0"
1346 #define BUILTIN_SPECIAL "1"
1347 #define BUILTIN_REGULAR "2"
1348 #define BUILTIN_SPEC_REG "3"
1349 #define BUILTIN_ASSIGN  "4"
1350 #define BUILTIN_SPEC_ASSG  "5"
1351 #define BUILTIN_REG_ASSG   "6"
1352 #define BUILTIN_SPEC_REG_ASSG   "7"
1353
1354 #define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1355 #define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
1356 #define IS_BUILTIN_ASSIGN(builtincmd) ((builtincmd)->name[0] & 4)
1357
1358 static const struct builtincmd builtincmd[] = {
1359         { BUILTIN_SPEC_REG      ".", dotcmd },
1360         { BUILTIN_SPEC_REG      ":", truecmd },
1361 #ifdef CONFIG_ASH_ALIAS
1362         { BUILTIN_REG_ASSG      "alias", aliascmd },
1363 #endif
1364 #ifdef JOBS
1365         { BUILTIN_REGULAR       "bg", bgcmd },
1366 #endif
1367         { BUILTIN_SPEC_REG      "break", breakcmd },
1368         { BUILTIN_REGULAR       "cd", cdcmd },
1369         { BUILTIN_NOSPEC        "chdir", cdcmd },
1370 #ifdef CONFIG_ASH_CMDCMD
1371         { BUILTIN_REGULAR       "command", commandcmd },
1372 #endif
1373         { BUILTIN_SPEC_REG      "continue", breakcmd },
1374         { BUILTIN_SPEC_REG      "eval", evalcmd },
1375         { BUILTIN_SPEC_REG      "exec", execcmd },
1376         { BUILTIN_SPEC_REG      "exit", exitcmd },
1377         { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
1378         { BUILTIN_REGULAR       "false", falsecmd },
1379 #ifdef JOBS
1380         { BUILTIN_REGULAR       "fg", fgcmd },
1381 #endif
1382 #ifdef CONFIG_ASH_GETOPTS
1383         { BUILTIN_REGULAR       "getopts", getoptscmd },
1384 #endif
1385         { BUILTIN_NOSPEC        "hash", hashcmd },
1386 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1387         { BUILTIN_NOSPEC        "help", helpcmd },
1388 #endif
1389 #ifdef JOBS
1390         { BUILTIN_REGULAR       "jobs", jobscmd },
1391         { BUILTIN_REGULAR       "kill", killcmd },
1392 #endif
1393 #ifdef CONFIG_ASH_MATH_SUPPORT
1394         { BUILTIN_NOSPEC        "let", letcmd },
1395 #endif
1396         { BUILTIN_ASSIGN        "local", localcmd },
1397         { BUILTIN_NOSPEC        "pwd", pwdcmd },
1398         { BUILTIN_REGULAR       "read", readcmd },
1399         { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
1400         { BUILTIN_SPEC_REG      "return", returncmd },
1401         { BUILTIN_SPEC_REG      "set", setcmd },
1402         { BUILTIN_SPEC_REG      "shift", shiftcmd },
1403         { BUILTIN_SPEC_REG      "times", timescmd },
1404         { BUILTIN_SPEC_REG      "trap", trapcmd },
1405         { BUILTIN_REGULAR       "true", truecmd },
1406         { BUILTIN_NOSPEC        "type", typecmd },
1407         { BUILTIN_NOSPEC        "ulimit", ulimitcmd },
1408         { BUILTIN_REGULAR       "umask", umaskcmd },
1409 #ifdef CONFIG_ASH_ALIAS
1410         { BUILTIN_REGULAR       "unalias", unaliascmd },
1411 #endif
1412         { BUILTIN_SPEC_REG      "unset", unsetcmd },
1413         { BUILTIN_REGULAR       "wait", waitcmd },
1414 };
1415
1416 #define NUMBUILTINS  (sizeof (builtincmd) / sizeof (struct builtincmd) )
1417
1418
1419
1420 struct cmdentry {
1421         int cmdtype;
1422         union param {
1423                 int index;
1424                 const struct builtincmd *cmd;
1425                 struct funcnode *func;
1426         } u;
1427 };
1428
1429
1430 /* action to find_command() */
1431 #define DO_ERR          0x01    /* prints errors */
1432 #define DO_ABS          0x02    /* checks absolute paths */
1433 #define DO_NOFUNC       0x04    /* don't return shell functions, for command */
1434 #define DO_ALTPATH      0x08    /* using alternate path */
1435 #define DO_ALTBLTIN     0x20    /* %builtin in alt. path */
1436
1437 static const char *pathopt;     /* set by padvance */
1438
1439 static void shellexec(char **, const char *, int)
1440     __attribute__((__noreturn__));
1441 static char *padvance(const char **, const char *);
1442 static void find_command(char *, struct cmdentry *, int, const char *);
1443 static struct builtincmd *find_builtin(const char *);
1444 static void hashcd(void);
1445 static void changepath(const char *);
1446 static void defun(char *, union node *);
1447 static void unsetfunc(const char *);
1448
1449 #ifdef CONFIG_ASH_MATH_SUPPORT_64
1450 typedef int64_t arith_t;
1451 #else
1452 typedef long arith_t;
1453 #endif
1454
1455 #ifdef CONFIG_ASH_MATH_SUPPORT
1456 static arith_t dash_arith(const char *);
1457 static arith_t arith(const char *expr, int *perrcode);
1458 #endif
1459
1460 #ifdef CONFIG_ASH_RANDOM_SUPPORT
1461 static unsigned long rseed;
1462 static void change_random(const char *);
1463 # ifndef DYNAMIC_VAR
1464 #  define DYNAMIC_VAR
1465 # endif
1466 #endif
1467
1468 /*      $NetBSD: init.h,v 1.9 2002/11/24 22:35:40 christos Exp $        */
1469
1470 static void reset(void);
1471
1472 /*      $NetBSD: var.h,v 1.21 2003/01/22 20:36:04 dsl Exp $     */
1473
1474 /*
1475  * Shell variables.
1476  */
1477
1478 /* flags */
1479 #define VEXPORT         0x01    /* variable is exported */
1480 #define VREADONLY       0x02    /* variable cannot be modified */
1481 #define VSTRFIXED       0x04    /* variable struct is statically allocated */
1482 #define VTEXTFIXED      0x08    /* text is statically allocated */
1483 #define VSTACK          0x10    /* text is allocated on the stack */
1484 #define VUNSET          0x20    /* the variable is not set */
1485 #define VNOFUNC         0x40    /* don't call the callback function */
1486 #define VNOSET          0x80    /* do not set variable - just readonly test */
1487 #define VNOSAVE         0x100   /* when text is on the heap before setvareq */
1488 #ifdef DYNAMIC_VAR
1489 # define VDYNAMIC        0x200   /* dynamic variable */
1490 # else
1491 # define VDYNAMIC        0
1492 #endif
1493
1494 struct var {
1495         struct var *next;               /* next entry in hash list */
1496         int flags;                      /* flags are defined above */
1497         const char *text;               /* name=value */
1498         void (*func)(const char *);     /* function to be called when  */
1499                                         /* the variable gets set/unset */
1500 };
1501
1502 struct localvar {
1503         struct localvar *next;          /* next local variable in list */
1504         struct var *vp;                 /* the variable that was made local */
1505         int flags;                      /* saved flags */
1506         const char *text;               /* saved text */
1507 };
1508
1509
1510 static struct localvar *localvars;
1511
1512 /*
1513  * Shell variables.
1514  */
1515
1516 #ifdef CONFIG_ASH_GETOPTS
1517 static void getoptsreset(const char *);
1518 #endif
1519
1520 #ifdef CONFIG_LOCALE_SUPPORT
1521 #include <locale.h>
1522 static void change_lc_all(const char *value);
1523 static void change_lc_ctype(const char *value);
1524 #endif
1525
1526
1527 #define VTABSIZE 39
1528
1529 static const char defpathvar[] = "PATH=/usr/local/bin:/usr/bin:/sbin:/bin";
1530 #ifdef IFS_BROKEN
1531 static const char defifsvar[] = "IFS= \t\n";
1532 #define defifs (defifsvar + 4)
1533 #else
1534 static const char defifs[] = " \t\n";
1535 #endif
1536
1537
1538 static struct var varinit[] = {
1539 #ifdef IFS_BROKEN
1540         { 0,    VSTRFIXED|VTEXTFIXED,           defifsvar,      0 },
1541 #else
1542         { 0,    VSTRFIXED|VTEXTFIXED|VUNSET,    "IFS\0",        0 },
1543 #endif
1544
1545 #ifdef CONFIG_ASH_MAIL
1546         { 0,    VSTRFIXED|VTEXTFIXED|VUNSET,    "MAIL\0",       changemail },
1547         { 0,    VSTRFIXED|VTEXTFIXED|VUNSET,    "MAILPATH\0",   changemail },
1548 #endif
1549
1550         { 0,    VSTRFIXED|VTEXTFIXED,           defpathvar,     changepath },
1551         { 0,    VSTRFIXED|VTEXTFIXED,           "PS1=$ ",       0          },
1552         { 0,    VSTRFIXED|VTEXTFIXED,           "PS2=> ",       0          },
1553         { 0,    VSTRFIXED|VTEXTFIXED,           "PS4=+ ",       0          },
1554 #ifdef CONFIG_ASH_GETOPTS
1555         { 0,    VSTRFIXED|VTEXTFIXED,           "OPTIND=1",     getoptsreset },
1556 #endif
1557 #ifdef CONFIG_ASH_RANDOM_SUPPORT
1558         {0, VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random },
1559 #endif
1560 #ifdef CONFIG_LOCALE_SUPPORT
1561         {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0", change_lc_all },
1562         {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0", change_lc_ctype },
1563 #endif
1564 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
1565         {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0", NULL },
1566 #endif
1567 };
1568
1569 #define vifs varinit[0]
1570 #ifdef CONFIG_ASH_MAIL
1571 #define vmail (&vifs)[1]
1572 #define vmpath (&vmail)[1]
1573 #else
1574 #define vmpath vifs
1575 #endif
1576 #define vpath (&vmpath)[1]
1577 #define vps1 (&vpath)[1]
1578 #define vps2 (&vps1)[1]
1579 #define vps4 (&vps2)[1]
1580 #define voptind (&vps4)[1]
1581 #ifdef CONFIG_ASH_GETOPTS
1582 #define vrandom (&voptind)[1]
1583 #else
1584 #define vrandom (&vps4)[1]
1585 #endif
1586 #define defpath (defpathvar + 5)
1587
1588 /*
1589  * The following macros access the values of the above variables.
1590  * They have to skip over the name.  They return the null string
1591  * for unset variables.
1592  */
1593
1594 #define ifsval()        (vifs.text + 4)
1595 #define ifsset()        ((vifs.flags & VUNSET) == 0)
1596 #define mailval()       (vmail.text + 5)
1597 #define mpathval()      (vmpath.text + 9)
1598 #define pathval()       (vpath.text + 5)
1599 #define ps1val()        (vps1.text + 4)
1600 #define ps2val()        (vps2.text + 4)
1601 #define ps4val()        (vps4.text + 4)
1602 #define optindval()     (voptind.text + 7)
1603
1604 #define mpathset()      ((vmpath.flags & VUNSET) == 0)
1605
1606 static void setvar(const char *, const char *, int);
1607 static void setvareq(char *, int);
1608 static void listsetvar(struct strlist *, int);
1609 static char *lookupvar(const char *);
1610 static char *bltinlookup(const char *);
1611 static char **listvars(int, int, char ***);
1612 #define environment() listvars(VEXPORT, VUNSET, 0)
1613 static int showvars(const char *, int, int);
1614 static void poplocalvars(void);
1615 static int unsetvar(const char *);
1616 #ifdef CONFIG_ASH_GETOPTS
1617 static int setvarsafe(const char *, const char *, int);
1618 #endif
1619 static int varcmp(const char *, const char *);
1620 static struct var **hashvar(const char *);
1621
1622
1623 static inline int varequal(const char *a, const char *b) {
1624         return !varcmp(a, b);
1625 }
1626
1627
1628 static int loopnest;            /* current loop nesting level */
1629
1630 /*
1631  * The parsefile structure pointed to by the global variable parsefile
1632  * contains information about the current file being read.
1633  */
1634
1635
1636 struct redirtab {
1637         struct redirtab *next;
1638         int renamed[10];
1639         int nullredirs;
1640 };
1641
1642 static struct redirtab *redirlist;
1643 static int nullredirs;
1644
1645 extern char **environ;
1646
1647 /*      $NetBSD: output.h,v 1.16 2002/11/24 22:35:42 christos Exp $     */
1648
1649
1650 static void outstr(const char *, FILE *);
1651 static void outcslow(int, FILE *);
1652 static void flushall(void);
1653 static void flusherr(void);
1654 static int  out1fmt(const char *, ...)
1655     __attribute__((__format__(__printf__,1,2)));
1656 static int fmtstr(char *, size_t, const char *, ...)
1657     __attribute__((__format__(__printf__,3,4)));
1658
1659 static int preverrout_fd;   /* save fd2 before print debug if xflag is set. */
1660
1661
1662 static void out1str(const char *p)
1663 {
1664         outstr(p, stdout);
1665 }
1666
1667 static void out2str(const char *p)
1668 {
1669         outstr(p, stderr);
1670         flusherr();
1671 }
1672
1673 /*
1674  * Initialization code.
1675  */
1676
1677 /*
1678  * This routine initializes the builtin variables.
1679  */
1680
1681 static inline void
1682 initvar(void)
1683 {
1684         struct var *vp;
1685         struct var *end;
1686         struct var **vpp;
1687
1688         /*
1689          * PS1 depends on uid
1690          */
1691 #if defined(CONFIG_FEATURE_COMMAND_EDITING) && defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
1692         vps1.text = "PS1=\\w \\$ ";
1693 #else
1694         if (!geteuid())
1695                 vps1.text = "PS1=# ";
1696 #endif
1697         vp = varinit;
1698         end = vp + sizeof(varinit) / sizeof(varinit[0]);
1699         do {
1700                 vpp = hashvar(vp->text);
1701                 vp->next = *vpp;
1702                 *vpp = vp;
1703         } while (++vp < end);
1704 }
1705
1706 static inline void
1707 init(void)
1708 {
1709
1710       /* from input.c: */
1711       {
1712               basepf.nextc = basepf.buf = basebuf;
1713       }
1714
1715       /* from trap.c: */
1716       {
1717               signal(SIGCHLD, SIG_DFL);
1718       }
1719
1720       /* from var.c: */
1721       {
1722               char **envp;
1723               char ppid[32];
1724
1725               initvar();
1726               for (envp = environ ; *envp ; envp++) {
1727                       if (strchr(*envp, '=')) {
1728                               setvareq(*envp, VEXPORT|VTEXTFIXED);
1729                       }
1730               }
1731
1732               snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
1733               setvar("PPID", ppid, 0);
1734               setpwd(0, 0);
1735       }
1736 }
1737
1738 /* PEOF (the end of file marker) */
1739
1740 /*
1741  * The input line number.  Input.c just defines this variable, and saves
1742  * and restores it when files are pushed and popped.  The user of this
1743  * package must set its value.
1744  */
1745
1746 static int pgetc(void);
1747 static int pgetc2(void);
1748 static int preadbuffer(void);
1749 static void pungetc(void);
1750 static void pushstring(char *, void *);
1751 static void popstring(void);
1752 static void setinputfile(const char *, int);
1753 static void setinputfd(int, int);
1754 static void setinputstring(char *);
1755 static void popfile(void);
1756 static void popallfiles(void);
1757 static void closescript(void);
1758
1759
1760 /*      $NetBSD: jobs.h,v 1.17 2003/01/22 20:36:04 dsl Exp $    */
1761
1762
1763 /* Mode argument to forkshell.  Don't change FORK_FG or FORK_BG. */
1764 #define FORK_FG 0
1765 #define FORK_BG 1
1766 #define FORK_NOJOB 2
1767
1768 /* mode flags for showjob(s) */
1769 #define SHOW_PGID       0x01    /* only show pgid - for jobs -p */
1770 #define SHOW_PID        0x04    /* include process pid */
1771 #define SHOW_CHANGED    0x08    /* only jobs whose state has changed */
1772
1773
1774 /*
1775  * A job structure contains information about a job.  A job is either a
1776  * single process or a set of processes contained in a pipeline.  In the
1777  * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1778  * array of pids.
1779  */
1780
1781 struct procstat {
1782         pid_t   pid;            /* process id */
1783         int     status;         /* last process status from wait() */
1784         char    *cmd;           /* text of command being run */
1785 };
1786
1787 struct job {
1788         struct procstat ps0;    /* status of process */
1789         struct procstat *ps;    /* status or processes when more than one */
1790 #if JOBS
1791         int stopstatus;         /* status of a stopped job */
1792 #endif
1793         uint32_t
1794                 nprocs: 16,     /* number of processes */
1795                 state: 8,
1796 #define JOBRUNNING      0       /* at least one proc running */
1797 #define JOBSTOPPED      1       /* all procs are stopped */
1798 #define JOBDONE         2       /* all procs are completed */
1799 #if JOBS
1800                 sigint: 1,      /* job was killed by SIGINT */
1801                 jobctl: 1,      /* job running under job control */
1802 #endif
1803                 waited: 1,      /* true if this entry has been waited for */
1804                 used: 1,        /* true if this entry is in used */
1805                 changed: 1;     /* true if status has changed */
1806         struct job *prev_job;   /* previous job */
1807 };
1808
1809 static pid_t backgndpid;        /* pid of last background process */
1810 static int job_warning;         /* user was warned about stopped jobs */
1811 #if JOBS
1812 static int jobctl;              /* true if doing job control */
1813 #endif
1814
1815 static struct job *makejob(union node *, int);
1816 static int forkshell(struct job *, union node *, int);
1817 static int waitforjob(struct job *);
1818 static int stoppedjobs(void);
1819
1820 #if ! JOBS
1821 #define setjobctl(on)   /* do nothing */
1822 #else
1823 static void setjobctl(int);
1824 static void showjobs(FILE *, int);
1825 #endif
1826
1827 /*      $NetBSD: main.h,v 1.9 2002/11/24 22:35:41 christos Exp $        */
1828
1829
1830 /* pid of main shell */
1831 static int rootpid;
1832 /* true if we aren't a child of the main shell */
1833 static int rootshell;
1834
1835 static void readcmdfile(char *);
1836 static void cmdloop(int);
1837
1838 /*      $NetBSD: memalloc.h,v 1.13 2003/01/22 20:36:04 dsl Exp $        */
1839
1840
1841 struct stackmark {
1842         struct stack_block *stackp;
1843         char *stacknxt;
1844         size_t stacknleft;
1845         struct stackmark *marknext;
1846 };
1847
1848 /* minimum size of a block */
1849 #define MINSIZE SHELL_ALIGN(504)
1850
1851 struct stack_block {
1852         struct stack_block *prev;
1853         char space[MINSIZE];
1854 };
1855
1856 static struct stack_block stackbase;
1857 static struct stack_block *stackp = &stackbase;
1858 static struct stackmark *markp;
1859 static char *stacknxt = stackbase.space;
1860 static size_t stacknleft = MINSIZE;
1861 static char *sstrend = stackbase.space + MINSIZE;
1862 static int herefd = -1;
1863
1864
1865 static pointer ckmalloc(size_t);
1866 static pointer ckrealloc(pointer, size_t);
1867 static char *savestr(const char *);
1868 static pointer stalloc(size_t);
1869 static void stunalloc(pointer);
1870 static void setstackmark(struct stackmark *);
1871 static void popstackmark(struct stackmark *);
1872 static void growstackblock(void);
1873 static void *growstackstr(void);
1874 static char *makestrspace(size_t, char *);
1875 static char *stnputs(const char *, size_t, char *);
1876 static char *stputs(const char *, char *);
1877
1878
1879 static inline char *_STPUTC(char c, char *p) {
1880         if (p == sstrend)
1881                 p = growstackstr();
1882         *p++ = c;
1883         return p;
1884 }
1885
1886 #define stackblock() ((void *)stacknxt)
1887 #define stackblocksize() stacknleft
1888 #define STARTSTACKSTR(p) ((p) = stackblock())
1889 #define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1890 #define CHECKSTRSPACE(n, p) \
1891         ({ \
1892                 char *q = (p); \
1893                 size_t l = (n); \
1894                 size_t m = sstrend - q; \
1895                 if (l > m) \
1896                         (p) = makestrspace(l, q); \
1897                 0; \
1898         })
1899 #define USTPUTC(c, p)   (*p++ = (c))
1900 #define STACKSTRNUL(p)  ((p) == sstrend? (p = growstackstr(), *p = '\0') : (*p = '\0'))
1901 #define STUNPUTC(p)     (--p)
1902 #define STTOPC(p)       p[-1]
1903 #define STADJUST(amount, p)     (p += (amount))
1904
1905 #define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1906 #define ungrabstackstr(s, p) stunalloc((s))
1907 #define stackstrend() ((void *)sstrend)
1908
1909 #define ckfree(p)       free((pointer)(p))
1910
1911 /*      $NetBSD: mystring.h,v 1.10 2002/11/24 22:35:42 christos Exp $   */
1912
1913
1914 #define DOLATSTRLEN 4
1915
1916 static char *prefix(const char *, const char *);
1917 static int number(const char *);
1918 static int is_number(const char *);
1919 static char *single_quote(const char *);
1920 static char *sstrdup(const char *);
1921
1922 #define equal(s1, s2)   (strcmp(s1, s2) == 0)
1923 #define scopy(s1, s2)   ((void)strcpy(s2, s1))
1924
1925 /*      $NetBSD: options.h,v 1.16 2003/01/22 20:36:04 dsl Exp $ */
1926
1927 struct shparam {
1928         int nparam;             /* # of positional parameters (without $0) */
1929         unsigned char malloc;   /* if parameter list dynamically allocated */
1930         char **p;               /* parameter list */
1931 #ifdef CONFIG_ASH_GETOPTS
1932         int optind;             /* next parameter to be processed by getopts */
1933         int optoff;             /* used by getopts */
1934 #endif
1935 };
1936
1937
1938 #define eflag optlist[0]
1939 #define fflag optlist[1]
1940 #define Iflag optlist[2]
1941 #define iflag optlist[3]
1942 #define mflag optlist[4]
1943 #define nflag optlist[5]
1944 #define sflag optlist[6]
1945 #define xflag optlist[7]
1946 #define vflag optlist[8]
1947 #define Cflag optlist[9]
1948 #define aflag optlist[10]
1949 #define bflag optlist[11]
1950 #define uflag optlist[12]
1951 #define qflag optlist[13]
1952
1953 #ifdef DEBUG
1954 #define nolog optlist[14]
1955 #define debug optlist[15]
1956 #define NOPTS   16
1957 #else
1958 #define NOPTS   14
1959 #endif
1960
1961 /*      $NetBSD: options.c,v 1.33 2003/01/22 20:36:04 dsl Exp $ */
1962
1963
1964 static const char *const optletters_optnames[NOPTS] = {
1965         "e"   "errexit",
1966         "f"   "noglob",
1967         "I"   "ignoreeof",
1968         "i"   "interactive",
1969         "m"   "monitor",
1970         "n"   "noexec",
1971         "s"   "stdin",
1972         "x"   "xtrace",
1973         "v"   "verbose",
1974         "C"   "noclobber",
1975         "a"   "allexport",
1976         "b"   "notify",
1977         "u"   "nounset",
1978         "q"   "quietprofile",
1979 #ifdef DEBUG
1980         "\0"  "nolog",
1981         "\0"  "debug",
1982 #endif
1983 };
1984
1985 #define optletters(n) optletters_optnames[(n)][0]
1986 #define optnames(n) (&optletters_optnames[(n)][1])
1987
1988
1989 static char optlist[NOPTS];
1990
1991
1992 static char *arg0;                     /* value of $0 */
1993 static struct shparam shellparam;      /* $@ current positional parameters */
1994 static char **argptr;                  /* argument list for builtin commands */
1995 static char *optionarg;                /* set by nextopt (like getopt) */
1996 static char *optptr;                   /* used by nextopt */
1997
1998 static char *minusc;                   /* argument to -c option */
1999
2000
2001 static void procargs(int, char **);
2002 static void optschanged(void);
2003 static void setparam(char **);
2004 static void freeparam(volatile struct shparam *);
2005 static int shiftcmd(int, char **);
2006 static int setcmd(int, char **);
2007 static int nextopt(const char *);
2008
2009 /*      $NetBSD: redir.h,v 1.14 2002/11/24 22:35:43 christos Exp $      */
2010
2011 /* flags passed to redirect */
2012 #define REDIR_PUSH 01           /* save previous values of file descriptors */
2013 #define REDIR_SAVEFD2 03       /* set preverrout */
2014
2015 union node;
2016 static void redirect(union node *, int);
2017 static void popredir(int);
2018 static void clearredir(int);
2019 static int copyfd(int, int);
2020 static int redirectsafe(union node *, int);
2021
2022 /*      $NetBSD: show.h,v 1.6 2003/01/22 20:36:04 dsl Exp $     */
2023
2024
2025 #ifdef DEBUG
2026 static void showtree(union node *);
2027 static void trace(const char *, ...);
2028 static void tracev(const char *, va_list);
2029 static void trargs(char **);
2030 static void trputc(int);
2031 static void trputs(const char *);
2032 static void opentrace(void);
2033 #endif
2034
2035 /*      $NetBSD: trap.h,v 1.16 2002/11/24 22:35:43 christos Exp $       */
2036
2037
2038 /* trap handler commands */
2039 static char *trap[NSIG];
2040 /* current value of signal */
2041 static char sigmode[NSIG - 1];
2042 /* indicates specified signal received */
2043 static char gotsig[NSIG - 1];
2044
2045 static void clear_traps(void);
2046 static void setsignal(int);
2047 static void ignoresig(int);
2048 static void onsig(int);
2049 static void dotrap(void);
2050 static void setinteractive(int);
2051 static void exitshell(void) __attribute__((__noreturn__));
2052 static int decode_signal(const char *, int);
2053
2054 /*
2055  * This routine is called when an error or an interrupt occurs in an
2056  * interactive shell and control is returned to the main command loop.
2057  */
2058
2059 static void
2060 reset(void)
2061 {
2062       /* from eval.c: */
2063       {
2064               evalskip = 0;
2065               loopnest = 0;
2066               funcnest = 0;
2067       }
2068
2069       /* from input.c: */
2070       {
2071               parselleft = parsenleft = 0;      /* clear input buffer */
2072               popallfiles();
2073       }
2074
2075       /* from parser.c: */
2076       {
2077               tokpushback = 0;
2078               checkkwd = 0;
2079       }
2080
2081       /* from redir.c: */
2082       {
2083               clearredir(0);
2084       }
2085
2086 }
2087
2088 #ifdef CONFIG_ASH_ALIAS
2089 static struct alias *atab[ATABSIZE];
2090
2091 static void setalias(const char *, const char *);
2092 static struct alias *freealias(struct alias *);
2093 static struct alias **__lookupalias(const char *);
2094
2095 static void
2096 setalias(const char *name, const char *val)
2097 {
2098         struct alias *ap, **app;
2099
2100         app = __lookupalias(name);
2101         ap = *app;
2102         INTOFF;
2103         if (ap) {
2104                 if (!(ap->flag & ALIASINUSE)) {
2105                         ckfree(ap->val);
2106                 }
2107                 ap->val = savestr(val);
2108                 ap->flag &= ~ALIASDEAD;
2109         } else {
2110                 /* not found */
2111                 ap = ckmalloc(sizeof (struct alias));
2112                 ap->name = savestr(name);
2113                 ap->val = savestr(val);
2114                 ap->flag = 0;
2115                 ap->next = 0;
2116                 *app = ap;
2117         }
2118         INTON;
2119 }
2120
2121 static int
2122 unalias(const char *name)
2123 {
2124         struct alias **app;
2125
2126         app = __lookupalias(name);
2127
2128         if (*app) {
2129                 INTOFF;
2130                 *app = freealias(*app);
2131                 INTON;
2132                 return (0);
2133         }
2134
2135         return (1);
2136 }
2137
2138 static void
2139 rmaliases(void)
2140 {
2141         struct alias *ap, **app;
2142         int i;
2143
2144         INTOFF;
2145         for (i = 0; i < ATABSIZE; i++) {
2146                 app = &atab[i];
2147                 for (ap = *app; ap; ap = *app) {
2148                         *app = freealias(*app);
2149                         if (ap == *app) {
2150                                 app = &ap->next;
2151                         }
2152                 }
2153         }
2154         INTON;
2155 }
2156
2157 static struct alias *
2158 lookupalias(const char *name, int check)
2159 {
2160         struct alias *ap = *__lookupalias(name);
2161
2162         if (check && ap && (ap->flag & ALIASINUSE))
2163                 return (NULL);
2164         return (ap);
2165 }
2166
2167 /*
2168  * TODO - sort output
2169  */
2170 static int
2171 aliascmd(int argc, char **argv)
2172 {
2173         char *n, *v;
2174         int ret = 0;
2175         struct alias *ap;
2176
2177         if (argc == 1) {
2178                 int i;
2179
2180                 for (i = 0; i < ATABSIZE; i++)
2181                         for (ap = atab[i]; ap; ap = ap->next) {
2182                                 printalias(ap);
2183                         }
2184                 return (0);
2185         }
2186         while ((n = *++argv) != NULL) {
2187                 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
2188                         if ((ap = *__lookupalias(n)) == NULL) {
2189                                 fprintf(stderr, "%s: %s not found\n", "alias", n);
2190                                 ret = 1;
2191                         } else
2192                                 printalias(ap);
2193                 } else {
2194                         *v++ = '\0';
2195                         setalias(n, v);
2196                 }
2197         }
2198
2199         return (ret);
2200 }
2201
2202 static int
2203 unaliascmd(int argc, char **argv)
2204 {
2205         int i;
2206
2207         while ((i = nextopt("a")) != '\0') {
2208                 if (i == 'a') {
2209                         rmaliases();
2210                         return (0);
2211                 }
2212         }
2213         for (i = 0; *argptr; argptr++) {
2214                 if (unalias(*argptr)) {
2215                         fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
2216                         i = 1;
2217                 }
2218         }
2219
2220         return (i);
2221 }
2222
2223 static struct alias *
2224 freealias(struct alias *ap) {
2225         struct alias *next;
2226
2227         if (ap->flag & ALIASINUSE) {
2228                 ap->flag |= ALIASDEAD;
2229                 return ap;
2230         }
2231
2232         next = ap->next;
2233         ckfree(ap->name);
2234         ckfree(ap->val);
2235         ckfree(ap);
2236         return next;
2237 }
2238
2239 static void
2240 printalias(const struct alias *ap) {
2241         out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
2242 }
2243
2244 static struct alias **
2245 __lookupalias(const char *name) {
2246         unsigned int hashval;
2247         struct alias **app;
2248         const char *p;
2249         unsigned int ch;
2250
2251         p = name;
2252
2253         ch = (unsigned char)*p;
2254         hashval = ch << 4;
2255         while (ch) {
2256                 hashval += ch;
2257                 ch = (unsigned char)*++p;
2258         }
2259         app = &atab[hashval % ATABSIZE];
2260
2261         for (; *app; app = &(*app)->next) {
2262                 if (equal(name, (*app)->name)) {
2263                         break;
2264                 }
2265         }
2266
2267         return app;
2268 }
2269 #endif /* CONFIG_ASH_ALIAS */
2270
2271
2272 /*      $NetBSD: cd.c,v 1.30 2003/01/22 20:36:03 dsl Exp $      */
2273
2274 /*
2275  * The cd and pwd commands.
2276  */
2277
2278 #define CD_PHYSICAL 1
2279 #define CD_PRINT 2
2280
2281 static int docd(const char *, int);
2282 static int cdopt(void);
2283
2284 static char *curdir = nullstr;          /* current working directory */
2285 static char *physdir = nullstr;         /* physical working directory */
2286
2287 static int
2288 cdopt(void)
2289 {
2290         int flags = 0;
2291         int i, j;
2292
2293         j = 'L';
2294         while ((i = nextopt("LP"))) {
2295                 if (i != j) {
2296                         flags ^= CD_PHYSICAL;
2297                         j = i;
2298                 }
2299         }
2300
2301         return flags;
2302 }
2303
2304 static int
2305 cdcmd(int argc, char **argv)
2306 {
2307         const char *dest;
2308         const char *path;
2309         const char *p;
2310         char c;
2311         struct stat statb;
2312         int flags;
2313
2314         flags = cdopt();
2315         dest = *argptr;
2316         if (!dest)
2317                 dest = bltinlookup(homestr);
2318         else if (dest[0] == '-' && dest[1] == '\0') {
2319                 dest = bltinlookup("OLDPWD");
2320                 if ( !dest ) goto out;
2321                 flags |= CD_PRINT;
2322                 goto step7;
2323         }
2324         if (!dest)
2325                 dest = nullstr;
2326         if (*dest == '/')
2327                 goto step7;
2328         if (*dest == '.') {
2329                 c = dest[1];
2330 dotdot:
2331                 switch (c) {
2332                 case '\0':
2333                 case '/':
2334                         goto step6;
2335                 case '.':
2336                         c = dest[2];
2337                         if (c != '.')
2338                                 goto dotdot;
2339                 }
2340         }
2341         if (!*dest)
2342                 dest = ".";
2343         if (!(path = bltinlookup("CDPATH"))) {
2344 step6:
2345 step7:
2346                 p = dest;
2347                 goto docd;
2348         }
2349         do {
2350                 c = *path;
2351                 p = padvance(&path, dest);
2352                 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2353                         if (c && c != ':')
2354                                 flags |= CD_PRINT;
2355 docd:
2356                         if (!docd(p, flags))
2357                                 goto out;
2358                         break;
2359                 }
2360         } while (path);
2361         error("can't cd to %s", dest);
2362         /* NOTREACHED */
2363 out:
2364         if (flags & CD_PRINT)
2365                 out1fmt(snlfmt, curdir);
2366         return 0;
2367 }
2368
2369
2370 /*
2371  * Update curdir (the name of the current directory) in response to a
2372  * cd command.
2373  */
2374
2375 static inline const char *
2376 updatepwd(const char *dir)
2377 {
2378         char *new;
2379         char *p;
2380         char *cdcomppath;
2381         const char *lim;
2382
2383         cdcomppath = sstrdup(dir);
2384         STARTSTACKSTR(new);
2385         if (*dir != '/') {
2386                 if (curdir == nullstr)
2387                         return 0;
2388                 new = stputs(curdir, new);
2389         }
2390         new = makestrspace(strlen(dir) + 2, new);
2391         lim = stackblock() + 1;
2392         if (*dir != '/') {
2393                 if (new[-1] != '/')
2394                         USTPUTC('/', new);
2395                 if (new > lim && *lim == '/')
2396                         lim++;
2397         } else {
2398                 USTPUTC('/', new);
2399                 cdcomppath++;
2400                 if (dir[1] == '/' && dir[2] != '/') {
2401                         USTPUTC('/', new);
2402                         cdcomppath++;
2403                         lim++;
2404                 }
2405         }
2406         p = strtok(cdcomppath, "/");
2407         while (p) {
2408                 switch(*p) {
2409                 case '.':
2410                         if (p[1] == '.' && p[2] == '\0') {
2411                                 while (new > lim) {
2412                                         STUNPUTC(new);
2413                                         if (new[-1] == '/')
2414                                                 break;
2415                                 }
2416                                 break;
2417                         } else if (p[1] == '\0')
2418                                 break;
2419                         /* fall through */
2420                 default:
2421                         new = stputs(p, new);
2422                         USTPUTC('/', new);
2423                 }
2424                 p = strtok(0, "/");
2425         }
2426         if (new > lim)
2427                 STUNPUTC(new);
2428         *new = 0;
2429         return stackblock();
2430 }
2431
2432 /*
2433  * Actually do the chdir.  We also call hashcd to let the routines in exec.c
2434  * know that the current directory has changed.
2435  */
2436
2437 static int
2438 docd(const char *dest, int flags)
2439 {
2440         const char *dir = 0;
2441         int err;
2442
2443         TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2444
2445         INTOFF;
2446         if (!(flags & CD_PHYSICAL)) {
2447                 dir = updatepwd(dest);
2448                 if (dir)
2449                         dest = dir;
2450         }
2451         err = chdir(dest);
2452         if (err)
2453                 goto out;
2454         setpwd(dir, 1);
2455         hashcd();
2456 out:
2457         INTON;
2458         return err;
2459 }
2460
2461 /*
2462  * Find out what the current directory is. If we already know the current
2463  * directory, this routine returns immediately.
2464  */
2465 static inline char *
2466 getpwd(void)
2467 {
2468         char *dir = getcwd(0, 0);
2469         return dir ? dir : nullstr;
2470 }
2471
2472 static int
2473 pwdcmd(int argc, char **argv)
2474 {
2475         int flags;
2476         const char *dir = curdir;
2477
2478         flags = cdopt();
2479         if (flags) {
2480                 if (physdir == nullstr)
2481                         setpwd(dir, 0);
2482                 dir = physdir;
2483         }
2484         out1fmt(snlfmt, dir);
2485         return 0;
2486 }
2487
2488 static void
2489 setpwd(const char *val, int setold)
2490 {
2491         char *oldcur, *dir;
2492
2493         oldcur = dir = curdir;
2494
2495         if (setold) {
2496                 setvar("OLDPWD", oldcur, VEXPORT);
2497         }
2498         INTOFF;
2499         if (physdir != nullstr) {
2500                 if (physdir != oldcur)
2501                         free(physdir);
2502                 physdir = nullstr;
2503         }
2504         if (oldcur == val || !val) {
2505                 char *s = getpwd();
2506                 physdir = s;
2507                 if (!val)
2508                         dir = s;
2509         } else
2510                 dir = savestr(val);
2511         if (oldcur != dir && oldcur != nullstr) {
2512                 free(oldcur);
2513         }
2514         curdir = dir;
2515         INTON;
2516         setvar("PWD", dir, VEXPORT);
2517 }
2518
2519 /*      $NetBSD: error.c,v 1.30 2003/01/22 20:36:03 dsl Exp $   */
2520
2521 /*
2522  * Errors and exceptions.
2523  */
2524
2525 /*
2526  * Code to handle exceptions in C.
2527  */
2528
2529
2530
2531 static void exverror(int, const char *, va_list)
2532     __attribute__((__noreturn__));
2533
2534 /*
2535  * Called to raise an exception.  Since C doesn't include exceptions, we
2536  * just do a longjmp to the exception handler.  The type of exception is
2537  * stored in the global variable "exception".
2538  */
2539
2540 static void
2541 exraise(int e)
2542 {
2543 #ifdef DEBUG
2544         if (handler == NULL)
2545                 abort();
2546 #endif
2547         INTOFF;
2548
2549         exception = e;
2550         longjmp(handler->loc, 1);
2551 }
2552
2553
2554 /*
2555  * Called from trap.c when a SIGINT is received.  (If the user specifies
2556  * that SIGINT is to be trapped or ignored using the trap builtin, then
2557  * this routine is not called.)  Suppressint is nonzero when interrupts
2558  * are held using the INTOFF macro.  (The test for iflag is just
2559  * defensive programming.)
2560  */
2561
2562 static void
2563 onint(void) {
2564         int i;
2565
2566         intpending = 0;
2567         sigsetmask(0);
2568         i = EXSIG;
2569         if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
2570                 if (!(rootshell && iflag)) {
2571                         signal(SIGINT, SIG_DFL);
2572                         raise(SIGINT);
2573                 }
2574                 i = EXINT;
2575         }
2576         exraise(i);
2577         /* NOTREACHED */
2578 }
2579
2580 static void
2581 exvwarning(const char *msg, va_list ap)
2582 {
2583         FILE *errs;
2584         const char *name;
2585         const char *fmt;
2586
2587         errs = stderr;
2588         name = arg0;
2589         fmt = "%s: ";
2590         if (commandname) {
2591                 name = commandname;
2592                 fmt = "%s: %d: ";
2593         }
2594         fprintf(errs, fmt, name, startlinno);
2595         vfprintf(errs, msg, ap);
2596         outcslow('\n', errs);
2597 }
2598
2599 /*
2600  * Exverror is called to raise the error exception.  If the second argument
2601  * is not NULL then error prints an error message using printf style
2602  * formatting.  It then raises the error exception.
2603  */
2604 static void
2605 exverror(int cond, const char *msg, va_list ap)
2606 {
2607 #ifdef DEBUG
2608         if (msg) {
2609                 TRACE(("exverror(%d, \"", cond));
2610                 TRACEV((msg, ap));
2611                 TRACE(("\") pid=%d\n", getpid()));
2612         } else
2613                 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
2614         if (msg)
2615 #endif
2616                 exvwarning(msg, ap);
2617
2618         flushall();
2619         exraise(cond);
2620         /* NOTREACHED */
2621 }
2622
2623
2624 static void
2625 error(const char *msg, ...)
2626 {
2627         va_list ap;
2628
2629         va_start(ap, msg);
2630         exverror(EXERROR, msg, ap);
2631         /* NOTREACHED */
2632         va_end(ap);
2633 }
2634
2635
2636 static void
2637 exerror(int cond, const char *msg, ...)
2638 {
2639         va_list ap;
2640
2641         va_start(ap, msg);
2642         exverror(cond, msg, ap);
2643         /* NOTREACHED */
2644         va_end(ap);
2645 }
2646
2647 /*
2648  * error/warning routines for external builtins
2649  */
2650
2651 static void
2652 sh_warnx(const char *fmt, ...)
2653 {
2654         va_list ap;
2655
2656         va_start(ap, fmt);
2657         exvwarning(fmt, ap);
2658         va_end(ap);
2659 }
2660
2661
2662 /*
2663  * Return a string describing an error.  The returned string may be a
2664  * pointer to a static buffer that will be overwritten on the next call.
2665  * Action describes the operation that got the error.
2666  */
2667
2668 static const char *
2669 errmsg(int e, const char *em)
2670 {
2671         if(e == ENOENT || e == ENOTDIR) {
2672
2673                 return em;
2674         }
2675         return strerror(e);
2676 }
2677
2678
2679 /*      $NetBSD: eval.c,v 1.71 2003/01/23 03:33:16 rafal Exp $  */
2680
2681 /*
2682  * Evaluate a command.
2683  */
2684
2685 /* flags in argument to evaltree */
2686 #define EV_EXIT 01              /* exit after evaluating tree */
2687 #define EV_TESTED 02            /* exit status is checked; ignore -e flag */
2688 #define EV_BACKCMD 04           /* command executing within back quotes */
2689
2690
2691 static void evalloop(union node *, int);
2692 static void evalfor(union node *, int);
2693 static void evalcase(union node *, int);
2694 static void evalsubshell(union node *, int);
2695 static void expredir(union node *);
2696 static void evalpipe(union node *, int);
2697 static void evalcommand(union node *, int);
2698 static int evalbltin(const struct builtincmd *, int, char **);
2699 static int evalfun(struct funcnode *, int, char **, int);
2700 static void prehash(union node *);
2701 static int bltincmd(int, char **);
2702
2703
2704 static const struct builtincmd bltin = {
2705         "\0\0", bltincmd
2706 };
2707
2708
2709 /*
2710  * Called to reset things after an exception.
2711  */
2712
2713 /*
2714  * The eval command.
2715  */
2716
2717 static int
2718 evalcmd(int argc, char **argv)
2719 {
2720         char *p;
2721         char *concat;
2722         char **ap;
2723
2724         if (argc > 1) {
2725                 p = argv[1];
2726                 if (argc > 2) {
2727                         STARTSTACKSTR(concat);
2728                         ap = argv + 2;
2729                         for (;;) {
2730                                 concat = stputs(p, concat);
2731                                 if ((p = *ap++) == NULL)
2732                                         break;
2733                                 STPUTC(' ', concat);
2734                         }
2735                         STPUTC('\0', concat);
2736                         p = grabstackstr(concat);
2737                 }
2738                 evalstring(p);
2739         }
2740         return exitstatus;
2741 }
2742
2743
2744 /*
2745  * Execute a command or commands contained in a string.
2746  */
2747
2748 static void
2749 evalstring(char *s)
2750 {
2751         union node *n;
2752         struct stackmark smark;
2753
2754         setstackmark(&smark);
2755         setinputstring(s);
2756
2757         while ((n = parsecmd(0)) != NEOF) {
2758                 evaltree(n, 0);
2759                 popstackmark(&smark);
2760                 if (evalskip)
2761                         break;
2762         }
2763         popfile();
2764         popstackmark(&smark);
2765 }
2766
2767
2768
2769 /*
2770  * Evaluate a parse tree.  The value is left in the global variable
2771  * exitstatus.
2772  */
2773
2774 static void
2775 evaltree(union node *n, int flags)
2776 {
2777         int checkexit = 0;
2778         void (*evalfn)(union node *, int);
2779         unsigned isor;
2780         int status;
2781         if (n == NULL) {
2782                 TRACE(("evaltree(NULL) called\n"));
2783                 goto out;
2784         }
2785         TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
2786             getpid(), n, n->type, flags));
2787         switch (n->type) {
2788         default:
2789 #ifdef DEBUG
2790                 out1fmt("Node type = %d\n", n->type);
2791                 fflush(stdout);
2792                 break;
2793 #endif
2794         case NNOT:
2795                 evaltree(n->nnot.com, EV_TESTED);
2796                 status = !exitstatus;
2797                 goto setstatus;
2798         case NREDIR:
2799                 expredir(n->nredir.redirect);
2800                 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
2801                 if (!status) {
2802                         evaltree(n->nredir.n, flags & EV_TESTED);
2803                         status = exitstatus;
2804                 }
2805                 popredir(0);
2806                 goto setstatus;
2807         case NCMD:
2808                 evalfn = evalcommand;
2809 checkexit:
2810                 if (eflag && !(flags & EV_TESTED))
2811                         checkexit = ~0;
2812                 goto calleval;
2813         case NFOR:
2814                 evalfn = evalfor;
2815                 goto calleval;
2816         case NWHILE:
2817         case NUNTIL:
2818                 evalfn = evalloop;
2819                 goto calleval;
2820         case NSUBSHELL:
2821         case NBACKGND:
2822                 evalfn = evalsubshell;
2823                 goto calleval;
2824         case NPIPE:
2825                 evalfn = evalpipe;
2826                 goto checkexit;
2827         case NCASE:
2828                 evalfn = evalcase;
2829                 goto calleval;
2830         case NAND:
2831         case NOR:
2832         case NSEMI:
2833 #if NAND + 1 != NOR
2834 #error NAND + 1 != NOR
2835 #endif
2836 #if NOR + 1 != NSEMI
2837 #error NOR + 1 != NSEMI
2838 #endif
2839                 isor = n->type - NAND;
2840                 evaltree(
2841                         n->nbinary.ch1,
2842                         (flags | ((isor >> 1) - 1)) & EV_TESTED
2843                 );
2844                 if (!exitstatus == isor)
2845                         break;
2846                 if (!evalskip) {
2847                         n = n->nbinary.ch2;
2848 evaln:
2849                         evalfn = evaltree;
2850 calleval:
2851                         evalfn(n, flags);
2852                         break;
2853                 }
2854                 break;
2855         case NIF:
2856                 evaltree(n->nif.test, EV_TESTED);
2857                 if (evalskip)
2858                         break;
2859                 if (exitstatus == 0) {
2860                         n = n->nif.ifpart;
2861                         goto evaln;
2862                 } else if (n->nif.elsepart) {
2863                         n = n->nif.elsepart;
2864                         goto evaln;
2865                 }
2866                 goto success;
2867         case NDEFUN:
2868                 defun(n->narg.text, n->narg.next);
2869 success:
2870                 status = 0;
2871 setstatus:
2872                 exitstatus = status;
2873                 break;
2874         }
2875 out:
2876         if (pendingsigs)
2877                 dotrap();
2878         if (flags & EV_EXIT || checkexit & exitstatus)
2879                 exraise(EXEXIT);
2880 }
2881
2882
2883 #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
2884 static
2885 #endif
2886 void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
2887
2888
2889 static void
2890 evalloop(union node *n, int flags)
2891 {
2892         int status;
2893
2894         loopnest++;
2895         status = 0;
2896         flags &= EV_TESTED;
2897         for (;;) {
2898                 int i;
2899
2900                 evaltree(n->nbinary.ch1, EV_TESTED);
2901                 if (evalskip) {
2902 skipping:         if (evalskip == SKIPCONT && --skipcount <= 0) {
2903                                 evalskip = 0;
2904                                 continue;
2905                         }
2906                         if (evalskip == SKIPBREAK && --skipcount <= 0)
2907                                 evalskip = 0;
2908                         break;
2909                 }
2910                 i = exitstatus;
2911                 if (n->type != NWHILE)
2912                         i = !i;
2913                 if (i != 0)
2914                         break;
2915                 evaltree(n->nbinary.ch2, flags);
2916                 status = exitstatus;
2917                 if (evalskip)
2918                         goto skipping;
2919         }
2920         loopnest--;
2921         exitstatus = status;
2922 }
2923
2924
2925
2926 static void
2927 evalfor(union node *n, int flags)
2928 {
2929         struct arglist arglist;
2930         union node *argp;
2931         struct strlist *sp;
2932         struct stackmark smark;
2933
2934         setstackmark(&smark);
2935         arglist.lastp = &arglist.list;
2936         for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
2937                 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
2938                 /* XXX */
2939                 if (evalskip)
2940                         goto out;
2941         }
2942         *arglist.lastp = NULL;
2943
2944         exitstatus = 0;
2945         loopnest++;
2946         flags &= EV_TESTED;
2947         for (sp = arglist.list ; sp ; sp = sp->next) {
2948                 setvar(n->nfor.var, sp->text, 0);
2949                 evaltree(n->nfor.body, flags);
2950                 if (evalskip) {
2951                         if (evalskip == SKIPCONT && --skipcount <= 0) {
2952                                 evalskip = 0;
2953                                 continue;
2954                         }
2955                         if (evalskip == SKIPBREAK && --skipcount <= 0)
2956                                 evalskip = 0;
2957                         break;
2958                 }
2959         }
2960         loopnest--;
2961 out:
2962         popstackmark(&smark);
2963 }
2964
2965
2966
2967 static void
2968 evalcase(union node *n, int flags)
2969 {
2970         union node *cp;
2971         union node *patp;
2972         struct arglist arglist;
2973         struct stackmark smark;
2974
2975         setstackmark(&smark);
2976         arglist.lastp = &arglist.list;
2977         expandarg(n->ncase.expr, &arglist, EXP_TILDE);
2978         exitstatus = 0;
2979         for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2980                 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
2981                         if (casematch(patp, arglist.list->text)) {
2982                                 if (evalskip == 0) {
2983                                         evaltree(cp->nclist.body, flags);
2984                                 }
2985                                 goto out;
2986                         }
2987                 }
2988         }
2989 out:
2990         popstackmark(&smark);
2991 }
2992
2993
2994
2995 /*
2996  * Kick off a subshell to evaluate a tree.
2997  */
2998
2999 static void
3000 evalsubshell(union node *n, int flags)
3001 {
3002         struct job *jp;
3003         int backgnd = (n->type == NBACKGND);
3004         int status;
3005
3006         expredir(n->nredir.redirect);
3007         if (!backgnd && flags & EV_EXIT && !trap[0])
3008                 goto nofork;
3009         INTOFF;
3010         jp = makejob(n, 1);
3011         if (forkshell(jp, n, backgnd) == 0) {
3012                 INTON;
3013                 flags |= EV_EXIT;
3014                 if (backgnd)
3015                         flags &=~ EV_TESTED;
3016 nofork:
3017                 redirect(n->nredir.redirect, 0);
3018                 evaltreenr(n->nredir.n, flags);
3019                 /* never returns */
3020         }
3021         status = 0;
3022         if (! backgnd)
3023                 status = waitforjob(jp);
3024         exitstatus = status;
3025         INTON;
3026 }
3027
3028
3029
3030 /*
3031  * Compute the names of the files in a redirection list.
3032  */
3033
3034 static void
3035 expredir(union node *n)
3036 {
3037         union node *redir;
3038
3039         for (redir = n ; redir ; redir = redir->nfile.next) {
3040                 struct arglist fn;
3041                 fn.lastp = &fn.list;
3042                 switch (redir->type) {
3043                 case NFROMTO:
3044                 case NFROM:
3045                 case NTO:
3046                 case NCLOBBER:
3047                 case NAPPEND:
3048                         expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
3049                         redir->nfile.expfname = fn.list->text;
3050                         break;
3051                 case NFROMFD:
3052                 case NTOFD:
3053                         if (redir->ndup.vname) {
3054                                 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
3055                                 fixredir(redir, fn.list->text, 1);
3056                         }
3057                         break;
3058                 }
3059         }
3060 }
3061
3062
3063
3064 /*
3065  * Evaluate a pipeline.  All the processes in the pipeline are children
3066  * of the process creating the pipeline.  (This differs from some versions
3067  * of the shell, which make the last process in a pipeline the parent
3068  * of all the rest.)
3069  */
3070
3071 static void
3072 evalpipe(union node *n, int flags)
3073 {
3074         struct job *jp;
3075         struct nodelist *lp;
3076         int pipelen;
3077         int prevfd;
3078         int pip[2];
3079
3080         TRACE(("evalpipe(0x%lx) called\n", (long)n));
3081         pipelen = 0;
3082         for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
3083                 pipelen++;
3084         flags |= EV_EXIT;
3085         INTOFF;
3086         jp = makejob(n, pipelen);
3087         prevfd = -1;
3088         for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
3089                 prehash(lp->n);
3090                 pip[1] = -1;
3091                 if (lp->next) {
3092                         if (pipe(pip) < 0) {
3093                                 close(prevfd);
3094                                 error("Pipe call failed");
3095                         }
3096                 }
3097                 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
3098                         INTON;
3099                         if (pip[1] >= 0) {
3100                                 close(pip[0]);
3101                         }
3102                         if (prevfd > 0) {
3103                                 dup2(prevfd, 0);
3104                                 close(prevfd);
3105                         }
3106                         if (pip[1] > 1) {
3107                                 dup2(pip[1], 1);
3108                                 close(pip[1]);
3109                         }
3110                         evaltreenr(lp->n, flags);
3111                         /* never returns */
3112                 }
3113                 if (prevfd >= 0)
3114                         close(prevfd);
3115                 prevfd = pip[0];
3116                 close(pip[1]);
3117         }
3118         if (n->npipe.backgnd == 0) {
3119                 exitstatus = waitforjob(jp);
3120                 TRACE(("evalpipe:  job done exit status %d\n", exitstatus));
3121         }
3122         INTON;
3123 }
3124
3125
3126
3127 /*
3128  * Execute a command inside back quotes.  If it's a builtin command, we
3129  * want to save its output in a block obtained from malloc.  Otherwise
3130  * we fork off a subprocess and get the output of the command via a pipe.
3131  * Should be called with interrupts off.
3132  */
3133
3134 static void
3135 evalbackcmd(union node *n, struct backcmd *result)
3136 {
3137         int saveherefd;
3138
3139         result->fd = -1;
3140         result->buf = NULL;
3141         result->nleft = 0;
3142         result->jp = NULL;
3143         if (n == NULL) {
3144                 goto out;
3145         }
3146
3147         saveherefd = herefd;
3148         herefd = -1;
3149
3150         {
3151                 int pip[2];
3152                 struct job *jp;
3153
3154                 if (pipe(pip) < 0)
3155                         error("Pipe call failed");
3156                 jp = makejob(n, 1);
3157                 if (forkshell(jp, n, FORK_NOJOB) == 0) {
3158                         FORCEINTON;
3159                         close(pip[0]);
3160                         if (pip[1] != 1) {
3161                                 close(1);
3162                                 copyfd(pip[1], 1);
3163                                 close(pip[1]);
3164                         }
3165                         eflag = 0;
3166                         evaltreenr(n, EV_EXIT);
3167                         /* NOTREACHED */
3168                 }
3169                 close(pip[1]);
3170                 result->fd = pip[0];
3171                 result->jp = jp;
3172         }
3173         herefd = saveherefd;
3174 out:
3175         TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
3176                 result->fd, result->buf, result->nleft, result->jp));
3177 }
3178
3179 #ifdef CONFIG_ASH_CMDCMD
3180 static inline char **
3181 parse_command_args(char **argv, const char **path)
3182 {
3183         char *cp, c;
3184
3185         for (;;) {
3186                 cp = *++argv;
3187                 if (!cp)
3188                         return 0;
3189                 if (*cp++ != '-')
3190                         break;
3191                 if (!(c = *cp++))
3192                         break;
3193                 if (c == '-' && !*cp) {
3194                         argv++;
3195                         break;
3196                 }
3197                 do {
3198                         switch (c) {
3199                         case 'p':
3200                                 *path = defpath;
3201                                 break;
3202                         default:
3203                                 /* run 'typecmd' for other options */
3204                                 return 0;
3205                         }
3206                 } while ((c = *cp++));
3207         }
3208         return argv;
3209 }
3210 #endif
3211
3212 static inline int
3213 isassignment(const char *p)
3214 {
3215         const char *q = endofname(p);
3216         if (p == q)
3217                 return 0;
3218         return *q == '=';
3219 }
3220
3221 /*
3222  * Execute a simple command.
3223  */
3224
3225 static void
3226 evalcommand(union node *cmd, int flags)
3227 {
3228         struct stackmark smark;
3229         union node *argp;
3230         struct arglist arglist;
3231         struct arglist varlist;
3232         char **argv;
3233         int argc;
3234         const struct strlist *sp;
3235         struct cmdentry cmdentry;
3236         struct job *jp;
3237         char *lastarg;
3238         const char *path;
3239         int spclbltin;
3240         int cmd_is_exec;
3241         int status;
3242         char **nargv;
3243         struct builtincmd *bcmd;
3244         int pseudovarflag = 0;
3245
3246         /* First expand the arguments. */
3247         TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
3248         setstackmark(&smark);
3249         back_exitstatus = 0;
3250
3251         cmdentry.cmdtype = CMDBUILTIN;
3252         cmdentry.u.cmd = &bltin;
3253         varlist.lastp = &varlist.list;
3254         *varlist.lastp = NULL;
3255         arglist.lastp = &arglist.list;
3256         *arglist.lastp = NULL;
3257
3258         argc = 0;
3259         if (cmd->ncmd.args)
3260         {
3261                 bcmd = find_builtin(cmd->ncmd.args->narg.text);
3262                 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
3263         }
3264
3265         for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
3266                 struct strlist **spp;
3267
3268                 spp = arglist.lastp;
3269                 if (pseudovarflag && isassignment(argp->narg.text)) 
3270                         expandarg(argp, &arglist, EXP_VARTILDE);
3271                 else
3272                         expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
3273
3274                 for (sp = *spp; sp; sp = sp->next)
3275                         argc++;
3276         }
3277
3278         argv = nargv = stalloc(sizeof (char *) * (argc + 1));
3279         for (sp = arglist.list ; sp ; sp = sp->next) {
3280                 TRACE(("evalcommand arg: %s\n", sp->text));
3281                 *nargv++ = sp->text;
3282         }
3283         *nargv = NULL;
3284
3285         lastarg = NULL;
3286         if (iflag && funcnest == 0 && argc > 0)
3287                 lastarg = nargv[-1];
3288
3289         preverrout_fd = 2;
3290         expredir(cmd->ncmd.redirect);
3291         status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH|REDIR_SAVEFD2);
3292
3293         path = vpath.text;
3294         for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
3295                 struct strlist **spp;
3296                 char *p;
3297
3298                 spp = varlist.lastp;
3299                 expandarg(argp, &varlist, EXP_VARTILDE);
3300
3301                 /*
3302                  * Modify the command lookup path, if a PATH= assignment
3303                  * is present
3304                  */
3305                 p = (*spp)->text;
3306                 if (varequal(p, path))
3307                         path = p;
3308         }
3309
3310         /* Print the command if xflag is set. */
3311         if (xflag) {
3312                 int n;
3313                 const char *p = " %s";
3314
3315                 p++;
3316                 dprintf(preverrout_fd, p, ps4val());
3317
3318                 sp = varlist.list;
3319                 for(n = 0; n < 2; n++) {
3320                         while (sp) {
3321                                 dprintf(preverrout_fd, p, sp->text);
3322                                 sp = sp->next;
3323                                 if(*p == '%') {
3324                                         p--;
3325                                 }
3326                         }
3327                         sp = arglist.list;
3328                 }
3329                 bb_full_write(preverrout_fd, "\n", 1);
3330         }
3331
3332         cmd_is_exec = 0;
3333         spclbltin = -1;
3334
3335         /* Now locate the command. */
3336         if (argc) {
3337                 const char *oldpath;
3338                 int cmd_flag = DO_ERR;
3339
3340                 path += 5;
3341                 oldpath = path;
3342                 for (;;) {
3343                         find_command(argv[0], &cmdentry, cmd_flag, path);
3344                         if (cmdentry.cmdtype == CMDUNKNOWN) {
3345                                 status = 127;
3346                                 flusherr();
3347                                 goto bail;
3348                         }
3349
3350                         /* implement bltin and command here */
3351                         if (cmdentry.cmdtype != CMDBUILTIN)
3352                                 break;
3353                         if (spclbltin < 0)
3354                                 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
3355                         if (cmdentry.u.cmd == EXECCMD)
3356                                 cmd_is_exec++;
3357 #ifdef CONFIG_ASH_CMDCMD
3358                         if (cmdentry.u.cmd == COMMANDCMD) {
3359
3360                                 path = oldpath;
3361                                 nargv = parse_command_args(argv, &path);
3362                                 if (!nargv)
3363                                         break;
3364                                 argc -= nargv - argv;
3365                                 argv = nargv;
3366                                 cmd_flag |= DO_NOFUNC;
3367                         } else
3368 #endif
3369                                 break;
3370                 }
3371         }
3372
3373         if (status) {
3374                 /* We have a redirection error. */
3375                 if (spclbltin > 0)
3376                         exraise(EXERROR);
3377 bail:
3378                 exitstatus = status;
3379                 goto out;
3380         }
3381
3382         /* Execute the command. */
3383         switch (cmdentry.cmdtype) {
3384         default:
3385                 /* Fork off a child process if necessary. */
3386                 if (!(flags & EV_EXIT) || trap[0]) {
3387                         INTOFF;
3388                         jp = makejob(cmd, 1);
3389                         if (forkshell(jp, cmd, FORK_FG) != 0) {
3390                                 exitstatus = waitforjob(jp);
3391                                 INTON;
3392                                 break;
3393                         }
3394                         FORCEINTON;
3395                 }
3396                 listsetvar(varlist.list, VEXPORT|VSTACK);
3397                 shellexec(argv, path, cmdentry.u.index);
3398                 /* NOTREACHED */
3399
3400         case CMDBUILTIN:
3401                 cmdenviron = varlist.list;
3402                 if (cmdenviron) {
3403                         struct strlist *list = cmdenviron;
3404                         int i = VNOSET;
3405                         if (spclbltin > 0 || argc == 0) {
3406                                 i = 0;
3407                                 if (cmd_is_exec && argc > 1)
3408                                         i = VEXPORT;
3409                         }
3410                         listsetvar(list, i);
3411                 }
3412                 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
3413                         int exit_status;
3414                         int i, j;
3415
3416                         i = exception;
3417                         if (i == EXEXIT)
3418                                 goto raise;
3419
3420                         exit_status = 2;
3421                         j = 0;
3422                         if (i == EXINT)
3423                                 j = SIGINT;
3424                         if (i == EXSIG)
3425                                 j = pendingsigs;
3426                         if (j)
3427                                 exit_status = j + 128;
3428                         exitstatus = exit_status;
3429
3430                         if (i == EXINT || spclbltin > 0) {
3431 raise:
3432                                 longjmp(handler->loc, 1);
3433                         }
3434                         FORCEINTON;
3435                 }
3436                 break;
3437
3438         case CMDFUNCTION:
3439                 listsetvar(varlist.list, 0);
3440                 if (evalfun(cmdentry.u.func, argc, argv, flags))
3441                         goto raise;
3442                 break;
3443         }
3444
3445 out:
3446         popredir(cmd_is_exec);
3447         if (lastarg)
3448                 /* dsl: I think this is intended to be used to support
3449                  * '_' in 'vi' command mode during line editing...
3450                  * However I implemented that within libedit itself.
3451                  */
3452                 setvar("_", lastarg, 0);
3453         popstackmark(&smark);
3454 }
3455
3456 static int
3457 evalbltin(const struct builtincmd *cmd, int argc, char **argv) {
3458         char *volatile savecmdname;
3459         struct jmploc *volatile savehandler;
3460         struct jmploc jmploc;
3461         int i;
3462
3463         savecmdname = commandname;
3464         if ((i = setjmp(jmploc.loc)))
3465                 goto cmddone;
3466         savehandler = handler;
3467         handler = &jmploc;
3468         commandname = argv[0];
3469         argptr = argv + 1;
3470         optptr = NULL;                  /* initialize nextopt */
3471         exitstatus = (*cmd->builtin)(argc, argv);
3472         flushall();
3473 cmddone:
3474         exitstatus |= ferror(stdout);
3475         commandname = savecmdname;
3476         exsig = 0;
3477         handler = savehandler;
3478
3479         return i;
3480 }
3481
3482 static int
3483 evalfun(struct funcnode *func, int argc, char **argv, int flags)
3484 {
3485         volatile struct shparam saveparam;
3486         struct localvar *volatile savelocalvars;
3487         struct jmploc *volatile savehandler;
3488         struct jmploc jmploc;
3489         int e;
3490
3491         saveparam = shellparam;
3492         savelocalvars = localvars;
3493         if ((e = setjmp(jmploc.loc))) {
3494                 goto funcdone;
3495         }
3496         INTOFF;
3497         savehandler = handler;
3498         handler = &jmploc;
3499         localvars = NULL;
3500         shellparam.malloc = 0;
3501         func->count++;
3502         INTON;
3503         shellparam.nparam = argc - 1;
3504         shellparam.p = argv + 1;
3505 #ifdef CONFIG_ASH_GETOPTS
3506         shellparam.optind = 1;
3507         shellparam.optoff = -1;
3508 #endif
3509         funcnest++;
3510         evaltree(&func->n, flags & EV_TESTED);
3511         funcnest--;
3512 funcdone:
3513         INTOFF;
3514         freefunc(func);
3515         poplocalvars();
3516         localvars = savelocalvars;
3517         freeparam(&shellparam);
3518         shellparam = saveparam;
3519         handler = savehandler;
3520         INTON;
3521         if (evalskip == SKIPFUNC) {
3522                 evalskip = 0;
3523                 skipcount = 0;
3524         }
3525         return e;
3526 }
3527
3528
3529 static inline int
3530 goodname(const char *p)
3531 {
3532         return !*endofname(p);
3533 }
3534
3535 /*
3536  * Search for a command.  This is called before we fork so that the
3537  * location of the command will be available in the parent as well as
3538  * the child.  The check for "goodname" is an overly conservative
3539  * check that the name will not be subject to expansion.
3540  */
3541
3542 static void
3543 prehash(union node *n)
3544 {
3545         struct cmdentry entry;
3546
3547         if (n->type == NCMD && n->ncmd.args)
3548                 if (goodname(n->ncmd.args->narg.text))
3549                         find_command(n->ncmd.args->narg.text, &entry, 0,
3550                                      pathval());
3551 }
3552
3553
3554
3555 /*
3556  * Builtin commands.  Builtin commands whose functions are closely
3557  * tied to evaluation are implemented here.
3558  */
3559
3560 /*
3561  * No command given.
3562  */
3563
3564 static int
3565 bltincmd(int argc, char **argv)
3566 {
3567         /*
3568          * Preserve exitstatus of a previous possible redirection
3569          * as POSIX mandates
3570          */
3571         return back_exitstatus;
3572 }
3573
3574
3575 /*
3576  * Handle break and continue commands.  Break, continue, and return are
3577  * all handled by setting the evalskip flag.  The evaluation routines
3578  * above all check this flag, and if it is set they start skipping
3579  * commands rather than executing them.  The variable skipcount is
3580  * the number of loops to break/continue, or the number of function
3581  * levels to return.  (The latter is always 1.)  It should probably
3582  * be an error to break out of more loops than exist, but it isn't
3583  * in the standard shell so we don't make it one here.
3584  */
3585
3586 static int
3587 breakcmd(int argc, char **argv)
3588 {
3589         int n = argc > 1 ? number(argv[1]) : 1;
3590
3591         if (n <= 0)
3592                 error(illnum, argv[1]);
3593         if (n > loopnest)
3594                 n = loopnest;
3595         if (n > 0) {
3596                 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
3597                 skipcount = n;
3598         }
3599         return 0;
3600 }
3601
3602
3603 /*
3604  * The return command.
3605  */
3606
3607 static int
3608 returncmd(int argc, char **argv)
3609 {
3610         int ret = argc > 1 ? number(argv[1]) : exitstatus;
3611
3612         if (funcnest) {
3613                 evalskip = SKIPFUNC;
3614                 skipcount = 1;
3615                 return ret;
3616         }
3617         else {
3618                 /* Do what ksh does; skip the rest of the file */
3619                 evalskip = SKIPFILE;
3620                 skipcount = 1;
3621                 return ret;
3622         }
3623 }
3624
3625
3626 static int
3627 falsecmd(int argc, char **argv)
3628 {
3629         return 1;
3630 }
3631
3632
3633 static int
3634 truecmd(int argc, char **argv)
3635 {
3636         return 0;
3637 }
3638
3639
3640 static int
3641 execcmd(int argc, char **argv)
3642 {
3643         if (argc > 1) {
3644                 iflag = 0;              /* exit on error */
3645                 mflag = 0;
3646                 optschanged();
3647                 shellexec(argv + 1, pathval(), 0);
3648         }
3649         return 0;
3650 }
3651
3652
3653 /*      $NetBSD: exec.c,v 1.35 2003/01/22 20:36:04 dsl Exp $    */
3654
3655 /*
3656  * When commands are first encountered, they are entered in a hash table.
3657  * This ensures that a full path search will not have to be done for them
3658  * on each invocation.
3659  *
3660  * We should investigate converting to a linear search, even though that
3661  * would make the command name "hash" a misnomer.
3662  */
3663
3664 #define CMDTABLESIZE 31         /* should be prime */
3665 #define ARB 1                   /* actual size determined at run time */
3666
3667
3668
3669 struct tblentry {
3670         struct tblentry *next;  /* next entry in hash chain */
3671         union param param;      /* definition of builtin function */
3672         short cmdtype;          /* index identifying command */
3673         char rehash;            /* if set, cd done since entry created */
3674         char cmdname[ARB];      /* name of command */
3675 };
3676
3677
3678 static struct tblentry *cmdtable[CMDTABLESIZE];
3679 static int builtinloc = -1;             /* index in path of %builtin, or -1 */
3680
3681
3682 static void tryexec(char *, char **, char **);
3683 static void clearcmdentry(int);
3684 static struct tblentry *cmdlookup(const char *, int);
3685 static void delete_cmd_entry(void);
3686
3687
3688 /*
3689  * Exec a program.  Never returns.  If you change this routine, you may
3690  * have to change the find_command routine as well.
3691  */
3692
3693 static void
3694 shellexec(char **argv, const char *path, int idx)
3695 {
3696         char *cmdname;
3697         int e;
3698         char **envp;
3699
3700         clearredir(1);
3701         envp = environment();
3702         if (strchr(argv[0], '/') != NULL
3703 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3704                 || find_applet_by_name(argv[0])
3705 #endif
3706                                                 ) {
3707                 tryexec(argv[0], argv, envp);
3708                 e = errno;
3709         } else {
3710                 e = ENOENT;
3711                 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3712                         if (--idx < 0 && pathopt == NULL) {
3713                                 tryexec(cmdname, argv, envp);
3714                                 if (errno != ENOENT && errno != ENOTDIR)
3715                                         e = errno;
3716                         }
3717                         stunalloc(cmdname);
3718                 }
3719         }
3720
3721         /* Map to POSIX errors */
3722         switch (e) {
3723         case EACCES:
3724                 exerrno = 126;
3725                 break;
3726         case ENOENT:
3727                 exerrno = 127;
3728                 break;
3729         default:
3730                 exerrno = 2;
3731                 break;
3732         }
3733         TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
3734                 argv[0], e, suppressint ));
3735         exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3736         /* NOTREACHED */
3737 }
3738
3739
3740 static void
3741 tryexec(char *cmd, char **argv, char **envp)
3742 {
3743         int repeated = 0;
3744 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3745         if(find_applet_by_name(cmd) != NULL) {
3746                 /* re-exec ourselves with the new arguments */
3747                 execve("/proc/self/exe",argv,envp);
3748                 /* If proc isn't mounted, try hardcoded path to busybox binary*/
3749                 execve("/bin/busybox",argv,envp);
3750                 /* If they called chroot or otherwise made the binary no longer
3751                  * executable, fall through */
3752         }
3753 #endif
3754
3755 repeat:
3756 #ifdef SYSV
3757         do {
3758                 execve(cmd, argv, envp);
3759         } while (errno == EINTR);
3760 #else
3761         execve(cmd, argv, envp);
3762 #endif
3763         if (repeated++) {
3764                 ckfree(argv);
3765         } else if (errno == ENOEXEC) {
3766                 char **ap;
3767                 char **new;
3768
3769                 for (ap = argv; *ap; ap++)
3770                         ;
3771                 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
3772                 ap[1] = cmd;
3773                 *ap = cmd = (char *)DEFAULT_SHELL;
3774                 ap += 2;
3775                 argv++;
3776                 while ((*ap++ = *argv++))
3777                         ;
3778                 argv = new;
3779                 goto repeat;
3780         }
3781 }
3782
3783
3784
3785 /*
3786  * Do a path search.  The variable path (passed by reference) should be
3787  * set to the start of the path before the first call; padvance will update
3788  * this value as it proceeds.  Successive calls to padvance will return
3789  * the possible path expansions in sequence.  If an option (indicated by
3790  * a percent sign) appears in the path entry then the global variable
3791  * pathopt will be set to point to it; otherwise pathopt will be set to
3792  * NULL.
3793  */
3794
3795 static char *
3796 padvance(const char **path, const char *name)
3797 {
3798         const char *p;
3799         char *q;
3800         const char *start;
3801         size_t len;
3802
3803         if (*path == NULL)
3804                 return NULL;
3805         start = *path;
3806         for (p = start ; *p && *p != ':' && *p != '%' ; p++);
3807         len = p - start + strlen(name) + 2;     /* "2" is for '/' and '\0' */
3808         while (stackblocksize() < len)
3809                 growstackblock();
3810         q = stackblock();
3811         if (p != start) {
3812                 memcpy(q, start, p - start);
3813                 q += p - start;
3814                 *q++ = '/';
3815         }
3816         strcpy(q, name);
3817         pathopt = NULL;
3818         if (*p == '%') {
3819                 pathopt = ++p;
3820                 while (*p && *p != ':')  p++;
3821         }
3822         if (*p == ':')
3823                 *path = p + 1;
3824         else
3825                 *path = NULL;
3826         return stalloc(len);
3827 }
3828
3829
3830 /*** Command hashing code ***/
3831
3832 static void
3833 printentry(struct tblentry *cmdp)
3834 {
3835         int idx;
3836         const char *path;
3837         char *name;
3838
3839         idx = cmdp->param.index;
3840         path = pathval();
3841         do {
3842                 name = padvance(&path, cmdp->cmdname);
3843                 stunalloc(name);
3844         } while (--idx >= 0);
3845         out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
3846 }
3847
3848
3849 static int
3850 hashcmd(int argc, char **argv)
3851 {
3852         struct tblentry **pp;
3853         struct tblentry *cmdp;
3854         int c;
3855         struct cmdentry entry;
3856         char *name;
3857
3858         while ((c = nextopt("r")) != '\0') {
3859                 clearcmdentry(0);
3860                 return 0;
3861         }
3862         if (*argptr == NULL) {
3863                 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3864                         for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3865                                 if (cmdp->cmdtype == CMDNORMAL)
3866                                         printentry(cmdp);
3867                         }
3868                 }
3869                 return 0;
3870         }
3871         c = 0;
3872         while ((name = *argptr) != NULL) {
3873                 if ((cmdp = cmdlookup(name, 0)) != NULL
3874                  && (cmdp->cmdtype == CMDNORMAL
3875                      || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
3876                         delete_cmd_entry();
3877                 find_command(name, &entry, DO_ERR, pathval());
3878                 if (entry.cmdtype == CMDUNKNOWN)
3879                         c = 1;
3880                 argptr++;
3881         }
3882         return c;
3883 }
3884
3885
3886 /*
3887  * Resolve a command name.  If you change this routine, you may have to
3888  * change the shellexec routine as well.
3889  */
3890
3891 static void
3892 find_command(char *name, struct cmdentry *entry, int act, const char *path)
3893 {
3894         struct tblentry *cmdp;
3895         int idx;
3896         int prev;
3897         char *fullname;
3898         struct stat statb;
3899         int e;
3900         int updatetbl;
3901         struct builtincmd *bcmd;
3902
3903         /* If name contains a slash, don't use PATH or hash table */
3904         if (strchr(name, '/') != NULL) {
3905                 entry->u.index = -1;
3906                 if (act & DO_ABS) {
3907                         while (stat(name, &statb) < 0) {
3908 #ifdef SYSV
3909                                 if (errno == EINTR)
3910                                         continue;
3911 #endif
3912                                 entry->cmdtype = CMDUNKNOWN;
3913                                 return;
3914                         }
3915                 }
3916                 entry->cmdtype = CMDNORMAL;
3917                 return;
3918         }
3919
3920 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3921         if (find_applet_by_name(name)) {
3922                 entry->cmdtype = CMDNORMAL;
3923                 entry->u.index = -1;
3924                 return;
3925         }
3926 #endif
3927
3928         updatetbl = (path == pathval());
3929         if (!updatetbl) {
3930                 act |= DO_ALTPATH;
3931                 if (strstr(path, "%builtin") != NULL)
3932                         act |= DO_ALTBLTIN;
3933         }
3934
3935         /* If name is in the table, check answer will be ok */
3936         if ((cmdp = cmdlookup(name, 0)) != NULL) {
3937                 int bit;
3938
3939                 switch (cmdp->cmdtype) {
3940                 default:
3941 #if DEBUG
3942                         abort();
3943 #endif
3944                 case CMDNORMAL:
3945                         bit = DO_ALTPATH;
3946                         break;
3947                 case CMDFUNCTION:
3948                         bit = DO_NOFUNC;
3949                         break;
3950                 case CMDBUILTIN:
3951                         bit = DO_ALTBLTIN;
3952                         break;
3953                 }
3954                 if (act & bit) {
3955                         updatetbl = 0;
3956                         cmdp = NULL;
3957                 } else if (cmdp->rehash == 0)
3958                         /* if not invalidated by cd, we're done */
3959                         goto success;
3960         }
3961
3962         /* If %builtin not in path, check for builtin next */
3963