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