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