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