2862f10324b694d31d7f83f3dfa79be5b48a0473
[oweals/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 barrier() ({ __asm__ __volatile__ ("": : :"memory"); })
216 #define INTOFF \
217         ({ \
218                 suppressint++; \
219                 barrier(); \
220                 0; \
221         })
222 #define SAVEINT(v) ((v) = suppressint)
223 #define RESTOREINT(v) \
224         ({ \
225                 barrier(); \
226                 if ((suppressint = (v)) == 0 && intpending) onint(); \
227                 0; \
228         })
229 #define EXSIGON() \
230         ({ \
231                 exsig++; \
232                 barrier(); \
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                 barrier(); \
267                 if (--suppressint == 0 && intpending) onint(); \
268                 0; \
269         })
270 #define FORCEINTON \
271         ({ \
272                 barrier(); \
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 likely(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
1357 static const struct builtincmd builtincmd[] = {
1358         { BUILTIN_SPEC_REG      ".", dotcmd },
1359         { BUILTIN_SPEC_REG      ":", truecmd },
1360 #ifdef CONFIG_ASH_ALIAS
1361         { BUILTIN_REG_ASSG      "alias", aliascmd },
1362 #endif
1363 #ifdef JOBS
1364         { BUILTIN_REGULAR       "bg", bgcmd },
1365 #endif
1366         { BUILTIN_SPEC_REG      "break", breakcmd },
1367         { BUILTIN_REGULAR       "cd", cdcmd },
1368         { BUILTIN_NOSPEC        "chdir", cdcmd },
1369 #ifdef CONFIG_ASH_CMDCMD
1370         { BUILTIN_REGULAR       "command", commandcmd },
1371 #endif
1372         { BUILTIN_SPEC_REG      "continue", breakcmd },
1373         { BUILTIN_SPEC_REG      "eval", evalcmd },
1374         { BUILTIN_SPEC_REG      "exec", execcmd },
1375         { BUILTIN_SPEC_REG      "exit", exitcmd },
1376         { BUILTIN_SPEC_REG_ASSG "export", exportcmd },
1377         { BUILTIN_REGULAR       "false", falsecmd },
1378 #ifdef JOBS
1379         { BUILTIN_REGULAR       "fg", fgcmd },
1380 #endif
1381 #ifdef CONFIG_ASH_GETOPTS
1382         { BUILTIN_REGULAR       "getopts", getoptscmd },
1383 #endif
1384         { BUILTIN_NOSPEC        "hash", hashcmd },
1385 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
1386         { BUILTIN_NOSPEC        "help", helpcmd },
1387 #endif
1388 #ifdef JOBS
1389         { BUILTIN_REGULAR       "jobs", jobscmd },
1390         { BUILTIN_REGULAR       "kill", killcmd },
1391 #endif
1392 #ifdef CONFIG_ASH_MATH_SUPPORT
1393         { BUILTIN_NOSPEC        "let", letcmd },
1394 #endif
1395         { BUILTIN_ASSIGN        "local", localcmd },
1396         { BUILTIN_NOSPEC        "pwd", pwdcmd },
1397         { BUILTIN_REGULAR       "read", readcmd },
1398         { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
1399         { BUILTIN_SPEC_REG      "return", returncmd },
1400         { BUILTIN_SPEC_REG      "set", setcmd },
1401         { BUILTIN_SPEC_REG      "shift", shiftcmd },
1402         { BUILTIN_SPEC_REG      "times", timescmd },
1403         { BUILTIN_SPEC_REG      "trap", trapcmd },
1404         { BUILTIN_REGULAR       "true", truecmd },
1405         { BUILTIN_NOSPEC        "type", typecmd },
1406         { BUILTIN_NOSPEC        "ulimit", ulimitcmd },
1407         { BUILTIN_REGULAR       "umask", umaskcmd },
1408 #ifdef CONFIG_ASH_ALIAS
1409         { BUILTIN_REGULAR       "unalias", unaliascmd },
1410 #endif
1411         { BUILTIN_SPEC_REG      "unset", unsetcmd },
1412         { BUILTIN_REGULAR       "wait", waitcmd },
1413 };
1414
1415 #define NUMBUILTINS  (sizeof (builtincmd) / sizeof (struct builtincmd) )
1416
1417
1418
1419 struct cmdentry {
1420         int cmdtype;
1421         union param {
1422                 int index;
1423                 const struct builtincmd *cmd;
1424                 struct funcnode *func;
1425         } u;
1426 };
1427
1428
1429 /* action to find_command() */
1430 #define DO_ERR          0x01    /* prints errors */
1431 #define DO_ABS          0x02    /* checks absolute paths */
1432 #define DO_NOFUNC       0x04    /* don't return shell functions, for command */
1433 #define DO_ALTPATH      0x08    /* using alternate path */
1434 #define DO_ALTBLTIN     0x20    /* %builtin in alt. path */
1435
1436 static const char *pathopt;     /* set by padvance */
1437
1438 static void shellexec(char **, const char *, int)
1439     __attribute__((__noreturn__));
1440 static char *padvance(const char **, const char *);
1441 static void find_command(char *, struct cmdentry *, int, const char *);
1442 static struct builtincmd *find_builtin(const char *);
1443 static void hashcd(void);
1444 static void changepath(const char *);
1445 static void defun(char *, union node *);
1446 static void unsetfunc(const char *);
1447
1448 #ifdef CONFIG_ASH_MATH_SUPPORT
1449 #ifdef CONFIG_ASH_MATH_SUPPORT_64
1450 typedef int64_t arith_t;
1451 #else
1452 typedef long arith_t;
1453 #endif
1454 static arith_t dash_arith(const char *);
1455 static arith_t arith(const char *expr, int *perrcode);
1456 #endif
1457
1458 #ifdef CONFIG_ASH_RANDOM_SUPPORT
1459 static unsigned long rseed;
1460 static void change_random(const char *);
1461 # ifndef DYNAMIC_VAR
1462 #  define DYNAMIC_VAR
1463 # endif
1464 #endif
1465
1466 /*      $NetBSD: init.h,v 1.9 2002/11/24 22:35:40 christos Exp $        */
1467
1468 static void reset(void);
1469
1470 /*      $NetBSD: var.h,v 1.21 2003/01/22 20:36:04 dsl Exp $     */
1471
1472 /*
1473  * Shell variables.
1474  */
1475
1476 /* flags */
1477 #define VEXPORT         0x01    /* variable is exported */
1478 #define VREADONLY       0x02    /* variable cannot be modified */
1479 #define VSTRFIXED       0x04    /* variable struct is statically allocated */
1480 #define VTEXTFIXED      0x08    /* text is statically allocated */
1481 #define VSTACK          0x10    /* text is allocated on the stack */
1482 #define VUNSET          0x20    /* the variable is not set */
1483 #define VNOFUNC         0x40    /* don't call the callback function */
1484 #define VNOSET          0x80    /* do not set variable - just readonly test */
1485 #define VNOSAVE         0x100   /* when text is on the heap before setvareq */
1486 #ifdef DYNAMIC_VAR
1487 # define VDYNAMIC        0x200   /* dynamic variable */
1488 # else
1489 # define VDYNAMIC        0
1490 #endif
1491
1492 struct var {
1493         struct var *next;               /* next entry in hash list */
1494         int flags;                      /* flags are defined above */
1495         const char *text;               /* name=value */
1496         void (*func)(const char *);     /* function to be called when  */
1497                                         /* the variable gets set/unset */
1498 };
1499
1500 struct localvar {
1501         struct localvar *next;          /* next local variable in list */
1502         struct var *vp;                 /* the variable that was made local */
1503         int flags;                      /* saved flags */
1504         const char *text;               /* saved text */
1505 };
1506
1507
1508 static struct localvar *localvars;
1509
1510 /*
1511  * Shell variables.
1512  */
1513
1514 #ifdef CONFIG_ASH_GETOPTS
1515 static void getoptsreset(const char *);
1516 #endif
1517
1518 #ifdef CONFIG_LOCALE_SUPPORT
1519 #include <locale.h>
1520 static void change_lc_all(const char *value);
1521 static void change_lc_ctype(const char *value);
1522 #endif
1523
1524
1525 #define VTABSIZE 39
1526
1527 static const char defpathvar[] = "PATH=/usr/local/bin:/usr/bin:/sbin:/bin";
1528 #ifdef IFS_BROKEN
1529 static const char defifsvar[] = "IFS= \t\n";
1530 #define defifs (defifsvar + 4)
1531 #else
1532 static const char defifs[] = " \t\n";
1533 #endif
1534
1535
1536 static struct var varinit[] = {
1537 #ifdef IFS_BROKEN
1538         { 0,    VSTRFIXED|VTEXTFIXED,           defifsvar,      0 },
1539 #else
1540         { 0,    VSTRFIXED|VTEXTFIXED|VUNSET,    "IFS\0",        0 },
1541 #endif
1542
1543 #ifdef CONFIG_ASH_MAIL
1544         { 0,    VSTRFIXED|VTEXTFIXED|VUNSET,    "MAIL\0",       changemail },
1545         { 0,    VSTRFIXED|VTEXTFIXED|VUNSET,    "MAILPATH\0",   changemail },
1546 #endif
1547
1548         { 0,    VSTRFIXED|VTEXTFIXED,           defpathvar,     changepath },
1549         { 0,    VSTRFIXED|VTEXTFIXED,           "PS1=$ ",       0          },
1550         { 0,    VSTRFIXED|VTEXTFIXED,           "PS2=> ",       0          },
1551         { 0,    VSTRFIXED|VTEXTFIXED,           "PS4=+ ",       0          },
1552 #ifdef CONFIG_ASH_GETOPTS
1553         { 0,    VSTRFIXED|VTEXTFIXED,           "OPTIND=1",     getoptsreset },
1554 #endif
1555 #ifdef CONFIG_ASH_RANDOM_SUPPORT
1556         {0, VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random },
1557 #endif
1558 #ifdef CONFIG_LOCALE_SUPPORT
1559         {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0", change_lc_all },
1560         {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0", change_lc_ctype },
1561 #endif
1562 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
1563         {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0", NULL },
1564 #endif
1565 };
1566
1567 #define vifs varinit[0]
1568 #ifdef CONFIG_ASH_MAIL
1569 #define vmail (&vifs)[1]
1570 #define vmpath (&vmail)[1]
1571 #else
1572 #define vmpath vifs
1573 #endif
1574 #define vpath (&vmpath)[1]
1575 #define vps1 (&vpath)[1]
1576 #define vps2 (&vps1)[1]
1577 #define vps4 (&vps2)[1]
1578 #define voptind (&vps4)[1]
1579 #ifdef CONFIG_ASH_GETOPTS
1580 #define vrandom (&voptind)[1]
1581 #else
1582 #define vrandom (&vps4)[1]
1583 #endif
1584 #define defpath (defpathvar + 5)
1585
1586 /*
1587  * The following macros access the values of the above variables.
1588  * They have to skip over the name.  They return the null string
1589  * for unset variables.
1590  */
1591
1592 #define ifsval()        (vifs.text + 4)
1593 #define ifsset()        ((vifs.flags & VUNSET) == 0)
1594 #define mailval()       (vmail.text + 5)
1595 #define mpathval()      (vmpath.text + 9)
1596 #define pathval()       (vpath.text + 5)
1597 #define ps1val()        (vps1.text + 4)
1598 #define ps2val()        (vps2.text + 4)
1599 #define ps4val()        (vps4.text + 4)
1600 #define optindval()     (voptind.text + 7)
1601
1602 #define mpathset()      ((vmpath.flags & VUNSET) == 0)
1603
1604 static void setvar(const char *, const char *, int);
1605 static void setvareq(char *, int);
1606 static void listsetvar(struct strlist *, int);
1607 static char *lookupvar(const char *);
1608 static char *bltinlookup(const char *);
1609 static char **listvars(int, int, char ***);
1610 #define environment() listvars(VEXPORT, VUNSET, 0)
1611 static int showvars(const char *, int, int);
1612 static void poplocalvars(void);
1613 static int unsetvar(const char *);
1614 #ifdef CONFIG_ASH_GETOPTS
1615 static int setvarsafe(const char *, const char *, int);
1616 #endif
1617 static int varcmp(const char *, const char *);
1618 static struct var **hashvar(const char *);
1619
1620
1621 static inline int varequal(const char *a, const char *b) {
1622         return !varcmp(a, b);
1623 }
1624
1625
1626 static int loopnest;            /* current loop nesting level */
1627
1628 /*
1629  * The parsefile structure pointed to by the global variable parsefile
1630  * contains information about the current file being read.
1631  */
1632
1633
1634 struct redirtab {
1635         struct redirtab *next;
1636         int renamed[10];
1637         int nullredirs;
1638 };
1639
1640 static struct redirtab *redirlist;
1641 static int nullredirs;
1642
1643 extern char **environ;
1644
1645 /*      $NetBSD: output.h,v 1.16 2002/11/24 22:35:42 christos Exp $     */
1646
1647
1648 static void outstr(const char *, FILE *);
1649 static void outcslow(int, FILE *);
1650 static void flushall(void);
1651 static void flusherr(void);
1652 static int  out1fmt(const char *, ...)
1653     __attribute__((__format__(__printf__,1,2)));
1654 static int fmtstr(char *, size_t, const char *, ...)
1655     __attribute__((__format__(__printf__,3,4)));
1656
1657 static int preverrout_fd;   /* save fd2 before print debug if xflag is set. */
1658
1659
1660 static void out1str(const char *p)
1661 {
1662         outstr(p, stdout);
1663 }
1664
1665 static void out2str(const char *p)
1666 {
1667         outstr(p, stderr);
1668         flusherr();
1669 }
1670
1671 /*
1672  * Initialization code.
1673  */
1674
1675 /*
1676  * This routine initializes the builtin variables.
1677  */
1678
1679 static inline void
1680 initvar(void)
1681 {
1682         struct var *vp;
1683         struct var *end;
1684         struct var **vpp;
1685
1686         /*
1687          * PS1 depends on uid
1688          */
1689 #if defined(CONFIG_FEATURE_COMMAND_EDITING) && defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
1690         vps1.text = "PS1=\\w \\$ ";
1691 #else
1692         if (!geteuid())
1693                 vps1.text = "PS1=# ";
1694 #endif
1695         vp = varinit;
1696         end = vp + sizeof(varinit) / sizeof(varinit[0]);
1697         do {
1698                 vpp = hashvar(vp->text);
1699                 vp->next = *vpp;
1700                 *vpp = vp;
1701         } while (++vp < end);
1702 }
1703
1704 static inline void
1705 init(void)
1706 {
1707
1708       /* from input.c: */
1709       {
1710               basepf.nextc = basepf.buf = basebuf;
1711       }
1712
1713       /* from trap.c: */
1714       {
1715               signal(SIGCHLD, SIG_DFL);
1716       }
1717
1718       /* from var.c: */
1719       {
1720               char **envp;
1721               char ppid[32];
1722
1723               initvar();
1724               for (envp = environ ; *envp ; envp++) {
1725                       if (strchr(*envp, '=')) {
1726                               setvareq(*envp, VEXPORT|VTEXTFIXED);
1727                       }
1728               }
1729
1730               snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
1731               setvar("PPID", ppid, 0);
1732               setpwd(0, 0);
1733       }
1734 }
1735
1736 /* PEOF (the end of file marker) */
1737
1738 /*
1739  * The input line number.  Input.c just defines this variable, and saves
1740  * and restores it when files are pushed and popped.  The user of this
1741  * package must set its value.
1742  */
1743
1744 static int pgetc(void);
1745 static int pgetc2(void);
1746 static int preadbuffer(void);
1747 static void pungetc(void);
1748 static void pushstring(char *, void *);
1749 static void popstring(void);
1750 static void setinputfile(const char *, int);
1751 static void setinputfd(int, int);
1752 static void setinputstring(char *);
1753 static void popfile(void);
1754 static void popallfiles(void);
1755 static void closescript(void);
1756
1757
1758 /*      $NetBSD: jobs.h,v 1.17 2003/01/22 20:36:04 dsl Exp $    */
1759
1760
1761 /* Mode argument to forkshell.  Don't change FORK_FG or FORK_BG. */
1762 #define FORK_FG 0
1763 #define FORK_BG 1
1764 #define FORK_NOJOB 2
1765
1766 /* mode flags for showjob(s) */
1767 #define SHOW_PGID       0x01    /* only show pgid - for jobs -p */
1768 #define SHOW_PID        0x04    /* include process pid */
1769 #define SHOW_CHANGED    0x08    /* only jobs whose state has changed */
1770
1771
1772 /*
1773  * A job structure contains information about a job.  A job is either a
1774  * single process or a set of processes contained in a pipeline.  In the
1775  * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1776  * array of pids.
1777  */
1778
1779 struct procstat {
1780         pid_t   pid;            /* process id */
1781         int     status;         /* last process status from wait() */
1782         char    *cmd;           /* text of command being run */
1783 };
1784
1785 struct job {
1786         struct procstat ps0;    /* status of process */
1787         struct procstat *ps;    /* status or processes when more than one */
1788 #if JOBS
1789         int stopstatus;         /* status of a stopped job */
1790 #endif
1791         uint32_t
1792                 nprocs: 16,     /* number of processes */
1793                 state: 8,
1794 #define JOBRUNNING      0       /* at least one proc running */
1795 #define JOBSTOPPED      1       /* all procs are stopped */
1796 #define JOBDONE         2       /* all procs are completed */
1797 #if JOBS
1798                 sigint: 1,      /* job was killed by SIGINT */
1799                 jobctl: 1,      /* job running under job control */
1800 #endif
1801                 waited: 1,      /* true if this entry has been waited for */
1802                 used: 1,        /* true if this entry is in used */
1803                 changed: 1;     /* true if status has changed */
1804         struct job *prev_job;   /* previous job */
1805 };
1806
1807 static pid_t backgndpid;        /* pid of last background process */
1808 static int job_warning;         /* user was warned about stopped jobs */
1809 #if JOBS
1810 static int jobctl;              /* true if doing job control */
1811 #endif
1812
1813 static struct job *makejob(union node *, int);
1814 static int forkshell(struct job *, union node *, int);
1815 static int waitforjob(struct job *);
1816 static int stoppedjobs(void);
1817
1818 #if ! JOBS
1819 #define setjobctl(on)   /* do nothing */
1820 #else
1821 static void setjobctl(int);
1822 static void showjobs(FILE *, int);
1823 #endif
1824
1825 /*      $NetBSD: main.h,v 1.9 2002/11/24 22:35:41 christos Exp $        */
1826
1827
1828 /* pid of main shell */
1829 static int rootpid;
1830 /* true if we aren't a child of the main shell */
1831 static int rootshell;
1832
1833 static void readcmdfile(char *);
1834 static void cmdloop(int);
1835
1836 /*      $NetBSD: memalloc.h,v 1.13 2003/01/22 20:36:04 dsl Exp $        */
1837
1838
1839 struct stackmark {
1840         struct stack_block *stackp;
1841         char *stacknxt;
1842         size_t stacknleft;
1843         struct stackmark *marknext;
1844 };
1845
1846 /* minimum size of a block */
1847 #define MINSIZE SHELL_ALIGN(504)
1848
1849 struct stack_block {
1850         struct stack_block *prev;
1851         char space[MINSIZE];
1852 };
1853
1854 static struct stack_block stackbase;
1855 static struct stack_block *stackp = &stackbase;
1856 static struct stackmark *markp;
1857 static char *stacknxt = stackbase.space;
1858 static size_t stacknleft = MINSIZE;
1859 static char *sstrend = stackbase.space + MINSIZE;
1860 static int herefd = -1;
1861
1862
1863 static pointer ckmalloc(size_t);
1864 static pointer ckrealloc(pointer, size_t);
1865 static char *savestr(const char *);
1866 static pointer stalloc(size_t);
1867 static void stunalloc(pointer);
1868 static void setstackmark(struct stackmark *);
1869 static void popstackmark(struct stackmark *);
1870 static void growstackblock(void);
1871 static void *growstackstr(void);
1872 static char *makestrspace(size_t, char *);
1873 static char *stnputs(const char *, size_t, char *);
1874 static char *stputs(const char *, char *);
1875
1876
1877 static inline char *_STPUTC(char c, char *p) {
1878         if (p == sstrend)
1879                 p = growstackstr();
1880         *p++ = c;
1881         return p;
1882 }
1883
1884 #define stackblock() ((void *)stacknxt)
1885 #define stackblocksize() stacknleft
1886 #define STARTSTACKSTR(p) ((p) = stackblock())
1887 #define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
1888 #define CHECKSTRSPACE(n, p) \
1889         ({ \
1890                 char *q = (p); \
1891                 size_t l = (n); \
1892                 size_t m = sstrend - q; \
1893                 if (l > m) \
1894                         (p) = makestrspace(l, q); \
1895                 0; \
1896         })
1897 #define USTPUTC(c, p)   (*p++ = (c))
1898 #define STACKSTRNUL(p)  ((p) == sstrend? (p = growstackstr(), *p = '\0') : (*p = '\0'))
1899 #define STUNPUTC(p)     (--p)
1900 #define STTOPC(p)       p[-1]
1901 #define STADJUST(amount, p)     (p += (amount))
1902
1903 #define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
1904 #define ungrabstackstr(s, p) stunalloc((s))
1905 #define stackstrend() ((void *)sstrend)
1906
1907 #define ckfree(p)       free((pointer)(p))
1908
1909 /*      $NetBSD: mystring.h,v 1.10 2002/11/24 22:35:42 christos Exp $   */
1910
1911
1912 #define DOLATSTRLEN 4
1913
1914 static char *prefix(const char *, const char *);
1915 static int number(const char *);
1916 static int is_number(const char *);
1917 static char *single_quote(const char *);
1918 static char *sstrdup(const char *);
1919
1920 #define equal(s1, s2)   (strcmp(s1, s2) == 0)
1921 #define scopy(s1, s2)   ((void)strcpy(s2, s1))
1922
1923 /*      $NetBSD: options.h,v 1.16 2003/01/22 20:36:04 dsl Exp $ */
1924
1925 struct shparam {
1926         int nparam;             /* # of positional parameters (without $0) */
1927         unsigned char malloc;   /* if parameter list dynamically allocated */
1928         char **p;               /* parameter list */
1929 #ifdef CONFIG_ASH_GETOPTS
1930         int optind;             /* next parameter to be processed by getopts */
1931         int optoff;             /* used by getopts */
1932 #endif
1933 };
1934
1935
1936 #define eflag optlist[0]
1937 #define fflag optlist[1]
1938 #define Iflag optlist[2]
1939 #define iflag optlist[3]
1940 #define mflag optlist[4]
1941 #define nflag optlist[5]
1942 #define sflag optlist[6]
1943 #define xflag optlist[7]
1944 #define vflag optlist[8]
1945 #define Cflag optlist[9]
1946 #define aflag optlist[10]
1947 #define bflag optlist[11]
1948 #define uflag optlist[12]
1949 #define qflag optlist[13]
1950
1951 #ifdef DEBUG
1952 #define nolog optlist[14]
1953 #define debug optlist[15]
1954 #define NOPTS   16
1955 #else
1956 #define NOPTS   14
1957 #endif
1958
1959 /*      $NetBSD: options.c,v 1.33 2003/01/22 20:36:04 dsl Exp $ */
1960
1961
1962 static const char *const optletters_optnames[NOPTS] = {
1963         "e"   "errexit",
1964         "f"   "noglob",
1965         "I"   "ignoreeof",
1966         "i"   "interactive",
1967         "m"   "monitor",
1968         "n"   "noexec",
1969         "s"   "stdin",
1970         "x"   "xtrace",
1971         "v"   "verbose",
1972         "C"   "noclobber",
1973         "a"   "allexport",
1974         "b"   "notify",
1975         "u"   "nounset",
1976         "q"   "quietprofile",
1977 #ifdef DEBUG
1978         "\0"  "nolog",
1979         "\0"  "debug",
1980 #endif
1981 };
1982
1983 #define optletters(n) optletters_optnames[(n)][0]
1984 #define optnames(n) (&optletters_optnames[(n)][1])
1985
1986
1987 static char optlist[NOPTS];
1988
1989
1990 static char *arg0;                     /* value of $0 */
1991 static struct shparam shellparam;      /* $@ current positional parameters */
1992 static char **argptr;                  /* argument list for builtin commands */
1993 static char *optionarg;                /* set by nextopt (like getopt) */
1994 static char *optptr;                   /* used by nextopt */
1995
1996 static char *minusc;                   /* argument to -c option */
1997
1998
1999 static void procargs(int, char **);
2000 static void optschanged(void);
2001 static void setparam(char **);
2002 static void freeparam(volatile struct shparam *);
2003 static int shiftcmd(int, char **);
2004 static int setcmd(int, char **);
2005 static int nextopt(const char *);
2006
2007 /*      $NetBSD: redir.h,v 1.14 2002/11/24 22:35:43 christos Exp $      */
2008
2009 /* flags passed to redirect */
2010 #define REDIR_PUSH 01           /* save previous values of file descriptors */
2011 #define REDIR_SAVEFD2 03       /* set preverrout */
2012
2013 union node;
2014 static void redirect(union node *, int);
2015 static void popredir(int);
2016 static void clearredir(int);
2017 static int copyfd(int, int);
2018 static int redirectsafe(union node *, int);
2019
2020 /*      $NetBSD: show.h,v 1.6 2003/01/22 20:36:04 dsl Exp $     */
2021
2022
2023 #ifdef DEBUG
2024 static void showtree(union node *);
2025 static void trace(const char *, ...);
2026 static void tracev(const char *, va_list);
2027 static void trargs(char **);
2028 static void trputc(int);
2029 static void trputs(const char *);
2030 static void opentrace(void);
2031 #endif
2032
2033 /*      $NetBSD: trap.h,v 1.16 2002/11/24 22:35:43 christos Exp $       */
2034
2035
2036 /* trap handler commands */
2037 static char *trap[NSIG];
2038 /* current value of signal */
2039 static char sigmode[NSIG - 1];
2040 /* indicates specified signal received */
2041 static char gotsig[NSIG - 1];
2042
2043 static void clear_traps(void);
2044 static void setsignal(int);
2045 static void ignoresig(int);
2046 static void onsig(int);
2047 static void dotrap(void);
2048 static void setinteractive(int);
2049 static void exitshell(void) __attribute__((__noreturn__));
2050 static int decode_signal(const char *, int);
2051
2052 /*
2053  * This routine is called when an error or an interrupt occurs in an
2054  * interactive shell and control is returned to the main command loop.
2055  */
2056
2057 static void
2058 reset(void)
2059 {
2060       /* from eval.c: */
2061       {
2062               evalskip = 0;
2063               loopnest = 0;
2064               funcnest = 0;
2065       }
2066
2067       /* from input.c: */
2068       {
2069               parselleft = parsenleft = 0;      /* clear input buffer */
2070               popallfiles();
2071       }
2072
2073       /* from parser.c: */
2074       {
2075               tokpushback = 0;
2076               checkkwd = 0;
2077       }
2078
2079       /* from redir.c: */
2080       {
2081               clearredir(0);
2082       }
2083
2084 }
2085
2086 #ifdef CONFIG_ASH_ALIAS
2087 static struct alias *atab[ATABSIZE];
2088
2089 static void setalias(const char *, const char *);
2090 static struct alias *freealias(struct alias *);
2091 static struct alias **__lookupalias(const char *);
2092
2093 static void
2094 setalias(const char *name, const char *val)
2095 {
2096         struct alias *ap, **app;
2097
2098         app = __lookupalias(name);
2099         ap = *app;
2100         INTOFF;
2101         if (ap) {
2102                 if (!(ap->flag & ALIASINUSE)) {
2103                         ckfree(ap->val);
2104                 }
2105                 ap->val = savestr(val);
2106                 ap->flag &= ~ALIASDEAD;
2107         } else {
2108                 /* not found */
2109                 ap = ckmalloc(sizeof (struct alias));
2110                 ap->name = savestr(name);
2111                 ap->val = savestr(val);
2112                 ap->flag = 0;
2113                 ap->next = 0;
2114                 *app = ap;
2115         }
2116         INTON;
2117 }
2118
2119 static int
2120 unalias(const char *name)
2121 {
2122         struct alias **app;
2123
2124         app = __lookupalias(name);
2125
2126         if (*app) {
2127                 INTOFF;
2128                 *app = freealias(*app);
2129                 INTON;
2130                 return (0);
2131         }
2132
2133         return (1);
2134 }
2135
2136 static void
2137 rmaliases(void)
2138 {
2139         struct alias *ap, **app;
2140         int i;
2141
2142         INTOFF;
2143         for (i = 0; i < ATABSIZE; i++) {
2144                 app = &atab[i];
2145                 for (ap = *app; ap; ap = *app) {
2146                         *app = freealias(*app);
2147                         if (ap == *app) {
2148                                 app = &ap->next;
2149                         }
2150                 }
2151         }
2152         INTON;
2153 }
2154
2155 static struct alias *
2156 lookupalias(const char *name, int check)
2157 {
2158         struct alias *ap = *__lookupalias(name);
2159
2160         if (check && ap && (ap->flag & ALIASINUSE))
2161                 return (NULL);
2162         return (ap);
2163 }
2164
2165 /*
2166  * TODO - sort output
2167  */
2168 static int
2169 aliascmd(int argc, char **argv)
2170 {
2171         char *n, *v;
2172         int ret = 0;
2173         struct alias *ap;
2174
2175         if (argc == 1) {
2176                 int i;
2177
2178                 for (i = 0; i < ATABSIZE; i++)
2179                         for (ap = atab[i]; ap; ap = ap->next) {
2180                                 printalias(ap);
2181                         }
2182                 return (0);
2183         }
2184         while ((n = *++argv) != NULL) {
2185                 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
2186                         if ((ap = *__lookupalias(n)) == NULL) {
2187                                 fprintf(stderr, "%s: %s not found\n", "alias", n);
2188                                 ret = 1;
2189                         } else
2190                                 printalias(ap);
2191                 } else {
2192                         *v++ = '\0';
2193                         setalias(n, v);
2194                 }
2195         }
2196
2197         return (ret);
2198 }
2199
2200 static int
2201 unaliascmd(int argc, char **argv)
2202 {
2203         int i;
2204
2205         while ((i = nextopt("a")) != '\0') {
2206                 if (i == 'a') {
2207                         rmaliases();
2208                         return (0);
2209                 }
2210         }
2211         for (i = 0; *argptr; argptr++) {
2212                 if (unalias(*argptr)) {
2213                         fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
2214                         i = 1;
2215                 }
2216         }
2217
2218         return (i);
2219 }
2220
2221 static struct alias *
2222 freealias(struct alias *ap) {
2223         struct alias *next;
2224
2225         if (ap->flag & ALIASINUSE) {
2226                 ap->flag |= ALIASDEAD;
2227                 return ap;
2228         }
2229
2230         next = ap->next;
2231         ckfree(ap->name);
2232         ckfree(ap->val);
2233         ckfree(ap);
2234         return next;
2235 }
2236
2237 static void
2238 printalias(const struct alias *ap) {
2239         out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
2240 }
2241
2242 static struct alias **
2243 __lookupalias(const char *name) {
2244         unsigned int hashval;
2245         struct alias **app;
2246         const char *p;
2247         unsigned int ch;
2248
2249         p = name;
2250
2251         ch = (unsigned char)*p;
2252         hashval = ch << 4;
2253         while (ch) {
2254                 hashval += ch;
2255                 ch = (unsigned char)*++p;
2256         }
2257         app = &atab[hashval % ATABSIZE];
2258
2259         for (; *app; app = &(*app)->next) {
2260                 if (equal(name, (*app)->name)) {
2261                         break;
2262                 }
2263         }
2264
2265         return app;
2266 }
2267 #endif /* CONFIG_ASH_ALIAS */
2268
2269
2270 /*      $NetBSD: cd.c,v 1.30 2003/01/22 20:36:03 dsl Exp $      */
2271
2272 /*
2273  * The cd and pwd commands.
2274  */
2275
2276 #define CD_PHYSICAL 1
2277 #define CD_PRINT 2
2278
2279 static int docd(const char *, int);
2280 static int cdopt(void);
2281
2282 static char *curdir = nullstr;          /* current working directory */
2283 static char *physdir = nullstr;         /* physical working directory */
2284
2285 static int
2286 cdopt(void)
2287 {
2288         int flags = 0;
2289         int i, j;
2290
2291         j = 'L';
2292         while ((i = nextopt("LP"))) {
2293                 if (i != j) {
2294                         flags ^= CD_PHYSICAL;
2295                         j = i;
2296                 }
2297         }
2298
2299         return flags;
2300 }
2301
2302 static int
2303 cdcmd(int argc, char **argv)
2304 {
2305         const char *dest;
2306         const char *path;
2307         const char *p;
2308         char c;
2309         struct stat statb;
2310         int flags;
2311
2312         flags = cdopt();
2313         dest = *argptr;
2314         if (!dest)
2315                 dest = bltinlookup(homestr);
2316         else if (dest[0] == '-' && dest[1] == '\0') {
2317                 dest = bltinlookup("OLDPWD");
2318                 flags |= CD_PRINT;
2319                 goto step7;
2320         }
2321         if (!dest)
2322                 dest = nullstr;
2323         if (*dest == '/')
2324                 goto step7;
2325         if (*dest == '.') {
2326                 c = dest[1];
2327 dotdot:
2328                 switch (c) {
2329                 case '\0':
2330                 case '/':
2331                         goto step6;
2332                 case '.':
2333                         c = dest[2];
2334                         if (c != '.')
2335                                 goto dotdot;
2336                 }
2337         }
2338         if (!*dest)
2339                 dest = ".";
2340         if (!(path = bltinlookup("CDPATH"))) {
2341 step6:
2342 step7:
2343                 p = dest;
2344                 goto docd;
2345         }
2346         do {
2347                 c = *path;
2348                 p = padvance(&path, dest);
2349                 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2350                         if (c && c != ':')
2351                                 flags |= CD_PRINT;
2352 docd:
2353                         if (!docd(p, flags))
2354                                 goto out;
2355                         break;
2356                 }
2357         } while (path);
2358         error("can't cd to %s", dest);
2359         /* NOTREACHED */
2360 out:
2361         if (flags & CD_PRINT)
2362                 out1fmt(snlfmt, curdir);
2363         return 0;
2364 }
2365
2366
2367 /*
2368  * Update curdir (the name of the current directory) in response to a
2369  * cd command.
2370  */
2371
2372 static inline const char *
2373 updatepwd(const char *dir)
2374 {
2375         char *new;
2376         char *p;
2377         char *cdcomppath;
2378         const char *lim;
2379
2380         cdcomppath = sstrdup(dir);
2381         STARTSTACKSTR(new);
2382         if (*dir != '/') {
2383                 if (curdir == nullstr)
2384                         return 0;
2385                 new = stputs(curdir, new);
2386         }
2387         new = makestrspace(strlen(dir) + 2, new);
2388         lim = stackblock() + 1;
2389         if (*dir != '/') {
2390                 if (new[-1] != '/')
2391                         USTPUTC('/', new);
2392                 if (new > lim && *lim == '/')
2393                         lim++;
2394         } else {
2395                 USTPUTC('/', new);
2396                 cdcomppath++;
2397                 if (dir[1] == '/' && dir[2] != '/') {
2398                         USTPUTC('/', new);
2399                         cdcomppath++;
2400                         lim++;
2401                 }
2402         }
2403         p = strtok(cdcomppath, "/");
2404         while (p) {
2405                 switch(*p) {
2406                 case '.':
2407                         if (p[1] == '.' && p[2] == '\0') {
2408                                 while (new > lim) {
2409                                         STUNPUTC(new);
2410                                         if (new[-1] == '/')
2411                                                 break;
2412                                 }
2413                                 break;
2414                         } else if (p[1] == '\0')
2415                                 break;
2416                         /* fall through */
2417                 default:
2418                         new = stputs(p, new);
2419                         USTPUTC('/', new);
2420                 }
2421                 p = strtok(0, "/");
2422         }
2423         if (new > lim)
2424                 STUNPUTC(new);
2425         *new = 0;
2426         return stackblock();
2427 }
2428
2429 /*
2430  * Actually do the chdir.  We also call hashcd to let the routines in exec.c
2431  * know that the current directory has changed.
2432  */
2433
2434 static int
2435 docd(const char *dest, int flags)
2436 {
2437         const char *dir = 0;
2438         int err;
2439
2440         TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2441
2442         INTOFF;
2443         if (!(flags & CD_PHYSICAL)) {
2444                 dir = updatepwd(dest);
2445                 if (dir)
2446                         dest = dir;
2447         }
2448         err = chdir(dest);
2449         if (err)
2450                 goto out;
2451         setpwd(dir, 1);
2452         hashcd();
2453 out:
2454         INTON;
2455         return err;
2456 }
2457
2458 /*
2459  * Find out what the current directory is. If we already know the current
2460  * directory, this routine returns immediately.
2461  */
2462 static inline char *
2463 getpwd(void)
2464 {
2465         char *dir = getcwd(0, 0);
2466         return dir ? dir : nullstr;
2467 }
2468
2469 static int
2470 pwdcmd(int argc, char **argv)
2471 {
2472         int flags;
2473         const char *dir = curdir;
2474
2475         flags = cdopt();
2476         if (flags) {
2477                 if (physdir == nullstr)
2478                         setpwd(dir, 0);
2479                 dir = physdir;
2480         }
2481         out1fmt(snlfmt, dir);
2482         return 0;
2483 }
2484
2485 static void
2486 setpwd(const char *val, int setold)
2487 {
2488         char *oldcur, *dir;
2489
2490         oldcur = dir = curdir;
2491
2492         if (setold) {
2493                 setvar("OLDPWD", oldcur, VEXPORT);
2494         }
2495         INTOFF;
2496         if (physdir != nullstr) {
2497                 if (physdir != oldcur)
2498                         free(physdir);
2499                 physdir = nullstr;
2500         }
2501         if (oldcur == val || !val) {
2502                 char *s = getpwd();
2503                 physdir = s;
2504                 if (!val)
2505                         dir = s;
2506         } else
2507                 dir = savestr(val);
2508         if (oldcur != dir && oldcur != nullstr) {
2509                 free(oldcur);
2510         }
2511         curdir = dir;
2512         INTON;
2513         setvar("PWD", dir, VEXPORT);
2514 }
2515
2516 /*      $NetBSD: error.c,v 1.30 2003/01/22 20:36:03 dsl Exp $   */
2517
2518 /*
2519  * Errors and exceptions.
2520  */
2521
2522 /*
2523  * Code to handle exceptions in C.
2524  */
2525
2526
2527
2528 static void exverror(int, const char *, va_list)
2529     __attribute__((__noreturn__));
2530
2531 /*
2532  * Called to raise an exception.  Since C doesn't include exceptions, we
2533  * just do a longjmp to the exception handler.  The type of exception is
2534  * stored in the global variable "exception".
2535  */
2536
2537 static void
2538 exraise(int e)
2539 {
2540 #ifdef DEBUG
2541         if (handler == NULL)
2542                 abort();
2543 #endif
2544         INTOFF;
2545
2546         exception = e;
2547         longjmp(handler->loc, 1);
2548 }
2549
2550
2551 /*
2552  * Called from trap.c when a SIGINT is received.  (If the user specifies
2553  * that SIGINT is to be trapped or ignored using the trap builtin, then
2554  * this routine is not called.)  Suppressint is nonzero when interrupts
2555  * are held using the INTOFF macro.  (The test for iflag is just
2556  * defensive programming.)
2557  */
2558
2559 static void
2560 onint(void) {
2561         int i;
2562
2563         intpending = 0;
2564         sigsetmask(0);
2565         i = EXSIG;
2566         if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
2567                 if (!(rootshell && iflag)) {
2568                         signal(SIGINT, SIG_DFL);
2569                         raise(SIGINT);
2570                 }
2571                 i = EXINT;
2572         }
2573         exraise(i);
2574         /* NOTREACHED */
2575 }
2576
2577 static void
2578 exvwarning(const char *msg, va_list ap)
2579 {
2580         FILE *errs;
2581         const char *name;
2582         const char *fmt;
2583
2584         errs = stderr;
2585         name = arg0;
2586         fmt = "%s: ";
2587         if (commandname) {
2588                 name = commandname;
2589                 fmt = "%s: %d: ";
2590         }
2591         fprintf(errs, fmt, name, startlinno);
2592         vfprintf(errs, msg, ap);
2593         outcslow('\n', errs);
2594 }
2595
2596 /*
2597  * Exverror is called to raise the error exception.  If the second argument
2598  * is not NULL then error prints an error message using printf style
2599  * formatting.  It then raises the error exception.
2600  */
2601 static void
2602 exverror(int cond, const char *msg, va_list ap)
2603 {
2604 #ifdef DEBUG
2605         if (msg) {
2606                 TRACE(("exverror(%d, \"", cond));
2607                 TRACEV((msg, ap));
2608                 TRACE(("\") pid=%d\n", getpid()));
2609         } else
2610                 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
2611         if (msg)
2612 #endif
2613                 exvwarning(msg, ap);
2614
2615         flushall();
2616         exraise(cond);
2617         /* NOTREACHED */
2618 }
2619
2620
2621 static void
2622 error(const char *msg, ...)
2623 {
2624         va_list ap;
2625
2626         va_start(ap, msg);
2627         exverror(EXERROR, msg, ap);
2628         /* NOTREACHED */
2629         va_end(ap);
2630 }
2631
2632
2633 static void
2634 exerror(int cond, const char *msg, ...)
2635 {
2636         va_list ap;
2637
2638         va_start(ap, msg);
2639         exverror(cond, msg, ap);
2640         /* NOTREACHED */
2641         va_end(ap);
2642 }
2643
2644 /*
2645  * error/warning routines for external builtins
2646  */
2647
2648 static void
2649 sh_warnx(const char *fmt, ...)
2650 {
2651         va_list ap;
2652
2653         va_start(ap, fmt);
2654         exvwarning(fmt, ap);
2655         va_end(ap);
2656 }
2657
2658
2659 /*
2660  * Return a string describing an error.  The returned string may be a
2661  * pointer to a static buffer that will be overwritten on the next call.
2662  * Action describes the operation that got the error.
2663  */
2664
2665 static const char *
2666 errmsg(int e, const char *em)
2667 {
2668         if(e == ENOENT || e == ENOTDIR) {
2669
2670                 return em;
2671         }
2672         return strerror(e);
2673 }
2674
2675
2676 /*      $NetBSD: eval.c,v 1.71 2003/01/23 03:33:16 rafal Exp $  */
2677
2678 /*
2679  * Evaluate a command.
2680  */
2681
2682 /* flags in argument to evaltree */
2683 #define EV_EXIT 01              /* exit after evaluating tree */
2684 #define EV_TESTED 02            /* exit status is checked; ignore -e flag */
2685 #define EV_BACKCMD 04           /* command executing within back quotes */
2686
2687
2688 static void evalloop(union node *, int);
2689 static void evalfor(union node *, int);
2690 static void evalcase(union node *, int);
2691 static void evalsubshell(union node *, int);
2692 static void expredir(union node *);
2693 static void evalpipe(union node *, int);
2694 static void evalcommand(union node *, int);
2695 static int evalbltin(const struct builtincmd *, int, char **);
2696 static int evalfun(struct funcnode *, int, char **, int);
2697 static void prehash(union node *);
2698 static int bltincmd(int, char **);
2699
2700
2701 static const struct builtincmd bltin = {
2702         "\0\0", bltincmd
2703 };
2704
2705
2706 /*
2707  * Called to reset things after an exception.
2708  */
2709
2710 /*
2711  * The eval command.
2712  */
2713
2714 static int
2715 evalcmd(int argc, char **argv)
2716 {
2717         char *p;
2718         char *concat;
2719         char **ap;
2720
2721         if (argc > 1) {
2722                 p = argv[1];
2723                 if (argc > 2) {
2724                         STARTSTACKSTR(concat);
2725                         ap = argv + 2;
2726                         for (;;) {
2727                                 concat = stputs(p, concat);
2728                                 if ((p = *ap++) == NULL)
2729                                         break;
2730                                 STPUTC(' ', concat);
2731                         }
2732                         STPUTC('\0', concat);
2733                         p = grabstackstr(concat);
2734                 }
2735                 evalstring(p);
2736         }
2737         return exitstatus;
2738 }
2739
2740
2741 /*
2742  * Execute a command or commands contained in a string.
2743  */
2744
2745 static void
2746 evalstring(char *s)
2747 {
2748         union node *n;
2749         struct stackmark smark;
2750
2751         setstackmark(&smark);
2752         setinputstring(s);
2753
2754         while ((n = parsecmd(0)) != NEOF) {
2755                 evaltree(n, 0);
2756                 popstackmark(&smark);
2757                 if (evalskip)
2758                         break;
2759         }
2760         popfile();
2761         popstackmark(&smark);
2762 }
2763
2764
2765
2766 /*
2767  * Evaluate a parse tree.  The value is left in the global variable
2768  * exitstatus.
2769  */
2770
2771 static void
2772 evaltree(union node *n, int flags)
2773 {
2774         int checkexit = 0;
2775         void (*evalfn)(union node *, int);
2776         unsigned isor;
2777         int status;
2778         if (n == NULL) {
2779                 TRACE(("evaltree(NULL) called\n"));
2780                 goto out;
2781         }
2782         TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
2783             getpid(), n, n->type, flags));
2784         switch (n->type) {
2785         default:
2786 #ifdef DEBUG
2787                 out1fmt("Node type = %d\n", n->type);
2788                 fflush(stdout);
2789                 break;
2790 #endif
2791         case NNOT:
2792                 evaltree(n->nnot.com, EV_TESTED);
2793                 status = !exitstatus;
2794                 goto setstatus;
2795         case NREDIR:
2796                 expredir(n->nredir.redirect);
2797                 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
2798                 if (!status) {
2799                         evaltree(n->nredir.n, flags & EV_TESTED);
2800                         status = exitstatus;
2801                 }
2802                 popredir(0);
2803                 goto setstatus;
2804         case NCMD:
2805                 evalfn = evalcommand;
2806 checkexit:
2807                 if (eflag && !(flags & EV_TESTED))
2808                         checkexit = ~0;
2809                 goto calleval;
2810         case NFOR:
2811                 evalfn = evalfor;
2812                 goto calleval;
2813         case NWHILE:
2814         case NUNTIL:
2815                 evalfn = evalloop;
2816                 goto calleval;
2817         case NSUBSHELL:
2818         case NBACKGND:
2819                 evalfn = evalsubshell;
2820                 goto calleval;
2821         case NPIPE:
2822                 evalfn = evalpipe;
2823                 goto checkexit;
2824         case NCASE:
2825                 evalfn = evalcase;
2826                 goto calleval;
2827         case NAND:
2828         case NOR:
2829         case NSEMI:
2830 #if NAND + 1 != NOR
2831 #error NAND + 1 != NOR
2832 #endif
2833 #if NOR + 1 != NSEMI
2834 #error NOR + 1 != NSEMI
2835 #endif
2836                 isor = n->type - NAND;
2837                 evaltree(
2838                         n->nbinary.ch1,
2839                         (flags | ((isor >> 1) - 1)) & EV_TESTED
2840                 );
2841                 if (!exitstatus == isor)
2842                         break;
2843                 if (!evalskip) {
2844                         n = n->nbinary.ch2;
2845 evaln:
2846                         evalfn = evaltree;
2847 calleval:
2848                         evalfn(n, flags);
2849                         break;
2850                 }
2851                 break;
2852         case NIF:
2853                 evaltree(n->nif.test, EV_TESTED);
2854                 if (evalskip)
2855                         break;
2856                 if (exitstatus == 0) {
2857                         n = n->nif.ifpart;
2858                         goto evaln;
2859                 } else if (n->nif.elsepart) {
2860                         n = n->nif.elsepart;
2861                         goto evaln;
2862                 }
2863                 goto success;
2864         case NDEFUN:
2865                 defun(n->narg.text, n->narg.next);
2866 success:
2867                 status = 0;
2868 setstatus:
2869                 exitstatus = status;
2870                 break;
2871         }
2872 out:
2873         if (pendingsigs)
2874                 dotrap();
2875         if (flags & EV_EXIT || checkexit & exitstatus)
2876                 exraise(EXEXIT);
2877 }
2878
2879
2880 #if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
2881 static
2882 #endif
2883 void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
2884
2885
2886 static void
2887 evalloop(union node *n, int flags)
2888 {
2889         int status;
2890
2891         loopnest++;
2892         status = 0;
2893         flags &= EV_TESTED;
2894         for (;;) {
2895                 int i;
2896
2897                 evaltree(n->nbinary.ch1, EV_TESTED);
2898                 if (evalskip) {
2899 skipping:         if (evalskip == SKIPCONT && --skipcount <= 0) {
2900                                 evalskip = 0;
2901                                 continue;
2902                         }
2903                         if (evalskip == SKIPBREAK && --skipcount <= 0)
2904                                 evalskip = 0;
2905                         break;
2906                 }
2907                 i = exitstatus;
2908                 if (n->type != NWHILE)
2909                         i = !i;
2910                 if (i != 0)
2911                         break;
2912                 evaltree(n->nbinary.ch2, flags);
2913                 status = exitstatus;
2914                 if (evalskip)
2915                         goto skipping;
2916         }
2917         loopnest--;
2918         exitstatus = status;
2919 }
2920
2921
2922
2923 static void
2924 evalfor(union node *n, int flags)
2925 {
2926         struct arglist arglist;
2927         union node *argp;
2928         struct strlist *sp;
2929         struct stackmark smark;
2930
2931         setstackmark(&smark);
2932         arglist.lastp = &arglist.list;
2933         for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
2934                 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
2935                 /* XXX */
2936                 if (evalskip)
2937                         goto out;
2938         }
2939         *arglist.lastp = NULL;
2940
2941         exitstatus = 0;
2942         loopnest++;
2943         flags &= EV_TESTED;
2944         for (sp = arglist.list ; sp ; sp = sp->next) {
2945                 setvar(n->nfor.var, sp->text, 0);
2946                 evaltree(n->nfor.body, flags);
2947                 if (evalskip) {
2948                         if (evalskip == SKIPCONT && --skipcount <= 0) {
2949                                 evalskip = 0;
2950                                 continue;
2951                         }
2952                         if (evalskip == SKIPBREAK && --skipcount <= 0)
2953                                 evalskip = 0;
2954                         break;
2955                 }
2956         }
2957         loopnest--;
2958 out:
2959         popstackmark(&smark);
2960 }
2961
2962
2963
2964 static void
2965 evalcase(union node *n, int flags)
2966 {
2967         union node *cp;
2968         union node *patp;
2969         struct arglist arglist;
2970         struct stackmark smark;
2971
2972         setstackmark(&smark);
2973         arglist.lastp = &arglist.list;
2974         expandarg(n->ncase.expr, &arglist, EXP_TILDE);
2975         exitstatus = 0;
2976         for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2977                 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
2978                         if (casematch(patp, arglist.list->text)) {
2979                                 if (evalskip == 0) {
2980                                         evaltree(cp->nclist.body, flags);
2981                                 }
2982                                 goto out;
2983                         }
2984                 }
2985         }
2986 out:
2987         popstackmark(&smark);
2988 }
2989
2990
2991
2992 /*
2993  * Kick off a subshell to evaluate a tree.
2994  */
2995
2996 static void
2997 evalsubshell(union node *n, int flags)
2998 {
2999         struct job *jp;
3000         int backgnd = (n->type == NBACKGND);
3001         int status;
3002
3003         expredir(n->nredir.redirect);
3004         if (!backgnd && flags & EV_EXIT && !trap[0])
3005                 goto nofork;
3006         INTOFF;
3007         jp = makejob(n, 1);
3008         if (forkshell(jp, n, backgnd) == 0) {
3009                 INTON;
3010                 flags |= EV_EXIT;
3011                 if (backgnd)
3012                         flags &=~ EV_TESTED;
3013 nofork:
3014                 redirect(n->nredir.redirect, 0);
3015                 evaltreenr(n->nredir.n, flags);
3016                 /* never returns */
3017         }
3018         status = 0;
3019         if (! backgnd)
3020                 status = waitforjob(jp);
3021         exitstatus = status;
3022         INTON;
3023 }
3024
3025
3026
3027 /*
3028  * Compute the names of the files in a redirection list.
3029  */
3030
3031 static void
3032 expredir(union node *n)
3033 {
3034         union node *redir;
3035
3036         for (redir = n ; redir ; redir = redir->nfile.next) {
3037                 struct arglist fn;
3038                 fn.lastp = &fn.list;
3039                 switch (redir->type) {
3040                 case NFROMTO:
3041                 case NFROM:
3042                 case NTO:
3043                 case NCLOBBER:
3044                 case NAPPEND:
3045                         expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
3046                         redir->nfile.expfname = fn.list->text;
3047                         break;
3048                 case NFROMFD:
3049                 case NTOFD:
3050                         if (redir->ndup.vname) {
3051                                 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
3052                                 fixredir(redir, fn.list->text, 1);
3053                         }
3054                         break;
3055                 }
3056         }
3057 }
3058
3059
3060
3061 /*
3062  * Evaluate a pipeline.  All the processes in the pipeline are children
3063  * of the process creating the pipeline.  (This differs from some versions
3064  * of the shell, which make the last process in a pipeline the parent
3065  * of all the rest.)
3066  */
3067
3068 static void
3069 evalpipe(union node *n, int flags)
3070 {
3071         struct job *jp;
3072         struct nodelist *lp;
3073         int pipelen;
3074         int prevfd;
3075         int pip[2];
3076
3077         TRACE(("evalpipe(0x%lx) called\n", (long)n));
3078         pipelen = 0;
3079         for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
3080                 pipelen++;
3081         flags |= EV_EXIT;
3082         INTOFF;
3083         jp = makejob(n, pipelen);
3084         prevfd = -1;
3085         for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
3086                 prehash(lp->n);
3087                 pip[1] = -1;
3088                 if (lp->next) {
3089                         if (pipe(pip) < 0) {
3090                                 close(prevfd);
3091                                 error("Pipe call failed");
3092                         }
3093                 }
3094                 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
3095                         INTON;
3096                         if (pip[1] >= 0) {
3097                                 close(pip[0]);
3098                         }
3099                         if (prevfd > 0) {
3100                                 dup2(prevfd, 0);
3101                                 close(prevfd);
3102                         }
3103                         if (pip[1] > 1) {
3104                                 dup2(pip[1], 1);
3105                                 close(pip[1]);
3106                         }
3107                         evaltreenr(lp->n, flags);
3108                         /* never returns */
3109                 }
3110                 if (prevfd >= 0)
3111                         close(prevfd);
3112                 prevfd = pip[0];
3113                 close(pip[1]);
3114         }
3115         if (n->npipe.backgnd == 0) {
3116                 exitstatus = waitforjob(jp);
3117                 TRACE(("evalpipe:  job done exit status %d\n", exitstatus));
3118         }
3119         INTON;
3120 }
3121
3122
3123
3124 /*
3125  * Execute a command inside back quotes.  If it's a builtin command, we
3126  * want to save its output in a block obtained from malloc.  Otherwise
3127  * we fork off a subprocess and get the output of the command via a pipe.
3128  * Should be called with interrupts off.
3129  */
3130
3131 static void
3132 evalbackcmd(union node *n, struct backcmd *result)
3133 {
3134         int saveherefd;
3135
3136         result->fd = -1;
3137         result->buf = NULL;
3138         result->nleft = 0;
3139         result->jp = NULL;
3140         if (n == NULL) {
3141                 goto out;
3142         }
3143
3144         saveherefd = herefd;
3145         herefd = -1;
3146
3147         {
3148                 int pip[2];
3149                 struct job *jp;
3150
3151                 if (pipe(pip) < 0)
3152                         error("Pipe call failed");
3153                 jp = makejob(n, 1);
3154                 if (forkshell(jp, n, FORK_NOJOB) == 0) {
3155                         FORCEINTON;
3156                         close(pip[0]);
3157                         if (pip[1] != 1) {
3158                                 close(1);
3159                                 copyfd(pip[1], 1);
3160                                 close(pip[1]);
3161                         }
3162                         eflag = 0;
3163                         evaltreenr(n, EV_EXIT);
3164                         /* NOTREACHED */
3165                 }
3166                 close(pip[1]);
3167                 result->fd = pip[0];
3168                 result->jp = jp;
3169         }
3170         herefd = saveherefd;
3171 out:
3172         TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
3173                 result->fd, result->buf, result->nleft, result->jp));
3174 }
3175
3176 #ifdef CONFIG_ASH_CMDCMD
3177 static inline char **
3178 parse_command_args(char **argv, const char **path)
3179 {
3180         char *cp, c;
3181
3182         for (;;) {
3183                 cp = *++argv;
3184                 if (!cp)
3185                         return 0;
3186                 if (*cp++ != '-')
3187                         break;
3188                 if (!(c = *cp++))
3189                         break;
3190                 if (c == '-' && !*cp) {
3191                         argv++;
3192                         break;
3193                 }
3194                 do {
3195                         switch (c) {
3196                         case 'p':
3197                                 *path = defpath;
3198                                 break;
3199                         default:
3200                                 /* run 'typecmd' for other options */
3201                                 return 0;
3202                         }
3203                 } while ((c = *cp++));
3204         }
3205         return argv;
3206 }
3207 #endif
3208
3209
3210
3211 /*
3212  * Execute a simple command.
3213  */
3214
3215 static void
3216 evalcommand(union node *cmd, int flags)
3217 {
3218         struct stackmark smark;
3219         union node *argp;
3220         struct arglist arglist;
3221         struct arglist varlist;
3222         char **argv;
3223         int argc;
3224         const struct strlist *sp;
3225         struct cmdentry cmdentry;
3226         struct job *jp;
3227         char *lastarg;
3228         const char *path;
3229         int spclbltin;
3230         int cmd_is_exec;
3231         int status;
3232         char **nargv;
3233
3234         /* First expand the arguments. */
3235         TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
3236         setstackmark(&smark);
3237         back_exitstatus = 0;
3238
3239         cmdentry.cmdtype = CMDBUILTIN;
3240         cmdentry.u.cmd = &bltin;
3241         varlist.lastp = &varlist.list;
3242         *varlist.lastp = NULL;
3243         arglist.lastp = &arglist.list;
3244         *arglist.lastp = NULL;
3245
3246         argc = 0;
3247         for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
3248                 struct strlist **spp;
3249
3250                 spp = arglist.lastp;
3251                 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
3252                 for (sp = *spp; sp; sp = sp->next)
3253                         argc++;
3254         }
3255
3256         argv = nargv = stalloc(sizeof (char *) * (argc + 1));
3257         for (sp = arglist.list ; sp ; sp = sp->next) {
3258                 TRACE(("evalcommand arg: %s\n", sp->text));
3259                 *nargv++ = sp->text;
3260         }
3261         *nargv = NULL;
3262
3263         lastarg = NULL;
3264         if (iflag && funcnest == 0 && argc > 0)
3265                 lastarg = nargv[-1];
3266
3267         preverrout_fd = 2;
3268         expredir(cmd->ncmd.redirect);
3269         status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH|REDIR_SAVEFD2);
3270
3271         path = vpath.text;
3272         for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
3273                 struct strlist **spp;
3274                 char *p;
3275
3276                 spp = varlist.lastp;
3277                 expandarg(argp, &varlist, EXP_VARTILDE);
3278
3279                 /*
3280                  * Modify the command lookup path, if a PATH= assignment
3281                  * is present
3282                  */
3283                 p = (*spp)->text;
3284                 if (varequal(p, path))
3285                         path = p;
3286         }
3287
3288         /* Print the command if xflag is set. */
3289         if (xflag) {
3290                 int n;
3291                 const char *p = " %s";
3292
3293                 p++;
3294                 dprintf(preverrout_fd, p, ps4val());
3295
3296                 sp = varlist.list;
3297                 for(n = 0; n < 2; n++) {
3298                         while (sp) {
3299                                 dprintf(preverrout_fd, p, sp->text);
3300                                 sp = sp->next;
3301                                 if(*p == '%') {
3302                                         p--;
3303                                 }
3304                         }
3305                         sp = arglist.list;
3306                 }
3307                 bb_full_write(preverrout_fd, "\n", 1);
3308         }
3309
3310         cmd_is_exec = 0;
3311         spclbltin = -1;
3312
3313         /* Now locate the command. */
3314         if (argc) {
3315                 const char *oldpath;
3316                 int cmd_flag = DO_ERR;
3317
3318                 path += 5;
3319                 oldpath = path;
3320                 for (;;) {
3321                         find_command(argv[0], &cmdentry, cmd_flag, path);
3322                         if (cmdentry.cmdtype == CMDUNKNOWN) {
3323                                 status = 127;
3324                                 flusherr();
3325                                 goto bail;
3326                         }
3327
3328                         /* implement bltin and command here */
3329                         if (cmdentry.cmdtype != CMDBUILTIN)
3330                                 break;
3331                         if (spclbltin < 0)
3332                                 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
3333                         if (cmdentry.u.cmd == EXECCMD)
3334                                 cmd_is_exec++;
3335 #ifdef CONFIG_ASH_CMDCMD
3336                         if (cmdentry.u.cmd == COMMANDCMD) {
3337
3338                                 path = oldpath;
3339                                 nargv = parse_command_args(argv, &path);
3340                                 if (!nargv)
3341                                         break;
3342                                 argc -= nargv - argv;
3343                                 argv = nargv;
3344                                 cmd_flag |= DO_NOFUNC;
3345                         } else
3346 #endif
3347                                 break;
3348                 }
3349         }
3350
3351         if (status) {
3352                 /* We have a redirection error. */
3353                 if (spclbltin > 0)
3354                         exraise(EXERROR);
3355 bail:
3356                 exitstatus = status;
3357                 goto out;
3358         }
3359
3360         /* Execute the command. */
3361         switch (cmdentry.cmdtype) {
3362         default:
3363                 /* Fork off a child process if necessary. */
3364                 if (!(flags & EV_EXIT) || trap[0]) {
3365                         INTOFF;
3366                         jp = makejob(cmd, 1);
3367                         if (forkshell(jp, cmd, FORK_FG) != 0) {
3368                                 exitstatus = waitforjob(jp);
3369                                 INTON;
3370                                 break;
3371                         }
3372                         FORCEINTON;
3373                 }
3374                 listsetvar(varlist.list, VEXPORT|VSTACK);
3375                 shellexec(argv, path, cmdentry.u.index);
3376                 /* NOTREACHED */
3377
3378         case CMDBUILTIN:
3379                 cmdenviron = varlist.list;
3380                 if (cmdenviron) {
3381                         struct strlist *list = cmdenviron;
3382                         int i = VNOSET;
3383                         if (spclbltin > 0 || argc == 0) {
3384                                 i = 0;
3385                                 if (cmd_is_exec && argc > 1)
3386                                         i = VEXPORT;
3387                         }
3388                         listsetvar(list, i);
3389                 }
3390                 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
3391                         int exit_status;
3392                         int i, j;
3393
3394                         i = exception;
3395                         if (i == EXEXIT)
3396                                 goto raise;
3397
3398                         exit_status = 2;
3399                         j = 0;
3400                         if (i == EXINT)
3401                                 j = SIGINT;
3402                         if (i == EXSIG)
3403                                 j = pendingsigs;
3404                         if (j)
3405                                 exit_status = j + 128;
3406                         exitstatus = exit_status;
3407
3408                         if (i == EXINT || spclbltin > 0) {
3409 raise:
3410                                 longjmp(handler->loc, 1);
3411                         }
3412                         FORCEINTON;
3413                 }
3414                 break;
3415
3416         case CMDFUNCTION:
3417                 listsetvar(varlist.list, 0);
3418                 if (evalfun(cmdentry.u.func, argc, argv, flags))
3419                         goto raise;
3420                 break;
3421         }
3422
3423 out:
3424         popredir(cmd_is_exec);
3425         if (lastarg)
3426                 /* dsl: I think this is intended to be used to support
3427                  * '_' in 'vi' command mode during line editing...
3428                  * However I implemented that within libedit itself.
3429                  */
3430                 setvar("_", lastarg, 0);
3431         popstackmark(&smark);
3432 }
3433
3434 static int
3435 evalbltin(const struct builtincmd *cmd, int argc, char **argv) {
3436         char *volatile savecmdname;
3437         struct jmploc *volatile savehandler;
3438         struct jmploc jmploc;
3439         int i;
3440
3441         savecmdname = commandname;
3442         if ((i = setjmp(jmploc.loc)))
3443                 goto cmddone;
3444         savehandler = handler;
3445         handler = &jmploc;
3446         commandname = argv[0];
3447         argptr = argv + 1;
3448         optptr = NULL;                  /* initialize nextopt */
3449         exitstatus = (*cmd->builtin)(argc, argv);
3450         flushall();
3451 cmddone:
3452         exitstatus |= ferror(stdout);
3453         commandname = savecmdname;
3454         exsig = 0;
3455         handler = savehandler;
3456
3457         return i;
3458 }
3459
3460 static int
3461 evalfun(struct funcnode *func, int argc, char **argv, int flags)
3462 {
3463         volatile struct shparam saveparam;
3464         struct localvar *volatile savelocalvars;
3465         struct jmploc *volatile savehandler;
3466         struct jmploc jmploc;
3467         int e;
3468
3469         saveparam = shellparam;
3470         savelocalvars = localvars;
3471         if ((e = setjmp(jmploc.loc))) {
3472                 goto funcdone;
3473         }
3474         INTOFF;
3475         savehandler = handler;
3476         handler = &jmploc;
3477         localvars = NULL;
3478         shellparam.malloc = 0;
3479         func->count++;
3480         INTON;
3481         shellparam.nparam = argc - 1;
3482         shellparam.p = argv + 1;
3483 #ifdef CONFIG_ASH_GETOPTS
3484         shellparam.optind = 1;
3485         shellparam.optoff = -1;
3486 #endif
3487         funcnest++;
3488         evaltree(&func->n, flags & EV_TESTED);
3489         funcnest--;
3490 funcdone:
3491         INTOFF;
3492         freefunc(func);
3493         poplocalvars();
3494         localvars = savelocalvars;
3495         freeparam(&shellparam);
3496         shellparam = saveparam;
3497         handler = savehandler;
3498         INTON;
3499         if (evalskip == SKIPFUNC) {
3500                 evalskip = 0;
3501                 skipcount = 0;
3502         }
3503         return e;
3504 }
3505
3506
3507 static inline int
3508 goodname(const char *p)
3509 {
3510         return !*endofname(p);
3511 }
3512
3513 /*
3514  * Search for a command.  This is called before we fork so that the
3515  * location of the command will be available in the parent as well as
3516  * the child.  The check for "goodname" is an overly conservative
3517  * check that the name will not be subject to expansion.
3518  */
3519
3520 static void
3521 prehash(union node *n)
3522 {
3523         struct cmdentry entry;
3524
3525         if (n->type == NCMD && n->ncmd.args)
3526                 if (goodname(n->ncmd.args->narg.text))
3527                         find_command(n->ncmd.args->narg.text, &entry, 0,
3528                                      pathval());
3529 }
3530
3531
3532
3533 /*
3534  * Builtin commands.  Builtin commands whose functions are closely
3535  * tied to evaluation are implemented here.
3536  */
3537
3538 /*
3539  * No command given.
3540  */
3541
3542 static int
3543 bltincmd(int argc, char **argv)
3544 {
3545         /*
3546          * Preserve exitstatus of a previous possible redirection
3547          * as POSIX mandates
3548          */
3549         return back_exitstatus;
3550 }
3551
3552
3553 /*
3554  * Handle break and continue commands.  Break, continue, and return are
3555  * all handled by setting the evalskip flag.  The evaluation routines
3556  * above all check this flag, and if it is set they start skipping
3557  * commands rather than executing them.  The variable skipcount is
3558  * the number of loops to break/continue, or the number of function
3559  * levels to return.  (The latter is always 1.)  It should probably
3560  * be an error to break out of more loops than exist, but it isn't
3561  * in the standard shell so we don't make it one here.
3562  */
3563
3564 static int
3565 breakcmd(int argc, char **argv)
3566 {
3567         int n = argc > 1 ? number(argv[1]) : 1;
3568
3569         if (n <= 0)
3570                 error(illnum, argv[1]);
3571         if (n > loopnest)
3572                 n = loopnest;
3573         if (n > 0) {
3574                 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
3575                 skipcount = n;
3576         }
3577         return 0;
3578 }
3579
3580
3581 /*
3582  * The return command.
3583  */
3584
3585 static int
3586 returncmd(int argc, char **argv)
3587 {
3588         int ret = argc > 1 ? number(argv[1]) : exitstatus;
3589
3590         if (funcnest) {
3591                 evalskip = SKIPFUNC;
3592                 skipcount = 1;
3593                 return ret;
3594         }
3595         else {
3596                 /* Do what ksh does; skip the rest of the file */
3597                 evalskip = SKIPFILE;
3598                 skipcount = 1;
3599                 return ret;
3600         }
3601 }
3602
3603
3604 static int
3605 falsecmd(int argc, char **argv)
3606 {
3607         return 1;
3608 }
3609
3610
3611 static int
3612 truecmd(int argc, char **argv)
3613 {
3614         return 0;
3615 }
3616
3617
3618 static int
3619 execcmd(int argc, char **argv)
3620 {
3621         if (argc > 1) {
3622                 iflag = 0;              /* exit on error */
3623                 mflag = 0;
3624                 optschanged();
3625                 shellexec(argv + 1, pathval(), 0);
3626         }
3627         return 0;
3628 }
3629
3630
3631 /*      $NetBSD: exec.c,v 1.35 2003/01/22 20:36:04 dsl Exp $    */
3632
3633 /*
3634  * When commands are first encountered, they are entered in a hash table.
3635  * This ensures that a full path search will not have to be done for them
3636  * on each invocation.
3637  *
3638  * We should investigate converting to a linear search, even though that
3639  * would make the command name "hash" a misnomer.
3640  */
3641
3642 #define CMDTABLESIZE 31         /* should be prime */
3643 #define ARB 1                   /* actual size determined at run time */
3644
3645
3646
3647 struct tblentry {
3648         struct tblentry *next;  /* next entry in hash chain */
3649         union param param;      /* definition of builtin function */
3650         short cmdtype;          /* index identifying command */
3651         char rehash;            /* if set, cd done since entry created */
3652         char cmdname[ARB];      /* name of command */
3653 };
3654
3655
3656 static struct tblentry *cmdtable[CMDTABLESIZE];
3657 static int builtinloc = -1;             /* index in path of %builtin, or -1 */
3658
3659
3660 static void tryexec(char *, char **, char **);
3661 static void clearcmdentry(int);
3662 static struct tblentry *cmdlookup(const char *, int);
3663 static void delete_cmd_entry(void);
3664
3665
3666 /*
3667  * Exec a program.  Never returns.  If you change this routine, you may
3668  * have to change the find_command routine as well.
3669  */
3670
3671 static void
3672 shellexec(char **argv, const char *path, int idx)
3673 {
3674         char *cmdname;
3675         int e;
3676         char **envp;
3677
3678         clearredir(1);
3679         envp = environment();
3680         if (strchr(argv[0], '/') != NULL
3681 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3682                 || find_applet_by_name(argv[0])
3683 #endif
3684                                                 ) {
3685                 tryexec(argv[0], argv, envp);
3686                 e = errno;
3687         } else {
3688                 e = ENOENT;
3689                 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3690                         if (--idx < 0 && pathopt == NULL) {
3691                                 tryexec(cmdname, argv, envp);
3692                                 if (errno != ENOENT && errno != ENOTDIR)
3693                                         e = errno;
3694                         }
3695                         stunalloc(cmdname);
3696                 }
3697         }
3698
3699         /* Map to POSIX errors */
3700         switch (e) {
3701         case EACCES:
3702                 exerrno = 126;
3703                 break;
3704         case ENOENT:
3705                 exerrno = 127;
3706                 break;
3707         default:
3708                 exerrno = 2;
3709                 break;
3710         }
3711         TRACE(("shellexec failed for %s, errno %d, suppressint %d\n",
3712                 argv[0], e, suppressint ));
3713         exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3714         /* NOTREACHED */
3715 }
3716
3717
3718 static void
3719 tryexec(char *cmd, char **argv, char **envp)
3720 {
3721         int repeated = 0;
3722 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3723         int flg_bb = 0;
3724         char *name = cmd;
3725
3726         if(strchr(name, '/') == NULL && find_applet_by_name(name) != NULL) {
3727                 flg_bb = 1;
3728         }
3729         if(flg_bb) {
3730                 char **ap;
3731                 char **new;
3732
3733                 *argv = name;
3734                 if(strcmp(name, "busybox")) {
3735                         for (ap = argv; *ap; ap++);
3736                         ap = new = xmalloc((ap - argv + 2) * sizeof(char *));
3737                         *ap++ = cmd = "/bin/busybox";
3738                         while ((*ap++ = *argv++));
3739                         argv = new;
3740                         repeated++;
3741                 } else {
3742                         cmd = "/bin/busybox";
3743                 }
3744         }
3745 #endif
3746
3747 repeat:
3748 #ifdef SYSV
3749         do {
3750                 execve(cmd, argv, envp);
3751         } while (errno == EINTR);
3752 #else
3753         execve(cmd, argv, envp);
3754 #endif
3755         if (repeated++) {
3756                 ckfree(argv);
3757         } else if (errno == ENOEXEC) {
3758                 char **ap;
3759                 char **new;
3760
3761                 for (ap = argv; *ap; ap++)
3762                         ;
3763                 ap = new = ckmalloc((ap - argv + 2) * sizeof(char *));
3764                 ap[1] = cmd;
3765                 *ap = cmd = (char *)DEFAULT_SHELL;
3766                 ap += 2;
3767                 argv++;
3768                 while ((*ap++ = *argv++))
3769                         ;
3770                 argv = new;
3771                 goto repeat;
3772         }
3773 }
3774
3775
3776
3777 /*
3778  * Do a path search.  The variable path (passed by reference) should be
3779  * set to the start of the path before the first call; padvance will update
3780  * this value as it proceeds.  Successive calls to padvance will return
3781  * the possible path expansions in sequence.  If an option (indicated by
3782  * a percent sign) appears in the path entry then the global variable
3783  * pathopt will be set to point to it; otherwise pathopt will be set to
3784  * NULL.
3785  */
3786
3787 static char *
3788 padvance(const char **path, const char *name)
3789 {
3790         const char *p;
3791         char *q;
3792         const char *start;
3793         size_t len;
3794
3795         if (*path == NULL)
3796                 return NULL;
3797         start = *path;
3798         for (p = start ; *p && *p != ':' && *p != '%' ; p++);
3799         len = p - start + strlen(name) + 2;     /* "2" is for '/' and '\0' */
3800         while (stackblocksize() < len)
3801                 growstackblock();
3802         q = stackblock();
3803         if (p != start) {
3804                 memcpy(q, start, p - start);
3805                 q += p - start;
3806                 *q++ = '/';
3807         }
3808         strcpy(q, name);
3809         pathopt = NULL;
3810         if (*p == '%') {
3811                 pathopt = ++p;
3812                 while (*p && *p != ':')  p++;
3813         }
3814         if (*p == ':')
3815                 *path = p + 1;
3816         else
3817                 *path = NULL;
3818         return stalloc(len);
3819 }
3820
3821
3822 /*** Command hashing code ***/
3823
3824 static void
3825 printentry(struct tblentry *cmdp)
3826 {
3827         int idx;
3828         const char *path;
3829         char *name;
3830
3831         idx = cmdp->param.index;
3832         path = pathval();
3833         do {
3834                 name = padvance(&path, cmdp->cmdname);
3835                 stunalloc(name);
3836         } while (--idx >= 0);
3837         out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
3838 }
3839
3840
3841 static int
3842 hashcmd(int argc, char **argv)
3843 {
3844         struct tblentry **pp;
3845         struct tblentry *cmdp;
3846         int c;
3847         struct cmdentry entry;
3848         char *name;
3849
3850         while ((c = nextopt("r")) != '\0') {
3851                 clearcmdentry(0);
3852                 return 0;
3853         }
3854         if (*argptr == NULL) {
3855                 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3856                         for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3857                                 if (cmdp->cmdtype == CMDNORMAL)
3858                                         printentry(cmdp);
3859                         }
3860                 }
3861                 return 0;
3862         }
3863         c = 0;
3864         while ((name = *argptr) != NULL) {
3865                 if ((cmdp = cmdlookup(name, 0)) != NULL
3866                  && (cmdp->cmdtype == CMDNORMAL
3867                      || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
3868                         delete_cmd_entry();
3869                 find_command(name, &entry, DO_ERR, pathval());
3870                 if (entry.cmdtype == CMDUNKNOWN)
3871                         c = 1;
3872                 argptr++;
3873         }
3874         return c;
3875 }
3876
3877
3878 /*
3879  * Resolve a command name.  If you change this routine, you may have to
3880  * change the shellexec routine as well.
3881  */
3882
3883 static void
3884 find_command(char *name, struct cmdentry *entry, int act, const char *path)
3885 {
3886         struct tblentry *cmdp;
3887         int idx;
3888         int prev;
3889         char *fullname;
3890         struct stat statb;
3891         int e;
3892         int updatetbl;
3893         struct builtincmd *bcmd;
3894
3895         /* If name contains a slash, don't use PATH or hash table */
3896         if (strchr(name, '/') != NULL) {
3897                 entry->u.index = -1;
3898                 if (act & DO_ABS) {
3899                         while (stat(name, &statb) < 0) {
3900 #ifdef SYSV
3901                                 if (errno == EINTR)
3902                                         continue;
3903 #endif
3904                                 entry->cmdtype = CMDUNKNOWN;
3905                                 return;
3906                         }
3907                 }
3908                 entry->cmdtype = CMDNORMAL;
3909                 return;
3910         }
3911
3912 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3913         if (find_applet_by_name(name)) {
3914                 entry->cmdtype = CMDNORMAL;
3915                 entry->u.index = -1;
3916                 return;
3917         }
3918 #endif
3919
3920         updatetbl = (path == pathval());
3921         if (!updatetbl) {
3922                 act |= DO_ALTPATH;
3923                 if (strstr(path, "%builtin") != NULL)
3924                         act |= DO_ALTBLTIN;
3925         }
3926
3927         /* If name is in the table, check answer will be ok */
3928         if ((cmdp = cmdlookup(name, 0)) != NULL) {
3929                 int bit;
3930
3931                 switch (cmdp->cmdtype) {
3932                 default:
3933 #if DEBUG
3934                         abort();
3935 #endif
3936                 case CMDNORMAL:
3937                         bit = DO_ALTPATH;
3938                         break;
3939                 case CMDFUNCTION:
3940                         bit = DO_NOFUNC;
3941                         break;
3942                 case CMDBUILTIN:
3943                         bit = DO_ALTBLTIN;
3944                         break;
3945                 }
3946                 if (act & bit) {
3947                         updatetbl = 0;
3948                         cmdp = NULL;
3949                 } else if (cmdp->rehash == 0)
3950                         /* if not invalidated by cd, we're done */
3951                         goto success;
3952         }
3953
3954         /* If %builtin not in path, check for builtin next */
3955         bcmd = find_builtin(name);
3956         if (bcmd && (IS_BUILTIN_REGULAR(bcmd) || (
3957                 act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0
3958         )))
3959                 goto builtin_success;
3960
3961         /* We have to search path. */
3962         prev = -1;              /* where to start */
3963         if (cmdp && cmdp->rehash) {     /* doing a rehash */
3964                 if (cmdp->cmdtype == CMDBUILTIN)
3965                         prev = builtinloc;
3966                 else
3967                         prev = cmdp->param.index;
3968         }
3969
3970         e = ENOENT;
3971         idx = -1;
3972 loop:
3973         while ((fullname = padvance(&path, name)) != NULL) {
3974                 stunalloc(fullname);
3975                 idx++;
3976                 if (pathopt) {
3977                         if (prefix(pathopt, "builtin")) {
3978                                 if (bcmd)
3979                                         goto builtin_success;
3980                                 continue;
3981                         } else if (!(act & DO_NOFUNC) &&
3982                                    prefix(pathopt, "func")) {
3983                                 /* handled below */
3984                         } else {
3985                                 /* ignore unimplemented options */
3986                                 continue;
3987                         }
3988                 }
3989                 /* if rehash, don't redo absolute path names */
3990                 if (fullname[0] == '/' && idx <= prev) {
3991                         if (idx < prev)
3992                                 continue;
3993                         TRACE(("searchexec \"%s\": no change\n", name));
3994                         goto success;
3995                 }
3996                 while (stat(fullname, &statb) < 0) {
3997 #ifdef SYSV
3998                         if (errno == EINTR)
3999                                 continue;
4000 #endif
4001                         if (errno != ENOENT && errno != ENOTDIR)
4002                                 e = errno;
4003                         goto loop;
4004                 }
4005                 e = EACCES;     /* if we fail, this will be the error */
4006                 if (!S_ISREG(statb.st_mode))
4007                         continue;
4008                 if (pathopt) {          /* this is a %func directory */
4009                         stalloc(strlen(fullname) + 1);
4010                         readcmdfile(fullname);
4011                         if ((cmdp = cmdlookup(name, 0)) == NULL ||
4012                             cmdp->cmdtype != CMDFUNCTION)
4013                                 error("%s not defined in %s", name, fullname);
4014                         stunalloc(fullname);
4015                         goto success;
4016                 }
4017                 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
4018                 if (!updatetbl) {
4019                         entry->cmdtype = CMDNORMAL;
4020                         entry->u.index = idx;
4021                         return;
4022                 }
4023                 INTOFF;
4024                 cmdp = cmdlookup(name, 1);
4025                 cmdp->cmdtype = CMDNORMAL;
4026                 cmdp->param.index = idx;
4027                 INTON;
4028                 goto success;
4029         }
4030
4031         /* We failed.  If there was an entry for this command, delete it */
4032         if (cmdp && updatetbl)
4033                 delete_cmd_entry();
4034         if (act & DO_ERR)
4035                 sh_warnx("%s: %s", name, errmsg(e, E_EXEC));
4036         entry->cmdtype = CMDUNKNOWN;
4037         return;
4038
4039 builtin_success:
4040         if (!updatetbl) {
4041                 entry->cmdtype = CMDBUILTIN;
4042                 entry->u.cmd = bcmd;
4043                 return;
4044         }
4045         INTOFF;
4046         cmdp = cmdlookup(name, 1);
4047         cmdp->cmdtype = CMDBUILTIN;
4048         cmdp->param.cmd = bcmd;
4049         INTON;
4050 success:
4051         cmdp->rehash = 0;
4052         entry->cmdtype = cmdp->cmdtype;
4053         entry->u = cmdp->param;
4054 }
4055
4056
4057 /*
4058  * Wrapper around strcmp for qsort/bsearch/...
4059  */
4060 static int pstrcmp(const void *a, const void *b)
4061 {
4062         return strcmp((const char *) a, (*(const char *const *) b) + 1);
4063 }
4064
4065 /*
4066  * Search the table of builtin commands.
4067  */
4068
4069 static struct builtincmd *
4070 find_builtin(const char *name)
4071 {
4072         struct builtincmd *bp;
4073
4074         bp = bsearch(
4075                 name, builtincmd, NUMBUILTINS, sizeof(struct builtincmd),
4076                 pstrcmp
4077         );
4078         return bp;
4079 }
4080
4081
4082
4083 /*
4084  * Called when a cd is done.  Marks all commands so the next time they
4085  * are executed they will be rehashed.
4086  */
4087
4088 static void
4089 hashcd(void)
4090 {
4091         struct tblentry **pp;
4092         struct tblentry *cmdp;
4093
4094         for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4095                 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4096                         if (cmdp->cmdtype == CMDNORMAL || (
4097                                 cmdp->cmdtype == CMDBUILTIN &&
4098                                 !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) &&
4099                                 builtinloc > 0
4100                         ))
4101                                 cmdp->rehash = 1;
4102                 }
4103         }
4104 }
4105
4106
4107
4108 /*
4109  * Fix command hash table when PATH changed.
4110  * Called before PATH is changed.  The argument is the new value of PATH;
4111  * pathval() still returns the old value at this point.
4112  * Called with interrupts off.
4113  */
4114
4115 static void
4116 changepath(const char *newval)
4117 {
4118         const char *old, *new;
4119         int idx;
4120         int firstchange;
4121         int idx_bltin;
4122
4123         old = pathval();
4124         new = newval;
4125         firstchange = 9999;     /* assume no change */
4126         idx = 0;
4127         idx_bltin = -1;
4128         for (;;) {
4129                 if (*old != *new) {
4130                         firstchange = idx;
4131                         if ((*old == '\0' && *new == ':')
4132                          || (*old == ':' && *new == '\0'))
4133                                 firstchange++;
4134                         old = new;      /* ignore subsequent differences */
4135                 }
4136                 if (*new == '\0')
4137                         break;
4138                 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
4139                         idx_bltin = idx;
4140                 if (*new == ':') {
4141                         idx++;
4142                 }
4143                 new++, old++;
4144         }
4145         if (builtinloc < 0 && idx_bltin >= 0)
4146                 builtinloc = idx_bltin;             /* zap builtins */
4147         if (builtinloc >= 0 && idx_bltin < 0)
4148                 firstchange = 0;
4149         clearcmdentry(firstchange);
4150         builtinloc = idx_bltin;
4151 }
4152
4153
4154 /*
4155  * Clear out command entries.  The argument specifies the first entry in
4156  * PATH which has changed.
4157  */
4158
4159 static void
4160 clearcmdentry(int firstchange)
4161 {
4162         struct tblentry **tblp;
4163         struct tblentry **pp;
4164         struct tblentry *cmdp;
4165
4166         INTOFF;
4167         for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4168                 pp = tblp;
4169                 while ((cmdp = *pp) != NULL) {
4170                         if ((cmdp->cmdtype == CMDNORMAL &&
4171                              cmdp->param.index >= firstchange)
4172                          || (cmdp->cmdtype == CMDBUILTIN &&
4173                              builtinloc >= firstchange)) {
4174                                 *pp = cmdp->next;
4175                                 ckfree(cmdp);
4176                         } else {
4177                                 pp = &cmdp->next;
4178                         }
4179                 }
4180         }
4181         INTON;
4182 }
4183
4184
4185
4186 /*
4187  * Locate a command in the command hash table.  If "add" is nonzero,
4188  * add the command to the table if it is not already present.  The
4189  * variable "lastcmdentry" is set to point to the address of the link
4190  * pointing to the entry, so that delete_cmd_entry can delete the
4191  * entry.
4192  *
4193  * Interrupts must be off if called with add != 0.
4194  */
4195
4196 static struct tblentry **lastcmdentry;
4197
4198
4199 static struct tblentry *
4200 cmdlookup(const char *name, int add)
4201 {
4202         unsigned int hashval;
4203         const char *p;
4204         struct tblentry *cmdp;
4205         struct tblentry **pp;
4206
4207         p = name;
4208         hashval = (unsigned char)*p << 4;
4209         while (*p)
4210                 hashval += (unsigned char)*p++;
4211         hashval &= 0x7FFF;
4212         pp = &cmdtable[hashval % CMDTABLESIZE];
4213         for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4214                 if (equal(cmdp->cmdname, name))
4215                         break;
4216                 pp = &cmdp->next;
4217         }
4218         if (add && cmdp == NULL) {
4219                 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4220                                         + strlen(name) + 1);
4221                 cmdp->next = NULL;
4222                 cmdp->cmdtype = CMDUNKNOWN;
4223                 strcpy(cmdp->cmdname, name);
4224         }
4225         lastcmdentry = pp;
4226         return cmdp;
4227 }
4228
4229 /*
4230  * Delete the command entry returned on the last lookup.
4231  */
4232
4233 static void
4234 delete_cmd_entry(void)
4235 {
4236         struct tblentry *cmdp;
4237
4238         INTOFF;
4239         cmdp = *lastcmdentry;
4240         *lastcmdentry = cmdp->next;
4241         if (cmdp->cmdtype == CMDFUNCTION)
4242                 freefunc(cmdp->param.func);
4243         ckfree(cmdp);
4244         INTON;
4245 }
4246
4247
4248 /*
4249  * Add a new command entry, replacing any existing command entry for
4250  * the same name - except special builtins.
4251  */
4252
4253 static inline void
4254 addcmdentry(char *name, struct cmdentry *entry)
4255 {
4256         struct tblentry *cmdp;
4257
4258         cmdp = cmdlookup(name, 1);
4259         if (cmdp->cmdtype == CMDFUNCTION) {
4260                 freefunc(cmdp->param.func);
4261         }
4262         cmdp->cmdtype = entry->cmdtype;
4263         cmdp->param = entry->u;
4264         cmdp->rehash = 0;
4265 }
4266
4267 /*
4268  * Make a copy of a parse tree.
4269  */
4270
4271 static inline struct funcnode *
4272 copyfunc(union node *n)
4273 {
4274         struct funcnode *f;
4275         size_t blocksize;
4276
4277         funcblocksize = offsetof(struct funcnode, n);
4278         funcstringsize = 0;
4279         calcsize(n);
4280         blocksize = funcblocksize;
4281         f = ckmalloc(blocksize + funcstringsize);
4282         funcblock = (char *) f + offsetof(struct funcnode, n);
4283         funcstring = (char *) f + blocksize;
4284         copynode(n);
4285         f->count = 0;
4286         return f;
4287 }
4288
4289 /*
4290  * Define a shell function.
4291  */
4292
4293 static void
4294 defun(char *name, union node *func)
4295 {
4296         struct cmdentry entry;
4297
4298         INTOFF;
4299         entry.cmdtype = CMDFUNCTION;
4300         entry.u.func = copyfunc(func);
4301         addcmdentry(name, &entry);
4302         INTON;
4303 }
4304
4305
4306 /*
4307  * Delete a function if it exists.
4308  */
4309
4310 static void
4311 unsetfunc(const char *name)
4312 {
4313         struct tblentry *cmdp;
4314
4315         if ((cmdp = cmdlookup(name, 0)) != NULL &&
4316             cmdp->cmdtype == CMDFUNCTION)
4317                 delete_cmd_entry();
4318 }
4319
4320 /*
4321  * Locate and print what a word is...
4322  */
4323
4324
4325 #ifdef CONFIG_ASH_CMDCMD
4326 static int
4327 describe_command(char *command, int describe_command_verbose)
4328 #else
4329 #define describe_command_verbose 1
4330 static int
4331 describe_command(char *command)
4332 #endif
4333 {
4334         struct cmdentry entry;
4335         struct tblentry *cmdp;
4336 #ifdef CONFIG_ASH_ALIAS
4337         const struct alias *ap;
4338 #endif
4339         const char *path = pathval();
4340
4341         if (describe_command_verbose) {
4342                 out1str(command);
4343         }
4344
4345         /* First look at the keywords */
4346         if (findkwd(command)) {
4347                 out1str(describe_command_verbose ? " is a shell keyword" : command);
4348                 goto out;
4349         }
4350
4351 #ifdef CONFIG_ASH_ALIAS
4352         /* Then look at the aliases */
4353         if ((ap = lookupalias(command, 0)) != NULL) {
4354                 if (describe_command_verbose) {
4355                         out1fmt(" is an alias for %s", ap->val);
4356                 } else {
4357                         out1str("alias ");
4358                         printalias(ap);
4359                         return 0;
4360                 }
4361                 goto out;
4362         }
4363 #endif
4364         /* Then check if it is a tracked alias */
4365         if ((cmdp = cmdlookup(command, 0)) != NULL) {
4366                 entry.cmdtype = cmdp->cmdtype;
4367                 entry.u = cmdp->param;
4368         } else {
4369                 /* Finally use brute force */
4370                 find_command(command, &entry, DO_ABS, path);
4371         }
4372
4373         switch (entry.cmdtype) {
4374         case CMDNORMAL: {
4375                 int j = entry.u.index;
4376                 char *p;
4377                 if (j == -1) {
4378                         p = command;
4379                 } else {
4380                         do {
4381                                 p = padvance(&path, command);
4382                                 stunalloc(p);
4383                         } while (--j >= 0);
4384                 }
4385                 if (describe_command_verbose) {
4386                         out1fmt(" is%s %s",
4387                                 (cmdp ? " a tracked alias for" : nullstr), p
4388                         );
4389                 } else {
4390                         out1str(p);
4391                 }
4392                 break;
4393         }
4394
4395         case CMDFUNCTION:
4396                 if (describe_command_verbose) {
4397                         out1str(" is a shell function");
4398                 } else {
4399                         out1str(command);
4400                 }
4401                 break;
4402
4403         case CMDBUILTIN:
4404                 if (describe_command_verbose) {
4405                         out1fmt(" is a %sshell builtin",
4406                                 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
4407                                         "special " : nullstr
4408                         );
4409                 } else {
4410                         out1str(command);
4411                 }
4412                 break;
4413
4414         default:
4415                 if (describe_command_verbose) {
4416                         out1str(": not found\n");
4417                 }
4418                 return 127;
4419         }
4420
4421 out:
4422         outstr("\n", stdout);
4423         return 0;
4424 }
4425
4426 static int
4427 typecmd(int argc, char **argv)
4428 {
4429         int i;
4430         int err = 0;
4431
4432         for (i = 1; i < argc; i++) {
4433 #ifdef CONFIG_ASH_CMDCMD
4434                 err |= describe_command(argv[i], 1);
4435 #else
4436                 err |= describe_command(argv[i]);
4437 #endif
4438         }
4439         return err;
4440 }
4441
4442 #ifdef CONFIG_ASH_CMDCMD
4443 static int
4444 commandcmd(int argc, char **argv)
4445 {
4446         int c;
4447         int default_path = 0;
4448         int verify_only = 0;
4449         int verbose_verify_only = 0;
4450
4451         while ((c = nextopt("pvV")) != '\0')
4452                 switch (c) {
4453                 default:
4454 #ifdef DEBUG
4455                         fprintf(stderr,
4456 "command: nextopt returned character code 0%o\n", c);
4457                         return EX_SOFTWARE;
4458 #endif
4459                 case 'p':
4460                         default_path = 1;
4461                         break;
4462                 case 'v':
4463                         verify_only = 1;
4464                         break;
4465                 case 'V':
4466                         verbose_verify_only = 1;
4467                         break;
4468                 }
4469
4470         if (default_path + verify_only + verbose_verify_only > 1 ||
4471             !*argptr) {
4472                         fprintf(stderr,
4473                                 "command [-p] command [arg ...]\n"
4474                                 "command {-v|-V} command\n");
4475                         return EX_USAGE;
4476         }
4477
4478         if (verify_only || verbose_verify_only) {
4479                 return describe_command(*argptr, verbose_verify_only);
4480         }
4481
4482         return 0;
4483 }
4484 #endif
4485
4486 /*      $NetBSD: expand.c,v 1.56 2002/11/24 22:35:39 christos Exp $     */
4487
4488 /*
4489  * Routines to expand arguments to commands.  We have to deal with
4490  * backquotes, shell variables, and file metacharacters.
4491  */
4492
4493 /*
4494  * _rmescape() flags
4495  */
4496 #define RMESCAPE_ALLOC  0x1     /* Allocate a new string */
4497 #define RMESCAPE_GLOB   0x2     /* Add backslashes for glob */
4498 #define RMESCAPE_QUOTED 0x4     /* Remove CTLESC unless in quotes */
4499 #define RMESCAPE_GROW   0x8     /* Grow strings instead of stalloc */
4500 #define RMESCAPE_HEAP   0x10    /* Malloc strings instead of stalloc */
4501
4502 /*
4503  * Structure specifying which parts of the string should be searched
4504  * for IFS characters.
4505  */
4506
4507 struct ifsregion {
4508         struct ifsregion *next; /* next region in list */
4509         int begoff;             /* offset of start of region */
4510         int endoff;             /* offset of end of region */
4511         int nulonly;            /* search for nul bytes only */
4512 };
4513
4514 /* output of current string */
4515 static char *expdest;
4516 /* list of back quote expressions */
4517 static struct nodelist *argbackq;
4518 /* first struct in list of ifs regions */
4519 static struct ifsregion ifsfirst;
4520 /* last struct in list */
4521 static struct ifsregion *ifslastp;
4522 /* holds expanded arg list */
4523 static struct arglist exparg;
4524
4525 static void argstr(char *, int);
4526 static char *exptilde(char *, char *, int);
4527 static void expbackq(union node *, int, int);
4528 static const char *subevalvar(char *, char *, int, int, int, int, int);
4529 static char *evalvar(char *, int);
4530 static void strtodest(const char *, int, int);
4531 static void memtodest(const char *p, size_t len, int syntax, int quotes);
4532 static ssize_t varvalue(char *, int, int);
4533 static void recordregion(int, int, int);
4534 static void removerecordregions(int);
4535 static void ifsbreakup(char *, struct arglist *);
4536 static void ifsfree(void);
4537 static void expandmeta(struct strlist *, int);
4538 static int patmatch(char *, const char *);
4539
4540 static int cvtnum(arith_t);
4541 static size_t esclen(const char *, const char *);
4542 static char *scanleft(char *, char *, char *, char *, int, int);
4543 static char *scanright(char *, char *, char *, char *, int, int);
4544 static void varunset(const char *, const char *, const char *, int)
4545         __attribute__((__noreturn__));
4546
4547
4548 #define pmatch(a, b) !fnmatch((a), (b), 0)
4549 /*
4550  * Prepare a pattern for a expmeta (internal glob(3)) call.
4551  *
4552  * Returns an stalloced string.
4553  */
4554
4555 static inline char *
4556 preglob(const char *pattern, int quoted, int flag) {
4557         flag |= RMESCAPE_GLOB;
4558         if (quoted) {
4559                 flag |= RMESCAPE_QUOTED;
4560         }
4561         return _rmescapes((char *)pattern, flag);
4562 }
4563
4564
4565 static size_t
4566 esclen(const char *start, const char *p) {
4567         size_t esc = 0;
4568
4569         while (p > start && *--p == CTLESC) {
4570                 esc++;
4571         }
4572         return esc;
4573 }
4574
4575
4576 /*
4577  * Expand shell variables and backquotes inside a here document.
4578  */
4579
4580 static inline void
4581 expandhere(union node *arg, int fd)
4582 {
4583         herefd = fd;
4584         expandarg(arg, (struct arglist *)NULL, 0);
4585         bb_full_write(fd, stackblock(), expdest - (char *)stackblock());
4586 }
4587
4588
4589 /*
4590  * Perform variable substitution and command substitution on an argument,
4591  * placing the resulting list of arguments in arglist.  If EXP_FULL is true,
4592  * perform splitting and file name expansion.  When arglist is NULL, perform
4593  * here document expansion.
4594  */
4595
4596 void
4597 expandarg(union node *arg, struct arglist *arglist, int flag)
4598 {
4599         struct strlist *sp;
4600         char *p;
4601
4602         argbackq = arg->narg.backquote;
4603         STARTSTACKSTR(expdest);
4604         ifsfirst.next = NULL;
4605         ifslastp = NULL;
4606         argstr(arg->narg.text, flag);
4607         if (arglist == NULL) {
4608                 return;                 /* here document expanded */
4609         }
4610         STPUTC('\0', expdest);
4611         p = grabstackstr(expdest);
4612         exparg.lastp = &exparg.list;
4613         /*
4614          * TODO - EXP_REDIR
4615          */
4616         if (flag & EXP_FULL) {
4617                 ifsbreakup(p, &exparg);
4618                 *exparg.lastp = NULL;
4619                 exparg.lastp = &exparg.list;
4620                 expandmeta(exparg.list, flag);
4621         } else {
4622                 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
4623                         rmescapes(p);
4624                 sp = (struct strlist *)stalloc(sizeof (struct strlist));
4625                 sp->text = p;
4626                 *exparg.lastp = sp;
4627                 exparg.lastp = &sp->next;
4628         }
4629         if (ifsfirst.next)
4630                 ifsfree();
4631         *exparg.lastp = NULL;
4632         if (exparg.list) {
4633                 *arglist->lastp = exparg.list;
4634                 arglist->lastp = exparg.lastp;
4635         }
4636 }
4637
4638
4639 /*
4640  * Perform variable and command substitution.  If EXP_FULL is set, output CTLESC
4641  * characters to allow for further processing.  Otherwise treat
4642  * $@ like $* since no splitting will be performed.
4643  */
4644
4645 static void
4646 argstr(char *p, int flag)
4647 {
4648         static const char spclchars[] = {
4649                 '=',
4650                 ':',
4651                 CTLQUOTEMARK,
4652                 CTLENDVAR,
4653                 CTLESC,
4654                 CTLVAR,
4655                 CTLBACKQ,
4656                 CTLBACKQ | CTLQUOTE,
4657 #ifdef CONFIG_ASH_MATH_SUPPORT
4658                 CTLENDARI,
4659 #endif
4660                 0
4661         };
4662         const char *reject = spclchars;
4663         int c;
4664         int quotes = flag & (EXP_FULL | EXP_CASE);      /* do CTLESC */
4665         int breakall = flag & EXP_WORD;
4666         int inquotes;
4667         size_t length;
4668         int startloc;
4669
4670         if (!(flag & EXP_VARTILDE)) {
4671                 reject += 2;
4672         } else if (flag & EXP_VARTILDE2) {
4673                 reject++;
4674         }
4675         inquotes = 0;
4676         length = 0;
4677         if (flag & EXP_TILDE) {
4678                 char *q;
4679
4680                 flag &= ~EXP_TILDE;
4681 tilde:
4682                 q = p;
4683                 if (*q == CTLESC && (flag & EXP_QWORD))
4684                         q++;
4685                 if (*q == '~')
4686                         p = exptilde(p, q, flag);
4687         }
4688 start:
4689         startloc = expdest - (char *)stackblock();
4690         for (;;) {
4691                 length += strcspn(p + length, reject);
4692                 c = p[length];
4693                 if (c && (!(c & 0x80)
4694 #ifdef CONFIG_ASH_MATH_SUPPORT
4695                                         || c == CTLENDARI
4696 #endif
4697                    )) {
4698                         /* c == '=' || c == ':' || c == CTLENDARI */
4699                         length++;
4700                 }
4701                 if (length > 0) {
4702                         int newloc;
4703                         expdest = stnputs(p, length, expdest);
4704                         newloc = expdest - (char *)stackblock();
4705                         if (breakall && !inquotes && newloc > startloc) {
4706                                 recordregion(startloc, newloc, 0);
4707                         }
4708                         startloc = newloc;
4709                 }
4710                 p += length + 1;
4711                 length = 0;
4712
4713                 switch (c) {
4714                 case '\0':
4715                         goto breakloop;
4716                 case '=':
4717                         if (flag & EXP_VARTILDE2) {
4718                                 p--;
4719                                 continue;
4720                         }
4721                         flag |= EXP_VARTILDE2;
4722                         reject++;
4723                         /* fall through */
4724                 case ':':
4725                         /*
4726                          * sort of a hack - expand tildes in variable
4727                          * assignments (after the first '=' and after ':'s).
4728                          */
4729                         if (*--p == '~') {
4730                                 goto tilde;
4731                         }
4732                         continue;
4733                 }
4734
4735                 switch (c) {
4736                 case CTLENDVAR: /* ??? */
4737                         goto breakloop;
4738                 case CTLQUOTEMARK:
4739                         /* "$@" syntax adherence hack */
4740                         if (
4741                                 !inquotes &&
4742                                 !memcmp(p, dolatstr, DOLATSTRLEN) &&
4743                                 (p[4] == CTLQUOTEMARK || (
4744                                         p[4] == CTLENDVAR &&
4745                                         p[5] == CTLQUOTEMARK
4746                                 ))
4747                         ) {
4748                                 p = evalvar(p + 1, flag) + 1;
4749                                 goto start;
4750                         }
4751                         inquotes = !inquotes;
4752 addquote:
4753                         if (quotes) {
4754                                 p--;
4755                                 length++;
4756                                 startloc++;
4757                         }
4758                         break;
4759                 case CTLESC:
4760                         startloc++;
4761                         length++;
4762                         goto addquote;
4763                 case CTLVAR:
4764                         p = evalvar(p, flag);
4765                         goto start;
4766                 case CTLBACKQ:
4767                         c = 0;
4768                 case CTLBACKQ|CTLQUOTE:
4769                         expbackq(argbackq->n, c, quotes);
4770                         argbackq = argbackq->next;
4771                         goto start;
4772 #ifdef CONFIG_ASH_MATH_SUPPORT
4773                 case CTLENDARI:
4774                         p--;
4775                         expari(quotes);
4776                         goto start;
4777 #endif
4778                 }
4779         }
4780 breakloop:
4781         ;
4782 }
4783
4784 static char *
4785 exptilde(char *startp, char *p, int flag)
4786 {
4787         char c;
4788         char *name;
4789         struct passwd *pw;
4790         const char *home;
4791         int quotes = flag & (EXP_FULL | EXP_CASE);
4792         int startloc;
4793
4794         name = p + 1;
4795
4796         while ((c = *++p) != '\0') {
4797                 switch(c) {
4798                 case CTLESC:
4799                         return (startp);
4800                 case CTLQUOTEMARK:
4801                         return (startp);
4802                 case ':':
4803                         if (flag & EXP_VARTILDE)
4804                                 goto done;
4805                         break;
4806                 case '/':
4807                 case CTLENDVAR:
4808                         goto done;
4809                 }
4810         }
4811 done:
4812         *p = '\0';
4813         if (*name == '\0') {
4814                 if ((home = lookupvar(homestr)) == NULL)
4815                         goto lose;
4816         } else {
4817                 if ((pw = getpwnam(name)) == NULL)
4818                         goto lose;
4819                 home = pw->pw_dir;
4820         }
4821         if (*home == '\0')
4822                 goto lose;
4823         *p = c;
4824         startloc = expdest - (char *)stackblock();
4825         strtodest(home, SQSYNTAX, quotes);
4826         recordregion(startloc, expdest - (char *)stackblock(), 0);
4827         return (p);
4828 lose:
4829         *p = c;
4830         return (startp);
4831 }
4832
4833
4834 static void
4835 removerecordregions(int endoff)
4836 {
4837         if (ifslastp == NULL)
4838                 return;
4839
4840         if (ifsfirst.endoff > endoff) {
4841                 while (ifsfirst.next != NULL) {
4842                         struct ifsregion *ifsp;
4843                         INTOFF;
4844                         ifsp = ifsfirst.next->next;
4845                         ckfree(ifsfirst.next);
4846                         ifsfirst.next = ifsp;
4847                         INTON;
4848                 }
4849                 if (ifsfirst.begoff > endoff)
4850                         ifslastp = NULL;
4851                 else {
4852                         ifslastp = &ifsfirst;
4853                         ifsfirst.endoff = endoff;
4854                 }
4855                 return;
4856         }
4857
4858         ifslastp = &ifsfirst;
4859         while (ifslastp->next && ifslastp->next->begoff < endoff)
4860                 ifslastp=ifslastp->next;
4861         while (ifslastp->next != NULL) {
4862                 struct ifsregion *ifsp;
4863                 INTOFF;
4864                 ifsp = ifslastp->next->next;
4865                 ckfree(ifslastp->next);
4866                 ifslastp->next = ifsp;
4867                 INTON;
4868         }
4869         if (ifslastp->endoff > endoff)
4870                 ifslastp->endoff = endoff;
4871 }
4872
4873
4874 #ifdef CONFIG_ASH_MATH_SUPPORT
4875 /*
4876  * Expand arithmetic expression.  Backup to start of expression,
4877  * evaluate, place result in (backed up) result, adjust string position.
4878  */
4879 void
4880 expari(int quotes)
4881 {
4882         char *p, *start;
4883         int begoff;
4884         int flag;
4885         int len;
4886
4887         /*      ifsfree(); */
4888
4889         /*
4890          * This routine is slightly over-complicated for
4891          * efficiency.  Next we scan backwards looking for the
4892          * start of arithmetic.
4893          */
4894         start = stackblock();
4895         p = expdest - 1;
4896         *p = '\0';
4897         p--;
4898         do {
4899                 int esc;
4900
4901                 while (*p != CTLARI) {
4902                         p--;
4903 #ifdef DEBUG
4904                         if (p < start) {
4905                                 error("missing CTLARI (shouldn't happen)");
4906                         }
4907 #endif
4908                 }
4909
4910                 esc = esclen(start, p);
4911                 if (!(esc % 2)) {
4912                         break;
4913                 }
4914
4915                 p -= esc + 1;
4916         } while (1);
4917
4918         begoff = p - start;
4919
4920         removerecordregions(begoff);
4921
4922         flag = p[1];
4923
4924         expdest = p;
4925
4926         if (quotes)
4927                 rmescapes(p + 2);
4928
4929         len = cvtnum(dash_arith(p + 2));
4930
4931         if (flag != '"')
4932                 recordregion(begoff, begoff + len, 0);
4933 }
4934 #endif
4935
4936 /*
4937  * Expand stuff in backwards quotes.
4938  */
4939
4940 static void
4941 expbackq(union node *cmd, int quoted, int quotes)
4942 {
4943         struct backcmd in;
4944         int i;
4945         char buf[128];
4946         char *p;
4947         char *dest;
4948         int startloc;
4949         int syntax = quoted? DQSYNTAX : BASESYNTAX;
4950         struct stackmark smark;
4951
4952         INTOFF;
4953         setstackmark(&smark);
4954         dest = expdest;
4955         startloc = dest - (char *)stackblock();
4956         grabstackstr(dest);
4957         evalbackcmd(cmd, (struct backcmd *) &in);
4958         popstackmark(&smark);
4959
4960         p = in.buf;
4961         i = in.nleft;
4962         if (i == 0)
4963                 goto read;
4964         for (;;) {
4965                 memtodest(p, i, syntax, quotes);
4966 read:
4967                 if (in.fd < 0)
4968                         break;
4969                 i = safe_read(in.fd, buf, sizeof buf);
4970                 TRACE(("expbackq: read returns %d\n", i));
4971                 if (i <= 0)
4972                         break;
4973                 p = buf;
4974         }
4975
4976         if (in.buf)
4977                 ckfree(in.buf);
4978         if (in.fd >= 0) {
4979                 close(in.fd);
4980                 back_exitstatus = waitforjob(in.jp);
4981         }
4982         INTON;
4983
4984         /* Eat all trailing newlines */
4985         dest = expdest;
4986         for (; dest > (char *)stackblock() && dest[-1] == '\n';)
4987                 STUNPUTC(dest);
4988         expdest = dest;
4989
4990         if (quoted == 0)
4991                 recordregion(startloc, dest - (char *)stackblock(), 0);
4992         TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4993                 (dest - (char *)stackblock()) - startloc,
4994                 (dest - (char *)stackblock()) - startloc,
4995                 stackblock() + startloc));
4996 }
4997
4998
4999 static char *
5000 scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5001         int zero)
5002 {
5003         char *loc;
5004         char *loc2;
5005         char c;
5006
5007         loc = startp;
5008         loc2 = rmesc;
5009         do {
5010                 int match;
5011                 const char *s = loc2;
5012                 c = *loc2;
5013                 if (zero) {
5014                         *loc2 = '\0';
5015                         s = rmesc;
5016                 }
5017                 match = pmatch(str, s);
5018                 *loc2 = c;
5019                 if (match)
5020                         return loc;
5021                 if (quotes && *loc == CTLESC)
5022                         loc++;
5023                 loc++;
5024                 loc2++;
5025         } while (c);
5026         return 0;
5027 }
5028
5029
5030 static char *
5031 scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes,
5032         int zero)
5033 {
5034         int esc = 0;
5035         char *loc;
5036         char *loc2;
5037
5038         for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) {
5039                 int match;
5040                 char c = *loc2;
5041                 const char *s = loc2;
5042                 if (zero) {
5043                         *loc2 = '\0';
5044                         s = rmesc;
5045                 }
5046                 match = pmatch(str, s);
5047                 *loc2 = c;
5048                 if (match)
5049                         return loc;
5050                 loc--;
5051                 if (quotes) {
5052                         if (--esc < 0) {
5053                                 esc = esclen(startp, loc);
5054                         }
5055                         if (esc % 2) {
5056                                 esc--;
5057                                 loc--;
5058                         }
5059                 }
5060         }
5061         return 0;
5062 }
5063
5064 static const char *
5065 subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
5066 {
5067         char *startp;
5068         char *loc;
5069         int saveherefd = herefd;
5070         struct nodelist *saveargbackq = argbackq;
5071         int amount;
5072         char *rmesc, *rmescend;
5073         int zero;
5074         char *(*scan)(char *, char *, char *, char *, int , int);
5075
5076         herefd = -1;
5077         argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
5078         STPUTC('\0', expdest);
5079         herefd = saveherefd;
5080         argbackq = saveargbackq;
5081         startp = stackblock() + startloc;
5082
5083         switch (subtype) {
5084         case VSASSIGN:
5085                 setvar(str, startp, 0);
5086                 amount = startp - expdest;
5087                 STADJUST(amount, expdest);
5088                 return startp;
5089
5090         case VSQUESTION:
5091                 varunset(p, str, startp, varflags);
5092                 /* NOTREACHED */
5093         }
5094
5095         subtype -= VSTRIMRIGHT;
5096 #ifdef DEBUG
5097         if (subtype < 0 || subtype > 3)
5098                 abort();
5099 #endif
5100
5101         rmesc = startp;
5102         rmescend = stackblock() + strloc;
5103         if (quotes) {
5104                 rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
5105                 if (rmesc != startp) {
5106                         rmescend = expdest;
5107                         startp = stackblock() + startloc;
5108                 }
5109         }
5110         rmescend--;
5111         str = stackblock() + strloc;
5112         preglob(str, varflags & VSQUOTE, 0);
5113
5114         /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */
5115         zero = subtype >> 1;
5116         /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
5117         scan = (subtype & 1) ^ zero ? scanleft : scanright;
5118
5119         loc = scan(startp, rmesc, rmescend, str, quotes, zero);
5120         if (loc) {
5121                 if (zero) {
5122                         memmove(startp, loc, str - loc);
5123                         loc = startp + (str - loc) - 1;
5124                 }
5125                 *loc = '\0';
5126                 amount = loc - expdest;
5127                 STADJUST(amount, expdest);
5128         }
5129         return loc;
5130 }
5131
5132
5133 /*
5134  * Expand a variable, and return a pointer to the next character in the
5135  * input string.
5136  */
5137 static char *
5138 evalvar(char *p, int flag)
5139 {
5140         int subtype;
5141         int varflags;
5142         char *var;
5143         int patloc;
5144         int c;
5145         int startloc;
5146         ssize_t varlen;
5147         int easy;
5148         int quotes;
5149         int quoted;
5150
5151         quotes = flag & (EXP_FULL | EXP_CASE);
5152         varflags = *p++;
5153         subtype = varflags & VSTYPE;
5154         quoted = varflags & VSQUOTE;
5155         var = p;
5156         easy = (!quoted || (*var == '@' && shellparam.nparam));
5157         startloc = expdest - (char *)stackblock();
5158         p = strchr(p, '=') + 1;
5159
5160 again:
5161         varlen = varvalue(var, varflags, flag);
5162         if (varflags & VSNUL)
5163                 varlen--;
5164
5165         if (subtype == VSPLUS) {
5166                 varlen = -1 - varlen;
5167                 goto vsplus;
5168         }
5169
5170         if (subtype == VSMINUS) {
5171 vsplus:
5172                 if (varlen < 0) {
5173                         argstr(
5174                                 p, flag | EXP_TILDE |
5175                                         (quoted ?  EXP_QWORD : EXP_WORD)
5176                         );
5177                         goto end;
5178                 }
5179                 if (easy)
5180                         goto record;
5181                 goto end;
5182         }
5183
5184         if (subtype == VSASSIGN || subtype == VSQUESTION) {
5185                 if (varlen < 0) {
5186                         if (subevalvar(p, var, 0, subtype, startloc,
5187                                        varflags, 0)) {
5188                                 varflags &= ~VSNUL;
5189                                 /*
5190                                  * Remove any recorded regions beyond
5191                                  * start of variable
5192                                  */
5193                                 removerecordregions(startloc);
5194                                 goto again;
5195                         }
5196                         goto end;
5197                 }
5198                 if (easy)
5199                         goto record;
5200                 goto end;
5201         }
5202
5203         if (varlen < 0 && uflag)
5204                 varunset(p, var, 0, 0);
5205
5206         if (subtype == VSLENGTH) {
5207                 cvtnum(varlen > 0 ? varlen : 0);
5208                 goto record;
5209         }
5210
5211         if (subtype == VSNORMAL) {
5212                 if (!easy)
5213                         goto end;
5214 record:
5215                 recordregion(startloc, expdest - (char *)stackblock(), quoted);
5216                 goto end;
5217         }
5218
5219 #ifdef DEBUG
5220         switch (subtype) {
5221         case VSTRIMLEFT:
5222         case VSTRIMLEFTMAX:
5223         case VSTRIMRIGHT:
5224         case VSTRIMRIGHTMAX:
5225                 break;
5226         default:
5227                 abort();
5228         }
5229 #endif
5230
5231         if (varlen >= 0) {
5232                 /*
5233                  * Terminate the string and start recording the pattern
5234                  * right after it
5235                  */
5236                 STPUTC('\0', expdest);
5237                 patloc = expdest - (char *)stackblock();
5238                 if (subevalvar(p, NULL, patloc, subtype,
5239                                startloc, varflags, quotes) == 0) {
5240                         int amount = expdest - (
5241                                 (char *)stackblock() + patloc - 1
5242                         );
5243                         STADJUST(-amount, expdest);
5244                 }
5245                 /* Remove any recorded regions beyond start of variable */
5246                 removerecordregions(startloc);
5247                 goto record;
5248         }
5249
5250 end:
5251         if (subtype != VSNORMAL) {      /* skip to end of alternative */
5252                 int nesting = 1;
5253                 for (;;) {
5254                         if ((c = *p++) == CTLESC)
5255                                 p++;
5256                         else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
5257                                 if (varlen >= 0)
5258                                         argbackq = argbackq->next;
5259                         } else if (c == CTLVAR) {
5260                                 if ((*p++ & VSTYPE) != VSNORMAL)
5261                                         nesting++;
5262                         } else if (c == CTLENDVAR) {
5263                                 if (--nesting == 0)
5264                                         break;
5265                         }
5266                 }
5267         }
5268         return p;
5269 }
5270
5271
5272 /*
5273  * Put a string on the stack.
5274  */
5275
5276 static void
5277 memtodest(const char *p, size_t len, int syntax, int quotes) {
5278         char *q = expdest;
5279
5280         q = makestrspace(len * 2, q);
5281
5282         while (len--) {
5283                 int c = *p++;
5284                 if (!c)
5285                         continue;
5286                 if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK))
5287                         USTPUTC(CTLESC, q);
5288                 USTPUTC(c, q);
5289         }
5290
5291         expdest = q;
5292 }
5293
5294
5295 static void
5296 strtodest(const char *p, int syntax, int quotes)
5297 {
5298         memtodest(p, strlen(p), syntax, quotes);
5299 }
5300
5301
5302 /*
5303  * Add the value of a specialized variable to the stack string.
5304  */
5305
5306 static ssize_t
5307 varvalue(char *name, int varflags, int flags)
5308 {
5309         int num;
5310         char *p;
5311         int i;
5312         int sep = 0;
5313         int sepq = 0;
5314         ssize_t len = 0;
5315         char **ap;
5316         int syntax;
5317         int quoted = varflags & VSQUOTE;
5318         int subtype = varflags & VSTYPE;
5319         int quotes = flags & (EXP_FULL | EXP_CASE);
5320
5321         if (quoted && (flags & EXP_FULL))
5322                 sep = 1 << CHAR_BIT;
5323
5324         syntax = quoted ? DQSYNTAX : BASESYNTAX;
5325         switch (*name) {
5326         case '$':
5327                 num = rootpid;
5328                 goto numvar;
5329         case '?':
5330                 num = exitstatus;
5331                 goto numvar;
5332         case '#':
5333                 num = shellparam.nparam;
5334                 goto numvar;
5335         case '!':
5336                 num = backgndpid;
5337                 if (num == 0)
5338                         return -1;
5339 numvar:
5340                 len = cvtnum(num);
5341                 break;
5342         case '-':
5343                 p = makestrspace(NOPTS, expdest);
5344                 for (i = NOPTS - 1; i >= 0; i--) {
5345                         if (optlist[i]) {
5346                                 USTPUTC(optletters(i), p);
5347                                 len++;
5348                         }
5349                 }
5350                 expdest = p;
5351                 break;
5352         case '@':
5353                 if (sep)
5354                         goto param;
5355                 /* fall through */
5356         case '*':
5357                 sep = ifsset() ? ifsval()[0] : ' ';
5358                 if (quotes && (SIT(sep, syntax) == CCTL || SIT(sep, syntax) == CBACK))
5359                         sepq = 1;
5360 param:
5361                 if (!(ap = shellparam.p))
5362                         return -1;
5363                 while ((p = *ap++)) {
5364                         size_t partlen;
5365
5366                         partlen = strlen(p);
5367
5368                         len += partlen;
5369                         if (len > partlen && sep) {
5370                                 char *q;
5371
5372                                 len++;
5373                                 if (subtype == VSPLUS || subtype == VSLENGTH) {
5374                                         continue;
5375                                 }
5376                                 q = expdest;
5377                                 if (sepq)
5378                                         STPUTC(CTLESC, q);
5379                                 STPUTC(sep, q);
5380                                 expdest = q;
5381                         }
5382
5383                         if (!(subtype == VSPLUS || subtype == VSLENGTH))
5384                                 memtodest(p, partlen, syntax, quotes);
5385                 }
5386                 return len;
5387         case '0':
5388         case '1':
5389         case '2':
5390         case '3':
5391         case '4':
5392         case '5':
5393         case '6':
5394         case '7':
5395         case '8':
5396         case '9':
5397                 num = atoi(name);
5398                 if (num < 0 || num > shellparam.nparam)
5399                         return -1;
5400                 p = num ? shellparam.p[num - 1] : arg0;
5401                 goto value;
5402         default:
5403                 p = lookupvar(name);
5404 value:
5405                 if (!p)
5406                         return -1;
5407
5408                 len = strlen(p);
5409                 if (!(subtype == VSPLUS || subtype == VSLENGTH))
5410                         memtodest(p, len, syntax, quotes);
5411                 return len;
5412         }
5413
5414         if (subtype == VSPLUS || subtype == VSLENGTH)
5415                 STADJUST(-len, expdest);
5416         return len;
5417 }
5418
5419
5420 /*
5421  * Record the fact that we have to scan this region of the
5422  * string for IFS characters.
5423  */
5424
5425 static void
5426 recordregion(int start, int end, int nulonly)
5427 {
5428         struct ifsregion *ifsp;
5429
5430         if (ifslastp == NULL) {
5431                 ifsp = &ifsfirst;
5432         } else {
5433                 INTOFF;
5434                 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
5435                 ifsp->next = NULL;
5436                 ifslastp->next = ifsp;
5437                 INTON;
5438         }
5439         ifslastp = ifsp;
5440         ifslastp->begoff = start;
5441         ifslastp->endoff = end;
5442         ifslastp->nulonly = nulonly;
5443 }
5444
5445
5446 /*
5447  * Break the argument string into pieces based upon IFS and add the
5448  * strings to the argument list.  The regions of the string to be
5449  * searched for IFS characters have been stored by recordregion.
5450  */
5451 static void
5452 ifsbreakup(char *string, struct arglist *arglist)
5453 {
5454         struct ifsregion *ifsp;
5455         struct strlist *sp;
5456         char *start;
5457         char *p;
5458         char *q;
5459         const char *ifs, *realifs;
5460         int ifsspc;
5461         int nulonly;
5462
5463
5464         start = string;
5465         if (ifslastp != NULL) {
5466                 ifsspc = 0;
5467                 nulonly = 0;
5468                 realifs = ifsset() ? ifsval() : defifs;
5469                 ifsp = &ifsfirst;
5470                 do {
5471                         p = string + ifsp->begoff;
5472                         nulonly = ifsp->nulonly;
5473                         ifs = nulonly ? nullstr : realifs;
5474                         ifsspc = 0;
5475                         while (p < string + ifsp->endoff) {
5476                                 q = p;
5477                                 if (*p == CTLESC)
5478                                         p++;
5479                                 if (strchr(ifs, *p)) {
5480                                         if (!nulonly)
5481                                                 ifsspc = (strchr(defifs, *p) != NULL);
5482                                         /* Ignore IFS whitespace at start */
5483                                         if (q == start && ifsspc) {
5484                                                 p++;
5485                                                 start = p;
5486                                                 continue;
5487                                         }
5488                                         *q = '\0';
5489                                         sp = (struct strlist *)stalloc(sizeof *sp);
5490                                         sp->text = start;
5491                                         *arglist->lastp = sp;
5492                                         arglist->lastp = &sp->next;
5493                                         p++;
5494                                         if (!nulonly) {
5495                                                 for (;;) {
5496                                                         if (p >= string + ifsp->endoff) {
5497                                                                 break;
5498                                                         }
5499                                                         q = p;
5500                                                         if (*p == CTLESC)
5501                                                                 p++;
5502                                                         if (strchr(ifs, *p) == NULL ) {
5503                                                                 p = q;
5504                                                                 break;
5505                                                         } else if (strchr(defifs, *p) == NULL) {
5506                                                                 if (ifsspc) {
5507                                                                         p++;
5508                                                                         ifsspc = 0;
5509                                                                 } else {
5510                                                                         p = q;
5511                                                                         break;
5512                                                                 }
5513                                                         } else
5514                                                                 p++;
5515                                                 }
5516                                         }
5517                                         start = p;
5518                                 } else
5519                                         p++;
5520                         }
5521                 } while ((ifsp = ifsp->next) != NULL);
5522                 if (nulonly)
5523                         goto add;
5524         }
5525
5526         if (!*start)
5527                 return;
5528
5529 add:
5530         sp = (struct strlist *)stalloc(sizeof *sp);
5531         sp->text = start;
5532         *arglist->lastp = sp;
5533         arglist->lastp = &sp->next;
5534 }
5535
5536 static void
5537 ifsfree(void)
5538 {
5539         struct ifsregion *p;
5540
5541         INTOFF;
5542         p = ifsfirst.next;
5543         do {
5544                 struct ifsregion *ifsp;
5545                 ifsp = p->next;
5546                 ckfree(p);
5547                 p = ifsp;
5548         } while (p);
5549         ifslastp = NULL;
5550         ifsfirst.next = NULL;
5551         INTON;
5552 }
5553
5554 static void expmeta(char *, char *);
5555 static struct strlist *expsort(struct strlist *);
5556 static struct strlist *msort(struct strlist *, int);
5557
5558 static char *expdir;
5559
5560
5561 static void
5562 expandmeta(struct strlist *str, int flag)
5563 {
5564         static const char metachars[] = {
5565                 '*', '?', '[', 0
5566         };
5567         /* TODO - EXP_REDIR */
5568
5569         while (str) {
5570                 struct strlist **savelastp;
5571                 struct strlist *sp;
5572                 char *p;
5573
5574                 if (fflag)
5575                         goto nometa;
5576                 if (!strpbrk(str->text, metachars))
5577                         goto nometa;
5578                 savelastp = exparg.lastp;
5579
5580                 INTOFF;
5581                 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
5582                 {
5583                         int i = strlen(str->text);
5584                         expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5585                 }
5586
5587                 expmeta(expdir, p);
5588                 ckfree(expdir);
5589                 if (p != str->text)
5590                         ckfree(p);
5591                 INTON;
5592                 if (exparg.lastp == savelastp) {
5593                         /*
5594                          * no matches
5595                          */
5596 nometa:
5597                         *exparg.lastp = str;
5598                         rmescapes(str->text);
5599                         exparg.lastp = &str->next;
5600                 } else {
5601                         *exparg.lastp = NULL;
5602                         *savelastp = sp = expsort(*savelastp);
5603                         while (sp->next != NULL)
5604                                 sp = sp->next;
5605                         exparg.lastp = &sp->next;
5606                 }
5607                 str = str->next;
5608         }
5609 }
5610
5611 /*
5612  * Add a file name to the list.
5613  */
5614
5615 static void
5616 addfname(const char *name)
5617 {
5618         struct strlist *sp;
5619
5620         sp = (struct strlist *)stalloc(sizeof *sp);
5621         sp->text = sstrdup(name);
5622         *exparg.lastp = sp;
5623         exparg.lastp = &sp->next;
5624 }
5625
5626
5627 /*
5628  * Do metacharacter (i.e. *, ?, [...]) expansion.
5629  */
5630
5631 static void
5632 expmeta(char *enddir, char *name)
5633 {
5634         char *p;
5635         const char *cp;
5636         char *start;
5637         char *endname;
5638         int metaflag;
5639         struct stat statb;
5640         DIR *dirp;
5641         struct dirent *dp;
5642         int atend;
5643         int matchdot;
5644
5645         metaflag = 0;
5646         start = name;
5647         for (p = name; *p; p++) {
5648                 if (*p == '*' || *p == '?')
5649                         metaflag = 1;
5650                 else if (*p == '[') {
5651                         char *q = p + 1;
5652                         if (*q == '!')
5653                                 q++;
5654                         for (;;) {
5655                                 if (*q == '\\')
5656                                         q++;
5657                                 if (*q == '/' || *q == '\0')
5658                                         break;
5659                                 if (*++q == ']') {
5660                                         metaflag = 1;
5661                                         break;
5662                                 }
5663                         }
5664                 } else if (*p == '\\')
5665                         p++;
5666                 else if (*p == '/') {
5667                         if (metaflag)
5668                                 goto out;
5669                         start = p + 1;
5670                 }
5671         }
5672 out:
5673         if (metaflag == 0) {    /* we've reached the end of the file name */
5674                 if (enddir != expdir)
5675                         metaflag++;
5676                 p = name;
5677                 do {
5678                         if (*p == '\\')
5679                                 p++;
5680                         *enddir++ = *p;
5681                 } while (*p++);
5682                 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
5683                         addfname(expdir);
5684                 return;
5685         }
5686         endname = p;
5687         if (name < start) {
5688                 p = name;
5689                 do {
5690                         if (*p == '\\')
5691                                 p++;
5692                         *enddir++ = *p++;
5693                 } while (p < start);
5694         }
5695         if (enddir == expdir) {
5696                 cp = ".";
5697         } else if (enddir == expdir + 1 && *expdir == '/') {
5698                 cp = "/";
5699         } else {
5700                 cp = expdir;
5701                 enddir[-1] = '\0';
5702         }
5703         if ((dirp = opendir(cp)) == NULL)
5704                 return;
5705         if (enddir != expdir)
5706                 enddir[-1] = '/';
5707         if (*endname == 0) {
5708                 atend = 1;
5709         } else {
5710                 atend = 0;
5711                 *endname++ = '\0';
5712         }
5713         matchdot = 0;
5714         p = start;
5715         if (*p == '\\')
5716                 p++;
5717         if (*p == '.')
5718                 matchdot++;
5719         while (! intpending && (dp = readdir(dirp)) != NULL) {
5720                 if (dp->d_name[0] == '.' && ! matchdot)
5721                         continue;
5722                 if (pmatch(start, dp->d_name)) {
5723                         if (atend) {
5724                                 scopy(dp->d_name, enddir);
5725                                 addfname(expdir);
5726                         } else {
5727                                 for (p = enddir, cp = dp->d_name;
5728                                      (*p++ = *cp++) != '\0';)
5729                                         continue;
5730                                 p[-1] = '/';
5731                                 expmeta(p, endname);
5732                         }
5733                 }
5734         }
5735         closedir(dirp);
5736         if (! atend)
5737                 endname[-1] = '/';
5738 }
5739
5740 /*
5741  * Sort the results of file name expansion.  It calculates the number of
5742  * strings to sort and then calls msort (short for merge sort) to do the
5743  * work.
5744  */
5745
5746 static struct strlist *
5747 expsort(struct strlist *str)
5748 {
5749         int len;
5750         struct strlist *sp;
5751
5752         len = 0;
5753         for (sp = str ; sp ; sp = sp->next)
5754                 len++;
5755         return msort(str, len);
5756 }
5757
5758
5759 static struct strlist *
5760 msort(struct strlist *list, int len)
5761 {
5762         struct strlist *p, *q = NULL;
5763         struct strlist **lpp;
5764         int half;
5765         int n;
5766
5767         if (len <= 1)
5768                 return list;
5769         half = len >> 1;
5770         p = list;
5771         for (n = half ; --n >= 0 ; ) {
5772                 q = p;
5773                 p = p->next;
5774         }
5775         q->next = NULL;                 /* terminate first half of list */
5776         q = msort(list, half);          /* sort first half of list */
5777         p = msort(p, len - half);               /* sort second half */
5778         lpp = &list;
5779         for (;;) {
5780 #ifdef CONFIG_LOCALE_SUPPORT
5781                 if (strcoll(p->text, q->text) < 0)
5782 #else
5783                 if (strcmp(p->text, q->text) < 0)
5784 #endif
5785                                                 {
5786                         *lpp = p;
5787                         lpp = &p->next;
5788                         if ((p = *lpp) == NULL) {
5789                                 *lpp = q;
5790                                 break;
5791                         }
5792                 } else {
5793                         *lpp = q;
5794                         lpp = &q->next;
5795                         if ((q = *lpp) == NULL) {
5796                                 *lpp = p;
5797                                 break;
5798                         }
5799                 }
5800         }
5801         return list;
5802 }
5803
5804
5805 /*
5806  * Returns true if the pattern matches the string.
5807  */
5808
5809 static inline int
5810 patmatch(char *pattern, const char *string)
5811 {
5812         return pmatch(preglob(pattern, 0, 0), string);
5813 }
5814
5815
5816 /*
5817  * Remove any CTLESC characters from a string.
5818  */
5819
5820 static char *
5821 _rmescapes(char *str, int flag)
5822 {
5823         char *p, *q, *r;
5824         static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
5825         unsigned inquotes;
5826         int notescaped;
5827         int globbing;
5828
5829         p = strpbrk(str, qchars);
5830         if (!p) {
5831                 return str;
5832         }
5833         q = p;
5834         r = str;
5835         if (flag & RMESCAPE_ALLOC) {
5836                 size_t len = p - str;
5837                 size_t fulllen = len + strlen(p) + 1;
5838
5839                 if (flag & RMESCAPE_GROW) {
5840                         r = makestrspace(fulllen, expdest);
5841                 } else if (flag & RMESCAPE_HEAP) {
5842                         r = ckmalloc(fulllen);
5843                 } else {
5844                         r = stalloc(fulllen);
5845                 }
5846                 q = r;
5847                 if (len > 0) {
5848                         q = mempcpy(q, str, len);
5849                 }
5850         }
5851         inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5852         globbing = flag & RMESCAPE_GLOB;
5853         notescaped = globbing;
5854         while (*p) {
5855                 if (*p == CTLQUOTEMARK) {
5856                         inquotes = ~inquotes;
5857                         p++;
5858                         notescaped = globbing;
5859                         continue;
5860                 }
5861                 if (*p == '\\') {
5862                         /* naked back slash */
5863                         notescaped = 0;
5864                         goto copy;
5865                 }
5866                 if (*p == CTLESC) {
5867                         p++;
5868                         if (notescaped && inquotes && *p != '/') {
5869                                 *q++ = '\\';
5870                         }
5871                 }
5872                 notescaped = globbing;
5873 copy:
5874                 *q++ = *p++;
5875         }
5876         *q = '\0';
5877         if (flag & RMESCAPE_GROW) {
5878                 expdest = r;
5879                 STADJUST(q - r + 1, expdest);
5880         }
5881         return r;
5882 }
5883
5884
5885 /*
5886  * See if a pattern matches in a case statement.
5887  */
5888
5889 int
5890 casematch(union node *pattern, char *val)
5891 {
5892         struct stackmark smark;
5893         int result;
5894
5895         setstackmark(&smark);
5896         argbackq = pattern->narg.backquote;
5897         STARTSTACKSTR(expdest);
5898         ifslastp = NULL;
5899         argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
5900         STACKSTRNUL(expdest);
5901         result = patmatch(stackblock(), val);
5902         popstackmark(&smark);
5903         return result;
5904 }
5905
5906 /*
5907  * Our own itoa().
5908  */
5909
5910 static int
5911 cvtnum(arith_t num)
5912 {
5913         int len;
5914
5915         expdest = makestrspace(32, expdest);
5916 #ifdef CONFIG_ASH_MATH_SUPPORT_64
5917         len = fmtstr(expdest, 32, "%lld", (long long) num);
5918 #else
5919         len = fmtstr(expdest, 32, "%ld", num);
5920 #endif
5921         STADJUST(len, expdest);
5922         return len;
5923 }
5924
5925 static void
5926 varunset(const char *end, const char *var, const char *umsg, int varflags)
5927 {
5928         const char *msg;
5929         const char *tail;
5930
5931         tail = nullstr;
5932         msg = "parameter not set";
5933         if (umsg) {
5934                 if (*end == CTLENDVAR) {
5935                         if (varflags & VSNUL)
5936                                 tail = " or null";
5937                 } else
5938                         msg = umsg;
5939         }
5940         error("%.*s: %s%s", end - var - 1, var, msg, tail);
5941 }
5942
5943
5944 /*      $NetBSD: input.c,v 1.37 2002/11/24 22:35:40 christos Exp $      */
5945
5946 /*
5947  * This implements the input routines used by the parser.
5948  */
5949
5950 #define EOF_NLEFT -99           /* value of parsenleft when EOF pushed back */
5951 #define IBUFSIZ (BUFSIZ + 1)
5952
5953 static void pushfile(void);
5954
5955 /*
5956  * Read a line from the script.
5957  */
5958
5959 static inline char *
5960 pfgets(char *line, int len)
5961 {
5962         char *p = line;
5963         int nleft = len;
5964         int c;
5965
5966         while (--nleft > 0) {
5967                 c = pgetc2();
5968                 if (c == PEOF) {
5969                         if (p == line)
5970                                 return NULL;
5971                         break;
5972                 }
5973                 *p++ = c;
5974                 if (c == '\n')
5975                         break;
5976         }
5977         *p = '\0';
5978         return line;
5979 }
5980
5981
5982 /*
5983  * Read a character from the script, returning PEOF on end of file.
5984  * Nul characters in the input are silently discarded.
5985  */
5986
5987 #define pgetc_as_macro()   (--parsenleft >= 0? *parsenextc++ : preadbuffer())
5988
5989 #ifdef CONFIG_ASH_OPTIMIZE_FOR_SIZE
5990 #define pgetc_macro() pgetc()
5991 static int
5992 pgetc(void)
5993 {
5994         return pgetc_as_macro();
5995 }
5996 #else
5997 #define pgetc_macro()   pgetc_as_macro()
5998 static int
5999 pgetc(void)
6000 {
6001         return pgetc_macro();
6002 }
6003 #endif
6004
6005
6006 /*
6007  * Same as pgetc(), but ignores PEOA.
6008  */
6009 #ifdef CONFIG_ASH_ALIAS
6010 static int pgetc2(void)
6011 {
6012         int c;
6013
6014         do {
6015                 c = pgetc_macro();
6016         } while (c == PEOA);
6017         return c;
6018 }
6019 #else
6020 static inline int pgetc2(void)
6021 {
6022         return pgetc_macro();
6023 }
6024 #endif
6025
6026
6027 #ifdef CONFIG_FEATURE_COMMAND_EDITING
6028 static const char *cmdedit_prompt;
6029 static inline void putprompt(const char *s)
6030 {
6031         cmdedit_prompt = s;
6032 }
6033 #else
6034 static inline void putprompt(const char *s)
6035 {
6036         out2str(s);
6037 }
6038 #endif
6039
6040 static inline int
6041 preadfd(void)
6042 {
6043         int nr;
6044         char *buf =  parsefile->buf;
6045         parsenextc = buf;
6046
6047 retry:
6048 #ifdef CONFIG_FEATURE_COMMAND_EDITING
6049         if (!iflag || parsefile->fd)
6050                 nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6051         else {
6052                 cmdedit_path_lookup = pathval();
6053                 nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
6054                 if(nr == 0) {
6055                         /* Ctrl+C presend */
6056                         if(trap[SIGINT]) {
6057                                 buf[0] = '\n';
6058                                 buf[1] = 0;
6059                                 raise(SIGINT);
6060                                 return 1;
6061                         }
6062                         goto retry;
6063                 }
6064                 if(nr < 0) {
6065                         /* Ctrl+D presend */
6066                         nr = 0;
6067                 }
6068         }
6069 #else
6070         nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
6071 #endif
6072
6073         if (nr < 0) {
6074                 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6075                         int flags = fcntl(0, F_GETFL, 0);
6076                         if (flags >= 0 && flags & O_NONBLOCK) {
6077                                 flags &=~ O_NONBLOCK;
6078                                 if (fcntl(0, F_SETFL, flags) >= 0) {
6079                                         out2str("sh: turning off NDELAY mode\n");
6080                                         goto retry;
6081                                 }
6082                         }
6083                 }
6084         }
6085         return nr;
6086 }
6087
6088 /*
6089  * Refill the input buffer and return the next input character:
6090  *
6091  * 1) If a string was pushed back on the input, pop it;
6092  * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6093  *    from a string so we can't refill the buffer, return EOF.
6094  * 3) If the is more stuff in this buffer, use it else call read to fill it.
6095  * 4) Process input up to the next newline, deleting nul characters.
6096  */
6097
6098 int
6099 preadbuffer(void)
6100 {
6101         char *p, *q;
6102         int more;
6103         char savec;
6104
6105         while (parsefile->strpush) {
6106 #ifdef CONFIG_ASH_ALIAS
6107                 if (parsenleft == -1 && parsefile->strpush->ap &&
6108                         parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
6109                         return PEOA;
6110                 }
6111 #endif
6112                 popstring();
6113                 if (--parsenleft >= 0)
6114                         return (*parsenextc++);
6115         }
6116         if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6117                 return PEOF;
6118         flushall();
6119
6120 again:
6121         if (parselleft <= 0) {
6122                 if ((parselleft = preadfd()) <= 0) {
6123                         parselleft = parsenleft = EOF_NLEFT;
6124                         return PEOF;
6125                 }
6126         }
6127
6128         q = p = parsenextc;
6129
6130         /* delete nul characters */
6131         for (more = 1; more;) {
6132                 switch (*p) {
6133                 case '\0':
6134                         p++;    /* Skip nul */
6135                         goto check;
6136
6137                 case '\n':
6138                         parsenleft = q - parsenextc;
6139                         more = 0; /* Stop processing here */
6140                         break;
6141
6142                 }
6143
6144                 *q++ = *p++;
6145 check:
6146                 if (--parselleft <= 0 && more) {
6147                         parsenleft = q - parsenextc - 1;
6148                         if (parsenleft < 0)
6149                                 goto again;
6150                         more = 0;
6151                 }
6152         }
6153
6154         savec = *q;
6155         *q = '\0';
6156
6157         if (vflag) {
6158                 out2str(parsenextc);
6159         }
6160
6161         *q = savec;
6162
6163         return *parsenextc++;
6164 }
6165
6166 /*
6167  * Undo the last call to pgetc.  Only one character may be pushed back.
6168  * PEOF may be pushed back.
6169  */
6170
6171 void
6172 pungetc(void)
6173 {
6174         parsenleft++;
6175         parsenextc--;
6176 }
6177
6178 /*
6179  * Push a string back onto the input at this current parsefile level.
6180  * We handle aliases this way.
6181  */
6182 void
6183 pushstring(char *s, void *ap)
6184 {
6185         struct strpush *sp;
6186         size_t len;
6187
6188         len = strlen(s);
6189         INTOFF;
6190 /*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6191         if (parsefile->strpush) {
6192                 sp = ckmalloc(sizeof (struct strpush));
6193                 sp->prev = parsefile->strpush;
6194                 parsefile->strpush = sp;
6195         } else
6196                 sp = parsefile->strpush = &(parsefile->basestrpush);
6197         sp->prevstring = parsenextc;
6198         sp->prevnleft = parsenleft;
6199 #ifdef CONFIG_ASH_ALIAS
6200         sp->ap = (struct alias *)ap;
6201         if (ap) {
6202                 ((struct alias *)ap)->flag |= ALIASINUSE;
6203                 sp->string = s;
6204         }
6205 #endif
6206         parsenextc = s;
6207         parsenleft = len;
6208         INTON;
6209 }
6210
6211 void
6212 popstring(void)
6213 {
6214         struct strpush *sp = parsefile->strpush;
6215
6216         INTOFF;
6217 #ifdef CONFIG_ASH_ALIAS
6218         if (sp->ap) {
6219                 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6220                         checkkwd |= CHKALIAS;
6221                 }
6222                 if (sp->string != sp->ap->val) {
6223                         ckfree(sp->string);
6224                 }
6225                 sp->ap->flag &= ~ALIASINUSE;
6226                 if (sp->ap->flag & ALIASDEAD) {
6227                         unalias(sp->ap->name);
6228                 }
6229         }
6230 #endif
6231         parsenextc = sp->prevstring;
6232         parsenleft = sp->prevnleft;
6233 /*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6234         parsefile->strpush = sp->prev;
6235         if (sp != &(parsefile->basestrpush))
6236                 ckfree(sp);
6237         INTON;
6238 }
6239
6240 /*
6241  * Set the input to take input from a file.  If push is set, push the
6242  * old input onto the stack first.
6243  */
6244
6245 void
6246 setinputfile(const char *fname, int push)
6247 {
6248         int fd;
6249         int fd2;
6250
6251         INTOFF;
6252         if ((fd = open(fname, O_RDONLY)) < 0)
6253                 error("Can't open %s", fname);
6254         if (fd < 10) {
6255                 fd2 = copyfd(fd, 10);
6256                 close(fd);
6257                 if (fd2 < 0)
6258                         error("Out of file descriptors");
6259                 fd = fd2;
6260         }
6261         setinputfd(fd, push);
6262         INTON;
6263 }
6264
6265
6266 /*
6267  * Like setinputfile, but takes an open file descriptor.  Call this with
6268  * interrupts off.
6269  */
6270
6271 static void
6272 setinputfd(int fd, int push)
6273 {
6274         (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
6275         if (push) {
6276                 pushfile();
6277                 parsefile->buf = 0;
6278         }
6279         parsefile->fd = fd;
6280         if (parsefile->buf == NULL)
6281                 parsefile->buf = ckmalloc(IBUFSIZ);
6282         parselleft = parsenleft = 0;
6283         plinno = 1;
6284 }
6285
6286
6287 /*
6288  * Like setinputfile, but takes input from a string.
6289  */
6290
6291 static void
6292 setinputstring(char *string)
6293 {
6294         INTOFF;
6295         pushfile();
6296         parsenextc = string;
6297         parsenleft = strlen(string);
6298         parsefile->buf = NULL;
6299         plinno = 1;
6300         INTON;
6301 }
6302
6303
6304 /*
6305  * To handle the "." command, a stack of input files is used.  Pushfile
6306  * adds a new entry to the stack and popfile restores the previous level.
6307  */
6308
6309 static void
6310 pushfile(void)
6311 {
6312         struct parsefile *pf;
6313
6314         parsefile->nleft = parsenleft;
6315         parsefile->lleft = parselleft;
6316         parsefile->nextc = parsenextc;
6317         parsefile->linno = plinno;
6318         pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
6319         pf->prev = parsefile;
6320         pf->fd = -1;
6321         pf->strpush = NULL;
6322         pf->basestrpush.prev = NULL;
6323         parsefile = pf;
6324 }
6325
6326
6327 static void
6328 popfile(void)
6329 {
6330         struct parsefile *pf = parsefile;
6331
6332         INTOFF;
6333         if (pf->fd >= 0)
6334                 close(pf->fd);
6335         if (pf->buf)
6336                 ckfree(pf->buf);
6337         while (pf->strpush)
6338                 popstring();
6339         parsefile = pf->prev;
6340         ckfree(pf);
6341         parsenleft = parsefile->nleft;
6342         parselleft = parsefile->lleft;
6343         parsenextc = parsefile->nextc;
6344         plinno = parsefile->linno;
6345         INTON;
6346 }
6347
6348
6349 /*
6350  * Return to top level.
6351  */
6352
6353 static void
6354 popallfiles(void)
6355 {
6356         while (parsefile != &basepf)
6357                 popfile();
6358 }
6359
6360
6361 /*
6362  * Close the file(s) that the shell is reading commands from.  Called
6363  * after a fork is done.
6364  */
6365
6366 static void
6367 closescript(void)
6368 {
6369         popallfiles();
6370         if (parsefile->fd > 0) {
6371                 close(parsefile->fd);
6372                 parsefile->fd = 0;
6373         }
6374 }
6375
6376 /*      $NetBSD: jobs.c,v 1.56 2002/11/25 12:13:03 agc Exp $    */
6377
6378 /* mode flags for set_curjob */
6379 #define CUR_DELETE 2
6380 #define CUR_RUNNING 1
6381 #define CUR_STOPPED 0
6382
6383 /* mode flags for dowait */
6384 #define DOWAIT_NORMAL 0
6385 #define DOWAIT_BLOCK 1
6386
6387 /* array of jobs */
6388 static struct job *jobtab;
6389 /* size of array */
6390 static unsigned njobs;
6391 #if JOBS
6392 /* pgrp of shell on invocation */
6393 static int initialpgrp;
6394 static int ttyfd = -1;
6395 #endif
6396 /* current job */
6397 static struct job *curjob;
6398 /* number of presumed living untracked jobs */
6399 static int jobless;
6400
6401 static void set_curjob(struct job *, unsigned);
6402 #if JOBS
6403 static int restartjob(struct job *, int);
6404 static void xtcsetpgrp(int, pid_t);
6405 static char *commandtext(union node *);
6406 static void cmdlist(union node *, int);
6407 static void cmdtxt(union node *);
6408 static void cmdputs(const char *);
6409 static void showpipe(struct job *, FILE *);
6410 #endif
6411 static int sprint_status(char *, int, int);
6412 static void freejob(struct job *);
6413 static struct job *getjob(const char *, int);
6414 static struct job *growjobtab(void);
6415 static void forkchild(struct job *, union node *, int);
6416 static void forkparent(struct job *, union node *, int, pid_t);
6417 static int dowait(int, struct job *);
6418 static int getstatus(struct job *);
6419
6420 static void
6421 set_curjob(struct job *jp, unsigned mode)
6422 {
6423         struct job *jp1;
6424         struct job **jpp, **curp;
6425
6426         /* first remove from list */
6427         jpp = curp = &curjob;
6428         do {
6429                 jp1 = *jpp;
6430                 if (jp1 == jp)
6431                         break;
6432                 jpp = &jp1->prev_job;
6433         } while (1);
6434         *jpp = jp1->prev_job;
6435
6436         /* Then re-insert in correct position */
6437         jpp = curp;
6438         switch (mode) {
6439         default:
6440 #ifdef DEBUG
6441                 abort();
6442 #endif
6443         case CUR_DELETE:
6444                 /* job being deleted */
6445                 break;
6446         case CUR_RUNNING:
6447                 /* newly created job or backgrounded job,
6448                    put after all stopped jobs. */
6449                 do {
6450                         jp1 = *jpp;
6451 #ifdef JOBS
6452                         if (!jp1 || jp1->state != JOBSTOPPED)
6453 #endif
6454                                 break;
6455                         jpp = &jp1->prev_job;
6456                 } while (1);
6457                 /* FALLTHROUGH */
6458 #ifdef JOBS
6459         case CUR_STOPPED:
6460 #endif
6461                 /* newly stopped job - becomes curjob */
6462                 jp->prev_job = *jpp;
6463                 *jpp = jp;
6464                 break;
6465         }
6466 }
6467
6468 #if JOBS
6469 /*
6470  * Turn job control on and off.
6471  *
6472  * Note:  This code assumes that the third arg to ioctl is a character
6473  * pointer, which is true on Berkeley systems but not System V.  Since
6474  * System V doesn't have job control yet, this isn't a problem now.
6475  *
6476  * Called with interrupts off.
6477  */
6478
6479 void
6480 setjobctl(int on)
6481 {
6482         int fd;
6483         int pgrp;
6484
6485         if (on == jobctl || rootshell == 0)
6486                 return;
6487         if (on) {
6488                 int ofd;
6489                 ofd = fd = open(_PATH_TTY, O_RDWR);
6490                 if (fd < 0) {
6491                         fd += 3;
6492                         while (!isatty(fd) && --fd >= 0)
6493                                 ;
6494                 }
6495                 fd = fcntl(fd, F_DUPFD, 10);
6496                 close(ofd);
6497                 if (fd < 0)
6498                         goto out;
6499                 fcntl(fd, F_SETFD, FD_CLOEXEC);
6500                 do { /* while we are in the background */
6501                         if ((pgrp = tcgetpgrp(fd)) < 0) {
6502 out:
6503                                 sh_warnx("can't access tty; job control turned off");
6504                                 mflag = on = 0;
6505                                 goto close;
6506                         }
6507                         if (pgrp == getpgrp())
6508                                 break;
6509                         killpg(0, SIGTTIN);
6510                 } while (1);
6511                 initialpgrp = pgrp;
6512
6513                 setsignal(SIGTSTP);
6514                 setsignal(SIGTTOU);
6515                 setsignal(SIGTTIN);
6516                 pgrp = rootpid;
6517                 setpgid(0, pgrp);
6518                 xtcsetpgrp(fd, pgrp);
6519         } else {
6520                 /* turning job control off */
6521                 fd = ttyfd;
6522                 pgrp = initialpgrp;
6523                 xtcsetpgrp(fd, pgrp);
6524                 setpgid(0, pgrp);
6525                 setsignal(SIGTSTP);
6526                 setsignal(SIGTTOU);
6527                 setsignal(SIGTTIN);
6528 close:
6529                 close(fd);
6530                 fd = -1;
6531         }
6532         ttyfd = fd;
6533         jobctl = on;
6534 }
6535
6536 static int
6537 killcmd(int argc, char **argv)
6538 {
6539         int signo = -1;
6540         int list = 0;
6541         int i;
6542         pid_t pid;
6543         struct job *jp;
6544
6545         if (argc <= 1) {
6546 usage:
6547                 error(
6548 "Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6549 "kill -l [exitstatus]"
6550                 );
6551         }
6552
6553         if (**++argv == '-') {
6554                 signo = decode_signal(*argv + 1, 1);
6555                 if (signo < 0) {
6556                         int c;
6557
6558                         while ((c = nextopt("ls:")) != '\0')
6559                                 switch (c) {
6560                                 default:
6561 #ifdef DEBUG
6562                                         abort();
6563 #endif
6564                                 case 'l':
6565                                         list = 1;
6566                                         break;
6567                                 case 's':
6568                                         signo = decode_signal(optionarg, 1);
6569                                         if (signo < 0) {
6570                                                 error(
6571                                                         "invalid signal number or name: %s",
6572                                                         optionarg
6573                                                 );
6574                                         }
6575                                         break;
6576                                 }
6577                         argv = argptr;
6578                 } else
6579                         argv++;
6580         }
6581
6582         if (!list && signo < 0)
6583                 signo = SIGTERM;
6584
6585         if ((signo < 0 || !*argv) ^ list) {
6586                 goto usage;
6587         }
6588
6589         if (list) {
6590                 const char *name;
6591
6592                 if (!*argv) {
6593                         for (i = 1; i < NSIG; i++) {
6594                                 name = u_signal_names(0, &i, 1);
6595                                 if (name)
6596                                         out1fmt(snlfmt, name);
6597                         }
6598                         return 0;
6599                 }
6600                 name = u_signal_names(*argptr, &signo, -1);
6601                 if (name)
6602                         out1fmt(snlfmt, name);
6603                 else
6604                         error("invalid signal number or exit status: %s", *argptr);
6605                 return 0;
6606         }
6607
6608         i = 0;
6609         do {
6610                 if (**argv == '%') {
6611                         jp = getjob(*argv, 0);
6612                         pid = -jp->ps[0].pid;
6613                 } else
6614                         pid = number(*argv);
6615                 if (kill(pid, signo) != 0) {
6616                         sh_warnx("%m\n");
6617                         i = 1;
6618                 }
6619         } while (*++argv);
6620
6621         return i;
6622 }
6623 #endif /* JOBS */
6624
6625 #if defined(JOBS) || defined(DEBUG)
6626 static int
6627 jobno(const struct job *jp)
6628 {
6629         return jp - jobtab + 1;
6630 }
6631 #endif
6632
6633 #ifdef JOBS
6634 static int
6635 fgcmd(int argc, char **argv)
6636 {
6637         struct job *jp;
6638         FILE *out;
6639         int mode;
6640         int retval;
6641
6642         mode = (**argv == 'f') ? FORK_FG : FORK_BG;
6643         nextopt(nullstr);
6644         argv = argptr;
6645         out = stdout;
6646         do {
6647                 jp = getjob(*argv, 1);
6648                 if (mode == FORK_BG) {
6649                         set_curjob(jp, CUR_RUNNING);
6650                         fprintf(out, "[%d] ", jobno(jp));
6651                 }
6652                 outstr(jp->ps->cmd, out);
6653                 showpipe(jp, out);
6654                 retval = restartjob(jp, mode);
6655         } while (*argv && *++argv);
6656         return retval;
6657 }
6658
6659 static int bgcmd(int, char **) __attribute__((__alias__("fgcmd")));
6660
6661
6662 static int
6663 restartjob(struct job *jp, int mode)
6664 {
6665         struct procstat *ps;
6666         int i;
6667         int status;
6668         pid_t pgid;
6669
6670         INTOFF;
6671         if (jp->state == JOBDONE)
6672                 goto out;
6673         jp->state = JOBRUNNING;
6674         pgid = jp->ps->pid;
6675         if (mode == FORK_FG)
6676                 xtcsetpgrp(ttyfd, pgid);
6677         killpg(pgid, SIGCONT);
6678         ps = jp->ps;
6679         i = jp->nprocs;
6680         do {
6681                 if (WIFSTOPPED(ps->status)) {
6682                         ps->status = -1;
6683                 }
6684         } while (ps++, --i);
6685 out:
6686         status = (mode == FORK_FG) ? waitforjob(jp) : 0;
6687         INTON;
6688         return status;
6689 }
6690 #endif
6691
6692 static int
6693 sprint_status(char *s, int status, int sigonly)
6694 {
6695         int col;
6696         int st;
6697
6698         col = 0;
6699         if (!WIFEXITED(status)) {
6700 #if JOBS
6701                 if (WIFSTOPPED(status))
6702                         st = WSTOPSIG(status);
6703                 else
6704 #endif
6705                         st = WTERMSIG(status);
6706                 if (sigonly) {
6707                         if (st == SIGINT || st == SIGPIPE)
6708                                 goto out;
6709 #if JOBS
6710                         if (WIFSTOPPED(status))
6711                                 goto out;
6712 #endif
6713                 }
6714                 st &= 0x7f;
6715                 col = fmtstr(s, 32, strsignal(st));
6716                 if (WCOREDUMP(status)) {
6717                         col += fmtstr(s + col, 16, " (core dumped)");
6718                 }
6719         } else if (!sigonly) {
6720                 st = WEXITSTATUS(status);
6721                 if (st)
6722                         col = fmtstr(s, 16, "Done(%d)", st);
6723                 else
6724                         col = fmtstr(s, 16, "Done");
6725         }
6726
6727 out:
6728         return col;
6729 }
6730
6731 #if JOBS
6732 static void
6733 showjob(FILE *out, struct job *jp, int mode)
6734 {
6735         struct procstat *ps;
6736         struct procstat *psend;
6737         int col;
6738         int indent;
6739         char s[80];
6740
6741         ps = jp->ps;
6742
6743         if (mode & SHOW_PGID) {
6744                 /* just output process (group) id of pipeline */
6745                 fprintf(out, "%d\n", ps->pid);
6746                 return;
6747         }
6748
6749         col = fmtstr(s, 16, "[%d]   ", jobno(jp));
6750         indent = col;
6751
6752         if (jp == curjob)
6753                 s[col - 2] = '+';
6754         else if (curjob && jp == curjob->prev_job)
6755                 s[col - 2] = '-';
6756
6757         if (mode & SHOW_PID)
6758                 col += fmtstr(s + col, 16, "%d ", ps->pid);
6759
6760         psend = ps + jp->nprocs;
6761
6762         if (jp->state == JOBRUNNING) {
6763                 scopy("Running", s + col);
6764                 col += strlen("Running");
6765         } else {
6766                 int status = psend[-1].status;
6767 #if JOBS
6768                 if (jp->state == JOBSTOPPED)
6769                         status = jp->stopstatus;
6770 #endif
6771                 col += sprint_status(s + col, status, 0);
6772         }
6773
6774         goto start;
6775
6776         do {
6777                 /* for each process */
6778                 col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3;
6779
6780 start:
6781                 fprintf(out, "%s%*c%s",
6782                         s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd
6783                 );
6784                 if (!(mode & SHOW_PID)) {
6785                         showpipe(jp, out);
6786                         break;
6787                 }
6788                 if (++ps == psend) {
6789                         outcslow('\n', out);
6790                         break;
6791                 }
6792         } while (1);
6793
6794         jp->changed = 0;
6795
6796         if (jp->state == JOBDONE) {
6797                 TRACE(("showjob: freeing job %d\n", jobno(jp)));
6798                 freejob(jp);
6799         }
6800 }
6801
6802
6803 static int
6804 jobscmd(int argc, char **argv)
6805 {
6806         int mode, m;
6807         FILE *out;
6808
6809         mode = 0;
6810         while ((m = nextopt("lp")))
6811                 if (m == 'l')
6812                         mode = SHOW_PID;
6813                 else
6814                         mode = SHOW_PGID;
6815
6816         out = stdout;
6817         argv = argptr;
6818         if (*argv)
6819                 do
6820                         showjob(out, getjob(*argv,0), mode);
6821                 while (*++argv);
6822         else
6823                 showjobs(out, mode);
6824
6825         return 0;
6826 }
6827
6828
6829 /*
6830  * Print a list of jobs.  If "change" is nonzero, only print jobs whose
6831  * statuses have changed since the last call to showjobs.
6832  */
6833
6834 static void
6835 showjobs(FILE *out, int mode)
6836 {
6837         struct job *jp;
6838
6839         TRACE(("showjobs(%x) called\n", mode));
6840
6841         /* If not even one one job changed, there is nothing to do */
6842         while (dowait(DOWAIT_NORMAL, NULL) > 0)
6843                 continue;
6844
6845         for (jp = curjob; jp; jp = jp->prev_job) {
6846                 if (!(mode & SHOW_CHANGED) || jp->changed)
6847                         showjob(out, jp, mode);
6848         }
6849 }
6850 #endif /* JOBS */
6851
6852 /*
6853  * Mark a job structure as unused.
6854  */
6855
6856 static void
6857 freejob(struct job *jp)
6858 {
6859         struct procstat *ps;
6860         int i;
6861
6862         INTOFF;
6863         for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
6864                 if (ps->cmd != nullstr)
6865                         ckfree(ps->cmd);
6866         }
6867         if (jp->ps != &jp->ps0)
6868                 ckfree(jp->ps);
6869         jp->used = 0;
6870         set_curjob(jp, CUR_DELETE);
6871         INTON;
6872 }
6873
6874
6875 static int
6876 waitcmd(int argc, char **argv)
6877 {
6878         struct job *job;
6879         int retval;
6880         struct job *jp;
6881
6882         EXSIGON();
6883
6884         nextopt(nullstr);
6885         retval = 0;
6886
6887         argv = argptr;
6888         if (!*argv) {
6889                 /* wait for all jobs */
6890                 for (;;) {
6891                         jp = curjob;
6892                         while (1) {
6893                                 if (!jp) {
6894                                         /* no running procs */
6895                                         goto out;
6896                                 }
6897                                 if (jp->state == JOBRUNNING)
6898                                         break;
6899                                 jp->waited = 1;
6900                                 jp = jp->prev_job;
6901                         }
6902                         dowait(DOWAIT_BLOCK, 0);
6903                 }
6904         }
6905
6906         retval = 127;
6907         do {
6908                 if (**argv != '%') {
6909                         pid_t pid = number(*argv);
6910                         job = curjob;
6911                         goto start;
6912                         do {
6913                                 if (job->ps[job->nprocs - 1].pid == pid)
6914                                         break;
6915                                 job = job->prev_job;
6916 start:
6917                                 if (!job)
6918                                         goto repeat;
6919                         } while (1);
6920                 } else
6921                         job = getjob(*argv, 0);
6922                 /* loop until process terminated or stopped */
6923                 while (job->state == JOBRUNNING)
6924                         dowait(DOWAIT_BLOCK, 0);
6925                 job->waited = 1;
6926                 retval = getstatus(job);
6927 repeat:
6928                 ;
6929         } while (*++argv);
6930
6931 out:
6932         return retval;
6933 }
6934
6935
6936 /*
6937  * Convert a job name to a job structure.
6938  */
6939
6940 static struct job *
6941 getjob(const char *name, int getctl)
6942 {
6943         struct job *jp;
6944         struct job *found;
6945         const char *err_msg = "No such job: %s";
6946         unsigned num;
6947         int c;
6948         const char *p;
6949         char *(*match)(const char *, const char *);
6950
6951         jp = curjob;
6952         p = name;
6953         if (!p)
6954                 goto currentjob;
6955
6956         if (*p != '%')
6957                 goto err;
6958
6959         c = *++p;
6960         if (!c)
6961                 goto currentjob;
6962
6963         if (!p[1]) {
6964                 if (c == '+' || c == '%') {
6965 currentjob:
6966                         err_msg = "No current job";
6967                         goto check;
6968                 } else if (c == '-') {
6969                         if (jp)
6970                                 jp = jp->prev_job;
6971                         err_msg = "No previous job";
6972 check:
6973                         if (!jp)
6974                                 goto err;
6975                         goto gotit;
6976                 }
6977         }
6978
6979         if (is_number(p)) {
6980                 num = atoi(p);
6981                 if (num < njobs) {
6982                         jp = jobtab + num - 1;
6983                         if (jp->used)
6984                                 goto gotit;
6985                         goto err;
6986                 }
6987         }
6988
6989         match = prefix;
6990         if (*p == '?') {
6991                 match = strstr;
6992                 p++;
6993         }
6994
6995         found = 0;
6996         while (1) {
6997                 if (!jp)
6998                         goto err;
6999                 if (match(jp->ps[0].cmd, p)) {
7000                         if (found)
7001                                 goto err;
7002                         found = jp;
7003                         err_msg = "%s: ambiguous";
7004                 }
7005                 jp = jp->prev_job;
7006         }
7007
7008 gotit:
7009 #if JOBS
7010         err_msg = "job %s not created under job control";
7011         if (getctl && jp->jobctl == 0)
7012                 goto err;
7013 #endif
7014         return jp;
7015 err:
7016         error(err_msg, name);
7017 }
7018
7019
7020 /*
7021  * Return a new job structure.
7022  * Called with interrupts off.
7023  */
7024
7025 static struct job *
7026 makejob(union node *node, int nprocs)
7027 {
7028         int i;
7029         struct job *jp;
7030
7031         for (i = njobs, jp = jobtab ; ; jp++) {
7032                 if (--i < 0) {
7033                         jp = growjobtab();
7034                         break;
7035                 }
7036                 if (jp->used == 0)
7037                         break;
7038                 if (jp->state != JOBDONE || !jp->waited)
7039                         continue;
7040 #if JOBS
7041                 if (jobctl)
7042                         continue;
7043 #endif
7044                 freejob(jp);
7045                 break;
7046         }
7047         memset(jp, 0, sizeof(*jp));
7048 #if JOBS
7049         if (jobctl)
7050                 jp->jobctl = 1;
7051 #endif
7052         jp->prev_job = curjob;
7053         curjob = jp;
7054         jp->used = 1;
7055         jp->ps = &jp->ps0;
7056         if (nprocs > 1) {
7057                 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
7058         }
7059         TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
7060             jobno(jp)));
7061         return jp;
7062 }
7063
7064 static struct job *
7065 growjobtab(void)
7066 {
7067         size_t len;
7068         ptrdiff_t offset;
7069         struct job *jp, *jq;
7070
7071         len = njobs * sizeof(*jp);
7072         jq = jobtab;
7073         jp = ckrealloc(jq, len + 4 * sizeof(*jp));
7074
7075         offset = (char *)jp - (char *)jq;
7076         if (offset) {
7077                 /* Relocate pointers */
7078                 size_t l = len;
7079
7080                 jq = (struct job *)((char *)jq + l);
7081                 while (l) {
7082                         l -= sizeof(*jp);
7083                         jq--;
7084 #define joff(p) ((struct job *)((char *)(p) + l))
7085 #define jmove(p) (p) = (void *)((char *)(p) + offset)
7086                         if (likely(joff(jp)->ps == &jq->ps0))
7087                                 jmove(joff(jp)->ps);
7088                         if (joff(jp)->prev_job)
7089                                 jmove(joff(jp)->prev_job);
7090                 }
7091                 if (curjob)
7092                         jmove(curjob);
7093 #undef joff
7094 #undef jmove
7095         }
7096
7097         njobs += 4;
7098         jobtab = jp;
7099         jp = (struct job *)((char *)jp + len);
7100         jq = jp + 3;
7101         do {
7102                 jq->used = 0;
7103         } while (--jq >= jp);
7104         return jp;
7105 }
7106
7107
7108 /*
7109  * Fork off a subshell.  If we are doing job control, give the subshell its
7110  * own process group.  Jp is a job structure that the job is to be added to.
7111  * N is the command that will be evaluated by the child.  Both jp and n may
7112  * be NULL.  The mode parameter can be one of the following:
7113  *      FORK_FG - Fork off a foreground process.
7114  *      FORK_BG - Fork off a background process.
7115  *      FORK_NOJOB - Like FORK_FG, but don't give the process its own
7116  *                   process group even if job control is on.
7117  *
7118  * When job control is turned off, background processes have their standard
7119  * input redirected to /dev/null (except for the second and later processes
7120  * in a pipeline).
7121  *
7122  * Called with interrupts off.
7123  */
7124
7125 static inline void
7126 forkchild(struct job *jp, union node *n, int mode)
7127 {
7128         int wasroot;
7129
7130         TRACE(("Child shell %d\n", getpid()));
7131         wasroot = rootshell;
7132         rootshell = 0;
7133
7134         closescript();
7135         clear_traps();
7136 #if JOBS
7137         /* do job control only in root shell */
7138         jobctl = 0;
7139         if (mode != FORK_NOJOB && jp->jobctl && wasroot) {
7140                 pid_t pgrp;
7141
7142                 if (jp->nprocs == 0)
7143                         pgrp = getpid();
7144                 else
7145                         pgrp = jp->ps[0].pid;
7146                 /* This can fail because we are doing it in the parent also */
7147                 (void)setpgid(0, pgrp);
7148                 if (mode == FORK_FG)
7149                         xtcsetpgrp(ttyfd, pgrp);
7150                 setsignal(SIGTSTP);
7151                 setsignal(SIGTTOU);
7152         } else
7153 #endif
7154         if (mode == FORK_BG) {
7155                 ignoresig(SIGINT);
7156                 ignoresig(SIGQUIT);
7157                 if (jp->nprocs == 0) {
7158                         close(0);
7159                         if (open(_PATH_DEVNULL, O_RDONLY) != 0)
7160                                 error("Can't open %s", _PATH_DEVNULL);
7161                 }
7162         }
7163         if (wasroot && iflag) {
7164                 setsignal(SIGINT);
7165                 setsignal(SIGQUIT);
7166                 setsignal(SIGTERM);
7167         }
7168         for (jp = curjob; jp; jp = jp->prev_job)
7169                 freejob(jp);
7170         jobless = 0;
7171 }
7172
7173 static inline void
7174 forkparent(struct job *jp, union node *n, int mode, pid_t pid)
7175 {
7176         TRACE(("In parent shell:  child = %d\n", pid));
7177         if (!jp) {
7178                 while (jobless && dowait(DOWAIT_NORMAL, 0) > 0);
7179                 jobless++;
7180                 return;
7181         }
7182 #if JOBS
7183         if (mode != FORK_NOJOB && jp->jobctl) {
7184                 int pgrp;
7185
7186                 if (jp->nprocs == 0)
7187                         pgrp = pid;
7188                 else
7189                         pgrp = jp->ps[0].pid;
7190                 /* This can fail because we are doing it in the child also */
7191                 (void)setpgid(pid, pgrp);
7192         }
7193 #endif
7194         if (mode == FORK_BG) {
7195                 backgndpid = pid;               /* set $! */
7196                 set_curjob(jp, CUR_RUNNING);
7197         }
7198         if (jp) {
7199                 struct procstat *ps = &jp->ps[jp->nprocs++];
7200                 ps->pid = pid;
7201                 ps->status = -1;
7202                 ps->cmd = nullstr;
7203 #if JOBS
7204                 if (jobctl && n)
7205                         ps->cmd = commandtext(n);
7206 #endif
7207         }
7208 }
7209
7210 static int
7211 forkshell(struct job *jp, union node *n, int mode)
7212 {
7213         int pid;
7214
7215         TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
7216         pid = fork();
7217         if (pid < 0) {
7218                 TRACE(("Fork failed, errno=%d", errno));
7219                 if (jp)
7220                         freejob(jp);
7221                 error("Cannot fork");
7222         }
7223         if (pid == 0)
7224                 forkchild(jp, n, mode);
7225         else
7226                 forkparent(jp, n, mode, pid);
7227         return pid;
7228 }
7229
7230 /*
7231  * Wait for job to finish.
7232  *
7233  * Under job control we have the problem that while a child process is
7234  * running interrupts generated by the user are sent to the child but not
7235  * to the shell.  This means that an infinite loop started by an inter-
7236  * active user may be hard to kill.  With job control turned off, an
7237  * interactive user may place an interactive program inside a loop.  If
7238  * the interactive program catches interrupts, the user doesn't want
7239  * these interrupts to also abort the loop.  The approach we take here
7240  * is to have the shell ignore interrupt signals while waiting for a
7241  * foreground process to terminate, and then send itself an interrupt
7242  * signal if the child process was terminated by an interrupt signal.
7243  * Unfortunately, some programs want to do a bit of cleanup and then
7244  * exit on interrupt; unless these processes terminate themselves by
7245  * sending a signal to themselves (instead of calling exit) they will
7246  * confuse this approach.
7247  *
7248  * Called with interrupts off.
7249  */
7250
7251 int
7252 waitforjob(struct job *jp)
7253 {
7254         int st;
7255
7256         TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
7257         while (jp->state == JOBRUNNING) {
7258                 dowait(DOWAIT_BLOCK, jp);
7259         }
7260         st = getstatus(jp);
7261 #if JOBS
7262         if (jp->jobctl) {
7263                 xtcsetpgrp(ttyfd, rootpid);
7264                 /*
7265                  * This is truly gross.
7266                  * If we're doing job control, then we did a TIOCSPGRP which
7267                  * caused us (the shell) to no longer be in the controlling
7268                  * session -- so we wouldn't have seen any ^C/SIGINT.  So, we
7269                  * intuit from the subprocess exit status whether a SIGINT
7270                  * occurred, and if so interrupt ourselves.  Yuck.  - mycroft
7271                  */
7272                 if (jp->sigint)
7273                         raise(SIGINT);
7274         }
7275         if (jp->state == JOBDONE)
7276 #endif
7277                 freejob(jp);
7278         return st;
7279 }
7280
7281
7282 /*
7283  * Do a wait system call.  If job control is compiled in, we accept
7284  * stopped processes.  If block is zero, we return a value of zero
7285  * rather than blocking.
7286  *
7287  * System V doesn't have a non-blocking wait system call.  It does
7288  * have a SIGCLD signal that is sent to a process when one of it's
7289  * children dies.  The obvious way to use SIGCLD would be to install
7290  * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7291  * was received, and have waitproc bump another counter when it got
7292  * the status of a process.  Waitproc would then know that a wait
7293  * system call would not block if the two counters were different.
7294  * This approach doesn't work because if a process has children that
7295  * have not been waited for, System V will send it a SIGCLD when it
7296  * installs a signal handler for SIGCLD.  What this means is that when
7297  * a child exits, the shell will be sent SIGCLD signals continuously
7298  * until is runs out of stack space, unless it does a wait call before
7299  * restoring the signal handler.  The code below takes advantage of
7300  * this (mis)feature by installing a signal handler for SIGCLD and
7301  * then checking to see whether it was called.  If there are any
7302  * children to be waited for, it will be.
7303  *
7304  * If neither SYSV nor BSD is defined, we don't implement nonblocking
7305  * waits at all.  In this case, the user will not be informed when
7306  * a background process until the next time she runs a real program
7307  * (as opposed to running a builtin command or just typing return),
7308  * and the jobs command may give out of date information.
7309  */
7310
7311 static inline int
7312 waitproc(int block, int *status)
7313 {
7314         int flags = 0;
7315
7316 #if JOBS
7317         if (jobctl)
7318                 flags |= WUNTRACED;
7319 #endif
7320         if (block == 0)
7321                 flags |= WNOHANG;
7322         return wait3(status, flags, (struct rusage *)NULL);
7323 }
7324
7325 /*
7326  * Wait for a process to terminate.
7327  */
7328
7329 static int
7330 dowait(int block, struct job *job)
7331 {
7332         int pid;
7333         int status;
7334         struct job *jp;
7335         struct job *thisjob;
7336         int state;
7337
7338         TRACE(("dowait(%d) called\n", block));
7339         pid = waitproc(block, &status);
7340         TRACE(("wait returns pid %d, status=%d\n", pid, status));
7341         if (pid <= 0)
7342                 return pid;
7343         INTOFF;
7344         thisjob = NULL;
7345         for (jp = curjob; jp; jp = jp->prev_job) {
7346                 struct procstat *sp;
7347                 struct procstat *spend;
7348                 if (jp->state == JOBDONE)
7349                         continue;
7350                 state = JOBDONE;
7351                 spend = jp->ps + jp->nprocs;
7352                 sp = jp->ps;
7353                 do {
7354                         if (sp->pid == pid) {
7355                                 TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status));
7356                                 sp->status = status;
7357                                 thisjob = jp;
7358                         }
7359                         if (sp->status == -1)
7360                                 state = JOBRUNNING;
7361 #ifdef JOBS
7362                         if (state == JOBRUNNING)
7363                                 continue;
7364                         if (WIFSTOPPED(sp->status)) {
7365                                 jp->stopstatus = sp->status;
7366                                 state = JOBSTOPPED;
7367                         }
7368 #endif
7369                 } while (++sp < spend);
7370                 if (thisjob)
7371                         goto gotjob;
7372         }
7373 #ifdef JOBS
7374         if (!WIFSTOPPED(status))
7375 #endif
7376
7377                 jobless--;
7378         goto out;
7379
7380 gotjob:
7381         if (state != JOBRUNNING) {
7382                 thisjob->changed = 1;
7383
7384                 if (thisjob->state != state) {
7385                         TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state));
7386                         thisjob->state = state;
7387 #ifdef JOBS
7388                         if (state == JOBSTOPPED) {
7389                                 set_curjob(thisjob, CUR_STOPPED);
7390                         }
7391 #endif
7392                 }
7393         }
7394
7395 out:
7396         INTON;
7397
7398         if (thisjob && thisjob == job) {
7399                 char s[48 + 1];
7400                 int len;
7401
7402                 len = sprint_status(s, status, 1);
7403                 if (len) {
7404                         s[len] = '\n';
7405                         s[len + 1] = 0;
7406                         out2str(s);
7407                 }
7408         }
7409         return pid;
7410 }
7411
7412
7413 /*
7414  * return 1 if there are stopped jobs, otherwise 0
7415  */
7416
7417 int
7418 stoppedjobs(void)
7419 {
7420         struct job *jp;
7421         int retval;
7422
7423         retval = 0;
7424         if (job_warning)
7425                 goto out;
7426         jp = curjob;
7427         if (jp && jp->state == JOBSTOPPED) {
7428                 out2str("You have stopped jobs.\n");
7429                 job_warning = 2;
7430                 retval++;
7431         }
7432
7433 out:
7434         return retval;
7435 }
7436
7437 /*
7438  * Return a string identifying a command (to be printed by the
7439  * jobs command).
7440  */
7441
7442 #if JOBS
7443 static char *cmdnextc;
7444
7445 static char *
7446 commandtext(union node *n)
7447 {
7448         char *name;
7449
7450         STARTSTACKSTR(cmdnextc);
7451         cmdtxt(n);
7452         name = stackblock();
7453         TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
7454                 name, cmdnextc, cmdnextc));
7455         return savestr(name);
7456 }
7457
7458 static void
7459 cmdtxt(union node *n)
7460 {
7461         union node *np;
7462         struct nodelist *lp;
7463         const char *p;
7464         char s[2];
7465
7466         if (!n)
7467                 return;
7468         switch (n->type) {
7469         default:
7470 #if DEBUG
7471                 abort();
7472 #endif
7473         case NPIPE:
7474                 lp = n->npipe.cmdlist;
7475                 for (;;) {
7476                         cmdtxt(lp->n);
7477                         lp = lp->next;
7478                         if (!lp)
7479                                 break;
7480                         cmdputs(" | ");
7481                 }
7482                 break;
7483         case NSEMI:
7484                 p = "; ";
7485                 goto binop;
7486         case NAND:
7487                 p = " && ";
7488                 goto binop;
7489         case NOR:
7490                 p = " || ";
7491 binop:
7492                 cmdtxt(n->nbinary.ch1);
7493                 cmdputs(p);
7494                 n = n->nbinary.ch2;
7495                 goto donode;
7496         case NREDIR:
7497         case NBACKGND:
7498                 n = n->nredir.n;
7499                 goto donode;
7500         case NNOT:
7501                 cmdputs("!");
7502                 n = n->nnot.com;
7503 donode:
7504                 cmdtxt(n);
7505                 break;
7506         case NIF:
7507                 cmdputs("if ");
7508                 cmdtxt(n->nif.test);
7509                 cmdputs("; then ");
7510                 n = n->nif.ifpart;
7511                 if (n->nif.elsepart) {
7512                         cmdtxt(n);
7513                         cmdputs("; else ");
7514                         n = n->nif.elsepart;
7515                 }
7516                 p = "; fi";
7517                 goto dotail;
7518         case NSUBSHELL:
7519                 cmdputs("(");
7520                 n = n->nredir.n;
7521                 p = ")";
7522                 goto dotail;
7523         case NWHILE:
7524                 p = "while ";
7525                 goto until;
7526         case NUNTIL:
7527                 p = "until ";
7528 until:
7529                 cmdputs(p);
7530                 cmdtxt(n->nbinary.ch1);
7531                 n = n->nbinary.ch2;
7532                 p = "; done";
7533 dodo:
7534                 cmdputs("; do ");
7535 dotail:
7536                 cmdtxt(n);
7537                 goto dotail2;
7538         case NFOR:
7539                 cmdputs("for ");
7540                 cmdputs(n->nfor.var);
7541                 cmdputs(" in ");
7542                 cmdlist(n->nfor.args, 1);
7543                 n = n->nfor.body;
7544                 p = "; done";
7545                 goto dodo;
7546         case NDEFUN:
7547                 cmdputs(n->narg.text);
7548                 p = "() { ... }";
7549                 goto dotail2;
7550         case NCMD:
7551                 cmdlist(n->ncmd.args, 1);
7552                 cmdlist(n->ncmd.redirect, 0);
7553                 break;
7554         case NARG:
7555                 p = n->narg.text;
7556 dotail2:
7557                 cmdputs(p);
7558                 break;
7559         case NHERE:
7560         case NXHERE:
7561                 p = "<<...";
7562                 goto dotail2;
7563         case NCASE:
7564                 cmdputs("case ");
7565                 cmdputs(n->ncase.expr->narg.text);
7566                 cmdputs(" in ");
7567                 for (np = n->ncase.cases; np; np = np->nclist.next) {
7568                         cmdtxt(np->nclist.pattern);
7569                         cmdputs(") ");
7570                         cmdtxt(np->nclist.body);
7571                         cmdputs(";; ");
7572                 }
7573                 p = "esac";
7574                 goto dotail2;
7575         case NTO:
7576                 p = ">";
7577                 goto redir;
7578         case NCLOBBER:
7579                 p = ">|";
7580                 goto redir;
7581         case NAPPEND:
7582                 p = ">>";
7583                 goto redir;
7584         case NTOFD:
7585                 p = ">&";
7586                 goto redir;
7587         case NFROM:
7588                 p = "<";
7589                 goto redir;
7590         case NFROMFD:
7591                 p = "<&";
7592                 goto redir;
7593         case NFROMTO:
7594                 p = "<>";
7595 redir:
7596                 s[0] = n->nfile.fd + '0';
7597                 s[1] = '\0';
7598                 cmdputs(s);
7599                 cmdputs(p);
7600                 if (n->type == NTOFD || n->type == NFROMFD) {
7601                         s[0] = n->ndup.dupfd + '0';
7602                         p = s;
7603                         goto dotail2;
7604                 } else {
7605                         n = n->nfile.fname;
7606                         goto donode;
7607                 }
7608         }
7609 }
7610
7611 static void
7612 cmdlist(union node *np, int sep)
7613 {
7614         for (; np; np = np->narg.next) {
7615                 if (!sep)
7616                         cmdputs(spcstr);
7617                 cmdtxt(np);
7618                 if (sep && np->narg.next)
7619                         cmdputs(spcstr);
7620         }
7621 }
7622
7623 static void
7624 cmdputs(const char *s)
7625 {
7626         const char *p, *str;
7627         char c, cc[2] = " ";
7628         char *nextc;
7629         int subtype = 0;
7630         int quoted = 0;
7631         static const char *const vstype[16] = {
7632                 nullstr, "}", "-", "+", "?", "=",
7633                 "%", "%%", "#", "##", nullstr
7634         };
7635
7636         nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
7637         p = s;
7638         while ((c = *p++) != 0) {
7639                 str = 0;
7640                 switch (c) {
7641                 case CTLESC:
7642                         c = *p++;
7643                         break;
7644                 case CTLVAR:
7645                         subtype = *p++;
7646                         if ((subtype & VSTYPE) == VSLENGTH)
7647                                 str = "${#";
7648                         else
7649                                 str = "${";
7650                         if (!(subtype & VSQUOTE) != !(quoted & 1)) {
7651                                 quoted ^= 1;
7652                                 c = '"';
7653                         } else
7654                                 goto dostr;
7655                         break;
7656                 case CTLENDVAR:
7657                         quoted >>= 1;
7658                         subtype = 0;
7659                         if (quoted & 1) {
7660                                 str = "\"}";
7661                                 goto dostr;
7662                         }
7663                         c = '}';
7664                         break;
7665                 case CTLBACKQ:
7666                         str = "$(...)";
7667                         goto dostr;
7668                 case CTLBACKQ+CTLQUOTE:
7669                         str = "\"$(...)\"";
7670                         goto dostr;
7671 #ifdef CONFIG_ASH_MATH_SUPPORT
7672                 case CTLARI:
7673                         str = "$((";
7674                         goto dostr;
7675                 case CTLENDARI:
7676                         str = "))";
7677                         goto dostr;
7678 #endif
7679                 case CTLQUOTEMARK:
7680                         quoted ^= 1;
7681                         c = '"';
7682                         break;
7683                 case '=':
7684                         if (subtype == 0)
7685                                 break;
7686                         str = vstype[subtype & VSTYPE];
7687                         if (subtype & VSNUL)
7688                                 c = ':';
7689                         else
7690                                 c = *str++;
7691                         if (c != '}')
7692                                 quoted <<= 1;
7693                         break;
7694                 case '\'':
7695                 case '\\':
7696                 case '"':
7697                 case '$':
7698                         /* These can only happen inside quotes */
7699                         cc[0] = c;
7700                         str = cc;
7701                         c = '\\';
7702                         break;
7703                 default:
7704                         break;
7705                 }
7706                 USTPUTC(c, nextc);
7707                 if (!str)
7708                         continue;
7709 dostr:
7710                 while ((c = *str++)) {
7711                         USTPUTC(c, nextc);
7712                 }
7713         }
7714         if (quoted & 1) {
7715                 USTPUTC('"', nextc);
7716         }
7717         *nextc = 0;
7718         cmdnextc = nextc;
7719 }
7720
7721
7722 static void
7723 showpipe(struct job *jp, FILE *out)
7724 {
7725         struct procstat *sp;
7726         struct procstat *spend;
7727
7728         spend = jp->ps + jp->nprocs;
7729         for (sp = jp->ps + 1; sp < spend; sp++)
7730                 fprintf(out, " | %s", sp->cmd);
7731         outcslow('\n', out);
7732         flushall();
7733 }
7734
7735 static void
7736 xtcsetpgrp(int fd, pid_t pgrp)
7737 {
7738         if (tcsetpgrp(fd, pgrp))
7739                 error("Cannot set tty process group (%m)");
7740 }
7741 #endif /* JOBS */
7742
7743 static int
7744 getstatus(struct job *job) {
7745         int status;
7746         int retval;
7747
7748         status = job->ps[job->nprocs - 1].status;
7749         retval = WEXITSTATUS(status);
7750         if (!WIFEXITED(status)) {
7751 #if JOBS
7752                 retval = WSTOPSIG(status);
7753                 if (!WIFSTOPPED(status))
7754 #endif
7755                 {
7756                         /* XXX: limits number of signals */
7757                         retval = WTERMSIG(status);
7758 #if JOBS
7759                         if (retval == SIGINT)
7760                                 job->sigint = 1;
7761 #endif
7762                 }
7763                 retval += 128;
7764         }
7765         TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n",
7766                 jobno(job), job->nprocs, status, retval));
7767         return retval;
7768 }
7769
7770 #ifdef CONFIG_ASH_MAIL
7771 /*      $NetBSD: mail.c,v 1.15 2002/11/24 22:35:40 christos Exp $       */
7772
7773 /*
7774  * Routines to check for mail.  (Perhaps make part of main.c?)
7775  */
7776
7777 #define MAXMBOXES 10
7778
7779 /* times of mailboxes */
7780 static time_t mailtime[MAXMBOXES];
7781 /* Set if MAIL or MAILPATH is changed. */
7782 static int mail_var_path_changed;
7783
7784
7785
7786 /*
7787  * Print appropriate message(s) if mail has arrived.
7788  * If mail_var_path_changed is set,
7789  * then the value of MAIL has mail_var_path_changed,
7790  * so we just update the values.
7791  */
7792
7793 static void
7794 chkmail(void)
7795 {
7796         const char *mpath;
7797         char *p;
7798         char *q;
7799         time_t *mtp;
7800         struct stackmark smark;
7801         struct stat statb;
7802
7803         setstackmark(&smark);
7804         mpath = mpathset() ? mpathval() : mailval();
7805         for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
7806                 p = padvance(&mpath, nullstr);
7807                 if (p == NULL)
7808                         break;
7809                 if (*p == '\0')
7810                         continue;
7811                 for (q = p ; *q ; q++);
7812 #ifdef DEBUG
7813                 if (q[-1] != '/')
7814                         abort();
7815 #endif
7816                 q[-1] = '\0';                   /* delete trailing '/' */
7817                 if (stat(p, &statb) < 0) {
7818                         *mtp = 0;
7819                         continue;
7820                 }
7821                 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
7822                         fprintf(
7823                                 stderr, snlfmt,
7824                                 pathopt ? pathopt : "you have mail"
7825                         );
7826                 }
7827                 *mtp = statb.st_mtime;
7828         }
7829         mail_var_path_changed = 0;
7830         popstackmark(&smark);
7831 }
7832
7833
7834 static void
7835 changemail(const char *val)
7836 {
7837         mail_var_path_changed++;
7838 }
7839
7840 #endif /* CONFIG_ASH_MAIL */
7841
7842 /*      $NetBSD: main.c,v 1.46 2002/12/11 19:12:18 christos Exp $       */
7843
7844
7845 #if PROFILE
7846 static short profile_buf[16384];
7847 extern int etext();
7848 #endif
7849
7850 static int isloginsh;
7851
7852 static void read_profile(const char *);
7853
7854 /*
7855  * Main routine.  We initialize things, parse the arguments, execute
7856  * profiles if we're a login shell, and then call cmdloop to execute
7857  * commands.  The setjmp call sets up the location to jump to when an
7858  * exception occurs.  When an exception occurs the variable "state"
7859  * is used to figure out how far we had gotten.
7860  */
7861
7862 int
7863 ash_main(int argc, char **argv)
7864 {
7865         char *shinit;
7866         volatile int state;
7867         struct jmploc jmploc;
7868         struct stackmark smark;
7869
7870 #ifdef __GLIBC__
7871         dash_errno = __errno_location();
7872 #endif
7873
7874 #if PROFILE
7875         monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7876 #endif
7877         state = 0;
7878         if (setjmp(jmploc.loc)) {
7879                 int status;
7880                 int e;
7881
7882                 reset();
7883
7884                 e = exception;
7885                 switch (exception) {
7886                 case EXEXEC:
7887                         status = exerrno;
7888                         break;
7889
7890                 case EXERROR:
7891                         status = 2;
7892                         break;
7893
7894                 default:
7895                         status = exitstatus;
7896                         break;
7897                 }
7898                 exitstatus = status;
7899
7900                 if (e == EXEXIT || state == 0 || iflag == 0 || ! rootshell)
7901                         exitshell();
7902
7903                 if (e == EXINT) {
7904                         outcslow('\n', stderr);
7905                 }
7906                 popstackmark(&smark);
7907                 FORCEINTON;                             /* enable interrupts */
7908                 if (state == 1)
7909                         goto state1;
7910                 else if (state == 2)
7911                         goto state2;
7912                 else if (state == 3)
7913                         goto state3;
7914                 else
7915                         goto state4;
7916         }
7917         handler = &jmploc;
7918 #ifdef DEBUG
7919         opentrace();
7920         trputs("Shell args:  ");  trargs(argv);
7921 #endif
7922         rootpid = getpid();
7923
7924 #ifdef CONFIG_ASH_RANDOM_SUPPORT
7925         rseed = rootpid + ((time_t)time((time_t *)0));
7926 #endif
7927         rootshell = 1;
7928         init();
7929         setstackmark(&smark);
7930         procargs(argc, argv);
7931 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7932         if ( iflag ) {
7933                 const char *hp = lookupvar("HISTFILE");
7934
7935                 if(hp == NULL ) {
7936                         hp = lookupvar("HOME");
7937                         if(hp != NULL) {
7938                                 char *defhp = concat_path_file(hp, ".ash_history");
7939                                 setvar("HISTFILE", defhp, 0);
7940                                 free(defhp);
7941                         }
7942                 }
7943         }
7944 #endif
7945         if (argv[0] && argv[0][0] == '-')
7946                 isloginsh = 1;
7947         if (isloginsh) {
7948                 state = 1;
7949                 read_profile("/etc/profile");
7950 state1:
7951                 state = 2;
7952                 read_profile(".profile");
7953         }
7954 state2:
7955         state = 3;
7956         if (
7957 #ifndef linux
7958                 getuid() == geteuid() && getgid() == getegid() &&
7959 #endif
7960                 iflag
7961         ) {
7962                 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
7963                         read_profile(shinit);
7964                 }
7965         }
7966 state3:
7967         state = 4;
7968         if (minusc)
7969                 evalstring(minusc);
7970
7971         if (sflag || minusc == NULL) {
7972 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
7973             if ( iflag ) {
7974                 const char *hp = lookupvar("HISTFILE");
7975
7976                 if(hp != NULL )
7977                         load_history ( hp );
7978             }
7979 #endif
7980 state4: /* XXX ??? - why isn't this before the "if" statement */
7981                 cmdloop(1);
7982         }
7983 #if PROFILE
7984         monitor(0);
7985 #endif
7986 #if GPROF
7987         {
7988                 extern void _mcleanup(void);
7989                 _mcleanup();
7990         }
7991 #endif
7992         exitshell();
7993         /* NOTREACHED */
7994 }
7995
7996
7997 /*
7998  * Read and execute commands.  "Top" is nonzero for the top level command
7999  * loop; it turns on prompting if the shell is interactive.
8000  */
8001
8002 static void
8003 cmdloop(int top)
8004 {
8005         union node *n;
8006         struct stackmark smark;
8007         int inter;
8008         int numeof = 0;
8009
8010         TRACE(("cmdloop(%d) called\n", top));
8011         for (;;) {
8012                 setstackmark(&smark);
8013                 if (pendingsigs)
8014                         dotrap();
8015 #if JOBS
8016                 if (jobctl)
8017                         showjobs(stderr, SHOW_CHANGED);
8018 #endif
8019                 inter = 0;
8020                 if (iflag && top) {
8021                         inter++;
8022 #ifdef CONFIG_ASH_MAIL
8023                         chkmail();
8024 #endif
8025                 }
8026                 n = parsecmd(inter);
8027                 /* showtree(n); DEBUG */
8028                 if (n == NEOF) {
8029                         if (!top || numeof >= 50)
8030                                 break;
8031                         if (!stoppedjobs()) {
8032                                 if (!Iflag)
8033                                         break;
8034                                 out2str("\nUse \"exit\" to leave shell.\n");
8035                         }
8036                         numeof++;
8037                 } else if (n != NULL && nflag == 0) {
8038                         job_warning = (job_warning == 2) ? 1 : 0;
8039                         numeof = 0;
8040                         evaltree(n, 0);
8041                 }
8042                 popstackmark(&smark);
8043                 if (evalskip) {
8044                         evalskip = 0;
8045                         break;
8046                 }
8047         }
8048 }
8049
8050
8051 /*
8052  * Read /etc/profile or .profile.  Return on error.
8053  */
8054
8055 static void
8056 read_profile(const char *name)
8057 {
8058         int fd;
8059         int xflag_set = 0;
8060         int vflag_set = 0;
8061
8062         INTOFF;
8063         if ((fd = open(name, O_RDONLY)) >= 0)
8064                 setinputfd(fd, 1);
8065         INTON;
8066         if (fd < 0)
8067                 return;
8068         /* -q turns off -x and -v just when executing init files */
8069         if (qflag)  {
8070             if (xflag)
8071                     xflag = 0, xflag_set = 1;
8072             if (vflag)
8073                     vflag = 0, vflag_set = 1;
8074         }
8075         cmdloop(0);
8076         if (qflag)  {
8077             if (xflag_set)
8078                     xflag = 1;
8079             if (vflag_set)
8080                     vflag = 1;
8081         }
8082         popfile();
8083 }
8084
8085
8086 /*
8087  * Read a file containing shell functions.
8088  */
8089
8090 static void
8091 readcmdfile(char *name)
8092 {
8093         int fd;
8094
8095         INTOFF;
8096         if ((fd = open(name, O_RDONLY)) >= 0)
8097                 setinputfd(fd, 1);
8098         else
8099                 error("Can't open %s", name);
8100         INTON;
8101         cmdloop(0);
8102         popfile();
8103 }
8104
8105
8106 /*
8107  * Take commands from a file.  To be compatible we should do a path
8108  * search for the file, which is necessary to find sub-commands.
8109  */
8110
8111 static inline char *
8112 find_dot_file(char *name)
8113 {
8114         char *fullname;
8115         const char *path = pathval();
8116         struct stat statb;
8117
8118         /* don't try this for absolute or relative paths */
8119         if (strchr(name, '/'))
8120                 return name;
8121
8122         while ((fullname = padvance(&path, name)) != NULL) {
8123                 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
8124                         /*
8125                          * Don't bother freeing here, since it will
8126                          * be freed by the caller.
8127                          */
8128                         return fullname;
8129                 }
8130                 stunalloc(fullname);
8131         }
8132
8133         /* not found in the PATH */
8134         error(not_found_msg, name);
8135         /* NOTREACHED */
8136 }
8137
8138 static int dotcmd(int argc, char **argv)
8139 {
8140         struct strlist *sp;
8141         volatile struct shparam saveparam;
8142
8143         exitstatus = 0;
8144
8145         for (sp = cmdenviron; sp; sp = sp->next)
8146                 setvareq(bb_xstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
8147
8148         if (argc >= 2) {        /* That's what SVR2 does */
8149                 char *fullname;
8150                 struct stackmark smark;
8151
8152                 setstackmark(&smark);
8153                 fullname = find_dot_file(argv[1]);
8154
8155                 if (argc > 2) {
8156                         saveparam = shellparam;
8157                         shellparam.malloc = 0;
8158                         shellparam.nparam = argc - 2;
8159                         shellparam.p = argv + 2;
8160                 };
8161
8162                 setinputfile(fullname, 1);
8163                 commandname = fullname;
8164                 cmdloop(0);
8165                 popfile();
8166
8167                 if (argc > 2) {
8168                         freeparam(&shellparam);
8169                         shellparam = saveparam;
8170                 };
8171
8172                 popstackmark(&smark);
8173         }
8174         return exitstatus;
8175 }
8176
8177
8178 static int
8179 exitcmd(int argc, char **argv)
8180 {
8181         if (stoppedjobs())
8182                 return 0;
8183         if (argc > 1)
8184                 exitstatus = number(argv[1]);
8185         exraise(EXEXIT);
8186         /* NOTREACHED */
8187 }
8188
8189 /*      $NetBSD: memalloc.c,v 1.27 2003/01/22 20:36:04 dsl Exp $        */
8190
8191 /*
8192  * Same for malloc, realloc, but returns an error when out of space.
8193  */
8194
8195 static pointer
8196 ckrealloc(pointer p, size_t nbytes)
8197 {
8198         p = realloc(p, nbytes);
8199         if (p == NULL)
8200                 error(bb_msg_memory_exhausted);
8201         return p;
8202 }
8203
8204 static pointer
8205 ckmalloc(size_t nbytes)
8206 {
8207         return ckrealloc(NULL, nbytes);
8208 }
8209
8210 /*
8211  * Make a copy of a string in safe storage.
8212  */
8213
8214 static char *
8215 savestr(const char *s)
8216 {
8217         char *p = strdup(s);
8218         if (!p)
8219                 error(bb_msg_memory_exhausted);
8220         return p;
8221 }
8222
8223
8224 /*
8225  * Parse trees for commands are allocated in lifo order, so we use a stack
8226  * to make this more efficient, and also to avoid all sorts of exception
8227  * handling code to handle interrupts in the middle of a parse.
8228  *
8229  * The size 504 was chosen because the Ultrix malloc handles that size
8230  * well.
8231  */
8232
8233
8234 static pointer
8235 stalloc(size_t nbytes)
8236 {
8237         char *p;
8238         size_t aligned;
8239
8240         aligned = SHELL_ALIGN(nbytes);
8241         if (aligned > stacknleft) {
8242                 size_t len;
8243                 size_t blocksize;
8244                 struct stack_block *sp;
8245
8246                 blocksize = aligned;
8247                 if (blocksize < MINSIZE)
8248                         blocksize = MINSIZE;
8249                 len = sizeof(struct stack_block) - MINSIZE + blocksize;
8250                 if (len < blocksize)
8251                         error(bb_msg_memory_exhausted);
8252                 INTOFF;
8253                 sp = ckmalloc(len);
8254                 sp->prev = stackp;
8255                 stacknxt = sp->space;
8256                 stacknleft = blocksize;
8257                 sstrend = stacknxt + blocksize;
8258                 stackp = sp;
8259                 INTON;
8260         }
8261         p = stacknxt;
8262         stacknxt += aligned;
8263         stacknleft -= aligned;
8264         return p;
8265 }
8266
8267
8268 void
8269 stunalloc(pointer p)
8270 {
8271 #ifdef DEBUG
8272         if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) {
8273                 write(2, "stunalloc\n", 10);
8274                 abort();
8275         }
8276 #endif
8277         stacknleft += stacknxt - (char *)p;
8278         stacknxt = p;
8279 }
8280
8281
8282 void
8283 setstackmark(struct stackmark *mark)
8284 {
8285         mark->stackp = stackp;
8286         mark->stacknxt = stacknxt;
8287         mark->stacknleft = stacknleft;
8288         mark->marknext = markp;
8289         markp = mark;
8290 }
8291
8292
8293 void
8294 popstackmark(struct stackmark *mark)
8295 {
8296         struct stack_block *sp;
8297
8298         INTOFF;
8299         markp = mark->marknext;
8300         while (stackp != mark->stackp) {
8301                 sp = stackp;
8302                 stackp = sp->prev;
8303                 ckfree(sp);
8304         }
8305         stacknxt = mark->stacknxt;
8306         stacknleft = mark->stacknleft;
8307         sstrend = mark->stacknxt + mark->stacknleft;
8308         INTON;
8309 }
8310
8311
8312 /*
8313  * When the parser reads in a string, it wants to stick the string on the
8314  * stack and only adjust the stack pointer when it knows how big the
8315  * string is.  Stackblock (defined in stack.h) returns a pointer to a block
8316  * of space on top of the stack and stackblocklen returns the length of
8317  * this block.  Growstackblock will grow this space by at least one byte,
8318  * possibly moving it (like realloc).  Grabstackblock actually allocates the
8319  * part of the block that has been used.
8320  */
8321
8322 void
8323 growstackblock(void)
8324 {
8325         size_t newlen;
8326
8327         newlen = stacknleft * 2;
8328         if (newlen < stacknleft)
8329                 error(bb_msg_memory_exhausted);
8330         if (newlen < 128)
8331                 newlen += 128;
8332
8333         if (stacknxt == stackp->space && stackp != &stackbase) {
8334                 struct stack_block *oldstackp;
8335                 struct stackmark *xmark;
8336                 struct stack_block *sp;
8337                 struct stack_block *prevstackp;
8338                 size_t grosslen;
8339
8340                 INTOFF;
8341                 oldstackp = stackp;
8342                 sp = stackp;
8343                 prevstackp = sp->prev;
8344                 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
8345                 sp = ckrealloc((pointer)sp, grosslen);
8346                 sp->prev = prevstackp;
8347                 stackp = sp;
8348                 stacknxt = sp->space;
8349                 stacknleft = newlen;
8350                 sstrend = sp->space + newlen;
8351
8352                 /*
8353                  * Stack marks pointing to the start of the old block
8354                  * must be relocated to point to the new block
8355                  */
8356                 xmark = markp;
8357                 while (xmark != NULL && xmark->stackp == oldstackp) {
8358                         xmark->stackp = stackp;
8359                         xmark->stacknxt = stacknxt;
8360                         xmark->stacknleft = stacknleft;
8361                         xmark = xmark->marknext;
8362                 }
8363                 INTON;
8364         } else {
8365                 char *oldspace = stacknxt;
8366                 int oldlen = stacknleft;
8367                 char *p = stalloc(newlen);
8368
8369                 /* free the space we just allocated */
8370                 stacknxt = memcpy(p, oldspace, oldlen);
8371                 stacknleft += newlen;
8372         }
8373 }
8374
8375 static inline void
8376 grabstackblock(size_t len)
8377 {
8378         len = SHELL_ALIGN(len);
8379         stacknxt += len;
8380         stacknleft -= len;
8381 }
8382
8383 /*
8384  * The following routines are somewhat easier to use than the above.
8385  * The user declares a variable of type STACKSTR, which may be declared
8386  * to be a register.  The macro STARTSTACKSTR initializes things.  Then
8387  * the user uses the macro STPUTC to add characters to the string.  In
8388  * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8389  * grown as necessary.  When the user is done, she can just leave the
8390  * string there and refer to it using stackblock().  Or she can allocate
8391  * the space for it using grabstackstr().  If it is necessary to allow
8392  * someone else to use the stack temporarily and then continue to grow
8393  * the string, the user should use grabstack to allocate the space, and
8394  * then call ungrabstr(p) to return to the previous mode of operation.
8395  *
8396  * USTPUTC is like STPUTC except that it doesn't check for overflow.
8397  * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8398  * is space for at least one character.
8399  */
8400
8401 void *
8402 growstackstr(void)
8403 {
8404         size_t len = stackblocksize();
8405         if (herefd >= 0 && len >= 1024) {
8406                 bb_full_write(herefd, stackblock(), len);
8407                 return stackblock();
8408         }
8409         growstackblock();
8410         return stackblock() + len;
8411 }
8412
8413 /*
8414  * Called from CHECKSTRSPACE.
8415  */
8416
8417 char *
8418 makestrspace(size_t newlen, char *p)
8419 {
8420         size_t len = p - stacknxt;
8421         size_t size = stackblocksize();
8422
8423         for (;;) {
8424                 size_t nleft;
8425
8426                 size = stackblocksize();
8427                 nleft = size - len;
8428                 if (nleft >= newlen)
8429                         break;
8430                 growstackblock();
8431         }
8432         return stackblock() + len;
8433 }
8434
8435 char *
8436 stnputs(const char *s, size_t n, char *p)
8437 {
8438         p = makestrspace(n, p);
8439         p = mempcpy(p, s, n);
8440         return p;
8441 }
8442
8443 char *
8444 stputs(const char *s, char *p)
8445 {
8446         return stnputs(s, strlen(s), p);
8447 }
8448
8449 /*      $NetBSD: mystring.c,v 1.15 2002/11/24 22:35:42 christos Exp $   */
8450
8451 /*
8452  * String functions.
8453  *
8454  *      number(s)               Convert a string of digits to an integer.
8455  *      is_number(s)            Return true if s is a string of digits.
8456  */
8457
8458 /*
8459  * prefix -- see if pfx is a prefix of string.
8460  */
8461
8462 char *
8463 prefix(const char *string, const char *pfx)
8464 {
8465         while (*pfx) {
8466                 if (*pfx++ != *string++)
8467                         return 0;
8468         }
8469         return (char *) string;
8470 }
8471
8472
8473 /*
8474  * Convert a string of digits to an integer, printing an error message on
8475  * failure.
8476  */
8477
8478 int
8479 number(const char *s)
8480 {
8481
8482         if (! is_number(s))
8483                 error(illnum, s);
8484         return atoi(s);
8485 }
8486
8487
8488 /*
8489  * Check for a valid number.  This should be elsewhere.
8490  */
8491
8492 int
8493 is_number(const char *p)
8494 {
8495         do {
8496                 if (! is_digit(*p))
8497                         return 0;
8498         } while (*++p != '\0');
8499         return 1;
8500 }
8501
8502
8503 /*
8504  * Produce a possibly single quoted string suitable as input to the shell.
8505  * The return string is allocated on the stack.
8506  */
8507
8508 char *
8509 single_quote(const char *s) {
8510         char *p;
8511
8512         STARTSTACKSTR(p);
8513
8514         do {
8515                 char *q;
8516                 size_t len;
8517
8518                 len = strchrnul(s, '\'') - s;
8519
8520                 q = p = makestrspace(len + 3, p);
8521
8522                 *q++ = '\'';
8523                 q = mempcpy(q, s, len);
8524                 *q++ = '\'';
8525                 s += len;
8526
8527                 STADJUST(q - p, p);
8528
8529                 len = strspn(s, "'");
8530                 if (!len)
8531                         break;
8532
8533                 q = p = makestrspace(len + 3, p);
8534
8535                 *q++ = '"';
8536                 q = mempcpy(q, s, len);
8537                 *q++ = '"';
8538                 s += len;
8539
8540                 STADJUST(q - p, p);
8541         } while (*s);
8542
8543         USTPUTC(0, p);
8544
8545         return stackblock();
8546 }
8547
8548 /*
8549  * Like strdup but works with the ash stack.
8550  */
8551
8552 char *
8553 sstrdup(const char *p)
8554 {
8555         size_t len = strlen(p) + 1;
8556         return memcpy(stalloc(len), p, len);
8557 }
8558
8559
8560 static void
8561 calcsize(union node *n)
8562 {
8563       if (n == NULL)
8564             return;
8565       funcblocksize += nodesize[n->type];
8566       switch (n->type) {
8567       case NCMD:
8568             calcsize(n->ncmd.redirect);
8569             calcsize(n->ncmd.args);
8570             calcsize(n->ncmd.assign);
8571             break;
8572       case NPIPE:
8573             sizenodelist(n->npipe.cmdlist);
8574             break;
8575       case NREDIR:
8576       case NBACKGND:
8577       case NSUBSHELL:
8578             calcsize(n->nredir.redirect);
8579             calcsize(n->nredir.n);
8580             break;
8581       case NAND:
8582       case NOR:
8583       case NSEMI:
8584       case NWHILE:
8585       case NUNTIL:
8586             calcsize(n->nbinary.ch2);
8587             calcsize(n->nbinary.ch1);
8588             break;
8589       case NIF:
8590             calcsize(n->nif.elsepart);
8591             calcsize(n->nif.ifpart);
8592             calcsize(n->nif.test);
8593             break;
8594       case NFOR:
8595             funcstringsize += strlen(n->nfor.var) + 1;
8596             calcsize(n->nfor.body);
8597             calcsize(n->nfor.args);
8598             break;
8599       case NCASE:
8600             calcsize(n->ncase.cases);
8601             calcsize(n->ncase.expr);
8602             break;
8603       case NCLIST:
8604             calcsize(n->nclist.body);
8605             calcsize(n->nclist.pattern);
8606             calcsize(n->nclist.next);
8607             break;
8608       case NDEFUN:
8609       case NARG:
8610             sizenodelist(n->narg.backquote);
8611             funcstringsize += strlen(n->narg.text) + 1;
8612             calcsize(n->narg.next);
8613             break;
8614       case NTO:
8615       case NCLOBBER:
8616       case NFROM:
8617       case NFROMTO:
8618       case NAPPEND:
8619             calcsize(n->nfile.fname);
8620             calcsize(n->nfile.next);
8621             break;
8622       case NTOFD:
8623       case NFROMFD:
8624             calcsize(n->ndup.vname);
8625             calcsize(n->ndup.next);
8626             break;
8627       case NHERE:
8628       case NXHERE:
8629             calcsize(n->nhere.doc);
8630             calcsize(n->nhere.next);
8631             break;
8632       case NNOT:
8633             calcsize(n->nnot.com);
8634             break;
8635       };
8636 }
8637
8638
8639 static void
8640 sizenodelist(struct nodelist *lp)
8641 {
8642         while (lp) {
8643                 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8644                 calcsize(lp->n);
8645                 lp = lp->next;
8646         }
8647 }
8648
8649
8650 static union node *
8651 copynode(union node *n)
8652 {
8653       union node *new;
8654
8655       if (n == NULL)
8656             return NULL;
8657       new = funcblock;
8658       funcblock = (char *) funcblock + nodesize[n->type];
8659       switch (n->type) {
8660       case NCMD:
8661             new->ncmd.redirect = copynode(n->ncmd.redirect);
8662             new->ncmd.args = copynode(n->ncmd.args);
8663             new->ncmd.assign = copynode(n->ncmd.assign);
8664             break;
8665       case NPIPE:
8666             new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8667             new->npipe.backgnd = n->npipe.backgnd;
8668             break;
8669       case NREDIR:
8670       case NBACKGND:
8671       case NSUBSHELL:
8672             new->nredir.redirect = copynode(n->nredir.redirect);
8673             new->nredir.n = copynode(n->nredir.n);
8674             break;
8675       case NAND:
8676       case NOR:
8677       case NSEMI:
8678       case NWHILE:
8679       case NUNTIL:
8680             new->nbinary.ch2 = copynode(n->nbinary.ch2);
8681             new->nbinary.ch1 = copynode(n->nbinary.ch1);
8682             break;
8683       case NIF:
8684             new->nif.elsepart = copynode(n->nif.elsepart);
8685             new->nif.ifpart = copynode(n->nif.ifpart);
8686             new->nif.test = copynode(n->nif.test);
8687             break;
8688       case NFOR:
8689             new->nfor.var = nodesavestr(n->nfor.var);
8690             new->nfor.body = copynode(n->nfor.body);
8691             new->nfor.args = copynode(n->nfor.args);
8692             break;
8693       case NCASE:
8694             new->ncase.cases = copynode(n->ncase.cases);
8695             new->ncase.expr = copynode(n->ncase.expr);
8696             break;
8697       case NCLIST:
8698             new->nclist.body = copynode(n->nclist.body);
8699             new->nclist.pattern = copynode(n->nclist.pattern);
8700             new->nclist.next = copynode(n->nclist.next);
8701             break;
8702       case NDEFUN:
8703       case NARG:
8704             new->narg.backquote = copynodelist(n->narg.backquote);
8705             new->narg.text = nodesavestr(n->narg.text);
8706             new->narg.next = copynode(n->narg.next);
8707             break;
8708       case NTO:
8709       case NCLOBBER:
8710       case NFROM:
8711       case NFROMTO:
8712       case NAPPEND:
8713             new->nfile.fname = copynode(n->nfile.fname);
8714             new->nfile.fd = n->nfile.fd;
8715             new->nfile.next = copynode(n->nfile.next);
8716             break;
8717       case NTOFD:
8718       case NFROMFD:
8719             new->ndup.vname = copynode(n->ndup.vname);
8720             new->ndup.dupfd = n->ndup.dupfd;
8721             new->ndup.fd = n->ndup.fd;
8722             new->ndup.next = copynode(n->ndup.next);
8723             break;
8724       case NHERE:
8725       case NXHERE:
8726             new->nhere.doc = copynode(n->nhere.doc);
8727             new->nhere.fd = n->nhere.fd;
8728             new->nhere.next = copynode(n->nhere.next);
8729             break;
8730       case NNOT:
8731             new->nnot.com = copynode(n->nnot.com);
8732             break;
8733       };
8734       new->type = n->type;
8735         return new;
8736 }
8737
8738
8739 static struct nodelist *
8740 copynodelist(struct nodelist *lp)
8741 {
8742         struct nodelist *start;
8743         struct nodelist **lpp;
8744
8745         lpp = &start;
8746         while (lp) {
8747                 *lpp = funcblock;
8748                 funcblock = (char *) funcblock +
8749                     SHELL_ALIGN(sizeof(struct nodelist));
8750                 (*lpp)->n = copynode(lp->n);
8751                 lp = lp->next;
8752                 lpp = &(*lpp)->next;
8753         }
8754         *lpp = NULL;
8755         return start;
8756 }
8757
8758
8759 static char *
8760 nodesavestr(char   *s)
8761 {
8762         char   *rtn = funcstring;
8763
8764         funcstring = stpcpy(funcstring, s) + 1;
8765         return rtn;
8766 }
8767
8768
8769 /*
8770  * Free a parse tree.
8771  */
8772
8773 static void
8774 freefunc(struct funcnode *f)
8775 {
8776         if (f && --f->count < 0)
8777                 ckfree(f);
8778 }
8779
8780
8781 static void options(int);
8782 static void setoption(int, int);
8783
8784
8785 /*
8786  * Process the shell command line arguments.
8787  */
8788
8789 void
8790 procargs(int argc, char **argv)
8791 {
8792         int i;
8793         const char *xminusc;
8794         char **xargv;
8795
8796         xargv = argv;
8797         arg0 = xargv[0];
8798         if (argc > 0)
8799                 xargv++;
8800         for (i = 0; i < NOPTS; i++)
8801                 optlist[i] = 2;
8802         argptr = xargv;
8803         options(1);
8804         xargv = argptr;
8805         xminusc = minusc;
8806         if (*xargv == NULL) {
8807                 if (xminusc)
8808                         error("-c requires an argument");
8809                 sflag = 1;
8810         }
8811         if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
8812                 iflag = 1;
8813         if (mflag == 2)
8814                 mflag = iflag;
8815         for (i = 0; i < NOPTS; i++)
8816                 if (optlist[i] == 2)
8817                         optlist[i] = 0;
8818 #if DEBUG == 2
8819         debug = 1;
8820 #endif
8821         /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
8822         if (xminusc) {
8823                 minusc = *xargv++;
8824                 if (*xargv)
8825                         goto setarg0;
8826         } else if (!sflag) {
8827                 setinputfile(*xargv, 0);
8828 setarg0:
8829                 arg0 = *xargv++;
8830                 commandname = arg0;
8831         }
8832
8833         shellparam.p = xargv;
8834 #ifdef CONFIG_ASH_GETOPTS
8835         shellparam.optind = 1;
8836         shellparam.optoff = -1;
8837 #endif
8838         /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
8839         while (*xargv) {
8840                 shellparam.nparam++;
8841                 xargv++;
8842         }
8843         optschanged();
8844 }
8845
8846
8847 void
8848 optschanged(void)
8849 {
8850 #ifdef DEBUG
8851         opentrace();
8852 #endif
8853         setinteractive(iflag);
8854         setjobctl(mflag);
8855 }
8856
8857 static inline void
8858 minus_o(char *name, int val)
8859 {
8860         int i;
8861
8862         if (name == NULL) {
8863                 out1str("Current option settings\n");
8864                 for (i = 0; i < NOPTS; i++)
8865                         out1fmt("%-16s%s\n", optnames(i),
8866                                 optlist[i] ? "on" : "off");
8867         } else {
8868                 for (i = 0; i < NOPTS; i++)
8869                         if (equal(name, optnames(i))) {
8870                                 optlist[i] = val;
8871                                 return;
8872                         }
8873                 error("Illegal option -o %s", name);
8874         }
8875 }
8876
8877 /*
8878  * Process shell options.  The global variable argptr contains a pointer
8879  * to the argument list; we advance it past the options.
8880  */
8881
8882 static void
8883 options(int cmdline)
8884 {
8885         char *p;
8886         int val;
8887         int c;
8888
8889         if (cmdline)
8890                 minusc = NULL;
8891         while ((p = *argptr) != NULL) {
8892                 argptr++;
8893                 if ((c = *p++) == '-') {
8894                         val = 1;
8895                         if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
8896                                 if (!cmdline) {
8897                                         /* "-" means turn off -x and -v */
8898                                         if (p[0] == '\0')
8899                                                 xflag = vflag = 0;
8900                                         /* "--" means reset params */
8901                                         else if (*argptr == NULL)
8902                                                 setparam(argptr);
8903                                 }
8904                                 break;    /* "-" or  "--" terminates options */
8905                         }
8906                 } else if (c == '+') {
8907                         val = 0;
8908                 } else {
8909                         argptr--;
8910                         break;
8911                 }
8912                 while ((c = *p++) != '\0') {
8913                         if (c == 'c' && cmdline) {
8914                                 minusc = p;     /* command is after shell args*/
8915                         } else if (c == 'o') {
8916                                 minus_o(*argptr, val);
8917                                 if (*argptr)
8918                                         argptr++;
8919                         } else if (cmdline && (c == '-')) {     // long options
8920                                 if (strcmp(p, "login") == 0)
8921                                         isloginsh = 1;
8922                                 break;
8923                         } else {
8924                                 setoption(c, val);
8925                         }
8926                 }
8927         }
8928 }
8929
8930
8931 static void
8932 setoption(int flag, int val)
8933 {
8934         int i;
8935
8936         for (i = 0; i < NOPTS; i++)
8937                 if (optletters(i) == flag) {
8938                         optlist[i] = val;
8939                         return;
8940                 }
8941         error("Illegal option -%c", flag);
8942         /* NOTREACHED */
8943 }
8944
8945
8946
8947 /*
8948  * Set the shell parameters.
8949  */
8950
8951 void
8952 setparam(char **argv)
8953 {
8954         char **newparam;
8955         char **ap;
8956         int nparam;
8957
8958         for (nparam = 0 ; argv[nparam] ; nparam++);
8959         ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
8960         while (*argv) {
8961                 *ap++ = savestr(*argv++);
8962         }
8963         *ap = NULL;
8964         freeparam(&shellparam);
8965         shellparam.malloc = 1;
8966         shellparam.nparam = nparam;
8967         shellparam.p = newparam;
8968 #ifdef CONFIG_ASH_GETOPTS
8969         shellparam.optind = 1;
8970         shellparam.optoff = -1;
8971 #endif
8972 }
8973
8974
8975 /*
8976  * Free the list of positional parameters.
8977  */
8978
8979 void
8980 freeparam(volatile struct shparam *param)
8981 {
8982         char **ap;
8983
8984         if (param->malloc) {
8985                 for (ap = param->p ; *ap ; ap++)
8986                         ckfree(*ap);
8987                 ckfree(param->p);
8988         }
8989 }
8990
8991
8992
8993 /*
8994  * The shift builtin command.
8995  */
8996
8997 int
8998 shiftcmd(int argc, char **argv)
8999 {
9000         int n;
9001         char **ap1, **ap2;
9002
9003         n = 1;
9004         if (argc > 1)
9005                 n = number(argv[1]);
9006         if (n > shellparam.nparam)
9007                 error("can't shift that many");
9008         INTOFF;
9009         shellparam.nparam -= n;
9010         for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
9011                 if (shellparam.malloc)
9012                         ckfree(*ap1);
9013         }
9014         ap2 = shellparam.p;
9015         while ((*ap2++ = *ap1++) != NULL);
9016 #ifdef CONFIG_ASH_GETOPTS
9017         shellparam.optind = 1;
9018         shellparam.optoff = -1;
9019 #endif
9020         INTON;
9021         return 0;
9022 }
9023
9024
9025
9026 /*
9027  * The set command builtin.
9028  */
9029
9030 int
9031 setcmd(int argc, char **argv)
9032 {
9033         if (argc == 1)
9034                 return showvars(nullstr, 0, VUNSET);
9035         INTOFF;
9036         options(0);
9037         optschanged();
9038         if (*argptr != NULL) {
9039                 setparam(argptr);
9040         }
9041         INTON;
9042         return 0;
9043 }
9044
9045
9046 #ifdef CONFIG_ASH_GETOPTS
9047 static void
9048 getoptsreset(value)
9049         const char *value;
9050 {
9051         shellparam.optind = number(value);
9052         shellparam.optoff = -1;
9053 }
9054 #endif
9055
9056 #ifdef CONFIG_LOCALE_SUPPORT
9057 static void change_lc_all(const char *value)
9058 {
9059         if (value != 0 && *value != 0)
9060                 setlocale(LC_ALL, value);
9061 }
9062
9063 static void change_lc_ctype(const char *value)
9064 {
9065         if (value != 0 && *value != 0)
9066                 setlocale(LC_CTYPE, value);
9067 }
9068
9069 #endif
9070
9071 #ifdef CONFIG_ASH_RANDOM_SUPPORT
9072 /* Roughly copied from bash.. */
9073 static void change_random(const char *value)
9074 {
9075         if(value == NULL) {
9076                 /* "get", generate */
9077                 char buf[16];
9078
9079                 rseed = rseed * 1103515245 + 12345;
9080                 sprintf(buf, "%d", (unsigned int)((rseed & 32767)));
9081                 /* set without recursion */
9082                 setvar(vrandom.text, buf, VNOFUNC);
9083                 vrandom.flags &= ~VNOFUNC;
9084         } else {
9085                 /* set/reset */
9086                 rseed = strtoul(value, (char **)NULL, 10);
9087         }
9088 }
9089 #endif
9090
9091
9092 #ifdef CONFIG_ASH_GETOPTS
9093 static int
9094 getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
9095 {
9096         char *p, *q;
9097         char c = '?';
9098         int done = 0;
9099         int err = 0;
9100         char s[12];
9101         char **optnext;
9102
9103         if(*param_optind < 1)
9104                 return 1;
9105         optnext = optfirst + *param_optind - 1;
9106
9107         if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff)
9108                 p = NULL;
9109         else
9110                 p = optnext[-1] + *optoff;
9111         if (p == NULL || *p == '\0') {
9112                 /* Current word is done, advance */
9113                 p = *optnext;
9114                 if (p == NULL || *p != '-' || *++p == '\0') {
9115 atend:
9116                         p = NULL;
9117                         done = 1;
9118                         goto out;
9119                 }
9120                 optnext++;
9121                 if (p[0] == '-' && p[1] == '\0')        /* check for "--" */
9122                         goto atend;
9123         }
9124
9125         c = *p++;
9126         for (q = optstr; *q != c; ) {
9127                 if (*q == '\0') {
9128                         if (optstr[0] == ':') {
9129                                 s[0] = c;
9130                                 s[1] = '\0';
9131                                 err |= setvarsafe("OPTARG", s, 0);
9132                         } else {
9133                                 fprintf(stderr, "Illegal option -%c\n", c);
9134                                 (void) unsetvar("OPTARG");
9135                         }
9136                         c = '?';
9137                         goto out;
9138                 }
9139                 if (*++q == ':')
9140                         q++;
9141         }
9142
9143         if (*++q == ':') {
9144                 if (*p == '\0' && (p = *optnext) == NULL) {
9145                         if (optstr[0] == ':') {
9146                                 s[0] = c;
9147                                 s[1] = '\0';
9148                                 err |= setvarsafe("OPTARG", s, 0);
9149                                 c = ':';
9150                         } else {
9151                                 fprintf(stderr, "No arg for -%c option\n", c);
9152                                 (void) unsetvar("OPTARG");
9153                                 c = '?';
9154                         }
9155                         goto out;
9156                 }
9157
9158                 if (p == *optnext)
9159                         optnext++;
9160                 err |= setvarsafe("OPTARG", p, 0);
9161                 p = NULL;
9162         } else
9163                 err |= setvarsafe("OPTARG", nullstr, 0);
9164
9165 out:
9166         *optoff = p ? p - *(optnext - 1) : -1;
9167         *param_optind = optnext - optfirst + 1;
9168         fmtstr(s, sizeof(s), "%d", *param_optind);
9169         err |= setvarsafe("OPTIND", s, VNOFUNC);
9170         s[0] = c;
9171         s[1] = '\0';
9172         err |= setvarsafe(optvar, s, 0);
9173         if (err) {
9174                 *param_optind = 1;
9175                 *optoff = -1;
9176                 flushall();
9177                 exraise(EXERROR);
9178         }
9179         return done;
9180 }
9181
9182 /*
9183  * The getopts builtin.  Shellparam.optnext points to the next argument
9184  * to be processed.  Shellparam.optptr points to the next character to
9185  * be processed in the current argument.  If shellparam.optnext is NULL,
9186  * then it's the first time getopts has been called.
9187  */
9188
9189 int
9190 getoptscmd(int argc, char **argv)
9191 {
9192         char **optbase;
9193
9194         if (argc < 3)
9195                 error("Usage: getopts optstring var [arg]");
9196         else if (argc == 3) {
9197                 optbase = shellparam.p;
9198                 if (shellparam.optind > shellparam.nparam + 1) {
9199                         shellparam.optind = 1;
9200                         shellparam.optoff = -1;
9201                 }
9202         }
9203         else {
9204                 optbase = &argv[3];
9205                 if (shellparam.optind > argc - 2) {
9206                         shellparam.optind = 1;
9207                         shellparam.optoff = -1;
9208                 }
9209         }
9210
9211         return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9212                        &shellparam.optoff);
9213 }
9214 #endif /* CONFIG_ASH_GETOPTS */
9215
9216 /*
9217  * XXX - should get rid of.  have all builtins use getopt(3).  the
9218  * library getopt must have the BSD extension static variable "optreset"
9219  * otherwise it can't be used within the shell safely.
9220  *
9221  * Standard option processing (a la getopt) for builtin routines.  The
9222  * only argument that is passed to nextopt is the option string; the
9223  * other arguments are unnecessary.  It return the character, or '\0' on
9224  * end of input.
9225  */
9226
9227 static int
9228 nextopt(const char *optstring)
9229 {
9230         char *p;
9231         const char *q;
9232         char c;
9233
9234         if ((p = optptr) == NULL || *p == '\0') {
9235                 p = *argptr;
9236                 if (p == NULL || *p != '-' || *++p == '\0')
9237                         return '\0';
9238                 argptr++;
9239                 if (p[0] == '-' && p[1] == '\0')        /* check for "--" */
9240                         return '\0';
9241         }
9242         c = *p++;
9243         for (q = optstring ; *q != c ; ) {
9244                 if (*q == '\0')
9245                         error("Illegal option -%c", c);
9246                 if (*++q == ':')
9247                         q++;
9248         }
9249         if (*++q == ':') {
9250                 if (*p == '\0' && (p = *argptr++) == NULL)
9251                         error("No arg for -%c option", c);
9252                 optionarg = p;
9253                 p = NULL;
9254         }
9255         optptr = p;
9256         return c;
9257 }
9258
9259
9260 /*      $NetBSD: output.c,v 1.27 2002/11/24 22:35:42 christos Exp $     */
9261
9262 void
9263 outstr(const char *p, FILE *file)
9264 {
9265         INTOFF;
9266         fputs(p, file);
9267         INTON;
9268 }
9269
9270 void
9271 flushall(void)
9272 {
9273         INTOFF;
9274         fflush(stdout);
9275         fflush(stderr);
9276         INTON;
9277 }
9278
9279 void
9280 flusherr(void)
9281 {
9282         INTOFF;
9283         fflush(stderr);
9284         INTON;
9285 }
9286
9287 static void
9288 outcslow(int c, FILE *dest)
9289 {
9290         INTOFF;
9291         putc(c, dest);
9292         fflush(dest);
9293         INTON;
9294 }
9295
9296
9297 static int
9298 out1fmt(const char *fmt, ...)
9299 {
9300         va_list ap;
9301         int r;
9302
9303         INTOFF;
9304         va_start(ap, fmt);
9305         r = vprintf(fmt, ap);
9306         va_end(ap);
9307         INTON;
9308         return r;
9309 }
9310
9311
9312 int
9313 fmtstr(char *outbuf, size_t length, const char *fmt, ...)
9314 {
9315         va_list ap;
9316         int ret;
9317
9318         va_start(ap, fmt);
9319         INTOFF;
9320         ret = vsnprintf(outbuf, length, fmt, ap);
9321         va_end(ap);
9322         INTON;
9323         return ret;
9324 }
9325
9326
9327
9328 /*      $NetBSD: parser.c,v 1.54 2002/11/24 22:35:42 christos Exp $     */
9329
9330
9331 /*
9332  * Shell command parser.
9333  */
9334
9335 #define EOFMARKLEN 79
9336
9337
9338 struct heredoc {
9339         struct heredoc *next;   /* next here document in list */
9340         union node *here;               /* redirection node */
9341         char *eofmark;          /* string indicating end of input */
9342         int striptabs;          /* if set, strip leading tabs */
9343 };
9344
9345
9346
9347 static struct heredoc *heredoclist;    /* list of here documents to read */
9348
9349
9350 static union node *list(int);
9351 static union node *andor(void);
9352 static union node *pipeline(void);
9353 static union node *command(void);
9354 static union node *simplecmd(void);
9355 static union node *makename(void);
9356 static void parsefname(void);
9357 static void parseheredoc(void);
9358 static char peektoken(void);
9359 static int readtoken(void);
9360 static int xxreadtoken(void);
9361 static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs);
9362 static int noexpand(char *);
9363 static void synexpect(int) __attribute__((__noreturn__));
9364 static void synerror(const char *) __attribute__((__noreturn__));
9365 static void setprompt(int);
9366
9367
9368
9369 static inline int
9370 isassignment(const char *p)
9371 {
9372         const char *q = endofname(p);
9373         if (p == q)
9374                 return 0;
9375         return *q == '=';
9376 }
9377
9378
9379 /*
9380  * Read and parse a command.  Returns NEOF on end of file.  (NULL is a
9381  * valid parse tree indicating a blank line.)
9382  */
9383
9384 union node *
9385 parsecmd(int interact)
9386 {
9387         int t;
9388
9389         tokpushback = 0;
9390         doprompt = interact;
9391         if (doprompt)
9392                 setprompt(doprompt);
9393         needprompt = 0;
9394         t = readtoken();
9395         if (t == TEOF)
9396                 return NEOF;
9397         if (t == TNL)
9398                 return NULL;
9399         tokpushback++;
9400         return list(1);
9401 }
9402
9403
9404 static union node *
9405 list(int nlflag)
9406 {
9407         union node *n1, *n2, *n3;
9408         int tok;
9409
9410         checkkwd = CHKNL | CHKKWD | CHKALIAS;
9411         if (nlflag == 2 && peektoken())
9412                 return NULL;
9413         n1 = NULL;
9414         for (;;) {
9415                 n2 = andor();
9416                 tok = readtoken();
9417                 if (tok == TBACKGND) {
9418                         if (n2->type == NPIPE) {
9419                                 n2->npipe.backgnd = 1;
9420                         } else {
9421                                 if (n2->type != NREDIR) {
9422                                         n3 = stalloc(sizeof(struct nredir));
9423                                         n3->nredir.n = n2;
9424                                         n3->nredir.redirect = NULL;
9425                                         n2 = n3;
9426                                 }
9427                                 n2->type = NBACKGND;
9428                         }
9429                 }
9430                 if (n1 == NULL) {
9431                         n1 = n2;
9432                 }
9433                 else {
9434                         n3 = (union node *)stalloc(sizeof (struct nbinary));
9435                         n3->type = NSEMI;
9436                         n3->nbinary.ch1 = n1;
9437                         n3->nbinary.ch2 = n2;
9438                         n1 = n3;
9439                 }
9440                 switch (tok) {
9441                 case TBACKGND:
9442                 case TSEMI:
9443                         tok = readtoken();
9444                         /* fall through */
9445                 case TNL:
9446                         if (tok == TNL) {
9447                                 parseheredoc();
9448                                 if (nlflag == 1)
9449                                         return n1;
9450                         } else {
9451                                 tokpushback++;
9452                         }
9453                         checkkwd = CHKNL | CHKKWD | CHKALIAS;
9454                         if (peektoken())
9455                                 return n1;
9456                         break;
9457                 case TEOF:
9458                         if (heredoclist)
9459                                 parseheredoc();
9460                         else
9461                                 pungetc();              /* push back EOF on input */
9462                         return n1;
9463                 default:
9464                         if (nlflag == 1)
9465                                 synexpect(-1);
9466                         tokpushback++;
9467                         return n1;
9468                 }
9469         }
9470 }
9471
9472
9473
9474 static union node *
9475 andor(void)
9476 {
9477         union node *n1, *n2, *n3;
9478         int t;
9479
9480         n1 = pipeline();
9481         for (;;) {
9482                 if ((t = readtoken()) == TAND) {
9483                         t = NAND;
9484                 } else if (t == TOR) {
9485                         t = NOR;
9486                 } else {
9487                         tokpushback++;
9488                         return n1;
9489                 }
9490                 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9491                 n2 = pipeline();
9492                 n3 = (union node *)stalloc(sizeof (struct nbinary));
9493                 n3->type = t;
9494                 n3->nbinary.ch1 = n1;
9495                 n3->nbinary.ch2 = n2;
9496                 n1 = n3;
9497         }
9498 }
9499
9500
9501
9502 static union node *
9503 pipeline(void)
9504 {
9505         union node *n1, *n2, *pipenode;
9506         struct nodelist *lp, *prev;
9507         int negate;
9508
9509         negate = 0;
9510         TRACE(("pipeline: entered\n"));
9511         if (readtoken() == TNOT) {
9512                 negate = !negate;
9513                 checkkwd = CHKKWD | CHKALIAS;
9514         } else
9515                 tokpushback++;
9516         n1 = command();
9517         if (readtoken() == TPIPE) {
9518                 pipenode = (union node *)stalloc(sizeof (struct npipe));
9519                 pipenode->type = NPIPE;
9520                 pipenode->npipe.backgnd = 0;
9521                 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9522                 pipenode->npipe.cmdlist = lp;
9523                 lp->n = n1;
9524                 do {
9525                         prev = lp;
9526                         lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9527                         checkkwd = CHKNL | CHKKWD | CHKALIAS;
9528                         lp->n = command();
9529                         prev->next = lp;
9530                 } while (readtoken() == TPIPE);
9531                 lp->next = NULL;
9532                 n1 = pipenode;
9533         }
9534         tokpushback++;
9535         if (negate) {
9536                 n2 = (union node *)stalloc(sizeof (struct nnot));
9537                 n2->type = NNOT;
9538                 n2->nnot.com = n1;
9539                 return n2;
9540         } else
9541                 return n1;
9542 }
9543
9544
9545
9546 static union node *
9547 command(void)
9548 {
9549         union node *n1, *n2;
9550         union node *ap, **app;
9551         union node *cp, **cpp;
9552         union node *redir, **rpp;
9553         union node **rpp2;
9554         int t;
9555
9556         redir = NULL;
9557         rpp2 = &redir;
9558
9559         switch (readtoken()) {
9560         default:
9561                 synexpect(-1);
9562                 /* NOTREACHED */
9563         case TIF:
9564                 n1 = (union node *)stalloc(sizeof (struct nif));
9565                 n1->type = NIF;
9566                 n1->nif.test = list(0);
9567                 if (readtoken() != TTHEN)
9568                         synexpect(TTHEN);
9569                 n1->nif.ifpart = list(0);
9570                 n2 = n1;
9571                 while (readtoken() == TELIF) {
9572                         n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
9573                         n2 = n2->nif.elsepart;
9574                         n2->type = NIF;
9575                         n2->nif.test = list(0);
9576                         if (readtoken() != TTHEN)
9577                                 synexpect(TTHEN);
9578                         n2->nif.ifpart = list(0);
9579                 }
9580                 if (lasttoken == TELSE)
9581                         n2->nif.elsepart = list(0);
9582                 else {
9583                         n2->nif.elsepart = NULL;
9584                         tokpushback++;
9585                 }
9586                 t = TFI;
9587                 break;
9588         case TWHILE:
9589         case TUNTIL: {
9590                 int got;
9591                 n1 = (union node *)stalloc(sizeof (struct nbinary));
9592                 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
9593                 n1->nbinary.ch1 = list(0);
9594                 if ((got=readtoken()) != TDO) {
9595 TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : ""));
9596                         synexpect(TDO);
9597                 }
9598                 n1->nbinary.ch2 = list(0);
9599                 t = TDONE;
9600                 break;
9601         }
9602         case TFOR:
9603                 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9604                         synerror("Bad for loop variable");
9605                 n1 = (union node *)stalloc(sizeof (struct nfor));
9606                 n1->type = NFOR;
9607                 n1->nfor.var = wordtext;
9608                 checkkwd = CHKKWD | CHKALIAS;
9609                 if (readtoken() == TIN) {
9610                         app = &ap;
9611                         while (readtoken() == TWORD) {
9612                                 n2 = (union node *)stalloc(sizeof (struct narg));
9613                                 n2->type = NARG;
9614                                 n2->narg.text = wordtext;
9615                                 n2->narg.backquote = backquotelist;
9616                                 *app = n2;
9617                                 app = &n2->narg.next;
9618                         }
9619                         *app = NULL;
9620                         n1->nfor.args = ap;
9621                         if (lasttoken != TNL && lasttoken != TSEMI)
9622                                 synexpect(-1);
9623                 } else {
9624                         n2 = (union node *)stalloc(sizeof (struct narg));
9625                         n2->type = NARG;
9626                         n2->narg.text = (char *)dolatstr;
9627                         n2->narg.backquote = NULL;
9628                         n2->narg.next = NULL;
9629                         n1->nfor.args = n2;
9630                         /*
9631                          * Newline or semicolon here is optional (but note
9632                          * that the original Bourne shell only allowed NL).
9633                          */
9634                         if (lasttoken != TNL && lasttoken != TSEMI)
9635                                 tokpushback++;
9636                 }
9637                 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9638                 if (readtoken() != TDO)
9639                         synexpect(TDO);
9640                 n1->nfor.body = list(0);
9641                 t = TDONE;
9642                 break;
9643         case TCASE:
9644                 n1 = (union node *)stalloc(sizeof (struct ncase));
9645                 n1->type = NCASE;
9646                 if (readtoken() != TWORD)
9647                         synexpect(TWORD);
9648                 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
9649                 n2->type = NARG;
9650                 n2->narg.text = wordtext;
9651                 n2->narg.backquote = backquotelist;
9652                 n2->narg.next = NULL;
9653                 do {
9654                         checkkwd = CHKKWD | CHKALIAS;
9655                 } while (readtoken() == TNL);
9656                 if (lasttoken != TIN)
9657                         synexpect(TIN);
9658                 cpp = &n1->ncase.cases;
9659 next_case:
9660                 checkkwd = CHKNL | CHKKWD;
9661                 t = readtoken();
9662                 while(t != TESAC) {
9663                         if (lasttoken == TLP)
9664                                 readtoken();
9665                         *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
9666                         cp->type = NCLIST;
9667                         app = &cp->nclist.pattern;
9668                         for (;;) {
9669                                 *app = ap = (union node *)stalloc(sizeof (struct narg));
9670                                 ap->type = NARG;
9671                                 ap->narg.text = wordtext;
9672                                 ap->narg.backquote = backquotelist;
9673                                 if (readtoken() != TPIPE)
9674                                         break;
9675                                 app = &ap->narg.next;
9676                                 readtoken();
9677                         }
9678                         ap->narg.next = NULL;
9679                         if (lasttoken != TRP)
9680                                 synexpect(TRP);
9681                         cp->nclist.body = list(2);
9682
9683                         cpp = &cp->nclist.next;
9684
9685                         checkkwd = CHKNL | CHKKWD;
9686                         if ((t = readtoken()) != TESAC) {
9687                                 if (t != TENDCASE)
9688                                         synexpect(TENDCASE);
9689                                 else
9690                                         goto next_case;
9691                         }
9692                 }
9693                 *cpp = NULL;
9694                 goto redir;
9695         case TLP:
9696                 n1 = (union node *)stalloc(sizeof (struct nredir));
9697                 n1->type = NSUBSHELL;
9698                 n1->nredir.n = list(0);
9699                 n1->nredir.redirect = NULL;
9700                 t = TRP;
9701                 break;
9702         case TBEGIN:
9703                 n1 = list(0);
9704                 t = TEND;
9705                 break;
9706         case TWORD:
9707         case TREDIR:
9708                 tokpushback++;
9709                 return simplecmd();
9710         }
9711
9712         if (readtoken() != t)
9713                 synexpect(t);
9714
9715 redir:
9716         /* Now check for redirection which may follow command */
9717         checkkwd = CHKKWD | CHKALIAS;
9718         rpp = rpp2;
9719         while (readtoken() == TREDIR) {
9720                 *rpp = n2 = redirnode;
9721                 rpp = &n2->nfile.next;
9722                 parsefname();
9723         }
9724         tokpushback++;
9725         *rpp = NULL;
9726         if (redir) {
9727                 if (n1->type != NSUBSHELL) {
9728                         n2 = (union node *)stalloc(sizeof (struct nredir));
9729                         n2->type = NREDIR;
9730                         n2->nredir.n = n1;
9731                         n1 = n2;
9732                 }
9733                 n1->nredir.redirect = redir;
9734         }
9735
9736         return n1;
9737 }
9738
9739
9740 static union node *
9741 simplecmd(void) {
9742         union node *args, **app;
9743         union node *n = NULL;
9744         union node *vars, **vpp;
9745         union node **rpp, *redir;
9746         int savecheckkwd;
9747
9748         args = NULL;
9749         app = &args;
9750         vars = NULL;
9751         vpp = &vars;
9752         redir = NULL;
9753         rpp = &redir;
9754
9755         savecheckkwd = CHKALIAS;
9756         for (;;) {
9757                 checkkwd = savecheckkwd;
9758                 switch (readtoken()) {
9759                 case TWORD:
9760                         n = (union node *)stalloc(sizeof (struct narg));
9761                         n->type = NARG;
9762                         n->narg.text = wordtext;
9763                         n->narg.backquote = backquotelist;
9764                         if (savecheckkwd && isassignment(wordtext)) {
9765                                 *vpp = n;
9766                                 vpp = &n->narg.next;
9767                         } else {
9768                                 *app = n;
9769                                 app = &n->narg.next;
9770                                 savecheckkwd = 0;
9771                         }
9772                         break;
9773                 case TREDIR:
9774                         *rpp = n = redirnode;
9775                         rpp = &n->nfile.next;
9776                         parsefname();   /* read name of redirection file */
9777                         break;
9778                 case TLP:
9779                         if (
9780                                 args && app == &args->narg.next &&
9781                                 !vars && !redir
9782                         ) {
9783                                 struct builtincmd *bcmd;
9784                                 const char *name;
9785
9786                                 /* We have a function */
9787                                 if (readtoken() != TRP)
9788                                         synexpect(TRP);
9789                                 name = n->narg.text;
9790                                 if (
9791                                         !goodname(name) || (
9792                                                 (bcmd = find_builtin(name)) &&
9793                                                 IS_BUILTIN_SPECIAL(bcmd)
9794                                         )
9795                                 )
9796                                         synerror("Bad function name");
9797                                 n->type = NDEFUN;
9798                                 checkkwd = CHKNL | CHKKWD | CHKALIAS;
9799                                 n->narg.next = command();
9800                                 return n;
9801                         }
9802                         /* fall through */
9803                 default:
9804                         tokpushback++;
9805                         goto out;
9806                 }
9807         }
9808 out:
9809         *app = NULL;
9810         *vpp = NULL;
9811         *rpp = NULL;
9812         n = (union node *)stalloc(sizeof (struct ncmd));
9813         n->type = NCMD;
9814         n->ncmd.args = args;
9815         n->ncmd.assign = vars;
9816         n->ncmd.redirect = redir;
9817         return n;
9818 }
9819
9820 static union node *
9821 makename(void)
9822 {
9823         union node *n;
9824
9825         n = (union node *)stalloc(sizeof (struct narg));
9826         n->type = NARG;
9827         n->narg.next = NULL;
9828         n->narg.text = wordtext;
9829         n->narg.backquote = backquotelist;
9830         return n;
9831 }
9832
9833 void fixredir(union node *n, const char *text, int err)
9834 {
9835         TRACE(("Fix redir %s %d\n", text, err));
9836         if (!err)
9837                 n->ndup.vname = NULL;
9838
9839         if (is_digit(text[0]) && text[1] == '\0')
9840                 n->ndup.dupfd = digit_val(text[0]);
9841         else if (text[0] == '-' && text[1] == '\0')
9842                 n->ndup.dupfd = -1;
9843         else {
9844
9845                 if (err)
9846                         synerror("Bad fd number");
9847                 else
9848                         n->ndup.vname = makename();
9849         }
9850 }
9851
9852
9853 static void
9854 parsefname(void)
9855 {
9856         union node *n = redirnode;
9857
9858         if (readtoken() != TWORD)
9859                 synexpect(-1);
9860         if (n->type == NHERE) {
9861                 struct heredoc *here = heredoc;
9862                 struct heredoc *p;
9863                 int i;
9864
9865                 if (quoteflag == 0)
9866                         n->type = NXHERE;
9867                 TRACE(("Here document %d\n", n->type));
9868                 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
9869                         synerror("Illegal eof marker for << redirection");
9870                 rmescapes(wordtext);
9871                 here->eofmark = wordtext;
9872                 here->next = NULL;
9873                 if (heredoclist == NULL)
9874                         heredoclist = here;
9875                 else {
9876                         for (p = heredoclist ; p->next ; p = p->next);
9877                         p->next = here;
9878                 }
9879         } else if (n->type == NTOFD || n->type == NFROMFD) {
9880                 fixredir(n, wordtext, 0);
9881         } else {
9882                 n->nfile.fname = makename();
9883         }
9884 }
9885
9886
9887 /*
9888  * Input any here documents.
9889  */
9890
9891 static void
9892 parseheredoc(void)
9893 {
9894         struct heredoc *here;
9895         union node *n;
9896
9897         here = heredoclist;
9898         heredoclist = 0;
9899
9900         while (here) {
9901                 if (needprompt) {
9902                         setprompt(2);
9903                         needprompt = 0;
9904                 }
9905                 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
9906                                 here->eofmark, here->striptabs);
9907                 n = (union node *)stalloc(sizeof (struct narg));
9908                 n->narg.type = NARG;
9909                 n->narg.next = NULL;
9910                 n->narg.text = wordtext;
9911                 n->narg.backquote = backquotelist;
9912                 here->here->nhere.doc = n;
9913                 here = here->next;
9914         }
9915 }
9916
9917 static char peektoken(void)
9918 {
9919         int t;
9920
9921         t = readtoken();
9922         tokpushback++;
9923         return tokname_array[t][0];
9924 }
9925
9926 static int
9927 readtoken(void)
9928 {
9929         int t;
9930 #ifdef DEBUG
9931         int alreadyseen = tokpushback;
9932 #endif
9933
9934 #ifdef CONFIG_ASH_ALIAS
9935 top:
9936 #endif
9937
9938         t = xxreadtoken();
9939
9940         /*
9941          * eat newlines
9942          */
9943         if (checkkwd & CHKNL) {
9944                 while (t == TNL) {
9945                         parseheredoc();
9946                         t = xxreadtoken();
9947                 }
9948         }
9949
9950         if (t != TWORD || quoteflag) {
9951                 goto out;
9952         }
9953
9954         /*
9955          * check for keywords
9956          */
9957         if (checkkwd & CHKKWD) {
9958                 const char *const *pp;
9959
9960                 if ((pp = findkwd(wordtext))) {
9961                         lasttoken = t = pp - tokname_array;
9962                         TRACE(("keyword %s recognized\n", tokname(t)));
9963                         goto out;
9964                 }
9965         }
9966
9967         if (checkkwd & CHKALIAS) {
9968 #ifdef CONFIG_ASH_ALIAS
9969                 struct alias *ap;
9970                 if ((ap = lookupalias(wordtext, 1)) != NULL) {
9971                         if (*ap->val) {
9972                                 pushstring(ap->val, ap);
9973                         }
9974                         goto top;
9975                 }
9976 #endif
9977         }
9978 out:
9979         checkkwd = 0;
9980 #ifdef DEBUG
9981         if (!alreadyseen)
9982             TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
9983         else
9984             TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : ""));
9985 #endif
9986         return (t);
9987 }
9988
9989
9990 /*
9991  * Read the next input token.
9992  * If the token is a word, we set backquotelist to the list of cmds in
9993  *      backquotes.  We set quoteflag to true if any part of the word was
9994  *      quoted.
9995  * If the token is TREDIR, then we set redirnode to a structure containing
9996  *      the redirection.
9997  * In all cases, the variable startlinno is set to the number of the line
9998  *      on which the token starts.
9999  *
10000  * [Change comment:  here documents and internal procedures]
10001  * [Readtoken shouldn't have any arguments.  Perhaps we should make the
10002  *  word parsing code into a separate routine.  In this case, readtoken
10003  *  doesn't need to have any internal procedures, but parseword does.
10004  *  We could also make parseoperator in essence the main routine, and
10005  *  have parseword (readtoken1?) handle both words and redirection.]
10006  */
10007
10008 #define NEW_xxreadtoken
10009 #ifdef NEW_xxreadtoken
10010
10011 /* singles must be first! */
10012 static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 };
10013
10014 static const char xxreadtoken_tokens[] = {
10015         TNL, TLP, TRP,          /* only single occurrence allowed */
10016         TBACKGND, TPIPE, TSEMI, /* if single occurrence */
10017         TEOF,                   /* corresponds to trailing nul */
10018         TAND, TOR, TENDCASE,    /* if double occurrence */
10019 };
10020
10021 #define xxreadtoken_doubles \
10022         (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars))
10023 #define xxreadtoken_singles \
10024         (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1)
10025
10026 static int xxreadtoken()
10027 {
10028         int c;
10029
10030         if (tokpushback) {
10031                 tokpushback = 0;
10032                 return lasttoken;
10033         }
10034         if (needprompt) {
10035                 setprompt(2);
10036                 needprompt = 0;
10037         }
10038         startlinno = plinno;
10039         for (;;) {                      /* until token or start of word found */
10040                 c = pgetc_macro();
10041
10042                 if ((c != ' ') && (c != '\t')
10043 #ifdef CONFIG_ASH_ALIAS
10044                         && (c != PEOA)
10045 #endif
10046                         ) {
10047                         if (c == '#') {
10048                                 while ((c = pgetc()) != '\n' && c != PEOF);
10049                                 pungetc();
10050                         } else if (c == '\\') {
10051                                 if (pgetc() != '\n') {
10052                                         pungetc();
10053                                         goto READTOKEN1;
10054                                 }
10055                                 startlinno = ++plinno;
10056                                 if (doprompt)
10057                                         setprompt(2);
10058                         } else {
10059                                 const char *p
10060                                         = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
10061
10062                                 if (c != PEOF) {
10063                                         if (c == '\n') {
10064                                                 plinno++;
10065                                                 needprompt = doprompt;
10066                                         }
10067
10068                                         p = strchr(xxreadtoken_chars, c);
10069                                         if (p == NULL) {
10070                                           READTOKEN1:
10071                                                 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
10072                                         }
10073
10074                                         if (p - xxreadtoken_chars >= xxreadtoken_singles) {
10075                                                 if (pgetc() == *p) {    /* double occurrence? */
10076                                                         p += xxreadtoken_doubles + 1;
10077                                                 } else {
10078                                                         pungetc();
10079                                                 }
10080                                         }
10081                                 }
10082
10083                                 return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
10084                         }
10085                 }
10086         }
10087 }
10088
10089
10090 #else
10091 #define RETURN(token)   return lasttoken = token
10092
10093 static int
10094 xxreadtoken(void)
10095 {
10096         int c;
10097
10098         if (tokpushback) {
10099                 tokpushback = 0;
10100                 return lasttoken;
10101         }
10102         if (needprompt) {
10103                 setprompt(2);
10104                 needprompt = 0;
10105         }
10106         startlinno = plinno;
10107         for (;;) {      /* until token or start of word found */
10108                 c = pgetc_macro();
10109                 switch (c) {
10110                 case ' ': case '\t':
10111 #ifdef CONFIG_ASH_ALIAS
10112                 case PEOA:
10113 #endif
10114                         continue;
10115                 case '#':
10116                         while ((c = pgetc()) != '\n' && c != PEOF);
10117                         pungetc();
10118                         continue;
10119                 case '\\':
10120                         if (pgetc() == '\n') {
10121                                 startlinno = ++plinno;
10122                                 if (doprompt)
10123                                         setprompt(2);
10124                                 continue;
10125                         }
10126                         pungetc();
10127                         goto breakloop;
10128                 case '\n':
10129                         plinno++;
10130                         needprompt = doprompt;
10131                         RETURN(TNL);
10132                 case PEOF:
10133                         RETURN(TEOF);
10134                 case '&':
10135                         if (pgetc() == '&')
10136                                 RETURN(TAND);
10137                         pungetc();
10138                         RETURN(TBACKGND);
10139                 case '|':
10140                         if (pgetc() == '|')
10141                                 RETURN(TOR);
10142                         pungetc();
10143                         RETURN(TPIPE);
10144                 case ';':
10145                         if (pgetc() == ';')
10146                                 RETURN(TENDCASE);
10147                         pungetc();
10148                         RETURN(TSEMI);
10149                 case '(':
10150                         RETURN(TLP);
10151                 case ')':
10152                         RETURN(TRP);
10153                 default:
10154                         goto breakloop;
10155                 }
10156         }
10157 breakloop:
10158         return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10159 #undef RETURN
10160 }
10161 #endif /* NEW_xxreadtoken */
10162
10163
10164 /*
10165  * If eofmark is NULL, read a word or a redirection symbol.  If eofmark
10166  * is not NULL, read a here document.  In the latter case, eofmark is the
10167  * word which marks the end of the document and striptabs is true if
10168  * leading tabs should be stripped from the document.  The argument firstc
10169  * is the first character of the input token or document.
10170  *
10171  * Because C does not have internal subroutines, I have simulated them
10172  * using goto's to implement the subroutine linkage.  The following macros
10173  * will run code that appears at the end of readtoken1.
10174  */
10175
10176 #define CHECKEND()      {goto checkend; checkend_return:;}
10177 #define PARSEREDIR()    {goto parseredir; parseredir_return:;}
10178 #define PARSESUB()      {goto parsesub; parsesub_return:;}
10179 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10180 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10181 #define PARSEARITH()    {goto parsearith; parsearith_return:;}
10182
10183 static int
10184 readtoken1(int firstc, int syntax, char *eofmark, int striptabs)
10185 {
10186         int c = firstc;
10187         char *out;
10188         int len;
10189         char line[EOFMARKLEN + 1];
10190         struct nodelist *bqlist;
10191         int quotef;
10192         int dblquote;
10193         int varnest;    /* levels of variables expansion */
10194         int arinest;    /* levels of arithmetic expansion */
10195         int parenlevel; /* levels of parens in arithmetic */
10196         int dqvarnest;  /* levels of variables expansion within double quotes */
10197         int oldstyle;
10198         int prevsyntax; /* syntax before arithmetic */
10199 #if __GNUC__
10200         /* Avoid longjmp clobbering */
10201         (void) &out;
10202         (void) &quotef;
10203         (void) &dblquote;
10204         (void) &varnest;
10205         (void) &arinest;
10206         (void) &parenlevel;
10207         (void) &dqvarnest;
10208         (void) &oldstyle;
10209         (void) &prevsyntax;
10210         (void) &syntax;
10211 #endif
10212
10213         startlinno = plinno;
10214         dblquote = 0;
10215         if (syntax == DQSYNTAX)
10216                 dblquote = 1;
10217         quotef = 0;
10218         bqlist = NULL;
10219         varnest = 0;
10220         arinest = 0;
10221         parenlevel = 0;
10222         dqvarnest = 0;
10223
10224         STARTSTACKSTR(out);
10225         loop: { /* for each line, until end of word */
10226                 CHECKEND();     /* set c to PEOF if at end of here document */
10227                 for (;;) {      /* until end of line or end of word */
10228                         CHECKSTRSPACE(4, out);  /* permit 4 calls to USTPUTC */
10229                         switch(SIT(c, syntax)) {
10230                         case CNL:       /* '\n' */
10231                                 if (syntax == BASESYNTAX)
10232                                         goto endword;   /* exit outer loop */
10233                                 USTPUTC(c, out);
10234                                 plinno++;
10235                                 if (doprompt)
10236                                         setprompt(2);
10237                                 c = pgetc();
10238                                 goto loop;              /* continue outer loop */
10239                         case CWORD:
10240                                 USTPUTC(c, out);
10241                                 break;
10242                         case CCTL:
10243                                 if (eofmark == NULL || dblquote)
10244                                         USTPUTC(CTLESC, out);
10245                                 USTPUTC(c, out);
10246                                 break;
10247                         case CBACK:     /* backslash */
10248                                 c = pgetc2();
10249                                 if (c == PEOF) {
10250                                         USTPUTC(CTLESC, out);
10251                                         USTPUTC('\\', out);
10252                                         pungetc();
10253                                 } else if (c == '\n') {
10254                                         if (doprompt)
10255                                                 setprompt(2);
10256                                 } else {
10257                                         if (
10258                                                 dblquote &&
10259                                                 c != '\\' && c != '`' &&
10260                                                 c != '$' && (
10261                                                         c != '"' ||
10262                                                         eofmark != NULL
10263                                                 )
10264                                         ) {
10265                                                 USTPUTC(CTLESC, out);
10266                                                 USTPUTC('\\', out);
10267                                         }
10268                                         if (SIT(c, SQSYNTAX) == CCTL)
10269                                                 USTPUTC(CTLESC, out);
10270                                         USTPUTC(c, out);
10271                                         quotef++;
10272                                 }
10273                                 break;
10274                         case CSQUOTE:
10275                                 syntax = SQSYNTAX;
10276 quotemark:
10277                                 if (eofmark == NULL) {
10278                                         USTPUTC(CTLQUOTEMARK, out);
10279                                 }
10280                                 break;
10281                         case CDQUOTE:
10282                                 syntax = DQSYNTAX;
10283                                 dblquote = 1;
10284                                 goto quotemark;
10285                         case CENDQUOTE:
10286                                 if (eofmark != NULL && arinest == 0 &&
10287                                     varnest == 0) {
10288                                         USTPUTC(c, out);
10289                                 } else {
10290                                         if (dqvarnest == 0) {
10291                                                 syntax = BASESYNTAX;
10292                                                 dblquote = 0;
10293                                         }
10294                                         quotef++;
10295                                         goto quotemark;
10296                                 }
10297                                 break;
10298                         case CVAR:      /* '$' */
10299                                 PARSESUB();             /* parse substitution */
10300                                 break;
10301                         case CENDVAR:   /* '}' */
10302                                 if (varnest > 0) {
10303                                         varnest--;
10304                                         if (dqvarnest > 0) {
10305                                                 dqvarnest--;
10306                                         }
10307                                         USTPUTC(CTLENDVAR, out);
10308                                 } else {
10309                                         USTPUTC(c, out);
10310                                 }
10311                                 break;
10312 #ifdef CONFIG_ASH_MATH_SUPPORT
10313                         case CLP:       /* '(' in arithmetic */
10314                                 parenlevel++;
10315                                 USTPUTC(c, out);
10316                                 break;
10317                         case CRP:       /* ')' in arithmetic */
10318                                 if (parenlevel > 0) {
10319                                         USTPUTC(c, out);
10320                                         --parenlevel;
10321                                 } else {
10322                                         if (pgetc() == ')') {
10323                                                 if (--arinest == 0) {
10324                                                         USTPUTC(CTLENDARI, out);
10325                                                         syntax = prevsyntax;
10326                                                         if (syntax == DQSYNTAX)
10327                                                                 dblquote = 1;
10328                                                         else
10329                                                                 dblquote = 0;
10330                                                 } else
10331                                                         USTPUTC(')', out);
10332                                         } else {
10333                                                 /*
10334                                                  * unbalanced parens
10335                                                  *  (don't 2nd guess - no error)
10336                                                  */
10337                                                 pungetc();
10338                                                 USTPUTC(')', out);
10339                                         }
10340                                 }
10341                                 break;
10342 #endif
10343                         case CBQUOTE:   /* '`' */
10344                                 PARSEBACKQOLD();
10345                                 break;
10346                         case CENDFILE:
10347                                 goto endword;           /* exit outer loop */
10348                         case CIGN:
10349                                 break;
10350                         default:
10351                                 if (varnest == 0)
10352                                         goto endword;   /* exit outer loop */
10353 #ifdef CONFIG_ASH_ALIAS
10354                                 if (c != PEOA)
10355 #endif
10356                                         USTPUTC(c, out);
10357
10358                         }
10359                         c = pgetc_macro();
10360                 }
10361         }
10362 endword:
10363 #ifdef CONFIG_ASH_MATH_SUPPORT
10364         if (syntax == ARISYNTAX)
10365                 synerror("Missing '))'");
10366 #endif
10367         if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10368                 synerror("Unterminated quoted string");
10369         if (varnest != 0) {
10370                 startlinno = plinno;
10371                 /* { */
10372                 synerror("Missing '}'");
10373         }
10374         USTPUTC('\0', out);
10375         len = out - (char *)stackblock();
10376         out = stackblock();
10377         if (eofmark == NULL) {
10378                 if ((c == '>' || c == '<')
10379                  && quotef == 0
10380                  && len <= 2
10381                  && (*out == '\0' || is_digit(*out))) {
10382                         PARSEREDIR();
10383                         return lasttoken = TREDIR;
10384                 } else {
10385                         pungetc();
10386                 }
10387         }
10388         quoteflag = quotef;
10389         backquotelist = bqlist;
10390         grabstackblock(len);
10391         wordtext = out;
10392         return lasttoken = TWORD;
10393 /* end of readtoken routine */
10394
10395
10396
10397 /*
10398  * Check to see whether we are at the end of the here document.  When this
10399  * is called, c is set to the first character of the next input line.  If
10400  * we are at the end of the here document, this routine sets the c to PEOF.
10401  */
10402
10403 checkend: {
10404         if (eofmark) {
10405 #ifdef CONFIG_ASH_ALIAS
10406                 if (c == PEOA) {
10407                         c = pgetc2();
10408                 }
10409 #endif
10410                 if (striptabs) {
10411                         while (c == '\t') {
10412                                 c = pgetc2();
10413                         }
10414                 }
10415                 if (c == *eofmark) {
10416                         if (pfgets(line, sizeof line) != NULL) {
10417                                 char *p, *q;
10418
10419                                 p = line;
10420                                 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10421                                 if (*p == '\n' && *q == '\0') {
10422                                         c = PEOF;
10423                                         plinno++;
10424                                         needprompt = doprompt;
10425                                 } else {
10426                                         pushstring(line, NULL);
10427                                 }
10428                         }
10429                 }
10430         }
10431         goto checkend_return;
10432 }
10433
10434
10435 /*
10436  * Parse a redirection operator.  The variable "out" points to a string
10437  * specifying the fd to be redirected.  The variable "c" contains the
10438  * first character of the redirection operator.
10439  */
10440
10441 parseredir: {
10442         char fd = *out;
10443         union node *np;
10444
10445         np = (union node *)stalloc(sizeof (struct nfile));
10446         if (c == '>') {
10447                 np->nfile.fd = 1;
10448                 c = pgetc();
10449                 if (c == '>')
10450                         np->type = NAPPEND;
10451                 else if (c == '|')
10452                         np->type = NCLOBBER;
10453                 else if (c == '&')
10454                         np->type = NTOFD;
10455                 else {
10456                         np->type = NTO;
10457                         pungetc();
10458                 }
10459         } else {        /* c == '<' */
10460                 np->nfile.fd = 0;
10461                 switch (c = pgetc()) {
10462                 case '<':
10463                         if (sizeof (struct nfile) != sizeof (struct nhere)) {
10464                                 np = (union node *)stalloc(sizeof (struct nhere));
10465                                 np->nfile.fd = 0;
10466                         }
10467                         np->type = NHERE;
10468                         heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10469                         heredoc->here = np;
10470                         if ((c = pgetc()) == '-') {
10471                                 heredoc->striptabs = 1;
10472                         } else {
10473                                 heredoc->striptabs = 0;
10474                                 pungetc();
10475                         }
10476                         break;
10477
10478                 case '&':
10479                         np->type = NFROMFD;
10480                         break;
10481
10482                 case '>':
10483                         np->type = NFROMTO;
10484                         break;
10485
10486                 default:
10487                         np->type = NFROM;
10488                         pungetc();
10489                         break;
10490                 }
10491         }
10492         if (fd != '\0')
10493                 np->nfile.fd = digit_val(fd);
10494         redirnode = np;
10495         goto parseredir_return;
10496 }
10497
10498
10499 /*
10500  * Parse a substitution.  At this point, we have read the dollar sign
10501  * and nothing else.
10502  */
10503
10504 parsesub: {
10505         int subtype;
10506         int typeloc;
10507         int flags;
10508         char *p;
10509         static const char types[] = "}-+?=";
10510
10511         c = pgetc();
10512         if (
10513                 c <= PEOA_OR_PEOF  ||
10514                 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10515         ) {
10516                 USTPUTC('$', out);
10517                 pungetc();
10518         } else if (c == '(') {  /* $(command) or $((arith)) */
10519                 if (pgetc() == '(') {
10520 #ifdef CONFIG_ASH_MATH_SUPPORT
10521                         PARSEARITH();
10522 #else
10523                         synerror("We unsupport $((arith))");
10524 #endif
10525                 } else {
10526                         pungetc();
10527                         PARSEBACKQNEW();
10528                 }
10529         } else {
10530                 USTPUTC(CTLVAR, out);
10531                 typeloc = out - (char *)stackblock();
10532                 USTPUTC(VSNORMAL, out);
10533                 subtype = VSNORMAL;
10534                 if (c == '{') {
10535                         c = pgetc();
10536                         if (c == '#') {
10537                                 if ((c = pgetc()) == '}')
10538                                         c = '#';
10539                                 else
10540                                         subtype = VSLENGTH;
10541                         }
10542                         else
10543                                 subtype = 0;
10544                 }
10545                 if (c > PEOA_OR_PEOF && is_name(c)) {
10546                         do {
10547                                 STPUTC(c, out);
10548                                 c = pgetc();
10549                         } while (c > PEOA_OR_PEOF && is_in_name(c));
10550                 } else if (is_digit(c)) {
10551                         do {
10552                                 STPUTC(c, out);
10553                                 c = pgetc();
10554                         } while (is_digit(c));
10555                 }
10556                 else if (is_special(c)) {
10557                         USTPUTC(c, out);
10558                         c = pgetc();
10559                 }
10560                 else
10561 badsub:                 synerror("Bad substitution");
10562
10563                 STPUTC('=', out);
10564                 flags = 0;
10565                 if (subtype == 0) {
10566                         switch (c) {
10567                         case ':':
10568                                 flags = VSNUL;
10569                                 c = pgetc();
10570                                 /*FALLTHROUGH*/
10571                         default:
10572                                 p = strchr(types, c);
10573                                 if (p == NULL)
10574                                         goto badsub;
10575                                 subtype = p - types + VSNORMAL;
10576                                 break;
10577                         case '%':
10578                         case '#':
10579                                 {
10580                                         int cc = c;
10581                                         subtype = c == '#' ? VSTRIMLEFT :
10582                                                              VSTRIMRIGHT;
10583                                         c = pgetc();
10584                                         if (c == cc)
10585                                                 subtype++;
10586                                         else
10587                                                 pungetc();
10588                                         break;
10589                                 }
10590                         }
10591                 } else {
10592                         pungetc();
10593                 }
10594                 if (dblquote || arinest)
10595                         flags |= VSQUOTE;
10596                 *((char *)stackblock() + typeloc) = subtype | flags;
10597                 if (subtype != VSNORMAL) {
10598                         varnest++;
10599                         if (dblquote || arinest) {
10600                                 dqvarnest++;
10601                         }
10602                 }
10603         }
10604         goto parsesub_return;
10605 }
10606
10607
10608 /*
10609  * Called to parse command substitutions.  Newstyle is set if the command
10610  * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10611  * list of commands (passed by reference), and savelen is the number of
10612  * characters on the top of the stack which must be preserved.
10613  */
10614
10615 parsebackq: {
10616         struct nodelist **nlpp;
10617         int savepbq;
10618         union node *n;
10619         char *volatile str;
10620         struct jmploc jmploc;
10621         struct jmploc *volatile savehandler;
10622         size_t savelen;
10623         int saveprompt;
10624 #ifdef __GNUC__
10625         (void) &saveprompt;
10626 #endif
10627
10628         savepbq = parsebackquote;
10629         if (setjmp(jmploc.loc)) {
10630                 if (str)
10631                         ckfree(str);
10632                 parsebackquote = 0;
10633                 handler = savehandler;
10634                 longjmp(handler->loc, 1);
10635         }
10636         INTOFF;
10637         str = NULL;
10638         savelen = out - (char *)stackblock();
10639         if (savelen > 0) {
10640                 str = ckmalloc(savelen);
10641                 memcpy(str, stackblock(), savelen);
10642         }
10643         savehandler = handler;
10644         handler = &jmploc;
10645         INTON;
10646         if (oldstyle) {
10647                 /* We must read until the closing backquote, giving special
10648                    treatment to some slashes, and then push the string and
10649                    reread it as input, interpreting it normally.  */
10650                 char *pout;
10651                 int pc;
10652                 size_t psavelen;
10653                 char *pstr;
10654
10655
10656                 STARTSTACKSTR(pout);
10657                 for (;;) {
10658                         if (needprompt) {
10659                                 setprompt(2);
10660                                 needprompt = 0;
10661                         }
10662                         switch (pc = pgetc()) {
10663                         case '`':
10664                                 goto done;
10665
10666                         case '\\':
10667                                 if ((pc = pgetc()) == '\n') {
10668                                         plinno++;
10669                                         if (doprompt)
10670                                                 setprompt(2);
10671                                         /*
10672                                          * If eating a newline, avoid putting
10673                                          * the newline into the new character
10674                                          * stream (via the STPUTC after the
10675                                          * switch).
10676                                          */
10677                                         continue;
10678                                 }
10679                                 if (pc != '\\' && pc != '`' && pc != '$'
10680                                     && (!dblquote || pc != '"'))
10681                                         STPUTC('\\', pout);
10682                                 if (pc > PEOA_OR_PEOF) {
10683                                         break;
10684                                 }
10685                                 /* fall through */
10686
10687                         case PEOF:
10688 #ifdef CONFIG_ASH_ALIAS
10689                         case PEOA:
10690 #endif
10691                                 startlinno = plinno;
10692                                 synerror("EOF in backquote substitution");
10693
10694                         case '\n':
10695                                 plinno++;
10696                                 needprompt = doprompt;
10697                                 break;
10698
10699                         default:
10700                                 break;
10701                         }
10702                         STPUTC(pc, pout);
10703                 }
10704 done:
10705                 STPUTC('\0', pout);
10706                 psavelen = pout - (char *)stackblock();
10707                 if (psavelen > 0) {
10708                         pstr = grabstackstr(pout);
10709                         setinputstring(pstr);
10710                 }
10711         }
10712         nlpp = &bqlist;
10713         while (*nlpp)
10714                 nlpp = &(*nlpp)->next;
10715         *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10716         (*nlpp)->next = NULL;
10717         parsebackquote = oldstyle;
10718
10719         if (oldstyle) {
10720                 saveprompt = doprompt;
10721                 doprompt = 0;
10722         }
10723
10724         n = list(2);
10725
10726         if (oldstyle)
10727                 doprompt = saveprompt;
10728         else {
10729                 if (readtoken() != TRP)
10730                         synexpect(TRP);
10731         }
10732
10733         (*nlpp)->n = n;
10734         if (oldstyle) {
10735                 /*
10736                  * Start reading from old file again, ignoring any pushed back
10737                  * tokens left from the backquote parsing
10738                  */
10739                 popfile();
10740                 tokpushback = 0;
10741         }
10742         while (stackblocksize() <= savelen)
10743                 growstackblock();
10744         STARTSTACKSTR(out);
10745         if (str) {
10746                 memcpy(out, str, savelen);
10747                 STADJUST(savelen, out);
10748                 INTOFF;
10749                 ckfree(str);
10750                 str = NULL;
10751                 INTON;
10752         }
10753         parsebackquote = savepbq;
10754         handler = savehandler;
10755         if (arinest || dblquote)
10756                 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10757         else
10758                 USTPUTC(CTLBACKQ, out);
10759         if (oldstyle)
10760                 goto parsebackq_oldreturn;
10761         else
10762                 goto parsebackq_newreturn;
10763 }
10764
10765 #ifdef CONFIG_ASH_MATH_SUPPORT
10766 /*
10767  * Parse an arithmetic expansion (indicate start of one and set state)
10768  */
10769 parsearith: {
10770
10771         if (++arinest == 1) {
10772                 prevsyntax = syntax;
10773                 syntax = ARISYNTAX;
10774                 USTPUTC(CTLARI, out);
10775                 if (dblquote)
10776                         USTPUTC('"',out);
10777                 else
10778                         USTPUTC(' ',out);
10779         } else {
10780                 /*
10781                  * we collapse embedded arithmetic expansion to
10782                  * parenthesis, which should be equivalent
10783                  */
10784                 USTPUTC('(', out);
10785         }
10786         goto parsearith_return;
10787 }
10788 #endif
10789
10790 } /* end of readtoken */
10791
10792
10793
10794 /*
10795  * Returns true if the text contains nothing to expand (no dollar signs
10796  * or backquotes).
10797  */
10798
10799 static int
10800 noexpand(char *text)
10801 {
10802         char *p;
10803         char c;
10804
10805         p = text;
10806         while ((c = *p++) != '\0') {
10807                 if (c == CTLQUOTEMARK)
10808                         continue;
10809                 if (c == CTLESC)
10810                         p++;
10811                 else if (SIT(c, BASESYNTAX) == CCTL)
10812                         return 0;
10813         }
10814         return 1;
10815 }
10816
10817
10818 /*
10819  * Return of a legal variable name (a letter or underscore followed by zero or
10820  * more letters, underscores, and digits).
10821  */
10822
10823 static char *
10824 endofname(const char *name)
10825 {
10826         char *p;
10827
10828         p = (char *) name;
10829         if (! is_name(*p))
10830                 return p;
10831         while (*++p) {
10832                 if (! is_in_name(*p))
10833                         break;
10834         }
10835         return p;
10836 }
10837
10838
10839 /*
10840  * Called when an unexpected token is read during the parse.  The argument
10841  * is the token that is expected, or -1 if more than one type of token can
10842  * occur at this point.
10843  */
10844
10845 static void synexpect(int token)
10846 {
10847         char msg[64];
10848         int l;
10849
10850         l = sprintf(msg, "%s unexpected", tokname(lasttoken));
10851         if (token >= 0)
10852                 sprintf(msg + l, " (expecting %s)", tokname(token));
10853         synerror(msg);
10854         /* NOTREACHED */
10855 }
10856
10857 static void
10858 synerror(const char *msg)
10859 {
10860         error("Syntax error: %s", msg);
10861         /* NOTREACHED */
10862 }
10863
10864
10865 /*
10866  * called by editline -- any expansions to the prompt
10867  *    should be added here.
10868  */
10869
10870 static void setprompt(int whichprompt)
10871 {
10872         const char *prompt;
10873
10874         switch (whichprompt) {
10875         case 1:
10876                 prompt = ps1val();
10877                 break;
10878         case 2:
10879                 prompt = ps2val();
10880                 break;
10881         default:                        /* 0 */
10882                 prompt = nullstr;
10883         }
10884         putprompt(prompt);
10885 }
10886
10887
10888 static const char *const *findkwd(const char *s)
10889 {
10890         return bsearch(s, tokname_array + KWDOFFSET,
10891                        (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET,
10892                                    sizeof(const char *), pstrcmp);
10893 }
10894
10895 /*      $NetBSD: redir.c,v 1.27 2002/11/24 22:35:42 christos Exp $      */
10896
10897 /*
10898  * Code for dealing with input/output redirection.
10899  */
10900
10901 #define EMPTY -2                /* marks an unused slot in redirtab */
10902 #ifndef PIPE_BUF
10903 # define PIPESIZE 4096          /* amount of buffering in a pipe */
10904 #else
10905 # define PIPESIZE PIPE_BUF
10906 #endif
10907
10908 /*
10909  * Open a file in noclobber mode.
10910  * The code was copied from bash.
10911  */
10912 static inline int
10913 noclobberopen(const char *fname)
10914 {
10915         int r, fd;
10916         struct stat finfo, finfo2;
10917
10918         /*
10919          * If the file exists and is a regular file, return an error
10920          * immediately.
10921          */
10922         r = stat(fname, &finfo);
10923         if (r == 0 && S_ISREG(finfo.st_mode)) {
10924                 errno = EEXIST;
10925                 return -1;
10926         }
10927
10928         /*
10929          * If the file was not present (r != 0), make sure we open it
10930          * exclusively so that if it is created before we open it, our open
10931          * will fail.  Make sure that we do not truncate an existing file.
10932          * Note that we don't turn on O_EXCL unless the stat failed -- if the
10933          * file was not a regular file, we leave O_EXCL off.
10934          */
10935         if (r != 0)
10936                 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
10937         fd = open(fname, O_WRONLY|O_CREAT, 0666);
10938
10939         /* If the open failed, return the file descriptor right away. */
10940         if (fd < 0)
10941                 return fd;
10942
10943         /*
10944          * OK, the open succeeded, but the file may have been changed from a
10945          * non-regular file to a regular file between the stat and the open.
10946          * We are assuming that the O_EXCL open handles the case where FILENAME
10947          * did not exist and is symlinked to an existing file between the stat
10948          * and open.
10949          */
10950
10951         /*
10952          * If we can open it and fstat the file descriptor, and neither check
10953          * revealed that it was a regular file, and the file has not been
10954          * replaced, return the file descriptor.
10955          */
10956          if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
10957              finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
10958                 return fd;
10959
10960         /* The file has been replaced.  badness. */
10961         close(fd);
10962         errno = EEXIST;
10963         return -1;
10964 }
10965
10966 /*
10967  * Handle here documents.  Normally we fork off a process to write the
10968  * data to a pipe.  If the document is short, we can stuff the data in
10969  * the pipe without forking.
10970  */
10971
10972 static inline int
10973 openhere(union node *redir)
10974 {
10975         int pip[2];
10976         size_t len = 0;
10977
10978         if (pipe(pip) < 0)
10979                 error("Pipe call failed");
10980         if (redir->type == NHERE) {
10981                 len = strlen(redir->nhere.doc->narg.text);
10982                 if (len <= PIPESIZE) {
10983                         bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
10984                         goto out;
10985                 }
10986         }
10987         if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
10988                 close(pip[0]);
10989                 signal(SIGINT, SIG_IGN);
10990                 signal(SIGQUIT, SIG_IGN);
10991                 signal(SIGHUP, SIG_IGN);
10992 #ifdef SIGTSTP
10993                 signal(SIGTSTP, SIG_IGN);
10994 #endif
10995                 signal(SIGPIPE, SIG_DFL);
10996                 if (redir->type == NHERE)
10997                         bb_full_write(pip[1], redir->nhere.doc->narg.text, len);
10998                 else
10999                         expandhere(redir->nhere.doc, pip[1]);
11000                 _exit(0);
11001         }
11002 out:
11003         close(pip[1]);
11004         return pip[0];
11005 }
11006
11007 static int
11008 openredirect(union node *redir)
11009 {
11010         char *fname;
11011         int f;
11012
11013         switch (redir->nfile.type) {
11014         case NFROM:
11015                 fname = redir->nfile.expfname;
11016                 if ((f = open(fname, O_RDONLY)) < 0)
11017                         goto eopen;
11018                 break;
11019         case NFROMTO:
11020                 fname = redir->nfile.expfname;
11021                 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
11022                         goto ecreate;
11023                 break;
11024         case NTO:
11025                 /* Take care of noclobber mode. */
11026                 if (Cflag) {
11027                         fname = redir->nfile.expfname;
11028                         if ((f = noclobberopen(fname)) < 0)
11029                                 goto ecreate;
11030                         break;
11031                 }
11032                 /* FALLTHROUGH */
11033         case NCLOBBER:
11034                 fname = redir->nfile.expfname;
11035                 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
11036                         goto ecreate;
11037                 break;
11038         case NAPPEND:
11039                 fname = redir->nfile.expfname;
11040                 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
11041                         goto ecreate;
11042                 break;
11043         default:
11044 #ifdef DEBUG
11045                 abort();
11046 #endif
11047                 /* Fall through to eliminate warning. */
11048         case NTOFD:
11049         case NFROMFD:
11050                 f = -1;
11051                 break;
11052         case NHERE:
11053         case NXHERE:
11054                 f = openhere(redir);
11055                 break;
11056         }
11057
11058         return f;
11059 ecreate:
11060         error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
11061 eopen:
11062         error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11063 }
11064
11065 static inline void
11066 dupredirect(union node *redir, int f)
11067 {
11068         int fd = redir->nfile.fd;
11069
11070         if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
11071                 if (redir->ndup.dupfd >= 0) {   /* if not ">&-" */
11072                                 copyfd(redir->ndup.dupfd, fd);
11073                 }
11074                 return;
11075         }
11076
11077         if (f != fd) {
11078                 copyfd(f, fd);
11079                 close(f);
11080         }
11081         return;
11082 }
11083
11084 /*
11085  * Process a list of redirection commands.  If the REDIR_PUSH flag is set,
11086  * old file descriptors are stashed away so that the redirection can be
11087  * undone by calling popredir.  If the REDIR_BACKQ flag is set, then the
11088  * standard output, and the standard error if it becomes a duplicate of
11089  * stdout, is saved in memory.
11090  */
11091
11092 static void
11093 redirect(union node *redir, int flags)
11094 {
11095         union node *n;
11096         struct redirtab *sv;
11097         int i;
11098         int fd;
11099         int newfd;
11100         int *p;
11101         nullredirs++;
11102         if (!redir) {
11103                 return;
11104         }
11105         sv = NULL;
11106         INTOFF;
11107         if (flags & REDIR_PUSH) {
11108                 struct redirtab *q;
11109                 q = ckmalloc(sizeof (struct redirtab));
11110                 q->next = redirlist;
11111                 redirlist = q;
11112                 q->nullredirs = nullredirs - 1;
11113                 for (i = 0 ; i < 10 ; i++)
11114                         q->renamed[i] = EMPTY;
11115                 nullredirs = 0;
11116                 sv = q;
11117         }
11118         n = redir;
11119         do {
11120                 fd = n->nfile.fd;
11121                 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
11122                     n->ndup.dupfd == fd)
11123                         continue; /* redirect from/to same file descriptor */
11124
11125                 newfd = openredirect(n);
11126                 if (fd == newfd)
11127                         continue;
11128                 if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
11129                         i = fcntl(fd, F_DUPFD, 10);
11130
11131                         if (i == -1) {
11132                                 i = errno;
11133                                 if (i != EBADF) {
11134                                         close(newfd);
11135                                         errno = i;
11136                                         error("%d: %m", fd);
11137                                         /* NOTREACHED */
11138                                 }
11139                         } else {
11140                                 *p = i;
11141                                 close(fd);
11142                         }
11143                 } else {
11144                         close(fd);
11145                 }
11146                 dupredirect(n, newfd);
11147         } while ((n = n->nfile.next));
11148         INTON;
11149         if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
11150                 preverrout_fd = sv->renamed[2];
11151 }
11152
11153
11154 /*
11155  * Undo the effects of the last redirection.
11156  */
11157
11158 void
11159 popredir(int drop)
11160 {
11161         struct redirtab *rp;
11162         int i;
11163
11164         if (--nullredirs >= 0)
11165                 return;
11166         INTOFF;
11167         rp = redirlist;
11168         for (i = 0 ; i < 10 ; i++) {
11169                 if (rp->renamed[i] != EMPTY) {
11170                         if (!drop) {
11171                                 close(i);
11172                                 copyfd(rp->renamed[i], i);
11173                         }
11174                         close(rp->renamed[i]);
11175                 }
11176         }
11177         redirlist = rp->next;
11178         nullredirs = rp->nullredirs;
11179         ckfree(rp);
11180         INTON;
11181 }
11182
11183 /*
11184  * Undo all redirections.  Called on error or interrupt.
11185  */
11186
11187 /*
11188  * Discard all saved file descriptors.
11189  */
11190
11191 void
11192 clearredir(int drop)
11193 {
11194         for (;;) {
11195                 nullredirs = 0;
11196                 if (!redirlist)
11197                         break;
11198                 popredir(drop);
11199         }
11200 }
11201
11202
11203 /*
11204  * Copy a file descriptor to be >= to.  Returns -1
11205  * if the source file descriptor is closed, EMPTY if there are no unused
11206  * file descriptors left.
11207  */
11208
11209 int
11210 copyfd(int from, int to)
11211 {
11212         int newfd;
11213
11214         newfd = fcntl(from, F_DUPFD, to);
11215         if (newfd < 0) {
11216                 if (errno == EMFILE)
11217                         return EMPTY;
11218                 else
11219                         error("%d: %m", from);
11220         }
11221         return newfd;
11222 }
11223
11224
11225 int
11226 redirectsafe(union node *redir, int flags)
11227 {
11228         int err;
11229         volatile int saveint;
11230         struct jmploc *volatile savehandler = handler;
11231         struct jmploc jmploc;
11232
11233         SAVEINT(saveint);
11234         if (!(err = setjmp(jmploc.loc) * 2)) {
11235                 handler = &jmploc;
11236                 redirect(redir, flags);
11237         }
11238         handler = savehandler;
11239         if (err && exception != EXERROR)
11240                 longjmp(handler->loc, 1);
11241         RESTOREINT(saveint);
11242         return err;
11243 }
11244
11245 /*      $NetBSD: show.c,v 1.24 2003/01/22 20:36:04 dsl Exp $    */
11246
11247 #ifdef DEBUG
11248 static void shtree(union node *, int, char *, FILE*);
11249 static void shcmd(union node *, FILE *);
11250 static void sharg(union node *, FILE *);
11251 static void indent(int, char *, FILE *);
11252 static void trstring(char *);
11253
11254
11255 void
11256 showtree(union node *n)
11257 {
11258         trputs("showtree called\n");
11259         shtree(n, 1, NULL, stdout);
11260 }
11261
11262
11263 static void
11264 shtree(union node *n, int ind, char *pfx, FILE *fp)
11265 {
11266         struct nodelist *lp;
11267         const char *s;
11268
11269         if (n == NULL)
11270                 return;
11271
11272         indent(ind, pfx, fp);
11273         switch(n->type) {
11274         case NSEMI:
11275                 s = "; ";
11276                 goto binop;
11277         case NAND:
11278                 s = " && ";
11279                 goto binop;
11280         case NOR:
11281                 s = " || ";
11282 binop:
11283                 shtree(n->nbinary.ch1, ind, NULL, fp);
11284            /*    if (ind < 0) */
11285                         fputs(s, fp);
11286                 shtree(n->nbinary.ch2, ind, NULL, fp);
11287                 break;
11288         case NCMD:
11289                 shcmd(n, fp);
11290                 if (ind >= 0)
11291                         putc('\n', fp);
11292                 break;
11293         case NPIPE:
11294                 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
11295                         shcmd(lp->n, fp);
11296                         if (lp->next)
11297                                 fputs(" | ", fp);
11298                 }
11299                 if (n->npipe.backgnd)
11300                         fputs(" &", fp);
11301                 if (ind >= 0)
11302                         putc('\n', fp);
11303                 break;
11304         default:
11305                 fprintf(fp, "<node type %d>", n->type);
11306                 if (ind >= 0)
11307                         putc('\n', fp);
11308                 break;
11309         }
11310 }
11311
11312
11313 static void
11314 shcmd(union node *cmd, FILE *fp)
11315 {
11316         union node *np;
11317         int first;
11318         const char *s;
11319         int dftfd;
11320
11321         first = 1;
11322         for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11323                 if (! first)
11324                         putchar(' ');
11325                 sharg(np, fp);
11326                 first = 0;
11327         }
11328         for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11329                 if (! first)
11330                         putchar(' ');
11331                 switch (np->nfile.type) {
11332                         case NTO:       s = ">";  dftfd = 1; break;
11333                         case NCLOBBER:  s = ">|"; dftfd = 1; break;
11334                         case NAPPEND:   s = ">>"; dftfd = 1; break;
11335                         case NTOFD:     s = ">&"; dftfd = 1; break;
11336                         case NFROM:     s = "<";  dftfd = 0; break;
11337                         case NFROMFD:   s = "<&"; dftfd = 0; break;
11338                         case NFROMTO:   s = "<>"; dftfd = 0; break;
11339                         default:        s = "*error*"; dftfd = 0; break;
11340                 }
11341                 if (np->nfile.fd != dftfd)
11342                         fprintf(fp, "%d", np->nfile.fd);
11343                 fputs(s, fp);
11344                 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11345                         fprintf(fp, "%d", np->ndup.dupfd);
11346                 } else {
11347                         sharg(np->nfile.fname, fp);
11348                 }
11349                 first = 0;
11350         }
11351 }
11352
11353
11354
11355 static void
11356 sharg(union node *arg, FILE *fp)
11357 {
11358         char *p;
11359         struct nodelist *bqlist;
11360         int subtype;
11361
11362         if (arg->type != NARG) {
11363                 out1fmt("<node type %d>\n", arg->type);
11364                 abort();
11365         }
11366         bqlist = arg->narg.backquote;
11367         for (p = arg->narg.text ; *p ; p++) {
11368                 switch (*p) {
11369                 case CTLESC:
11370                         putc(*++p, fp);
11371                         break;
11372                 case CTLVAR:
11373                         putc('$', fp);
11374                         putc('{', fp);
11375                         subtype = *++p;
11376                         if (subtype == VSLENGTH)
11377                                 putc('#', fp);
11378
11379                         while (*p != '=')
11380                                 putc(*p++, fp);
11381
11382                         if (subtype & VSNUL)
11383                                 putc(':', fp);
11384
11385                         switch (subtype & VSTYPE) {
11386                         case VSNORMAL:
11387                                 putc('}', fp);
11388                                 break;
11389                         case VSMINUS:
11390                                 putc('-', fp);
11391                                 break;
11392                         case VSPLUS:
11393                                 putc('+', fp);
11394                                 break;
11395                         case VSQUESTION:
11396                                 putc('?', fp);
11397                                 break;
11398                         case VSASSIGN:
11399                                 putc('=', fp);
11400                                 break;
11401                         case VSTRIMLEFT:
11402                                 putc('#', fp);
11403                                 break;
11404                         case VSTRIMLEFTMAX:
11405                                 putc('#', fp);
11406                                 putc('#', fp);
11407                                 break;
11408                         case VSTRIMRIGHT:
11409                                 putc('%', fp);
11410                                 break;
11411                         case VSTRIMRIGHTMAX:
11412                                 putc('%', fp);
11413                                 putc('%', fp);
11414                                 break;
11415                         case VSLENGTH:
11416                                 break;
11417                         default:
11418                                 out1fmt("<subtype %d>", subtype);
11419                         }
11420                         break;
11421                 case CTLENDVAR:
11422                      putc('}', fp);
11423                      break;
11424                 case CTLBACKQ:
11425                 case CTLBACKQ|CTLQUOTE:
11426                         putc('$', fp);
11427                         putc('(', fp);
11428                         shtree(bqlist->n, -1, NULL, fp);
11429                         putc(')', fp);
11430                         break;
11431                 default:
11432                         putc(*p, fp);
11433                         break;
11434                 }
11435         }
11436 }
11437
11438
11439 static void
11440 indent(int amount, char *pfx, FILE *fp)
11441 {
11442         int i;
11443
11444         for (i = 0 ; i < amount ; i++) {
11445                 if (pfx && i == amount - 1)
11446                         fputs(pfx, fp);
11447                 putc('\t', fp);
11448         }
11449 }
11450
11451
11452
11453 /*
11454  * Debugging stuff.
11455  */
11456
11457
11458 FILE *tracefile;
11459
11460
11461 void
11462 trputc(int c)
11463 {
11464         if (debug != 1)
11465                 return;
11466         putc(c, tracefile);
11467 }
11468
11469 void
11470 trace(const char *fmt, ...)
11471 {
11472         va_list va;
11473
11474         if (debug != 1)
11475                 return;
11476         va_start(va, fmt);
11477         (void) vfprintf(tracefile, fmt, va);
11478         va_end(va);
11479 }
11480
11481 void
11482 tracev(const char *fmt, va_list va)
11483 {
11484         if (debug != 1)
11485                 return;
11486         (void) vfprintf(tracefile, fmt, va);
11487 }
11488
11489
11490 void
11491 trputs(const char *s)
11492 {
11493         if (debug != 1)
11494                 return;
11495         fputs(s, tracefile);
11496 }
11497
11498
11499 static void
11500 trstring(char *s)
11501 {
11502         char *p;
11503         char c;
11504
11505         if (debug != 1)
11506                 return;
11507         putc('"', tracefile);
11508         for (p = s ; *p ; p++) {
11509                 switch (*p) {
11510                 case '\n':  c = 'n';  goto backslash;
11511                 case '\t':  c = 't';  goto backslash;
11512                 case '\r':  c = 'r';  goto backslash;
11513                 case '"':  c = '"';  goto backslash;
11514                 case '\\':  c = '\\';  goto backslash;
11515                 case CTLESC:  c = 'e';  goto backslash;
11516                 case CTLVAR:  c = 'v';  goto backslash;
11517                 case CTLVAR+CTLQUOTE:  c = 'V';  goto backslash;
11518                 case CTLBACKQ:  c = 'q';  goto backslash;
11519                 case CTLBACKQ+CTLQUOTE:  c = 'Q';  goto backslash;
11520 backslash:        putc('\\', tracefile);
11521                         putc(c, tracefile);
11522                         break;
11523                 default:
11524                         if (*p >= ' ' && *p <= '~')
11525                                 putc(*p, tracefile);
11526                         else {
11527                                 putc('\\', tracefile);
11528                                 putc(*p >> 6 & 03, tracefile);
11529                                 putc(*p >> 3 & 07, tracefile);
11530                                 putc(*p & 07, tracefile);
11531                         }
11532                         break;
11533                 }
11534         }
11535         putc('"', tracefile);
11536 }
11537
11538
11539 void
11540 trargs(char **ap)
11541 {
11542         if (debug != 1)
11543                 return;
11544         while (*ap) {
11545                 trstring(*ap++);
11546                 if (*ap)
11547                         putc(' ', tracefile);
11548                 else
11549                         putc('\n', tracefile);
11550         }
11551 }
11552
11553
11554 void
11555 opentrace(void)
11556 {
11557         char s[100];
11558 #ifdef O_APPEND
11559         int flags;
11560 #endif
11561
11562         if (debug != 1) {
11563                 if (tracefile)
11564                         fflush(tracefile);
11565                 /* leave open because libedit might be using it */
11566                 return;
11567         }
11568         scopy("./trace", s);
11569         if (tracefile) {
11570                 if (!freopen(s, "a", tracefile)) {
11571                         fprintf(stderr, "Can't re-open %s\n", s);
11572                         debug = 0;
11573                         return;
11574                 }
11575         } else {
11576                 if ((tracefile = fopen(s, "a")) == NULL) {
11577                         fprintf(stderr, "Can't open %s\n", s);
11578                         debug = 0;
11579                         return;
11580                 }
11581         }
11582 #ifdef O_APPEND
11583         if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
11584                 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
11585 #endif
11586         setlinebuf(tracefile);
11587         fputs("\nTracing started.\n", tracefile);
11588 }
11589 #endif /* DEBUG */
11590
11591
11592 /*      $NetBSD: trap.c,v 1.28 2002/11/24 22:35:43 christos Exp $       */
11593
11594 /*
11595  * Sigmode records the current value of the signal handlers for the various
11596  * modes.  A value of zero means that the current handler is not known.
11597  * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
11598  */
11599
11600 #define S_DFL 1                 /* default signal handling (SIG_DFL) */
11601 #define S_CATCH 2               /* signal is caught */
11602 #define S_IGN 3                 /* signal is ignored (SIG_IGN) */
11603 #define S_HARD_IGN 4            /* signal is ignored permenantly */
11604 #define S_RESET 5               /* temporary - to reset a hard ignored sig */
11605
11606
11607
11608 /*
11609  * The trap builtin.
11610  */
11611
11612 int
11613 trapcmd(int argc, char **argv)
11614 {
11615         char *action;
11616         char **ap;
11617         int signo;
11618
11619         nextopt(nullstr);
11620         ap = argptr;
11621         if (!*ap) {
11622                 for (signo = 0 ; signo < NSIG ; signo++) {
11623                         if (trap[signo] != NULL) {
11624                                 const char *sn;
11625
11626                                 sn = u_signal_names(0, &signo, 0);
11627                                 if (sn == NULL)
11628                                         sn = "???";
11629                                 out1fmt("trap -- %s %s\n",
11630                                         single_quote(trap[signo]), sn);
11631                         }
11632                 }
11633                 return 0;
11634         }
11635         if (!ap[1])
11636                 action = NULL;
11637         else
11638                 action = *ap++;
11639         while (*ap) {
11640                 if ((signo = decode_signal(*ap, 0)) < 0)
11641                         error("%s: bad trap", *ap);
11642                 INTOFF;
11643                 if (action) {
11644                         if (action[0] == '-' && action[1] == '\0')
11645                                 action = NULL;
11646                         else
11647                                 action = savestr(action);
11648                 }
11649                 if (trap[signo])
11650                         ckfree(trap[signo]);
11651                 trap[signo] = action;
11652                 if (signo != 0)
11653                         setsignal(signo);
11654                 INTON;
11655                 ap++;
11656         }
11657         return 0;
11658 }
11659
11660
11661 /*
11662  * Clear traps on a fork.
11663  */
11664
11665 void
11666 clear_traps(void)
11667 {
11668         char **tp;
11669
11670         for (tp = trap ; tp < &trap[NSIG] ; tp++) {
11671                 if (*tp && **tp) {      /* trap not NULL or SIG_IGN */
11672                         INTOFF;
11673                         ckfree(*tp);
11674                         *tp = NULL;
11675                         if (tp != &trap[0])
11676                                 setsignal(tp - trap);
11677                         INTON;
11678                 }
11679         }
11680 }
11681
11682
11683 /*
11684  * Set the signal handler for the specified signal.  The routine figures
11685  * out what it should be set to.
11686  */
11687
11688 void
11689 setsignal(int signo)
11690 {
11691         int action;
11692         char *t, tsig;
11693         struct sigaction act;
11694
11695         if ((t = trap[signo]) == NULL)
11696                 action = S_DFL;
11697         else if (*t != '\0')
11698                 action = S_CATCH;
11699         else
11700                 action = S_IGN;
11701         if (rootshell && action == S_DFL) {
11702                 switch (signo) {
11703                 case SIGINT:
11704                         if (iflag || minusc || sflag == 0)
11705                                 action = S_CATCH;
11706                         break;
11707                 case SIGQUIT:
11708 #ifdef DEBUG
11709                         if (debug)
11710                                 break;
11711 #endif
11712                         /* FALLTHROUGH */
11713                 case SIGTERM:
11714                         if (iflag)
11715                                 action = S_IGN;
11716                         break;
11717 #if JOBS
11718                 case SIGTSTP:
11719                 case SIGTTOU:
11720                         if (mflag)
11721                                 action = S_IGN;
11722                         break;
11723 #endif
11724                 }
11725         }
11726
11727         t = &sigmode[signo - 1];
11728         tsig = *t;
11729         if (tsig == 0) {
11730                 /*
11731                  * current setting unknown
11732                  */
11733                 if (sigaction(signo, 0, &act) == -1) {
11734                         /*
11735                          * Pretend it worked; maybe we should give a warning
11736                          * here, but other shells don't. We don't alter
11737                          * sigmode, so that we retry every time.
11738                          */
11739                         return;
11740                 }
11741                 if (act.sa_handler == SIG_IGN) {
11742                         if (mflag && (signo == SIGTSTP ||
11743                              signo == SIGTTIN || signo == SIGTTOU)) {
11744                                 tsig = S_IGN;   /* don't hard ignore these */
11745                         } else
11746                                 tsig = S_HARD_IGN;
11747                 } else {
11748                         tsig = S_RESET; /* force to be set */
11749                 }
11750         }
11751         if (tsig == S_HARD_IGN || tsig == action)
11752                 return;
11753         switch (action) {
11754         case S_CATCH:
11755                 act.sa_handler = onsig;
11756                 break;
11757         case S_IGN:
11758                 act.sa_handler = SIG_IGN;
11759                 break;
11760         default:
11761                 act.sa_handler = SIG_DFL;
11762         }
11763         *t = action;
11764         act.sa_flags = 0;
11765         sigfillset(&act.sa_mask);
11766         sigaction(signo, &act, 0);
11767 }
11768
11769 /*
11770  * Ignore a signal.
11771  */
11772
11773 void
11774 ignoresig(int signo)
11775 {
11776         if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
11777                 signal(signo, SIG_IGN);
11778         }
11779         sigmode[signo - 1] = S_HARD_IGN;
11780 }
11781
11782
11783 /*
11784  * Signal handler.
11785  */
11786
11787 void
11788 onsig(int signo)
11789 {
11790         gotsig[signo - 1] = 1;
11791         pendingsigs = signo;
11792
11793         if (exsig || (signo == SIGINT && !trap[SIGINT])) {
11794                 if (!suppressint)
11795                         onint();
11796                 intpending = 1;
11797         }
11798 }
11799
11800
11801 /*
11802  * Called to execute a trap.  Perhaps we should avoid entering new trap
11803  * handlers while we are executing a trap handler.
11804  */
11805
11806 void
11807 dotrap(void)
11808 {
11809         char *p;
11810         char *q;
11811         int savestatus;
11812
11813         savestatus = exitstatus;
11814         q = gotsig;
11815         while (pendingsigs = 0, barrier(), (p = memchr(q, 1, NSIG - 1))) {
11816                 *p = 0;
11817                 p = trap[p - q + 1];
11818                 if (!p)
11819                         continue;
11820                 evalstring(p);
11821                 exitstatus = savestatus;
11822         }
11823 }
11824
11825
11826 /*
11827  * Controls whether the shell is interactive or not.
11828  */
11829
11830 void
11831 setinteractive(int on)
11832 {
11833         static int is_interactive;
11834
11835         if (++on == is_interactive)
11836                 return;
11837         is_interactive = on;
11838         setsignal(SIGINT);
11839         setsignal(SIGQUIT);
11840         setsignal(SIGTERM);
11841 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11842                 if(is_interactive > 1) {
11843                         /* Looks like they want an interactive shell */
11844                         static int do_banner;
11845
11846                                 if(!do_banner) {
11847                                         out1fmt(
11848                         "\n\n" BB_BANNER " Built-in shell (ash)\n"
11849                         "Enter 'help' for a list of built-in commands.\n\n");
11850                                         do_banner++;
11851                                 }
11852                 }
11853 #endif
11854 }
11855
11856
11857 #ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
11858 /*** List the available builtins ***/
11859
11860 static int helpcmd(int argc, char **argv)
11861 {
11862         int col, i;
11863
11864         out1fmt("\nBuilt-in commands:\n-------------------\n");
11865         for (col = 0, i = 0; i < NUMBUILTINS; i++) {
11866                 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
11867                                           builtincmd[i].name + 1);
11868                 if (col > 60) {
11869                         out1fmt("\n");
11870                         col = 0;
11871                 }
11872         }
11873 #ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
11874         {
11875                 extern const struct BB_applet applets[];
11876                 extern const size_t NUM_APPLETS;
11877
11878                 for (i = 0; i < NUM_APPLETS; i++) {
11879
11880                         col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name);
11881                         if (col > 60) {
11882                                 out1fmt("\n");
11883                                 col = 0;
11884                         }
11885                 }
11886         }
11887 #endif
11888         out1fmt("\n\n");
11889         return EXIT_SUCCESS;
11890 }
11891 #endif /* CONFIG_FEATURE_SH_EXTRA_QUIET */
11892
11893 /*
11894  * Called to exit the shell.
11895  */
11896
11897 void
11898 exitshell(void)
11899 {
11900         struct jmploc loc;
11901         char *p;
11902         int status;
11903         int jmp;
11904
11905         jmp = setjmp(loc.loc);
11906         status = exitstatus;
11907         TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
11908         if (jmp)
11909                 goto out;
11910         handler = &loc;
11911         if ((p = trap[0]) != NULL && *p != '\0') {
11912                 trap[0] = NULL;
11913                 evalstring(p);
11914         }
11915         flushall();
11916 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
11917         if (iflag && rootshell) {
11918                 const char *hp = lookupvar("HISTFILE");
11919
11920                 if(hp != NULL )
11921                         save_history ( hp );
11922         }
11923 #endif
11924 out:
11925         _exit(status);
11926         /* NOTREACHED */
11927 }
11928
11929 static int decode_signal(const char *string, int minsig)
11930 {
11931         int signo;
11932         const char *name = u_signal_names(string, &signo, minsig);
11933
11934         return name ? signo : -1;
11935 }
11936
11937 /*      $NetBSD: var.c,v 1.32 2003/01/22 20:36:04 dsl Exp $     */
11938
11939 static struct var *vartab[VTABSIZE];
11940
11941 static int vpcmp(const void *, const void *);
11942 static struct var **findvar(struct var **, const char *);
11943
11944 /*
11945  * Initialize the variable symbol tables and import the environment
11946  */
11947
11948
11949 #ifdef CONFIG_ASH_GETOPTS
11950 /*
11951  * Safe version of setvar, returns 1 on success 0 on failure.
11952  */
11953
11954 int
11955 setvarsafe(const char *name, const char *val, int flags)
11956 {
11957         int err;
11958         volatile int saveint;
11959         struct jmploc *volatile savehandler = handler;
11960         struct jmploc jmploc;
11961
11962         SAVEINT(saveint);
11963         if (setjmp(jmploc.loc))
11964                 err = 1;
11965         else {
11966                 handler = &jmploc;
11967                 setvar(name, val, flags);
11968                 err = 0;
11969         }
11970         handler = savehandler;
11971         RESTOREINT(saveint);
11972         return err;
11973 }
11974 #endif
11975
11976 /*
11977  * Set the value of a variable.  The flags argument is ored with the
11978  * flags of the variable.  If val is NULL, the variable is unset.
11979  */
11980
11981 static void
11982 setvar(const char *name, const char *val, int flags)
11983 {
11984         char *p, *q;
11985         size_t namelen;
11986         char *nameeq;
11987         size_t vallen;
11988
11989         q = endofname(name);
11990         p = strchrnul(q, '=');
11991         namelen = p - name;
11992         if (!namelen || p != q)
11993                 error("%.*s: bad variable name", namelen, name);
11994         vallen = 0;
11995         if (val == NULL) {
11996                 flags |= VUNSET;
11997         } else {
11998                 vallen = strlen(val);
11999         }
12000         INTOFF;
12001         p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen);
12002         *p++ = '\0';
12003         if (vallen) {
12004                 p[-1] = '=';
12005                 p = mempcpy(p, val, vallen);
12006         }
12007         *p = '\0';
12008         setvareq(nameeq, flags | VNOSAVE);
12009         INTON;
12010 }
12011
12012
12013 /*
12014  * Same as setvar except that the variable and value are passed in
12015  * the first argument as name=value.  Since the first argument will
12016  * be actually stored in the table, it should not be a string that
12017  * will go away.
12018  * Called with interrupts off.
12019  */
12020
12021 void
12022 setvareq(char *s, int flags)
12023 {
12024         struct var *vp, **vpp;
12025
12026         vpp = hashvar(s);
12027         flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
12028         vp = *findvar(vpp, s);
12029         if (vp) {
12030                 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
12031                         const char *n;
12032
12033                         if (flags & VNOSAVE)
12034                                 free(s);
12035                         n = vp->text;
12036                         error("%.*s: is read only", strchrnul(n, '=') - n, n);
12037                 }
12038
12039                 if (flags & VNOSET)
12040                         return;
12041
12042                 if (vp->func && (flags & VNOFUNC) == 0)
12043                         (*vp->func)(strchrnul(s, '=') + 1);
12044
12045                 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12046                         ckfree(vp->text);
12047
12048                 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
12049         } else {
12050                 if (flags & VNOSET)
12051                         return;
12052                 /* not found */
12053                 vp = ckmalloc(sizeof (*vp));
12054                 vp->next = *vpp;
12055                 vp->func = NULL;
12056                 *vpp = vp;
12057         }
12058         if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
12059                 s = savestr(s);
12060         vp->text = s;
12061         vp->flags = flags;
12062 }
12063
12064
12065 /*
12066  * Process a linked list of variable assignments.
12067  */
12068
12069 static void
12070 listsetvar(struct strlist *list_set_var, int flags)
12071 {
12072         struct strlist *lp = list_set_var;
12073
12074         if (!lp)
12075                 return;
12076         INTOFF;
12077         do {
12078                 setvareq(lp->text, flags);
12079         } while ((lp = lp->next));
12080         INTON;
12081 }
12082
12083
12084 /*
12085  * Find the value of a variable.  Returns NULL if not set.
12086  */
12087
12088 static char *
12089 lookupvar(const char *name)
12090 {
12091         struct var *v;
12092
12093         if ((v = *findvar(hashvar(name), name))) {
12094 #ifdef DYNAMIC_VAR
12095         /*
12096          * Dynamic variables are implemented roughly the same way they are
12097          * in bash. Namely, they're "special" so long as they aren't unset.
12098          * As soon as they're unset, they're no longer dynamic, and dynamic
12099          * lookup will no longer happen at that point. -- PFM.
12100          */
12101                 if((v->flags & VDYNAMIC))
12102                         (*v->func)(NULL);
12103 #endif
12104                 if(!(v->flags & VUNSET))
12105                         return strchrnul(v->text, '=') + 1;
12106         }
12107
12108         return NULL;
12109 }
12110
12111
12112 /*
12113  * Search the environment of a builtin command.
12114  */
12115
12116 static char *
12117 bltinlookup(const char *name)
12118 {
12119         struct strlist *sp;
12120
12121         for (sp = cmdenviron ; sp ; sp = sp->next) {
12122                 if (varequal(sp->text, name))
12123                         return strchrnul(sp->text, '=') + 1;
12124         }
12125         return lookupvar(name);
12126 }
12127
12128
12129 /*
12130  * Generate a list of variables satisfying the given conditions.
12131  */
12132
12133 static char **
12134 listvars(int on, int off, char ***end)
12135 {
12136         struct var **vpp;
12137         struct var *vp;
12138         char **ep;
12139         int mask;
12140
12141         STARTSTACKSTR(ep);
12142         vpp = vartab;
12143         mask = on | off;
12144         do {
12145                 for (vp = *vpp ; vp ; vp = vp->next)
12146                         if ((vp->flags & mask) == on) {
12147                                 if (ep == stackstrend())
12148                                         ep = growstackstr();
12149                                 *ep++ = (char *) vp->text;
12150                         }
12151         } while (++vpp < vartab + VTABSIZE);
12152         if (ep == stackstrend())
12153                 ep = growstackstr();
12154         if (end)
12155                 *end = ep;
12156         *ep++ = NULL;
12157         return grabstackstr(ep);
12158 }
12159
12160
12161 /*
12162  * POSIX requires that 'set' (but not export or readonly) output the
12163  * variables in lexicographic order - by the locale's collating order (sigh).
12164  * Maybe we could keep them in an ordered balanced binary tree
12165  * instead of hashed lists.
12166  * For now just roll 'em through qsort for printing...
12167  */
12168
12169 static int
12170 showvars(const char *sep_prefix, int on, int off)
12171 {
12172         const char *sep;
12173         char **ep, **epend;
12174
12175         ep = listvars(on, off, &epend);
12176         qsort(ep, epend - ep, sizeof(char *), vpcmp);
12177
12178         sep = *sep_prefix ? spcstr : sep_prefix;
12179
12180         for (; ep < epend; ep++) {
12181                 const char *p;
12182                 const char *q;
12183
12184                 p = strchrnul(*ep, '=');
12185                 q = nullstr;
12186                 if (*p)
12187                         q = single_quote(++p);
12188
12189                 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
12190         }
12191
12192         return 0;
12193 }
12194
12195
12196
12197 /*
12198  * The export and readonly commands.
12199  */
12200
12201 static int
12202 exportcmd(int argc, char **argv)
12203 {
12204         struct var *vp;
12205         char *name;
12206         const char *p;
12207         char **aptr;
12208         int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12209         int notp;
12210
12211         notp = nextopt("p") - 'p';
12212         if (notp && ((name = *(aptr = argptr)))) {
12213                 do {
12214                         if ((p = strchr(name, '=')) != NULL) {
12215                                 p++;
12216                         } else {
12217                                 if ((vp = *findvar(hashvar(name), name))) {
12218                                         vp->flags |= flag;
12219                                         continue;
12220                                 }
12221                         }
12222                         setvar(name, p, flag);
12223                 } while ((name = *++aptr) != NULL);
12224         } else {
12225                 showvars(argv[0], flag, 0);
12226         }
12227         return 0;
12228 }
12229
12230
12231 /*
12232  * Make a variable a local variable.  When a variable is made local, it's
12233  * value and flags are saved in a localvar structure.  The saved values
12234  * will be restored when the shell function returns.  We handle the name
12235  * "-" as a special case.
12236  */
12237
12238 static inline void
12239 mklocal(char *name)
12240 {
12241         struct localvar *lvp;
12242         struct var **vpp;
12243         struct var *vp;
12244
12245         INTOFF;
12246         lvp = ckmalloc(sizeof (struct localvar));
12247         if (name[0] == '-' && name[1] == '\0') {
12248                 char *p;
12249                 p = ckmalloc(sizeof(optlist));
12250                 lvp->text = memcpy(p, optlist, sizeof(optlist));
12251                 vp = NULL;
12252         } else {
12253                 char *eq;
12254
12255                 vpp = hashvar(name);
12256                 vp = *findvar(vpp, name);
12257                 eq = strchr(name, '=');
12258                 if (vp == NULL) {
12259                         if (eq)
12260                                 setvareq(name, VSTRFIXED);
12261                         else
12262                                 setvar(name, NULL, VSTRFIXED);
12263                         vp = *vpp;      /* the new variable */
12264                         lvp->flags = VUNSET;
12265                 } else {
12266                         lvp->text = vp->text;
12267                         lvp->flags = vp->flags;
12268                         vp->flags |= VSTRFIXED|VTEXTFIXED;
12269                         if (eq)
12270                                 setvareq(name, 0);
12271                 }
12272         }
12273         lvp->vp = vp;
12274         lvp->next = localvars;
12275         localvars = lvp;
12276         INTON;
12277 }
12278
12279 /*
12280  * The "local" command.
12281  */
12282
12283 static int
12284 localcmd(int argc, char **argv)
12285 {
12286         char *name;
12287
12288         argv = argptr;
12289         while ((name = *argv++) != NULL) {
12290                 mklocal(name);
12291         }
12292         return 0;
12293 }
12294
12295
12296 /*
12297  * Called after a function returns.
12298  * Interrupts must be off.
12299  */
12300
12301 static void
12302 poplocalvars(void)
12303 {
12304         struct localvar *lvp;
12305         struct var *vp;
12306
12307         while ((lvp = localvars) != NULL) {
12308                 localvars = lvp->next;
12309                 vp = lvp->vp;
12310                 TRACE(("poplocalvar %s", vp ? vp->text : "-"));
12311                 if (vp == NULL) {       /* $- saved */
12312                         memcpy(optlist, lvp->text, sizeof(optlist));
12313                         ckfree(lvp->text);
12314                         optschanged();
12315                 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12316                         unsetvar(vp->text);
12317                 } else {
12318                         if (vp->func)
12319                                 (*vp->func)(strchrnul(lvp->text, '=') + 1);
12320                         if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12321                                 ckfree(vp->text);
12322                         vp->flags = lvp->flags;
12323                         vp->text = lvp->text;
12324                 }
12325                 ckfree(lvp);
12326         }
12327 }
12328
12329
12330 /*
12331  * The unset builtin command.  We unset the function before we unset the
12332  * variable to allow a function to be unset when there is a readonly variable
12333  * with the same name.
12334  */
12335
12336 int
12337 unsetcmd(int argc, char **argv)
12338 {
12339         char **ap;
12340         int i;
12341         int flag = 0;
12342         int ret = 0;
12343
12344         while ((i = nextopt("vf")) != '\0') {
12345                 flag = i;
12346         }
12347
12348         for (ap = argptr; *ap ; ap++) {
12349                 if (flag != 'f') {
12350                         i = unsetvar(*ap);
12351                         ret |= i;
12352                         if (!(i & 2))
12353                                 continue;
12354                 }
12355                 if (flag != 'v')
12356                         unsetfunc(*ap);
12357         }
12358         return ret & 1;
12359 }
12360
12361
12362 /*
12363  * Unset the specified variable.
12364  */
12365
12366 int
12367 unsetvar(const char *s)
12368 {
12369         struct var **vpp;
12370         struct var *vp;
12371         int retval;
12372
12373         vpp = findvar(hashvar(s), s);
12374         vp = *vpp;
12375         retval = 2;
12376         if (vp) {
12377                 int flags = vp->flags;
12378
12379                 retval = 1;
12380                 if (flags & VREADONLY)
12381                         goto out;
12382 #ifdef DYNAMIC_VAR
12383                 vp->flags &= ~VDYNAMIC;
12384 #endif
12385                 if (flags & VUNSET)
12386                         goto ok;
12387                 if ((flags & VSTRFIXED) == 0) {
12388                         INTOFF;
12389                         if ((flags & (VTEXTFIXED|VSTACK)) == 0)
12390                                 ckfree(vp->text);
12391                         *vpp = vp->next;
12392                         ckfree(vp);
12393                         INTON;
12394                 } else {
12395                         setvar(s, 0, 0);
12396                         vp->flags &= ~VEXPORT;
12397                 }
12398 ok:
12399                 retval = 0;
12400         }
12401
12402 out:
12403         return retval;
12404 }
12405
12406
12407
12408 /*
12409  * Find the appropriate entry in the hash table from the name.
12410  */
12411
12412 static struct var **
12413 hashvar(const char *p)
12414 {
12415         unsigned int hashval;
12416
12417         hashval = ((unsigned char) *p) << 4;
12418         while (*p && *p != '=')
12419                 hashval += (unsigned char) *p++;
12420         return &vartab[hashval % VTABSIZE];
12421 }
12422
12423
12424
12425 /*
12426  * Compares two strings up to the first = or '\0'.  The first
12427  * string must be terminated by '='; the second may be terminated by
12428  * either '=' or '\0'.
12429  */
12430
12431 int
12432 varcmp(const char *p, const char *q)
12433 {
12434         int c, d;
12435
12436         while ((c = *p) == (d = *q)) {
12437                 if (!c || c == '=')
12438                         goto out;
12439                 p++;
12440                 q++;
12441         }
12442         if (c == '=')
12443                 c = 0;
12444         if (d == '=')
12445                 d = 0;
12446 out:
12447         return c - d;
12448 }
12449
12450 static int
12451 vpcmp(const void *a, const void *b)
12452 {
12453         return varcmp(*(const char **)a, *(const char **)b);
12454 }
12455
12456 static struct var **
12457 findvar(struct var **vpp, const char *name)
12458 {
12459         for (; *vpp; vpp = &(*vpp)->next) {
12460                 if (varequal((*vpp)->text, name)) {
12461                         break;
12462                 }
12463         }
12464         return vpp;
12465 }
12466 /*      $NetBSD: setmode.c,v 1.29 2003/01/15 23:58:03 kleink Exp $      */
12467
12468 #include <sys/times.h>
12469
12470 static const unsigned char timescmd_str[] = {
12471         ' ',  offsetof(struct tms, tms_utime),
12472         '\n', offsetof(struct tms, tms_stime),
12473         ' ',  offsetof(struct tms, tms_cutime),
12474         '\n', offsetof(struct tms, tms_cstime),
12475         0
12476 };
12477
12478 static int timescmd(int ac, char **av)
12479 {
12480         long int clk_tck, s, t;
12481         const unsigned char *p;
12482         struct tms buf;
12483
12484         clk_tck = sysconf(_SC_CLK_TCK);
12485         times(&buf);
12486
12487         p = timescmd_str;
12488         do {
12489                 t = *(clock_t *)(((char *) &buf) + p[1]);
12490                 s = t / clk_tck;
12491                 out1fmt("%ldm%ld.%.3lds%c",
12492                         s/60, s%60,
12493                         ((t - s * clk_tck) * 1000) / clk_tck,
12494                         p[0]);
12495         } while (*(p += 2));
12496
12497         return 0;
12498 }
12499
12500 #ifdef CONFIG_ASH_MATH_SUPPORT
12501 static arith_t
12502 dash_arith(const char *s)
12503 {
12504         arith_t result;
12505         int errcode = 0;
12506
12507         INTOFF;
12508         result = arith(s, &errcode);
12509         if (errcode < 0) {
12510                 if (errcode == -3)
12511                         error("exponent less than 0");
12512                 else if (errcode == -2)
12513                         error("divide by zero");
12514                 else if (errcode == -5)
12515                         error("expression recursion loop detected");
12516                 else
12517                         synerror(s);
12518         }
12519         INTON;
12520
12521         return (result);
12522 }
12523
12524
12525 /*
12526  *  The let builtin. partial stolen from GNU Bash, the Bourne Again SHell.
12527  *  Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
12528  *
12529  *  Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12530  */
12531
12532 static int
12533 letcmd(int argc, char **argv)
12534 {
12535         char **ap;
12536         arith_t i;
12537
12538         ap = argv + 1;
12539         if(!*ap)
12540                 error("expression expected");
12541         for (ap = argv + 1; *ap; ap++) {
12542                 i = dash_arith(*ap);
12543         }
12544
12545         return (!i);
12546 }
12547 #endif /* CONFIG_ASH_MATH_SUPPORT */
12548
12549 /*      $NetBSD: miscbltin.c,v 1.31 2002/11/24 22:35:41 christos Exp $  */
12550
12551 /*
12552  * Miscellaneous builtins.
12553  */
12554
12555 #undef rflag
12556
12557 #ifdef __GLIBC__
12558 #if __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
12559 typedef enum __rlimit_resource rlim_t;
12560 #endif
12561 #endif
12562
12563
12564 /*
12565  * The read builtin.  The -e option causes backslashes to escape the
12566  * following character.
12567  *
12568  * This uses unbuffered input, which may be avoidable in some cases.
12569  */
12570
12571 static int
12572 readcmd(int argc, char **argv)
12573 {
12574         char **ap;
12575         int backslash;
12576         char c;
12577         int rflag;
12578         char *prompt;
12579         const char *ifs;
12580         char *p;
12581         int startword;
12582         int status;
12583         int i;
12584
12585         rflag = 0;
12586         prompt = NULL;
12587         while ((i = nextopt("p:r")) != '\0') {
12588                 if (i == 'p')
12589                         prompt = optionarg;
12590                 else
12591                         rflag = 1;
12592         }
12593         if (prompt && isatty(0)) {
12594                 out2str(prompt);
12595         }
12596         if (*(ap = argptr) == NULL)
12597                 error("arg count");
12598         if ((ifs = bltinlookup("IFS")) == NULL)
12599                 ifs = defifs;
12600         status = 0;
12601         startword = 1;
12602         backslash = 0;
12603         STARTSTACKSTR(p);
12604         for (;;) {
12605                 if (read(0, &c, 1) != 1) {
12606                         status = 1;
12607                         break;
12608                 }
12609                 if (c == '\0')
12610                         continue;
12611                 if (backslash) {
12612                         backslash = 0;
12613                         if (c != '\n')
12614                                 goto put;
12615                         continue;
12616                 }
12617                 if (!rflag && c == '\\') {
12618                         backslash++;
12619                         continue;
12620                 }
12621                 if (c == '\n')
12622                         break;
12623                 if (startword && *ifs == ' ' && strchr(ifs, c)) {
12624                         continue;
12625                 }
12626                 startword = 0;
12627                 if (ap[1] != NULL && strchr(ifs, c) != NULL) {
12628                         STACKSTRNUL(p);
12629                         setvar(*ap, stackblock(), 0);
12630                         ap++;
12631                         startword = 1;
12632                         STARTSTACKSTR(p);
12633                 } else {
12634 put:
12635                         STPUTC(c, p);
12636                 }
12637         }
12638         STACKSTRNUL(p);
12639         /* Remove trailing blanks */
12640         while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)
12641                 *p = '\0';
12642         setvar(*ap, stackblock(), 0);
12643         while (*++ap != NULL)
12644                 setvar(*ap, nullstr, 0);
12645         return status;
12646 }
12647
12648
12649 static int umaskcmd(int argc, char **argv)
12650 {
12651         static const char permuser[3] = "ugo";
12652         static const char permmode[3] = "rwx";
12653         static const short int permmask[] = {
12654                 S_IRUSR, S_IWUSR, S_IXUSR,
12655                 S_IRGRP, S_IWGRP, S_IXGRP,
12656                 S_IROTH, S_IWOTH, S_IXOTH
12657         };
12658
12659         char *ap;
12660         mode_t mask;
12661         int i;
12662         int symbolic_mode = 0;
12663
12664         while (nextopt("S") != '\0') {
12665                 symbolic_mode = 1;
12666         }
12667
12668         INTOFF;
12669         mask = umask(0);
12670         umask(mask);
12671         INTON;
12672
12673         if ((ap = *argptr) == NULL) {
12674                 if (symbolic_mode) {
12675                         char buf[18];
12676                         char *p = buf;
12677
12678                         for (i = 0; i < 3; i++) {
12679                                 int j;
12680
12681                                 *p++ = permuser[i];
12682                                 *p++ = '=';
12683                                 for (j = 0; j < 3; j++) {
12684                                         if ((mask & permmask[3 * i + j]) == 0) {
12685                                                 *p++ = permmode[j];
12686                                         }
12687                                 }
12688                                 *p++ = ',';
12689                         }
12690                         *--p = 0;
12691                         puts(buf);
12692                 } else {
12693                         out1fmt("%.4o\n", mask);
12694                 }
12695         } else {
12696                 if (is_digit((unsigned char) *ap)) {
12697                         mask = 0;
12698                         do {
12699                                 if (*ap >= '8' || *ap < '0')
12700                                         error(illnum, argv[1]);
12701                                 mask = (mask << 3) + (*ap - '0');
12702                         } while (*++ap != '\0');
12703                         umask(mask);
12704                 } else {
12705                         mask = ~mask & 0777;
12706                         if (!bb_parse_mode(ap, &mask)) {
12707                                 error("Illegal mode: %s", ap);
12708                         }
12709                         umask(~mask & 0777);
12710                 }
12711         }
12712         return 0;
12713 }
12714
12715 /*
12716  * ulimit builtin
12717  *
12718  * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
12719  * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
12720  * ash by J.T. Conklin.
12721  *
12722  * Public domain.
12723  */
12724
12725 struct limits {
12726         const char *name;
12727         int     cmd;
12728         int     factor; /* multiply by to get rlim_{cur,max} values */
12729         char    option;
12730 };
12731
12732 static const struct limits limits[] = {
12733 #ifdef RLIMIT_CPU
12734         { "time(seconds)",              RLIMIT_CPU,        1, 't' },
12735 #endif
12736 #ifdef RLIMIT_FSIZE
12737         { "file(blocks)",               RLIMIT_FSIZE,    512, 'f' },
12738 #endif
12739 #ifdef RLIMIT_DATA
12740         { "data(kbytes)",               RLIMIT_DATA,    1024, 'd' },
12741 #endif
12742 #ifdef RLIMIT_STACK
12743         { "stack(kbytes)",              RLIMIT_STACK,   1024, 's' },
12744 #endif
12745 #ifdef  RLIMIT_CORE
12746         { "coredump(blocks)",           RLIMIT_CORE,     512, 'c' },
12747 #endif
12748 #ifdef RLIMIT_RSS
12749         { "memory(kbytes)",             RLIMIT_RSS,     1024, 'm' },
12750 #endif
12751 #ifdef RLIMIT_MEMLOCK
12752         { "locked memory(kbytes)",      RLIMIT_MEMLOCK, 1024, 'l' },
12753 #endif
12754 #ifdef RLIMIT_NPROC
12755         { "process",                    RLIMIT_NPROC,      1, 'p' },
12756 #endif
12757 #ifdef RLIMIT_NOFILE
12758         { "nofiles",                    RLIMIT_NOFILE,     1, 'n' },
12759 #endif
12760 #ifdef RLIMIT_AS
12761         { "vmemory(kbytes)",            RLIMIT_AS,      1024, 'v' },
12762 #endif
12763 #ifdef RLIMIT_LOCKS
12764         { "locks",                      RLIMIT_LOCKS,      1, 'w' },
12765 #endif
12766         { (char *) 0,                   0,                 0,  '\0' }
12767 };
12768
12769 enum limtype { SOFT = 0x1, HARD = 0x2 };
12770
12771 static void printlim(enum limtype how, const struct rlimit *limit,
12772                         const struct limits *l)
12773 {
12774         rlim_t val;
12775
12776         val = limit->rlim_max;
12777         if (how & SOFT)
12778                 val = limit->rlim_cur;
12779
12780         if (val == RLIM_INFINITY)
12781                 out1fmt("unlimited\n");
12782         else {
12783                 val /= l->factor;
12784                 out1fmt("%lld\n", (long long) val);
12785         }
12786 }
12787
12788 int
12789 ulimitcmd(int argc, char **argv)
12790 {
12791         int     c;
12792         rlim_t val = 0;
12793         enum limtype how = SOFT | HARD;
12794         const struct limits     *l;
12795         int             set, all = 0;
12796         int             optc, what;
12797         struct rlimit   limit;
12798
12799         what = 'f';
12800         while ((optc = nextopt("HSa"
12801 #ifdef RLIMIT_CPU
12802                                 "t"
12803 #endif
12804 #ifdef RLIMIT_FSIZE
12805                                 "f"
12806 #endif
12807 #ifdef RLIMIT_DATA
12808                                 "d"
12809 #endif
12810 #ifdef RLIMIT_STACK
12811                                 "s"
12812 #endif
12813 #ifdef RLIMIT_CORE
12814                                 "c"
12815 #endif
12816 #ifdef RLIMIT_RSS
12817                                 "m"
12818 #endif
12819 #ifdef RLIMIT_MEMLOCK
12820                                 "l"
12821 #endif
12822 #ifdef RLIMIT_NPROC
12823                                 "p"
12824 #endif
12825 #ifdef RLIMIT_NOFILE
12826                                 "n"
12827 #endif
12828 #ifdef RLIMIT_AS
12829                                 "v"
12830 #endif
12831 #ifdef RLIMIT_LOCKS
12832                                 "w"
12833 #endif
12834                                                 )) != '\0')
12835                 switch (optc) {
12836                 case 'H':
12837                         how = HARD;
12838                         break;
12839                 case 'S':
12840                         how = SOFT;
12841                         break;
12842                 case 'a':
12843                         all = 1;
12844                         break;
12845                 default:
12846                         what = optc;
12847                 }
12848
12849         for (l = limits; l->option != what; l++)
12850                 ;
12851
12852         set = *argptr ? 1 : 0;
12853         if (set) {
12854                 char *p = *argptr;
12855
12856                 if (all || argptr[1])
12857                         error("too many arguments");
12858                 if (strncmp(p, "unlimited\n", 9) == 0)
12859                         val = RLIM_INFINITY;
12860                 else {
12861                         val = (rlim_t) 0;
12862
12863                         while ((c = *p++) >= '0' && c <= '9')
12864                         {
12865                                 val = (val * 10) + (long)(c - '0');
12866                                 if (val < (rlim_t) 0)
12867                                         break;
12868                         }
12869                         if (c)
12870                                 error("bad number");
12871                         val *= l->factor;
12872                 }
12873         }
12874         if (all) {
12875                 for (l = limits; l->name; l++) {
12876                         getrlimit(l->cmd, &limit);
12877                         out1fmt("%-20s ", l->name);
12878                         printlim(how, &limit, l);
12879                 }
12880                 return 0;
12881         }
12882
12883         getrlimit(l->cmd, &limit);
12884         if (set) {
12885                 if (how & HARD)
12886                         limit.rlim_max = val;
12887                 if (how & SOFT)
12888                         limit.rlim_cur = val;
12889                 if (setrlimit(l->cmd, &limit) < 0)
12890                         error("error setting limit (%m)");
12891         } else {
12892                 printlim(how, &limit, l);
12893         }
12894         return 0;
12895 }
12896
12897
12898 #ifdef CONFIG_ASH_MATH_SUPPORT
12899
12900 /* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
12901
12902    Permission is hereby granted, free of charge, to any person obtaining
12903    a copy of this software and associated documentation files (the
12904    "Software"), to deal in the Software without restriction, including
12905    without limitation the rights to use, copy, modify, merge, publish,
12906    distribute, sublicense, and/or sell copies of the Software, and to
12907    permit persons to whom the Software is furnished to do so, subject to
12908    the following conditions:
12909
12910    The above copyright notice and this permission notice shall be
12911    included in all copies or substantial portions of the Software.
12912
12913    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12914    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12915    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
12916    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
12917    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
12918    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
12919    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12920 */
12921
12922 /* This is my infix parser/evaluator. It is optimized for size, intended
12923  * as a replacement for yacc-based parsers. However, it may well be faster
12924  * than a comparable parser written in yacc. The supported operators are
12925  * listed in #defines below. Parens, order of operations, and error handling
12926  * are supported. This code is thread safe. The exact expression format should
12927  * be that which POSIX specifies for shells. */
12928
12929 /* The code uses a simple two-stack algorithm. See
12930  * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
12931  * for a detailed explanation of the infix-to-postfix algorithm on which
12932  * this is based (this code differs in that it applies operators immediately
12933  * to the stack instead of adding them to a queue to end up with an
12934  * expression). */
12935
12936 /* To use the routine, call it with an expression string and error return
12937  * pointer */
12938
12939 /*
12940  * Aug 24, 2001              Manuel Novoa III
12941  *
12942  * Reduced the generated code size by about 30% (i386) and fixed several bugs.
12943  *
12944  * 1) In arith_apply():
12945  *    a) Cached values of *numptr and &(numptr[-1]).
12946  *    b) Removed redundant test for zero denominator.
12947  *
12948  * 2) In arith():
12949  *    a) Eliminated redundant code for processing operator tokens by moving
12950  *       to a table-based implementation.  Also folded handling of parens
12951  *       into the table.
12952  *    b) Combined all 3 loops which called arith_apply to reduce generated
12953  *       code size at the cost of speed.
12954  *
12955  * 3) The following expressions were treated as valid by the original code:
12956  *       1()  ,    0!  ,    1 ( *3 )   .
12957  *    These bugs have been fixed by internally enclosing the expression in
12958  *    parens and then checking that all binary ops and right parens are
12959  *    preceded by a valid expression (NUM_TOKEN).
12960  *
12961  * Note: It may be desirable to replace Aaron's test for whitespace with
12962  * ctype's isspace() if it is used by another busybox applet or if additional
12963  * whitespace chars should be considered.  Look below the "#include"s for a
12964  * precompiler test.
12965  */
12966
12967 /*
12968  * Aug 26, 2001              Manuel Novoa III
12969  *
12970  * Return 0 for null expressions.  Pointed out by Vladimir Oleynik.
12971  *
12972  * Merge in Aaron's comments previously posted to the busybox list,
12973  * modified slightly to take account of my changes to the code.
12974  *
12975  */
12976
12977 /*
12978  *  (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
12979  *
12980  * - allow access to variable,
12981  *   used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
12982  * - realize assign syntax (VAR=expr, +=, *= etc)
12983  * - realize exponentiation (** operator)
12984  * - realize comma separated - expr, expr
12985  * - realise ++expr --expr expr++ expr--
12986  * - realise expr ? expr : expr (but, second expr calculate always)
12987  * - allow hexadecimal and octal numbers
12988  * - was restored loses XOR operator
12989  * - remove one goto label, added three ;-)
12990  * - protect $((num num)) as true zero expr (Manuel`s error)
12991  * - always use special isspace(), see comment from bash ;-)
12992  */
12993
12994
12995 #define arith_isspace(arithval) \
12996         (arithval == ' ' || arithval == '\n' || arithval == '\t')
12997
12998
12999 typedef unsigned char operator;
13000
13001 /* An operator's token id is a bit of a bitfield. The lower 5 bits are the
13002  * precedence, and 3 high bits are an ID unique across operators of that
13003  * precedence. The ID portion is so that multiple operators can have the
13004  * same precedence, ensuring that the leftmost one is evaluated first.
13005  * Consider * and /. */
13006
13007 #define tok_decl(prec,id) (((id)<<5)|(prec))
13008 #define PREC(op) ((op) & 0x1F)
13009
13010 #define TOK_LPAREN tok_decl(0,0)
13011
13012 #define TOK_COMMA tok_decl(1,0)
13013
13014 #define TOK_ASSIGN tok_decl(2,0)
13015 #define TOK_AND_ASSIGN tok_decl(2,1)
13016 #define TOK_OR_ASSIGN tok_decl(2,2)
13017 #define TOK_XOR_ASSIGN tok_decl(2,3)
13018 #define TOK_PLUS_ASSIGN tok_decl(2,4)
13019 #define TOK_MINUS_ASSIGN tok_decl(2,5)
13020 #define TOK_LSHIFT_ASSIGN tok_decl(2,6)
13021 #define TOK_RSHIFT_ASSIGN tok_decl(2,7)
13022
13023 #define TOK_MUL_ASSIGN tok_decl(3,0)
13024 #define TOK_DIV_ASSIGN tok_decl(3,1)
13025 #define TOK_REM_ASSIGN tok_decl(3,2)
13026
13027 /* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
13028 #define convert_prec_is_assing(prec) do { if(prec == 3) prec = 2; } while(0)
13029
13030 /* conditional is right associativity too */
13031 #define TOK_CONDITIONAL tok_decl(4,0)
13032 #define TOK_CONDITIONAL_SEP tok_decl(4,1)
13033
13034 #define TOK_OR tok_decl(5,0)
13035
13036 #define TOK_AND tok_decl(6,0)
13037
13038 #define TOK_BOR tok_decl(7,0)
13039
13040 #define TOK_BXOR tok_decl(8,0)
13041
13042 #define TOK_BAND tok_decl(9,0)
13043
13044 #define TOK_EQ tok_decl(10,0)
13045 #define TOK_NE tok_decl(10,1)
13046
13047 #define TOK_LT tok_decl(11,0)
13048 #define TOK_GT tok_decl(11,1)
13049 #define TOK_GE tok_decl(11,2)
13050 #define TOK_LE tok_decl(11,3)
13051
13052 #define TOK_LSHIFT tok_decl(12,0)
13053 #define TOK_RSHIFT tok_decl(12,1)
13054
13055 #define TOK_ADD tok_decl(13,0)
13056 #define TOK_SUB tok_decl(13,1)
13057
13058 #define TOK_MUL tok_decl(14,0)
13059 #define TOK_DIV tok_decl(14,1)
13060 #define TOK_REM tok_decl(14,2)
13061
13062 /* exponent is right associativity */
13063 #define TOK_EXPONENT tok_decl(15,1)
13064
13065 /* For now unary operators. */
13066 #define UNARYPREC 16
13067 #define TOK_BNOT tok_decl(UNARYPREC,0)
13068 #define TOK_NOT tok_decl(UNARYPREC,1)
13069
13070 #define TOK_UMINUS tok_decl(UNARYPREC+1,0)
13071 #define TOK_UPLUS tok_decl(UNARYPREC+1,1)
13072
13073 #define PREC_PRE (UNARYPREC+2)
13074
13075 #define TOK_PRE_INC tok_decl(PREC_PRE, 0)
13076 #define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
13077
13078 #define PREC_POST (UNARYPREC+3)
13079
13080 #define TOK_POST_INC tok_decl(PREC_POST, 0)
13081 #define TOK_POST_DEC tok_decl(PREC_POST, 1)
13082
13083 #define SPEC_PREC (UNARYPREC+4)
13084
13085 #define TOK_NUM tok_decl(SPEC_PREC, 0)
13086 #define TOK_RPAREN tok_decl(SPEC_PREC, 1)
13087
13088 #define NUMPTR (*numstackptr)
13089
13090 static inline int tok_have_assign(operator op)
13091 {
13092         operator prec = PREC(op);
13093
13094         convert_prec_is_assing(prec);
13095         return (prec == PREC(TOK_ASSIGN) ||
13096                         prec == PREC_PRE || prec == PREC_POST);
13097 }
13098
13099 static inline int is_right_associativity(operator prec)
13100 {
13101     return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) ||
13102             prec == PREC(TOK_CONDITIONAL));
13103 }
13104
13105
13106 typedef struct ARITCH_VAR_NUM {
13107         arith_t val;
13108         arith_t contidional_second_val;
13109         char contidional_second_val_initialized;
13110         char *var;      /* if NULL then is regular number,
13111                            else is variable name */
13112 } v_n_t;
13113
13114
13115 typedef struct CHK_VAR_RECURSIVE_LOOPED {
13116         const char *var;
13117         struct CHK_VAR_RECURSIVE_LOOPED *next;
13118 } chk_var_recursive_looped_t;
13119
13120 static chk_var_recursive_looped_t *prev_chk_var_recursive;
13121
13122
13123 static int arith_lookup_val(v_n_t *t)
13124 {
13125     if(t->var) {
13126         const char * p = lookupvar(t->var);
13127
13128         if(p) {
13129             int errcode;
13130
13131             /* recursive try as expression */
13132             chk_var_recursive_looped_t *cur;
13133             chk_var_recursive_looped_t cur_save;
13134
13135             for(cur = prev_chk_var_recursive; cur; cur = cur->next) {
13136                 if(strcmp(cur->var, t->var) == 0) {
13137                     /* expression recursion loop detected */
13138                     return -5;
13139                 }
13140             }
13141             /* save current lookuped var name */
13142             cur = prev_chk_var_recursive;
13143             cur_save.var = t->var;
13144             cur_save.next = cur;
13145             prev_chk_var_recursive = &cur_save;
13146
13147             t->val = arith (p, &errcode);
13148             /* restore previous ptr after recursiving */
13149             prev_chk_var_recursive = cur;
13150             return errcode;
13151         } else {
13152             /* allow undefined var as 0 */
13153             t->val = 0;
13154         }
13155     }
13156     return 0;
13157 }
13158
13159 /* "applying" a token means performing it on the top elements on the integer
13160  * stack. For a unary operator it will only change the top element, but a
13161  * binary operator will pop two arguments and push a result */
13162 static inline int
13163 arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr)
13164 {
13165         v_n_t *numptr_m1;
13166         arith_t numptr_val, rez
13167         int ret_arith_lookup_val;
13168
13169         if (NUMPTR == numstack) goto err; /* There is no operator that can work
13170                                                                                  without arguments */
13171         numptr_m1 = NUMPTR - 1;
13172
13173         /* check operand is var with noninteger value */
13174         ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13175         if(ret_arith_lookup_val)
13176                 return ret_arith_lookup_val;
13177
13178         rez = numptr_m1->val;
13179         if (op == TOK_UMINUS)
13180                 rez *= -1;
13181         else if (op == TOK_NOT)
13182                 rez = !rez;
13183         else if (op == TOK_BNOT)
13184                 rez = ~rez;
13185         else if (op == TOK_POST_INC || op == TOK_PRE_INC)
13186                 rez++;
13187         else if (op == TOK_POST_DEC || op == TOK_PRE_DEC)
13188                 rez--;
13189         else if (op != TOK_UPLUS) {
13190                 /* Binary operators */
13191
13192             /* check and binary operators need two arguments */
13193             if (numptr_m1 == numstack) goto err;
13194
13195             /* ... and they pop one */
13196             --NUMPTR;
13197             numptr_val = rez;
13198             if (op == TOK_CONDITIONAL) {
13199                 if(! numptr_m1->contidional_second_val_initialized) {
13200                     /* protect $((expr1 ? expr2)) without ": expr" */
13201                     goto err;
13202                 }
13203                 rez = numptr_m1->contidional_second_val;
13204             } else if(numptr_m1->contidional_second_val_initialized) {
13205                     /* protect $((expr1 : expr2)) without "expr ? " */
13206                     goto err;
13207             }
13208             numptr_m1 = NUMPTR - 1;
13209             if(op != TOK_ASSIGN) {
13210                 /* check operand is var with noninteger value for not '=' */
13211                 ret_arith_lookup_val = arith_lookup_val(numptr_m1);
13212                 if(ret_arith_lookup_val)
13213                     return ret_arith_lookup_val;
13214             }
13215             if (op == TOK_CONDITIONAL) {
13216                     numptr_m1->contidional_second_val = rez;
13217             }
13218             rez = numptr_m1->val;
13219             if (op == TOK_BOR || op == TOK_OR_ASSIGN)
13220                         rez |= numptr_val;
13221             else if (op == TOK_OR)
13222                         rez = numptr_val || rez;
13223             else if (op == TOK_BAND || op == TOK_AND_ASSIGN)
13224                         rez &= numptr_val;
13225             else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN)
13226                         rez ^= numptr_val;
13227             else if (op == TOK_AND)
13228                         rez = rez && numptr_val;
13229             else if (op == TOK_EQ)
13230                         rez = (rez == numptr_val);
13231             else if (op == TOK_NE)
13232                         rez = (rez != numptr_val);
13233             else if (op == TOK_GE)
13234                         rez = (rez >= numptr_val);
13235             else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN)
13236                         rez >>= numptr_val;
13237             else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN)
13238                         rez <<= numptr_val;
13239             else if (op == TOK_GT)
13240                         rez = (rez > numptr_val);
13241             else if (op == TOK_LT)
13242                         rez = (rez < numptr_val);
13243             else if (op == TOK_LE)
13244                         rez = (rez <= numptr_val);
13245             else if (op == TOK_MUL || op == TOK_MUL_ASSIGN)
13246                         rez *= numptr_val;
13247             else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN)
13248                         rez += numptr_val;
13249             else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN)
13250                         rez -= numptr_val;
13251             else if (op == TOK_ASSIGN || op == TOK_COMMA)
13252                         rez = numptr_val;
13253             else if (op == TOK_CONDITIONAL_SEP) {
13254                         if (numptr_m1 == numstack) {
13255                             /* protect $((expr : expr)) without "expr ? " */
13256                             goto err;
13257                         }
13258                         numptr_m1->contidional_second_val_initialized = op;
13259                         numptr_m1->contidional_second_val = numptr_val;
13260             }
13261             else if (op == TOK_CONDITIONAL) {
13262                         rez = rez ?
13263                               numptr_val : numptr_m1->contidional_second_val;
13264             }
13265             else if(op == TOK_EXPONENT) {
13266                         if(numptr_val < 0)
13267                                 return -3;      /* exponent less than 0 */
13268                         else {
13269                                 long c = 1;
13270
13271                                 if(numptr_val)
13272                                         while(numptr_val--)
13273                                                 c *= rez;
13274                                 rez = c;
13275                         }
13276             }
13277             else if(numptr_val==0)          /* zero divisor check */
13278                         return -2;
13279             else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
13280                         rez /= numptr_val;
13281             else if (op == TOK_REM || op == TOK_REM_ASSIGN)
13282                         rez %= numptr_val;
13283         }
13284         if(tok_have_assign(op)) {
13285                 char buf[32];
13286
13287                 if(numptr_m1->var == NULL) {
13288                         /* Hmm, 1=2 ? */
13289                         goto err;
13290                 }
13291                 /* save to shell variable */
13292                 sprintf(buf, "%lld", (long long) rez);
13293                 setvar(numptr_m1->var, buf, 0);
13294                 /* after saving, make previous value for v++ or v-- */
13295                 if(op == TOK_POST_INC)
13296                         rez--;
13297                 else if(op == TOK_POST_DEC)
13298                         rez++;
13299         }
13300         numptr_m1->val = rez;
13301         /* protect geting var value, is number now */
13302         numptr_m1->var = NULL;
13303         return 0;
13304 err: return(-1);
13305 }
13306
13307 /* longest must first */
13308 static const char op_tokens[] = {
13309         '<','<','=',0, TOK_LSHIFT_ASSIGN,
13310         '>','>','=',0, TOK_RSHIFT_ASSIGN,
13311         '<','<',    0, TOK_LSHIFT,
13312         '>','>',    0, TOK_RSHIFT,
13313         '|','|',    0, TOK_OR,
13314         '&','&',    0, TOK_AND,
13315         '!','=',    0, TOK_NE,
13316         '<','=',    0, TOK_LE,
13317         '>','=',    0, TOK_GE,
13318         '=','=',    0, TOK_EQ,
13319         '|','=',    0, TOK_OR_ASSIGN,
13320         '&','=',    0, TOK_AND_ASSIGN,
13321         '*','=',    0, TOK_MUL_ASSIGN,
13322         '/','=',    0, TOK_DIV_ASSIGN,
13323         '%','=',    0, TOK_REM_ASSIGN,
13324         '+','=',    0, TOK_PLUS_ASSIGN,
13325         '-','=',    0, TOK_MINUS_ASSIGN,
13326         '-','-',    0, TOK_POST_DEC,
13327         '^','=',    0, TOK_XOR_ASSIGN,
13328         '+','+',    0, TOK_POST_INC,
13329         '*','*',    0, TOK_EXPONENT,
13330         '!',        0, TOK_NOT,
13331         '<',        0, TOK_LT,
13332         '>',        0, TOK_GT,
13333         '=',        0, TOK_ASSIGN,
13334         '|',        0, TOK_BOR,
13335         '&',        0, TOK_BAND,
13336         '*',        0, TOK_MUL,
13337         '/',        0, TOK_DIV,
13338         '%',        0, TOK_REM,
13339         '+',        0, TOK_ADD,
13340         '-',        0, TOK_SUB,
13341         '^',        0, TOK_BXOR,
13342         /* uniq */
13343         '~',        0, TOK_BNOT,
13344         ',',        0, TOK_COMMA,
13345         '?',        0, TOK_CONDITIONAL,
13346         ':',        0, TOK_CONDITIONAL_SEP,
13347         ')',        0, TOK_RPAREN,
13348         '(',        0, TOK_LPAREN,
13349         0
13350 };
13351 /* ptr to ")" */
13352 #define endexpression &op_tokens[sizeof(op_tokens)-7]
13353
13354
13355 static arith_t arith (const char *expr, int *perrcode)
13356 {
13357     register char arithval; /* Current character under analysis */
13358     operator lasttok, op;
13359     operator prec;
13360
13361     const char *p = endexpression;
13362     int errcode;
13363
13364     size_t datasizes = strlen(expr) + 2;
13365
13366     /* Stack of integers */
13367     /* The proof that there can be no more than strlen(startbuf)/2+1 integers
13368      * in any given correct or incorrect expression is left as an exercise to
13369      * the reader. */
13370     v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)),
13371             *numstackptr = numstack;
13372     /* Stack of operator tokens */
13373     operator *stack = alloca((datasizes) * sizeof(operator)),
13374             *stackptr = stack;
13375
13376     *stackptr++ = lasttok = TOK_LPAREN;     /* start off with a left paren */
13377     *perrcode = errcode = 0;
13378
13379     while(1) {
13380         if ((arithval = *expr) == 0) {
13381                 if (p == endexpression) {
13382                         /* Null expression. */
13383                         return 0;
13384                 }
13385
13386                 /* This is only reached after all tokens have been extracted from the
13387                  * input stream. If there are still tokens on the operator stack, they
13388                  * are to be applied in order. At the end, there should be a final
13389                  * result on the integer stack */
13390
13391                 if (expr != endexpression + 1) {
13392                         /* If we haven't done so already, */
13393                         /* append a closing right paren */
13394                         expr = endexpression;
13395                         /* and let the loop process it. */
13396                         continue;
13397                 }
13398                 /* At this point, we're done with the expression. */
13399                 if (numstackptr != numstack+1) {
13400                         /* ... but if there isn't, it's bad */
13401                   err:
13402                         return (*perrcode = -1);
13403                 }
13404                 if(numstack->var) {
13405                     /* expression is $((var)) only, lookup now */
13406                     errcode = arith_lookup_val(numstack);
13407                 }
13408         ret:
13409                 *perrcode = errcode;
13410                 return numstack->val;
13411         } else {
13412                 /* Continue processing the expression. */
13413                 if (arith_isspace(arithval)) {
13414                         /* Skip whitespace */
13415                         goto prologue;
13416                 }
13417                 if((p = endofname(expr)) != expr) {
13418                         int var_name_size = (p-expr) + 1;  /* trailing zero */
13419
13420                         numstackptr->var = alloca(var_name_size);
13421                         safe_strncpy(numstackptr->var, expr, var_name_size);
13422                         expr = p;
13423                 num:
13424                         numstackptr->contidional_second_val_initialized = 0;
13425                         numstackptr++;
13426                         lasttok = TOK_NUM;
13427                         continue;
13428                 } else if (is_digit(arithval)) {
13429                         numstackptr->var = NULL;
13430                         numstackptr->val = strtol(expr, (char **) &expr, 0);
13431                         goto num;
13432                 }
13433                 for(p = op_tokens; ; p++) {
13434                         const char *o;
13435
13436                         if(*p == 0) {
13437                                 /* strange operator not found */
13438                                 goto err;
13439                         }
13440                         for(o = expr; *p && *o == *p; p++)
13441                                 o++;
13442                         if(! *p) {
13443                                 /* found */
13444                                 expr = o - 1;
13445                                 break;
13446                         }
13447                         /* skip tail uncompared token */
13448                         while(*p)
13449                                 p++;
13450                         /* skip zero delim */
13451                         p++;
13452                 }
13453                 op = p[1];
13454
13455                 /* post grammar: a++ reduce to num */
13456                 if(lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC)
13457                     lasttok = TOK_NUM;
13458
13459                 /* Plus and minus are binary (not unary) _only_ if the last
13460                  * token was as number, or a right paren (which pretends to be
13461                  * a number, since it evaluates to one). Think about it.
13462                  * It makes sense. */
13463                 if (lasttok != TOK_NUM) {
13464                         switch(op) {
13465                                 case TOK_ADD:
13466                                     op = TOK_UPLUS;
13467                                     break;
13468                                 case TOK_SUB:
13469                                     op = TOK_UMINUS;
13470                                     break;
13471                                 case TOK_POST_INC:
13472                                     op = TOK_PRE_INC;
13473                                     break;
13474                                 case TOK_POST_DEC:
13475                                     op = TOK_PRE_DEC;
13476                                     break;
13477                         }
13478                 }
13479                 /* We don't want a unary operator to cause recursive descent on the
13480                  * stack, because there can be many in a row and it could cause an
13481                  * operator to be evaluated before its argument is pushed onto the
13482                  * integer stack. */
13483                 /* But for binary operators, "apply" everything on the operator
13484                  * stack until we find an operator with a lesser priority than the
13485                  * one we have just extracted. */
13486                 /* Left paren is given the lowest priority so it will never be
13487                  * "applied" in this way.
13488                  * if associativity is right and priority eq, applied also skip
13489                  */
13490                 prec = PREC(op);
13491                 if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
13492                         /* not left paren or unary */
13493                         if (lasttok != TOK_NUM) {
13494                                 /* binary op must be preceded by a num */
13495                                 goto err;
13496                         }
13497                         while (stackptr != stack) {
13498                             if (op == TOK_RPAREN) {
13499                                 /* The algorithm employed here is simple: while we don't
13500                                  * hit an open paren nor the bottom of the stack, pop
13501                                  * tokens and apply them */
13502                                 if (stackptr[-1] == TOK_LPAREN) {
13503                                     --stackptr;
13504                                     /* Any operator directly after a */
13505                                     lasttok = TOK_NUM;
13506                                     /* close paren should consider itself binary */
13507                                     goto prologue;
13508                                 }
13509                             } else {
13510                                 operator prev_prec = PREC(stackptr[-1]);
13511
13512                                 convert_prec_is_assing(prec);
13513                                 convert_prec_is_assing(prev_prec);
13514                                 if (prev_prec < prec)
13515                                         break;
13516                                 /* check right assoc */
13517                                 if(prev_prec == prec && is_right_associativity(prec))
13518                                         break;
13519                             }
13520                             errcode = arith_apply(*--stackptr, numstack, &numstackptr);
13521                             if(errcode) goto ret;
13522                         }
13523                         if (op == TOK_RPAREN) {
13524                                 goto err;
13525                         }
13526                 }
13527
13528                 /* Push this operator to the stack and remember it. */
13529                 *stackptr++ = lasttok = op;
13530
13531           prologue:
13532                 ++expr;
13533         }
13534     }
13535 }
13536 #endif /* CONFIG_ASH_MATH_SUPPORT */
13537
13538
13539 #ifdef DEBUG
13540 const char *bb_applet_name = "debug stuff usage";
13541 int main(int argc, char **argv)
13542 {
13543         return ash_main(argc, argv);
13544 }
13545 #endif
13546
13547 /*-
13548  * Copyright (c) 1989, 1991, 1993, 1994
13549  *      The Regents of the University of California.  All rights reserved.
13550  *
13551  * This code is derived from software contributed to Berkeley by
13552  * Kenneth Almquist.
13553  *
13554  * Redistribution and use in source and binary forms, with or without
13555  * modification, are permitted provided that the following conditions
13556  * are met:
13557  * 1. Redistributions of source code must retain the above copyright
13558  *    notice, this list of conditions and the following disclaimer.
13559  * 2. Redistributions in binary form must reproduce the above copyright
13560  *    notice, this list of conditions and the following disclaimer in the
13561  *    documentation and/or other materials provided with the distribution.
13562  *
13563  * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
13564  *              ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
13565  *
13566  * 4. Neither the name of the University nor the names of its contributors
13567  *    may be used to endorse or promote products derived from this software
13568  *    without specific prior written permission.
13569  *
13570  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13571  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13572  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13573  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13574  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13575  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13576  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13577  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13578  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13579  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13580  * SUCH DAMAGE.
13581  */