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