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