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