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