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