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