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