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