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