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