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