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