blob: 4250f50e2186c1505804011468c2e357eb861555 [file] [log] [blame]
Eric Andersendf82f612001-06-28 07:46:40 +00001/* vi: set sw=4 ts=4: */
2/*
3 * ash shell port for busybox
4 *
5 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +00006 * The Regents of the University of California. All rights reserved.
Eric Andersencb57d552001-06-28 07:25:16 +00007 *
8 * This code is derived from software contributed to Berkeley by
9 * Kenneth Almquist.
10 *
Eric Andersendf82f612001-06-28 07:46:40 +000011 * 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.
Eric Andersencb57d552001-06-28 07:25:16 +000015 *
Eric Andersendf82f612001-06-28 07:46:40 +000016 * 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 *
Eric Andersen2870d962001-07-02 17:27:21 +000025 * This version of ash is adapted from the source in Debian's ash 0.3.8-5
26 * package.
Eric Andersendf82f612001-06-28 07:46:40 +000027 *
Eric Andersen2870d962001-07-02 17:27:21 +000028 * Modified by Erik Andersen <andersee@debian.org> and
29 * Vladimir Oleynik <vodz@usa.net> to be used in busybox
30 *
Eric Andersendf82f612001-06-28 07:46:40 +000031 *
32 * Original copyright notice is retained at the end of this file.
Eric Andersencb57d552001-06-28 07:25:16 +000033 */
34
Eric Andersen2870d962001-07-02 17:27:21 +000035
36/* These defines allow you to adjust the feature set to be compiled
37 * into the ash shell. As a rule, enabling these options will make
38 * ash get bigger... With all of these options off, ash adds about
39 * 62k to busybox on an x86 system.*/
40
41
42
43/* Enable job control. This allows you to run jobs in the background,
44 * which is great when ash is being used as an interactive shell, but
Eric Andersen3102ac42001-07-06 04:26:23 +000045 * it completely useless for is all you are doing is running scripts.
Eric Andersen2870d962001-07-02 17:27:21 +000046 * This adds about 2.5k on an x86 system. */
47#define JOBS
48
49/* This enables alias support in ash. If you want to support things
50 * like "alias ls='ls -l'" with ash, enable this. This is only useful
51 * when ash is used as an intractive shell. This adds about 1.5k */
52#define ASH_ALIAS
53
54/* If you need ash to act as a full Posix shell, with full math
55 * support, enable this. This option needs some work, since it
56 * doesn't compile right now... */
Eric Andersencb57d552001-06-28 07:25:16 +000057#undef ASH_MATH_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +000058
59/* This shell builtin is used to indicate how the shell would interpret
60 * what you give it. This command is only useful when debugging, and
61 * is obsolete anyways. Adds about 670 bytes... You probably want to
62 * leave this disabled. */
63#undef ASH_TYPE
64
65/* Getopts is used by shell procedures to parse positional parameters.
66 * You probably want to leave this disabled, and use the busybox getopt
67 * applet if you want to do this sort of thing. There are some scripts
68 * out there that use it, so it you need it, enable. Most people will
69 * leave this disabled. This adds 1k on an x86 system. */
70#undef ASH_GETOPTS
71
72/* This allows you to override shell builtins and use whatever is on
73 * the filesystem. This is most useful when ash is acting as a
74 * standalone shell. Adds about 320 bytes. */
75#undef ASH_CMDCMD
76
77/* This makes a few common apps that are usually part of busybox
78 * anyways to be used as builtins. This may cause these builtins to be
79 * a little bit faster, but leaving this disabled will save you 2k. */
80#undef ASH_BBAPPS_AS_BUILTINS
81
Eric Andersen3102ac42001-07-06 04:26:23 +000082/* Optimize size vs speed as size */
83#define ASH_OPTIMIZE_FOR_SIZE
84
Eric Andersen2870d962001-07-02 17:27:21 +000085/* Enable this to compile in extra debugging noise. When debugging is
86 * on, debugging info will be written to $HOME/trace and a quit signal
87 * will generate a core dump. */
88#undef DEBUG
89
90
91
92/* These are here to work with glibc -- Don't change these... */
Eric Andersendf82f612001-06-28 07:46:40 +000093#undef FNMATCH_BROKEN
94#undef GLOB_BROKEN
Eric Andersen2870d962001-07-02 17:27:21 +000095#undef _GNU_SOURCE
Eric Andersencb57d552001-06-28 07:25:16 +000096
97#include <assert.h>
98#include <ctype.h>
99#include <dirent.h>
100#include <errno.h>
101#include <fcntl.h>
102#include <limits.h>
103#include <paths.h>
104#include <pwd.h>
105#include <setjmp.h>
106#include <signal.h>
107#include <stdarg.h>
108#include <stdbool.h>
109#include <stdio.h>
110#include <stdlib.h>
111#include <string.h>
112#include <sysexits.h>
113#include <unistd.h>
114#include <sys/stat.h>
115#include <sys/cdefs.h>
116#include <sys/ioctl.h>
117#include <sys/param.h>
118#include <sys/resource.h>
119#include <sys/time.h>
120#include <sys/times.h>
121#include <sys/types.h>
122#include <sys/wait.h>
123
124
125#if !defined(FNMATCH_BROKEN)
126#include <fnmatch.h>
127#endif
128#if !defined(GLOB_BROKEN)
129#include <glob.h>
130#endif
131
Eric Andersen2870d962001-07-02 17:27:21 +0000132#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +0000133#include <termios.h>
Eric Andersencb57d552001-06-28 07:25:16 +0000134#endif
135
Eric Andersencb57d552001-06-28 07:25:16 +0000136#include "busybox.h"
Eric Andersen2870d962001-07-02 17:27:21 +0000137#include "cmdedit.h"
138
Eric Andersen2870d962001-07-02 17:27:21 +0000139/*
140 * This file was generated by the mksyntax program.
141 */
142
143/* Syntax classes */
144#define CWORD 0 /* character is nothing special */
145#define CNL 1 /* newline character */
146#define CBACK 2 /* a backslash character */
147#define CSQUOTE 3 /* single quote */
148#define CDQUOTE 4 /* double quote */
149#define CENDQUOTE 5 /* a terminating quote */
150#define CBQUOTE 6 /* backwards single quote */
151#define CVAR 7 /* a dollar sign */
152#define CENDVAR 8 /* a '}' character */
153#define CLP 9 /* a left paren in arithmetic */
154#define CRP 10 /* a right paren in arithmetic */
155#define CENDFILE 11 /* end of file */
156#define CCTL 12 /* like CWORD, except it must be escaped */
157#define CSPCL 13 /* these terminate a word */
158#define CIGN 14 /* character should be ignored */
159
160/* Syntax classes for is_ functions */
161#define ISDIGIT 01 /* a digit */
162#define ISUPPER 02 /* an upper case letter */
163#define ISLOWER 04 /* a lower case letter */
164#define ISUNDER 010 /* an underscore */
165#define ISSPECL 020 /* the name of a special parameter */
166
167#define SYNBASE 130
168#define PEOF -130
169
170#define PEOA -129
171
172#define TEOF 0
173#define TNL 1
174#define TSEMI 2
175#define TBACKGND 3
176#define TAND 4
177#define TOR 5
178#define TPIPE 6
179#define TLP 7
180#define TRP 8
181#define TENDCASE 9
182#define TENDBQUOTE 10
183#define TREDIR 11
184#define TWORD 12
185#define TASSIGN 13
186#define TNOT 14
187#define TCASE 15
188#define TDO 16
189#define TDONE 17
190#define TELIF 18
191#define TELSE 19
192#define TESAC 20
193#define TFI 21
194#define TFOR 22
195#define TIF 23
196#define TIN 24
197#define TTHEN 25
198#define TUNTIL 26
199#define TWHILE 27
200#define TBEGIN 28
201#define TEND 29
202
203
204#define BASESYNTAX (basesyntax + SYNBASE)
205#define DQSYNTAX (dqsyntax + SYNBASE)
206#define SQSYNTAX (sqsyntax + SYNBASE)
207#define ARISYNTAX (arisyntax + SYNBASE)
208
209/* control characters in argument strings */
210#define CTLESC '\201'
211#define CTLVAR '\202'
212#define CTLENDVAR '\203'
213#define CTLBACKQ '\204'
214#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
215/* CTLBACKQ | CTLQUOTE == '\205' */
216#define CTLARI '\206'
217#define CTLENDARI '\207'
218#define CTLQUOTEMARK '\210'
219
220#define is_digit(c) ((((unsigned char)(c)) - '0') <= 9)
221#define is_alpha(c) (((c) < CTLESC || (c) > CTLENDARI) && isalpha((unsigned char) (c)))
222#define is_name(c) (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalpha((unsigned char) (c))))
223#define is_in_name(c) (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalnum((unsigned char) (c))))
224#define is_special(c) ((is_type+SYNBASE)[c] & (ISSPECL|ISDIGIT))
225#define digit_val(c) ((c) - '0')
Eric Andersencb57d552001-06-28 07:25:16 +0000226
227
228#define _DIAGASSERT(x)
229
Eric Andersen3102ac42001-07-06 04:26:23 +0000230
Eric Andersencb57d552001-06-28 07:25:16 +0000231
Eric Andersen2870d962001-07-02 17:27:21 +0000232#define S_DFL 1 /* default signal handling (SIG_DFL) */
233#define S_CATCH 2 /* signal is caught */
234#define S_IGN 3 /* signal is ignored (SIG_IGN) */
235#define S_HARD_IGN 4 /* signal is ignored permenantly */
236#define S_RESET 5 /* temporary - to reset a hard ignored sig */
Eric Andersencb57d552001-06-28 07:25:16 +0000237
238
Eric Andersen2870d962001-07-02 17:27:21 +0000239/* variable substitution byte (follows CTLVAR) */
240#define VSTYPE 0x0f /* type of variable substitution */
241#define VSNUL 0x10 /* colon--treat the empty string as unset */
242#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
Eric Andersencb57d552001-06-28 07:25:16 +0000243
Eric Andersen2870d962001-07-02 17:27:21 +0000244/* values of VSTYPE field */
245#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
246#define VSMINUS 0x2 /* ${var-text} */
247#define VSPLUS 0x3 /* ${var+text} */
248#define VSQUESTION 0x4 /* ${var?message} */
249#define VSASSIGN 0x5 /* ${var=text} */
250#define VSTRIMLEFT 0x6 /* ${var#pattern} */
251#define VSTRIMLEFTMAX 0x7 /* ${var##pattern} */
252#define VSTRIMRIGHT 0x8 /* ${var%pattern} */
253#define VSTRIMRIGHTMAX 0x9 /* ${var%%pattern} */
254#define VSLENGTH 0xa /* ${#var} */
Eric Andersencb57d552001-06-28 07:25:16 +0000255
Eric Andersen2870d962001-07-02 17:27:21 +0000256/* flags passed to redirect */
257#define REDIR_PUSH 01 /* save previous values of file descriptors */
Eric Andersen3102ac42001-07-06 04:26:23 +0000258#define REDIR_BACKQ 02 /* save the command output to pipe */
Eric Andersencb57d552001-06-28 07:25:16 +0000259
Eric Andersen2870d962001-07-02 17:27:21 +0000260/*
261 * BSD setjmp saves the signal mask, which violates ANSI C and takes time,
262 * so we use _setjmp instead.
263 */
264
265#if !defined(__GLIBC__)
266#define setjmp(jmploc) _setjmp(jmploc)
267#define longjmp(jmploc, val) _longjmp(jmploc, val)
268#endif
269
270/*
271 * Most machines require the value returned from malloc to be aligned
272 * in some way. The following macro will get this right on many machines.
273 */
274
275#ifndef ALIGN
276union align {
277 int i;
278 char *cp;
279};
280
281#define ALIGN(nbytes) (((nbytes) + sizeof(union align) - 1) & ~(sizeof(union align) - 1))
282#endif
283
284#ifdef BB_LOCALE_SUPPORT
285#include <locale.h>
286static void change_lc_all(const char *value);
287static void change_lc_ctype(const char *value);
288#endif
289
290/*
291 * These macros allow the user to suspend the handling of interrupt signals
292 * over a period of time. This is similar to SIGHOLD to or sigblock, but
293 * much more efficient and portable. (But hacking the kernel is so much
294 * more fun than worrying about efficiency and portability. :-))
295 */
296
297static void onint (void);
298static volatile int suppressint;
299static volatile int intpending;
300
301#define INTOFF suppressint++
Eric Andersen3102ac42001-07-06 04:26:23 +0000302#ifndef ASH_OPTIMIZE_FOR_SIZE
Eric Andersen2870d962001-07-02 17:27:21 +0000303#define INTON { if (--suppressint == 0 && intpending) onint(); }
Eric Andersen3102ac42001-07-06 04:26:23 +0000304#define FORCEINTON {suppressint = 0; if (intpending) onint();}
Eric Andersen2870d962001-07-02 17:27:21 +0000305#else
306static void __inton (void);
Eric Andersen3102ac42001-07-06 04:26:23 +0000307static void forceinton (void);
Eric Andersen2870d962001-07-02 17:27:21 +0000308#define INTON __inton()
Eric Andersen3102ac42001-07-06 04:26:23 +0000309#define FORCEINTON forceinton()
Eric Andersen2870d962001-07-02 17:27:21 +0000310#endif
Eric Andersen3102ac42001-07-06 04:26:23 +0000311
Eric Andersen2870d962001-07-02 17:27:21 +0000312#define CLEAR_PENDING_INT intpending = 0
313#define int_pending() intpending
314
315
316typedef void *pointer;
317#ifndef NULL
318#define NULL (void *)0
319#endif
320
321static inline pointer ckmalloc (int sz) { return xmalloc(sz); }
322static inline pointer ckrealloc(void *p, int sz) { return xrealloc(p, sz); }
323static inline char * savestr (const char *s) { return xstrdup(s); }
324
325static pointer stalloc (int);
326static void stunalloc (pointer);
327static void ungrabstackstr (char *, char *);
328static char * growstackstr(void);
Eric Andersen3102ac42001-07-06 04:26:23 +0000329static char * makestrspace(size_t newlen);
Eric Andersen2870d962001-07-02 17:27:21 +0000330static char *sstrdup (const char *);
331
332/*
333 * Parse trees for commands are allocated in lifo order, so we use a stack
334 * to make this more efficient, and also to avoid all sorts of exception
335 * handling code to handle interrupts in the middle of a parse.
336 *
337 * The size 504 was chosen because the Ultrix malloc handles that size
338 * well.
339 */
340
341#define MINSIZE 504 /* minimum size of a block */
342
343
344struct stack_block {
345 struct stack_block *prev;
346 char space[MINSIZE];
347};
348
349static struct stack_block stackbase;
350static struct stack_block *stackp = &stackbase;
351static struct stackmark *markp;
352static char *stacknxt = stackbase.space;
353static int stacknleft = MINSIZE;
354
355
356#define equal(s1, s2) (strcmp(s1, s2) == 0)
357
358#define stackblock() stacknxt
359#define stackblocksize() stacknleft
360#define STARTSTACKSTR(p) p = stackblock(), sstrnleft = stackblocksize()
Eric Andersen3102ac42001-07-06 04:26:23 +0000361
Eric Andersen2870d962001-07-02 17:27:21 +0000362#define STPUTC(c, p) (--sstrnleft >= 0? (*p++ = (c)) : (p = growstackstr(), *p++ = (c)))
363#define CHECKSTRSPACE(n, p) { if (sstrnleft < n) p = makestrspace(n); }
Eric Andersen2870d962001-07-02 17:27:21 +0000364#define STACKSTRNUL(p) (sstrnleft == 0? (p = growstackstr(), *p = '\0') : (*p = '\0'))
Eric Andersen3102ac42001-07-06 04:26:23 +0000365
366
367#define USTPUTC(c, p) (--sstrnleft, *p++ = (c))
Eric Andersen2870d962001-07-02 17:27:21 +0000368#define STUNPUTC(p) (++sstrnleft, --p)
369#define STTOPC(p) p[-1]
370#define STADJUST(amount, p) (p += (amount), sstrnleft -= (amount))
371#define grabstackstr(p) stalloc(stackblocksize() - sstrnleft)
372
373#define ckfree(p) free((pointer)(p))
374
Eric Andersen2870d962001-07-02 17:27:21 +0000375
376#ifdef DEBUG
377#define TRACE(param) trace param
378static void trace (const char *, ...);
379static void trargs (char **);
380static void showtree (union node *);
381static void trputc (int);
382static void trputs (const char *);
383static void opentrace (void);
384#else
385#define TRACE(param)
386#endif
387
388#define NSEMI 0
389#define NCMD 1
390#define NPIPE 2
391#define NREDIR 3
392#define NBACKGND 4
393#define NSUBSHELL 5
394#define NAND 6
395#define NOR 7
396#define NIF 8
397#define NWHILE 9
398#define NUNTIL 10
399#define NFOR 11
400#define NCASE 12
401#define NCLIST 13
402#define NDEFUN 14
403#define NARG 15
404#define NTO 16
405#define NFROM 17
406#define NFROMTO 18
407#define NAPPEND 19
408#define NTOOV 20
409#define NTOFD 21
410#define NFROMFD 22
411#define NHERE 23
412#define NXHERE 24
413#define NNOT 25
414
415/*
416 * expandarg() flags
417 */
418#define EXP_FULL 0x1 /* perform word splitting & file globbing */
419#define EXP_TILDE 0x2 /* do normal tilde expansion */
420#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
421#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
422#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
423#define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
424
425
426#define NOPTS 16
427
428static char optet_vals[NOPTS];
429
430static const char * const optlist[NOPTS] = {
431 "e" "errexit",
432 "f" "noglob",
433 "I" "ignoreeof",
434 "i" "interactive",
435 "m" "monitor",
436 "n" "noexec",
437 "s" "stdin",
438 "x" "xtrace",
439 "v" "verbose",
440 "V" "vi",
441 "E" "emacs",
442 "C" "noclobber",
443 "a" "allexport",
444 "b" "notify",
445 "u" "nounset",
446 "q" "quietprofile"
447};
448
449#define optent_name(optent) (optent+1)
450#define optent_letter(optent) optent[0]
451#define optent_val(optent) optet_vals[optent]
452
453#define eflag optent_val(0)
454#define fflag optent_val(1)
455#define Iflag optent_val(2)
456#define iflag optent_val(3)
457#define mflag optent_val(4)
458#define nflag optent_val(5)
459#define sflag optent_val(6)
460#define xflag optent_val(7)
461#define vflag optent_val(8)
462#define Vflag optent_val(9)
463#define Eflag optent_val(10)
464#define Cflag optent_val(11)
465#define aflag optent_val(12)
466#define bflag optent_val(13)
467#define uflag optent_val(14)
468#define qflag optent_val(15)
469
470
471/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
472#define FORK_FG 0
473#define FORK_BG 1
474#define FORK_NOJOB 2
475
476
477struct nbinary {
478 int type;
479 union node *ch1;
480 union node *ch2;
481};
482
483
484struct ncmd {
485 int type;
486 int backgnd;
487 union node *assign;
488 union node *args;
489 union node *redirect;
490};
491
492
493struct npipe {
494 int type;
495 int backgnd;
496 struct nodelist *cmdlist;
497};
498
499
500struct nredir {
501 int type;
502 union node *n;
503 union node *redirect;
504};
505
506
507struct nif {
508 int type;
509 union node *test;
510 union node *ifpart;
511 union node *elsepart;
512};
513
514
515struct nfor {
516 int type;
517 union node *args;
518 union node *body;
519 char *var;
520};
521
522
523struct ncase {
524 int type;
525 union node *expr;
526 union node *cases;
527};
528
529
530struct nclist {
531 int type;
532 union node *next;
533 union node *pattern;
534 union node *body;
535};
536
537
538struct narg {
539 int type;
540 union node *next;
541 char *text;
542 struct nodelist *backquote;
543};
544
545
546struct nfile {
547 int type;
548 union node *next;
549 int fd;
550 union node *fname;
551 char *expfname;
552};
553
554
555struct ndup {
556 int type;
557 union node *next;
558 int fd;
559 int dupfd;
560 union node *vname;
561};
562
563
564struct nhere {
565 int type;
566 union node *next;
567 int fd;
568 union node *doc;
569};
570
571
572struct nnot {
573 int type;
574 union node *com;
575};
576
577
578union node {
579 int type;
580 struct nbinary nbinary;
581 struct ncmd ncmd;
582 struct npipe npipe;
583 struct nredir nredir;
584 struct nif nif;
585 struct nfor nfor;
586 struct ncase ncase;
587 struct nclist nclist;
588 struct narg narg;
589 struct nfile nfile;
590 struct ndup ndup;
591 struct nhere nhere;
592 struct nnot nnot;
593};
594
595
596struct nodelist {
597 struct nodelist *next;
598 union node *n;
599};
600
601struct backcmd { /* result of evalbackcmd */
602 int fd; /* file descriptor to read from */
603 char *buf; /* buffer */
604 int nleft; /* number of chars in buffer */
605 struct job *jp; /* job structure for command */
606};
607
608struct cmdentry {
609 int cmdtype;
610 union param {
611 int index;
612 union node *func;
613 const struct builtincmd *cmd;
614 } u;
615};
616
617struct strlist {
618 struct strlist *next;
619 char *text;
620};
621
622
623struct arglist {
624 struct strlist *list;
625 struct strlist **lastp;
626};
627
628struct strpush {
629 struct strpush *prev; /* preceding string on stack */
630 char *prevstring;
631 int prevnleft;
632#ifdef ASH_ALIAS
633 struct alias *ap; /* if push was associated with an alias */
634#endif
635 char *string; /* remember the string since it may change */
636};
637
638struct parsefile {
639 struct parsefile *prev; /* preceding file on stack */
640 int linno; /* current line */
641 int fd; /* file descriptor (or -1 if string) */
642 int nleft; /* number of chars left in this line */
643 int lleft; /* number of chars left in this buffer */
644 char *nextc; /* next char in buffer */
645 char *buf; /* input buffer */
646 struct strpush *strpush; /* for pushing strings at this level */
647 struct strpush basestrpush; /* so pushing one is fast */
648};
649
650struct stackmark {
651 struct stack_block *stackp;
652 char *stacknxt;
653 int stacknleft;
654 struct stackmark *marknext;
655};
656
657struct shparam {
658 int nparam; /* # of positional parameters (without $0) */
659 unsigned char malloc; /* if parameter list dynamically allocated */
660 char **p; /* parameter list */
661 int optind; /* next parameter to be processed by getopts */
662 int optoff; /* used by getopts */
663};
664
Eric Andersen2870d962001-07-02 17:27:21 +0000665static void flushall (void);
Eric Andersen3102ac42001-07-06 04:26:23 +0000666static void out2fmt (const char *, ...)
667 __attribute__((__format__(__printf__,1,2)));
Eric Andersen2870d962001-07-02 17:27:21 +0000668static void out1fmt (const char *, ...)
669 __attribute__((__format__(__printf__,1,2)));
Eric Andersen2870d962001-07-02 17:27:21 +0000670static int xwrite (int, const char *, int);
Eric Andersen2870d962001-07-02 17:27:21 +0000671
Eric Andersen3102ac42001-07-06 04:26:23 +0000672static void outstr (const char *p, FILE *file) { fputs(p, file); }
673static void out1str(const char *p) { outstr(p, stdout); }
674static void out2str(const char *p) { outstr(p, stderr); }
Eric Andersen2870d962001-07-02 17:27:21 +0000675
Eric Andersen3102ac42001-07-06 04:26:23 +0000676#define out2c(c) putc((c), stderr)
Eric Andersen2870d962001-07-02 17:27:21 +0000677
678/* syntax table used when not in quotes */
679static const char basesyntax[257] = {
680 CENDFILE, CSPCL, CWORD, CCTL,
681 CCTL, CCTL, CCTL, CCTL,
682 CCTL, CCTL, CCTL, CWORD,
683 CWORD, CWORD, CWORD, CWORD,
684 CWORD, CWORD, CWORD, CWORD,
685 CWORD, CWORD, CWORD, CWORD,
686 CWORD, CWORD, CWORD, CWORD,
687 CWORD, CWORD, CWORD, CWORD,
688 CWORD, CWORD, CWORD, CWORD,
689 CWORD, CWORD, CWORD, CWORD,
690 CWORD, CWORD, CWORD, CWORD,
691 CWORD, CWORD, CWORD, CWORD,
692 CWORD, CWORD, CWORD, CWORD,
693 CWORD, CWORD, CWORD, CWORD,
694 CWORD, CWORD, CWORD, CWORD,
695 CWORD, CWORD, CWORD, CWORD,
696 CWORD, CWORD, CWORD, CWORD,
697 CWORD, CWORD, CWORD, CWORD,
698 CWORD, CWORD, CWORD, CWORD,
699 CWORD, CWORD, CWORD, CWORD,
700 CWORD, CWORD, CWORD, CWORD,
701 CWORD, CWORD, CWORD, CWORD,
702 CWORD, CWORD, CWORD, CWORD,
703 CWORD, CWORD, CWORD, CWORD,
704 CWORD, CWORD, CWORD, CWORD,
705 CWORD, CWORD, CWORD, CWORD,
706 CWORD, CWORD, CWORD, CWORD,
707 CWORD, CWORD, CWORD, CWORD,
708 CWORD, CWORD, CWORD, CWORD,
709 CWORD, CWORD, CWORD, CWORD,
710 CWORD, CWORD, CWORD, CWORD,
711 CWORD, CWORD, CWORD, CWORD,
712 CWORD, CWORD, CWORD, CWORD,
713 CWORD, CWORD, CWORD, CWORD,
714 CWORD, CWORD, CWORD, CSPCL,
715 CNL, CWORD, CWORD, CWORD,
716 CWORD, CWORD, CWORD, CWORD,
717 CWORD, CWORD, CWORD, CWORD,
718 CWORD, CWORD, CWORD, CWORD,
719 CWORD, CWORD, CWORD, CWORD,
720 CWORD, CWORD, CSPCL, CWORD,
721 CDQUOTE, CWORD, CVAR, CWORD,
722 CSPCL, CSQUOTE, CSPCL, CSPCL,
723 CWORD, CWORD, CWORD, CWORD,
724 CWORD, CWORD, CWORD, CWORD,
725 CWORD, CWORD, CWORD, CWORD,
726 CWORD, CWORD, CWORD, CWORD,
727 CWORD, CSPCL, CSPCL, CWORD,
728 CSPCL, CWORD, CWORD, CWORD,
729 CWORD, CWORD, CWORD, CWORD,
730 CWORD, CWORD, CWORD, CWORD,
731 CWORD, CWORD, CWORD, CWORD,
732 CWORD, CWORD, CWORD, CWORD,
733 CWORD, CWORD, CWORD, CWORD,
734 CWORD, CWORD, CWORD, CWORD,
735 CWORD, CWORD, CBACK, CWORD,
736 CWORD, CWORD, CBQUOTE, CWORD,
737 CWORD, CWORD, CWORD, CWORD,
738 CWORD, CWORD, CWORD, CWORD,
739 CWORD, CWORD, CWORD, CWORD,
740 CWORD, CWORD, CWORD, CWORD,
741 CWORD, CWORD, CWORD, CWORD,
742 CWORD, CWORD, CWORD, CWORD,
743 CWORD, CWORD, CSPCL, CENDVAR,
744 CWORD
745};
746
747/* syntax table used when in double quotes */
748static const char dqsyntax[257] = {
749 CENDFILE, CIGN, CWORD, CCTL,
750 CCTL, CCTL, CCTL, CCTL,
751 CCTL, CCTL, CCTL, CWORD,
752 CWORD, CWORD, CWORD, CWORD,
753 CWORD, CWORD, CWORD, CWORD,
754 CWORD, CWORD, CWORD, CWORD,
755 CWORD, CWORD, CWORD, CWORD,
756 CWORD, CWORD, CWORD, CWORD,
757 CWORD, CWORD, CWORD, CWORD,
758 CWORD, CWORD, CWORD, CWORD,
759 CWORD, CWORD, CWORD, CWORD,
760 CWORD, CWORD, CWORD, CWORD,
761 CWORD, CWORD, CWORD, CWORD,
762 CWORD, CWORD, CWORD, CWORD,
763 CWORD, CWORD, CWORD, CWORD,
764 CWORD, CWORD, CWORD, CWORD,
765 CWORD, CWORD, CWORD, CWORD,
766 CWORD, CWORD, CWORD, CWORD,
767 CWORD, CWORD, CWORD, CWORD,
768 CWORD, CWORD, CWORD, CWORD,
769 CWORD, CWORD, CWORD, CWORD,
770 CWORD, CWORD, CWORD, CWORD,
771 CWORD, CWORD, CWORD, CWORD,
772 CWORD, CWORD, CWORD, CWORD,
773 CWORD, CWORD, CWORD, CWORD,
774 CWORD, CWORD, CWORD, CWORD,
775 CWORD, CWORD, CWORD, CWORD,
776 CWORD, CWORD, CWORD, CWORD,
777 CWORD, CWORD, CWORD, CWORD,
778 CWORD, CWORD, CWORD, CWORD,
779 CWORD, CWORD, CWORD, CWORD,
780 CWORD, CWORD, CWORD, CWORD,
781 CWORD, CWORD, CWORD, CWORD,
782 CWORD, CWORD, CWORD, CWORD,
783 CWORD, CWORD, CWORD, CWORD,
784 CNL, CWORD, CWORD, CWORD,
785 CWORD, CWORD, CWORD, CWORD,
786 CWORD, CWORD, CWORD, CWORD,
787 CWORD, CWORD, CWORD, CWORD,
788 CWORD, CWORD, CWORD, CWORD,
789 CWORD, CWORD, CWORD, CCTL,
790 CENDQUOTE,CWORD, CVAR, CWORD,
791 CWORD, CWORD, CWORD, CWORD,
792 CCTL, CWORD, CWORD, CCTL,
793 CWORD, CCTL, CWORD, CWORD,
794 CWORD, CWORD, CWORD, CWORD,
795 CWORD, CWORD, CWORD, CWORD,
796 CCTL, CWORD, CWORD, CCTL,
797 CWORD, CCTL, CWORD, CWORD,
798 CWORD, CWORD, CWORD, CWORD,
799 CWORD, CWORD, CWORD, CWORD,
800 CWORD, CWORD, CWORD, CWORD,
801 CWORD, CWORD, CWORD, CWORD,
802 CWORD, CWORD, CWORD, CWORD,
803 CWORD, CWORD, CWORD, CWORD,
804 CWORD, CCTL, CBACK, CCTL,
805 CWORD, CWORD, CBQUOTE, CWORD,
806 CWORD, CWORD, CWORD, CWORD,
807 CWORD, CWORD, CWORD, CWORD,
808 CWORD, CWORD, CWORD, CWORD,
809 CWORD, CWORD, CWORD, CWORD,
810 CWORD, CWORD, CWORD, CWORD,
811 CWORD, CWORD, CWORD, CWORD,
812 CWORD, CWORD, CWORD, CENDVAR,
813 CCTL
814};
815
816/* syntax table used when in single quotes */
817static const char sqsyntax[257] = {
818 CENDFILE, CIGN, CWORD, CCTL,
819 CCTL, CCTL, CCTL, CCTL,
820 CCTL, CCTL, CCTL, CWORD,
821 CWORD, CWORD, CWORD, CWORD,
822 CWORD, CWORD, CWORD, CWORD,
823 CWORD, CWORD, CWORD, CWORD,
824 CWORD, CWORD, CWORD, CWORD,
825 CWORD, CWORD, CWORD, CWORD,
826 CWORD, CWORD, CWORD, CWORD,
827 CWORD, CWORD, CWORD, CWORD,
828 CWORD, CWORD, CWORD, CWORD,
829 CWORD, CWORD, CWORD, CWORD,
830 CWORD, CWORD, CWORD, CWORD,
831 CWORD, CWORD, CWORD, CWORD,
832 CWORD, CWORD, CWORD, CWORD,
833 CWORD, CWORD, CWORD, CWORD,
834 CWORD, CWORD, CWORD, CWORD,
835 CWORD, CWORD, CWORD, CWORD,
836 CWORD, CWORD, CWORD, CWORD,
837 CWORD, CWORD, CWORD, CWORD,
838 CWORD, CWORD, CWORD, CWORD,
839 CWORD, CWORD, CWORD, CWORD,
840 CWORD, CWORD, CWORD, CWORD,
841 CWORD, CWORD, CWORD, CWORD,
842 CWORD, CWORD, CWORD, CWORD,
843 CWORD, CWORD, CWORD, CWORD,
844 CWORD, CWORD, CWORD, CWORD,
845 CWORD, CWORD, CWORD, CWORD,
846 CWORD, CWORD, CWORD, CWORD,
847 CWORD, CWORD, CWORD, CWORD,
848 CWORD, CWORD, CWORD, CWORD,
849 CWORD, CWORD, CWORD, CWORD,
850 CWORD, CWORD, CWORD, CWORD,
851 CWORD, CWORD, CWORD, CWORD,
852 CWORD, CWORD, CWORD, CWORD,
853 CNL, CWORD, CWORD, CWORD,
854 CWORD, CWORD, CWORD, CWORD,
855 CWORD, CWORD, CWORD, CWORD,
856 CWORD, CWORD, CWORD, CWORD,
857 CWORD, CWORD, CWORD, CWORD,
858 CWORD, CWORD, CWORD, CCTL,
859 CWORD, CWORD, CWORD, CWORD,
860 CWORD, CENDQUOTE,CWORD, CWORD,
861 CCTL, CWORD, CWORD, CCTL,
862 CWORD, CCTL, CWORD, CWORD,
863 CWORD, CWORD, CWORD, CWORD,
864 CWORD, CWORD, CWORD, CWORD,
865 CCTL, CWORD, CWORD, CCTL,
866 CWORD, CCTL, CWORD, CWORD,
867 CWORD, CWORD, CWORD, CWORD,
868 CWORD, CWORD, CWORD, CWORD,
869 CWORD, CWORD, CWORD, CWORD,
870 CWORD, CWORD, CWORD, CWORD,
871 CWORD, CWORD, CWORD, CWORD,
872 CWORD, CWORD, CWORD, CWORD,
873 CWORD, CCTL, CCTL, CCTL,
874 CWORD, CWORD, CWORD, CWORD,
875 CWORD, CWORD, CWORD, CWORD,
876 CWORD, CWORD, CWORD, CWORD,
877 CWORD, CWORD, CWORD, CWORD,
878 CWORD, CWORD, CWORD, CWORD,
879 CWORD, CWORD, CWORD, CWORD,
880 CWORD, CWORD, CWORD, CWORD,
881 CWORD, CWORD, CWORD, CWORD,
882 CCTL
883};
884
885/* syntax table used when in arithmetic */
886static const char arisyntax[257] = {
887 CENDFILE, CIGN, CWORD, CCTL,
888 CCTL, CCTL, CCTL, CCTL,
889 CCTL, CCTL, CCTL, CWORD,
890 CWORD, CWORD, CWORD, CWORD,
891 CWORD, CWORD, CWORD, CWORD,
892 CWORD, CWORD, CWORD, CWORD,
893 CWORD, CWORD, CWORD, CWORD,
894 CWORD, CWORD, CWORD, CWORD,
895 CWORD, CWORD, CWORD, CWORD,
896 CWORD, CWORD, CWORD, CWORD,
897 CWORD, CWORD, CWORD, CWORD,
898 CWORD, CWORD, CWORD, CWORD,
899 CWORD, CWORD, CWORD, CWORD,
900 CWORD, CWORD, CWORD, CWORD,
901 CWORD, CWORD, CWORD, CWORD,
902 CWORD, CWORD, CWORD, CWORD,
903 CWORD, CWORD, CWORD, CWORD,
904 CWORD, CWORD, CWORD, CWORD,
905 CWORD, CWORD, CWORD, CWORD,
906 CWORD, CWORD, CWORD, CWORD,
907 CWORD, CWORD, CWORD, CWORD,
908 CWORD, CWORD, CWORD, CWORD,
909 CWORD, CWORD, CWORD, CWORD,
910 CWORD, CWORD, CWORD, CWORD,
911 CWORD, CWORD, CWORD, CWORD,
912 CWORD, CWORD, CWORD, CWORD,
913 CWORD, CWORD, CWORD, CWORD,
914 CWORD, CWORD, CWORD, CWORD,
915 CWORD, CWORD, CWORD, CWORD,
916 CWORD, CWORD, CWORD, CWORD,
917 CWORD, CWORD, CWORD, CWORD,
918 CWORD, CWORD, CWORD, CWORD,
919 CWORD, CWORD, CWORD, CWORD,
920 CWORD, CWORD, CWORD, CWORD,
921 CWORD, CWORD, CWORD, CWORD,
922 CNL, CWORD, CWORD, CWORD,
923 CWORD, CWORD, CWORD, CWORD,
924 CWORD, CWORD, CWORD, CWORD,
925 CWORD, CWORD, CWORD, CWORD,
926 CWORD, CWORD, CWORD, CWORD,
927 CWORD, CWORD, CWORD, CWORD,
928 CDQUOTE, CWORD, CVAR, CWORD,
929 CWORD, CSQUOTE, CLP, CRP,
930 CWORD, CWORD, CWORD, CWORD,
931 CWORD, CWORD, CWORD, CWORD,
932 CWORD, CWORD, CWORD, CWORD,
933 CWORD, CWORD, CWORD, CWORD,
934 CWORD, CWORD, CWORD, CWORD,
935 CWORD, CWORD, CWORD, CWORD,
936 CWORD, CWORD, CWORD, CWORD,
937 CWORD, CWORD, CWORD, CWORD,
938 CWORD, CWORD, CWORD, CWORD,
939 CWORD, CWORD, CWORD, CWORD,
940 CWORD, CWORD, CWORD, CWORD,
941 CWORD, CWORD, CWORD, CWORD,
942 CWORD, CWORD, CBACK, CWORD,
943 CWORD, CWORD, CBQUOTE, CWORD,
944 CWORD, CWORD, CWORD, CWORD,
945 CWORD, CWORD, CWORD, CWORD,
946 CWORD, CWORD, CWORD, CWORD,
947 CWORD, CWORD, CWORD, CWORD,
948 CWORD, CWORD, CWORD, CWORD,
949 CWORD, CWORD, CWORD, CWORD,
950 CWORD, CWORD, CWORD, CENDVAR,
951 CWORD
952};
953
954/* character classification table */
955static const char is_type[257] = {
956 0, 0, 0, 0,
957 0, 0, 0, 0,
958 0, 0, 0, 0,
959 0, 0, 0, 0,
960 0, 0, 0, 0,
961 0, 0, 0, 0,
962 0, 0, 0, 0,
963 0, 0, 0, 0,
964 0, 0, 0, 0,
965 0, 0, 0, 0,
966 0, 0, 0, 0,
967 0, 0, 0, 0,
968 0, 0, 0, 0,
969 0, 0, 0, 0,
970 0, 0, 0, 0,
971 0, 0, 0, 0,
972 0, 0, 0, 0,
973 0, 0, 0, 0,
974 0, 0, 0, 0,
975 0, 0, 0, 0,
976 0, 0, 0, 0,
977 0, 0, 0, 0,
978 0, 0, 0, 0,
979 0, 0, 0, 0,
980 0, 0, 0, 0,
981 0, 0, 0, 0,
982 0, 0, 0, 0,
983 0, 0, 0, 0,
984 0, 0, 0, 0,
985 0, 0, 0, 0,
986 0, 0, 0, 0,
987 0, 0, 0, 0,
988 0, 0, 0, 0,
989 0, 0, 0, 0,
990 0, 0, 0, 0,
991 0, 0, 0, 0,
992 0, 0, 0, 0,
993 0, 0, 0, 0,
994 0, 0, 0, 0,
995 0, 0, 0, 0,
996 0, 0, 0, ISSPECL,
997 0, ISSPECL, ISSPECL, 0,
998 0, 0, 0, 0,
999 ISSPECL, 0, 0, ISSPECL,
1000 0, 0, ISDIGIT, ISDIGIT,
1001 ISDIGIT, ISDIGIT, ISDIGIT, ISDIGIT,
1002 ISDIGIT, ISDIGIT, ISDIGIT, ISDIGIT,
1003 0, 0, 0, 0,
1004 0, ISSPECL, ISSPECL, ISUPPER,
1005 ISUPPER, ISUPPER, ISUPPER, ISUPPER,
1006 ISUPPER, ISUPPER, ISUPPER, ISUPPER,
1007 ISUPPER, ISUPPER, ISUPPER, ISUPPER,
1008 ISUPPER, ISUPPER, ISUPPER, ISUPPER,
1009 ISUPPER, ISUPPER, ISUPPER, ISUPPER,
1010 ISUPPER, ISUPPER, ISUPPER, ISUPPER,
1011 ISUPPER, 0, 0, 0,
1012 0, ISUNDER, 0, ISLOWER,
1013 ISLOWER, ISLOWER, ISLOWER, ISLOWER,
1014 ISLOWER, ISLOWER, ISLOWER, ISLOWER,
1015 ISLOWER, ISLOWER, ISLOWER, ISLOWER,
1016 ISLOWER, ISLOWER, ISLOWER, ISLOWER,
1017 ISLOWER, ISLOWER, ISLOWER, ISLOWER,
1018 ISLOWER, ISLOWER, ISLOWER, ISLOWER,
1019 ISLOWER, 0, 0, 0,
1020 0
1021};
1022
1023/* Array indicating which tokens mark the end of a list */
1024static const char tokendlist[] = {
1025 1,
1026 0,
1027 0,
1028 0,
1029 0,
1030 0,
1031 0,
1032 0,
1033 1,
1034 1,
1035 1,
1036 0,
1037 0,
1038 0,
1039 0,
1040 0,
1041 1,
1042 1,
1043 1,
1044 1,
1045 1,
1046 1,
1047 0,
1048 0,
1049 0,
1050 1,
1051 0,
1052 0,
1053 0,
1054 1,
1055};
1056
1057static const char *const tokname[] = {
1058 "end of file",
1059 "newline",
1060 "\";\"",
1061 "\"&\"",
1062 "\"&&\"",
1063 "\"||\"",
1064 "\"|\"",
1065 "\"(\"",
1066 "\")\"",
1067 "\";;\"",
1068 "\"`\"",
1069 "redirection",
1070 "word",
1071 "assignment",
1072 "\"!\"",
1073 "\"case\"",
1074 "\"do\"",
1075 "\"done\"",
1076 "\"elif\"",
1077 "\"else\"",
1078 "\"esac\"",
1079 "\"fi\"",
1080 "\"for\"",
1081 "\"if\"",
1082 "\"in\"",
1083 "\"then\"",
1084 "\"until\"",
1085 "\"while\"",
1086 "\"{\"",
1087 "\"}\"",
1088};
1089
1090#define KWDOFFSET 14
1091
1092static const char *const parsekwd[] = {
1093 "!",
1094 "case",
1095 "do",
1096 "done",
1097 "elif",
1098 "else",
1099 "esac",
1100 "fi",
1101 "for",
1102 "if",
1103 "in",
1104 "then",
1105 "until",
1106 "while",
1107 "{",
1108 "}"
1109};
1110
1111
1112static int plinno = 1; /* input line number */
1113
1114static int parselleft; /* copy of parsefile->lleft */
1115
1116static struct parsefile basepf; /* top level input file */
1117static char basebuf[BUFSIZ]; /* buffer for top level input file */
1118static struct parsefile *parsefile = &basepf; /* current input file */
1119
1120/*
1121 * NEOF is returned by parsecmd when it encounters an end of file. It
1122 * must be distinct from NULL, so we use the address of a variable that
1123 * happens to be handy.
1124 */
1125
1126static int tokpushback; /* last token pushed back */
1127#define NEOF ((union node *)&tokpushback)
1128static int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */
1129
1130
1131static void error (const char *, ...) __attribute__((__noreturn__));
1132static void exerror (int, const char *, ...) __attribute__((__noreturn__));
1133static void shellexec (char **, char **, const char *, int)
1134 __attribute__((noreturn));
1135static void exitshell (int) __attribute__((noreturn));
1136
1137static int goodname(const char *);
1138static void ignoresig (int);
1139static void onsig (int);
1140static void dotrap (void);
1141static int decode_signal (const char *, int);
1142
1143static void shprocvar(void);
1144static void deletefuncs(void);
1145static void setparam (char **);
1146static void freeparam (volatile struct shparam *);
1147
1148/* reasons for skipping commands (see comment on breakcmd routine) */
1149#define SKIPBREAK 1
1150#define SKIPCONT 2
1151#define SKIPFUNC 3
1152#define SKIPFILE 4
1153
1154/* values of cmdtype */
1155#define CMDUNKNOWN -1 /* no entry in table for command */
1156#define CMDNORMAL 0 /* command is an executable program */
1157#define CMDBUILTIN 1 /* command is a shell builtin */
1158#define CMDFUNCTION 2 /* command is a shell function */
1159
1160#define DO_ERR 1 /* find_command prints errors */
1161#define DO_ABS 2 /* find_command checks absolute paths */
1162#define DO_NOFUN 4 /* find_command ignores functions */
1163#define DO_BRUTE 8 /* find_command ignores hash table */
1164
1165/*
1166 * Shell variables.
1167 */
1168
1169/* flags */
1170#define VEXPORT 0x01 /* variable is exported */
1171#define VREADONLY 0x02 /* variable cannot be modified */
1172#define VSTRFIXED 0x04 /* variable struct is staticly allocated */
1173#define VTEXTFIXED 0x08 /* text is staticly allocated */
1174#define VSTACK 0x10 /* text is allocated on the stack */
1175#define VUNSET 0x20 /* the variable is not set */
1176#define VNOFUNC 0x40 /* don't call the callback function */
1177
1178
1179struct var {
1180 struct var *next; /* next entry in hash list */
1181 int flags; /* flags are defined above */
1182 char *text; /* name=value */
1183 void (*func) (const char *);
1184 /* function to be called when */
1185 /* the variable gets set/unset */
1186};
1187
1188struct localvar {
1189 struct localvar *next; /* next local variable in list */
1190 struct var *vp; /* the variable that was made local */
1191 int flags; /* saved flags */
1192 char *text; /* saved text */
1193};
1194
1195
1196#if defined(__GLIBC__) && !defined(FNMATCH_BROKEN)
1197#define rmescapes(p) _rmescapes((p), 0)
1198static char *_rmescapes (char *, int);
1199#else
1200static void rmescapes (char *);
1201#endif
1202
1203static int casematch (union node *, const char *);
1204static void clearredir(void);
1205static void popstring(void);
1206static void readcmdfile (const char *);
1207
1208static int number (const char *);
1209static int is_number (const char *, int *num);
1210static char *single_quote (const char *);
1211static int nextopt (const char *);
1212
1213static void redirect (union node *, int);
1214static void popredir (void);
1215static int dup_as_newfd (int, int);
1216
1217static void changepath(const char *newval);
1218static void getoptsreset(const char *value);
1219
1220
1221static int parsenleft; /* copy of parsefile->nleft */
1222static char *parsenextc; /* copy of parsefile->nextc */
1223static int rootpid; /* pid of main shell */
1224static int rootshell; /* true if we aren't a child of the main shell */
1225
1226static const char spcstr[] = " ";
1227static const char snlfmt[] = "%s\n";
1228
1229static int sstrnleft;
1230static int herefd = -1;
1231
1232static struct localvar *localvars;
1233
1234static struct var vifs;
1235static struct var vmail;
1236static struct var vmpath;
1237static struct var vpath;
1238static struct var vps1;
1239static struct var vps2;
1240static struct var voptind;
1241#ifdef BB_LOCALE_SUPPORT
1242static struct var vlc_all;
1243static struct var vlc_ctype;
1244#endif
1245
1246struct varinit {
1247 struct var *var;
1248 int flags;
1249 const char *text;
1250 void (*func) (const char *);
1251};
1252
1253static const char defpathvar[] =
1254 "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
1255#define defpath (defpathvar + 5)
1256
1257#ifdef IFS_BROKEN
1258static const char defifsvar[] = "IFS= \t\n";
1259#define defifs (defifsvar + 4)
1260#else
1261static const char defifs[] = " \t\n";
1262#endif
1263
1264static const struct varinit varinit[] = {
1265#ifdef IFS_BROKEN
1266 { &vifs, VSTRFIXED|VTEXTFIXED, defifsvar,
1267#else
1268 { &vifs, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS=",
1269#endif
1270 NULL },
1271 { &vmail, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL=",
1272 NULL },
1273 { &vmpath, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH=",
1274 NULL },
1275 { &vpath, VSTRFIXED|VTEXTFIXED, defpathvar,
1276 changepath },
1277 /*
1278 * vps1 depends on uid
1279 */
1280 { &vps2, VSTRFIXED|VTEXTFIXED, "PS2=> ",
1281 NULL },
1282 { &voptind, VSTRFIXED|VTEXTFIXED, "OPTIND=1",
1283 getoptsreset },
1284#ifdef BB_LOCALE_SUPPORT
1285 { &vlc_all, VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL=",
1286 change_lc_all },
1287 { &vlc_ctype, VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE=",
1288 change_lc_ctype },
1289#endif
1290 { NULL, 0, NULL,
1291 NULL }
1292};
1293
1294#define VTABSIZE 39
1295
1296static struct var *vartab[VTABSIZE];
1297
1298/*
1299 * The following macros access the values of the above variables.
1300 * They have to skip over the name. They return the null string
1301 * for unset variables.
1302 */
1303
1304#define ifsval() (vifs.text + 4)
1305#define ifsset() ((vifs.flags & VUNSET) == 0)
1306#define mailval() (vmail.text + 5)
1307#define mpathval() (vmpath.text + 9)
1308#define pathval() (vpath.text + 5)
1309#define ps1val() (vps1.text + 4)
1310#define ps2val() (vps2.text + 4)
1311#define optindval() (voptind.text + 7)
1312
1313#define mpathset() ((vmpath.flags & VUNSET) == 0)
1314
1315static void initvar (void);
1316static void setvar (const char *, const char *, int);
1317static void setvareq (char *, int);
1318static void listsetvar (struct strlist *);
1319static char *lookupvar (const char *);
1320static char *bltinlookup (const char *);
1321static char **environment (void);
1322static int showvarscmd (int, char **);
1323static void mklocal (char *);
1324static void poplocalvars (void);
1325static int unsetvar (const char *);
1326static int varequal (const char *, const char *);
1327
1328
1329static char *arg0; /* value of $0 */
1330static struct shparam shellparam; /* current positional parameters */
1331static char **argptr; /* argument list for builtin commands */
1332static char *optionarg; /* set by nextopt (like getopt) */
1333static char *optptr; /* used by nextopt */
1334static char *minusc; /* argument to -c option */
1335
1336
1337#ifdef ASH_ALIAS
1338
1339#define ALIASINUSE 1
1340#define ALIASDEAD 2
1341
Eric Andersen3102ac42001-07-06 04:26:23 +00001342#define ATABSIZE 39
1343
Eric Andersen2870d962001-07-02 17:27:21 +00001344struct alias {
1345 struct alias *next;
1346 char *name;
1347 char *val;
1348 int flag;
1349};
1350
1351static struct alias *atab[ATABSIZE];
1352
1353static void setalias (char *, char *);
1354static struct alias **hashalias (const char *);
1355static struct alias *freealias (struct alias *);
1356static struct alias **__lookupalias (const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00001357
1358static void
1359setalias(name, val)
1360 char *name, *val;
1361{
1362 struct alias *ap, **app;
1363
1364 app = __lookupalias(name);
1365 ap = *app;
1366 INTOFF;
1367 if (ap) {
1368 if (!(ap->flag & ALIASINUSE)) {
1369 ckfree(ap->val);
1370 }
Eric Andersen2870d962001-07-02 17:27:21 +00001371 ap->val = savestr(val);
Eric Andersencb57d552001-06-28 07:25:16 +00001372 ap->flag &= ~ALIASDEAD;
1373 } else {
1374 /* not found */
1375 ap = ckmalloc(sizeof (struct alias));
1376 ap->name = savestr(name);
1377 ap->val = savestr(val);
1378 ap->flag = 0;
1379 ap->next = 0;
1380 *app = ap;
1381 }
1382 INTON;
1383}
1384
1385static int
Eric Andersen2870d962001-07-02 17:27:21 +00001386unalias(char *name)
1387{
Eric Andersencb57d552001-06-28 07:25:16 +00001388 struct alias **app;
1389
1390 app = __lookupalias(name);
1391
1392 if (*app) {
1393 INTOFF;
1394 *app = freealias(*app);
1395 INTON;
1396 return (0);
1397 }
1398
1399 return (1);
1400}
1401
Eric Andersencb57d552001-06-28 07:25:16 +00001402static void
Eric Andersen2870d962001-07-02 17:27:21 +00001403rmaliases(void)
1404{
Eric Andersencb57d552001-06-28 07:25:16 +00001405 struct alias *ap, **app;
1406 int i;
1407
1408 INTOFF;
1409 for (i = 0; i < ATABSIZE; i++) {
1410 app = &atab[i];
1411 for (ap = *app; ap; ap = *app) {
1412 *app = freealias(*app);
1413 if (ap == *app) {
1414 app = &ap->next;
1415 }
1416 }
1417 }
1418 INTON;
1419}
1420
Eric Andersen2870d962001-07-02 17:27:21 +00001421static struct alias *
1422lookupalias(const char *name, int check)
Eric Andersencb57d552001-06-28 07:25:16 +00001423{
1424 struct alias *ap = *__lookupalias(name);
1425
1426 if (check && ap && (ap->flag & ALIASINUSE))
1427 return (NULL);
1428 return (ap);
1429}
1430
Eric Andersen2870d962001-07-02 17:27:21 +00001431static void
1432printalias(const struct alias *ap) {
1433 char *p;
1434
1435 p = single_quote(ap->val);
1436 out1fmt("alias %s=%s\n", ap->name, p);
1437 stunalloc(p);
1438}
1439
Eric Andersencb57d552001-06-28 07:25:16 +00001440
1441/*
1442 * TODO - sort output
1443 */
1444static int
Eric Andersen2870d962001-07-02 17:27:21 +00001445aliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00001446{
1447 char *n, *v;
1448 int ret = 0;
1449 struct alias *ap;
1450
1451 if (argc == 1) {
1452 int i;
1453
1454 for (i = 0; i < ATABSIZE; i++)
1455 for (ap = atab[i]; ap; ap = ap->next) {
1456 printalias(ap);
1457 }
1458 return (0);
1459 }
1460 while ((n = *++argv) != NULL) {
1461 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
1462 if ((ap = *__lookupalias(n)) == NULL) {
Eric Andersen3102ac42001-07-06 04:26:23 +00001463 out2fmt("%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00001464 ret = 1;
1465 } else
1466 printalias(ap);
1467 }
1468 else {
1469 *v++ = '\0';
1470 setalias(n, v);
1471 }
1472 }
1473
1474 return (ret);
1475}
1476
1477static int
Eric Andersen2870d962001-07-02 17:27:21 +00001478unaliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00001479{
1480 int i;
1481
1482 while ((i = nextopt("a")) != '\0') {
1483 if (i == 'a') {
1484 rmaliases();
1485 return (0);
1486 }
1487 }
1488 for (i = 0; *argptr; argptr++) {
1489 if (unalias(*argptr)) {
Eric Andersen3102ac42001-07-06 04:26:23 +00001490 out2fmt("%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00001491 i = 1;
1492 }
1493 }
1494
1495 return (i);
1496}
1497
1498static struct alias **
1499hashalias(p)
1500 const char *p;
1501 {
1502 unsigned int hashval;
1503
1504 hashval = *p << 4;
1505 while (*p)
1506 hashval+= *p++;
1507 return &atab[hashval % ATABSIZE];
1508}
1509
1510static struct alias *
1511freealias(struct alias *ap) {
1512 struct alias *next;
1513
1514 if (ap->flag & ALIASINUSE) {
1515 ap->flag |= ALIASDEAD;
1516 return ap;
1517 }
1518
1519 next = ap->next;
1520 ckfree(ap->name);
1521 ckfree(ap->val);
1522 ckfree(ap);
1523 return next;
1524}
1525
Eric Andersencb57d552001-06-28 07:25:16 +00001526
1527static struct alias **
1528__lookupalias(const char *name) {
1529 struct alias **app = hashalias(name);
1530
1531 for (; *app; app = &(*app)->next) {
1532 if (equal(name, (*app)->name)) {
1533 break;
1534 }
1535 }
1536
1537 return app;
1538}
Eric Andersen2870d962001-07-02 17:27:21 +00001539#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001540
1541#ifdef ASH_MATH_SUPPORT
1542/* The generated file arith.c has been snipped. If you want this
1543 * stuff back in, feel free to add it to your own copy. */
Eric Andersen2870d962001-07-02 17:27:21 +00001544#define ARITH_NUM 257
1545#define ARITH_LPAREN 258
1546#define ARITH_RPAREN 259
1547#define ARITH_OR 260
1548#define ARITH_AND 261
1549#define ARITH_BOR 262
1550#define ARITH_BXOR 263
1551#define ARITH_BAND 264
1552#define ARITH_EQ 265
1553#define ARITH_NE 266
1554#define ARITH_LT 267
1555#define ARITH_GT 268
1556#define ARITH_GE 269
1557#define ARITH_LE 270
1558#define ARITH_LSHIFT 271
1559#define ARITH_RSHIFT 272
1560#define ARITH_ADD 273
1561#define ARITH_SUB 274
1562#define ARITH_MUL 275
1563#define ARITH_DIV 276
1564#define ARITH_REM 277
1565#define ARITH_UNARYMINUS 278
1566#define ARITH_UNARYPLUS 279
1567#define ARITH_NOT 280
1568#define ARITH_BNOT 281
1569
1570static void expari (int);
1571/* From arith.y */
1572static int arith (const char *);
1573static int expcmd (int , char **);
1574static void arith_lex_reset (void);
1575static int yylex (void);
1576
Eric Andersencb57d552001-06-28 07:25:16 +00001577#endif
1578
Eric Andersen2870d962001-07-02 17:27:21 +00001579static char *trap[NSIG]; /* trap handler commands */
1580static char sigmode[NSIG - 1]; /* current value of signal */
1581static char gotsig[NSIG - 1]; /* indicates specified signal received */
1582static int pendingsigs; /* indicates some signal received */
1583
Eric Andersencb57d552001-06-28 07:25:16 +00001584/*
1585 * This file was generated by the mkbuiltins program.
1586 */
1587
Eric Andersen2870d962001-07-02 17:27:21 +00001588#ifdef JOBS
1589static int bgcmd (int, char **);
1590static int fgcmd (int, char **);
1591static int killcmd (int, char **);
1592#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001593static int bltincmd (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001594static int cdcmd (int, char **);
1595static int breakcmd (int, char **);
1596#ifdef ASH_CMDCMD
1597static int commandcmd (int, char **);
1598#endif
1599static int dotcmd (int, char **);
1600static int evalcmd (int, char **);
1601static int execcmd (int, char **);
1602static int exitcmd (int, char **);
1603static int exportcmd (int, char **);
1604static int histcmd (int, char **);
1605static int hashcmd (int, char **);
Eric Andersen1c039232001-07-07 00:05:55 +00001606static int helpcmd (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001607static int jobscmd (int, char **);
1608static int localcmd (int, char **);
Eric Andersen3102ac42001-07-06 04:26:23 +00001609#ifndef BB_PWD
Eric Andersen2870d962001-07-02 17:27:21 +00001610static int pwdcmd (int, char **);
1611#endif
1612static int readcmd (int, char **);
1613static int returncmd (int, char **);
1614static int setcmd (int, char **);
1615static int setvarcmd (int, char **);
1616static int shiftcmd (int, char **);
1617static int trapcmd (int, char **);
1618static int umaskcmd (int, char **);
1619#ifdef ASH_ALIAS
1620static int aliascmd (int, char **);
1621static int unaliascmd (int, char **);
1622#endif
1623static int unsetcmd (int, char **);
1624static int waitcmd (int, char **);
1625static int ulimitcmd (int, char **);
1626static int timescmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001627#ifdef ASH_MATH_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00001628static int expcmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001629#endif
1630#ifdef ASH_TYPE
Eric Andersen2870d962001-07-02 17:27:21 +00001631static int typecmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001632#endif
1633#ifdef ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00001634static int getoptscmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001635#endif
1636
Eric Andersen2870d962001-07-02 17:27:21 +00001637#ifndef BB_TRUE_FALSE
1638# ifdef ASH_BBAPPS_AS_BUILTINS
1639static int true_main (int, char **);
1640static int false_main (int, char **);
1641# endif
1642#endif
1643
1644static void setpwd (const char *, int);
1645
1646
1647#define BUILTIN_NOSPEC "0"
1648#define BUILTIN_SPECIAL "1"
1649#define BUILTIN_REGULAR "2"
1650#define BUILTIN_ASSIGN "4"
1651#define BUILTIN_SPEC_ASSG "5"
1652#define BUILTIN_REG_ASSG "6"
1653
1654#define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1655#define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
1656#define IS_BUILTIN_ASSIGN(builtincmd) ((builtincmd)->name[0] & 4)
1657
1658struct builtincmd {
1659 const char *name;
1660 int (*const builtinfunc) (int, char **);
1661 //unsigned flags;
1662};
1663
Eric Andersencb57d552001-06-28 07:25:16 +00001664
1665/* It is CRUCIAL that this listing be kept in ascii order, otherwise
1666 * the binary search in find_builtin() will stop working. If you value
1667 * your kneecaps, you'll be sure to *make sure* that any changes made
1668 * to this array result in the listing remaining in ascii order. You
1669 * have been warned.
1670 */
1671static const struct builtincmd builtincmds[] = {
Eric Andersen2870d962001-07-02 17:27:21 +00001672 { BUILTIN_SPECIAL ".", dotcmd },
1673 { BUILTIN_SPECIAL ":", true_main },
1674#ifdef ASH_ALIAS
1675 { BUILTIN_REG_ASSG "alias", aliascmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001676#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001677#ifdef JOBS
1678 { BUILTIN_REGULAR "bg", bgcmd },
1679#endif
1680 { BUILTIN_SPECIAL "break", breakcmd },
Eric Andersen3102ac42001-07-06 04:26:23 +00001681 { BUILTIN_SPECIAL "builtin", bltincmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001682 { BUILTIN_REGULAR "cd", cdcmd },
1683#ifdef ASH_BBAPPS_AS_BUILTINS
1684 { BUILTIN_NOSPEC "chdir", cdcmd },
1685#endif
1686#ifdef ASH_CMDCMD
1687 { BUILTIN_REGULAR "command", commandcmd },
1688#endif
1689 { BUILTIN_SPECIAL "continue", breakcmd },
1690 { BUILTIN_SPECIAL "eval", evalcmd },
1691 { BUILTIN_SPECIAL "exec", execcmd },
1692 { BUILTIN_SPECIAL "exit", exitcmd },
1693#ifdef ASH_MATH_SUPPORT
1694 { BUILTIN_NOSPEC "exp", expcmd },
1695#endif
1696 { BUILTIN_SPEC_ASSG "export", exportcmd },
1697#ifdef ASH_BBAPPS_AS_BUILTINS
1698 { BUILTIN_REGULAR "false", false_main },
1699#endif
1700 { BUILTIN_REGULAR "fc", histcmd },
1701#ifdef JOBS
1702 { BUILTIN_REGULAR "fg", fgcmd },
1703#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001704#ifdef ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00001705 { BUILTIN_REGULAR "getopts", getoptscmd },
1706#endif
1707 { BUILTIN_NOSPEC "hash", hashcmd },
Eric Andersen1c039232001-07-07 00:05:55 +00001708 { BUILTIN_NOSPEC "help", helpcmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001709 { BUILTIN_REGULAR "jobs", jobscmd },
1710#ifdef JOBS
1711 { BUILTIN_REGULAR "kill", killcmd },
1712#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001713#ifdef ASH_MATH_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00001714 { BUILTIN_NOSPEC "let", expcmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001715#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001716 { BUILTIN_ASSIGN "local", localcmd },
Eric Andersen3102ac42001-07-06 04:26:23 +00001717#ifndef BB_PWD
Eric Andersen2870d962001-07-02 17:27:21 +00001718 { BUILTIN_NOSPEC "pwd", pwdcmd },
1719#endif
1720 { BUILTIN_REGULAR "read", readcmd },
1721 { BUILTIN_SPEC_ASSG "readonly", exportcmd },
1722 { BUILTIN_SPECIAL "return", returncmd },
1723 { BUILTIN_SPECIAL "set", setcmd },
1724 { BUILTIN_NOSPEC "setvar", setvarcmd },
1725 { BUILTIN_SPECIAL "shift", shiftcmd },
1726 { BUILTIN_SPECIAL "times", timescmd },
1727 { BUILTIN_SPECIAL "trap", trapcmd },
1728#ifdef ASH_BBAPPS_AS_BUILTINS
1729 { BUILTIN_REGULAR "true", true_main },
1730#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001731#ifdef ASH_TYPE
Eric Andersen2870d962001-07-02 17:27:21 +00001732 { BUILTIN_NOSPEC "type", typecmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001733#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001734 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
1735 { BUILTIN_REGULAR "umask", umaskcmd },
1736#ifdef ASH_ALIAS
1737 { BUILTIN_REGULAR "unalias", unaliascmd },
1738#endif
1739 { BUILTIN_SPECIAL "unset", unsetcmd },
1740 { BUILTIN_REGULAR "wait", waitcmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001741};
1742#define NUMBUILTINS (sizeof (builtincmds) / sizeof (struct builtincmd) )
1743
Eric Andersen2870d962001-07-02 17:27:21 +00001744static const struct builtincmd *DOTCMD = &builtincmds[0];
1745static struct builtincmd *BLTINCMD;
1746static struct builtincmd *EXECCMD;
1747static struct builtincmd *EVALCMD;
Eric Andersencb57d552001-06-28 07:25:16 +00001748
Eric Andersen2870d962001-07-02 17:27:21 +00001749/* states */
1750#define JOBSTOPPED 1 /* all procs are stopped */
1751#define JOBDONE 2 /* all procs are completed */
Eric Andersencb57d552001-06-28 07:25:16 +00001752
Eric Andersen2870d962001-07-02 17:27:21 +00001753/*
1754 * A job structure contains information about a job. A job is either a
1755 * single process or a set of processes contained in a pipeline. In the
1756 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1757 * array of pids.
1758 */
Eric Andersencb57d552001-06-28 07:25:16 +00001759
Eric Andersen2870d962001-07-02 17:27:21 +00001760struct procstat {
1761 pid_t pid; /* process id */
1762 int status; /* status flags (defined above) */
1763 char *cmd; /* text of command being run */
1764};
Eric Andersencb57d552001-06-28 07:25:16 +00001765
Eric Andersen2870d962001-07-02 17:27:21 +00001766
1767static int job_warning; /* user was warned about stopped jobs */
1768
1769#ifdef JOBS
1770static void setjobctl(int enable);
1771#else
1772#define setjobctl(on) /* do nothing */
Eric Andersencb57d552001-06-28 07:25:16 +00001773#endif
1774
Eric Andersen2870d962001-07-02 17:27:21 +00001775
1776struct job {
1777 struct procstat ps0; /* status of process */
1778 struct procstat *ps; /* status or processes when more than one */
1779 short nprocs; /* number of processes */
1780 short pgrp; /* process group of this job */
1781 char state; /* true if job is finished */
1782 char used; /* true if this entry is in used */
1783 char changed; /* true if status has changed */
1784#ifdef JOBS
1785 char jobctl; /* job running under job control */
1786#endif
1787};
1788
1789static struct job *jobtab; /* array of jobs */
1790static int njobs; /* size of array */
1791static int backgndpid = -1; /* pid of last background process */
1792#ifdef JOBS
1793static int initialpgrp; /* pgrp of shell on invocation */
1794static int curjob; /* current job */
1795static int jobctl;
1796#endif
1797static int intreceived;
1798
1799static struct job *makejob (union node *, int);
1800static int forkshell (struct job *, union node *, int);
1801static int waitforjob (struct job *);
1802
1803static int docd (char *, int);
1804static char *getcomponent (void);
1805static void updatepwd (const char *);
1806static void getpwd (void);
1807
1808static char *padvance (const char **, const char *);
1809
1810static char nullstr[1]; /* zero length string */
1811static char *curdir = nullstr; /* current working directory */
1812static char *cdcomppath;
1813
Eric Andersencb57d552001-06-28 07:25:16 +00001814static int
1815cdcmd(argc, argv)
1816 int argc;
1817 char **argv;
1818{
1819 const char *dest;
1820 const char *path;
1821 char *p;
1822 struct stat statb;
1823 int print = 0;
1824
1825 nextopt(nullstr);
1826 if ((dest = *argptr) == NULL && (dest = bltinlookup("HOME")) == NULL)
1827 error("HOME not set");
1828 if (*dest == '\0')
Eric Andersen2870d962001-07-02 17:27:21 +00001829 dest = ".";
Eric Andersencb57d552001-06-28 07:25:16 +00001830 if (dest[0] == '-' && dest[1] == '\0') {
1831 dest = bltinlookup("OLDPWD");
1832 if (!dest || !*dest) {
1833 dest = curdir;
1834 }
1835 print = 1;
1836 if (dest)
Eric Andersen2870d962001-07-02 17:27:21 +00001837 print = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00001838 else
Eric Andersen2870d962001-07-02 17:27:21 +00001839 dest = ".";
Eric Andersencb57d552001-06-28 07:25:16 +00001840 }
1841 if (*dest == '/' || (path = bltinlookup("CDPATH")) == NULL)
1842 path = nullstr;
1843 while ((p = padvance(&path, dest)) != NULL) {
1844 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
1845 if (!print) {
1846 /*
1847 * XXX - rethink
1848 */
1849 if (p[0] == '.' && p[1] == '/' && p[2] != '\0')
1850 p += 2;
1851 print = strcmp(p, dest);
1852 }
1853 if (docd(p, print) >= 0)
1854 return 0;
1855
1856 }
1857 }
1858 error("can't cd to %s", dest);
1859 /* NOTREACHED */
1860}
1861
1862
1863/*
1864 * Actually do the chdir. In an interactive shell, print the
1865 * directory name if "print" is nonzero.
1866 */
1867
1868static int
1869docd(dest, print)
1870 char *dest;
1871 int print;
1872{
1873 char *p;
1874 char *q;
1875 char *component;
1876 struct stat statb;
1877 int first;
1878 int badstat;
1879
1880 TRACE(("docd(\"%s\", %d) called\n", dest, print));
1881
1882 /*
1883 * Check each component of the path. If we find a symlink or
1884 * something we can't stat, clear curdir to force a getcwd()
1885 * next time we get the value of the current directory.
1886 */
1887 badstat = 0;
1888 cdcomppath = sstrdup(dest);
1889 STARTSTACKSTR(p);
1890 if (*dest == '/') {
1891 STPUTC('/', p);
1892 cdcomppath++;
1893 }
1894 first = 1;
1895 while ((q = getcomponent()) != NULL) {
1896 if (q[0] == '\0' || (q[0] == '.' && q[1] == '\0'))
1897 continue;
1898 if (! first)
1899 STPUTC('/', p);
1900 first = 0;
1901 component = q;
1902 while (*q)
1903 STPUTC(*q++, p);
1904 if (equal(component, ".."))
1905 continue;
1906 STACKSTRNUL(p);
1907 if ((lstat(stackblock(), &statb) < 0)
1908 || (S_ISLNK(statb.st_mode))) {
1909 /* print = 1; */
1910 badstat = 1;
1911 break;
1912 }
1913 }
1914
1915 INTOFF;
1916 if (chdir(dest) < 0) {
1917 INTON;
1918 return -1;
1919 }
1920 updatepwd(badstat ? NULL : dest);
1921 INTON;
1922 if (print && iflag)
1923 out1fmt(snlfmt, curdir);
1924 return 0;
1925}
1926
1927
1928/*
1929 * Get the next component of the path name pointed to by cdcomppath.
1930 * This routine overwrites the string pointed to by cdcomppath.
1931 */
1932
1933static char *
1934getcomponent() {
1935 char *p;
1936 char *start;
1937
1938 if ((p = cdcomppath) == NULL)
1939 return NULL;
1940 start = cdcomppath;
1941 while (*p != '/' && *p != '\0')
1942 p++;
1943 if (*p == '\0') {
1944 cdcomppath = NULL;
1945 } else {
1946 *p++ = '\0';
1947 cdcomppath = p;
1948 }
1949 return start;
1950}
1951
1952
1953
1954/*
1955 * Update curdir (the name of the current directory) in response to a
1956 * cd command. We also call hashcd to let the routines in exec.c know
1957 * that the current directory has changed.
1958 */
1959
Eric Andersen2870d962001-07-02 17:27:21 +00001960static void hashcd (void);
1961
Eric Andersencb57d552001-06-28 07:25:16 +00001962static void
Eric Andersen2870d962001-07-02 17:27:21 +00001963updatepwd(const char *dir)
1964{
Eric Andersencb57d552001-06-28 07:25:16 +00001965 char *new;
1966 char *p;
1967 size_t len;
1968
Eric Andersen2870d962001-07-02 17:27:21 +00001969 hashcd(); /* update command hash table */
Eric Andersencb57d552001-06-28 07:25:16 +00001970
1971 /*
1972 * If our argument is NULL, we don't know the current directory
1973 * any more because we traversed a symbolic link or something
1974 * we couldn't stat().
1975 */
1976 if (dir == NULL || curdir == nullstr) {
1977 setpwd(0, 1);
1978 return;
1979 }
1980 len = strlen(dir);
1981 cdcomppath = sstrdup(dir);
1982 STARTSTACKSTR(new);
1983 if (*dir != '/') {
1984 p = curdir;
1985 while (*p)
1986 STPUTC(*p++, new);
1987 if (p[-1] == '/')
1988 STUNPUTC(new);
1989 }
1990 while ((p = getcomponent()) != NULL) {
1991 if (equal(p, "..")) {
1992 while (new > stackblock() && (STUNPUTC(new), *new) != '/');
1993 } else if (*p != '\0' && ! equal(p, ".")) {
1994 STPUTC('/', new);
1995 while (*p)
1996 STPUTC(*p++, new);
1997 }
1998 }
1999 if (new == stackblock())
2000 STPUTC('/', new);
2001 STACKSTRNUL(new);
2002 setpwd(stackblock(), 1);
2003}
2004
2005
Eric Andersen3102ac42001-07-06 04:26:23 +00002006#ifndef BB_PWD
Eric Andersencb57d552001-06-28 07:25:16 +00002007static int
2008pwdcmd(argc, argv)
2009 int argc;
2010 char **argv;
2011{
2012 out1fmt(snlfmt, curdir);
2013 return 0;
2014}
Eric Andersen2870d962001-07-02 17:27:21 +00002015#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002016
2017/*
2018 * Find out what the current directory is. If we already know the current
2019 * directory, this routine returns immediately.
2020 */
2021static void
Eric Andersen2870d962001-07-02 17:27:21 +00002022getpwd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00002023{
Eric Andersen2870d962001-07-02 17:27:21 +00002024 curdir = xgetcwd(0);
2025 if(curdir==0)
2026 curdir = nullstr;
Eric Andersencb57d552001-06-28 07:25:16 +00002027}
2028
2029static void
2030setpwd(const char *val, int setold)
2031{
2032 if (setold) {
2033 setvar("OLDPWD", curdir, VEXPORT);
2034 }
2035 INTOFF;
2036 if (curdir != nullstr) {
2037 free(curdir);
2038 curdir = nullstr;
2039 }
2040 if (!val) {
2041 getpwd();
2042 } else {
2043 curdir = savestr(val);
2044 }
2045 INTON;
2046 setvar("PWD", curdir, VEXPORT);
2047}
2048
Eric Andersencb57d552001-06-28 07:25:16 +00002049/*
2050 * Errors and exceptions.
2051 */
2052
2053/*
2054 * Code to handle exceptions in C.
2055 */
2056
Eric Andersen2870d962001-07-02 17:27:21 +00002057/*
2058 * We enclose jmp_buf in a structure so that we can declare pointers to
2059 * jump locations. The global variable handler contains the location to
2060 * jump to when an exception occurs, and the global variable exception
2061 * contains a code identifying the exeception. To implement nested
2062 * exception handlers, the user should save the value of handler on entry
2063 * to an inner scope, set handler to point to a jmploc structure for the
2064 * inner scope, and restore handler on exit from the scope.
2065 */
2066
2067struct jmploc {
2068 jmp_buf loc;
2069};
2070
2071/* exceptions */
2072#define EXINT 0 /* SIGINT received */
2073#define EXERROR 1 /* a generic error */
2074#define EXSHELLPROC 2 /* execute a shell procedure */
2075#define EXEXEC 3 /* command execution failed */
2076
2077static struct jmploc *handler;
Eric Andersencb57d552001-06-28 07:25:16 +00002078static int exception;
Eric Andersencb57d552001-06-28 07:25:16 +00002079
Eric Andersen2870d962001-07-02 17:27:21 +00002080static void exverror (int, const char *, va_list)
Eric Andersencb57d552001-06-28 07:25:16 +00002081 __attribute__((__noreturn__));
2082
2083/*
2084 * Called to raise an exception. Since C doesn't include exceptions, we
2085 * just do a longjmp to the exception handler. The type of exception is
2086 * stored in the global variable "exception".
2087 */
2088
Eric Andersen2870d962001-07-02 17:27:21 +00002089static void exraise (int) __attribute__((__noreturn__));
2090
Eric Andersencb57d552001-06-28 07:25:16 +00002091static void
Eric Andersen2870d962001-07-02 17:27:21 +00002092exraise(int e)
Eric Andersencb57d552001-06-28 07:25:16 +00002093{
2094#ifdef DEBUG
2095 if (handler == NULL)
2096 abort();
2097#endif
2098 exception = e;
2099 longjmp(handler->loc, 1);
2100}
2101
2102
2103/*
2104 * Called from trap.c when a SIGINT is received. (If the user specifies
2105 * that SIGINT is to be trapped or ignored using the trap builtin, then
2106 * this routine is not called.) Suppressint is nonzero when interrupts
2107 * are held using the INTOFF macro. The call to _exit is necessary because
2108 * there is a short period after a fork before the signal handlers are
2109 * set to the appropriate value for the child. (The test for iflag is
2110 * just defensive programming.)
2111 */
2112
2113static void
Eric Andersen2870d962001-07-02 17:27:21 +00002114onint(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00002115 sigset_t mysigset;
2116
2117 if (suppressint) {
2118 intpending++;
2119 return;
2120 }
2121 intpending = 0;
2122 sigemptyset(&mysigset);
2123 sigprocmask(SIG_SETMASK, &mysigset, NULL);
2124 if (rootshell && iflag)
2125 exraise(EXINT);
2126 else {
2127 signal(SIGINT, SIG_DFL);
2128 raise(SIGINT);
2129 }
2130 /* NOTREACHED */
2131}
2132
2133
Eric Andersen2870d962001-07-02 17:27:21 +00002134static char *commandname; /* currently executing command */
2135
Eric Andersencb57d552001-06-28 07:25:16 +00002136/*
2137 * Exverror is called to raise the error exception. If the first argument
2138 * is not NULL then error prints an error message using printf style
2139 * formatting. It then raises the error exception.
2140 */
2141static void
Eric Andersen2870d962001-07-02 17:27:21 +00002142exverror(int cond, const char *msg, va_list ap)
Eric Andersencb57d552001-06-28 07:25:16 +00002143{
2144 CLEAR_PENDING_INT;
2145 INTOFF;
2146
2147#ifdef DEBUG
2148 if (msg)
2149 TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid()));
2150 else
2151 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
2152#endif
2153 if (msg) {
2154 if (commandname)
Eric Andersen3102ac42001-07-06 04:26:23 +00002155 out2fmt("%s: ", commandname);
2156 vfprintf(stderr, msg, ap);
2157 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00002158 }
2159 flushall();
2160 exraise(cond);
2161 /* NOTREACHED */
2162}
2163
2164
2165#ifdef __STDC__
2166static void
2167error(const char *msg, ...)
2168#else
2169static void
2170error(va_alist)
2171 va_dcl
2172#endif
2173{
2174#ifndef __STDC__
2175 const char *msg;
2176#endif
2177 va_list ap;
2178#ifdef __STDC__
2179 va_start(ap, msg);
2180#else
2181 va_start(ap);
2182 msg = va_arg(ap, const char *);
2183#endif
2184 exverror(EXERROR, msg, ap);
2185 /* NOTREACHED */
2186 va_end(ap);
2187}
2188
2189
2190#ifdef __STDC__
2191static void
2192exerror(int cond, const char *msg, ...)
2193#else
2194static void
2195exerror(va_alist)
2196 va_dcl
2197#endif
2198{
2199#ifndef __STDC__
2200 int cond;
2201 const char *msg;
2202#endif
2203 va_list ap;
2204#ifdef __STDC__
2205 va_start(ap, msg);
2206#else
2207 va_start(ap);
2208 cond = va_arg(ap, int);
2209 msg = va_arg(ap, const char *);
2210#endif
2211 exverror(cond, msg, ap);
2212 /* NOTREACHED */
2213 va_end(ap);
2214}
2215
2216
2217
2218/*
2219 * Table of error messages.
2220 */
2221
2222struct errname {
Eric Andersen2870d962001-07-02 17:27:21 +00002223 short errcode; /* error number */
2224 short action; /* operation which encountered the error */
Eric Andersencb57d552001-06-28 07:25:16 +00002225};
2226
Eric Andersen2870d962001-07-02 17:27:21 +00002227/*
2228 * Types of operations (passed to the errmsg routine).
2229 */
2230
2231#define E_OPEN 01 /* opening a file */
2232#define E_CREAT 02 /* creating a file */
2233#define E_EXEC 04 /* executing a program */
Eric Andersencb57d552001-06-28 07:25:16 +00002234
2235#define ALL (E_OPEN|E_CREAT|E_EXEC)
2236
2237static const struct errname errormsg[] = {
Eric Andersen2870d962001-07-02 17:27:21 +00002238 { EINTR, ALL },
2239 { EACCES, ALL },
2240 { EIO, ALL },
2241 { ENOENT, E_OPEN },
2242 { ENOENT, E_CREAT },
2243 { ENOENT, E_EXEC },
2244 { ENOTDIR, E_OPEN },
2245 { ENOTDIR, E_CREAT },
2246 { ENOTDIR, E_EXEC },
2247 { EISDIR, ALL },
2248 { EEXIST, E_CREAT },
2249#ifdef EMFILE
2250 { EMFILE, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002251#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002252 { ENFILE, ALL },
2253 { ENOSPC, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002254#ifdef EDQUOT
Eric Andersen2870d962001-07-02 17:27:21 +00002255 { EDQUOT, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002256#endif
2257#ifdef ENOSR
Eric Andersen2870d962001-07-02 17:27:21 +00002258 { ENOSR, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002259#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002260 { ENXIO, ALL },
2261 { EROFS, ALL },
2262 { ETXTBSY, ALL },
2263#ifdef EAGAIN
2264 { EAGAIN, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002265#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002266 { ENOMEM, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002267#ifdef ENOLINK
Eric Andersen2870d962001-07-02 17:27:21 +00002268 { ENOLINK, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002269#endif
2270#ifdef EMULTIHOP
Eric Andersen2870d962001-07-02 17:27:21 +00002271 { EMULTIHOP, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002272#endif
2273#ifdef ECOMM
Eric Andersen2870d962001-07-02 17:27:21 +00002274 { ECOMM, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002275#endif
2276#ifdef ESTALE
Eric Andersen2870d962001-07-02 17:27:21 +00002277 { ESTALE, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002278#endif
2279#ifdef ETIMEDOUT
Eric Andersen2870d962001-07-02 17:27:21 +00002280 { ETIMEDOUT, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002281#endif
2282#ifdef ELOOP
Eric Andersen2870d962001-07-02 17:27:21 +00002283 { ELOOP, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002284#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002285 { E2BIG, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002286#ifdef ELIBACC
Eric Andersen2870d962001-07-02 17:27:21 +00002287 { ELIBACC, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002288#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002289};
2290
Eric Andersen2870d962001-07-02 17:27:21 +00002291#define ERRNAME_SIZE (sizeof(errormsg)/sizeof(struct errname))
Eric Andersencb57d552001-06-28 07:25:16 +00002292
2293/*
2294 * Return a string describing an error. The returned string may be a
2295 * pointer to a static buffer that will be overwritten on the next call.
2296 * Action describes the operation that got the error.
2297 */
2298
2299static const char *
Eric Andersen2870d962001-07-02 17:27:21 +00002300errmsg(int e, int action)
Eric Andersencb57d552001-06-28 07:25:16 +00002301{
2302 struct errname const *ep;
2303 static char buf[12];
2304
Eric Andersen2870d962001-07-02 17:27:21 +00002305 for (ep = errormsg ; ep < errormsg+ERRNAME_SIZE; ep++) {
Eric Andersencb57d552001-06-28 07:25:16 +00002306 if (ep->errcode == e && (ep->action & action) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00002307 return strerror(e);
Eric Andersencb57d552001-06-28 07:25:16 +00002308 }
Eric Andersen2870d962001-07-02 17:27:21 +00002309
Eric Andersen3102ac42001-07-06 04:26:23 +00002310 snprintf(buf, sizeof buf, "error %d", e);
Eric Andersencb57d552001-06-28 07:25:16 +00002311 return buf;
2312}
2313
2314
Eric Andersen3102ac42001-07-06 04:26:23 +00002315#ifdef ASH_OPTIMIZE_FOR_SIZE
Eric Andersencb57d552001-06-28 07:25:16 +00002316static void
2317__inton() {
2318 if (--suppressint == 0 && intpending) {
2319 onint();
2320 }
2321}
Eric Andersen3102ac42001-07-06 04:26:23 +00002322static void forceinton (void) {
2323 suppressint = 0;
2324 if (intpending)
2325 onint();
2326}
Eric Andersencb57d552001-06-28 07:25:16 +00002327#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002328
2329/* flags in argument to evaltree */
Eric Andersen2870d962001-07-02 17:27:21 +00002330#define EV_EXIT 01 /* exit after evaluating tree */
2331#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2332#define EV_BACKCMD 04 /* command executing within back quotes */
Eric Andersencb57d552001-06-28 07:25:16 +00002333
Eric Andersen2870d962001-07-02 17:27:21 +00002334static int evalskip; /* set if we are skipping commands */
2335static int skipcount; /* number of levels to skip */
2336static int loopnest; /* current loop nesting level */
2337static int funcnest; /* depth of function calls */
Eric Andersencb57d552001-06-28 07:25:16 +00002338
2339
Eric Andersen2870d962001-07-02 17:27:21 +00002340
2341static struct strlist *cmdenviron; /* environment for builtin command */
2342static int exitstatus; /* exit status of last command */
2343static int oexitstatus; /* saved exit status */
Eric Andersencb57d552001-06-28 07:25:16 +00002344
2345
Eric Andersen2870d962001-07-02 17:27:21 +00002346static void evalloop (union node *, int);
2347static void evalfor (union node *, int);
2348static void evalcase (union node *, int);
2349static void evalsubshell (union node *, int);
2350static void expredir (union node *);
2351static void evalpipe (union node *);
Eric Andersen2870d962001-07-02 17:27:21 +00002352static void evalcommand (union node *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00002353static void prehash (union node *);
2354static void eprintlist (struct strlist *);
Eric Andersencb57d552001-06-28 07:25:16 +00002355
Eric Andersen2870d962001-07-02 17:27:21 +00002356static union node *parsecmd(int);
Eric Andersencb57d552001-06-28 07:25:16 +00002357/*
2358 * Called to reset things after an exception.
2359 */
2360
Eric Andersencb57d552001-06-28 07:25:16 +00002361/*
2362 * The eval commmand.
2363 */
Eric Andersen2870d962001-07-02 17:27:21 +00002364static void evalstring (char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00002365
2366static int
2367evalcmd(argc, argv)
2368 int argc;
2369 char **argv;
2370{
Eric Andersen2870d962001-07-02 17:27:21 +00002371 char *p;
2372 char *concat;
2373 char **ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002374
Eric Andersen2870d962001-07-02 17:27:21 +00002375 if (argc > 1) {
2376 p = argv[1];
2377 if (argc > 2) {
2378 STARTSTACKSTR(concat);
2379 ap = argv + 2;
2380 for (;;) {
2381 while (*p)
2382 STPUTC(*p++, concat);
2383 if ((p = *ap++) == NULL)
2384 break;
2385 STPUTC(' ', concat);
2386 }
2387 STPUTC('\0', concat);
2388 p = grabstackstr(concat);
2389 }
2390 evalstring(p, EV_TESTED);
2391 }
2392 return exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00002393}
2394
Eric Andersencb57d552001-06-28 07:25:16 +00002395/*
2396 * Execute a command or commands contained in a string.
2397 */
2398
Eric Andersen2870d962001-07-02 17:27:21 +00002399static void evaltree (union node *, int);
2400static void setinputstring (char *);
2401static void popfile (void);
2402static void setstackmark(struct stackmark *mark);
2403static void popstackmark(struct stackmark *mark);
2404
2405
Eric Andersencb57d552001-06-28 07:25:16 +00002406static void
Eric Andersen2870d962001-07-02 17:27:21 +00002407evalstring(char *s, int flag)
2408{
Eric Andersencb57d552001-06-28 07:25:16 +00002409 union node *n;
2410 struct stackmark smark;
2411
2412 setstackmark(&smark);
2413 setinputstring(s);
2414 while ((n = parsecmd(0)) != NEOF) {
2415 evaltree(n, flag);
2416 popstackmark(&smark);
2417 }
2418 popfile();
2419 popstackmark(&smark);
2420}
2421
Eric Andersencb57d552001-06-28 07:25:16 +00002422/*
2423 * Evaluate a parse tree. The value is left in the global variable
2424 * exitstatus.
2425 */
Eric Andersen2870d962001-07-02 17:27:21 +00002426static struct builtincmd *find_builtin (const char *);
2427static void defun (char *, union node *);
Eric Andersencb57d552001-06-28 07:25:16 +00002428
2429static void
2430evaltree(n, flags)
2431 union node *n;
2432 int flags;
2433{
2434 int checkexit = 0;
2435 if (n == NULL) {
2436 TRACE(("evaltree(NULL) called\n"));
2437 goto out;
2438 }
2439 TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type));
2440 switch (n->type) {
2441 case NSEMI:
2442 evaltree(n->nbinary.ch1, flags & EV_TESTED);
2443 if (evalskip)
2444 goto out;
2445 evaltree(n->nbinary.ch2, flags);
2446 break;
2447 case NAND:
2448 evaltree(n->nbinary.ch1, EV_TESTED);
2449 if (evalskip || exitstatus != 0)
2450 goto out;
2451 evaltree(n->nbinary.ch2, flags);
2452 break;
2453 case NOR:
2454 evaltree(n->nbinary.ch1, EV_TESTED);
2455 if (evalskip || exitstatus == 0)
2456 goto out;
2457 evaltree(n->nbinary.ch2, flags);
2458 break;
2459 case NREDIR:
2460 expredir(n->nredir.redirect);
2461 redirect(n->nredir.redirect, REDIR_PUSH);
2462 evaltree(n->nredir.n, flags);
2463 popredir();
2464 break;
2465 case NSUBSHELL:
2466 evalsubshell(n, flags);
2467 break;
2468 case NBACKGND:
2469 evalsubshell(n, flags);
2470 break;
2471 case NIF: {
2472 evaltree(n->nif.test, EV_TESTED);
2473 if (evalskip)
2474 goto out;
2475 if (exitstatus == 0)
2476 evaltree(n->nif.ifpart, flags);
2477 else if (n->nif.elsepart)
2478 evaltree(n->nif.elsepart, flags);
2479 else
2480 exitstatus = 0;
2481 break;
2482 }
2483 case NWHILE:
2484 case NUNTIL:
2485 evalloop(n, flags);
2486 break;
2487 case NFOR:
2488 evalfor(n, flags);
2489 break;
2490 case NCASE:
2491 evalcase(n, flags);
2492 break;
2493 case NDEFUN: {
2494 struct builtincmd *bcmd;
2495 if (
2496 (bcmd = find_builtin(n->narg.text)) &&
Eric Andersen2870d962001-07-02 17:27:21 +00002497 IS_BUILTIN_SPECIAL(bcmd)
Eric Andersencb57d552001-06-28 07:25:16 +00002498 ) {
Eric Andersen3102ac42001-07-06 04:26:23 +00002499 out2fmt("%s is a special built-in\n", n->narg.text);
Eric Andersencb57d552001-06-28 07:25:16 +00002500 exitstatus = 1;
2501 break;
2502 }
2503 defun(n->narg.text, n->narg.next);
2504 exitstatus = 0;
2505 break;
2506 }
2507 case NNOT:
2508 evaltree(n->nnot.com, EV_TESTED);
2509 exitstatus = !exitstatus;
2510 break;
2511
2512 case NPIPE:
2513 evalpipe(n);
2514 checkexit = 1;
2515 break;
2516 case NCMD:
Eric Andersencb57d552001-06-28 07:25:16 +00002517 evalcommand(n, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00002518 checkexit = 1;
2519 break;
2520#ifdef DEBUG
2521 default:
2522 out1fmt("Node type = %d\n", n->type);
Eric Andersencb57d552001-06-28 07:25:16 +00002523 break;
2524#endif
2525 }
2526out:
2527 if (pendingsigs)
2528 dotrap();
2529 if (
2530 flags & EV_EXIT ||
2531 (checkexit && eflag && exitstatus && !(flags & EV_TESTED))
2532 )
2533 exitshell(exitstatus);
2534}
2535
2536
2537static void
2538evalloop(n, flags)
2539 union node *n;
2540 int flags;
2541{
2542 int status;
2543
2544 loopnest++;
2545 status = 0;
2546 for (;;) {
2547 evaltree(n->nbinary.ch1, EV_TESTED);
2548 if (evalskip) {
Eric Andersen2870d962001-07-02 17:27:21 +00002549skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00002550 evalskip = 0;
2551 continue;
2552 }
2553 if (evalskip == SKIPBREAK && --skipcount <= 0)
2554 evalskip = 0;
2555 break;
2556 }
2557 if (n->type == NWHILE) {
2558 if (exitstatus != 0)
2559 break;
2560 } else {
2561 if (exitstatus == 0)
2562 break;
2563 }
2564 evaltree(n->nbinary.ch2, flags & EV_TESTED);
2565 status = exitstatus;
2566 if (evalskip)
2567 goto skipping;
2568 }
2569 loopnest--;
2570 exitstatus = status;
2571}
2572
Eric Andersen2870d962001-07-02 17:27:21 +00002573static void expandarg (union node *, struct arglist *, int);
2574static void fixredir(union node *n, const char *text, int err);
Eric Andersencb57d552001-06-28 07:25:16 +00002575
2576static void
2577evalfor(n, flags)
2578 union node *n;
2579 int flags;
2580{
2581 struct arglist arglist;
2582 union node *argp;
2583 struct strlist *sp;
2584 struct stackmark smark;
2585
2586 setstackmark(&smark);
2587 arglist.lastp = &arglist.list;
2588 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
2589 oexitstatus = exitstatus;
2590 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
2591 if (evalskip)
2592 goto out;
2593 }
2594 *arglist.lastp = NULL;
2595
2596 exitstatus = 0;
2597 loopnest++;
2598 for (sp = arglist.list ; sp ; sp = sp->next) {
2599 setvar(n->nfor.var, sp->text, 0);
2600 evaltree(n->nfor.body, flags & EV_TESTED);
2601 if (evalskip) {
2602 if (evalskip == SKIPCONT && --skipcount <= 0) {
2603 evalskip = 0;
2604 continue;
2605 }
2606 if (evalskip == SKIPBREAK && --skipcount <= 0)
2607 evalskip = 0;
2608 break;
2609 }
2610 }
2611 loopnest--;
2612out:
2613 popstackmark(&smark);
2614}
2615
2616
Eric Andersencb57d552001-06-28 07:25:16 +00002617static void
2618evalcase(n, flags)
2619 union node *n;
2620 int flags;
2621{
2622 union node *cp;
2623 union node *patp;
2624 struct arglist arglist;
2625 struct stackmark smark;
2626
2627 setstackmark(&smark);
2628 arglist.lastp = &arglist.list;
2629 oexitstatus = exitstatus;
2630 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
2631 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2632 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
2633 if (casematch(patp, arglist.list->text)) {
2634 if (evalskip == 0) {
2635 evaltree(cp->nclist.body, flags);
2636 }
2637 goto out;
2638 }
2639 }
2640 }
2641out:
2642 popstackmark(&smark);
2643}
2644
Eric Andersencb57d552001-06-28 07:25:16 +00002645/*
2646 * Kick off a subshell to evaluate a tree.
2647 */
2648
2649static void
2650evalsubshell(n, flags)
2651 union node *n;
2652 int flags;
2653{
2654 struct job *jp;
2655 int backgnd = (n->type == NBACKGND);
2656
2657 expredir(n->nredir.redirect);
2658 jp = makejob(n, 1);
2659 if (forkshell(jp, n, backgnd) == 0) {
2660 if (backgnd)
2661 flags &=~ EV_TESTED;
2662 redirect(n->nredir.redirect, 0);
Eric Andersen2870d962001-07-02 17:27:21 +00002663 evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00002664 }
2665 if (! backgnd) {
2666 INTOFF;
2667 exitstatus = waitforjob(jp);
2668 INTON;
2669 }
2670}
2671
2672
Eric Andersencb57d552001-06-28 07:25:16 +00002673/*
2674 * Compute the names of the files in a redirection list.
2675 */
2676
2677static void
2678expredir(n)
2679 union node *n;
2680{
2681 union node *redir;
2682
2683 for (redir = n ; redir ; redir = redir->nfile.next) {
2684 struct arglist fn;
2685 fn.lastp = &fn.list;
2686 oexitstatus = exitstatus;
2687 switch (redir->type) {
2688 case NFROMTO:
2689 case NFROM:
2690 case NTO:
2691 case NAPPEND:
2692 case NTOOV:
2693 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
2694 redir->nfile.expfname = fn.list->text;
2695 break;
2696 case NFROMFD:
2697 case NTOFD:
2698 if (redir->ndup.vname) {
2699 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
2700 fixredir(redir, fn.list->text, 1);
2701 }
2702 break;
2703 }
2704 }
2705}
2706
Eric Andersencb57d552001-06-28 07:25:16 +00002707/*
2708 * Evaluate a pipeline. All the processes in the pipeline are children
2709 * of the process creating the pipeline. (This differs from some versions
2710 * of the shell, which make the last process in a pipeline the parent
2711 * of all the rest.)
2712 */
2713
2714static void
2715evalpipe(n)
2716 union node *n;
2717{
2718 struct job *jp;
2719 struct nodelist *lp;
2720 int pipelen;
2721 int prevfd;
2722 int pip[2];
2723
2724 TRACE(("evalpipe(0x%lx) called\n", (long)n));
2725 pipelen = 0;
2726 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
2727 pipelen++;
2728 INTOFF;
2729 jp = makejob(n, pipelen);
2730 prevfd = -1;
2731 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
2732 prehash(lp->n);
2733 pip[1] = -1;
2734 if (lp->next) {
2735 if (pipe(pip) < 0) {
2736 close(prevfd);
2737 error("Pipe call failed");
2738 }
2739 }
2740 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
2741 INTON;
2742 if (prevfd > 0) {
2743 close(0);
2744 dup_as_newfd(prevfd, 0);
2745 close(prevfd);
2746 if (pip[0] == 0) {
2747 pip[0] = -1;
2748 }
2749 }
2750 if (pip[1] >= 0) {
2751 if (pip[0] >= 0) {
2752 close(pip[0]);
2753 }
2754 if (pip[1] != 1) {
2755 close(1);
2756 dup_as_newfd(pip[1], 1);
2757 close(pip[1]);
2758 }
2759 }
2760 evaltree(lp->n, EV_EXIT);
2761 }
2762 if (prevfd >= 0)
2763 close(prevfd);
2764 prevfd = pip[0];
2765 close(pip[1]);
2766 }
2767 INTON;
2768 if (n->npipe.backgnd == 0) {
2769 INTOFF;
2770 exitstatus = waitforjob(jp);
2771 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
2772 INTON;
2773 }
2774}
2775
2776
2777
2778/*
2779 * Execute a command inside back quotes. If it's a builtin command, we
2780 * want to save its output in a block obtained from malloc. Otherwise
2781 * we fork off a subprocess and get the output of the command via a pipe.
2782 * Should be called with interrupts off.
2783 */
2784
2785static void
Eric Andersen2870d962001-07-02 17:27:21 +00002786evalbackcmd(union node *n, struct backcmd *result)
Eric Andersencb57d552001-06-28 07:25:16 +00002787{
2788 int pip[2];
2789 struct job *jp;
Eric Andersen2870d962001-07-02 17:27:21 +00002790 struct stackmark smark; /* unnecessary */
Eric Andersencb57d552001-06-28 07:25:16 +00002791
2792 setstackmark(&smark);
2793 result->fd = -1;
2794 result->buf = NULL;
2795 result->nleft = 0;
2796 result->jp = NULL;
2797 if (n == NULL) {
2798 exitstatus = 0;
2799 goto out;
2800 }
Eric Andersen3102ac42001-07-06 04:26:23 +00002801 exitstatus = 0;
2802 if (pipe(pip) < 0)
2803 error("Pipe call failed");
2804 jp = makejob(n, 1);
2805 if (forkshell(jp, n, FORK_NOJOB) == 0) {
2806 FORCEINTON;
2807 close(pip[0]);
2808 if (pip[1] != 1) {
2809 close(1);
2810 dup_as_newfd(pip[1], 1);
2811 close(pip[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00002812 }
Eric Andersen3102ac42001-07-06 04:26:23 +00002813 eflag = 0;
2814 evaltree(n, EV_EXIT);
Eric Andersencb57d552001-06-28 07:25:16 +00002815 }
Eric Andersen3102ac42001-07-06 04:26:23 +00002816 close(pip[1]);
2817 result->fd = pip[0];
2818 result->jp = jp;
Eric Andersencb57d552001-06-28 07:25:16 +00002819out:
2820 popstackmark(&smark);
2821 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
2822 result->fd, result->buf, result->nleft, result->jp));
2823}
2824
2825
2826
2827/*
2828 * Execute a simple command.
2829 */
2830
Eric Andersen2870d962001-07-02 17:27:21 +00002831static void find_command (const char *, struct cmdentry *, int, const char *);
2832
2833static int
2834isassignment(const char *word) {
2835 if (!is_name(*word)) {
2836 return 0;
2837 }
2838 do {
2839 word++;
2840 } while (is_in_name(*word));
2841 return *word == '=';
2842}
2843
Eric Andersencb57d552001-06-28 07:25:16 +00002844static void
Eric Andersen3102ac42001-07-06 04:26:23 +00002845evalcommand(union node *cmd, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002846{
2847 struct stackmark smark;
2848 union node *argp;
2849 struct arglist arglist;
2850 struct arglist varlist;
2851 char **argv;
2852 int argc;
2853 char **envp;
2854 struct strlist *sp;
2855 int mode;
Eric Andersencb57d552001-06-28 07:25:16 +00002856 struct cmdentry cmdentry;
2857 struct job *jp;
2858 char *volatile savecmdname;
2859 volatile struct shparam saveparam;
2860 struct localvar *volatile savelocalvars;
2861 volatile int e;
2862 char *lastarg;
2863 const char *path;
2864 const struct builtincmd *firstbltin;
2865 struct jmploc *volatile savehandler;
2866 struct jmploc jmploc;
2867#if __GNUC__
2868 /* Avoid longjmp clobbering */
2869 (void) &argv;
2870 (void) &argc;
2871 (void) &lastarg;
2872 (void) &flags;
2873#endif
2874
2875 /* First expand the arguments. */
2876 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
2877 setstackmark(&smark);
2878 arglist.lastp = &arglist.list;
2879 varlist.lastp = &varlist.list;
2880 arglist.list = 0;
2881 oexitstatus = exitstatus;
2882 exitstatus = 0;
2883 path = pathval();
2884 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
2885 expandarg(argp, &varlist, EXP_VARTILDE);
2886 }
2887 for (
2888 argp = cmd->ncmd.args; argp && !arglist.list;
2889 argp = argp->narg.next
2890 ) {
2891 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
2892 }
2893 if (argp) {
2894 struct builtincmd *bcmd;
2895 bool pseudovarflag;
2896 bcmd = find_builtin(arglist.list->text);
Eric Andersen2870d962001-07-02 17:27:21 +00002897 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
Eric Andersencb57d552001-06-28 07:25:16 +00002898 for (; argp; argp = argp->narg.next) {
2899 if (pseudovarflag && isassignment(argp->narg.text)) {
2900 expandarg(argp, &arglist, EXP_VARTILDE);
2901 continue;
2902 }
2903 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
2904 }
2905 }
2906 *arglist.lastp = NULL;
2907 *varlist.lastp = NULL;
2908 expredir(cmd->ncmd.redirect);
2909 argc = 0;
2910 for (sp = arglist.list ; sp ; sp = sp->next)
2911 argc++;
2912 argv = stalloc(sizeof (char *) * (argc + 1));
2913
2914 for (sp = arglist.list ; sp ; sp = sp->next) {
2915 TRACE(("evalcommand arg: %s\n", sp->text));
2916 *argv++ = sp->text;
2917 }
2918 *argv = NULL;
2919 lastarg = NULL;
2920 if (iflag && funcnest == 0 && argc > 0)
2921 lastarg = argv[-1];
2922 argv -= argc;
2923
2924 /* Print the command if xflag is set. */
2925 if (xflag) {
Eric Andersen3102ac42001-07-06 04:26:23 +00002926 out2c('+');
Eric Andersencb57d552001-06-28 07:25:16 +00002927 eprintlist(varlist.list);
2928 eprintlist(arglist.list);
Eric Andersen3102ac42001-07-06 04:26:23 +00002929 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00002930 }
2931
2932 /* Now locate the command. */
2933 if (argc == 0) {
2934 cmdentry.cmdtype = CMDBUILTIN;
2935 firstbltin = cmdentry.u.cmd = BLTINCMD;
2936 } else {
2937 const char *oldpath;
2938 int findflag = DO_ERR;
2939 int oldfindflag;
2940
2941 /*
2942 * Modify the command lookup path, if a PATH= assignment
2943 * is present
2944 */
2945 for (sp = varlist.list ; sp ; sp = sp->next)
2946 if (varequal(sp->text, defpathvar)) {
2947 path = sp->text + 5;
2948 findflag |= DO_BRUTE;
2949 }
2950 oldpath = path;
2951 oldfindflag = findflag;
2952 firstbltin = 0;
2953 for(;;) {
2954 find_command(argv[0], &cmdentry, findflag, path);
Eric Andersen2870d962001-07-02 17:27:21 +00002955 if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */
Eric Andersencb57d552001-06-28 07:25:16 +00002956 exitstatus = 127;
Eric Andersencb57d552001-06-28 07:25:16 +00002957 goto out;
2958 }
2959 /* implement bltin and command here */
2960 if (cmdentry.cmdtype != CMDBUILTIN) {
2961 break;
2962 }
2963 if (!firstbltin) {
2964 firstbltin = cmdentry.u.cmd;
2965 }
2966 if (cmdentry.u.cmd == BLTINCMD) {
2967 for(;;) {
2968 struct builtincmd *bcmd;
2969
2970 argv++;
2971 if (--argc == 0)
2972 goto found;
2973 if (!(bcmd = find_builtin(*argv))) {
Eric Andersen3102ac42001-07-06 04:26:23 +00002974 out2fmt("%s: not found\n", *argv);
Eric Andersencb57d552001-06-28 07:25:16 +00002975 exitstatus = 127;
Eric Andersencb57d552001-06-28 07:25:16 +00002976 goto out;
2977 }
2978 cmdentry.u.cmd = bcmd;
2979 if (bcmd != BLTINCMD)
2980 break;
2981 }
2982 }
Eric Andersen2870d962001-07-02 17:27:21 +00002983 if (cmdentry.u.cmd == find_builtin("command")) {
Eric Andersencb57d552001-06-28 07:25:16 +00002984 argv++;
2985 if (--argc == 0) {
2986 goto found;
2987 }
2988 if (*argv[0] == '-') {
2989 if (!equal(argv[0], "-p")) {
2990 argv--;
2991 argc++;
2992 break;
2993 }
2994 argv++;
2995 if (--argc == 0) {
2996 goto found;
2997 }
2998 path = defpath;
2999 findflag |= DO_BRUTE;
3000 } else {
3001 path = oldpath;
3002 findflag = oldfindflag;
3003 }
3004 findflag |= DO_NOFUN;
3005 continue;
3006 }
3007found:
3008 break;
3009 }
3010 }
3011
3012 /* Fork off a child process if necessary. */
3013 if (cmd->ncmd.backgnd
3014 || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00003015 ) {
3016 jp = makejob(cmd, 1);
3017 mode = cmd->ncmd.backgnd;
Eric Andersencb57d552001-06-28 07:25:16 +00003018 if (forkshell(jp, cmd, mode) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00003019 goto parent; /* at end of routine */
Eric Andersencb57d552001-06-28 07:25:16 +00003020 flags |= EV_EXIT;
3021 }
3022
3023 /* This is the child process if a fork occurred. */
3024 /* Execute the command. */
3025 if (cmdentry.cmdtype == CMDFUNCTION) {
3026#ifdef DEBUG
3027 trputs("Shell function: "); trargs(argv);
3028#endif
3029 exitstatus = oexitstatus;
3030 redirect(cmd->ncmd.redirect, REDIR_PUSH);
3031 saveparam = shellparam;
3032 shellparam.malloc = 0;
3033 shellparam.nparam = argc - 1;
3034 shellparam.p = argv + 1;
3035 INTOFF;
3036 savelocalvars = localvars;
3037 localvars = NULL;
3038 INTON;
3039 if (setjmp(jmploc.loc)) {
3040 if (exception == EXSHELLPROC) {
3041 freeparam((volatile struct shparam *)
3042 &saveparam);
3043 } else {
3044 saveparam.optind = shellparam.optind;
3045 saveparam.optoff = shellparam.optoff;
3046 freeparam(&shellparam);
3047 shellparam = saveparam;
3048 }
3049 poplocalvars();
3050 localvars = savelocalvars;
3051 handler = savehandler;
3052 longjmp(handler->loc, 1);
3053 }
3054 savehandler = handler;
3055 handler = &jmploc;
3056 for (sp = varlist.list ; sp ; sp = sp->next)
3057 mklocal(sp->text);
3058 funcnest++;
3059 evaltree(cmdentry.u.func, flags & EV_TESTED);
3060 funcnest--;
3061 INTOFF;
3062 poplocalvars();
3063 localvars = savelocalvars;
3064 saveparam.optind = shellparam.optind;
3065 saveparam.optoff = shellparam.optoff;
3066 freeparam(&shellparam);
3067 shellparam = saveparam;
3068 handler = savehandler;
3069 popredir();
3070 INTON;
3071 if (evalskip == SKIPFUNC) {
3072 evalskip = 0;
3073 skipcount = 0;
3074 }
3075 if (flags & EV_EXIT)
3076 exitshell(exitstatus);
3077 } else if (cmdentry.cmdtype == CMDBUILTIN) {
3078#ifdef DEBUG
3079 trputs("builtin command: "); trargs(argv);
3080#endif
3081 mode = (cmdentry.u.cmd == EXECCMD)? 0 : REDIR_PUSH;
Eric Andersencb57d552001-06-28 07:25:16 +00003082 redirect(cmd->ncmd.redirect, mode);
3083 savecmdname = commandname;
Eric Andersen2870d962001-07-02 17:27:21 +00003084 if (IS_BUILTIN_SPECIAL(firstbltin)) {
Eric Andersencb57d552001-06-28 07:25:16 +00003085 listsetvar(varlist.list);
3086 } else {
3087 cmdenviron = varlist.list;
3088 }
3089 e = -1;
3090 if (setjmp(jmploc.loc)) {
3091 e = exception;
3092 exitstatus = (e == EXINT)? SIGINT+128 : 2;
3093 goto cmddone;
3094 }
3095 savehandler = handler;
3096 handler = &jmploc;
3097 commandname = argv[0];
3098 argptr = argv + 1;
Eric Andersen2870d962001-07-02 17:27:21 +00003099 optptr = NULL; /* initialize nextopt */
Eric Andersencb57d552001-06-28 07:25:16 +00003100 exitstatus = (*cmdentry.u.cmd->builtinfunc)(argc, argv);
3101 flushall();
3102cmddone:
Eric Andersencb57d552001-06-28 07:25:16 +00003103 cmdenviron = NULL;
3104 if (e != EXSHELLPROC) {
3105 commandname = savecmdname;
3106 if (flags & EV_EXIT)
3107 exitshell(exitstatus);
3108 }
3109 handler = savehandler;
3110 if (e != -1) {
3111 if ((e != EXERROR && e != EXEXEC)
3112 || cmdentry.u.cmd == BLTINCMD
3113 || cmdentry.u.cmd == DOTCMD
3114 || cmdentry.u.cmd == EVALCMD
3115 || cmdentry.u.cmd == EXECCMD)
3116 exraise(e);
3117 FORCEINTON;
3118 }
3119 if (cmdentry.u.cmd != EXECCMD)
3120 popredir();
Eric Andersencb57d552001-06-28 07:25:16 +00003121 } else {
3122#ifdef DEBUG
3123 trputs("normal command: "); trargs(argv);
3124#endif
3125 redirect(cmd->ncmd.redirect, 0);
3126 clearredir();
3127 for (sp = varlist.list ; sp ; sp = sp->next)
3128 setvareq(sp->text, VEXPORT|VSTACK);
3129 envp = environment();
3130 shellexec(argv, envp, path, cmdentry.u.index);
3131 }
3132 goto out;
3133
Eric Andersen2870d962001-07-02 17:27:21 +00003134parent: /* parent process gets here (if we forked) */
3135 if (mode == 0) { /* argument to fork */
Eric Andersencb57d552001-06-28 07:25:16 +00003136 INTOFF;
3137 exitstatus = waitforjob(jp);
3138 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00003139 }
3140
3141out:
3142 if (lastarg)
3143 setvar("_", lastarg, 0);
3144 popstackmark(&smark);
3145}
3146
3147
3148
3149/*
3150 * Search for a command. This is called before we fork so that the
3151 * location of the command will be available in the parent as well as
3152 * the child. The check for "goodname" is an overly conservative
3153 * check that the name will not be subject to expansion.
3154 */
3155
3156static void
3157prehash(n)
3158 union node *n;
3159{
3160 struct cmdentry entry;
3161
3162 if (n->type == NCMD && n->ncmd.args)
3163 if (goodname(n->ncmd.args->narg.text))
3164 find_command(n->ncmd.args->narg.text, &entry, 0,
3165 pathval());
3166}
3167
3168
3169
3170/*
3171 * Builtin commands. Builtin commands whose functions are closely
3172 * tied to evaluation are implemented here.
3173 */
3174
3175/*
3176 * No command given, or a bltin command with no arguments. Set the
3177 * specified variables.
3178 */
3179
3180int
3181bltincmd(argc, argv)
3182 int argc;
3183 char **argv;
3184{
3185 /*
3186 * Preserve exitstatus of a previous possible redirection
3187 * as POSIX mandates
3188 */
3189 return exitstatus;
3190}
3191
3192
3193/*
3194 * Handle break and continue commands. Break, continue, and return are
3195 * all handled by setting the evalskip flag. The evaluation routines
3196 * above all check this flag, and if it is set they start skipping
3197 * commands rather than executing them. The variable skipcount is
3198 * the number of loops to break/continue, or the number of function
3199 * levels to return. (The latter is always 1.) It should probably
3200 * be an error to break out of more loops than exist, but it isn't
3201 * in the standard shell so we don't make it one here.
3202 */
3203
3204static int
3205breakcmd(argc, argv)
3206 int argc;
3207 char **argv;
3208{
3209 int n = argc > 1 ? number(argv[1]) : 1;
3210
3211 if (n > loopnest)
3212 n = loopnest;
3213 if (n > 0) {
3214 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
3215 skipcount = n;
3216 }
3217 return 0;
3218}
3219
3220
3221/*
3222 * The return command.
3223 */
3224
3225static int
3226returncmd(argc, argv)
3227 int argc;
3228 char **argv;
3229{
3230 int ret = argc > 1 ? number(argv[1]) : oexitstatus;
3231
3232 if (funcnest) {
3233 evalskip = SKIPFUNC;
3234 skipcount = 1;
3235 return ret;
3236 }
3237 else {
3238 /* Do what ksh does; skip the rest of the file */
3239 evalskip = SKIPFILE;
3240 skipcount = 1;
3241 return ret;
3242 }
3243}
3244
3245
3246#ifndef BB_TRUE_FALSE
Eric Andersen2870d962001-07-02 17:27:21 +00003247#ifdef ASH_BBAPPS_AS_BUILTINS
Eric Andersencb57d552001-06-28 07:25:16 +00003248static int
3249false_main(argc, argv)
3250 int argc;
3251 char **argv;
3252{
3253 return 1;
3254}
3255
3256
3257static int
3258true_main(argc, argv)
3259 int argc;
3260 char **argv;
3261{
3262 return 0;
3263}
3264#endif
Eric Andersen2870d962001-07-02 17:27:21 +00003265#endif
3266
3267/*
3268 * Controls whether the shell is interactive or not.
3269 */
3270
3271static void setsignal(int signo);
3272static void chkmail(int silent);
3273
3274
3275static void
3276setinteractive(int on)
3277{
3278 static int is_interactive;
Eric Andersen1c039232001-07-07 00:05:55 +00003279 static int do_banner=0;
Eric Andersen2870d962001-07-02 17:27:21 +00003280
3281 if (on == is_interactive)
3282 return;
3283 setsignal(SIGINT);
3284 setsignal(SIGQUIT);
3285 setsignal(SIGTERM);
3286 chkmail(1);
3287 is_interactive = on;
Eric Andersen1c039232001-07-07 00:05:55 +00003288 if (do_banner==0 && is_interactive) {
3289 /* Looks like they want an interactive shell */
3290 printf( "\n\n" BB_BANNER " Built-in shell (ash)\n");
3291 printf( "Enter 'help' for a list of built-in commands.\n\n");
3292 do_banner=1;
3293 }
Eric Andersen2870d962001-07-02 17:27:21 +00003294}
3295
3296static void
3297optschanged(void)
3298{
3299 setinteractive(iflag);
3300 setjobctl(mflag);
3301}
3302
Eric Andersencb57d552001-06-28 07:25:16 +00003303
3304static int
3305execcmd(argc, argv)
3306 int argc;
3307 char **argv;
3308{
3309 if (argc > 1) {
3310 struct strlist *sp;
3311
Eric Andersen2870d962001-07-02 17:27:21 +00003312 iflag = 0; /* exit on error */
Eric Andersencb57d552001-06-28 07:25:16 +00003313 mflag = 0;
3314 optschanged();
3315 for (sp = cmdenviron; sp ; sp = sp->next)
3316 setvareq(sp->text, VEXPORT|VSTACK);
3317 shellexec(argv + 1, environment(), pathval(), 0);
3318 }
3319 return 0;
3320}
3321
3322static void
3323eprintlist(struct strlist *sp)
3324{
3325 for (; sp; sp = sp->next) {
Eric Andersen3102ac42001-07-06 04:26:23 +00003326 out2fmt(" %s",sp->text);
Eric Andersencb57d552001-06-28 07:25:16 +00003327 }
3328}
Eric Andersencb57d552001-06-28 07:25:16 +00003329/*
3330 * When commands are first encountered, they are entered in a hash table.
3331 * This ensures that a full path search will not have to be done for them
3332 * on each invocation.
3333 *
3334 * We should investigate converting to a linear search, even though that
3335 * would make the command name "hash" a misnomer.
3336 */
Eric Andersen2870d962001-07-02 17:27:21 +00003337#define CMDTABLESIZE 31 /* should be prime */
3338#define ARB 1 /* actual size determined at run time */
Eric Andersencb57d552001-06-28 07:25:16 +00003339
3340
3341
3342struct tblentry {
Eric Andersen2870d962001-07-02 17:27:21 +00003343 struct tblentry *next; /* next entry in hash chain */
3344 union param param; /* definition of builtin function */
3345 short cmdtype; /* index identifying command */
3346 char rehash; /* if set, cd done since entry created */
3347 char cmdname[ARB]; /* name of command */
Eric Andersencb57d552001-06-28 07:25:16 +00003348};
3349
3350
3351static struct tblentry *cmdtable[CMDTABLESIZE];
Eric Andersen2870d962001-07-02 17:27:21 +00003352static int builtinloc = -1; /* index in path of %builtin, or -1 */
3353static int exerrno = 0; /* Last exec error */
Eric Andersencb57d552001-06-28 07:25:16 +00003354
3355
Eric Andersen2870d962001-07-02 17:27:21 +00003356static void tryexec (char *, char **, char **);
3357static void printentry (struct tblentry *, int);
3358static void clearcmdentry (int);
3359static struct tblentry *cmdlookup (const char *, int);
3360static void delete_cmd_entry (void);
Eric Andersencb57d552001-06-28 07:25:16 +00003361#ifdef ASH_TYPE
Eric Andersen2870d962001-07-02 17:27:21 +00003362static int describe_command (char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00003363#endif
Eric Andersen2870d962001-07-02 17:27:21 +00003364static int path_change (const char *, int *);
Eric Andersencb57d552001-06-28 07:25:16 +00003365
3366
3367/*
3368 * Exec a program. Never returns. If you change this routine, you may
3369 * have to change the find_command routine as well.
3370 */
3371
Eric Andersen2870d962001-07-02 17:27:21 +00003372static const char *pathopt; /* set by padvance */
3373
Eric Andersencb57d552001-06-28 07:25:16 +00003374static void
3375shellexec(argv, envp, path, idx)
3376 char **argv, **envp;
3377 const char *path;
3378 int idx;
3379{
3380 char *cmdname;
3381 int e;
3382
3383 if (strchr(argv[0], '/') != NULL) {
3384 tryexec(argv[0], argv, envp);
3385 e = errno;
3386 } else {
3387 e = ENOENT;
3388 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3389 if (--idx < 0 && pathopt == NULL) {
3390 tryexec(cmdname, argv, envp);
3391 if (errno != ENOENT && errno != ENOTDIR)
3392 e = errno;
3393 }
3394 stunalloc(cmdname);
3395 }
3396 }
3397
3398 /* Map to POSIX errors */
3399 switch (e) {
3400 case EACCES:
3401 exerrno = 126;
3402 break;
3403 case ENOENT:
3404 exerrno = 127;
3405 break;
3406 default:
3407 exerrno = 2;
3408 break;
3409 }
3410 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3411 /* NOTREACHED */
3412}
3413
Eric Andersen2870d962001-07-02 17:27:21 +00003414/*
3415 * Clear traps on a fork.
3416 */
3417static void
3418clear_traps(void) {
3419 char **tp;
3420
3421 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
3422 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
3423 INTOFF;
3424 ckfree(*tp);
3425 *tp = NULL;
3426 if (tp != &trap[0])
3427 setsignal(tp - trap);
3428 INTON;
3429 }
3430 }
3431}
3432
3433
3434static void
3435initshellproc(void) {
3436
3437#ifdef ASH_ALIAS
3438 /* from alias.c: */
3439 {
3440 rmaliases();
3441 }
3442#endif
3443 /* from eval.c: */
3444 {
3445 exitstatus = 0;
3446 }
3447
3448 /* from exec.c: */
3449 {
3450 deletefuncs();
3451 }
3452
3453 /* from jobs.c: */
3454 {
3455 backgndpid = -1;
3456#ifdef JOBS
3457 jobctl = 0;
3458#endif
3459 }
3460
3461 /* from options.c: */
3462 {
3463 int i;
3464
3465 for (i = 0; i < NOPTS; i++)
3466 optent_val(i) = 0;
3467 optschanged();
3468
3469 }
3470
3471 /* from redir.c: */
3472 {
3473 clearredir();
3474 }
3475
3476 /* from trap.c: */
3477 {
3478 char *sm;
3479
3480 clear_traps();
3481 for (sm = sigmode ; sm < sigmode + NSIG - 1; sm++) {
3482 if (*sm == S_IGN)
3483 *sm = S_HARD_IGN;
3484 }
3485 }
3486
3487 /* from var.c: */
3488 {
3489 shprocvar();
3490 }
3491}
3492
3493static int preadbuffer(void);
3494static void pushfile (void);
3495static int preadfd (void);
3496
3497/*
3498 * Read a character from the script, returning PEOF on end of file.
3499 * Nul characters in the input are silently discarded.
3500 */
3501
Eric Andersen3102ac42001-07-06 04:26:23 +00003502#ifndef ASH_OPTIMIZE_FOR_SIZE
Eric Andersen2870d962001-07-02 17:27:21 +00003503#define pgetc_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
3504static int
3505pgetc(void)
3506{
3507 return pgetc_macro();
3508}
3509#else
3510static int
3511pgetc_macro(void)
3512{
3513 return --parsenleft >= 0? *parsenextc++ : preadbuffer();
3514}
3515
3516static inline int
3517pgetc(void)
3518{
3519 return pgetc_macro();
3520}
3521#endif
3522
3523
3524/*
3525 * Undo the last call to pgetc. Only one character may be pushed back.
3526 * PEOF may be pushed back.
3527 */
3528
3529static void
3530pungetc() {
3531 parsenleft++;
3532 parsenextc--;
3533}
3534
3535
3536static void
3537popfile(void) {
3538 struct parsefile *pf = parsefile;
3539
3540 INTOFF;
3541 if (pf->fd >= 0)
3542 close(pf->fd);
3543 if (pf->buf)
3544 ckfree(pf->buf);
3545 while (pf->strpush)
3546 popstring();
3547 parsefile = pf->prev;
3548 ckfree(pf);
3549 parsenleft = parsefile->nleft;
3550 parselleft = parsefile->lleft;
3551 parsenextc = parsefile->nextc;
3552 plinno = parsefile->linno;
3553 INTON;
3554}
3555
3556
3557/*
3558 * Return to top level.
3559 */
3560
3561static void
3562popallfiles(void) {
3563 while (parsefile != &basepf)
3564 popfile();
3565}
3566
3567/*
3568 * Close the file(s) that the shell is reading commands from. Called
3569 * after a fork is done.
3570 */
3571
3572static void
3573closescript() {
3574 popallfiles();
3575 if (parsefile->fd > 0) {
3576 close(parsefile->fd);
3577 parsefile->fd = 0;
3578 }
3579}
3580
3581
3582/*
3583 * Like setinputfile, but takes an open file descriptor. Call this with
3584 * interrupts off.
3585 */
3586
3587static void
3588setinputfd(fd, push)
3589 int fd, push;
3590{
3591 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
3592 if (push) {
3593 pushfile();
3594 parsefile->buf = 0;
3595 } else {
3596 closescript();
3597 while (parsefile->strpush)
3598 popstring();
3599 }
3600 parsefile->fd = fd;
3601 if (parsefile->buf == NULL)
3602 parsefile->buf = ckmalloc(BUFSIZ);
3603 parselleft = parsenleft = 0;
3604 plinno = 1;
3605}
3606
3607
3608/*
3609 * Set the input to take input from a file. If push is set, push the
3610 * old input onto the stack first.
3611 */
3612
3613static void
3614setinputfile(const char *fname, int push)
3615{
3616 int fd;
3617 int myfileno2;
3618
3619 INTOFF;
3620 if ((fd = open(fname, O_RDONLY)) < 0)
3621 error("Can't open %s", fname);
3622 if (fd < 10) {
3623 myfileno2 = dup_as_newfd(fd, 10);
3624 close(fd);
3625 if (myfileno2 < 0)
3626 error("Out of file descriptors");
3627 fd = myfileno2;
3628 }
3629 setinputfd(fd, push);
3630 INTON;
3631}
3632
Eric Andersencb57d552001-06-28 07:25:16 +00003633
3634static void
3635tryexec(cmd, argv, envp)
3636 char *cmd;
3637 char **argv;
3638 char **envp;
3639 {
3640 int e;
Eric Andersencb57d552001-06-28 07:25:16 +00003641
Eric Andersen3102ac42001-07-06 04:26:23 +00003642#ifdef BB_FEATURE_SH_STANDALONE_SHELL
3643 char *name = cmd;
3644 char** argv_l=argv;
3645 int argc_l;
3646#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN
3647 name = get_last_path_component(name);
3648#endif
3649 argv_l=envp;
3650 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++)
3651 putenv(*argv_l);
3652 argv_l=argv;
3653 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++);
3654 optind = 1;
3655 run_applet_by_name(name, argc_l, argv);
3656#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003657 execve(cmd, argv, envp);
Eric Andersencb57d552001-06-28 07:25:16 +00003658 e = errno;
3659 if (e == ENOEXEC) {
3660 INTOFF;
3661 initshellproc();
3662 setinputfile(cmd, 0);
3663 commandname = arg0 = savestr(argv[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00003664 setparam(argv + 1);
3665 exraise(EXSHELLPROC);
3666 }
3667 errno = e;
3668}
3669
Eric Andersen2870d962001-07-02 17:27:21 +00003670static char *commandtext (const union node *);
Eric Andersencb57d552001-06-28 07:25:16 +00003671
3672/*
3673 * Do a path search. The variable path (passed by reference) should be
3674 * set to the start of the path before the first call; padvance will update
3675 * this value as it proceeds. Successive calls to padvance will return
3676 * the possible path expansions in sequence. If an option (indicated by
3677 * a percent sign) appears in the path entry then the global variable
3678 * pathopt will be set to point to it; otherwise pathopt will be set to
3679 * NULL.
3680 */
3681
3682static const char *pathopt;
3683
Eric Andersen2870d962001-07-02 17:27:21 +00003684static void growstackblock(void);
3685
3686
Eric Andersencb57d552001-06-28 07:25:16 +00003687static char *
Eric Andersen2870d962001-07-02 17:27:21 +00003688padvance(const char **path, const char *name)
3689{
Eric Andersencb57d552001-06-28 07:25:16 +00003690 const char *p;
3691 char *q;
3692 const char *start;
3693 int len;
3694
3695 if (*path == NULL)
3696 return NULL;
3697 start = *path;
3698 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
Eric Andersen2870d962001-07-02 17:27:21 +00003699 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +00003700 while (stackblocksize() < len)
3701 growstackblock();
3702 q = stackblock();
3703 if (p != start) {
3704 memcpy(q, start, p - start);
3705 q += p - start;
3706 *q++ = '/';
3707 }
3708 strcpy(q, name);
3709 pathopt = NULL;
3710 if (*p == '%') {
3711 pathopt = ++p;
3712 while (*p && *p != ':') p++;
3713 }
3714 if (*p == ':')
3715 *path = p + 1;
3716 else
3717 *path = NULL;
3718 return stalloc(len);
3719}
3720
3721
3722
3723/*** Command hashing code ***/
3724
3725
3726static int
3727hashcmd(argc, argv)
3728 int argc;
3729 char **argv;
3730{
3731 struct tblentry **pp;
3732 struct tblentry *cmdp;
3733 int c;
3734 int verbose;
3735 struct cmdentry entry;
3736 char *name;
3737
3738 verbose = 0;
3739 while ((c = nextopt("rv")) != '\0') {
3740 if (c == 'r') {
3741 clearcmdentry(0);
3742 return 0;
3743 } else if (c == 'v') {
3744 verbose++;
3745 }
3746 }
3747 if (*argptr == NULL) {
3748 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3749 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3750 if (cmdp->cmdtype != CMDBUILTIN) {
3751 printentry(cmdp, verbose);
3752 }
3753 }
3754 }
3755 return 0;
3756 }
3757 c = 0;
3758 while ((name = *argptr) != NULL) {
3759 if ((cmdp = cmdlookup(name, 0)) != NULL
3760 && (cmdp->cmdtype == CMDNORMAL
3761 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
3762 delete_cmd_entry();
3763 find_command(name, &entry, DO_ERR, pathval());
3764 if (entry.cmdtype == CMDUNKNOWN) c = 1;
3765 else if (verbose) {
3766 cmdp = cmdlookup(name, 0);
3767 if (cmdp) printentry(cmdp, verbose);
3768 flushall();
3769 }
3770 argptr++;
3771 }
3772 return c;
3773}
3774
3775
3776static void
3777printentry(cmdp, verbose)
3778 struct tblentry *cmdp;
3779 int verbose;
3780 {
3781 int idx;
3782 const char *path;
3783 char *name;
3784
3785 if (cmdp->cmdtype == CMDNORMAL) {
3786 idx = cmdp->param.index;
3787 path = pathval();
3788 do {
3789 name = padvance(&path, cmdp->cmdname);
3790 stunalloc(name);
3791 } while (--idx >= 0);
3792 out1str(name);
3793 } else if (cmdp->cmdtype == CMDBUILTIN) {
3794 out1fmt("builtin %s", cmdp->cmdname);
3795 } else if (cmdp->cmdtype == CMDFUNCTION) {
3796 out1fmt("function %s", cmdp->cmdname);
3797 if (verbose) {
3798 INTOFF;
3799 name = commandtext(cmdp->param.func);
3800 out1fmt(" %s", name);
3801 ckfree(name);
3802 INTON;
3803 }
3804#ifdef DEBUG
3805 } else {
3806 error("internal error: cmdtype %d", cmdp->cmdtype);
3807#endif
3808 }
3809 out1fmt(snlfmt, cmdp->rehash ? "*" : nullstr);
3810}
3811
3812
3813
Eric Andersen1c039232001-07-07 00:05:55 +00003814/*** List the available builtins ***/
3815
3816
3817static int helpcmd(int argc, char** argv)
3818{
3819 int col, i;
3820 const struct builtincmd *x;
3821
3822 printf("\nBuilt-in commands:\n");
3823 printf("-------------------\n");
3824 for (col=0, i=0, x = builtincmds; i < NUMBUILTINS; x++, i++) {
3825 if (!x->name || ! (x->name+1))
3826 continue;
3827 col += printf("%s%s", ((col == 0) ? "\t" : " "),
3828 (x->name+1));
3829 if (col > 60) {
3830 printf("\n");
3831 col = 0;
3832 }
3833 }
3834#ifdef BB_FEATURE_SH_STANDALONE_SHELL
3835 {
3836 const struct BB_applet *applet;
3837 extern const struct BB_applet applets[];
3838 extern const size_t NUM_APPLETS;
3839
3840 for (i=0, applet = applets; i < NUM_APPLETS; applet++, i++) {
3841 if (!applet->name)
3842 continue;
3843
3844 col += printf("%s%s", ((col == 0) ? "\t" : " "),
3845 applet->name);
3846 if (col > 60) {
3847 printf("\n");
3848 col = 0;
3849 }
3850 }
3851 }
3852#endif
3853 printf("\n\n");
3854 return EXIT_SUCCESS;
3855}
3856
3857
3858
Eric Andersencb57d552001-06-28 07:25:16 +00003859/*
3860 * Resolve a command name. If you change this routine, you may have to
3861 * change the shellexec routine as well.
3862 */
3863
Eric Andersen2870d962001-07-02 17:27:21 +00003864static int prefix (const char *, const char *);
3865
Eric Andersencb57d552001-06-28 07:25:16 +00003866static void
Eric Andersen2870d962001-07-02 17:27:21 +00003867find_command(const char *name, struct cmdentry *entry, int act, const char *path)
Eric Andersencb57d552001-06-28 07:25:16 +00003868{
3869 struct tblentry *cmdp;
3870 int idx;
3871 int prev;
3872 char *fullname;
3873 struct stat statb;
3874 int e;
3875 int bltin;
3876 int firstchange;
3877 int updatetbl;
3878 bool regular;
3879 struct builtincmd *bcmd;
3880
3881 /* If name contains a slash, don't use the hash table */
3882 if (strchr(name, '/') != NULL) {
3883 if (act & DO_ABS) {
3884 while (stat(name, &statb) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003885 if (errno != ENOENT && errno != ENOTDIR)
3886 e = errno;
3887 entry->cmdtype = CMDUNKNOWN;
3888 entry->u.index = -1;
3889 return;
3890 }
3891 entry->cmdtype = CMDNORMAL;
3892 entry->u.index = -1;
3893 return;
3894 }
3895 entry->cmdtype = CMDNORMAL;
3896 entry->u.index = 0;
3897 return;
3898 }
3899
3900 updatetbl = 1;
3901 if (act & DO_BRUTE) {
3902 firstchange = path_change(path, &bltin);
3903 } else {
3904 bltin = builtinloc;
3905 firstchange = 9999;
3906 }
3907
3908 /* If name is in the table, and not invalidated by cd, we're done */
3909 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0) {
3910 if (cmdp->cmdtype == CMDFUNCTION) {
3911 if (act & DO_NOFUN) {
3912 updatetbl = 0;
3913 } else {
3914 goto success;
3915 }
3916 } else if (act & DO_BRUTE) {
3917 if ((cmdp->cmdtype == CMDNORMAL &&
3918 cmdp->param.index >= firstchange) ||
3919 (cmdp->cmdtype == CMDBUILTIN &&
3920 ((builtinloc < 0 && bltin >= 0) ?
3921 bltin : builtinloc) >= firstchange)) {
3922 /* need to recompute the entry */
3923 } else {
3924 goto success;
3925 }
3926 } else {
3927 goto success;
3928 }
3929 }
3930
3931 bcmd = find_builtin(name);
Eric Andersen2870d962001-07-02 17:27:21 +00003932 regular = bcmd && IS_BUILTIN_REGULAR(bcmd);
Eric Andersencb57d552001-06-28 07:25:16 +00003933
3934 if (regular) {
3935 if (cmdp && (cmdp->cmdtype == CMDBUILTIN)) {
Eric Andersen2870d962001-07-02 17:27:21 +00003936 goto success;
Eric Andersencb57d552001-06-28 07:25:16 +00003937 }
3938 } else if (act & DO_BRUTE) {
3939 if (firstchange == 0) {
3940 updatetbl = 0;
3941 }
3942 }
3943
3944 /* If %builtin not in path, check for builtin next */
3945 if (regular || (bltin < 0 && bcmd)) {
3946builtin:
3947 if (!updatetbl) {
3948 entry->cmdtype = CMDBUILTIN;
3949 entry->u.cmd = bcmd;
3950 return;
3951 }
3952 INTOFF;
3953 cmdp = cmdlookup(name, 1);
3954 cmdp->cmdtype = CMDBUILTIN;
3955 cmdp->param.cmd = bcmd;
3956 INTON;
3957 goto success;
3958 }
3959
3960 /* We have to search path. */
Eric Andersen2870d962001-07-02 17:27:21 +00003961 prev = -1; /* where to start */
3962 if (cmdp && cmdp->rehash) { /* doing a rehash */
Eric Andersencb57d552001-06-28 07:25:16 +00003963 if (cmdp->cmdtype == CMDBUILTIN)
3964 prev = builtinloc;
3965 else
3966 prev = cmdp->param.index;
3967 }
3968
3969 e = ENOENT;
3970 idx = -1;
3971loop:
3972 while ((fullname = padvance(&path, name)) != NULL) {
3973 stunalloc(fullname);
3974 idx++;
3975 if (idx >= firstchange) {
3976 updatetbl = 0;
3977 }
3978 if (pathopt) {
3979 if (prefix("builtin", pathopt)) {
3980 if ((bcmd = find_builtin(name))) {
3981 goto builtin;
3982 }
3983 continue;
3984 } else if (!(act & DO_NOFUN) &&
3985 prefix("func", pathopt)) {
3986 /* handled below */
3987 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00003988 continue; /* ignore unimplemented options */
Eric Andersencb57d552001-06-28 07:25:16 +00003989 }
3990 }
3991 /* if rehash, don't redo absolute path names */
3992 if (fullname[0] == '/' && idx <= prev &&
3993 idx < firstchange) {
3994 if (idx < prev)
3995 continue;
3996 TRACE(("searchexec \"%s\": no change\n", name));
3997 goto success;
3998 }
3999 while (stat(fullname, &statb) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00004000 if (errno != ENOENT && errno != ENOTDIR)
4001 e = errno;
4002 goto loop;
4003 }
Eric Andersen2870d962001-07-02 17:27:21 +00004004 e = EACCES; /* if we fail, this will be the error */
Eric Andersencb57d552001-06-28 07:25:16 +00004005 if (!S_ISREG(statb.st_mode))
4006 continue;
Eric Andersen2870d962001-07-02 17:27:21 +00004007 if (pathopt) { /* this is a %func directory */
Eric Andersencb57d552001-06-28 07:25:16 +00004008 stalloc(strlen(fullname) + 1);
4009 readcmdfile(fullname);
4010 if ((cmdp = cmdlookup(name, 0)) == NULL || cmdp->cmdtype != CMDFUNCTION)
4011 error("%s not defined in %s", name, fullname);
4012 stunalloc(fullname);
4013 goto success;
4014 }
Eric Andersencb57d552001-06-28 07:25:16 +00004015 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
4016 /* If we aren't called with DO_BRUTE and cmdp is set, it must
4017 be a function and we're being called with DO_NOFUN */
4018 if (!updatetbl) {
4019 entry->cmdtype = CMDNORMAL;
4020 entry->u.index = idx;
4021 return;
4022 }
4023 INTOFF;
4024 cmdp = cmdlookup(name, 1);
4025 cmdp->cmdtype = CMDNORMAL;
4026 cmdp->param.index = idx;
4027 INTON;
4028 goto success;
4029 }
4030
4031 /* We failed. If there was an entry for this command, delete it */
4032 if (cmdp && updatetbl)
4033 delete_cmd_entry();
4034 if (act & DO_ERR)
Eric Andersen3102ac42001-07-06 04:26:23 +00004035 out2fmt("%s: %s\n", name, errmsg(e, E_EXEC));
Eric Andersencb57d552001-06-28 07:25:16 +00004036 entry->cmdtype = CMDUNKNOWN;
4037 return;
4038
4039success:
4040 cmdp->rehash = 0;
4041 entry->cmdtype = cmdp->cmdtype;
4042 entry->u = cmdp->param;
4043}
4044
4045
4046
4047/*
4048 * Search the table of builtin commands.
4049 */
4050
Eric Andersen2870d962001-07-02 17:27:21 +00004051static int
4052bstrcmp(const void *name, const void *b)
4053{
4054 return strcmp((const char *)name, (*(const char *const *) b)+1);
4055}
4056
4057static struct builtincmd *
4058find_builtin(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00004059{
4060 struct builtincmd *bp;
4061
Eric Andersen2870d962001-07-02 17:27:21 +00004062 bp = bsearch(name, builtincmds, NUMBUILTINS, sizeof(struct builtincmd),
4063 bstrcmp
Eric Andersencb57d552001-06-28 07:25:16 +00004064 );
4065 return bp;
4066}
4067
4068
4069/*
4070 * Called when a cd is done. Marks all commands so the next time they
4071 * are executed they will be rehashed.
4072 */
4073
4074static void
Eric Andersen2870d962001-07-02 17:27:21 +00004075hashcd(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00004076 struct tblentry **pp;
4077 struct tblentry *cmdp;
4078
4079 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4080 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4081 if (cmdp->cmdtype == CMDNORMAL
4082 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
4083 cmdp->rehash = 1;
4084 }
4085 }
4086}
4087
4088
4089
4090/*
4091 * Called before PATH is changed. The argument is the new value of PATH;
4092 * pathval() still returns the old value at this point. Called with
4093 * interrupts off.
4094 */
4095
4096static void
Eric Andersen2870d962001-07-02 17:27:21 +00004097changepath(const char *newval)
Eric Andersencb57d552001-06-28 07:25:16 +00004098{
4099 int firstchange;
4100 int bltin;
4101
4102 firstchange = path_change(newval, &bltin);
4103 if (builtinloc < 0 && bltin >= 0)
Eric Andersen2870d962001-07-02 17:27:21 +00004104 builtinloc = bltin; /* zap builtins */
Eric Andersencb57d552001-06-28 07:25:16 +00004105 clearcmdentry(firstchange);
4106 builtinloc = bltin;
4107}
4108
4109
4110/*
4111 * Clear out command entries. The argument specifies the first entry in
4112 * PATH which has changed.
4113 */
4114
4115static void
4116clearcmdentry(firstchange)
4117 int firstchange;
4118{
4119 struct tblentry **tblp;
4120 struct tblentry **pp;
4121 struct tblentry *cmdp;
4122
4123 INTOFF;
4124 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4125 pp = tblp;
4126 while ((cmdp = *pp) != NULL) {
4127 if ((cmdp->cmdtype == CMDNORMAL &&
4128 cmdp->param.index >= firstchange)
4129 || (cmdp->cmdtype == CMDBUILTIN &&
4130 builtinloc >= firstchange)) {
4131 *pp = cmdp->next;
4132 ckfree(cmdp);
4133 } else {
4134 pp = &cmdp->next;
4135 }
4136 }
4137 }
4138 INTON;
4139}
4140
Eric Andersen2870d962001-07-02 17:27:21 +00004141/*
4142 * Free a parse tree.
4143 */
4144
4145static void
4146freefunc(union node *n)
4147{
4148 if (n)
4149 ckfree(n);
4150}
4151
Eric Andersencb57d552001-06-28 07:25:16 +00004152
4153/*
4154 * Delete all functions.
4155 */
4156
Eric Andersencb57d552001-06-28 07:25:16 +00004157static void
Eric Andersen2870d962001-07-02 17:27:21 +00004158deletefuncs(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00004159 struct tblentry **tblp;
4160 struct tblentry **pp;
4161 struct tblentry *cmdp;
4162
4163 INTOFF;
4164 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4165 pp = tblp;
4166 while ((cmdp = *pp) != NULL) {
4167 if (cmdp->cmdtype == CMDFUNCTION) {
4168 *pp = cmdp->next;
4169 freefunc(cmdp->param.func);
4170 ckfree(cmdp);
4171 } else {
4172 pp = &cmdp->next;
4173 }
4174 }
4175 }
4176 INTON;
4177}
4178
4179
4180
4181/*
4182 * Locate a command in the command hash table. If "add" is nonzero,
4183 * add the command to the table if it is not already present. The
4184 * variable "lastcmdentry" is set to point to the address of the link
4185 * pointing to the entry, so that delete_cmd_entry can delete the
4186 * entry.
4187 */
4188
Eric Andersen2870d962001-07-02 17:27:21 +00004189static struct tblentry **lastcmdentry;
Eric Andersencb57d552001-06-28 07:25:16 +00004190
4191static struct tblentry *
Eric Andersen2870d962001-07-02 17:27:21 +00004192cmdlookup(const char *name, int add)
Eric Andersencb57d552001-06-28 07:25:16 +00004193{
4194 int hashval;
Eric Andersen2870d962001-07-02 17:27:21 +00004195 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00004196 struct tblentry *cmdp;
4197 struct tblentry **pp;
4198
4199 p = name;
4200 hashval = *p << 4;
4201 while (*p)
4202 hashval += *p++;
4203 hashval &= 0x7FFF;
4204 pp = &cmdtable[hashval % CMDTABLESIZE];
4205 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4206 if (equal(cmdp->cmdname, name))
4207 break;
4208 pp = &cmdp->next;
4209 }
4210 if (add && cmdp == NULL) {
4211 INTOFF;
4212 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4213 + strlen(name) + 1);
4214 cmdp->next = NULL;
4215 cmdp->cmdtype = CMDUNKNOWN;
4216 cmdp->rehash = 0;
4217 strcpy(cmdp->cmdname, name);
4218 INTON;
4219 }
4220 lastcmdentry = pp;
4221 return cmdp;
4222}
4223
4224/*
4225 * Delete the command entry returned on the last lookup.
4226 */
4227
4228static void
4229delete_cmd_entry() {
4230 struct tblentry *cmdp;
4231
4232 INTOFF;
4233 cmdp = *lastcmdentry;
4234 *lastcmdentry = cmdp->next;
4235 ckfree(cmdp);
4236 INTON;
4237}
4238
4239
4240
Eric Andersencb57d552001-06-28 07:25:16 +00004241/*
4242 * Add a new command entry, replacing any existing command entry for
4243 * the same name.
4244 */
4245
4246static void
Eric Andersen2870d962001-07-02 17:27:21 +00004247addcmdentry(char *name, struct cmdentry *entry)
4248{
Eric Andersencb57d552001-06-28 07:25:16 +00004249 struct tblentry *cmdp;
4250
4251 INTOFF;
4252 cmdp = cmdlookup(name, 1);
4253 if (cmdp->cmdtype == CMDFUNCTION) {
4254 freefunc(cmdp->param.func);
4255 }
4256 cmdp->cmdtype = entry->cmdtype;
4257 cmdp->param = entry->u;
4258 INTON;
4259}
4260
4261
4262/*
4263 * Define a shell function.
4264 */
4265
Eric Andersen2870d962001-07-02 17:27:21 +00004266static union node *copyfunc(union node *);
4267
Eric Andersencb57d552001-06-28 07:25:16 +00004268static void
Eric Andersen2870d962001-07-02 17:27:21 +00004269defun(char *name, union node *func)
4270{
Eric Andersencb57d552001-06-28 07:25:16 +00004271 struct cmdentry entry;
4272
4273 entry.cmdtype = CMDFUNCTION;
4274 entry.u.func = copyfunc(func);
4275 addcmdentry(name, &entry);
4276}
4277
4278
4279/*
4280 * Delete a function if it exists.
4281 */
4282
4283static void
Eric Andersen2870d962001-07-02 17:27:21 +00004284unsetfunc(char *name)
4285{
Eric Andersencb57d552001-06-28 07:25:16 +00004286 struct tblentry *cmdp;
4287
4288 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) {
4289 freefunc(cmdp->param.func);
4290 delete_cmd_entry();
4291 }
4292}
4293
Eric Andersen2870d962001-07-02 17:27:21 +00004294/*
4295 * Wrapper around strcmp for qsort/bsearch/...
4296 */
4297static int
4298pstrcmp(const void *a, const void *b)
4299{
4300 return strcmp((const char *) a, *(const char *const *) b);
4301}
4302
4303/*
4304 * Find a keyword is in a sorted array.
4305 */
4306
4307static const char *const *
4308findkwd(const char *s)
4309{
4310 return bsearch(s, parsekwd, sizeof(parsekwd) / sizeof(const char *),
4311 sizeof(const char *), pstrcmp);
4312}
4313
Eric Andersencb57d552001-06-28 07:25:16 +00004314#ifdef ASH_TYPE
4315/*
4316 * Locate and print what a word is...
4317 */
4318
4319static int
4320typecmd(argc, argv)
4321 int argc;
4322 char **argv;
4323{
4324 int i;
4325 int err = 0;
4326
4327 for (i = 1; i < argc; i++) {
4328 err |= describe_command(argv[i], 1);
4329 }
4330 return err;
4331}
4332
4333static int
Eric Andersen2870d962001-07-02 17:27:21 +00004334describe_command(char *command, int verbose)
Eric Andersencb57d552001-06-28 07:25:16 +00004335{
4336 struct cmdentry entry;
4337 struct tblentry *cmdp;
Eric Andersen2870d962001-07-02 17:27:21 +00004338#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00004339 const struct alias *ap;
Eric Andersen2870d962001-07-02 17:27:21 +00004340#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004341 const char *path = pathval();
4342
4343 if (verbose) {
4344 out1str(command);
4345 }
4346
4347 /* First look at the keywords */
4348 if (findkwd(command)) {
4349 out1str(verbose ? " is a shell keyword" : command);
4350 goto out;
4351 }
4352
Eric Andersen2870d962001-07-02 17:27:21 +00004353#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00004354 /* Then look at the aliases */
4355 if ((ap = lookupalias(command, 0)) != NULL) {
4356 if (verbose) {
4357 out1fmt(" is an alias for %s", ap->val);
4358 } else {
4359 printalias(ap);
4360 }
4361 goto out;
4362 }
Eric Andersen2870d962001-07-02 17:27:21 +00004363#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004364 /* Then check if it is a tracked alias */
4365 if ((cmdp = cmdlookup(command, 0)) != NULL) {
4366 entry.cmdtype = cmdp->cmdtype;
4367 entry.u = cmdp->param;
4368 } else {
4369 /* Finally use brute force */
4370 find_command(command, &entry, DO_ABS, path);
4371 }
4372
4373 switch (entry.cmdtype) {
4374 case CMDNORMAL: {
4375 int j = entry.u.index;
4376 char *p;
4377 if (j == -1) {
4378 p = command;
4379 } else {
4380 do {
4381 p = padvance(&path, command);
4382 stunalloc(p);
4383 } while (--j >= 0);
4384 }
4385 if (verbose) {
4386 out1fmt(
4387 " is%s %s",
4388 cmdp ? " a tracked alias for" : nullstr, p
4389 );
4390 } else {
4391 out1str(p);
4392 }
4393 break;
4394 }
4395
4396 case CMDFUNCTION:
4397 if (verbose) {
4398 out1str(" is a shell function");
4399 } else {
4400 out1str(command);
4401 }
4402 break;
4403
4404 case CMDBUILTIN:
4405 if (verbose) {
4406 out1fmt(
4407 " is a %sshell builtin",
Eric Andersen2870d962001-07-02 17:27:21 +00004408 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
Eric Andersencb57d552001-06-28 07:25:16 +00004409 "special " : nullstr
4410 );
4411 } else {
4412 out1str(command);
4413 }
4414 break;
4415
4416 default:
4417 if (verbose) {
4418 out1str(": not found\n");
4419 }
4420 return 127;
4421 }
4422
4423out:
Eric Andersen3102ac42001-07-06 04:26:23 +00004424 putchar('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00004425 return 0;
4426}
Eric Andersen2870d962001-07-02 17:27:21 +00004427#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004428
Eric Andersen2870d962001-07-02 17:27:21 +00004429#ifdef ASH_CMDCMD
Eric Andersencb57d552001-06-28 07:25:16 +00004430static int
4431commandcmd(argc, argv)
4432 int argc;
4433 char **argv;
4434{
4435 int c;
4436 int default_path = 0;
4437 int verify_only = 0;
4438 int verbose_verify_only = 0;
4439
4440 while ((c = nextopt("pvV")) != '\0')
4441 switch (c) {
4442 case 'p':
4443 default_path = 1;
4444 break;
4445 case 'v':
4446 verify_only = 1;
4447 break;
4448 case 'V':
4449 verbose_verify_only = 1;
4450 break;
4451 default:
Eric Andersen3102ac42001-07-06 04:26:23 +00004452 out2fmt(
Eric Andersencb57d552001-06-28 07:25:16 +00004453"command: nextopt returned character code 0%o\n", c);
4454 return EX_SOFTWARE;
4455 }
4456
4457 if (default_path + verify_only + verbose_verify_only > 1 ||
4458 !*argptr) {
Eric Andersen3102ac42001-07-06 04:26:23 +00004459 out2fmt(
Eric Andersencb57d552001-06-28 07:25:16 +00004460"command [-p] command [arg ...]\n");
Eric Andersen3102ac42001-07-06 04:26:23 +00004461 out2fmt(
Eric Andersencb57d552001-06-28 07:25:16 +00004462"command {-v|-V} command\n");
4463 return EX_USAGE;
4464 }
4465
4466#ifdef ASH_TYPE
4467 if (verify_only || verbose_verify_only) {
4468 return describe_command(*argptr, verbose_verify_only);
4469 }
Eric Andersen2870d962001-07-02 17:27:21 +00004470#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004471
4472 return 0;
4473}
Eric Andersen2870d962001-07-02 17:27:21 +00004474#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004475
4476static int
4477path_change(newval, bltin)
4478 const char *newval;
4479 int *bltin;
4480{
4481 const char *old, *new;
4482 int idx;
4483 int firstchange;
4484
4485 old = pathval();
4486 new = newval;
Eric Andersen2870d962001-07-02 17:27:21 +00004487 firstchange = 9999; /* assume no change */
Eric Andersencb57d552001-06-28 07:25:16 +00004488 idx = 0;
4489 *bltin = -1;
4490 for (;;) {
4491 if (*old != *new) {
4492 firstchange = idx;
4493 if ((*old == '\0' && *new == ':')
4494 || (*old == ':' && *new == '\0'))
4495 firstchange++;
Eric Andersen2870d962001-07-02 17:27:21 +00004496 old = new; /* ignore subsequent differences */
Eric Andersencb57d552001-06-28 07:25:16 +00004497 }
4498 if (*new == '\0')
4499 break;
4500 if (*new == '%' && *bltin < 0 && prefix("builtin", new + 1))
4501 *bltin = idx;
4502 if (*new == ':') {
4503 idx++;
4504 }
4505 new++, old++;
4506 }
4507 if (builtinloc >= 0 && *bltin < 0)
4508 firstchange = 0;
4509 return firstchange;
4510}
Eric Andersencb57d552001-06-28 07:25:16 +00004511/*
4512 * Routines to expand arguments to commands. We have to deal with
4513 * backquotes, shell variables, and file metacharacters.
4514 */
4515/*
4516 * _rmescape() flags
4517 */
Eric Andersen2870d962001-07-02 17:27:21 +00004518#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4519#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Eric Andersencb57d552001-06-28 07:25:16 +00004520
4521/*
4522 * Structure specifying which parts of the string should be searched
4523 * for IFS characters.
4524 */
4525
4526struct ifsregion {
Eric Andersen2870d962001-07-02 17:27:21 +00004527 struct ifsregion *next; /* next region in list */
4528 int begoff; /* offset of start of region */
4529 int endoff; /* offset of end of region */
4530 int nulonly; /* search for nul bytes only */
Eric Andersencb57d552001-06-28 07:25:16 +00004531};
4532
4533
Eric Andersen2870d962001-07-02 17:27:21 +00004534static char *expdest; /* output of current string */
4535static struct nodelist *argbackq; /* list of back quote expressions */
4536static struct ifsregion ifsfirst; /* first struct in list of ifs regions */
4537static struct ifsregion *ifslastp; /* last struct in list */
4538static struct arglist exparg; /* holds expanded arg list */
Eric Andersencb57d552001-06-28 07:25:16 +00004539
Eric Andersen2870d962001-07-02 17:27:21 +00004540static void argstr (char *, int);
4541static char *exptilde (char *, int);
4542static void expbackq (union node *, int, int);
4543static int subevalvar (char *, char *, int, int, int, int, int);
4544static char *evalvar (char *, int);
4545static int varisset (char *, int);
4546static void strtodest (const char *, const char *, int);
4547static void varvalue (char *, int, int);
4548static void recordregion (int, int, int);
4549static void removerecordregions (int);
4550static void ifsbreakup (char *, struct arglist *);
4551static void ifsfree (void);
4552static void expandmeta (struct strlist *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004553#if defined(__GLIBC__) && !defined(FNMATCH_BROKEN)
4554#define preglob(p) _rmescapes((p), RMESCAPE_ALLOC | RMESCAPE_GLOB)
4555#if !defined(GLOB_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00004556static void addglob (const glob_t *);
Eric Andersencb57d552001-06-28 07:25:16 +00004557#endif
4558#endif
4559#if !(defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersen2870d962001-07-02 17:27:21 +00004560static void expmeta (char *, char *);
Eric Andersencb57d552001-06-28 07:25:16 +00004561#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004562#if !(defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersen2870d962001-07-02 17:27:21 +00004563static struct strlist *expsort (struct strlist *);
4564static struct strlist *msort (struct strlist *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004565#endif
4566#if defined(__GLIBC__) && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00004567static int patmatch (char *, char *, int);
4568static int patmatch2 (char *, char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004569#else
Eric Andersen2870d962001-07-02 17:27:21 +00004570static int pmatch (char *, char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004571#define patmatch2 patmatch
4572#endif
Eric Andersen2870d962001-07-02 17:27:21 +00004573static char *cvtnum (int, char *);
Eric Andersencb57d552001-06-28 07:25:16 +00004574
4575/*
4576 * Expand shell variables and backquotes inside a here document.
4577 */
4578
Eric Andersen2870d962001-07-02 17:27:21 +00004579/* arg: the document, fd: where to write the expanded version */
Eric Andersencb57d552001-06-28 07:25:16 +00004580static void
Eric Andersen2870d962001-07-02 17:27:21 +00004581expandhere(union node *arg, int fd)
4582{
Eric Andersencb57d552001-06-28 07:25:16 +00004583 herefd = fd;
4584 expandarg(arg, (struct arglist *)NULL, 0);
4585 xwrite(fd, stackblock(), expdest - stackblock());
4586}
4587
4588
4589/*
4590 * Perform variable substitution and command substitution on an argument,
4591 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4592 * perform splitting and file name expansion. When arglist is NULL, perform
4593 * here document expansion.
4594 */
4595
4596static void
4597expandarg(arg, arglist, flag)
4598 union node *arg;
4599 struct arglist *arglist;
4600 int flag;
4601{
4602 struct strlist *sp;
4603 char *p;
4604
4605 argbackq = arg->narg.backquote;
4606 STARTSTACKSTR(expdest);
4607 ifsfirst.next = NULL;
4608 ifslastp = NULL;
4609 argstr(arg->narg.text, flag);
4610 if (arglist == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00004611 return; /* here document expanded */
Eric Andersencb57d552001-06-28 07:25:16 +00004612 }
4613 STPUTC('\0', expdest);
4614 p = grabstackstr(expdest);
4615 exparg.lastp = &exparg.list;
4616 /*
4617 * TODO - EXP_REDIR
4618 */
4619 if (flag & EXP_FULL) {
4620 ifsbreakup(p, &exparg);
4621 *exparg.lastp = NULL;
4622 exparg.lastp = &exparg.list;
4623 expandmeta(exparg.list, flag);
4624 } else {
4625 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
4626 rmescapes(p);
4627 sp = (struct strlist *)stalloc(sizeof (struct strlist));
4628 sp->text = p;
4629 *exparg.lastp = sp;
4630 exparg.lastp = &sp->next;
4631 }
4632 ifsfree();
4633 *exparg.lastp = NULL;
4634 if (exparg.list) {
4635 *arglist->lastp = exparg.list;
4636 arglist->lastp = exparg.lastp;
4637 }
4638}
4639
4640
4641
4642/*
4643 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4644 * characters to allow for further processing. Otherwise treat
4645 * $@ like $* since no splitting will be performed.
4646 */
4647
4648static void
4649argstr(p, flag)
4650 char *p;
4651 int flag;
4652{
4653 char c;
Eric Andersen2870d962001-07-02 17:27:21 +00004654 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
Eric Andersencb57d552001-06-28 07:25:16 +00004655 int firsteq = 1;
4656
4657 if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
4658 p = exptilde(p, flag);
4659 for (;;) {
4660 switch (c = *p++) {
4661 case '\0':
4662 case CTLENDVAR: /* ??? */
4663 goto breakloop;
4664 case CTLQUOTEMARK:
4665 /* "$@" syntax adherence hack */
4666 if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=')
4667 break;
4668 if ((flag & EXP_FULL) != 0)
4669 STPUTC(c, expdest);
4670 break;
4671 case CTLESC:
4672 if (quotes)
4673 STPUTC(c, expdest);
4674 c = *p++;
4675 STPUTC(c, expdest);
4676 break;
4677 case CTLVAR:
4678 p = evalvar(p, flag);
4679 break;
4680 case CTLBACKQ:
4681 case CTLBACKQ|CTLQUOTE:
4682 expbackq(argbackq->n, c & CTLQUOTE, flag);
4683 argbackq = argbackq->next;
4684 break;
4685#ifdef ASH_MATH_SUPPORT
4686 case CTLENDARI:
4687 expari(flag);
4688 break;
Eric Andersen2870d962001-07-02 17:27:21 +00004689#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004690 case ':':
4691 case '=':
4692 /*
4693 * sort of a hack - expand tildes in variable
4694 * assignments (after the first '=' and after ':'s).
4695 */
4696 STPUTC(c, expdest);
4697 if (flag & EXP_VARTILDE && *p == '~') {
4698 if (c == '=') {
4699 if (firsteq)
4700 firsteq = 0;
4701 else
4702 break;
4703 }
4704 p = exptilde(p, flag);
4705 }
4706 break;
4707 default:
4708 STPUTC(c, expdest);
4709 }
4710 }
4711breakloop:;
4712 return;
4713}
4714
4715static char *
4716exptilde(p, flag)
4717 char *p;
4718 int flag;
4719{
4720 char c, *startp = p;
4721 struct passwd *pw;
4722 const char *home;
4723 int quotes = flag & (EXP_FULL | EXP_CASE);
4724
4725 while ((c = *p) != '\0') {
4726 switch(c) {
4727 case CTLESC:
4728 return (startp);
4729 case CTLQUOTEMARK:
4730 return (startp);
4731 case ':':
4732 if (flag & EXP_VARTILDE)
4733 goto done;
4734 break;
4735 case '/':
4736 goto done;
4737 }
4738 p++;
4739 }
4740done:
4741 *p = '\0';
4742 if (*(startp+1) == '\0') {
4743 if ((home = lookupvar("HOME")) == NULL)
4744 goto lose;
4745 } else {
4746 if ((pw = getpwnam(startp+1)) == NULL)
4747 goto lose;
4748 home = pw->pw_dir;
4749 }
4750 if (*home == '\0')
4751 goto lose;
4752 *p = c;
4753 strtodest(home, SQSYNTAX, quotes);
4754 return (p);
4755lose:
4756 *p = c;
4757 return (startp);
4758}
4759
4760
Eric Andersen2870d962001-07-02 17:27:21 +00004761static void
4762removerecordregions(int endoff)
Eric Andersencb57d552001-06-28 07:25:16 +00004763{
4764 if (ifslastp == NULL)
4765 return;
4766
4767 if (ifsfirst.endoff > endoff) {
4768 while (ifsfirst.next != NULL) {
4769 struct ifsregion *ifsp;
4770 INTOFF;
4771 ifsp = ifsfirst.next->next;
4772 ckfree(ifsfirst.next);
4773 ifsfirst.next = ifsp;
4774 INTON;
4775 }
4776 if (ifsfirst.begoff > endoff)
4777 ifslastp = NULL;
4778 else {
4779 ifslastp = &ifsfirst;
4780 ifsfirst.endoff = endoff;
4781 }
4782 return;
4783 }
Eric Andersen2870d962001-07-02 17:27:21 +00004784
Eric Andersencb57d552001-06-28 07:25:16 +00004785 ifslastp = &ifsfirst;
4786 while (ifslastp->next && ifslastp->next->begoff < endoff)
4787 ifslastp=ifslastp->next;
4788 while (ifslastp->next != NULL) {
4789 struct ifsregion *ifsp;
4790 INTOFF;
4791 ifsp = ifslastp->next->next;
4792 ckfree(ifslastp->next);
4793 ifslastp->next = ifsp;
4794 INTON;
4795 }
4796 if (ifslastp->endoff > endoff)
4797 ifslastp->endoff = endoff;
4798}
4799
4800
4801#ifdef ASH_MATH_SUPPORT
4802/*
4803 * Expand arithmetic expression. Backup to start of expression,
4804 * evaluate, place result in (backed up) result, adjust string position.
4805 */
4806static void
Eric Andersen2870d962001-07-02 17:27:21 +00004807expari(int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004808{
4809 char *p, *start;
4810 int result;
4811 int begoff;
4812 int quotes = flag & (EXP_FULL | EXP_CASE);
4813 int quoted;
4814
Eric Andersen2870d962001-07-02 17:27:21 +00004815 /* ifsfree(); */
Eric Andersencb57d552001-06-28 07:25:16 +00004816
4817 /*
4818 * This routine is slightly over-complicated for
4819 * efficiency. First we make sure there is
4820 * enough space for the result, which may be bigger
4821 * than the expression if we add exponentation. Next we
4822 * scan backwards looking for the start of arithmetic. If the
4823 * next previous character is a CTLESC character, then we
4824 * have to rescan starting from the beginning since CTLESC
4825 * characters have to be processed left to right.
4826 */
4827 CHECKSTRSPACE(10, expdest);
4828 USTPUTC('\0', expdest);
4829 start = stackblock();
4830 p = expdest - 1;
4831 while (*p != CTLARI && p >= start)
4832 --p;
4833 if (*p != CTLARI)
4834 error("missing CTLARI (shouldn't happen)");
4835 if (p > start && *(p-1) == CTLESC)
4836 for (p = start; *p != CTLARI; p++)
4837 if (*p == CTLESC)
4838 p++;
4839
4840 if (p[1] == '"')
4841 quoted=1;
4842 else
4843 quoted=0;
4844 begoff = p - start;
4845 removerecordregions(begoff);
4846 if (quotes)
4847 rmescapes(p+2);
4848 result = arith(p+2);
Eric Andersen3102ac42001-07-06 04:26:23 +00004849 snprintf(p, 12, "%d", result);
Eric Andersencb57d552001-06-28 07:25:16 +00004850
4851 while (*p++)
4852 ;
4853
4854 if (quoted == 0)
4855 recordregion(begoff, p - 1 - start, 0);
4856 result = expdest - p + 1;
4857 STADJUST(-result, expdest);
4858}
Eric Andersen2870d962001-07-02 17:27:21 +00004859#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004860
4861/*
4862 * Expand stuff in backwards quotes.
4863 */
4864
4865static void
4866expbackq(cmd, quoted, flag)
4867 union node *cmd;
4868 int quoted;
4869 int flag;
4870{
4871 volatile struct backcmd in;
4872 int i;
4873 char buf[128];
4874 char *p;
4875 char *dest = expdest;
4876 volatile struct ifsregion saveifs;
4877 struct ifsregion *volatile savelastp;
4878 struct nodelist *volatile saveargbackq;
4879 char lastc;
4880 int startloc = dest - stackblock();
4881 char const *syntax = quoted? DQSYNTAX : BASESYNTAX;
4882 volatile int saveherefd;
4883 int quotes = flag & (EXP_FULL | EXP_CASE);
4884 struct jmploc jmploc;
4885 struct jmploc *volatile savehandler;
4886 int ex;
4887
4888#if __GNUC__
4889 /* Avoid longjmp clobbering */
4890 (void) &dest;
4891 (void) &syntax;
4892#endif
4893
4894 in.fd = -1;
4895 in.buf = 0;
4896 in.jp = 0;
4897
4898 INTOFF;
4899 saveifs = ifsfirst;
4900 savelastp = ifslastp;
4901 saveargbackq = argbackq;
4902 saveherefd = herefd;
4903 herefd = -1;
4904 if ((ex = setjmp(jmploc.loc))) {
4905 goto err1;
4906 }
4907 savehandler = handler;
4908 handler = &jmploc;
4909 INTON;
4910 p = grabstackstr(dest);
4911 evalbackcmd(cmd, (struct backcmd *) &in);
4912 ungrabstackstr(p, dest);
4913err1:
4914 INTOFF;
4915 ifsfirst = saveifs;
4916 ifslastp = savelastp;
4917 argbackq = saveargbackq;
4918 herefd = saveherefd;
4919 if (ex) {
4920 goto err2;
4921 }
4922
4923 p = in.buf;
4924 lastc = '\0';
4925 for (;;) {
4926 if (--in.nleft < 0) {
4927 if (in.fd < 0)
4928 break;
4929 while ((i = read(in.fd, buf, sizeof buf)) < 0 && errno == EINTR);
4930 TRACE(("expbackq: read returns %d\n", i));
4931 if (i <= 0)
4932 break;
4933 p = buf;
4934 in.nleft = i - 1;
4935 }
4936 lastc = *p++;
4937 if (lastc != '\0') {
4938 if (quotes && syntax[(int)lastc] == CCTL)
4939 STPUTC(CTLESC, dest);
4940 STPUTC(lastc, dest);
4941 }
4942 }
4943
4944 /* Eat all trailing newlines */
4945 for (; dest > stackblock() && dest[-1] == '\n';)
4946 STUNPUTC(dest);
4947
4948err2:
4949 if (in.fd >= 0)
4950 close(in.fd);
4951 if (in.buf)
4952 ckfree(in.buf);
4953 if (in.jp)
4954 exitstatus = waitforjob(in.jp);
4955 handler = savehandler;
4956 if (ex) {
4957 longjmp(handler->loc, 1);
4958 }
4959 if (quoted == 0)
4960 recordregion(startloc, dest - stackblock(), 0);
4961 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4962 (dest - stackblock()) - startloc,
4963 (dest - stackblock()) - startloc,
4964 stackblock() + startloc));
4965 expdest = dest;
4966 INTON;
4967}
4968
Eric Andersencb57d552001-06-28 07:25:16 +00004969static int
4970subevalvar(p, str, strloc, subtype, startloc, varflags, quotes)
4971 char *p;
4972 char *str;
4973 int strloc;
4974 int subtype;
4975 int startloc;
4976 int varflags;
4977 int quotes;
4978{
4979 char *startp;
4980 char *loc = NULL;
4981 char *q;
4982 int c = 0;
4983 int saveherefd = herefd;
4984 struct nodelist *saveargbackq = argbackq;
4985 int amount;
4986
4987 herefd = -1;
4988 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
4989 STACKSTRNUL(expdest);
4990 herefd = saveherefd;
4991 argbackq = saveargbackq;
4992 startp = stackblock() + startloc;
4993 if (str == NULL)
4994 str = stackblock() + strloc;
4995
4996 switch (subtype) {
4997 case VSASSIGN:
4998 setvar(str, startp, 0);
4999 amount = startp - expdest;
5000 STADJUST(amount, expdest);
5001 varflags &= ~VSNUL;
5002 if (c != 0)
5003 *loc = c;
5004 return 1;
5005
5006 case VSQUESTION:
5007 if (*p != CTLENDVAR) {
Eric Andersen3102ac42001-07-06 04:26:23 +00005008 out2fmt(snlfmt, startp);
Eric Andersencb57d552001-06-28 07:25:16 +00005009 error((char *)NULL);
5010 }
5011 error("%.*s: parameter %snot set", p - str - 1,
5012 str, (varflags & VSNUL) ? "null or "
5013 : nullstr);
5014 /* NOTREACHED */
5015
5016 case VSTRIMLEFT:
5017 for (loc = startp; loc < str; loc++) {
5018 c = *loc;
5019 *loc = '\0';
5020 if (patmatch2(str, startp, quotes))
5021 goto recordleft;
5022 *loc = c;
5023 if (quotes && *loc == CTLESC)
Eric Andersen2870d962001-07-02 17:27:21 +00005024 loc++;
Eric Andersencb57d552001-06-28 07:25:16 +00005025 }
5026 return 0;
5027
5028 case VSTRIMLEFTMAX:
5029 for (loc = str - 1; loc >= startp;) {
5030 c = *loc;
5031 *loc = '\0';
5032 if (patmatch2(str, startp, quotes))
5033 goto recordleft;
5034 *loc = c;
5035 loc--;
5036 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
5037 for (q = startp; q < loc; q++)
5038 if (*q == CTLESC)
5039 q++;
5040 if (q > loc)
5041 loc--;
5042 }
5043 }
5044 return 0;
5045
5046 case VSTRIMRIGHT:
Eric Andersen2870d962001-07-02 17:27:21 +00005047 for (loc = str - 1; loc >= startp;) {
Eric Andersencb57d552001-06-28 07:25:16 +00005048 if (patmatch2(str, loc, quotes))
5049 goto recordright;
5050 loc--;
Eric Andersen2870d962001-07-02 17:27:21 +00005051 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
Eric Andersencb57d552001-06-28 07:25:16 +00005052 for (q = startp; q < loc; q++)
5053 if (*q == CTLESC)
5054 q++;
5055 if (q > loc)
5056 loc--;
5057 }
5058 }
5059 return 0;
5060
5061 case VSTRIMRIGHTMAX:
5062 for (loc = startp; loc < str - 1; loc++) {
5063 if (patmatch2(str, loc, quotes))
5064 goto recordright;
5065 if (quotes && *loc == CTLESC)
Eric Andersen2870d962001-07-02 17:27:21 +00005066 loc++;
Eric Andersencb57d552001-06-28 07:25:16 +00005067 }
5068 return 0;
5069
5070#ifdef DEBUG
5071 default:
5072 abort();
5073#endif
5074 }
5075
5076recordleft:
5077 *loc = c;
5078 amount = ((str - 1) - (loc - startp)) - expdest;
5079 STADJUST(amount, expdest);
5080 while (loc != str - 1)
5081 *startp++ = *loc++;
5082 return 1;
5083
5084recordright:
5085 amount = loc - expdest;
5086 STADJUST(amount, expdest);
5087 STPUTC('\0', expdest);
5088 STADJUST(-1, expdest);
5089 return 1;
5090}
5091
5092
5093/*
5094 * Expand a variable, and return a pointer to the next character in the
5095 * input string.
5096 */
5097
5098static char *
5099evalvar(p, flag)
5100 char *p;
5101 int flag;
5102{
5103 int subtype;
5104 int varflags;
5105 char *var;
5106 char *val;
5107 int patloc;
5108 int c;
5109 int set;
5110 int special;
5111 int startloc;
5112 int varlen;
5113 int easy;
5114 int quotes = flag & (EXP_FULL | EXP_CASE);
5115
5116 varflags = *p++;
5117 subtype = varflags & VSTYPE;
5118 var = p;
5119 special = 0;
5120 if (! is_name(*p))
5121 special = 1;
5122 p = strchr(p, '=') + 1;
5123again: /* jump here after setting a variable with ${var=text} */
5124 if (special) {
5125 set = varisset(var, varflags & VSNUL);
5126 val = NULL;
5127 } else {
5128 val = lookupvar(var);
5129 if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
5130 val = NULL;
5131 set = 0;
5132 } else
5133 set = 1;
5134 }
5135 varlen = 0;
5136 startloc = expdest - stackblock();
5137 if (set && subtype != VSPLUS) {
5138 /* insert the value of the variable */
5139 if (special) {
5140 varvalue(var, varflags & VSQUOTE, flag);
5141 if (subtype == VSLENGTH) {
5142 varlen = expdest - stackblock() - startloc;
5143 STADJUST(-varlen, expdest);
5144 }
5145 } else {
5146 if (subtype == VSLENGTH) {
5147 varlen = strlen(val);
5148 } else {
5149 strtodest(
5150 val,
5151 varflags & VSQUOTE ?
5152 DQSYNTAX : BASESYNTAX,
5153 quotes
5154 );
5155 }
5156 }
5157 }
5158
5159 if (subtype == VSPLUS)
5160 set = ! set;
5161
5162 easy = ((varflags & VSQUOTE) == 0 ||
5163 (*var == '@' && shellparam.nparam != 1));
5164
5165
5166 switch (subtype) {
5167 case VSLENGTH:
5168 expdest = cvtnum(varlen, expdest);
5169 goto record;
5170
5171 case VSNORMAL:
5172 if (!easy)
5173 break;
5174record:
5175 recordregion(startloc, expdest - stackblock(),
5176 varflags & VSQUOTE);
5177 break;
5178
5179 case VSPLUS:
5180 case VSMINUS:
5181 if (!set) {
Eric Andersen2870d962001-07-02 17:27:21 +00005182 argstr(p, flag);
Eric Andersencb57d552001-06-28 07:25:16 +00005183 break;
5184 }
5185 if (easy)
5186 goto record;
5187 break;
5188
5189 case VSTRIMLEFT:
5190 case VSTRIMLEFTMAX:
5191 case VSTRIMRIGHT:
5192 case VSTRIMRIGHTMAX:
5193 if (!set)
5194 break;
5195 /*
5196 * Terminate the string and start recording the pattern
5197 * right after it
5198 */
5199 STPUTC('\0', expdest);
5200 patloc = expdest - stackblock();
5201 if (subevalvar(p, NULL, patloc, subtype,
5202 startloc, varflags, quotes) == 0) {
5203 int amount = (expdest - stackblock() - patloc) + 1;
5204 STADJUST(-amount, expdest);
5205 }
5206 /* Remove any recorded regions beyond start of variable */
5207 removerecordregions(startloc);
5208 goto record;
5209
5210 case VSASSIGN:
5211 case VSQUESTION:
5212 if (!set) {
5213 if (subevalvar(p, var, 0, subtype, startloc,
5214 varflags, quotes)) {
5215 varflags &= ~VSNUL;
Eric Andersen2870d962001-07-02 17:27:21 +00005216 /*
5217 * Remove any recorded regions beyond
5218 * start of variable
Eric Andersencb57d552001-06-28 07:25:16 +00005219 */
5220 removerecordregions(startloc);
5221 goto again;
5222 }
5223 break;
5224 }
5225 if (easy)
5226 goto record;
5227 break;
5228
5229#ifdef DEBUG
5230 default:
5231 abort();
5232#endif
5233 }
5234
Eric Andersen2870d962001-07-02 17:27:21 +00005235 if (subtype != VSNORMAL) { /* skip to end of alternative */
Eric Andersencb57d552001-06-28 07:25:16 +00005236 int nesting = 1;
5237 for (;;) {
5238 if ((c = *p++) == CTLESC)
5239 p++;
5240 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
5241 if (set)
5242 argbackq = argbackq->next;
5243 } else if (c == CTLVAR) {
5244 if ((*p++ & VSTYPE) != VSNORMAL)
5245 nesting++;
5246 } else if (c == CTLENDVAR) {
5247 if (--nesting == 0)
5248 break;
5249 }
5250 }
5251 }
5252 return p;
5253}
5254
Eric Andersencb57d552001-06-28 07:25:16 +00005255/*
5256 * Test whether a specialized variable is set.
5257 */
5258
5259static int
5260varisset(name, nulok)
5261 char *name;
5262 int nulok;
5263{
5264 if (*name == '!')
5265 return backgndpid != -1;
5266 else if (*name == '@' || *name == '*') {
5267 if (*shellparam.p == NULL)
5268 return 0;
5269
5270 if (nulok) {
5271 char **av;
5272
5273 for (av = shellparam.p; *av; av++)
5274 if (**av != '\0')
5275 return 1;
5276 return 0;
5277 }
5278 } else if (is_digit(*name)) {
5279 char *ap;
5280 int num = atoi(name);
5281
5282 if (num > shellparam.nparam)
5283 return 0;
5284
5285 if (num == 0)
5286 ap = arg0;
5287 else
5288 ap = shellparam.p[num - 1];
5289
5290 if (nulok && (ap == NULL || *ap == '\0'))
5291 return 0;
5292 }
5293 return 1;
5294}
5295
Eric Andersencb57d552001-06-28 07:25:16 +00005296/*
5297 * Put a string on the stack.
5298 */
5299
5300static void
5301strtodest(p, syntax, quotes)
5302 const char *p;
5303 const char *syntax;
5304 int quotes;
5305{
5306 while (*p) {
5307 if (quotes && syntax[(int) *p] == CCTL)
5308 STPUTC(CTLESC, expdest);
5309 STPUTC(*p++, expdest);
5310 }
5311}
5312
Eric Andersencb57d552001-06-28 07:25:16 +00005313/*
5314 * Add the value of a specialized variable to the stack string.
5315 */
5316
5317static void
5318varvalue(name, quoted, flags)
5319 char *name;
5320 int quoted;
5321 int flags;
5322{
5323 int num;
5324 char *p;
5325 int i;
5326 int sep;
5327 int sepq = 0;
5328 char **ap;
5329 char const *syntax;
5330 int allow_split = flags & EXP_FULL;
5331 int quotes = flags & (EXP_FULL | EXP_CASE);
5332
5333 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5334 switch (*name) {
5335 case '$':
5336 num = rootpid;
5337 goto numvar;
5338 case '?':
5339 num = oexitstatus;
5340 goto numvar;
5341 case '#':
5342 num = shellparam.nparam;
5343 goto numvar;
5344 case '!':
5345 num = backgndpid;
5346numvar:
5347 expdest = cvtnum(num, expdest);
5348 break;
5349 case '-':
5350 for (i = 0 ; i < NOPTS ; i++) {
Eric Andersen2870d962001-07-02 17:27:21 +00005351 if (optent_val(i))
5352 STPUTC(optent_letter(optlist[i]), expdest);
Eric Andersencb57d552001-06-28 07:25:16 +00005353 }
5354 break;
5355 case '@':
5356 if (allow_split && quoted) {
5357 sep = 1 << CHAR_BIT;
5358 goto param;
5359 }
5360 /* fall through */
5361 case '*':
5362 sep = ifsset() ? ifsval()[0] : ' ';
5363 if (quotes) {
5364 sepq = syntax[(int) sep] == CCTL;
5365 }
5366param:
5367 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
5368 strtodest(p, syntax, quotes);
5369 if (*ap && sep) {
5370 if (sepq)
5371 STPUTC(CTLESC, expdest);
5372 STPUTC(sep, expdest);
5373 }
5374 }
5375 break;
5376 case '0':
5377 strtodest(arg0, syntax, quotes);
5378 break;
5379 default:
5380 num = atoi(name);
5381 if (num > 0 && num <= shellparam.nparam) {
5382 strtodest(shellparam.p[num - 1], syntax, quotes);
5383 }
5384 break;
5385 }
5386}
5387
5388
Eric Andersencb57d552001-06-28 07:25:16 +00005389/*
5390 * Record the fact that we have to scan this region of the
5391 * string for IFS characters.
5392 */
5393
5394static void
5395recordregion(start, end, nulonly)
5396 int start;
5397 int end;
5398 int nulonly;
5399{
5400 struct ifsregion *ifsp;
5401
5402 if (ifslastp == NULL) {
5403 ifsp = &ifsfirst;
5404 } else {
5405 INTOFF;
5406 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
5407 ifsp->next = NULL;
5408 ifslastp->next = ifsp;
5409 INTON;
5410 }
5411 ifslastp = ifsp;
5412 ifslastp->begoff = start;
5413 ifslastp->endoff = end;
5414 ifslastp->nulonly = nulonly;
5415}
5416
5417
5418
5419/*
5420 * Break the argument string into pieces based upon IFS and add the
5421 * strings to the argument list. The regions of the string to be
5422 * searched for IFS characters have been stored by recordregion.
5423 */
5424static void
5425ifsbreakup(string, arglist)
5426 char *string;
5427 struct arglist *arglist;
5428 {
5429 struct ifsregion *ifsp;
5430 struct strlist *sp;
5431 char *start;
5432 char *p;
5433 char *q;
5434 const char *ifs, *realifs;
5435 int ifsspc;
5436 int nulonly;
5437
5438
5439 start = string;
5440 ifsspc = 0;
5441 nulonly = 0;
5442 realifs = ifsset() ? ifsval() : defifs;
5443 if (ifslastp != NULL) {
5444 ifsp = &ifsfirst;
5445 do {
5446 p = string + ifsp->begoff;
5447 nulonly = ifsp->nulonly;
5448 ifs = nulonly ? nullstr : realifs;
5449 ifsspc = 0;
5450 while (p < string + ifsp->endoff) {
5451 q = p;
5452 if (*p == CTLESC)
5453 p++;
5454 if (strchr(ifs, *p)) {
5455 if (!nulonly)
5456 ifsspc = (strchr(defifs, *p) != NULL);
5457 /* Ignore IFS whitespace at start */
5458 if (q == start && ifsspc) {
5459 p++;
5460 start = p;
5461 continue;
5462 }
5463 *q = '\0';
5464 sp = (struct strlist *)stalloc(sizeof *sp);
5465 sp->text = start;
5466 *arglist->lastp = sp;
5467 arglist->lastp = &sp->next;
5468 p++;
5469 if (!nulonly) {
5470 for (;;) {
5471 if (p >= string + ifsp->endoff) {
5472 break;
5473 }
5474 q = p;
5475 if (*p == CTLESC)
5476 p++;
5477 if (strchr(ifs, *p) == NULL ) {
5478 p = q;
5479 break;
5480 } else if (strchr(defifs, *p) == NULL) {
5481 if (ifsspc) {
5482 p++;
5483 ifsspc = 0;
5484 } else {
5485 p = q;
5486 break;
5487 }
5488 } else
5489 p++;
5490 }
5491 }
5492 start = p;
5493 } else
5494 p++;
5495 }
5496 } while ((ifsp = ifsp->next) != NULL);
5497 if (!(*start || (!ifsspc && start > string && nulonly))) {
5498 return;
5499 }
5500 }
5501
5502 sp = (struct strlist *)stalloc(sizeof *sp);
5503 sp->text = start;
5504 *arglist->lastp = sp;
5505 arglist->lastp = &sp->next;
5506}
5507
5508static void
5509ifsfree()
5510{
5511 while (ifsfirst.next != NULL) {
5512 struct ifsregion *ifsp;
5513 INTOFF;
5514 ifsp = ifsfirst.next->next;
5515 ckfree(ifsfirst.next);
5516 ifsfirst.next = ifsp;
5517 INTON;
5518 }
5519 ifslastp = NULL;
5520 ifsfirst.next = NULL;
5521}
5522
Eric Andersen2870d962001-07-02 17:27:21 +00005523/*
5524 * Add a file name to the list.
5525 */
Eric Andersencb57d552001-06-28 07:25:16 +00005526
Eric Andersen2870d962001-07-02 17:27:21 +00005527static void
5528addfname(const char *name)
5529{
5530 char *p;
5531 struct strlist *sp;
5532
5533 p = sstrdup(name);
5534 sp = (struct strlist *)stalloc(sizeof *sp);
5535 sp->text = p;
5536 *exparg.lastp = sp;
5537 exparg.lastp = &sp->next;
5538}
Eric Andersencb57d552001-06-28 07:25:16 +00005539
5540/*
5541 * Expand shell metacharacters. At this point, the only control characters
5542 * should be escapes. The results are stored in the list exparg.
5543 */
5544
5545#if defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)
5546static void
5547expandmeta(str, flag)
5548 struct strlist *str;
5549 int flag;
5550{
5551 const char *p;
5552 glob_t pglob;
5553 /* TODO - EXP_REDIR */
5554
5555 while (str) {
5556 if (fflag)
5557 goto nometa;
5558 p = preglob(str->text);
5559 INTOFF;
5560 switch (glob(p, GLOB_NOMAGIC, 0, &pglob)) {
5561 case 0:
5562 if (!(pglob.gl_flags & GLOB_MAGCHAR))
5563 goto nometa2;
5564 addglob(&pglob);
5565 globfree(&pglob);
5566 INTON;
5567 break;
5568 case GLOB_NOMATCH:
5569nometa2:
5570 globfree(&pglob);
5571 INTON;
5572nometa:
5573 *exparg.lastp = str;
5574 rmescapes(str->text);
5575 exparg.lastp = &str->next;
5576 break;
Eric Andersen2870d962001-07-02 17:27:21 +00005577 default: /* GLOB_NOSPACE */
Eric Andersencb57d552001-06-28 07:25:16 +00005578 error("Out of space");
5579 }
5580 str = str->next;
5581 }
5582}
5583
5584
5585/*
5586 * Add the result of glob(3) to the list.
5587 */
5588
5589static void
5590addglob(pglob)
5591 const glob_t *pglob;
5592{
5593 char **p = pglob->gl_pathv;
5594
5595 do {
5596 addfname(*p);
5597 } while (*++p);
5598}
5599
5600
Eric Andersen2870d962001-07-02 17:27:21 +00005601#else /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
Eric Andersencb57d552001-06-28 07:25:16 +00005602static char *expdir;
5603
5604
5605static void
5606expandmeta(str, flag)
5607 struct strlist *str;
5608 int flag;
5609{
5610 char *p;
5611 struct strlist **savelastp;
5612 struct strlist *sp;
5613 char c;
5614 /* TODO - EXP_REDIR */
5615
5616 while (str) {
5617 if (fflag)
5618 goto nometa;
5619 p = str->text;
Eric Andersen2870d962001-07-02 17:27:21 +00005620 for (;;) { /* fast check for meta chars */
Eric Andersencb57d552001-06-28 07:25:16 +00005621 if ((c = *p++) == '\0')
5622 goto nometa;
5623 if (c == '*' || c == '?' || c == '[' || c == '!')
5624 break;
5625 }
5626 savelastp = exparg.lastp;
5627 INTOFF;
5628 if (expdir == NULL) {
5629 int i = strlen(str->text);
5630 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5631 }
5632
5633 expmeta(expdir, str->text);
5634 ckfree(expdir);
5635 expdir = NULL;
5636 INTON;
5637 if (exparg.lastp == savelastp) {
5638 /*
5639 * no matches
5640 */
5641nometa:
5642 *exparg.lastp = str;
5643 rmescapes(str->text);
5644 exparg.lastp = &str->next;
5645 } else {
5646 *exparg.lastp = NULL;
5647 *savelastp = sp = expsort(*savelastp);
5648 while (sp->next != NULL)
5649 sp = sp->next;
5650 exparg.lastp = &sp->next;
5651 }
5652 str = str->next;
5653 }
5654}
5655
5656
5657/*
5658 * Do metacharacter (i.e. *, ?, [...]) expansion.
5659 */
5660
5661static void
5662expmeta(enddir, name)
5663 char *enddir;
5664 char *name;
5665 {
5666 char *p;
5667 const char *cp;
5668 char *q;
5669 char *start;
5670 char *endname;
5671 int metaflag;
5672 struct stat statb;
5673 DIR *dirp;
5674 struct dirent *dp;
5675 int atend;
5676 int matchdot;
5677
5678 metaflag = 0;
5679 start = name;
5680 for (p = name ; ; p++) {
5681 if (*p == '*' || *p == '?')
5682 metaflag = 1;
5683 else if (*p == '[') {
5684 q = p + 1;
5685 if (*q == '!')
5686 q++;
5687 for (;;) {
5688 while (*q == CTLQUOTEMARK)
5689 q++;
5690 if (*q == CTLESC)
5691 q++;
5692 if (*q == '/' || *q == '\0')
5693 break;
5694 if (*++q == ']') {
5695 metaflag = 1;
5696 break;
5697 }
5698 }
Eric Andersen2870d962001-07-02 17:27:21 +00005699 } else if (*p == '!' && p[1] == '!' && (p == name || p[-1] == '/')) {
Eric Andersencb57d552001-06-28 07:25:16 +00005700 metaflag = 1;
5701 } else if (*p == '\0')
5702 break;
5703 else if (*p == CTLQUOTEMARK)
5704 continue;
5705 else if (*p == CTLESC)
5706 p++;
5707 if (*p == '/') {
5708 if (metaflag)
5709 break;
5710 start = p + 1;
5711 }
5712 }
Eric Andersen2870d962001-07-02 17:27:21 +00005713 if (metaflag == 0) { /* we've reached the end of the file name */
Eric Andersencb57d552001-06-28 07:25:16 +00005714 if (enddir != expdir)
5715 metaflag++;
5716 for (p = name ; ; p++) {
5717 if (*p == CTLQUOTEMARK)
5718 continue;
5719 if (*p == CTLESC)
5720 p++;
5721 *enddir++ = *p;
5722 if (*p == '\0')
5723 break;
5724 }
5725 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
5726 addfname(expdir);
5727 return;
5728 }
5729 endname = p;
5730 if (start != name) {
5731 p = name;
5732 while (p < start) {
5733 while (*p == CTLQUOTEMARK)
5734 p++;
5735 if (*p == CTLESC)
5736 p++;
5737 *enddir++ = *p++;
5738 }
5739 }
5740 if (enddir == expdir) {
5741 cp = ".";
5742 } else if (enddir == expdir + 1 && *expdir == '/') {
5743 cp = "/";
5744 } else {
5745 cp = expdir;
5746 enddir[-1] = '\0';
5747 }
5748 if ((dirp = opendir(cp)) == NULL)
5749 return;
5750 if (enddir != expdir)
5751 enddir[-1] = '/';
5752 if (*endname == 0) {
5753 atend = 1;
5754 } else {
5755 atend = 0;
5756 *endname++ = '\0';
5757 }
5758 matchdot = 0;
5759 p = start;
5760 while (*p == CTLQUOTEMARK)
5761 p++;
5762 if (*p == CTLESC)
5763 p++;
5764 if (*p == '.')
5765 matchdot++;
5766 while (! int_pending() && (dp = readdir(dirp)) != NULL) {
5767 if (dp->d_name[0] == '.' && ! matchdot)
5768 continue;
5769 if (patmatch(start, dp->d_name, 0)) {
5770 if (atend) {
Eric Andersen2870d962001-07-02 17:27:21 +00005771 strcpy(enddir, dp->d_name);
Eric Andersencb57d552001-06-28 07:25:16 +00005772 addfname(expdir);
5773 } else {
5774 for (p = enddir, cp = dp->d_name;
5775 (*p++ = *cp++) != '\0';)
5776 continue;
5777 p[-1] = '/';
5778 expmeta(p, endname);
5779 }
5780 }
5781 }
5782 closedir(dirp);
5783 if (! atend)
5784 endname[-1] = '/';
5785}
Eric Andersen2870d962001-07-02 17:27:21 +00005786#endif /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
Eric Andersencb57d552001-06-28 07:25:16 +00005787
5788
Eric Andersencb57d552001-06-28 07:25:16 +00005789
5790#if !(defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
5791/*
5792 * Sort the results of file name expansion. It calculates the number of
5793 * strings to sort and then calls msort (short for merge sort) to do the
5794 * work.
5795 */
5796
5797static struct strlist *
5798expsort(str)
5799 struct strlist *str;
5800 {
5801 int len;
5802 struct strlist *sp;
5803
5804 len = 0;
5805 for (sp = str ; sp ; sp = sp->next)
5806 len++;
5807 return msort(str, len);
5808}
5809
5810
5811static struct strlist *
5812msort(list, len)
5813 struct strlist *list;
5814 int len;
5815{
5816 struct strlist *p, *q = NULL;
5817 struct strlist **lpp;
5818 int half;
5819 int n;
5820
5821 if (len <= 1)
5822 return list;
5823 half = len >> 1;
5824 p = list;
5825 for (n = half ; --n >= 0 ; ) {
5826 q = p;
5827 p = p->next;
5828 }
Eric Andersen2870d962001-07-02 17:27:21 +00005829 q->next = NULL; /* terminate first half of list */
5830 q = msort(list, half); /* sort first half of list */
5831 p = msort(p, len - half); /* sort second half */
Eric Andersencb57d552001-06-28 07:25:16 +00005832 lpp = &list;
5833 for (;;) {
5834 if (strcmp(p->text, q->text) < 0) {
5835 *lpp = p;
5836 lpp = &p->next;
5837 if ((p = *lpp) == NULL) {
5838 *lpp = q;
5839 break;
5840 }
5841 } else {
5842 *lpp = q;
5843 lpp = &q->next;
5844 if ((q = *lpp) == NULL) {
5845 *lpp = p;
5846 break;
5847 }
5848 }
5849 }
5850 return list;
5851}
5852#endif
5853
5854
5855
5856/*
5857 * Returns true if the pattern matches the string.
5858 */
5859
5860#if defined(__GLIBC__) && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00005861/* squoted: string might have quote chars */
Eric Andersencb57d552001-06-28 07:25:16 +00005862static int
Eric Andersen2870d962001-07-02 17:27:21 +00005863patmatch(char *pattern, char *string, int squoted)
5864{
Eric Andersencb57d552001-06-28 07:25:16 +00005865 const char *p;
5866 char *q;
5867
5868 p = preglob(pattern);
5869 q = squoted ? _rmescapes(string, RMESCAPE_ALLOC) : string;
5870
5871 return !fnmatch(p, q, 0);
5872}
5873
5874
5875static int
Eric Andersen2870d962001-07-02 17:27:21 +00005876patmatch2(char *pattern, char *string, int squoted)
5877{
Eric Andersencb57d552001-06-28 07:25:16 +00005878 char *p;
5879 int res;
5880
5881 sstrnleft--;
5882 p = grabstackstr(expdest);
5883 res = patmatch(pattern, string, squoted);
5884 ungrabstackstr(p, expdest);
5885 return res;
5886}
5887#else
5888static int
Eric Andersen2870d962001-07-02 17:27:21 +00005889patmatch(char *pattern, char *string, int squoted) {
5890 return pmatch(pattern, string, squoted);
Eric Andersencb57d552001-06-28 07:25:16 +00005891}
5892
5893
5894static int
Eric Andersen2870d962001-07-02 17:27:21 +00005895pmatch(char *pattern, char *string, int squoted)
5896{
Eric Andersencb57d552001-06-28 07:25:16 +00005897 char *p, *q;
5898 char c;
5899
5900 p = pattern;
5901 q = string;
5902 for (;;) {
5903 switch (c = *p++) {
5904 case '\0':
5905 goto breakloop;
5906 case CTLESC:
5907 if (squoted && *q == CTLESC)
5908 q++;
5909 if (*q++ != *p++)
5910 return 0;
5911 break;
5912 case CTLQUOTEMARK:
5913 continue;
5914 case '?':
5915 if (squoted && *q == CTLESC)
5916 q++;
5917 if (*q++ == '\0')
5918 return 0;
5919 break;
5920 case '*':
5921 c = *p;
5922 while (c == CTLQUOTEMARK || c == '*')
5923 c = *++p;
5924 if (c != CTLESC && c != CTLQUOTEMARK &&
5925 c != '?' && c != '*' && c != '[') {
5926 while (*q != c) {
5927 if (squoted && *q == CTLESC &&
5928 q[1] == c)
5929 break;
5930 if (*q == '\0')
5931 return 0;
5932 if (squoted && *q == CTLESC)
5933 q++;
5934 q++;
5935 }
5936 }
5937 do {
5938 if (pmatch(p, q, squoted))
5939 return 1;
5940 if (squoted && *q == CTLESC)
5941 q++;
5942 } while (*q++ != '\0');
5943 return 0;
5944 case '[': {
5945 char *endp;
5946 int invert, found;
5947 char chr;
5948
5949 endp = p;
5950 if (*endp == '!')
5951 endp++;
5952 for (;;) {
5953 while (*endp == CTLQUOTEMARK)
5954 endp++;
5955 if (*endp == '\0')
Eric Andersen2870d962001-07-02 17:27:21 +00005956 goto dft; /* no matching ] */
Eric Andersencb57d552001-06-28 07:25:16 +00005957 if (*endp == CTLESC)
5958 endp++;
5959 if (*++endp == ']')
5960 break;
5961 }
5962 invert = 0;
5963 if (*p == '!') {
5964 invert++;
5965 p++;
5966 }
5967 found = 0;
5968 chr = *q++;
5969 if (squoted && chr == CTLESC)
5970 chr = *q++;
5971 if (chr == '\0')
5972 return 0;
5973 c = *p++;
5974 do {
5975 if (c == CTLQUOTEMARK)
5976 continue;
5977 if (c == CTLESC)
5978 c = *p++;
5979 if (*p == '-' && p[1] != ']') {
5980 p++;
5981 while (*p == CTLQUOTEMARK)
5982 p++;
5983 if (*p == CTLESC)
5984 p++;
5985 if (chr >= c && chr <= *p)
5986 found = 1;
5987 p++;
5988 } else {
5989 if (chr == c)
5990 found = 1;
5991 }
5992 } while ((c = *p++) != ']');
5993 if (found == invert)
5994 return 0;
5995 break;
5996 }
Eric Andersen2870d962001-07-02 17:27:21 +00005997dft: default:
Eric Andersencb57d552001-06-28 07:25:16 +00005998 if (squoted && *q == CTLESC)
5999 q++;
6000 if (*q++ != c)
6001 return 0;
6002 break;
6003 }
6004 }
6005breakloop:
6006 if (*q != '\0')
6007 return 0;
6008 return 1;
6009}
6010#endif
6011
6012
6013
6014/*
6015 * Remove any CTLESC characters from a string.
6016 */
6017
6018#if defined(__GLIBC__) && !defined(FNMATCH_BROKEN)
6019static char *
Eric Andersen2870d962001-07-02 17:27:21 +00006020_rmescapes(char *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00006021{
6022 char *p, *q, *r;
6023 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
6024
6025 p = strpbrk(str, qchars);
6026 if (!p) {
6027 return str;
6028 }
6029 q = p;
6030 r = str;
6031 if (flag & RMESCAPE_ALLOC) {
6032 size_t len = p - str;
6033 q = r = stalloc(strlen(p) + len + 1);
6034 if (len > 0) {
6035#ifdef _GNU_SOURCE
6036 q = mempcpy(q, str, len);
6037#else
6038 memcpy(q, str, len);
6039 q += len;
6040#endif
6041 }
6042 }
6043 while (*p) {
6044 if (*p == CTLQUOTEMARK) {
6045 p++;
6046 continue;
6047 }
6048 if (*p == CTLESC) {
6049 p++;
6050 if (flag & RMESCAPE_GLOB && *p != '/') {
6051 *q++ = '\\';
6052 }
6053 }
6054 *q++ = *p++;
6055 }
6056 *q = '\0';
6057 return r;
6058}
6059#else
6060static void
6061rmescapes(str)
6062 char *str;
6063{
6064 char *p, *q;
6065
6066 p = str;
6067 while (*p != CTLESC && *p != CTLQUOTEMARK) {
6068 if (*p++ == '\0')
6069 return;
6070 }
6071 q = p;
6072 while (*p) {
6073 if (*p == CTLQUOTEMARK) {
6074 p++;
6075 continue;
6076 }
6077 if (*p == CTLESC)
6078 p++;
6079 *q++ = *p++;
6080 }
6081 *q = '\0';
6082}
6083#endif
6084
6085
6086
6087/*
6088 * See if a pattern matches in a case statement.
6089 */
6090
6091static int
Eric Andersen2870d962001-07-02 17:27:21 +00006092casematch(union node *pattern, const char *val)
6093{
Eric Andersencb57d552001-06-28 07:25:16 +00006094 struct stackmark smark;
6095 int result;
6096 char *p;
6097
6098 setstackmark(&smark);
6099 argbackq = pattern->narg.backquote;
6100 STARTSTACKSTR(expdest);
6101 ifslastp = NULL;
6102 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
6103 STPUTC('\0', expdest);
6104 p = grabstackstr(expdest);
Eric Andersen2870d962001-07-02 17:27:21 +00006105 result = patmatch(p, (char *)val, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006106 popstackmark(&smark);
6107 return result;
6108}
6109
6110/*
6111 * Our own itoa().
6112 */
6113
6114static char *
6115cvtnum(num, buf)
6116 int num;
6117 char *buf;
6118 {
6119 int len;
6120
6121 CHECKSTRSPACE(32, buf);
6122 len = sprintf(buf, "%d", num);
6123 STADJUST(len, buf);
6124 return buf;
6125}
Eric Andersencb57d552001-06-28 07:25:16 +00006126/*
6127 * Editline and history functions (and glue).
6128 */
6129static int histcmd(argc, argv)
6130 int argc;
6131 char **argv;
6132{
6133 error("not compiled with history support");
6134 /* NOTREACHED */
6135}
6136
6137
Eric Andersen2870d962001-07-02 17:27:21 +00006138static int whichprompt; /* 1 == PS1, 2 == PS2 */
Eric Andersencb57d552001-06-28 07:25:16 +00006139
Eric Andersencb57d552001-06-28 07:25:16 +00006140
6141struct redirtab {
6142 struct redirtab *next;
6143 short renamed[10];
6144};
6145
Eric Andersen2870d962001-07-02 17:27:21 +00006146static struct redirtab *redirlist;
Eric Andersencb57d552001-06-28 07:25:16 +00006147
6148extern char **environ;
6149
6150
6151
6152/*
6153 * Initialization code.
6154 */
6155
6156static void
Eric Andersen2870d962001-07-02 17:27:21 +00006157init(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00006158
6159 /* from cd.c: */
6160 {
6161 setpwd(0, 0);
6162 }
6163
6164 /* from input.c: */
6165 {
6166 basepf.nextc = basepf.buf = basebuf;
6167 }
6168
Eric Andersencb57d552001-06-28 07:25:16 +00006169 /* from var.c: */
6170 {
6171 char **envp;
6172 char ppid[32];
6173
6174 initvar();
6175 for (envp = environ ; *envp ; envp++) {
6176 if (strchr(*envp, '=')) {
6177 setvareq(*envp, VEXPORT|VTEXTFIXED);
6178 }
6179 }
6180
Eric Andersen3102ac42001-07-06 04:26:23 +00006181 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
Eric Andersencb57d552001-06-28 07:25:16 +00006182 setvar("PPID", ppid, 0);
6183 }
6184}
6185
6186
6187
6188/*
6189 * This routine is called when an error or an interrupt occurs in an
6190 * interactive shell and control is returned to the main command loop.
6191 */
6192
Eric Andersen2870d962001-07-02 17:27:21 +00006193#ifdef ASH_ALIAS
6194/* 1 == check for aliases, 2 == also check for assignments */
6195static int checkalias;
6196#endif
6197
Eric Andersencb57d552001-06-28 07:25:16 +00006198static void
Eric Andersen2870d962001-07-02 17:27:21 +00006199reset(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00006200
6201 /* from eval.c: */
6202 {
6203 evalskip = 0;
6204 loopnest = 0;
6205 funcnest = 0;
6206 }
6207
6208 /* from input.c: */
6209 {
6210 if (exception != EXSHELLPROC)
Eric Andersen2870d962001-07-02 17:27:21 +00006211 parselleft = parsenleft = 0; /* clear input buffer */
Eric Andersencb57d552001-06-28 07:25:16 +00006212 popallfiles();
6213 }
6214
6215 /* from parser.c: */
6216 {
6217 tokpushback = 0;
6218 checkkwd = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00006219#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00006220 checkalias = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00006221#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006222 }
6223
6224 /* from redir.c: */
6225 {
6226 while (redirlist)
6227 popredir();
6228 }
6229
Eric Andersencb57d552001-06-28 07:25:16 +00006230}
6231
6232
6233
6234/*
Eric Andersencb57d552001-06-28 07:25:16 +00006235 * This file implements the input routines used by the parser.
6236 */
6237
6238#ifdef BB_FEATURE_COMMAND_EDITING
6239unsigned int shell_context;
6240static const char * cmdedit_prompt;
6241static inline void putprompt(const char *s) {
6242 cmdedit_prompt = s;
6243}
6244#else
6245static inline void putprompt(const char *s) {
6246 out2str(s);
6247}
6248#endif
6249
Eric Andersen2870d962001-07-02 17:27:21 +00006250#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
Eric Andersencb57d552001-06-28 07:25:16 +00006251
Eric Andersencb57d552001-06-28 07:25:16 +00006252
Eric Andersencb57d552001-06-28 07:25:16 +00006253
Eric Andersen2870d962001-07-02 17:27:21 +00006254/*
6255 * Same as pgetc(), but ignores PEOA.
6256 */
Eric Andersencb57d552001-06-28 07:25:16 +00006257
Eric Andersen2870d962001-07-02 17:27:21 +00006258#ifdef ASH_ALIAS
6259static int
6260pgetc2()
6261{
6262 int c;
6263 do {
6264 c = pgetc_macro();
6265 } while (c == PEOA);
6266 return c;
Eric Andersencb57d552001-06-28 07:25:16 +00006267}
Eric Andersen2870d962001-07-02 17:27:21 +00006268#else
6269static inline int pgetc2() { return pgetc_macro(); }
Eric Andersencb57d552001-06-28 07:25:16 +00006270#endif
6271
Eric Andersencb57d552001-06-28 07:25:16 +00006272/*
6273 * Read a line from the script.
6274 */
6275
6276static char *
Eric Andersen2870d962001-07-02 17:27:21 +00006277pfgets(char *line, int len)
Eric Andersencb57d552001-06-28 07:25:16 +00006278{
6279 char *p = line;
6280 int nleft = len;
6281 int c;
6282
6283 while (--nleft > 0) {
6284 c = pgetc2();
6285 if (c == PEOF) {
6286 if (p == line)
6287 return NULL;
6288 break;
6289 }
6290 *p++ = c;
6291 if (c == '\n')
6292 break;
6293 }
6294 *p = '\0';
6295 return line;
6296}
6297
Eric Andersencb57d552001-06-28 07:25:16 +00006298static int
Eric Andersen2870d962001-07-02 17:27:21 +00006299preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006300{
6301 int nr;
6302 char *buf = parsefile->buf;
6303 parsenextc = buf;
6304
6305retry:
6306#ifdef BB_FEATURE_COMMAND_EDITING
6307 {
6308 if (parsefile->fd)
6309 nr = read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersen2870d962001-07-02 17:27:21 +00006310 else {
Eric Andersencb57d552001-06-28 07:25:16 +00006311 do {
6312 cmdedit_read_input((char*)cmdedit_prompt, buf);
6313 nr = strlen(buf);
6314 } while (nr <=0 || shell_context);
6315 cmdedit_terminate();
6316 }
6317 }
6318#else
6319 nr = read(parsefile->fd, buf, BUFSIZ - 1);
6320#endif
6321
6322 if (nr < 0) {
6323 if (errno == EINTR)
6324 goto retry;
6325 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6326 int flags = fcntl(0, F_GETFL, 0);
6327 if (flags >= 0 && flags & O_NONBLOCK) {
6328 flags &=~ O_NONBLOCK;
6329 if (fcntl(0, F_SETFL, flags) >= 0) {
6330 out2str("sh: turning off NDELAY mode\n");
6331 goto retry;
6332 }
6333 }
6334 }
6335 }
6336 return nr;
6337}
6338
Eric Andersen2870d962001-07-02 17:27:21 +00006339static void
6340popstring(void)
6341{
6342 struct strpush *sp = parsefile->strpush;
6343
6344 INTOFF;
6345#ifdef ASH_ALIAS
6346 if (sp->ap) {
6347 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6348 if (!checkalias) {
6349 checkalias = 1;
6350 }
6351 }
6352 if (sp->string != sp->ap->val) {
6353 ckfree(sp->string);
6354 }
6355
6356 sp->ap->flag &= ~ALIASINUSE;
6357 if (sp->ap->flag & ALIASDEAD) {
6358 unalias(sp->ap->name);
6359 }
6360 }
6361#endif
6362 parsenextc = sp->prevstring;
6363 parsenleft = sp->prevnleft;
6364/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6365 parsefile->strpush = sp->prev;
6366 if (sp != &(parsefile->basestrpush))
6367 ckfree(sp);
6368 INTON;
6369}
6370
6371
Eric Andersencb57d552001-06-28 07:25:16 +00006372/*
6373 * Refill the input buffer and return the next input character:
6374 *
6375 * 1) If a string was pushed back on the input, pop it;
6376 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6377 * from a string so we can't refill the buffer, return EOF.
6378 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6379 * 4) Process input up to the next newline, deleting nul characters.
6380 */
6381
6382static int
Eric Andersen2870d962001-07-02 17:27:21 +00006383preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006384{
6385 char *p, *q;
6386 int more;
6387 char savec;
6388
6389 while (parsefile->strpush) {
Eric Andersen2870d962001-07-02 17:27:21 +00006390#ifdef ASH_ALIAS
6391 if (parsenleft == -1 && parsefile->strpush->ap &&
6392 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +00006393 return PEOA;
6394 }
Eric Andersen2870d962001-07-02 17:27:21 +00006395#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006396 popstring();
6397 if (--parsenleft >= 0)
6398 return (*parsenextc++);
6399 }
6400 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6401 return PEOF;
Eric Andersen3102ac42001-07-06 04:26:23 +00006402 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00006403
6404again:
6405 if (parselleft <= 0) {
6406 if ((parselleft = preadfd()) <= 0) {
6407 parselleft = parsenleft = EOF_NLEFT;
6408 return PEOF;
6409 }
6410 }
6411
6412 q = p = parsenextc;
6413
6414 /* delete nul characters */
6415 for (more = 1; more;) {
6416 switch (*p) {
6417 case '\0':
Eric Andersen2870d962001-07-02 17:27:21 +00006418 p++; /* Skip nul */
Eric Andersencb57d552001-06-28 07:25:16 +00006419 goto check;
6420
6421
6422 case '\n':
6423 parsenleft = q - parsenextc;
6424 more = 0; /* Stop processing here */
6425 break;
6426 }
6427
6428 *q++ = *p++;
6429check:
6430 if (--parselleft <= 0 && more) {
6431 parsenleft = q - parsenextc - 1;
6432 if (parsenleft < 0)
6433 goto again;
6434 more = 0;
6435 }
6436 }
6437
6438 savec = *q;
6439 *q = '\0';
6440
6441 if (vflag) {
6442 out2str(parsenextc);
Eric Andersencb57d552001-06-28 07:25:16 +00006443 }
6444
6445 *q = savec;
6446
6447 return *parsenextc++;
6448}
6449
Eric Andersencb57d552001-06-28 07:25:16 +00006450
6451/*
6452 * Push a string back onto the input at this current parsefile level.
6453 * We handle aliases this way.
6454 */
6455static void
Eric Andersen2870d962001-07-02 17:27:21 +00006456pushstring(char *s, int len, void *ap)
6457{
Eric Andersencb57d552001-06-28 07:25:16 +00006458 struct strpush *sp;
6459
6460 INTOFF;
6461/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6462 if (parsefile->strpush) {
6463 sp = ckmalloc(sizeof (struct strpush));
6464 sp->prev = parsefile->strpush;
6465 parsefile->strpush = sp;
6466 } else
6467 sp = parsefile->strpush = &(parsefile->basestrpush);
6468 sp->prevstring = parsenextc;
6469 sp->prevnleft = parsenleft;
Eric Andersen2870d962001-07-02 17:27:21 +00006470#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00006471 sp->ap = (struct alias *)ap;
6472 if (ap) {
6473 ((struct alias *)ap)->flag |= ALIASINUSE;
6474 sp->string = s;
6475 }
Eric Andersen2870d962001-07-02 17:27:21 +00006476#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006477 parsenextc = s;
6478 parsenleft = len;
6479 INTON;
6480}
6481
Eric Andersencb57d552001-06-28 07:25:16 +00006482
Eric Andersencb57d552001-06-28 07:25:16 +00006483
6484
6485/*
6486 * Like setinputfile, but takes input from a string.
6487 */
6488
6489static void
6490setinputstring(string)
6491 char *string;
6492 {
6493 INTOFF;
6494 pushfile();
6495 parsenextc = string;
6496 parsenleft = strlen(string);
6497 parsefile->buf = NULL;
6498 plinno = 1;
6499 INTON;
6500}
6501
6502
6503
6504/*
6505 * To handle the "." command, a stack of input files is used. Pushfile
6506 * adds a new entry to the stack and popfile restores the previous level.
6507 */
6508
6509static void
Eric Andersen2870d962001-07-02 17:27:21 +00006510pushfile(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00006511 struct parsefile *pf;
6512
6513 parsefile->nleft = parsenleft;
6514 parsefile->lleft = parselleft;
6515 parsefile->nextc = parsenextc;
6516 parsefile->linno = plinno;
6517 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
6518 pf->prev = parsefile;
6519 pf->fd = -1;
6520 pf->strpush = NULL;
6521 pf->basestrpush.prev = NULL;
6522 parsefile = pf;
6523}
6524
Eric Andersen2870d962001-07-02 17:27:21 +00006525#ifdef JOBS
6526static void restartjob (struct job *);
Eric Andersencb57d552001-06-28 07:25:16 +00006527#endif
Eric Andersen2870d962001-07-02 17:27:21 +00006528static void freejob (struct job *);
6529static struct job *getjob (const char *);
6530static int dowait (int, struct job *);
6531static int waitproc (int, int *);
Eric Andersencb57d552001-06-28 07:25:16 +00006532static void waitonint(int);
6533
6534
Eric Andersen2870d962001-07-02 17:27:21 +00006535/*
6536 * We keep track of whether or not fd0 has been redirected. This is for
6537 * background commands, where we want to redirect fd0 to /dev/null only
6538 * if it hasn't already been redirected.
6539*/
6540static int fd0_redirected = 0;
6541
6542/* Return true if fd 0 has already been redirected at least once. */
6543static inline int
6544fd0_redirected_p () {
6545 return fd0_redirected != 0;
6546}
6547
Eric Andersen2870d962001-07-02 17:27:21 +00006548static int openredirect (union node *);
6549static void dupredirect (union node *, int, char[10 ]);
6550static int openhere (union node *);
6551static int noclobberopen (const char *);
6552
6553
6554
6555#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006556/*
6557 * Turn job control on and off.
6558 *
6559 * Note: This code assumes that the third arg to ioctl is a character
6560 * pointer, which is true on Berkeley systems but not System V. Since
6561 * System V doesn't have job control yet, this isn't a problem now.
6562 */
6563
Eric Andersen2870d962001-07-02 17:27:21 +00006564
Eric Andersencb57d552001-06-28 07:25:16 +00006565
6566static void setjobctl(int enable)
6567{
6568#ifdef OLD_TTY_DRIVER
6569 int ldisc;
6570#endif
6571
6572 if (enable == jobctl || rootshell == 0)
6573 return;
6574 if (enable) {
6575 do { /* while we are in the background */
6576#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006577 if (ioctl(2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006578#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006579 initialpgrp = tcgetpgrp(2);
Eric Andersencb57d552001-06-28 07:25:16 +00006580 if (initialpgrp < 0) {
6581#endif
6582 out2str("sh: can't access tty; job cenabletrol turned off\n");
6583 mflag = 0;
6584 return;
6585 }
6586 if (initialpgrp == -1)
6587 initialpgrp = getpgrp();
6588 else if (initialpgrp != getpgrp()) {
6589 killpg(initialpgrp, SIGTTIN);
6590 continue;
6591 }
6592 } while (0);
6593#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006594 if (ioctl(2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
Eric Andersencb57d552001-06-28 07:25:16 +00006595 out2str("sh: need new tty driver to run job cenabletrol; job cenabletrol turned off\n");
6596 mflag = 0;
6597 return;
6598 }
6599#endif
6600 setsignal(SIGTSTP);
6601 setsignal(SIGTTOU);
6602 setsignal(SIGTTIN);
6603 setpgid(0, rootpid);
6604#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006605 ioctl(2, TIOCSPGRP, (char *)&rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00006606#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006607 tcsetpgrp(2, rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00006608#endif
6609 } else { /* turning job cenabletrol off */
6610 setpgid(0, initialpgrp);
6611#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006612 ioctl(2, TIOCSPGRP, (char *)&initialpgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006613#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006614 tcsetpgrp(2, initialpgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006615#endif
6616 setsignal(SIGTSTP);
6617 setsignal(SIGTTOU);
6618 setsignal(SIGTTIN);
6619 }
6620 jobctl = enable;
6621}
6622#endif
6623
6624
Eric Andersencb57d552001-06-28 07:25:16 +00006625/* A translation list so we can be polite to our users. */
6626static char *signal_names[NSIG + 2] = {
6627 "EXIT",
6628 "SIGHUP",
6629 "SIGINT",
6630 "SIGQUIT",
6631 "SIGILL",
6632 "SIGTRAP",
6633 "SIGABRT",
6634 "SIGBUS",
6635 "SIGFPE",
6636 "SIGKILL",
6637 "SIGUSR1",
6638 "SIGSEGV",
6639 "SIGUSR2",
6640 "SIGPIPE",
6641 "SIGALRM",
6642 "SIGTERM",
6643 "SIGJUNK(16)",
6644 "SIGCHLD",
6645 "SIGCONT",
6646 "SIGSTOP",
6647 "SIGTSTP",
6648 "SIGTTIN",
6649 "SIGTTOU",
6650 "SIGURG",
6651 "SIGXCPU",
6652 "SIGXFSZ",
6653 "SIGVTALRM",
6654 "SIGPROF",
6655 "SIGWINCH",
6656 "SIGIO",
6657 "SIGPWR",
6658 "SIGSYS",
6659 "SIGRTMIN",
6660 "SIGRTMIN+1",
6661 "SIGRTMIN+2",
6662 "SIGRTMIN+3",
6663 "SIGRTMIN+4",
6664 "SIGRTMIN+5",
6665 "SIGRTMIN+6",
6666 "SIGRTMIN+7",
6667 "SIGRTMIN+8",
6668 "SIGRTMIN+9",
6669 "SIGRTMIN+10",
6670 "SIGRTMIN+11",
6671 "SIGRTMIN+12",
6672 "SIGRTMIN+13",
6673 "SIGRTMIN+14",
6674 "SIGRTMIN+15",
6675 "SIGRTMAX-15",
6676 "SIGRTMAX-14",
6677 "SIGRTMAX-13",
6678 "SIGRTMAX-12",
6679 "SIGRTMAX-11",
6680 "SIGRTMAX-10",
6681 "SIGRTMAX-9",
6682 "SIGRTMAX-8",
6683 "SIGRTMAX-7",
6684 "SIGRTMAX-6",
6685 "SIGRTMAX-5",
6686 "SIGRTMAX-4",
6687 "SIGRTMAX-3",
6688 "SIGRTMAX-2",
6689 "SIGRTMAX-1",
6690 "SIGRTMAX",
6691 "DEBUG",
6692 (char *)0x0,
6693};
6694
6695
6696
Eric Andersen2870d962001-07-02 17:27:21 +00006697#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006698static int
6699killcmd(argc, argv)
6700 int argc;
6701 char **argv;
6702{
6703 int signo = -1;
6704 int list = 0;
6705 int i;
6706 pid_t pid;
6707 struct job *jp;
6708
6709 if (argc <= 1) {
6710usage:
6711 error(
6712"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6713"kill -l [exitstatus]"
6714 );
6715 }
6716
6717 if (*argv[1] == '-') {
6718 signo = decode_signal(argv[1] + 1, 1);
6719 if (signo < 0) {
6720 int c;
6721
6722 while ((c = nextopt("ls:")) != '\0')
6723 switch (c) {
6724 case 'l':
6725 list = 1;
6726 break;
6727 case 's':
6728 signo = decode_signal(optionarg, 1);
6729 if (signo < 0) {
6730 error(
6731 "invalid signal number or name: %s",
6732 optionarg
6733 );
6734 }
Eric Andersen2870d962001-07-02 17:27:21 +00006735 break;
Eric Andersencb57d552001-06-28 07:25:16 +00006736#ifdef DEBUG
6737 default:
6738 error(
6739 "nextopt returned character code 0%o", c);
6740#endif
6741 }
6742 } else
6743 argptr++;
6744 }
6745
6746 if (!list && signo < 0)
6747 signo = SIGTERM;
6748
6749 if ((signo < 0 || !*argptr) ^ list) {
6750 goto usage;
6751 }
6752
6753 if (list) {
6754 if (!*argptr) {
6755 out1str("0\n");
6756 for (i = 1; i < NSIG; i++) {
6757 out1fmt(snlfmt, signal_names[i] + 3);
6758 }
6759 return 0;
6760 }
6761 signo = atoi(*argptr);
6762 if (signo > 128)
6763 signo -= 128;
6764 if (0 < signo && signo < NSIG)
6765 out1fmt(snlfmt, signal_names[signo] + 3);
6766 else
6767 error("invalid signal number or exit status: %s",
6768 *argptr);
6769 return 0;
6770 }
6771
6772 do {
6773 if (**argptr == '%') {
6774 jp = getjob(*argptr);
6775 if (jp->jobctl == 0)
6776 error("job %s not created under job control",
6777 *argptr);
6778 pid = -jp->ps[0].pid;
6779 } else
6780 pid = atoi(*argptr);
6781 if (kill(pid, signo) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00006782 error("%s: %m", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006783 } while (*++argptr);
6784
6785 return 0;
6786}
6787
6788static int
6789fgcmd(argc, argv)
6790 int argc;
6791 char **argv;
6792{
6793 struct job *jp;
6794 int pgrp;
6795 int status;
6796
6797 jp = getjob(argv[1]);
6798 if (jp->jobctl == 0)
6799 error("job not created under job control");
6800 pgrp = jp->ps[0].pid;
6801#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006802 ioctl(2, TIOCSPGRP, (char *)&pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006803#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006804 tcsetpgrp(2, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006805#endif
6806 restartjob(jp);
6807 INTOFF;
6808 status = waitforjob(jp);
6809 INTON;
6810 return status;
6811}
6812
6813
6814static int
6815bgcmd(argc, argv)
6816 int argc;
6817 char **argv;
6818{
6819 struct job *jp;
6820
6821 do {
6822 jp = getjob(*++argv);
6823 if (jp->jobctl == 0)
6824 error("job not created under job control");
6825 restartjob(jp);
6826 } while (--argc > 1);
6827 return 0;
6828}
6829
6830
6831static void
6832restartjob(jp)
6833 struct job *jp;
6834{
6835 struct procstat *ps;
6836 int i;
6837
6838 if (jp->state == JOBDONE)
6839 return;
6840 INTOFF;
6841 killpg(jp->ps[0].pid, SIGCONT);
6842 for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
6843 if (WIFSTOPPED(ps->status)) {
6844 ps->status = -1;
6845 jp->state = 0;
6846 }
6847 }
6848 INTON;
6849}
6850#endif
6851
Eric Andersen2870d962001-07-02 17:27:21 +00006852static void showjobs(int change);
6853
Eric Andersencb57d552001-06-28 07:25:16 +00006854
6855static int
6856jobscmd(argc, argv)
6857 int argc;
6858 char **argv;
6859{
6860 showjobs(0);
6861 return 0;
6862}
6863
6864
6865/*
6866 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6867 * statuses have changed since the last call to showjobs.
6868 *
6869 * If the shell is interrupted in the process of creating a job, the
6870 * result may be a job structure containing zero processes. Such structures
6871 * will be freed here.
6872 */
6873
6874static void
6875showjobs(change)
6876 int change;
6877{
6878 int jobno;
6879 int procno;
6880 int i;
6881 struct job *jp;
6882 struct procstat *ps;
6883 int col;
6884 char s[64];
6885
6886 TRACE(("showjobs(%d) called\n", change));
6887 while (dowait(0, (struct job *)NULL) > 0);
6888 for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
6889 if (! jp->used)
6890 continue;
6891 if (jp->nprocs == 0) {
6892 freejob(jp);
6893 continue;
6894 }
6895 if (change && ! jp->changed)
6896 continue;
6897 procno = jp->nprocs;
Eric Andersen2870d962001-07-02 17:27:21 +00006898 for (ps = jp->ps ; ; ps++) { /* for each process */
Eric Andersencb57d552001-06-28 07:25:16 +00006899 if (ps == jp->ps)
Eric Andersen3102ac42001-07-06 04:26:23 +00006900 snprintf(s, 64, "[%d] %ld ", jobno,
Eric Andersencb57d552001-06-28 07:25:16 +00006901 (long)ps->pid);
6902 else
Eric Andersen3102ac42001-07-06 04:26:23 +00006903 snprintf(s, 64, " %ld ",
Eric Andersencb57d552001-06-28 07:25:16 +00006904 (long)ps->pid);
6905 out1str(s);
6906 col = strlen(s);
6907 s[0] = '\0';
6908 if (ps->status == -1) {
6909 /* don't print anything */
6910 } else if (WIFEXITED(ps->status)) {
Eric Andersen3102ac42001-07-06 04:26:23 +00006911 snprintf(s, 64, "Exit %d",
Eric Andersencb57d552001-06-28 07:25:16 +00006912 WEXITSTATUS(ps->status));
6913 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00006914#ifdef JOBS
6915 if (WIFSTOPPED(ps->status))
Eric Andersencb57d552001-06-28 07:25:16 +00006916 i = WSTOPSIG(ps->status);
6917 else /* WIFSIGNALED(ps->status) */
6918#endif
6919 i = WTERMSIG(ps->status);
6920 if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F])
Eric Andersen2870d962001-07-02 17:27:21 +00006921 strcpy(s, sys_siglist[i & 0x7F]);
Eric Andersencb57d552001-06-28 07:25:16 +00006922 else
Eric Andersen3102ac42001-07-06 04:26:23 +00006923 snprintf(s, 64, "Signal %d", i & 0x7F);
Eric Andersencb57d552001-06-28 07:25:16 +00006924 if (WCOREDUMP(ps->status))
6925 strcat(s, " (core dumped)");
6926 }
6927 out1str(s);
6928 col += strlen(s);
6929 out1fmt(
6930 "%*c%s\n", 30 - col >= 0 ? 30 - col : 0, ' ',
6931 ps->cmd
6932 );
6933 if (--procno <= 0)
6934 break;
6935 }
6936 jp->changed = 0;
6937 if (jp->state == JOBDONE) {
6938 freejob(jp);
6939 }
6940 }
6941}
6942
6943
6944/*
6945 * Mark a job structure as unused.
6946 */
6947
6948static void
6949freejob(jp)
6950 struct job *jp;
6951 {
6952 struct procstat *ps;
6953 int i;
6954
6955 INTOFF;
6956 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
6957 if (ps->cmd != nullstr)
6958 ckfree(ps->cmd);
6959 }
6960 if (jp->ps != &jp->ps0)
6961 ckfree(jp->ps);
6962 jp->used = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00006963#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006964 if (curjob == jp - jobtab + 1)
6965 curjob = 0;
6966#endif
6967 INTON;
6968}
6969
6970
6971
6972static int
6973waitcmd(argc, argv)
6974 int argc;
6975 char **argv;
6976{
6977 struct job *job;
6978 int status, retval;
6979 struct job *jp;
6980
6981 if (--argc > 0) {
6982start:
6983 job = getjob(*++argv);
6984 } else {
6985 job = NULL;
6986 }
Eric Andersen2870d962001-07-02 17:27:21 +00006987 for (;;) { /* loop until process terminated or stopped */
Eric Andersencb57d552001-06-28 07:25:16 +00006988 if (job != NULL) {
6989 if (job->state) {
6990 status = job->ps[job->nprocs - 1].status;
6991 if (! iflag)
6992 freejob(job);
6993 if (--argc) {
6994 goto start;
6995 }
6996 if (WIFEXITED(status))
6997 retval = WEXITSTATUS(status);
Eric Andersen2870d962001-07-02 17:27:21 +00006998#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006999 else if (WIFSTOPPED(status))
7000 retval = WSTOPSIG(status) + 128;
7001#endif
7002 else {
7003 /* XXX: limits number of signals */
7004 retval = WTERMSIG(status) + 128;
7005 }
7006 return retval;
7007 }
7008 } else {
7009 for (jp = jobtab ; ; jp++) {
Eric Andersen2870d962001-07-02 17:27:21 +00007010 if (jp >= jobtab + njobs) { /* no running procs */
Eric Andersencb57d552001-06-28 07:25:16 +00007011 return 0;
7012 }
7013 if (jp->used && jp->state == 0)
7014 break;
7015 }
7016 }
7017 if (dowait(2, 0) < 0 && errno == EINTR) {
7018 return 129;
7019 }
7020 }
7021}
7022
7023
7024
7025/*
7026 * Convert a job name to a job structure.
7027 */
7028
7029static struct job *
Eric Andersen2870d962001-07-02 17:27:21 +00007030getjob(const char *name)
7031{
Eric Andersencb57d552001-06-28 07:25:16 +00007032 int jobno;
7033 struct job *jp;
7034 int pid;
7035 int i;
7036
7037 if (name == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00007038#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007039currentjob:
7040 if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0)
7041 error("No current job");
7042 return &jobtab[jobno - 1];
7043#else
7044 error("No current job");
7045#endif
7046 } else if (name[0] == '%') {
7047 if (is_digit(name[1])) {
7048 jobno = number(name + 1);
7049 if (jobno > 0 && jobno <= njobs
7050 && jobtab[jobno - 1].used != 0)
7051 return &jobtab[jobno - 1];
Eric Andersen2870d962001-07-02 17:27:21 +00007052#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007053 } else if (name[1] == '%' && name[2] == '\0') {
7054 goto currentjob;
7055#endif
7056 } else {
7057 struct job *found = NULL;
7058 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
7059 if (jp->used && jp->nprocs > 0
7060 && prefix(name + 1, jp->ps[0].cmd)) {
7061 if (found)
7062 error("%s: ambiguous", name);
7063 found = jp;
7064 }
7065 }
7066 if (found)
7067 return found;
7068 }
Eric Andersen2870d962001-07-02 17:27:21 +00007069 } else if (is_number(name, &pid)) {
Eric Andersencb57d552001-06-28 07:25:16 +00007070 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
7071 if (jp->used && jp->nprocs > 0
7072 && jp->ps[jp->nprocs - 1].pid == pid)
7073 return jp;
7074 }
7075 }
7076 error("No such job: %s", name);
7077 /* NOTREACHED */
7078}
7079
7080
7081
7082/*
7083 * Return a new job structure,
7084 */
7085
Eric Andersen2870d962001-07-02 17:27:21 +00007086static struct job *
Eric Andersencb57d552001-06-28 07:25:16 +00007087makejob(node, nprocs)
7088 union node *node;
7089 int nprocs;
7090{
7091 int i;
7092 struct job *jp;
7093
7094 for (i = njobs, jp = jobtab ; ; jp++) {
7095 if (--i < 0) {
7096 INTOFF;
7097 if (njobs == 0) {
7098 jobtab = ckmalloc(4 * sizeof jobtab[0]);
7099 } else {
7100 jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
7101 memcpy(jp, jobtab, njobs * sizeof jp[0]);
7102 /* Relocate `ps' pointers */
7103 for (i = 0; i < njobs; i++)
7104 if (jp[i].ps == &jobtab[i].ps0)
7105 jp[i].ps = &jp[i].ps0;
7106 ckfree(jobtab);
7107 jobtab = jp;
7108 }
7109 jp = jobtab + njobs;
7110 for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0);
7111 INTON;
7112 break;
7113 }
7114 if (jp->used == 0)
7115 break;
7116 }
7117 INTOFF;
7118 jp->state = 0;
7119 jp->used = 1;
7120 jp->changed = 0;
7121 jp->nprocs = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00007122#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007123 jp->jobctl = jobctl;
7124#endif
7125 if (nprocs > 1) {
7126 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
7127 } else {
7128 jp->ps = &jp->ps0;
7129 }
7130 INTON;
7131 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
7132 jp - jobtab + 1));
7133 return jp;
7134}
7135
7136
7137/*
7138 * Fork of a subshell. If we are doing job control, give the subshell its
7139 * own process group. Jp is a job structure that the job is to be added to.
7140 * N is the command that will be evaluated by the child. Both jp and n may
7141 * be NULL. The mode parameter can be one of the following:
Eric Andersen2870d962001-07-02 17:27:21 +00007142 * FORK_FG - Fork off a foreground process.
7143 * FORK_BG - Fork off a background process.
7144 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
7145 * process group even if job control is on.
Eric Andersencb57d552001-06-28 07:25:16 +00007146 *
7147 * When job control is turned off, background processes have their standard
7148 * input redirected to /dev/null (except for the second and later processes
7149 * in a pipeline).
7150 */
7151
Eric Andersen2870d962001-07-02 17:27:21 +00007152
7153
Eric Andersencb57d552001-06-28 07:25:16 +00007154static int
Eric Andersen2870d962001-07-02 17:27:21 +00007155forkshell(struct job *jp, union node *n, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00007156{
7157 int pid;
7158 int pgrp;
7159 const char *devnull = _PATH_DEVNULL;
7160 const char *nullerr = "Can't open %s";
7161
7162 TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long)n,
7163 mode));
7164 INTOFF;
7165 pid = fork();
7166 if (pid == -1) {
7167 TRACE(("Fork failed, errno=%d\n", errno));
7168 INTON;
7169 error("Cannot fork");
7170 }
7171 if (pid == 0) {
7172 struct job *p;
7173 int wasroot;
7174 int i;
7175
7176 TRACE(("Child shell %d\n", getpid()));
7177 wasroot = rootshell;
7178 rootshell = 0;
7179 closescript();
7180 INTON;
7181 clear_traps();
Eric Andersen2870d962001-07-02 17:27:21 +00007182#ifdef JOBS
7183 jobctl = 0; /* do job control only in root shell */
Eric Andersencb57d552001-06-28 07:25:16 +00007184 if (wasroot && mode != FORK_NOJOB && mflag) {
7185 if (jp == NULL || jp->nprocs == 0)
7186 pgrp = getpid();
7187 else
7188 pgrp = jp->ps[0].pid;
7189 setpgid(0, pgrp);
7190 if (mode == FORK_FG) {
7191 /*** this causes superfluous TIOCSPGRPS ***/
7192#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00007193 if (ioctl(2, TIOCSPGRP, (char *)&pgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007194 error("TIOCSPGRP failed, errno=%d", errno);
7195#else
Eric Andersen3102ac42001-07-06 04:26:23 +00007196 if (tcsetpgrp(2, pgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007197 error("tcsetpgrp failed, errno=%d", errno);
7198#endif
7199 }
7200 setsignal(SIGTSTP);
7201 setsignal(SIGTTOU);
7202 } else if (mode == FORK_BG) {
7203 ignoresig(SIGINT);
7204 ignoresig(SIGQUIT);
7205 if ((jp == NULL || jp->nprocs == 0) &&
7206 ! fd0_redirected_p ()) {
7207 close(0);
7208 if (open(devnull, O_RDONLY) != 0)
7209 error(nullerr, devnull);
7210 }
7211 }
7212#else
7213 if (mode == FORK_BG) {
7214 ignoresig(SIGINT);
7215 ignoresig(SIGQUIT);
7216 if ((jp == NULL || jp->nprocs == 0) &&
7217 ! fd0_redirected_p ()) {
7218 close(0);
7219 if (open(devnull, O_RDONLY) != 0)
7220 error(nullerr, devnull);
7221 }
7222 }
7223#endif
7224 for (i = njobs, p = jobtab ; --i >= 0 ; p++)
7225 if (p->used)
7226 freejob(p);
7227 if (wasroot && iflag) {
7228 setsignal(SIGINT);
7229 setsignal(SIGQUIT);
7230 setsignal(SIGTERM);
7231 }
7232 return pid;
7233 }
7234 if (rootshell && mode != FORK_NOJOB && mflag) {
7235 if (jp == NULL || jp->nprocs == 0)
7236 pgrp = pid;
7237 else
7238 pgrp = jp->ps[0].pid;
7239 setpgid(pid, pgrp);
7240 }
7241 if (mode == FORK_BG)
Eric Andersen2870d962001-07-02 17:27:21 +00007242 backgndpid = pid; /* set $! */
Eric Andersencb57d552001-06-28 07:25:16 +00007243 if (jp) {
7244 struct procstat *ps = &jp->ps[jp->nprocs++];
7245 ps->pid = pid;
7246 ps->status = -1;
7247 ps->cmd = nullstr;
7248 if (iflag && rootshell && n)
7249 ps->cmd = commandtext(n);
7250 }
7251 INTON;
7252 TRACE(("In parent shell: child = %d\n", pid));
7253 return pid;
7254}
7255
7256
7257
7258/*
7259 * Wait for job to finish.
7260 *
7261 * Under job control we have the problem that while a child process is
7262 * running interrupts generated by the user are sent to the child but not
7263 * to the shell. This means that an infinite loop started by an inter-
7264 * active user may be hard to kill. With job control turned off, an
7265 * interactive user may place an interactive program inside a loop. If
7266 * the interactive program catches interrupts, the user doesn't want
7267 * these interrupts to also abort the loop. The approach we take here
7268 * is to have the shell ignore interrupt signals while waiting for a
7269 * forground process to terminate, and then send itself an interrupt
7270 * signal if the child process was terminated by an interrupt signal.
7271 * Unfortunately, some programs want to do a bit of cleanup and then
7272 * exit on interrupt; unless these processes terminate themselves by
7273 * sending a signal to themselves (instead of calling exit) they will
7274 * confuse this approach.
7275 */
7276
7277static int
7278waitforjob(jp)
7279 struct job *jp;
7280 {
Eric Andersen2870d962001-07-02 17:27:21 +00007281#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007282 int mypgrp = getpgrp();
7283#endif
7284 int status;
7285 int st;
7286 struct sigaction act, oact;
7287
7288 INTOFF;
7289 intreceived = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00007290#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007291 if (!jobctl) {
7292#else
7293 if (!iflag) {
7294#endif
7295 sigaction(SIGINT, 0, &act);
7296 act.sa_handler = waitonint;
7297 sigaction(SIGINT, &act, &oact);
7298 }
7299 TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
7300 while (jp->state == 0) {
7301 dowait(1, jp);
7302 }
Eric Andersen2870d962001-07-02 17:27:21 +00007303#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007304 if (!jobctl) {
7305#else
7306 if (!iflag) {
7307#endif
7308 sigaction(SIGINT, &oact, 0);
7309 if (intreceived && trap[SIGINT]) kill(getpid(), SIGINT);
7310 }
Eric Andersen2870d962001-07-02 17:27:21 +00007311#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007312 if (jp->jobctl) {
7313#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00007314 if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007315 error("TIOCSPGRP failed, errno=%d\n", errno);
7316#else
Eric Andersen3102ac42001-07-06 04:26:23 +00007317 if (tcsetpgrp(2, mypgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007318 error("tcsetpgrp failed, errno=%d\n", errno);
7319#endif
7320 }
7321 if (jp->state == JOBSTOPPED)
7322 curjob = jp - jobtab + 1;
7323#endif
7324 status = jp->ps[jp->nprocs - 1].status;
7325 /* convert to 8 bits */
7326 if (WIFEXITED(status))
7327 st = WEXITSTATUS(status);
Eric Andersen2870d962001-07-02 17:27:21 +00007328#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007329 else if (WIFSTOPPED(status))
7330 st = WSTOPSIG(status) + 128;
7331#endif
7332 else
7333 st = WTERMSIG(status) + 128;
Eric Andersen2870d962001-07-02 17:27:21 +00007334#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007335 if (jp->jobctl) {
7336 /*
7337 * This is truly gross.
7338 * If we're doing job control, then we did a TIOCSPGRP which
7339 * caused us (the shell) to no longer be in the controlling
7340 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7341 * intuit from the subprocess exit status whether a SIGINT
7342 * occured, and if so interrupt ourselves. Yuck. - mycroft
7343 */
7344 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
7345 raise(SIGINT);
7346 }
Eric Andersen2870d962001-07-02 17:27:21 +00007347 if (jp->state == JOBDONE)
7348
Eric Andersencb57d552001-06-28 07:25:16 +00007349#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007350 freejob(jp);
7351 INTON;
7352 return st;
7353}
7354
7355
7356
7357/*
7358 * Wait for a process to terminate.
7359 */
7360
7361static int
7362dowait(block, job)
7363 int block;
7364 struct job *job;
7365{
7366 int pid;
7367 int status;
7368 struct procstat *sp;
7369 struct job *jp;
7370 struct job *thisjob;
7371 int done;
7372 int stopped;
7373 int core;
7374 int sig;
7375
7376 TRACE(("dowait(%d) called\n", block));
7377 do {
7378 pid = waitproc(block, &status);
7379 TRACE(("wait returns %d, status=%d\n", pid, status));
7380 } while (!(block & 2) && pid == -1 && errno == EINTR);
7381 if (pid <= 0)
7382 return pid;
7383 INTOFF;
7384 thisjob = NULL;
7385 for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
7386 if (jp->used) {
7387 done = 1;
7388 stopped = 1;
7389 for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
7390 if (sp->pid == -1)
7391 continue;
7392 if (sp->pid == pid) {
7393 TRACE(("Changing status of proc %d from 0x%x to 0x%x\n", pid, sp->status, status));
7394 sp->status = status;
7395 thisjob = jp;
7396 }
7397 if (sp->status == -1)
7398 stopped = 0;
7399 else if (WIFSTOPPED(sp->status))
7400 done = 0;
7401 }
Eric Andersen2870d962001-07-02 17:27:21 +00007402 if (stopped) { /* stopped or done */
Eric Andersencb57d552001-06-28 07:25:16 +00007403 int state = done? JOBDONE : JOBSTOPPED;
7404 if (jp->state != state) {
7405 TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
7406 jp->state = state;
Eric Andersen2870d962001-07-02 17:27:21 +00007407#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007408 if (done && curjob == jp - jobtab + 1)
Eric Andersen2870d962001-07-02 17:27:21 +00007409 curjob = 0; /* no current job */
Eric Andersencb57d552001-06-28 07:25:16 +00007410#endif
7411 }
7412 }
7413 }
7414 }
7415 INTON;
7416 if (! rootshell || ! iflag || (job && thisjob == job)) {
7417 core = WCOREDUMP(status);
Eric Andersen2870d962001-07-02 17:27:21 +00007418#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007419 if (WIFSTOPPED(status)) sig = WSTOPSIG(status);
7420 else
7421#endif
7422 if (WIFEXITED(status)) sig = 0;
7423 else sig = WTERMSIG(status);
7424
7425 if (sig != 0 && sig != SIGINT && sig != SIGPIPE) {
7426 if (thisjob != job)
Eric Andersen3102ac42001-07-06 04:26:23 +00007427 out2fmt("%d: ", pid);
Eric Andersen2870d962001-07-02 17:27:21 +00007428#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007429 if (sig == SIGTSTP && rootshell && iflag)
Eric Andersen3102ac42001-07-06 04:26:23 +00007430 out2fmt("%%%ld ",
Eric Andersencb57d552001-06-28 07:25:16 +00007431 (long)(job - jobtab + 1));
7432#endif
7433 if (sig < NSIG && sys_siglist[sig])
7434 out2str(sys_siglist[sig]);
7435 else
Eric Andersen3102ac42001-07-06 04:26:23 +00007436 out2fmt("Signal %d", sig);
Eric Andersencb57d552001-06-28 07:25:16 +00007437 if (core)
7438 out2str(" - core dumped");
7439 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00007440 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00007441 TRACE(("Not printing status: status=%d, sig=%d\n",
Eric Andersencb57d552001-06-28 07:25:16 +00007442 status, sig));
7443 }
7444 } else {
7445 TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job));
7446 if (thisjob)
7447 thisjob->changed = 1;
7448 }
7449 return pid;
7450}
7451
7452
7453
7454/*
7455 * Do a wait system call. If job control is compiled in, we accept
7456 * stopped processes. If block is zero, we return a value of zero
7457 * rather than blocking.
7458 *
7459 * System V doesn't have a non-blocking wait system call. It does
7460 * have a SIGCLD signal that is sent to a process when one of it's
7461 * children dies. The obvious way to use SIGCLD would be to install
7462 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7463 * was received, and have waitproc bump another counter when it got
7464 * the status of a process. Waitproc would then know that a wait
7465 * system call would not block if the two counters were different.
7466 * This approach doesn't work because if a process has children that
7467 * have not been waited for, System V will send it a SIGCLD when it
7468 * installs a signal handler for SIGCLD. What this means is that when
7469 * a child exits, the shell will be sent SIGCLD signals continuously
7470 * until is runs out of stack space, unless it does a wait call before
7471 * restoring the signal handler. The code below takes advantage of
7472 * this (mis)feature by installing a signal handler for SIGCLD and
7473 * then checking to see whether it was called. If there are any
7474 * children to be waited for, it will be.
7475 *
Eric Andersencb57d552001-06-28 07:25:16 +00007476 */
7477
Eric Andersencb57d552001-06-28 07:25:16 +00007478static int
7479waitproc(block, status)
7480 int block;
7481 int *status;
7482{
Eric Andersencb57d552001-06-28 07:25:16 +00007483 int flags;
7484
7485 flags = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00007486#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007487 if (jobctl)
7488 flags |= WUNTRACED;
7489#endif
7490 if (block == 0)
7491 flags |= WNOHANG;
7492 return wait3(status, flags, (struct rusage *)NULL);
Eric Andersencb57d552001-06-28 07:25:16 +00007493}
7494
7495/*
7496 * return 1 if there are stopped jobs, otherwise 0
7497 */
Eric Andersencb57d552001-06-28 07:25:16 +00007498static int
Eric Andersen2870d962001-07-02 17:27:21 +00007499stoppedjobs(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007500{
7501 int jobno;
7502 struct job *jp;
7503
7504 if (job_warning)
7505 return (0);
7506 for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
7507 if (jp->used == 0)
7508 continue;
7509 if (jp->state == JOBSTOPPED) {
7510 out2str("You have stopped jobs.\n");
7511 job_warning = 2;
7512 return (1);
7513 }
7514 }
7515
7516 return (0);
7517}
7518
7519/*
7520 * Return a string identifying a command (to be printed by the
7521 * jobs command.
7522 */
7523
7524static char *cmdnextc;
7525static int cmdnleft;
Eric Andersen2870d962001-07-02 17:27:21 +00007526#define MAXCMDTEXT 200
Eric Andersencb57d552001-06-28 07:25:16 +00007527
Eric Andersen2870d962001-07-02 17:27:21 +00007528static void
7529cmdputs(const char *s)
7530{
7531 const char *p;
7532 char *q;
7533 char c;
7534 int subtype = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007535
Eric Andersen2870d962001-07-02 17:27:21 +00007536 if (cmdnleft <= 0)
7537 return;
7538 p = s;
7539 q = cmdnextc;
7540 while ((c = *p++) != '\0') {
7541 if (c == CTLESC)
7542 *q++ = *p++;
7543 else if (c == CTLVAR) {
7544 *q++ = '$';
7545 if (--cmdnleft > 0)
7546 *q++ = '{';
7547 subtype = *p++;
7548 } else if (c == '=' && subtype != 0) {
7549 *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
7550 subtype = 0;
7551 } else if (c == CTLENDVAR) {
7552 *q++ = '}';
7553 } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE)
7554 cmdnleft++; /* ignore it */
7555 else
7556 *q++ = c;
7557 if (--cmdnleft <= 0) {
7558 *q++ = '.';
7559 *q++ = '.';
7560 *q++ = '.';
7561 break;
7562 }
7563 }
7564 cmdnextc = q;
Eric Andersencb57d552001-06-28 07:25:16 +00007565}
7566
7567
7568static void
Eric Andersen2870d962001-07-02 17:27:21 +00007569cmdtxt(const union node *n)
7570{
Eric Andersencb57d552001-06-28 07:25:16 +00007571 union node *np;
7572 struct nodelist *lp;
7573 const char *p;
7574 int i;
7575 char s[2];
7576
7577 if (n == NULL)
7578 return;
7579 switch (n->type) {
7580 case NSEMI:
7581 cmdtxt(n->nbinary.ch1);
7582 cmdputs("; ");
7583 cmdtxt(n->nbinary.ch2);
7584 break;
7585 case NAND:
7586 cmdtxt(n->nbinary.ch1);
7587 cmdputs(" && ");
7588 cmdtxt(n->nbinary.ch2);
7589 break;
7590 case NOR:
7591 cmdtxt(n->nbinary.ch1);
7592 cmdputs(" || ");
7593 cmdtxt(n->nbinary.ch2);
7594 break;
7595 case NPIPE:
7596 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
7597 cmdtxt(lp->n);
7598 if (lp->next)
7599 cmdputs(" | ");
7600 }
7601 break;
7602 case NSUBSHELL:
7603 cmdputs("(");
7604 cmdtxt(n->nredir.n);
7605 cmdputs(")");
7606 break;
7607 case NREDIR:
7608 case NBACKGND:
7609 cmdtxt(n->nredir.n);
7610 break;
7611 case NIF:
7612 cmdputs("if ");
7613 cmdtxt(n->nif.test);
7614 cmdputs("; then ");
7615 cmdtxt(n->nif.ifpart);
7616 cmdputs("...");
7617 break;
7618 case NWHILE:
7619 cmdputs("while ");
7620 goto until;
7621 case NUNTIL:
7622 cmdputs("until ");
7623until:
7624 cmdtxt(n->nbinary.ch1);
7625 cmdputs("; do ");
7626 cmdtxt(n->nbinary.ch2);
7627 cmdputs("; done");
7628 break;
7629 case NFOR:
7630 cmdputs("for ");
7631 cmdputs(n->nfor.var);
7632 cmdputs(" in ...");
7633 break;
7634 case NCASE:
7635 cmdputs("case ");
7636 cmdputs(n->ncase.expr->narg.text);
7637 cmdputs(" in ...");
7638 break;
7639 case NDEFUN:
7640 cmdputs(n->narg.text);
7641 cmdputs("() ...");
7642 break;
7643 case NCMD:
7644 for (np = n->ncmd.args ; np ; np = np->narg.next) {
7645 cmdtxt(np);
7646 if (np->narg.next)
7647 cmdputs(spcstr);
7648 }
7649 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
7650 cmdputs(spcstr);
7651 cmdtxt(np);
7652 }
7653 break;
7654 case NARG:
7655 cmdputs(n->narg.text);
7656 break;
7657 case NTO:
7658 p = ">"; i = 1; goto redir;
7659 case NAPPEND:
7660 p = ">>"; i = 1; goto redir;
7661 case NTOFD:
7662 p = ">&"; i = 1; goto redir;
7663 case NTOOV:
7664 p = ">|"; i = 1; goto redir;
7665 case NFROM:
7666 p = "<"; i = 0; goto redir;
7667 case NFROMFD:
7668 p = "<&"; i = 0; goto redir;
7669 case NFROMTO:
7670 p = "<>"; i = 0; goto redir;
7671redir:
7672 if (n->nfile.fd != i) {
7673 s[0] = n->nfile.fd + '0';
7674 s[1] = '\0';
7675 cmdputs(s);
7676 }
7677 cmdputs(p);
7678 if (n->type == NTOFD || n->type == NFROMFD) {
7679 s[0] = n->ndup.dupfd + '0';
7680 s[1] = '\0';
7681 cmdputs(s);
7682 } else {
7683 cmdtxt(n->nfile.fname);
7684 }
7685 break;
7686 case NHERE:
7687 case NXHERE:
7688 cmdputs("<<...");
7689 break;
7690 default:
7691 cmdputs("???");
7692 break;
7693 }
7694}
7695
7696
Eric Andersen2870d962001-07-02 17:27:21 +00007697static char *
7698commandtext(const union node *n)
7699{
7700 char *name;
Eric Andersencb57d552001-06-28 07:25:16 +00007701
Eric Andersen2870d962001-07-02 17:27:21 +00007702 cmdnextc = name = ckmalloc(MAXCMDTEXT);
7703 cmdnleft = MAXCMDTEXT - 4;
7704 cmdtxt(n);
7705 *cmdnextc = '\0';
7706 return name;
Eric Andersencb57d552001-06-28 07:25:16 +00007707}
7708
Eric Andersen2870d962001-07-02 17:27:21 +00007709
Eric Andersencb57d552001-06-28 07:25:16 +00007710static void waitonint(int sig) {
7711 intreceived = 1;
7712 return;
7713}
Eric Andersencb57d552001-06-28 07:25:16 +00007714/*
7715 * Routines to check for mail. (Perhaps make part of main.c?)
7716 */
7717
7718
7719#define MAXMBOXES 10
7720
7721
Eric Andersen2870d962001-07-02 17:27:21 +00007722static int nmboxes; /* number of mailboxes */
7723static time_t mailtime[MAXMBOXES]; /* times of mailboxes */
Eric Andersencb57d552001-06-28 07:25:16 +00007724
7725
7726
7727/*
7728 * Print appropriate message(s) if mail has arrived. If the argument is
7729 * nozero, then the value of MAIL has changed, so we just update the
7730 * values.
7731 */
7732
7733static void
Eric Andersen2870d962001-07-02 17:27:21 +00007734chkmail(int silent)
Eric Andersencb57d552001-06-28 07:25:16 +00007735{
7736 int i;
7737 const char *mpath;
7738 char *p;
7739 char *q;
7740 struct stackmark smark;
7741 struct stat statb;
7742
7743 if (silent)
7744 nmboxes = 10;
7745 if (nmboxes == 0)
7746 return;
7747 setstackmark(&smark);
7748 mpath = mpathset()? mpathval() : mailval();
7749 for (i = 0 ; i < nmboxes ; i++) {
7750 p = padvance(&mpath, nullstr);
7751 if (p == NULL)
7752 break;
7753 if (*p == '\0')
7754 continue;
7755 for (q = p ; *q ; q++);
7756#ifdef DEBUG
7757 if (q[-1] != '/')
7758 abort();
7759#endif
Eric Andersen2870d962001-07-02 17:27:21 +00007760 q[-1] = '\0'; /* delete trailing '/' */
Eric Andersencb57d552001-06-28 07:25:16 +00007761 if (stat(p, &statb) < 0)
7762 statb.st_size = 0;
7763 if (statb.st_size > mailtime[i] && ! silent) {
Eric Andersen3102ac42001-07-06 04:26:23 +00007764 out2fmt(snlfmt,
7765 pathopt? pathopt : "you have mail");
Eric Andersencb57d552001-06-28 07:25:16 +00007766 }
7767 mailtime[i] = statb.st_size;
Eric Andersencb57d552001-06-28 07:25:16 +00007768 }
7769 nmboxes = i;
7770 popstackmark(&smark);
7771}
Eric Andersencb57d552001-06-28 07:25:16 +00007772
7773#define PROFILE 0
7774
Eric Andersencb57d552001-06-28 07:25:16 +00007775#if PROFILE
Eric Andersen2870d962001-07-02 17:27:21 +00007776static short profile_buf[16384];
Eric Andersencb57d552001-06-28 07:25:16 +00007777extern int etext();
7778#endif
7779
Eric Andersen2870d962001-07-02 17:27:21 +00007780static void read_profile (const char *);
7781static char *find_dot_file (char *);
7782static void cmdloop (int);
7783static void options (int);
7784static void minus_o (char *, int);
7785static void setoption (int, int);
7786static void procargs (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00007787
Eric Andersen2870d962001-07-02 17:27:21 +00007788
Eric Andersencb57d552001-06-28 07:25:16 +00007789/*
7790 * Main routine. We initialize things, parse the arguments, execute
7791 * profiles if we're a login shell, and then call cmdloop to execute
7792 * commands. The setjmp call sets up the location to jump to when an
7793 * exception occurs. When an exception occurs the variable "state"
7794 * is used to figure out how far we had gotten.
7795 */
7796
7797int
7798shell_main(argc, argv)
7799 int argc;
7800 char **argv;
7801{
7802 struct jmploc jmploc;
7803 struct stackmark smark;
7804 volatile int state;
7805 char *shinit;
7806
7807 DOTCMD = find_builtin(".");
7808 BLTINCMD = find_builtin("builtin");
Eric Andersencb57d552001-06-28 07:25:16 +00007809 EXECCMD = find_builtin("exec");
7810 EVALCMD = find_builtin("eval");
7811
Eric Andersen1c039232001-07-07 00:05:55 +00007812#ifndef BB_FEATURE_SH_FANCY_PROMPT
7813 unsetenv("PS1");
7814 unsetenv("PS2");
7815#endif
7816
Eric Andersencb57d552001-06-28 07:25:16 +00007817#if PROFILE
7818 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7819#endif
7820#if defined(linux) || defined(__GNU__)
7821 signal(SIGCHLD, SIG_DFL);
7822#endif
7823 state = 0;
7824 if (setjmp(jmploc.loc)) {
7825 INTOFF;
7826 /*
7827 * When a shell procedure is executed, we raise the
7828 * exception EXSHELLPROC to clean up before executing
7829 * the shell procedure.
7830 */
7831 switch (exception) {
7832 case EXSHELLPROC:
7833 rootpid = getpid();
7834 rootshell = 1;
7835 minusc = NULL;
7836 state = 3;
7837 break;
7838
7839 case EXEXEC:
7840 exitstatus = exerrno;
7841 break;
7842
7843 case EXERROR:
7844 exitstatus = 2;
7845 break;
7846
7847 default:
7848 break;
7849 }
7850
7851 if (exception != EXSHELLPROC) {
7852 if (state == 0 || iflag == 0 || ! rootshell)
7853 exitshell(exitstatus);
7854 }
7855 reset();
Eric Andersen2870d962001-07-02 17:27:21 +00007856 if (exception == EXINT) {
Eric Andersencb57d552001-06-28 07:25:16 +00007857 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00007858 }
7859 popstackmark(&smark);
Eric Andersen2870d962001-07-02 17:27:21 +00007860 FORCEINTON; /* enable interrupts */
Eric Andersencb57d552001-06-28 07:25:16 +00007861 if (state == 1)
7862 goto state1;
7863 else if (state == 2)
7864 goto state2;
7865 else if (state == 3)
7866 goto state3;
7867 else
7868 goto state4;
7869 }
7870 handler = &jmploc;
7871#ifdef DEBUG
7872 opentrace();
7873 trputs("Shell args: "); trargs(argv);
7874#endif
7875 rootpid = getpid();
7876 rootshell = 1;
7877 init();
7878 setstackmark(&smark);
7879 procargs(argc, argv);
7880 if (argv[0] && argv[0][0] == '-') {
7881 state = 1;
7882 read_profile("/etc/profile");
7883state1:
7884 state = 2;
7885 read_profile(".profile");
7886 }
7887state2:
7888 state = 3;
7889#ifndef linux
7890 if (getuid() == geteuid() && getgid() == getegid()) {
7891#endif
7892 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
7893 state = 3;
7894 read_profile(shinit);
7895 }
7896#ifndef linux
7897 }
7898#endif
7899state3:
7900 state = 4;
7901 if (sflag == 0 || minusc) {
7902 static int sigs[] = {
Eric Andersen2870d962001-07-02 17:27:21 +00007903 SIGINT, SIGQUIT, SIGHUP,
Eric Andersencb57d552001-06-28 07:25:16 +00007904#ifdef SIGTSTP
7905 SIGTSTP,
7906#endif
7907 SIGPIPE
7908 };
7909#define SIGSSIZE (sizeof(sigs)/sizeof(sigs[0]))
7910 int i;
7911
7912 for (i = 0; i < SIGSSIZE; i++)
7913 setsignal(sigs[i]);
7914 }
7915
7916 if (minusc)
7917 evalstring(minusc, 0);
7918
7919 if (sflag || minusc == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00007920state4: /* XXX ??? - why isn't this before the "if" statement */
Eric Andersencb57d552001-06-28 07:25:16 +00007921 cmdloop(1);
7922 }
7923#if PROFILE
7924 monitor(0);
7925#endif
7926 exitshell(exitstatus);
7927 /* NOTREACHED */
7928}
7929
7930
7931/*
7932 * Read and execute commands. "Top" is nonzero for the top level command
7933 * loop; it turns on prompting if the shell is interactive.
7934 */
7935
7936static void
Eric Andersen2870d962001-07-02 17:27:21 +00007937cmdloop(int top)
Eric Andersencb57d552001-06-28 07:25:16 +00007938{
7939 union node *n;
7940 struct stackmark smark;
7941 int inter;
7942 int numeof = 0;
7943
7944 TRACE(("cmdloop(%d) called\n", top));
7945 setstackmark(&smark);
7946 for (;;) {
7947 if (pendingsigs)
7948 dotrap();
7949 inter = 0;
7950 if (iflag && top) {
7951 inter++;
7952 showjobs(1);
7953 chkmail(0);
Eric Andersen3102ac42001-07-06 04:26:23 +00007954 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00007955 }
7956 n = parsecmd(inter);
7957 /* showtree(n); DEBUG */
7958 if (n == NEOF) {
7959 if (!top || numeof >= 50)
7960 break;
7961 if (!stoppedjobs()) {
7962 if (!Iflag)
7963 break;
7964 out2str("\nUse \"exit\" to leave shell.\n");
7965 }
7966 numeof++;
7967 } else if (n != NULL && nflag == 0) {
7968 job_warning = (job_warning == 2) ? 1 : 0;
7969 numeof = 0;
7970 evaltree(n, 0);
7971 }
7972 popstackmark(&smark);
7973 setstackmark(&smark);
7974 if (evalskip == SKIPFILE) {
7975 evalskip = 0;
7976 break;
7977 }
7978 }
7979 popstackmark(&smark);
7980}
7981
7982
7983
7984/*
7985 * Read /etc/profile or .profile. Return on error.
7986 */
7987
7988static void
7989read_profile(name)
7990 const char *name;
7991{
7992 int fd;
7993 int xflag_set = 0;
7994 int vflag_set = 0;
7995
7996 INTOFF;
7997 if ((fd = open(name, O_RDONLY)) >= 0)
7998 setinputfd(fd, 1);
7999 INTON;
8000 if (fd < 0)
8001 return;
8002 /* -q turns off -x and -v just when executing init files */
8003 if (qflag) {
8004 if (xflag)
8005 xflag = 0, xflag_set = 1;
8006 if (vflag)
8007 vflag = 0, vflag_set = 1;
8008 }
8009 cmdloop(0);
8010 if (qflag) {
8011 if (xflag_set)
8012 xflag = 1;
8013 if (vflag_set)
8014 vflag = 1;
8015 }
8016 popfile();
8017}
8018
8019
8020
8021/*
8022 * Read a file containing shell functions.
8023 */
8024
8025static void
Eric Andersen2870d962001-07-02 17:27:21 +00008026readcmdfile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008027{
8028 int fd;
8029
8030 INTOFF;
8031 if ((fd = open(name, O_RDONLY)) >= 0)
8032 setinputfd(fd, 1);
8033 else
8034 error("Can't open %s", name);
8035 INTON;
8036 cmdloop(0);
8037 popfile();
8038}
8039
8040
8041
8042/*
8043 * Take commands from a file. To be compatable we should do a path
8044 * search for the file, which is necessary to find sub-commands.
8045 */
8046
8047
8048static char *
8049find_dot_file(mybasename)
8050 char *mybasename;
8051{
8052 char *fullname;
8053 const char *path = pathval();
8054 struct stat statb;
8055
8056 /* don't try this for absolute or relative paths */
8057 if (strchr(mybasename, '/'))
8058 return mybasename;
8059
8060 while ((fullname = padvance(&path, mybasename)) != NULL) {
8061 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
8062 /*
8063 * Don't bother freeing here, since it will
8064 * be freed by the caller.
8065 */
8066 return fullname;
8067 }
8068 stunalloc(fullname);
8069 }
8070
8071 /* not found in the PATH */
8072 error("%s: not found", mybasename);
8073 /* NOTREACHED */
8074}
8075
8076static int
8077dotcmd(argc, argv)
8078 int argc;
8079 char **argv;
8080{
8081 struct strlist *sp;
8082 exitstatus = 0;
8083
8084 for (sp = cmdenviron; sp ; sp = sp->next)
8085 setvareq(savestr(sp->text), VSTRFIXED|VTEXTFIXED);
8086
Eric Andersen2870d962001-07-02 17:27:21 +00008087 if (argc >= 2) { /* That's what SVR2 does */
Eric Andersencb57d552001-06-28 07:25:16 +00008088 char *fullname;
8089 struct stackmark smark;
8090
8091 setstackmark(&smark);
8092 fullname = find_dot_file(argv[1]);
8093 setinputfile(fullname, 1);
8094 commandname = fullname;
8095 cmdloop(0);
8096 popfile();
8097 popstackmark(&smark);
8098 }
8099 return exitstatus;
8100}
8101
8102
8103static int
8104exitcmd(argc, argv)
8105 int argc;
8106 char **argv;
8107{
8108 if (stoppedjobs())
8109 return 0;
8110 if (argc > 1)
8111 exitstatus = number(argv[1]);
8112 else
8113 exitstatus = oexitstatus;
8114 exitshell(exitstatus);
8115 /* NOTREACHED */
8116}
Eric Andersen2870d962001-07-02 17:27:21 +00008117static pointer
8118stalloc(int nbytes)
Eric Andersencb57d552001-06-28 07:25:16 +00008119{
8120 char *p;
8121
8122 nbytes = ALIGN(nbytes);
8123 if (nbytes > stacknleft) {
8124 int blocksize;
8125 struct stack_block *sp;
8126
8127 blocksize = nbytes;
8128 if (blocksize < MINSIZE)
8129 blocksize = MINSIZE;
8130 INTOFF;
8131 sp = ckmalloc(sizeof(struct stack_block) - MINSIZE + blocksize);
8132 sp->prev = stackp;
8133 stacknxt = sp->space;
8134 stacknleft = blocksize;
8135 stackp = sp;
8136 INTON;
8137 }
8138 p = stacknxt;
8139 stacknxt += nbytes;
8140 stacknleft -= nbytes;
8141 return p;
8142}
8143
8144
8145static void
Eric Andersen2870d962001-07-02 17:27:21 +00008146stunalloc(pointer p)
8147{
Eric Andersencb57d552001-06-28 07:25:16 +00008148#ifdef DEBUG
Eric Andersen2870d962001-07-02 17:27:21 +00008149 if (p == NULL) { /*DEBUG */
Eric Andersencb57d552001-06-28 07:25:16 +00008150 write(2, "stunalloc\n", 10);
8151 abort();
8152 }
8153#endif
8154 if (!(stacknxt >= (char *)p && (char *)p >= stackp->space)) {
8155 p = stackp->space;
8156 }
8157 stacknleft += stacknxt - (char *)p;
8158 stacknxt = p;
8159}
8160
8161
Eric Andersencb57d552001-06-28 07:25:16 +00008162static void
Eric Andersen2870d962001-07-02 17:27:21 +00008163setstackmark(struct stackmark *mark)
8164{
Eric Andersencb57d552001-06-28 07:25:16 +00008165 mark->stackp = stackp;
8166 mark->stacknxt = stacknxt;
8167 mark->stacknleft = stacknleft;
8168 mark->marknext = markp;
8169 markp = mark;
8170}
8171
8172
8173static void
Eric Andersen2870d962001-07-02 17:27:21 +00008174popstackmark(struct stackmark *mark)
8175{
Eric Andersencb57d552001-06-28 07:25:16 +00008176 struct stack_block *sp;
8177
8178 INTOFF;
8179 markp = mark->marknext;
8180 while (stackp != mark->stackp) {
8181 sp = stackp;
8182 stackp = sp->prev;
8183 ckfree(sp);
8184 }
8185 stacknxt = mark->stacknxt;
8186 stacknleft = mark->stacknleft;
8187 INTON;
8188}
8189
8190
8191/*
8192 * When the parser reads in a string, it wants to stick the string on the
8193 * stack and only adjust the stack pointer when it knows how big the
8194 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8195 * of space on top of the stack and stackblocklen returns the length of
8196 * this block. Growstackblock will grow this space by at least one byte,
8197 * possibly moving it (like realloc). Grabstackblock actually allocates the
8198 * part of the block that has been used.
8199 */
8200
8201static void
Eric Andersen2870d962001-07-02 17:27:21 +00008202growstackblock(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00008203 char *p;
8204 int newlen = ALIGN(stacknleft * 2 + 100);
8205 char *oldspace = stacknxt;
8206 int oldlen = stacknleft;
8207 struct stack_block *sp;
8208 struct stack_block *oldstackp;
8209
8210 if (stacknxt == stackp->space && stackp != &stackbase) {
8211 INTOFF;
8212 oldstackp = stackp;
8213 sp = stackp;
8214 stackp = sp->prev;
8215 sp = ckrealloc((pointer)sp, sizeof(struct stack_block) - MINSIZE + newlen);
8216 sp->prev = stackp;
8217 stackp = sp;
8218 stacknxt = sp->space;
8219 stacknleft = newlen;
8220 {
8221 /* Stack marks pointing to the start of the old block
Eric Andersen2870d962001-07-02 17:27:21 +00008222 * must be relocated to point to the new block
Eric Andersencb57d552001-06-28 07:25:16 +00008223 */
8224 struct stackmark *xmark;
8225 xmark = markp;
8226 while (xmark != NULL && xmark->stackp == oldstackp) {
8227 xmark->stackp = stackp;
8228 xmark->stacknxt = stacknxt;
8229 xmark->stacknleft = stacknleft;
8230 xmark = xmark->marknext;
8231 }
8232 }
8233 INTON;
8234 } else {
8235 p = stalloc(newlen);
8236 memcpy(p, oldspace, oldlen);
Eric Andersen2870d962001-07-02 17:27:21 +00008237 stacknxt = p; /* free the space */
8238 stacknleft += newlen; /* we just allocated */
Eric Andersencb57d552001-06-28 07:25:16 +00008239 }
8240}
8241
8242
8243
Eric Andersen2870d962001-07-02 17:27:21 +00008244static inline void
8245grabstackblock(int len)
Eric Andersencb57d552001-06-28 07:25:16 +00008246{
8247 len = ALIGN(len);
8248 stacknxt += len;
8249 stacknleft -= len;
8250}
8251
8252
8253
8254/*
8255 * The following routines are somewhat easier to use that the above.
8256 * The user declares a variable of type STACKSTR, which may be declared
8257 * to be a register. The macro STARTSTACKSTR initializes things. Then
8258 * the user uses the macro STPUTC to add characters to the string. In
8259 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8260 * grown as necessary. When the user is done, she can just leave the
8261 * string there and refer to it using stackblock(). Or she can allocate
8262 * the space for it using grabstackstr(). If it is necessary to allow
8263 * someone else to use the stack temporarily and then continue to grow
8264 * the string, the user should use grabstack to allocate the space, and
8265 * then call ungrabstr(p) to return to the previous mode of operation.
8266 *
8267 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8268 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8269 * is space for at least one character.
8270 */
8271
8272
8273static char *
Eric Andersen2870d962001-07-02 17:27:21 +00008274growstackstr(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00008275 int len = stackblocksize();
8276 if (herefd >= 0 && len >= 1024) {
8277 xwrite(herefd, stackblock(), len);
8278 sstrnleft = len - 1;
8279 return stackblock();
8280 }
8281 growstackblock();
8282 sstrnleft = stackblocksize() - len - 1;
8283 return stackblock() + len;
8284}
8285
8286
8287/*
8288 * Called from CHECKSTRSPACE.
8289 */
8290
8291static char *
8292makestrspace(size_t newlen) {
8293 int len = stackblocksize() - sstrnleft;
8294 do {
8295 growstackblock();
8296 sstrnleft = stackblocksize() - len;
8297 } while (sstrnleft < newlen);
8298 return stackblock() + len;
8299}
8300
8301
8302
8303static void
Eric Andersen2870d962001-07-02 17:27:21 +00008304ungrabstackstr(char *s, char *p)
8305{
Eric Andersencb57d552001-06-28 07:25:16 +00008306 stacknleft += stacknxt - s;
8307 stacknxt = s;
8308 sstrnleft = stacknleft - (p - s);
8309}
Eric Andersencb57d552001-06-28 07:25:16 +00008310/*
8311 * Miscelaneous builtins.
8312 */
8313
8314
8315#undef rflag
8316
8317#ifdef __GLIBC__
Eric Andersen2870d962001-07-02 17:27:21 +00008318static mode_t getmode(const void *, mode_t);
Eric Andersencb57d552001-06-28 07:25:16 +00008319static void *setmode(const char *);
8320
8321#if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
8322typedef enum __rlimit_resource rlim_t;
8323#endif
8324#endif
8325
8326
8327
8328/*
8329 * The read builtin. The -e option causes backslashes to escape the
8330 * following character.
8331 *
8332 * This uses unbuffered input, which may be avoidable in some cases.
8333 */
8334
8335static int
8336readcmd(argc, argv)
8337 int argc;
8338 char **argv;
8339{
8340 char **ap;
8341 int backslash;
8342 char c;
8343 int rflag;
8344 char *prompt;
8345 const char *ifs;
8346 char *p;
8347 int startword;
8348 int status;
8349 int i;
8350
8351 rflag = 0;
8352 prompt = NULL;
8353 while ((i = nextopt("p:r")) != '\0') {
8354 if (i == 'p')
8355 prompt = optionarg;
8356 else
8357 rflag = 1;
8358 }
8359 if (prompt && isatty(0)) {
8360 putprompt(prompt);
8361 flushall();
8362 }
8363 if (*(ap = argptr) == NULL)
8364 error("arg count");
8365 if ((ifs = bltinlookup("IFS")) == NULL)
8366 ifs = defifs;
8367 status = 0;
8368 startword = 1;
8369 backslash = 0;
8370 STARTSTACKSTR(p);
8371 for (;;) {
8372 if (read(0, &c, 1) != 1) {
8373 status = 1;
8374 break;
8375 }
8376 if (c == '\0')
8377 continue;
8378 if (backslash) {
8379 backslash = 0;
8380 if (c != '\n')
8381 STPUTC(c, p);
8382 continue;
8383 }
8384 if (!rflag && c == '\\') {
8385 backslash++;
8386 continue;
8387 }
8388 if (c == '\n')
8389 break;
8390 if (startword && *ifs == ' ' && strchr(ifs, c)) {
8391 continue;
8392 }
8393 startword = 0;
8394 if (backslash && c == '\\') {
8395 if (read(0, &c, 1) != 1) {
8396 status = 1;
8397 break;
8398 }
8399 STPUTC(c, p);
8400 } else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
8401 STACKSTRNUL(p);
8402 setvar(*ap, stackblock(), 0);
8403 ap++;
8404 startword = 1;
8405 STARTSTACKSTR(p);
8406 } else {
8407 STPUTC(c, p);
8408 }
8409 }
8410 STACKSTRNUL(p);
8411 /* Remove trailing blanks */
8412 while (stackblock() <= --p && strchr(ifs, *p) != NULL)
8413 *p = '\0';
8414 setvar(*ap, stackblock(), 0);
8415 while (*++ap != NULL)
8416 setvar(*ap, nullstr, 0);
8417 return status;
8418}
8419
8420
8421
8422static int
8423umaskcmd(argc, argv)
8424 int argc;
8425 char **argv;
8426{
8427 char *ap;
8428 int mask;
8429 int i;
8430 int symbolic_mode = 0;
8431
8432 while ((i = nextopt("S")) != '\0') {
8433 symbolic_mode = 1;
8434 }
8435
8436 INTOFF;
8437 mask = umask(0);
8438 umask(mask);
8439 INTON;
8440
8441 if ((ap = *argptr) == NULL) {
8442 if (symbolic_mode) {
8443 char u[4], g[4], o[4];
8444
8445 i = 0;
8446 if ((mask & S_IRUSR) == 0)
8447 u[i++] = 'r';
8448 if ((mask & S_IWUSR) == 0)
8449 u[i++] = 'w';
8450 if ((mask & S_IXUSR) == 0)
8451 u[i++] = 'x';
8452 u[i] = '\0';
8453
8454 i = 0;
8455 if ((mask & S_IRGRP) == 0)
8456 g[i++] = 'r';
8457 if ((mask & S_IWGRP) == 0)
8458 g[i++] = 'w';
8459 if ((mask & S_IXGRP) == 0)
8460 g[i++] = 'x';
8461 g[i] = '\0';
8462
8463 i = 0;
8464 if ((mask & S_IROTH) == 0)
8465 o[i++] = 'r';
8466 if ((mask & S_IWOTH) == 0)
8467 o[i++] = 'w';
8468 if ((mask & S_IXOTH) == 0)
8469 o[i++] = 'x';
8470 o[i] = '\0';
8471
8472 out1fmt("u=%s,g=%s,o=%s\n", u, g, o);
8473 } else {
8474 out1fmt("%.4o\n", mask);
8475 }
8476 } else {
8477 if (isdigit((unsigned char)*ap)) {
8478 mask = 0;
8479 do {
8480 if (*ap >= '8' || *ap < '0')
8481 error("Illegal number: %s", argv[1]);
8482 mask = (mask << 3) + (*ap - '0');
8483 } while (*++ap != '\0');
8484 umask(mask);
8485 } else {
8486 void *set;
8487
8488 INTOFF;
8489 if ((set = setmode(ap)) != 0) {
8490 mask = getmode(set, ~mask & 0777);
8491 ckfree(set);
8492 }
8493 INTON;
8494 if (!set)
8495 error("Illegal mode: %s", ap);
8496
8497 umask(~mask & 0777);
8498 }
8499 }
8500 return 0;
8501}
8502
8503/*
8504 * ulimit builtin
8505 *
8506 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
8507 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
8508 * ash by J.T. Conklin.
8509 *
8510 * Public domain.
8511 */
8512
8513struct limits {
8514 const char *name;
Eric Andersen2870d962001-07-02 17:27:21 +00008515 int cmd;
8516 int factor; /* multiply by to get rlim_{cur,max} values */
8517 char option;
Eric Andersencb57d552001-06-28 07:25:16 +00008518};
8519
8520static const struct limits limits[] = {
8521#ifdef RLIMIT_CPU
Eric Andersen2870d962001-07-02 17:27:21 +00008522 { "time(seconds)", RLIMIT_CPU, 1, 't' },
Eric Andersencb57d552001-06-28 07:25:16 +00008523#endif
8524#ifdef RLIMIT_FSIZE
Eric Andersen2870d962001-07-02 17:27:21 +00008525 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
Eric Andersencb57d552001-06-28 07:25:16 +00008526#endif
8527#ifdef RLIMIT_DATA
Eric Andersen2870d962001-07-02 17:27:21 +00008528 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
Eric Andersencb57d552001-06-28 07:25:16 +00008529#endif
8530#ifdef RLIMIT_STACK
Eric Andersen2870d962001-07-02 17:27:21 +00008531 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
Eric Andersencb57d552001-06-28 07:25:16 +00008532#endif
8533#ifdef RLIMIT_CORE
Eric Andersen2870d962001-07-02 17:27:21 +00008534 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
Eric Andersencb57d552001-06-28 07:25:16 +00008535#endif
8536#ifdef RLIMIT_RSS
Eric Andersen2870d962001-07-02 17:27:21 +00008537 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
Eric Andersencb57d552001-06-28 07:25:16 +00008538#endif
8539#ifdef RLIMIT_MEMLOCK
Eric Andersen2870d962001-07-02 17:27:21 +00008540 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
Eric Andersencb57d552001-06-28 07:25:16 +00008541#endif
8542#ifdef RLIMIT_NPROC
Eric Andersen2870d962001-07-02 17:27:21 +00008543 { "process(processes)", RLIMIT_NPROC, 1, 'p' },
Eric Andersencb57d552001-06-28 07:25:16 +00008544#endif
8545#ifdef RLIMIT_NOFILE
Eric Andersen2870d962001-07-02 17:27:21 +00008546 { "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' },
Eric Andersencb57d552001-06-28 07:25:16 +00008547#endif
8548#ifdef RLIMIT_VMEM
Eric Andersen2870d962001-07-02 17:27:21 +00008549 { "vmemory(kbytes)", RLIMIT_VMEM, 1024, 'v' },
Eric Andersencb57d552001-06-28 07:25:16 +00008550#endif
8551#ifdef RLIMIT_SWAP
Eric Andersen2870d962001-07-02 17:27:21 +00008552 { "swap(kbytes)", RLIMIT_SWAP, 1024, 'w' },
Eric Andersencb57d552001-06-28 07:25:16 +00008553#endif
Eric Andersen2870d962001-07-02 17:27:21 +00008554 { (char *) 0, 0, 0, '\0' }
Eric Andersencb57d552001-06-28 07:25:16 +00008555};
8556
8557static int
8558ulimitcmd(argc, argv)
8559 int argc;
8560 char **argv;
8561{
Eric Andersen2870d962001-07-02 17:27:21 +00008562 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00008563 rlim_t val = 0;
8564 enum { SOFT = 0x1, HARD = 0x2 }
8565 how = SOFT | HARD;
Eric Andersen2870d962001-07-02 17:27:21 +00008566 const struct limits *l;
8567 int set, all = 0;
8568 int optc, what;
8569 struct rlimit limit;
Eric Andersencb57d552001-06-28 07:25:16 +00008570
8571 what = 'f';
8572 while ((optc = nextopt("HSatfdsmcnpl")) != '\0')
8573 switch (optc) {
8574 case 'H':
8575 how = HARD;
8576 break;
8577 case 'S':
8578 how = SOFT;
8579 break;
8580 case 'a':
8581 all = 1;
8582 break;
8583 default:
8584 what = optc;
8585 }
8586
8587 for (l = limits; l->name && l->option != what; l++)
8588 ;
8589 if (!l->name)
8590 error("internal error (%c)", what);
8591
8592 set = *argptr ? 1 : 0;
8593 if (set) {
8594 char *p = *argptr;
8595
8596 if (all || argptr[1])
8597 error("too many arguments");
8598 if (strcmp(p, "unlimited") == 0)
8599 val = RLIM_INFINITY;
8600 else {
8601 val = (rlim_t) 0;
8602
8603 while ((c = *p++) >= '0' && c <= '9')
8604 {
8605 val = (val * 10) + (long)(c - '0');
8606 if (val < (rlim_t) 0)
8607 break;
8608 }
8609 if (c)
8610 error("bad number");
8611 val *= l->factor;
8612 }
8613 }
8614 if (all) {
8615 for (l = limits; l->name; l++) {
8616 getrlimit(l->cmd, &limit);
8617 if (how & SOFT)
8618 val = limit.rlim_cur;
8619 else if (how & HARD)
8620 val = limit.rlim_max;
8621
8622 out1fmt("%-20s ", l->name);
8623 if (val == RLIM_INFINITY)
8624 out1fmt("unlimited\n");
8625 else
8626 {
8627 val /= l->factor;
Eric Andersencb57d552001-06-28 07:25:16 +00008628 out1fmt("%lld\n", (long long) val);
Eric Andersencb57d552001-06-28 07:25:16 +00008629 }
8630 }
8631 return 0;
8632 }
8633
8634 getrlimit(l->cmd, &limit);
8635 if (set) {
8636 if (how & HARD)
8637 limit.rlim_max = val;
8638 if (how & SOFT)
8639 limit.rlim_cur = val;
8640 if (setrlimit(l->cmd, &limit) < 0)
Eric Andersen2870d962001-07-02 17:27:21 +00008641 error("error setting limit (%m)");
Eric Andersencb57d552001-06-28 07:25:16 +00008642 } else {
8643 if (how & SOFT)
8644 val = limit.rlim_cur;
8645 else if (how & HARD)
8646 val = limit.rlim_max;
8647
8648 if (val == RLIM_INFINITY)
8649 out1fmt("unlimited\n");
8650 else
8651 {
8652 val /= l->factor;
Eric Andersencb57d552001-06-28 07:25:16 +00008653 out1fmt("%lld\n", (long long) val);
Eric Andersencb57d552001-06-28 07:25:16 +00008654 }
8655 }
8656 return 0;
8657}
Eric Andersencb57d552001-06-28 07:25:16 +00008658/*
8659 * prefix -- see if pfx is a prefix of string.
8660 */
8661
8662static int
8663prefix(pfx, string)
8664 char const *pfx;
8665 char const *string;
8666 {
8667 while (*pfx) {
8668 if (*pfx++ != *string++)
8669 return 0;
8670 }
8671 return 1;
8672}
8673
Eric Andersen2870d962001-07-02 17:27:21 +00008674/*
8675 * Return true if s is a string of digits, and save munber in intptr
8676 * nagative is bad
8677 */
8678
8679static int
8680is_number(const char *p, int *intptr)
8681{
8682 int ret = 0;
8683
8684 do {
8685 if (! is_digit(*p))
8686 return 0;
8687 ret *= 10;
8688 ret += digit_val(*p);
8689 p++;
8690 } while (*p != '\0');
8691
8692 *intptr = ret;
8693 return 1;
8694}
Eric Andersencb57d552001-06-28 07:25:16 +00008695
8696/*
8697 * Convert a string of digits to an integer, printing an error message on
8698 * failure.
8699 */
8700
8701static int
Eric Andersen2870d962001-07-02 17:27:21 +00008702number(const char *s)
8703{
8704 int i;
8705 if (! is_number(s, &i))
Eric Andersencb57d552001-06-28 07:25:16 +00008706 error("Illegal number: %s", s);
Eric Andersen2870d962001-07-02 17:27:21 +00008707 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00008708}
8709
Eric Andersencb57d552001-06-28 07:25:16 +00008710/*
8711 * Produce a possibly single quoted string suitable as input to the shell.
8712 * The return string is allocated on the stack.
8713 */
8714
8715static char *
8716single_quote(const char *s) {
8717 char *p;
8718
8719 STARTSTACKSTR(p);
8720
8721 do {
8722 char *q = p;
8723 size_t len1, len1p, len2, len2p;
8724
8725 len1 = strcspn(s, "'");
8726 len2 = strspn(s + len1, "'");
8727
8728 len1p = len1 ? len1 + 2 : len1;
8729 switch (len2) {
8730 case 0:
8731 len2p = 0;
8732 break;
8733 case 1:
8734 len2p = 2;
8735 break;
8736 default:
8737 len2p = len2 + 2;
8738 }
8739
8740 CHECKSTRSPACE(len1p + len2p + 1, p);
8741
8742 if (len1) {
8743 *p = '\'';
8744#ifdef _GNU_SOURCE
8745 q = mempcpy(p + 1, s, len1);
8746#else
8747 q = p + 1 + len1;
8748 memcpy(p + 1, s, len1);
8749#endif
8750 *q++ = '\'';
8751 s += len1;
8752 }
8753
8754 switch (len2) {
8755 case 0:
8756 break;
8757 case 1:
8758 *q++ = '\\';
8759 *q = '\'';
8760 s++;
8761 break;
8762 default:
8763 *q = '"';
8764#ifdef _GNU_SOURCE
8765 *(char *) mempcpy(q + 1, s, len2) = '"';
8766#else
8767 q += 1 + len2;
8768 memcpy(q + 1, s, len2);
8769 *q = '"';
8770#endif
8771 s += len2;
8772 }
8773
8774 STADJUST(len1p + len2p, p);
8775 } while (*s);
8776
8777 USTPUTC(0, p);
8778
8779 return grabstackstr(p);
8780}
8781
8782/*
8783 * Like strdup but works with the ash stack.
8784 */
8785
8786static char *
8787sstrdup(const char *p)
8788{
8789 size_t len = strlen(p) + 1;
8790 return memcpy(stalloc(len), p, len);
8791}
8792
Eric Andersencb57d552001-06-28 07:25:16 +00008793
8794/*
Eric Andersencb57d552001-06-28 07:25:16 +00008795 * This file was generated by the mknodes program.
8796 */
8797
Eric Andersencb57d552001-06-28 07:25:16 +00008798/*
8799 * Routine for dealing with parsed shell commands.
8800 */
8801
8802
Eric Andersen2870d962001-07-02 17:27:21 +00008803static int funcblocksize; /* size of structures in function */
8804static int funcstringsize; /* size of strings in node */
8805static pointer funcblock; /* block to allocate function from */
8806static char *funcstring; /* block to allocate strings from */
Eric Andersencb57d552001-06-28 07:25:16 +00008807
8808static const short nodesize[26] = {
8809 ALIGN(sizeof (struct nbinary)),
8810 ALIGN(sizeof (struct ncmd)),
8811 ALIGN(sizeof (struct npipe)),
8812 ALIGN(sizeof (struct nredir)),
8813 ALIGN(sizeof (struct nredir)),
8814 ALIGN(sizeof (struct nredir)),
8815 ALIGN(sizeof (struct nbinary)),
8816 ALIGN(sizeof (struct nbinary)),
8817 ALIGN(sizeof (struct nif)),
8818 ALIGN(sizeof (struct nbinary)),
8819 ALIGN(sizeof (struct nbinary)),
8820 ALIGN(sizeof (struct nfor)),
8821 ALIGN(sizeof (struct ncase)),
8822 ALIGN(sizeof (struct nclist)),
8823 ALIGN(sizeof (struct narg)),
8824 ALIGN(sizeof (struct narg)),
8825 ALIGN(sizeof (struct nfile)),
8826 ALIGN(sizeof (struct nfile)),
8827 ALIGN(sizeof (struct nfile)),
8828 ALIGN(sizeof (struct nfile)),
8829 ALIGN(sizeof (struct nfile)),
8830 ALIGN(sizeof (struct ndup)),
8831 ALIGN(sizeof (struct ndup)),
8832 ALIGN(sizeof (struct nhere)),
8833 ALIGN(sizeof (struct nhere)),
8834 ALIGN(sizeof (struct nnot)),
8835};
8836
8837
Eric Andersen2870d962001-07-02 17:27:21 +00008838static void calcsize (union node *);
8839static void sizenodelist (struct nodelist *);
8840static union node *copynode (union node *);
8841static struct nodelist *copynodelist (struct nodelist *);
8842static char *nodesavestr (char *);
Eric Andersencb57d552001-06-28 07:25:16 +00008843
8844
8845
8846/*
8847 * Make a copy of a parse tree.
8848 */
8849
Eric Andersen2870d962001-07-02 17:27:21 +00008850static union node *
8851copyfunc(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008852{
8853 if (n == NULL)
8854 return NULL;
8855 funcblocksize = 0;
8856 funcstringsize = 0;
8857 calcsize(n);
8858 funcblock = ckmalloc(funcblocksize + funcstringsize);
8859 funcstring = (char *) funcblock + funcblocksize;
8860 return copynode(n);
8861}
8862
8863
8864
8865static void
8866calcsize(n)
8867 union node *n;
8868{
8869 if (n == NULL)
8870 return;
8871 funcblocksize += nodesize[n->type];
8872 switch (n->type) {
8873 case NSEMI:
8874 case NAND:
8875 case NOR:
8876 case NWHILE:
8877 case NUNTIL:
8878 calcsize(n->nbinary.ch2);
8879 calcsize(n->nbinary.ch1);
8880 break;
8881 case NCMD:
8882 calcsize(n->ncmd.redirect);
8883 calcsize(n->ncmd.args);
8884 calcsize(n->ncmd.assign);
8885 break;
8886 case NPIPE:
8887 sizenodelist(n->npipe.cmdlist);
8888 break;
8889 case NREDIR:
8890 case NBACKGND:
8891 case NSUBSHELL:
8892 calcsize(n->nredir.redirect);
8893 calcsize(n->nredir.n);
8894 break;
8895 case NIF:
8896 calcsize(n->nif.elsepart);
8897 calcsize(n->nif.ifpart);
8898 calcsize(n->nif.test);
8899 break;
8900 case NFOR:
8901 funcstringsize += strlen(n->nfor.var) + 1;
8902 calcsize(n->nfor.body);
8903 calcsize(n->nfor.args);
8904 break;
8905 case NCASE:
8906 calcsize(n->ncase.cases);
8907 calcsize(n->ncase.expr);
8908 break;
8909 case NCLIST:
8910 calcsize(n->nclist.body);
8911 calcsize(n->nclist.pattern);
8912 calcsize(n->nclist.next);
8913 break;
8914 case NDEFUN:
8915 case NARG:
8916 sizenodelist(n->narg.backquote);
8917 funcstringsize += strlen(n->narg.text) + 1;
8918 calcsize(n->narg.next);
8919 break;
8920 case NTO:
8921 case NFROM:
8922 case NFROMTO:
8923 case NAPPEND:
8924 case NTOOV:
8925 calcsize(n->nfile.fname);
8926 calcsize(n->nfile.next);
8927 break;
8928 case NTOFD:
8929 case NFROMFD:
8930 calcsize(n->ndup.vname);
8931 calcsize(n->ndup.next);
8932 break;
8933 case NHERE:
8934 case NXHERE:
8935 calcsize(n->nhere.doc);
8936 calcsize(n->nhere.next);
8937 break;
8938 case NNOT:
8939 calcsize(n->nnot.com);
8940 break;
8941 };
8942}
8943
8944
8945
8946static void
8947sizenodelist(lp)
8948 struct nodelist *lp;
8949{
8950 while (lp) {
8951 funcblocksize += ALIGN(sizeof(struct nodelist));
8952 calcsize(lp->n);
8953 lp = lp->next;
8954 }
8955}
8956
8957
8958
8959static union node *
8960copynode(n)
8961 union node *n;
8962{
8963 union node *new;
8964
8965 if (n == NULL)
8966 return NULL;
8967 new = funcblock;
8968 funcblock = (char *) funcblock + nodesize[n->type];
8969 switch (n->type) {
8970 case NSEMI:
8971 case NAND:
8972 case NOR:
8973 case NWHILE:
8974 case NUNTIL:
8975 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8976 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8977 break;
8978 case NCMD:
8979 new->ncmd.redirect = copynode(n->ncmd.redirect);
8980 new->ncmd.args = copynode(n->ncmd.args);
8981 new->ncmd.assign = copynode(n->ncmd.assign);
8982 new->ncmd.backgnd = n->ncmd.backgnd;
8983 break;
8984 case NPIPE:
8985 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8986 new->npipe.backgnd = n->npipe.backgnd;
8987 break;
8988 case NREDIR:
8989 case NBACKGND:
8990 case NSUBSHELL:
8991 new->nredir.redirect = copynode(n->nredir.redirect);
8992 new->nredir.n = copynode(n->nredir.n);
8993 break;
8994 case NIF:
8995 new->nif.elsepart = copynode(n->nif.elsepart);
8996 new->nif.ifpart = copynode(n->nif.ifpart);
8997 new->nif.test = copynode(n->nif.test);
8998 break;
8999 case NFOR:
9000 new->nfor.var = nodesavestr(n->nfor.var);
9001 new->nfor.body = copynode(n->nfor.body);
9002 new->nfor.args = copynode(n->nfor.args);
9003 break;
9004 case NCASE:
9005 new->ncase.cases = copynode(n->ncase.cases);
9006 new->ncase.expr = copynode(n->ncase.expr);
9007 break;
9008 case NCLIST:
9009 new->nclist.body = copynode(n->nclist.body);
9010 new->nclist.pattern = copynode(n->nclist.pattern);
9011 new->nclist.next = copynode(n->nclist.next);
9012 break;
9013 case NDEFUN:
9014 case NARG:
9015 new->narg.backquote = copynodelist(n->narg.backquote);
9016 new->narg.text = nodesavestr(n->narg.text);
9017 new->narg.next = copynode(n->narg.next);
9018 break;
9019 case NTO:
9020 case NFROM:
9021 case NFROMTO:
9022 case NAPPEND:
9023 case NTOOV:
9024 new->nfile.fname = copynode(n->nfile.fname);
9025 new->nfile.fd = n->nfile.fd;
9026 new->nfile.next = copynode(n->nfile.next);
9027 break;
9028 case NTOFD:
9029 case NFROMFD:
9030 new->ndup.vname = copynode(n->ndup.vname);
9031 new->ndup.dupfd = n->ndup.dupfd;
9032 new->ndup.fd = n->ndup.fd;
9033 new->ndup.next = copynode(n->ndup.next);
9034 break;
9035 case NHERE:
9036 case NXHERE:
9037 new->nhere.doc = copynode(n->nhere.doc);
9038 new->nhere.fd = n->nhere.fd;
9039 new->nhere.next = copynode(n->nhere.next);
9040 break;
9041 case NNOT:
9042 new->nnot.com = copynode(n->nnot.com);
9043 break;
9044 };
9045 new->type = n->type;
9046 return new;
9047}
9048
9049
9050static struct nodelist *
9051copynodelist(lp)
9052 struct nodelist *lp;
9053{
9054 struct nodelist *start;
9055 struct nodelist **lpp;
9056
9057 lpp = &start;
9058 while (lp) {
9059 *lpp = funcblock;
9060 funcblock = (char *) funcblock + ALIGN(sizeof(struct nodelist));
9061 (*lpp)->n = copynode(lp->n);
9062 lp = lp->next;
9063 lpp = &(*lpp)->next;
9064 }
9065 *lpp = NULL;
9066 return start;
9067}
9068
9069
9070
9071static char *
9072nodesavestr(s)
9073 char *s;
9074{
9075#ifdef _GNU_SOURCE
9076 char *rtn = funcstring;
9077
9078 funcstring = stpcpy(funcstring, s) + 1;
9079 return rtn;
9080#else
9081 register char *p = s;
9082 register char *q = funcstring;
9083 char *rtn = funcstring;
9084
9085 while ((*q++ = *p++) != '\0')
9086 continue;
9087 funcstring = q;
9088 return rtn;
9089#endif
9090}
9091
Eric Andersencb57d552001-06-28 07:25:16 +00009092#ifdef ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00009093static int getopts (char *, char *, char **, int *, int *);
Eric Andersencb57d552001-06-28 07:25:16 +00009094#endif
9095
9096
9097/*
9098 * Process the shell command line arguments.
9099 */
9100
9101static void
9102procargs(argc, argv)
9103 int argc;
9104 char **argv;
9105{
9106 int i;
9107
9108 argptr = argv;
9109 if (argc > 0)
9110 argptr++;
9111 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00009112 optent_val(i) = 2;
Eric Andersencb57d552001-06-28 07:25:16 +00009113 options(1);
9114 if (*argptr == NULL && minusc == NULL)
9115 sflag = 1;
9116 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
9117 iflag = 1;
9118 if (mflag == 2)
9119 mflag = iflag;
9120 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00009121 if (optent_val(i) == 2)
9122 optent_val(i) = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009123 arg0 = argv[0];
9124 if (sflag == 0 && minusc == NULL) {
9125 commandname = argv[0];
9126 arg0 = *argptr++;
9127 setinputfile(arg0, 0);
9128 commandname = arg0;
9129 }
9130 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
9131 if (argptr && minusc && *argptr)
Eric Andersen2870d962001-07-02 17:27:21 +00009132 arg0 = *argptr++;
Eric Andersencb57d552001-06-28 07:25:16 +00009133
9134 shellparam.p = argptr;
9135 shellparam.optind = 1;
9136 shellparam.optoff = -1;
9137 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
9138 while (*argptr) {
9139 shellparam.nparam++;
9140 argptr++;
9141 }
9142 optschanged();
9143}
9144
9145
Eric Andersencb57d552001-06-28 07:25:16 +00009146
9147/*
9148 * Process shell options. The global variable argptr contains a pointer
9149 * to the argument list; we advance it past the options.
9150 */
9151
9152static void
9153options(cmdline)
9154 int cmdline;
9155{
9156 char *p;
9157 int val;
9158 int c;
9159
9160 if (cmdline)
9161 minusc = NULL;
9162 while ((p = *argptr) != NULL) {
9163 argptr++;
9164 if ((c = *p++) == '-') {
9165 val = 1;
Eric Andersen2870d962001-07-02 17:27:21 +00009166 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
9167 if (!cmdline) {
9168 /* "-" means turn off -x and -v */
9169 if (p[0] == '\0')
9170 xflag = vflag = 0;
9171 /* "--" means reset params */
9172 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00009173 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +00009174 }
9175 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +00009176 }
9177 } else if (c == '+') {
9178 val = 0;
9179 } else {
9180 argptr--;
9181 break;
9182 }
9183 while ((c = *p++) != '\0') {
9184 if (c == 'c' && cmdline) {
9185 char *q;
Eric Andersen2870d962001-07-02 17:27:21 +00009186#ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */
Eric Andersencb57d552001-06-28 07:25:16 +00009187 if (*p == '\0')
9188#endif
9189 q = *argptr++;
9190 if (q == NULL || minusc != NULL)
9191 error("Bad -c option");
9192 minusc = q;
9193#ifdef NOHACK
9194 break;
9195#endif
9196 } else if (c == 'o') {
9197 minus_o(*argptr, val);
9198 if (*argptr)
9199 argptr++;
9200 } else {
9201 setoption(c, val);
9202 }
9203 }
9204 }
9205}
9206
9207static void
9208minus_o(name, val)
9209 char *name;
9210 int val;
9211{
9212 int i;
9213
9214 if (name == NULL) {
9215 out1str("Current option settings\n");
9216 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00009217 out1fmt("%-16s%s\n", optent_name(optlist[i]),
9218 optent_val(i) ? "on" : "off");
Eric Andersencb57d552001-06-28 07:25:16 +00009219 } else {
9220 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00009221 if (equal(name, optent_name(optlist[i]))) {
9222 setoption(optent_letter(optlist[i]), val);
Eric Andersencb57d552001-06-28 07:25:16 +00009223 return;
9224 }
9225 error("Illegal option -o %s", name);
9226 }
9227}
9228
9229
9230static void
Eric Andersen2870d962001-07-02 17:27:21 +00009231setoption(int flag, int val)
9232{
Eric Andersencb57d552001-06-28 07:25:16 +00009233 int i;
9234
9235 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00009236 if (optent_letter(optlist[i]) == flag) {
9237 optent_val(i) = val;
Eric Andersencb57d552001-06-28 07:25:16 +00009238 if (val) {
9239 /* #%$ hack for ksh semantics */
9240 if (flag == 'V')
9241 Eflag = 0;
9242 else if (flag == 'E')
9243 Vflag = 0;
9244 }
9245 return;
9246 }
9247 error("Illegal option -%c", flag);
9248 /* NOTREACHED */
9249}
9250
9251
9252
Eric Andersencb57d552001-06-28 07:25:16 +00009253/*
9254 * Set the shell parameters.
9255 */
9256
9257static void
Eric Andersen2870d962001-07-02 17:27:21 +00009258setparam(char **argv)
9259{
Eric Andersencb57d552001-06-28 07:25:16 +00009260 char **newparam;
9261 char **ap;
9262 int nparam;
9263
9264 for (nparam = 0 ; argv[nparam] ; nparam++);
9265 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
9266 while (*argv) {
9267 *ap++ = savestr(*argv++);
9268 }
9269 *ap = NULL;
9270 freeparam(&shellparam);
9271 shellparam.malloc = 1;
9272 shellparam.nparam = nparam;
9273 shellparam.p = newparam;
9274 shellparam.optind = 1;
9275 shellparam.optoff = -1;
9276}
9277
9278
9279/*
9280 * Free the list of positional parameters.
9281 */
9282
9283static void
Eric Andersen2870d962001-07-02 17:27:21 +00009284freeparam(volatile struct shparam *param)
9285{
Eric Andersencb57d552001-06-28 07:25:16 +00009286 char **ap;
9287
9288 if (param->malloc) {
9289 for (ap = param->p ; *ap ; ap++)
9290 ckfree(*ap);
9291 ckfree(param->p);
9292 }
9293}
9294
9295
9296
9297/*
9298 * The shift builtin command.
9299 */
9300
9301static int
9302shiftcmd(argc, argv)
9303 int argc;
9304 char **argv;
9305{
9306 int n;
9307 char **ap1, **ap2;
9308
9309 n = 1;
9310 if (argc > 1)
9311 n = number(argv[1]);
9312 if (n > shellparam.nparam)
9313 error("can't shift that many");
9314 INTOFF;
9315 shellparam.nparam -= n;
9316 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
9317 if (shellparam.malloc)
9318 ckfree(*ap1);
9319 }
9320 ap2 = shellparam.p;
9321 while ((*ap2++ = *ap1++) != NULL);
9322 shellparam.optind = 1;
9323 shellparam.optoff = -1;
9324 INTON;
9325 return 0;
9326}
9327
9328
9329
9330/*
9331 * The set command builtin.
9332 */
9333
9334static int
9335setcmd(argc, argv)
9336 int argc;
9337 char **argv;
9338{
9339 if (argc == 1)
9340 return showvarscmd(argc, argv);
9341 INTOFF;
9342 options(0);
9343 optschanged();
9344 if (*argptr != NULL) {
9345 setparam(argptr);
9346 }
9347 INTON;
9348 return 0;
9349}
9350
9351
9352static void
Eric Andersen2870d962001-07-02 17:27:21 +00009353getoptsreset(const char *value)
Eric Andersencb57d552001-06-28 07:25:16 +00009354{
9355 shellparam.optind = number(value);
9356 shellparam.optoff = -1;
9357}
9358
Eric Andersen2870d962001-07-02 17:27:21 +00009359#ifdef BB_LOCALE_SUPPORT
9360static void change_lc_all(const char *value)
9361{
9362 if(value != 0 && *value != 0)
9363 setlocale(LC_ALL, value);
9364}
9365
9366static void change_lc_ctype(const char *value)
9367{
9368 if(value != 0 && *value != 0)
9369 setlocale(LC_CTYPE, value);
9370}
9371
9372#endif
9373
Eric Andersencb57d552001-06-28 07:25:16 +00009374#ifdef ASH_GETOPTS
9375/*
9376 * The getopts builtin. Shellparam.optnext points to the next argument
9377 * to be processed. Shellparam.optptr points to the next character to
9378 * be processed in the current argument. If shellparam.optnext is NULL,
9379 * then it's the first time getopts has been called.
9380 */
9381
9382static int
9383getoptscmd(argc, argv)
9384 int argc;
9385 char **argv;
9386{
9387 char **optbase;
9388
9389 if (argc < 3)
9390 error("Usage: getopts optstring var [arg]");
9391 else if (argc == 3) {
9392 optbase = shellparam.p;
9393 if (shellparam.optind > shellparam.nparam + 1) {
9394 shellparam.optind = 1;
9395 shellparam.optoff = -1;
9396 }
9397 }
9398 else {
9399 optbase = &argv[3];
9400 if (shellparam.optind > argc - 2) {
9401 shellparam.optind = 1;
9402 shellparam.optoff = -1;
9403 }
9404 }
9405
9406 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9407 &shellparam.optoff);
9408}
9409
9410/*
9411 * Safe version of setvar, returns 1 on success 0 on failure.
9412 */
9413
9414static int
9415setvarsafe(name, val, flags)
9416 const char *name, *val;
9417 int flags;
9418{
9419 struct jmploc jmploc;
9420 struct jmploc *volatile savehandler = handler;
9421 int err = 0;
9422#ifdef __GNUC__
9423 (void) &err;
9424#endif
9425
9426 if (setjmp(jmploc.loc))
9427 err = 1;
9428 else {
9429 handler = &jmploc;
9430 setvar(name, val, flags);
9431 }
9432 handler = savehandler;
9433 return err;
9434}
9435
9436static int
9437getopts(optstr, optvar, optfirst, myoptind, optoff)
9438 char *optstr;
9439 char *optvar;
9440 char **optfirst;
9441 int *myoptind;
9442 int *optoff;
9443{
9444 char *p, *q;
9445 char c = '?';
9446 int done = 0;
9447 int err = 0;
9448 char s[10];
9449 char **optnext = optfirst + *myoptind - 1;
9450
9451 if (*myoptind <= 1 || *optoff < 0 || !(*(optnext - 1)) ||
9452 strlen(*(optnext - 1)) < *optoff)
9453 p = NULL;
9454 else
9455 p = *(optnext - 1) + *optoff;
9456 if (p == NULL || *p == '\0') {
9457 /* Current word is done, advance */
9458 if (optnext == NULL)
9459 return 1;
9460 p = *optnext;
9461 if (p == NULL || *p != '-' || *++p == '\0') {
9462atend:
9463 *myoptind = optnext - optfirst + 1;
9464 p = NULL;
9465 done = 1;
9466 goto out;
9467 }
9468 optnext++;
Eric Andersen2870d962001-07-02 17:27:21 +00009469 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009470 goto atend;
9471 }
9472
9473 c = *p++;
9474 for (q = optstr; *q != c; ) {
9475 if (*q == '\0') {
9476 if (optstr[0] == ':') {
9477 s[0] = c;
9478 s[1] = '\0';
9479 err |= setvarsafe("OPTARG", s, 0);
9480 }
9481 else {
Eric Andersen3102ac42001-07-06 04:26:23 +00009482 out2fmt("Illegal option -%c\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009483 (void) unsetvar("OPTARG");
9484 }
9485 c = '?';
9486 goto bad;
9487 }
9488 if (*++q == ':')
9489 q++;
9490 }
9491
9492 if (*++q == ':') {
9493 if (*p == '\0' && (p = *optnext) == NULL) {
9494 if (optstr[0] == ':') {
9495 s[0] = c;
9496 s[1] = '\0';
9497 err |= setvarsafe("OPTARG", s, 0);
9498 c = ':';
9499 }
9500 else {
Eric Andersen3102ac42001-07-06 04:26:23 +00009501 out2fmt("No arg for -%c option\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009502 (void) unsetvar("OPTARG");
9503 c = '?';
9504 }
9505 goto bad;
9506 }
9507
9508 if (p == *optnext)
9509 optnext++;
9510 setvarsafe("OPTARG", p, 0);
9511 p = NULL;
9512 }
9513 else
9514 setvarsafe("OPTARG", "", 0);
9515 *myoptind = optnext - optfirst + 1;
9516 goto out;
9517
9518bad:
9519 *myoptind = 1;
9520 p = NULL;
9521out:
9522 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersen3102ac42001-07-06 04:26:23 +00009523 snprintf(s, sizeof(s), "%d", *myoptind);
Eric Andersencb57d552001-06-28 07:25:16 +00009524 err |= setvarsafe("OPTIND", s, VNOFUNC);
9525 s[0] = c;
9526 s[1] = '\0';
9527 err |= setvarsafe(optvar, s, 0);
9528 if (err) {
9529 *myoptind = 1;
9530 *optoff = -1;
9531 flushall();
9532 exraise(EXERROR);
9533 }
9534 return done;
9535}
Eric Andersen2870d962001-07-02 17:27:21 +00009536#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009537
9538/*
9539 * XXX - should get rid of. have all builtins use getopt(3). the
9540 * library getopt must have the BSD extension static variable "optreset"
9541 * otherwise it can't be used within the shell safely.
9542 *
9543 * Standard option processing (a la getopt) for builtin routines. The
9544 * only argument that is passed to nextopt is the option string; the
9545 * other arguments are unnecessary. It return the character, or '\0' on
9546 * end of input.
9547 */
9548
9549static int
9550nextopt(optstring)
9551 const char *optstring;
9552 {
9553 char *p;
9554 const char *q;
9555 char c;
9556
9557 if ((p = optptr) == NULL || *p == '\0') {
9558 p = *argptr;
9559 if (p == NULL || *p != '-' || *++p == '\0')
9560 return '\0';
9561 argptr++;
Eric Andersen2870d962001-07-02 17:27:21 +00009562 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009563 return '\0';
9564 }
9565 c = *p++;
9566 for (q = optstring ; *q != c ; ) {
9567 if (*q == '\0')
9568 error("Illegal option -%c", c);
9569 if (*++q == ':')
9570 q++;
9571 }
9572 if (*++q == ':') {
9573 if (*p == '\0' && (p = *argptr++) == NULL)
9574 error("No arg for -%c option", c);
9575 optionarg = p;
9576 p = NULL;
9577 }
9578 optptr = p;
9579 return c;
9580}
9581
Eric Andersencb57d552001-06-28 07:25:16 +00009582static void
9583flushall() {
Eric Andersencb57d552001-06-28 07:25:16 +00009584 INTOFF;
Eric Andersen3102ac42001-07-06 04:26:23 +00009585 fflush(stdout);
Eric Andersencb57d552001-06-28 07:25:16 +00009586 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00009587}
9588
9589
9590static void
Eric Andersen3102ac42001-07-06 04:26:23 +00009591out2fmt(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00009592{
9593 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00009594 va_start(ap, fmt);
Eric Andersen3102ac42001-07-06 04:26:23 +00009595 vfprintf(stderr, fmt, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009596 va_end(ap);
9597}
9598
9599
9600static void
Eric Andersencb57d552001-06-28 07:25:16 +00009601out1fmt(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00009602{
9603 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00009604 va_start(ap, fmt);
Eric Andersen3102ac42001-07-06 04:26:23 +00009605 vfprintf(stdout, fmt, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009606 va_end(ap);
9607}
9608
Eric Andersencb57d552001-06-28 07:25:16 +00009609/*
9610 * Version of write which resumes after a signal is caught.
9611 */
9612
9613static int
Eric Andersen2870d962001-07-02 17:27:21 +00009614xwrite(int fd, const char *buf, int nbytes)
9615{
Eric Andersencb57d552001-06-28 07:25:16 +00009616 int ntry;
9617 int i;
9618 int n;
9619
9620 n = nbytes;
9621 ntry = 0;
9622 for (;;) {
9623 i = write(fd, buf, n);
9624 if (i > 0) {
9625 if ((n -= i) <= 0)
9626 return nbytes;
9627 buf += i;
9628 ntry = 0;
9629 } else if (i == 0) {
9630 if (++ntry > 10)
9631 return nbytes - n;
9632 } else if (errno != EINTR) {
9633 return -1;
9634 }
9635 }
9636}
9637
9638
Eric Andersencb57d552001-06-28 07:25:16 +00009639/*
9640 * Shell command parser.
9641 */
9642
9643#define EOFMARKLEN 79
9644
9645
9646
9647struct heredoc {
Eric Andersen2870d962001-07-02 17:27:21 +00009648 struct heredoc *next; /* next here document in list */
9649 union node *here; /* redirection node */
9650 char *eofmark; /* string indicating end of input */
9651 int striptabs; /* if set, strip leading tabs */
Eric Andersencb57d552001-06-28 07:25:16 +00009652};
9653
Eric Andersen2870d962001-07-02 17:27:21 +00009654static struct heredoc *heredoclist; /* list of here documents to read */
9655static int parsebackquote; /* nonzero if we are inside backquotes */
9656static int doprompt; /* if set, prompt the user */
9657static int needprompt; /* true if interactive and at start of line */
9658static int lasttoken; /* last token read */
Eric Andersencb57d552001-06-28 07:25:16 +00009659
Eric Andersen2870d962001-07-02 17:27:21 +00009660static char *wordtext; /* text of last word returned by readtoken */
Eric Andersencb57d552001-06-28 07:25:16 +00009661
Eric Andersen2870d962001-07-02 17:27:21 +00009662static struct nodelist *backquotelist;
9663static union node *redirnode;
Eric Andersencb57d552001-06-28 07:25:16 +00009664struct heredoc *heredoc;
Eric Andersen2870d962001-07-02 17:27:21 +00009665static int quoteflag; /* set if (part of) last token was quoted */
9666static int startlinno; /* line # where last token started */
Eric Andersencb57d552001-06-28 07:25:16 +00009667
9668
Eric Andersen2870d962001-07-02 17:27:21 +00009669static union node *list (int);
9670static union node *andor (void);
9671static union node *pipeline (void);
9672static union node *command (void);
9673static union node *simplecmd (void);
9674static void parsefname (void);
9675static void parseheredoc (void);
9676static int peektoken (void);
9677static int readtoken (void);
9678static int xxreadtoken (void);
9679static int readtoken1 (int, char const *, char *, int);
9680static int noexpand (char *);
9681static void synexpect (int) __attribute__((noreturn));
9682static void synerror (const char *) __attribute__((noreturn));
9683static void setprompt (int);
Eric Andersencb57d552001-06-28 07:25:16 +00009684
9685
9686/*
9687 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9688 * valid parse tree indicating a blank line.)
9689 */
9690
Eric Andersen2870d962001-07-02 17:27:21 +00009691static union node *
Eric Andersencb57d552001-06-28 07:25:16 +00009692parsecmd(int interact)
9693{
9694 int t;
9695
9696 tokpushback = 0;
9697 doprompt = interact;
9698 if (doprompt)
9699 setprompt(1);
9700 else
9701 setprompt(0);
9702 needprompt = 0;
9703 t = readtoken();
9704 if (t == TEOF)
9705 return NEOF;
9706 if (t == TNL)
9707 return NULL;
9708 tokpushback++;
9709 return list(1);
9710}
9711
9712
9713static union node *
9714list(nlflag)
9715 int nlflag;
9716{
9717 union node *n1, *n2, *n3;
9718 int tok;
9719
9720 checkkwd = 2;
9721 if (nlflag == 0 && tokendlist[peektoken()])
9722 return NULL;
9723 n1 = NULL;
9724 for (;;) {
9725 n2 = andor();
9726 tok = readtoken();
9727 if (tok == TBACKGND) {
9728 if (n2->type == NCMD || n2->type == NPIPE) {
9729 n2->ncmd.backgnd = 1;
9730 } else if (n2->type == NREDIR) {
9731 n2->type = NBACKGND;
9732 } else {
9733 n3 = (union node *)stalloc(sizeof (struct nredir));
9734 n3->type = NBACKGND;
9735 n3->nredir.n = n2;
9736 n3->nredir.redirect = NULL;
9737 n2 = n3;
9738 }
9739 }
9740 if (n1 == NULL) {
9741 n1 = n2;
9742 }
9743 else {
9744 n3 = (union node *)stalloc(sizeof (struct nbinary));
9745 n3->type = NSEMI;
9746 n3->nbinary.ch1 = n1;
9747 n3->nbinary.ch2 = n2;
9748 n1 = n3;
9749 }
9750 switch (tok) {
9751 case TBACKGND:
9752 case TSEMI:
9753 tok = readtoken();
9754 /* fall through */
9755 case TNL:
9756 if (tok == TNL) {
9757 parseheredoc();
9758 if (nlflag)
9759 return n1;
9760 } else {
9761 tokpushback++;
9762 }
9763 checkkwd = 2;
9764 if (tokendlist[peektoken()])
9765 return n1;
9766 break;
9767 case TEOF:
9768 if (heredoclist)
9769 parseheredoc();
9770 else
Eric Andersen2870d962001-07-02 17:27:21 +00009771 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +00009772 return n1;
9773 default:
9774 if (nlflag)
9775 synexpect(-1);
9776 tokpushback++;
9777 return n1;
9778 }
9779 }
9780}
9781
9782
9783
9784static union node *
9785andor() {
9786 union node *n1, *n2, *n3;
9787 int t;
9788
9789 checkkwd = 1;
9790 n1 = pipeline();
9791 for (;;) {
9792 if ((t = readtoken()) == TAND) {
9793 t = NAND;
9794 } else if (t == TOR) {
9795 t = NOR;
9796 } else {
9797 tokpushback++;
9798 return n1;
9799 }
9800 checkkwd = 2;
9801 n2 = pipeline();
9802 n3 = (union node *)stalloc(sizeof (struct nbinary));
9803 n3->type = t;
9804 n3->nbinary.ch1 = n1;
9805 n3->nbinary.ch2 = n2;
9806 n1 = n3;
9807 }
9808}
9809
9810
9811
9812static union node *
9813pipeline() {
9814 union node *n1, *n2, *pipenode;
9815 struct nodelist *lp, *prev;
9816 int negate;
9817
9818 negate = 0;
9819 TRACE(("pipeline: entered\n"));
9820 if (readtoken() == TNOT) {
9821 negate = !negate;
9822 checkkwd = 1;
9823 } else
9824 tokpushback++;
9825 n1 = command();
9826 if (readtoken() == TPIPE) {
9827 pipenode = (union node *)stalloc(sizeof (struct npipe));
9828 pipenode->type = NPIPE;
9829 pipenode->npipe.backgnd = 0;
9830 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9831 pipenode->npipe.cmdlist = lp;
9832 lp->n = n1;
9833 do {
9834 prev = lp;
9835 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9836 checkkwd = 2;
9837 lp->n = command();
9838 prev->next = lp;
9839 } while (readtoken() == TPIPE);
9840 lp->next = NULL;
9841 n1 = pipenode;
9842 }
9843 tokpushback++;
9844 if (negate) {
9845 n2 = (union node *)stalloc(sizeof (struct nnot));
9846 n2->type = NNOT;
9847 n2->nnot.com = n1;
9848 return n2;
9849 } else
9850 return n1;
9851}
9852
9853
9854
9855static union node *
9856command() {
9857 union node *n1, *n2;
9858 union node *ap, **app;
9859 union node *cp, **cpp;
9860 union node *redir, **rpp;
9861 int t;
9862
9863 redir = NULL;
9864 n1 = NULL;
9865 rpp = &redir;
9866
9867 switch (readtoken()) {
9868 case TIF:
9869 n1 = (union node *)stalloc(sizeof (struct nif));
9870 n1->type = NIF;
9871 n1->nif.test = list(0);
9872 if (readtoken() != TTHEN)
9873 synexpect(TTHEN);
9874 n1->nif.ifpart = list(0);
9875 n2 = n1;
9876 while (readtoken() == TELIF) {
9877 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
9878 n2 = n2->nif.elsepart;
9879 n2->type = NIF;
9880 n2->nif.test = list(0);
9881 if (readtoken() != TTHEN)
9882 synexpect(TTHEN);
9883 n2->nif.ifpart = list(0);
9884 }
9885 if (lasttoken == TELSE)
9886 n2->nif.elsepart = list(0);
9887 else {
9888 n2->nif.elsepart = NULL;
9889 tokpushback++;
9890 }
9891 if (readtoken() != TFI)
9892 synexpect(TFI);
9893 checkkwd = 1;
9894 break;
9895 case TWHILE:
9896 case TUNTIL: {
9897 int got;
9898 n1 = (union node *)stalloc(sizeof (struct nbinary));
9899 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
9900 n1->nbinary.ch1 = list(0);
9901 if ((got=readtoken()) != TDO) {
9902TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
9903 synexpect(TDO);
9904 }
9905 n1->nbinary.ch2 = list(0);
9906 if (readtoken() != TDONE)
9907 synexpect(TDONE);
9908 checkkwd = 1;
9909 break;
9910 }
9911 case TFOR:
9912 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9913 synerror("Bad for loop variable");
9914 n1 = (union node *)stalloc(sizeof (struct nfor));
9915 n1->type = NFOR;
9916 n1->nfor.var = wordtext;
9917 checkkwd = 1;
9918 if (readtoken() == TIN) {
9919 app = &ap;
9920 while (readtoken() == TWORD) {
9921 n2 = (union node *)stalloc(sizeof (struct narg));
9922 n2->type = NARG;
9923 n2->narg.text = wordtext;
9924 n2->narg.backquote = backquotelist;
9925 *app = n2;
9926 app = &n2->narg.next;
9927 }
9928 *app = NULL;
9929 n1->nfor.args = ap;
9930 if (lasttoken != TNL && lasttoken != TSEMI)
9931 synexpect(-1);
9932 } else {
9933 static char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
9934 '@', '=', '\0'};
9935 n2 = (union node *)stalloc(sizeof (struct narg));
9936 n2->type = NARG;
9937 n2->narg.text = argvars;
9938 n2->narg.backquote = NULL;
9939 n2->narg.next = NULL;
9940 n1->nfor.args = n2;
9941 /*
9942 * Newline or semicolon here is optional (but note
9943 * that the original Bourne shell only allowed NL).
9944 */
9945 if (lasttoken != TNL && lasttoken != TSEMI)
9946 tokpushback++;
9947 }
9948 checkkwd = 2;
9949 if (readtoken() != TDO)
9950 synexpect(TDO);
9951 n1->nfor.body = list(0);
9952 if (readtoken() != TDONE)
9953 synexpect(TDONE);
9954 checkkwd = 1;
9955 break;
9956 case TCASE:
9957 n1 = (union node *)stalloc(sizeof (struct ncase));
9958 n1->type = NCASE;
9959 if (readtoken() != TWORD)
9960 synexpect(TWORD);
9961 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
9962 n2->type = NARG;
9963 n2->narg.text = wordtext;
9964 n2->narg.backquote = backquotelist;
9965 n2->narg.next = NULL;
9966 do {
9967 checkkwd = 1;
9968 } while (readtoken() == TNL);
9969 if (lasttoken != TIN)
9970 synerror("expecting \"in\"");
9971 cpp = &n1->ncase.cases;
9972 checkkwd = 2, readtoken();
9973 do {
9974 if (lasttoken == TLP)
9975 readtoken();
9976 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
9977 cp->type = NCLIST;
9978 app = &cp->nclist.pattern;
9979 for (;;) {
9980 *app = ap = (union node *)stalloc(sizeof (struct narg));
9981 ap->type = NARG;
9982 ap->narg.text = wordtext;
9983 ap->narg.backquote = backquotelist;
9984 if (checkkwd = 2, readtoken() != TPIPE)
9985 break;
9986 app = &ap->narg.next;
9987 readtoken();
9988 }
9989 ap->narg.next = NULL;
9990 if (lasttoken != TRP)
9991 synexpect(TRP);
9992 cp->nclist.body = list(0);
9993
9994 checkkwd = 2;
9995 if ((t = readtoken()) != TESAC) {
9996 if (t != TENDCASE)
9997 synexpect(TENDCASE);
9998 else
9999 checkkwd = 2, readtoken();
10000 }
10001 cpp = &cp->nclist.next;
10002 } while(lasttoken != TESAC);
10003 *cpp = NULL;
10004 checkkwd = 1;
10005 break;
10006 case TLP:
10007 n1 = (union node *)stalloc(sizeof (struct nredir));
10008 n1->type = NSUBSHELL;
10009 n1->nredir.n = list(0);
10010 n1->nredir.redirect = NULL;
10011 if (readtoken() != TRP)
10012 synexpect(TRP);
10013 checkkwd = 1;
10014 break;
10015 case TBEGIN:
10016 n1 = list(0);
10017 if (readtoken() != TEND)
10018 synexpect(TEND);
10019 checkkwd = 1;
10020 break;
10021 /* Handle an empty command like other simple commands. */
10022 case TSEMI:
10023 case TAND:
10024 case TOR:
10025 case TNL:
10026 case TEOF:
10027 case TRP:
10028 case TBACKGND:
10029 /*
10030 * An empty command before a ; doesn't make much sense, and
10031 * should certainly be disallowed in the case of `if ;'.
10032 */
10033 if (!redir)
10034 synexpect(-1);
10035 case TWORD:
10036 case TREDIR:
10037 tokpushback++;
10038 n1 = simplecmd();
10039 return n1;
10040 default:
10041 synexpect(-1);
10042 /* NOTREACHED */
10043 }
10044
10045 /* Now check for redirection which may follow command */
10046 while (readtoken() == TREDIR) {
10047 *rpp = n2 = redirnode;
10048 rpp = &n2->nfile.next;
10049 parsefname();
10050 }
10051 tokpushback++;
10052 *rpp = NULL;
10053 if (redir) {
10054 if (n1->type != NSUBSHELL) {
10055 n2 = (union node *)stalloc(sizeof (struct nredir));
10056 n2->type = NREDIR;
10057 n2->nredir.n = n1;
10058 n1 = n2;
10059 }
10060 n1->nredir.redirect = redir;
10061 }
10062
10063 return n1;
10064}
10065
10066
10067static union node *
10068simplecmd() {
10069 union node *args, **app;
10070 union node *n = NULL;
10071 union node *vars, **vpp;
10072 union node **rpp, *redir;
10073
10074 args = NULL;
10075 app = &args;
10076 vars = NULL;
10077 vpp = &vars;
10078 redir = NULL;
10079 rpp = &redir;
10080
Eric Andersen2870d962001-07-02 17:27:21 +000010081#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010082 checkalias = 2;
Eric Andersen2870d962001-07-02 17:27:21 +000010083#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010084 for (;;) {
10085 switch (readtoken()) {
10086 case TWORD:
10087 case TASSIGN:
10088 n = (union node *)stalloc(sizeof (struct narg));
10089 n->type = NARG;
10090 n->narg.text = wordtext;
10091 n->narg.backquote = backquotelist;
10092 if (lasttoken == TWORD) {
10093 *app = n;
10094 app = &n->narg.next;
10095 } else {
10096 *vpp = n;
10097 vpp = &n->narg.next;
10098 }
10099 break;
10100 case TREDIR:
10101 *rpp = n = redirnode;
10102 rpp = &n->nfile.next;
Eric Andersen2870d962001-07-02 17:27:21 +000010103 parsefname(); /* read name of redirection file */
Eric Andersencb57d552001-06-28 07:25:16 +000010104 break;
10105 case TLP:
10106 if (
10107 args && app == &args->narg.next &&
10108 !vars && !redir
10109 ) {
10110 /* We have a function */
10111 if (readtoken() != TRP)
10112 synexpect(TRP);
Eric Andersencb57d552001-06-28 07:25:16 +000010113 n->type = NDEFUN;
10114 checkkwd = 2;
10115 n->narg.next = command();
10116 return n;
10117 }
10118 /* fall through */
10119 default:
10120 tokpushback++;
10121 goto out;
10122 }
10123 }
10124out:
10125 *app = NULL;
10126 *vpp = NULL;
10127 *rpp = NULL;
10128 n = (union node *)stalloc(sizeof (struct ncmd));
10129 n->type = NCMD;
10130 n->ncmd.backgnd = 0;
10131 n->ncmd.args = args;
10132 n->ncmd.assign = vars;
10133 n->ncmd.redirect = redir;
10134 return n;
10135}
10136
10137static union node *
Eric Andersen2870d962001-07-02 17:27:21 +000010138makename(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000010139 union node *n;
10140
10141 n = (union node *)stalloc(sizeof (struct narg));
10142 n->type = NARG;
10143 n->narg.next = NULL;
10144 n->narg.text = wordtext;
10145 n->narg.backquote = backquotelist;
10146 return n;
10147}
10148
10149static void fixredir(union node *n, const char *text, int err)
Eric Andersen2870d962001-07-02 17:27:21 +000010150{
Eric Andersencb57d552001-06-28 07:25:16 +000010151 TRACE(("Fix redir %s %d\n", text, err));
10152 if (!err)
10153 n->ndup.vname = NULL;
10154
10155 if (is_digit(text[0]) && text[1] == '\0')
10156 n->ndup.dupfd = digit_val(text[0]);
10157 else if (text[0] == '-' && text[1] == '\0')
10158 n->ndup.dupfd = -1;
10159 else {
10160
10161 if (err)
10162 synerror("Bad fd number");
10163 else
10164 n->ndup.vname = makename();
10165 }
10166}
10167
10168
10169static void
Eric Andersen2870d962001-07-02 17:27:21 +000010170parsefname(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000010171 union node *n = redirnode;
10172
10173 if (readtoken() != TWORD)
10174 synexpect(-1);
10175 if (n->type == NHERE) {
10176 struct heredoc *here = heredoc;
10177 struct heredoc *p;
10178 int i;
10179
10180 if (quoteflag == 0)
10181 n->type = NXHERE;
10182 TRACE(("Here document %d\n", n->type));
10183 if (here->striptabs) {
10184 while (*wordtext == '\t')
10185 wordtext++;
10186 }
10187 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
10188 synerror("Illegal eof marker for << redirection");
10189 rmescapes(wordtext);
10190 here->eofmark = wordtext;
10191 here->next = NULL;
10192 if (heredoclist == NULL)
10193 heredoclist = here;
10194 else {
10195 for (p = heredoclist ; p->next ; p = p->next);
10196 p->next = here;
10197 }
10198 } else if (n->type == NTOFD || n->type == NFROMFD) {
10199 fixredir(n, wordtext, 0);
10200 } else {
10201 n->nfile.fname = makename();
10202 }
10203}
10204
10205
10206/*
10207 * Input any here documents.
10208 */
10209
10210static void
10211parseheredoc() {
10212 struct heredoc *here;
10213 union node *n;
10214
10215 while (heredoclist) {
10216 here = heredoclist;
10217 heredoclist = here->next;
10218 if (needprompt) {
10219 setprompt(2);
10220 needprompt = 0;
10221 }
10222 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
10223 here->eofmark, here->striptabs);
10224 n = (union node *)stalloc(sizeof (struct narg));
10225 n->narg.type = NARG;
10226 n->narg.next = NULL;
10227 n->narg.text = wordtext;
10228 n->narg.backquote = backquotelist;
10229 here->here->nhere.doc = n;
10230 }
10231}
10232
10233static int
10234peektoken() {
10235 int t;
10236
10237 t = readtoken();
10238 tokpushback++;
10239 return (t);
10240}
10241
10242static int
10243readtoken() {
10244 int t;
Eric Andersen2870d962001-07-02 17:27:21 +000010245#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010246 int savecheckkwd = checkkwd;
10247 int savecheckalias = checkalias;
10248 struct alias *ap;
Eric Andersen2870d962001-07-02 17:27:21 +000010249#endif
10250
Eric Andersencb57d552001-06-28 07:25:16 +000010251#ifdef DEBUG
10252 int alreadyseen = tokpushback;
10253#endif
10254
Eric Andersen2870d962001-07-02 17:27:21 +000010255#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010256top:
Eric Andersen2870d962001-07-02 17:27:21 +000010257#endif
10258
Eric Andersencb57d552001-06-28 07:25:16 +000010259 t = xxreadtoken();
Eric Andersen2870d962001-07-02 17:27:21 +000010260
10261#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010262 checkalias = savecheckalias;
Eric Andersen2870d962001-07-02 17:27:21 +000010263#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010264
10265 if (checkkwd) {
10266 /*
10267 * eat newlines
10268 */
10269 if (checkkwd == 2) {
10270 checkkwd = 0;
10271 while (t == TNL) {
10272 parseheredoc();
10273 t = xxreadtoken();
10274 }
10275 }
10276 checkkwd = 0;
10277 /*
10278 * check for keywords
10279 */
10280 if (t == TWORD && !quoteflag)
10281 {
10282 const char *const *pp;
10283
10284 if ((pp = findkwd(wordtext))) {
10285 lasttoken = t = pp - parsekwd + KWDOFFSET;
10286 TRACE(("keyword %s recognized\n", tokname[t]));
10287 goto out;
10288 }
10289 }
10290 }
10291
Eric Andersen2870d962001-07-02 17:27:21 +000010292#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010293 if (t != TWORD) {
10294 if (t != TREDIR) {
10295 checkalias = 0;
10296 }
10297 } else if (checkalias == 2 && isassignment(wordtext)) {
10298 lasttoken = t = TASSIGN;
10299 } else if (checkalias) {
10300 if (!quoteflag && (ap = lookupalias(wordtext, 1)) != NULL) {
10301 if (*ap->val) {
10302 pushstring(ap->val, strlen(ap->val), ap);
10303 }
10304 checkkwd = savecheckkwd;
10305 goto top;
10306 }
10307 checkalias = 0;
10308 }
Eric Andersen2870d962001-07-02 17:27:21 +000010309#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010310out:
10311#ifdef DEBUG
10312 if (!alreadyseen)
10313 TRACE(("token %s %s\n", tokname[t], t == TWORD || t == TASSIGN ? wordtext : ""));
10314 else
10315 TRACE(("reread token %s %s\n", tokname[t], t == TWORD || t == TASSIGN ? wordtext : ""));
10316#endif
10317 return (t);
10318}
10319
10320
10321/*
10322 * Read the next input token.
10323 * If the token is a word, we set backquotelist to the list of cmds in
Eric Andersen2870d962001-07-02 17:27:21 +000010324 * backquotes. We set quoteflag to true if any part of the word was
10325 * quoted.
Eric Andersencb57d552001-06-28 07:25:16 +000010326 * If the token is TREDIR, then we set redirnode to a structure containing
Eric Andersen2870d962001-07-02 17:27:21 +000010327 * the redirection.
Eric Andersencb57d552001-06-28 07:25:16 +000010328 * In all cases, the variable startlinno is set to the number of the line
Eric Andersen2870d962001-07-02 17:27:21 +000010329 * on which the token starts.
Eric Andersencb57d552001-06-28 07:25:16 +000010330 *
10331 * [Change comment: here documents and internal procedures]
10332 * [Readtoken shouldn't have any arguments. Perhaps we should make the
10333 * word parsing code into a separate routine. In this case, readtoken
10334 * doesn't need to have any internal procedures, but parseword does.
10335 * We could also make parseoperator in essence the main routine, and
10336 * have parseword (readtoken1?) handle both words and redirection.]
10337 */
10338
Eric Andersen2870d962001-07-02 17:27:21 +000010339#define RETURN(token) return lasttoken = token
Eric Andersencb57d552001-06-28 07:25:16 +000010340
10341static int
10342xxreadtoken() {
10343 int c;
10344
10345 if (tokpushback) {
10346 tokpushback = 0;
10347 return lasttoken;
10348 }
10349 if (needprompt) {
10350 setprompt(2);
10351 needprompt = 0;
10352 }
10353 startlinno = plinno;
Eric Andersen2870d962001-07-02 17:27:21 +000010354 for (;;) { /* until token or start of word found */
Eric Andersencb57d552001-06-28 07:25:16 +000010355 c = pgetc_macro();
10356 switch (c) {
10357 case ' ': case '\t':
Eric Andersen3102ac42001-07-06 04:26:23 +000010358#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010359 case PEOA:
Eric Andersen3102ac42001-07-06 04:26:23 +000010360#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010361 continue;
10362 case '#':
10363 while ((c = pgetc()) != '\n' && c != PEOF);
10364 pungetc();
10365 continue;
10366 case '\\':
10367 if (pgetc() == '\n') {
10368 startlinno = ++plinno;
10369 if (doprompt)
10370 setprompt(2);
10371 else
10372 setprompt(0);
10373 continue;
10374 }
10375 pungetc();
10376 goto breakloop;
10377 case '\n':
10378 plinno++;
10379 needprompt = doprompt;
10380 RETURN(TNL);
10381 case PEOF:
10382 RETURN(TEOF);
10383 case '&':
10384 if (pgetc() == '&')
10385 RETURN(TAND);
10386 pungetc();
10387 RETURN(TBACKGND);
10388 case '|':
10389 if (pgetc() == '|')
10390 RETURN(TOR);
10391 pungetc();
10392 RETURN(TPIPE);
10393 case ';':
10394 if (pgetc() == ';')
10395 RETURN(TENDCASE);
10396 pungetc();
10397 RETURN(TSEMI);
10398 case '(':
10399 RETURN(TLP);
10400 case ')':
10401 RETURN(TRP);
10402 default:
10403 goto breakloop;
10404 }
10405 }
10406breakloop:
10407 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10408#undef RETURN
10409}
10410
10411
10412
10413/*
10414 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10415 * is not NULL, read a here document. In the latter case, eofmark is the
10416 * word which marks the end of the document and striptabs is true if
10417 * leading tabs should be stripped from the document. The argument firstc
10418 * is the first character of the input token or document.
10419 *
10420 * Because C does not have internal subroutines, I have simulated them
10421 * using goto's to implement the subroutine linkage. The following macros
10422 * will run code that appears at the end of readtoken1.
10423 */
10424
Eric Andersen2870d962001-07-02 17:27:21 +000010425#define CHECKEND() {goto checkend; checkend_return:;}
10426#define PARSEREDIR() {goto parseredir; parseredir_return:;}
10427#define PARSESUB() {goto parsesub; parsesub_return:;}
10428#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10429#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10430#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000010431
10432static int
10433readtoken1(firstc, syntax, eofmark, striptabs)
10434 int firstc;
10435 char const *syntax;
10436 char *eofmark;
10437 int striptabs;
10438 {
10439 int c = firstc;
10440 char *out;
10441 int len;
10442 char line[EOFMARKLEN + 1];
10443 struct nodelist *bqlist;
10444 int quotef;
10445 int dblquote;
Eric Andersen2870d962001-07-02 17:27:21 +000010446 int varnest; /* levels of variables expansion */
10447 int arinest; /* levels of arithmetic expansion */
10448 int parenlevel; /* levels of parens in arithmetic */
10449 int dqvarnest; /* levels of variables expansion within double quotes */
Eric Andersencb57d552001-06-28 07:25:16 +000010450 int oldstyle;
Eric Andersen2870d962001-07-02 17:27:21 +000010451 char const *prevsyntax; /* syntax before arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010452#if __GNUC__
10453 /* Avoid longjmp clobbering */
10454 (void) &out;
10455 (void) &quotef;
10456 (void) &dblquote;
10457 (void) &varnest;
10458 (void) &arinest;
10459 (void) &parenlevel;
10460 (void) &dqvarnest;
10461 (void) &oldstyle;
10462 (void) &prevsyntax;
10463 (void) &syntax;
10464#endif
10465
10466 startlinno = plinno;
10467 dblquote = 0;
10468 if (syntax == DQSYNTAX)
10469 dblquote = 1;
10470 quotef = 0;
10471 bqlist = NULL;
10472 varnest = 0;
10473 arinest = 0;
10474 parenlevel = 0;
10475 dqvarnest = 0;
10476
10477 STARTSTACKSTR(out);
Eric Andersen2870d962001-07-02 17:27:21 +000010478 loop: { /* for each line, until end of word */
10479 CHECKEND(); /* set c to PEOF if at end of here document */
10480 for (;;) { /* until end of line or end of word */
10481 CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */
Eric Andersencb57d552001-06-28 07:25:16 +000010482 switch(syntax[c]) {
Eric Andersen2870d962001-07-02 17:27:21 +000010483 case CNL: /* '\n' */
Eric Andersencb57d552001-06-28 07:25:16 +000010484 if (syntax == BASESYNTAX)
Eric Andersen2870d962001-07-02 17:27:21 +000010485 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010486 USTPUTC(c, out);
10487 plinno++;
10488 if (doprompt)
10489 setprompt(2);
10490 else
10491 setprompt(0);
10492 c = pgetc();
Eric Andersen2870d962001-07-02 17:27:21 +000010493 goto loop; /* continue outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010494 case CWORD:
10495 USTPUTC(c, out);
10496 break;
10497 case CCTL:
10498 if ((eofmark == NULL || dblquote) &&
10499 dqvarnest == 0)
10500 USTPUTC(CTLESC, out);
10501 USTPUTC(c, out);
10502 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010503 case CBACK: /* backslash */
Eric Andersencb57d552001-06-28 07:25:16 +000010504 c = pgetc2();
10505 if (c == PEOF) {
10506 USTPUTC('\\', out);
10507 pungetc();
10508 } else if (c == '\n') {
10509 if (doprompt)
10510 setprompt(2);
10511 else
10512 setprompt(0);
10513 } else {
10514 if (dblquote && c != '\\' && c != '`' && c != '$'
10515 && (c != '"' || eofmark != NULL))
10516 USTPUTC('\\', out);
10517 if (SQSYNTAX[c] == CCTL)
10518 USTPUTC(CTLESC, out);
10519 else if (eofmark == NULL)
10520 USTPUTC(CTLQUOTEMARK, out);
10521 USTPUTC(c, out);
10522 quotef++;
10523 }
10524 break;
10525 case CSQUOTE:
10526 if (eofmark == NULL)
10527 USTPUTC(CTLQUOTEMARK, out);
10528 syntax = SQSYNTAX;
10529 break;
10530 case CDQUOTE:
10531 if (eofmark == NULL)
10532 USTPUTC(CTLQUOTEMARK, out);
10533 syntax = DQSYNTAX;
10534 dblquote = 1;
10535 break;
10536 case CENDQUOTE:
10537 if (eofmark != NULL && arinest == 0 &&
10538 varnest == 0) {
10539 USTPUTC(c, out);
10540 } else {
10541 if (arinest) {
10542 syntax = ARISYNTAX;
10543 dblquote = 0;
10544 } else if (eofmark == NULL &&
10545 dqvarnest == 0) {
10546 syntax = BASESYNTAX;
10547 dblquote = 0;
10548 }
10549 quotef++;
10550 }
10551 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010552 case CVAR: /* '$' */
10553 PARSESUB(); /* parse substitution */
Eric Andersencb57d552001-06-28 07:25:16 +000010554 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010555 case CENDVAR: /* '}' */
Eric Andersencb57d552001-06-28 07:25:16 +000010556 if (varnest > 0) {
10557 varnest--;
10558 if (dqvarnest > 0) {
10559 dqvarnest--;
10560 }
10561 USTPUTC(CTLENDVAR, out);
10562 } else {
10563 USTPUTC(c, out);
10564 }
10565 break;
10566#ifdef ASH_MATH_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +000010567 case CLP: /* '(' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010568 parenlevel++;
10569 USTPUTC(c, out);
10570 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010571 case CRP: /* ')' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010572 if (parenlevel > 0) {
10573 USTPUTC(c, out);
10574 --parenlevel;
10575 } else {
10576 if (pgetc() == ')') {
10577 if (--arinest == 0) {
10578 USTPUTC(CTLENDARI, out);
10579 syntax = prevsyntax;
10580 if (syntax == DQSYNTAX)
10581 dblquote = 1;
10582 else
10583 dblquote = 0;
10584 } else
10585 USTPUTC(')', out);
10586 } else {
10587 /*
10588 * unbalanced parens
10589 * (don't 2nd guess - no error)
10590 */
10591 pungetc();
10592 USTPUTC(')', out);
10593 }
10594 }
10595 break;
10596#endif
Eric Andersen2870d962001-07-02 17:27:21 +000010597 case CBQUOTE: /* '`' */
Eric Andersencb57d552001-06-28 07:25:16 +000010598 PARSEBACKQOLD();
10599 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010600 case CENDFILE:
10601 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010602 case CIGN:
10603 break;
10604 default:
10605 if (varnest == 0)
Eric Andersen2870d962001-07-02 17:27:21 +000010606 goto endword; /* exit outer loop */
Eric Andersen3102ac42001-07-06 04:26:23 +000010607#ifdef ASH_ALIAS
10608 if (c != PEOA)
10609#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010610 USTPUTC(c, out);
Eric Andersen3102ac42001-07-06 04:26:23 +000010611
Eric Andersencb57d552001-06-28 07:25:16 +000010612 }
10613 c = pgetc_macro();
10614 }
10615 }
10616endword:
10617 if (syntax == ARISYNTAX)
10618 synerror("Missing '))'");
10619 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10620 synerror("Unterminated quoted string");
10621 if (varnest != 0) {
10622 startlinno = plinno;
10623 synerror("Missing '}'");
10624 }
10625 USTPUTC('\0', out);
10626 len = out - stackblock();
10627 out = stackblock();
10628 if (eofmark == NULL) {
10629 if ((c == '>' || c == '<')
10630 && quotef == 0
10631 && len <= 2
10632 && (*out == '\0' || is_digit(*out))) {
10633 PARSEREDIR();
10634 return lasttoken = TREDIR;
10635 } else {
10636 pungetc();
10637 }
10638 }
10639 quoteflag = quotef;
10640 backquotelist = bqlist;
10641 grabstackblock(len);
10642 wordtext = out;
10643 return lasttoken = TWORD;
10644/* end of readtoken routine */
10645
10646
10647
10648/*
10649 * Check to see whether we are at the end of the here document. When this
10650 * is called, c is set to the first character of the next input line. If
10651 * we are at the end of the here document, this routine sets the c to PEOF.
10652 */
10653
10654checkend: {
10655 if (eofmark) {
Eric Andersen2870d962001-07-02 17:27:21 +000010656#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010657 if (c == PEOA) {
10658 c = pgetc2();
10659 }
Eric Andersen2870d962001-07-02 17:27:21 +000010660#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010661 if (striptabs) {
10662 while (c == '\t') {
10663 c = pgetc2();
10664 }
10665 }
10666 if (c == *eofmark) {
10667 if (pfgets(line, sizeof line) != NULL) {
10668 char *p, *q;
10669
10670 p = line;
10671 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10672 if (*p == '\n' && *q == '\0') {
10673 c = PEOF;
10674 plinno++;
10675 needprompt = doprompt;
10676 } else {
10677 pushstring(line, strlen(line), NULL);
10678 }
10679 }
10680 }
10681 }
10682 goto checkend_return;
10683}
10684
10685
10686/*
10687 * Parse a redirection operator. The variable "out" points to a string
10688 * specifying the fd to be redirected. The variable "c" contains the
10689 * first character of the redirection operator.
10690 */
10691
10692parseredir: {
10693 char fd = *out;
10694 union node *np;
10695
10696 np = (union node *)stalloc(sizeof (struct nfile));
10697 if (c == '>') {
10698 np->nfile.fd = 1;
10699 c = pgetc();
10700 if (c == '>')
10701 np->type = NAPPEND;
10702 else if (c == '&')
10703 np->type = NTOFD;
10704 else if (c == '|')
10705 np->type = NTOOV;
10706 else {
10707 np->type = NTO;
10708 pungetc();
10709 }
Eric Andersen2870d962001-07-02 17:27:21 +000010710 } else { /* c == '<' */
Eric Andersencb57d552001-06-28 07:25:16 +000010711 np->nfile.fd = 0;
10712 switch (c = pgetc()) {
10713 case '<':
10714 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10715 np = (union node *)stalloc(sizeof (struct nhere));
10716 np->nfile.fd = 0;
10717 }
10718 np->type = NHERE;
10719 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10720 heredoc->here = np;
10721 if ((c = pgetc()) == '-') {
10722 heredoc->striptabs = 1;
10723 } else {
10724 heredoc->striptabs = 0;
10725 pungetc();
10726 }
10727 break;
10728
10729 case '&':
10730 np->type = NFROMFD;
10731 break;
10732
10733 case '>':
10734 np->type = NFROMTO;
10735 break;
10736
10737 default:
10738 np->type = NFROM;
10739 pungetc();
10740 break;
10741 }
10742 }
10743 if (fd != '\0')
10744 np->nfile.fd = digit_val(fd);
10745 redirnode = np;
10746 goto parseredir_return;
10747}
10748
10749
10750/*
10751 * Parse a substitution. At this point, we have read the dollar sign
10752 * and nothing else.
10753 */
10754
10755parsesub: {
10756 int subtype;
10757 int typeloc;
10758 int flags;
10759 char *p;
10760 static const char types[] = "}-+?=";
10761
10762 c = pgetc();
10763 if (
10764 c <= PEOA ||
10765 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10766 ) {
10767 USTPUTC('$', out);
10768 pungetc();
Eric Andersen2870d962001-07-02 17:27:21 +000010769 } else if (c == '(') { /* $(command) or $((arith)) */
Eric Andersencb57d552001-06-28 07:25:16 +000010770 if (pgetc() == '(') {
10771 PARSEARITH();
10772 } else {
10773 pungetc();
10774 PARSEBACKQNEW();
10775 }
10776 } else {
10777 USTPUTC(CTLVAR, out);
10778 typeloc = out - stackblock();
10779 USTPUTC(VSNORMAL, out);
10780 subtype = VSNORMAL;
10781 if (c == '{') {
10782 c = pgetc();
10783 if (c == '#') {
10784 if ((c = pgetc()) == '}')
10785 c = '#';
10786 else
10787 subtype = VSLENGTH;
10788 }
10789 else
10790 subtype = 0;
10791 }
10792 if (c > PEOA && is_name(c)) {
10793 do {
10794 STPUTC(c, out);
10795 c = pgetc();
10796 } while (c > PEOA && is_in_name(c));
10797 } else if (is_digit(c)) {
10798 do {
10799 USTPUTC(c, out);
10800 c = pgetc();
10801 } while (is_digit(c));
10802 }
10803 else if (is_special(c)) {
10804 USTPUTC(c, out);
10805 c = pgetc();
10806 }
10807 else
Eric Andersen2870d962001-07-02 17:27:21 +000010808badsub: synerror("Bad substitution");
Eric Andersencb57d552001-06-28 07:25:16 +000010809
10810 STPUTC('=', out);
10811 flags = 0;
10812 if (subtype == 0) {
10813 switch (c) {
10814 case ':':
10815 flags = VSNUL;
10816 c = pgetc();
10817 /*FALLTHROUGH*/
10818 default:
10819 p = strchr(types, c);
10820 if (p == NULL)
10821 goto badsub;
10822 subtype = p - types + VSNORMAL;
10823 break;
10824 case '%':
10825 case '#':
10826 {
10827 int cc = c;
10828 subtype = c == '#' ? VSTRIMLEFT :
10829 VSTRIMRIGHT;
10830 c = pgetc();
10831 if (c == cc)
10832 subtype++;
10833 else
10834 pungetc();
10835 break;
10836 }
10837 }
10838 } else {
10839 pungetc();
10840 }
10841 if (dblquote || arinest)
10842 flags |= VSQUOTE;
10843 *(stackblock() + typeloc) = subtype | flags;
10844 if (subtype != VSNORMAL) {
10845 varnest++;
10846 if (dblquote) {
10847 dqvarnest++;
10848 }
10849 }
10850 }
10851 goto parsesub_return;
10852}
10853
10854
10855/*
10856 * Called to parse command substitutions. Newstyle is set if the command
10857 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10858 * list of commands (passed by reference), and savelen is the number of
10859 * characters on the top of the stack which must be preserved.
10860 */
10861
10862parsebackq: {
10863 struct nodelist **nlpp;
10864 int savepbq;
10865 union node *n;
10866 char *volatile str;
10867 struct jmploc jmploc;
10868 struct jmploc *volatile savehandler;
10869 int savelen;
10870 int saveprompt;
10871#ifdef __GNUC__
10872 (void) &saveprompt;
10873#endif
10874
10875 savepbq = parsebackquote;
10876 if (setjmp(jmploc.loc)) {
10877 if (str)
10878 ckfree(str);
10879 parsebackquote = 0;
10880 handler = savehandler;
10881 longjmp(handler->loc, 1);
10882 }
10883 INTOFF;
10884 str = NULL;
10885 savelen = out - stackblock();
10886 if (savelen > 0) {
10887 str = ckmalloc(savelen);
10888 memcpy(str, stackblock(), savelen);
10889 }
10890 savehandler = handler;
10891 handler = &jmploc;
10892 INTON;
Eric Andersen2870d962001-07-02 17:27:21 +000010893 if (oldstyle) {
10894 /* We must read until the closing backquote, giving special
10895 treatment to some slashes, and then push the string and
10896 reread it as input, interpreting it normally. */
10897 char *pout;
10898 int pc;
10899 int psavelen;
10900 char *pstr;
Eric Andersencb57d552001-06-28 07:25:16 +000010901
10902
Eric Andersen2870d962001-07-02 17:27:21 +000010903 STARTSTACKSTR(pout);
Eric Andersencb57d552001-06-28 07:25:16 +000010904 for (;;) {
10905 if (needprompt) {
10906 setprompt(2);
10907 needprompt = 0;
10908 }
10909 switch (pc = pgetc()) {
10910 case '`':
10911 goto done;
10912
10913 case '\\':
Eric Andersen2870d962001-07-02 17:27:21 +000010914 if ((pc = pgetc()) == '\n') {
Eric Andersencb57d552001-06-28 07:25:16 +000010915 plinno++;
10916 if (doprompt)
10917 setprompt(2);
10918 else
10919 setprompt(0);
10920 /*
10921 * If eating a newline, avoid putting
10922 * the newline into the new character
10923 * stream (via the STPUTC after the
10924 * switch).
10925 */
10926 continue;
10927 }
Eric Andersen2870d962001-07-02 17:27:21 +000010928 if (pc != '\\' && pc != '`' && pc != '$'
10929 && (!dblquote || pc != '"'))
10930 STPUTC('\\', pout);
Eric Andersencb57d552001-06-28 07:25:16 +000010931 if (pc > PEOA) {
10932 break;
10933 }
10934 /* fall through */
10935
10936 case PEOF:
Eric Andersen2870d962001-07-02 17:27:21 +000010937#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010938 case PEOA:
Eric Andersen2870d962001-07-02 17:27:21 +000010939#endif
10940 startlinno = plinno;
Eric Andersencb57d552001-06-28 07:25:16 +000010941 synerror("EOF in backquote substitution");
10942
10943 case '\n':
10944 plinno++;
10945 needprompt = doprompt;
10946 break;
10947
10948 default:
10949 break;
10950 }
10951 STPUTC(pc, pout);
Eric Andersen2870d962001-07-02 17:27:21 +000010952 }
Eric Andersencb57d552001-06-28 07:25:16 +000010953done:
Eric Andersen2870d962001-07-02 17:27:21 +000010954 STPUTC('\0', pout);
10955 psavelen = pout - stackblock();
10956 if (psavelen > 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010957 pstr = grabstackstr(pout);
10958 setinputstring(pstr);
Eric Andersen2870d962001-07-02 17:27:21 +000010959 }
10960 }
Eric Andersencb57d552001-06-28 07:25:16 +000010961 nlpp = &bqlist;
10962 while (*nlpp)
10963 nlpp = &(*nlpp)->next;
10964 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10965 (*nlpp)->next = NULL;
10966 parsebackquote = oldstyle;
10967
10968 if (oldstyle) {
10969 saveprompt = doprompt;
10970 doprompt = 0;
10971 }
10972
10973 n = list(0);
10974
10975 if (oldstyle)
10976 doprompt = saveprompt;
10977 else {
10978 if (readtoken() != TRP)
10979 synexpect(TRP);
10980 }
10981
10982 (*nlpp)->n = n;
Eric Andersen2870d962001-07-02 17:27:21 +000010983 if (oldstyle) {
Eric Andersencb57d552001-06-28 07:25:16 +000010984 /*
10985 * Start reading from old file again, ignoring any pushed back
10986 * tokens left from the backquote parsing
10987 */
Eric Andersen2870d962001-07-02 17:27:21 +000010988 popfile();
Eric Andersencb57d552001-06-28 07:25:16 +000010989 tokpushback = 0;
10990 }
10991 while (stackblocksize() <= savelen)
10992 growstackblock();
10993 STARTSTACKSTR(out);
10994 if (str) {
10995 memcpy(out, str, savelen);
10996 STADJUST(savelen, out);
10997 INTOFF;
10998 ckfree(str);
10999 str = NULL;
11000 INTON;
11001 }
11002 parsebackquote = savepbq;
11003 handler = savehandler;
11004 if (arinest || dblquote)
11005 USTPUTC(CTLBACKQ | CTLQUOTE, out);
11006 else
11007 USTPUTC(CTLBACKQ, out);
11008 if (oldstyle)
11009 goto parsebackq_oldreturn;
11010 else
11011 goto parsebackq_newreturn;
11012}
11013
11014/*
11015 * Parse an arithmetic expansion (indicate start of one and set state)
11016 */
11017parsearith: {
11018
11019 if (++arinest == 1) {
11020 prevsyntax = syntax;
11021 syntax = ARISYNTAX;
11022 USTPUTC(CTLARI, out);
11023 if (dblquote)
11024 USTPUTC('"',out);
11025 else
11026 USTPUTC(' ',out);
11027 } else {
11028 /*
11029 * we collapse embedded arithmetic expansion to
11030 * parenthesis, which should be equivalent
11031 */
11032 USTPUTC('(', out);
11033 }
11034 goto parsearith_return;
11035}
11036
11037} /* end of readtoken */
11038
11039
Eric Andersencb57d552001-06-28 07:25:16 +000011040/*
11041 * Returns true if the text contains nothing to expand (no dollar signs
11042 * or backquotes).
11043 */
11044
11045static int
11046noexpand(text)
11047 char *text;
11048 {
11049 char *p;
11050 char c;
11051
11052 p = text;
11053 while ((c = *p++) != '\0') {
11054 if (c == CTLQUOTEMARK)
11055 continue;
11056 if (c == CTLESC)
11057 p++;
11058 else if (BASESYNTAX[(int)c] == CCTL)
11059 return 0;
11060 }
11061 return 1;
11062}
11063
11064
11065/*
11066 * Return true if the argument is a legal variable name (a letter or
11067 * underscore followed by zero or more letters, underscores, and digits).
11068 */
11069
11070static int
Eric Andersen2870d962001-07-02 17:27:21 +000011071goodname(const char *name)
11072{
11073 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +000011074
11075 p = name;
11076 if (! is_name(*p))
11077 return 0;
11078 while (*++p) {
11079 if (! is_in_name(*p))
11080 return 0;
11081 }
11082 return 1;
11083}
11084
11085
11086/*
11087 * Called when an unexpected token is read during the parse. The argument
11088 * is the token that is expected, or -1 if more than one type of token can
11089 * occur at this point.
11090 */
11091
11092static void
11093synexpect(token)
11094 int token;
11095{
11096 char msg[64];
11097
11098 if (token >= 0) {
Eric Andersen3102ac42001-07-06 04:26:23 +000011099 snprintf(msg, 64, "%s unexpected (expecting %s)",
Eric Andersencb57d552001-06-28 07:25:16 +000011100 tokname[lasttoken], tokname[token]);
11101 } else {
Eric Andersen3102ac42001-07-06 04:26:23 +000011102 snprintf(msg, 64, "%s unexpected", tokname[lasttoken]);
Eric Andersencb57d552001-06-28 07:25:16 +000011103 }
11104 synerror(msg);
11105 /* NOTREACHED */
11106}
11107
11108
11109static void
Eric Andersen2870d962001-07-02 17:27:21 +000011110synerror(const char *msg)
11111{
Eric Andersencb57d552001-06-28 07:25:16 +000011112 if (commandname)
Eric Andersen3102ac42001-07-06 04:26:23 +000011113 out2fmt("%s: %d: ", commandname, startlinno);
11114 out2fmt("Syntax error: %s\n", msg);
Eric Andersencb57d552001-06-28 07:25:16 +000011115 error((char *)NULL);
11116 /* NOTREACHED */
11117}
11118
Eric Andersencb57d552001-06-28 07:25:16 +000011119
11120/*
11121 * called by editline -- any expansions to the prompt
11122 * should be added here.
11123 */
Eric Andersen3102ac42001-07-06 04:26:23 +000011124static inline const char *
Eric Andersencb57d552001-06-28 07:25:16 +000011125getprompt(void *unused)
Eric Andersen2870d962001-07-02 17:27:21 +000011126{
Eric Andersencb57d552001-06-28 07:25:16 +000011127 switch (whichprompt) {
11128 case 0:
11129 return "";
11130 case 1:
11131 return ps1val();
11132 case 2:
11133 return ps2val();
11134 default:
11135 return "<internal prompt error>";
11136 }
11137}
11138
Eric Andersen2870d962001-07-02 17:27:21 +000011139static void
11140setprompt(int which)
11141{
11142 whichprompt = which;
11143 putprompt(getprompt(NULL));
Eric Andersencb57d552001-06-28 07:25:16 +000011144}
11145
Eric Andersencb57d552001-06-28 07:25:16 +000011146
Eric Andersencb57d552001-06-28 07:25:16 +000011147/*
11148 * Code for dealing with input/output redirection.
11149 */
11150
Eric Andersen2870d962001-07-02 17:27:21 +000011151#define EMPTY -2 /* marks an unused slot in redirtab */
Eric Andersencb57d552001-06-28 07:25:16 +000011152#ifndef PIPE_BUF
Eric Andersen2870d962001-07-02 17:27:21 +000011153# define PIPESIZE 4096 /* amount of buffering in a pipe */
Eric Andersencb57d552001-06-28 07:25:16 +000011154#else
11155# define PIPESIZE PIPE_BUF
11156#endif
11157
11158
Eric Andersencb57d552001-06-28 07:25:16 +000011159
11160/*
11161 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11162 * old file descriptors are stashed away so that the redirection can be
11163 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11164 * standard output, and the standard error if it becomes a duplicate of
Eric Andersen3102ac42001-07-06 04:26:23 +000011165 * stdout.
Eric Andersencb57d552001-06-28 07:25:16 +000011166 */
11167
11168static void
11169redirect(redir, flags)
11170 union node *redir;
11171 int flags;
11172 {
11173 union node *n;
11174 struct redirtab *sv = NULL;
11175 int i;
11176 int fd;
11177 int newfd;
11178 int try;
Eric Andersen2870d962001-07-02 17:27:21 +000011179 char memory[10]; /* file descriptors to write to memory */
Eric Andersencb57d552001-06-28 07:25:16 +000011180
11181 for (i = 10 ; --i >= 0 ; )
11182 memory[i] = 0;
11183 memory[1] = flags & REDIR_BACKQ;
11184 if (flags & REDIR_PUSH) {
11185 sv = ckmalloc(sizeof (struct redirtab));
11186 for (i = 0 ; i < 10 ; i++)
11187 sv->renamed[i] = EMPTY;
11188 sv->next = redirlist;
11189 redirlist = sv;
11190 }
11191 for (n = redir ; n ; n = n->nfile.next) {
11192 fd = n->nfile.fd;
11193 try = 0;
11194 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
11195 n->ndup.dupfd == fd)
11196 continue; /* redirect from/to same file descriptor */
11197
11198 INTOFF;
11199 newfd = openredirect(n);
Eric Andersen3102ac42001-07-06 04:26:23 +000011200 if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
Eric Andersencb57d552001-06-28 07:25:16 +000011201 if (newfd == fd) {
11202 try++;
11203 } else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
11204 switch (errno) {
11205 case EBADF:
11206 if (!try) {
11207 dupredirect(n, newfd, memory);
11208 try++;
11209 break;
11210 }
11211 /* FALLTHROUGH*/
11212 default:
11213 if (newfd >= 0) {
11214 close(newfd);
11215 }
11216 INTON;
Eric Andersen2870d962001-07-02 17:27:21 +000011217 error("%d: %m", fd);
Eric Andersencb57d552001-06-28 07:25:16 +000011218 /* NOTREACHED */
11219 }
11220 }
11221 if (!try) {
11222 close(fd);
11223 if (flags & REDIR_PUSH) {
11224 sv->renamed[fd] = i;
11225 }
Eric Andersencb57d552001-06-28 07:25:16 +000011226 }
11227 } else if (fd != newfd) {
11228 close(fd);
11229 }
Eric Andersen2870d962001-07-02 17:27:21 +000011230 if (fd == 0)
11231 fd0_redirected++;
Eric Andersencb57d552001-06-28 07:25:16 +000011232 if (!try)
11233 dupredirect(n, newfd, memory);
11234 INTON;
11235 }
Eric Andersencb57d552001-06-28 07:25:16 +000011236}
11237
11238
11239static int
11240openredirect(redir)
11241 union node *redir;
11242 {
11243 char *fname;
11244 int f;
11245
11246 switch (redir->nfile.type) {
11247 case NFROM:
11248 fname = redir->nfile.expfname;
11249 if ((f = open(fname, O_RDONLY)) < 0)
11250 goto eopen;
11251 break;
11252 case NFROMTO:
11253 fname = redir->nfile.expfname;
11254 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
11255 goto ecreate;
11256 break;
11257 case NTO:
11258 /* Take care of noclobber mode. */
11259 if (Cflag) {
11260 fname = redir->nfile.expfname;
11261 if ((f = noclobberopen(fname)) < 0)
11262 goto ecreate;
11263 break;
11264 }
11265 case NTOOV:
11266 fname = redir->nfile.expfname;
11267#ifdef O_CREAT
11268 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
11269 goto ecreate;
11270#else
11271 if ((f = creat(fname, 0666)) < 0)
11272 goto ecreate;
11273#endif
11274 break;
11275 case NAPPEND:
11276 fname = redir->nfile.expfname;
11277#ifdef O_APPEND
11278 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
11279 goto ecreate;
11280#else
11281 if ((f = open(fname, O_WRONLY)) < 0
11282 && (f = creat(fname, 0666)) < 0)
11283 goto ecreate;
11284 lseek(f, (off_t)0, 2);
11285#endif
11286 break;
11287 default:
11288#ifdef DEBUG
11289 abort();
11290#endif
11291 /* Fall through to eliminate warning. */
11292 case NTOFD:
11293 case NFROMFD:
11294 f = -1;
11295 break;
11296 case NHERE:
11297 case NXHERE:
11298 f = openhere(redir);
11299 break;
11300 }
11301
11302 return f;
11303ecreate:
11304 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
11305eopen:
11306 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11307}
11308
11309
11310static void
Eric Andersen2870d962001-07-02 17:27:21 +000011311dupredirect(union node *redir, int f, char memory[10])
11312{
Eric Andersencb57d552001-06-28 07:25:16 +000011313 int fd = redir->nfile.fd;
11314
11315 memory[fd] = 0;
11316 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Eric Andersen2870d962001-07-02 17:27:21 +000011317 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
Eric Andersencb57d552001-06-28 07:25:16 +000011318 if (memory[redir->ndup.dupfd])
11319 memory[fd] = 1;
11320 else
11321 dup_as_newfd(redir->ndup.dupfd, fd);
11322 }
11323 return;
11324 }
11325
11326 if (f != fd) {
11327 dup_as_newfd(f, fd);
11328 close(f);
11329 }
11330 return;
11331}
11332
11333
11334/*
11335 * Handle here documents. Normally we fork off a process to write the
11336 * data to a pipe. If the document is short, we can stuff the data in
11337 * the pipe without forking.
11338 */
11339
11340static int
11341openhere(redir)
11342 union node *redir;
11343 {
11344 int pip[2];
11345 int len = 0;
11346
11347 if (pipe(pip) < 0)
11348 error("Pipe call failed");
11349 if (redir->type == NHERE) {
11350 len = strlen(redir->nhere.doc->narg.text);
11351 if (len <= PIPESIZE) {
11352 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11353 goto out;
11354 }
11355 }
11356 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
11357 close(pip[0]);
11358 signal(SIGINT, SIG_IGN);
11359 signal(SIGQUIT, SIG_IGN);
11360 signal(SIGHUP, SIG_IGN);
11361#ifdef SIGTSTP
11362 signal(SIGTSTP, SIG_IGN);
11363#endif
11364 signal(SIGPIPE, SIG_DFL);
11365 if (redir->type == NHERE)
11366 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11367 else
11368 expandhere(redir->nhere.doc, pip[1]);
11369 _exit(0);
11370 }
11371out:
11372 close(pip[1]);
11373 return pip[0];
11374}
11375
11376
Eric Andersencb57d552001-06-28 07:25:16 +000011377/*
11378 * Undo the effects of the last redirection.
11379 */
11380
11381static void
Eric Andersen2870d962001-07-02 17:27:21 +000011382popredir(void)
11383{
Eric Andersencb57d552001-06-28 07:25:16 +000011384 struct redirtab *rp = redirlist;
11385 int i;
11386
11387 INTOFF;
11388 for (i = 0 ; i < 10 ; i++) {
11389 if (rp->renamed[i] != EMPTY) {
Eric Andersen2870d962001-07-02 17:27:21 +000011390 if (i == 0)
11391 fd0_redirected--;
Eric Andersencb57d552001-06-28 07:25:16 +000011392 close(i);
11393 if (rp->renamed[i] >= 0) {
11394 dup_as_newfd(rp->renamed[i], i);
11395 close(rp->renamed[i]);
11396 }
Eric Andersencb57d552001-06-28 07:25:16 +000011397 }
11398 }
11399 redirlist = rp->next;
11400 ckfree(rp);
11401 INTON;
11402}
11403
11404/*
Eric Andersencb57d552001-06-28 07:25:16 +000011405 * Discard all saved file descriptors.
11406 */
11407
11408static void
Eric Andersen2870d962001-07-02 17:27:21 +000011409clearredir(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000011410 struct redirtab *rp;
11411 int i;
11412
11413 for (rp = redirlist ; rp ; rp = rp->next) {
11414 for (i = 0 ; i < 10 ; i++) {
11415 if (rp->renamed[i] >= 0) {
11416 close(rp->renamed[i]);
Eric Andersencb57d552001-06-28 07:25:16 +000011417 }
11418 rp->renamed[i] = EMPTY;
11419 }
11420 }
Eric Andersencb57d552001-06-28 07:25:16 +000011421}
11422
11423
Eric Andersencb57d552001-06-28 07:25:16 +000011424/*
11425 * Copy a file descriptor to be >= to. Returns -1
11426 * if the source file descriptor is closed, EMPTY if there are no unused
11427 * file descriptors left.
11428 */
11429
11430static int
11431dup_as_newfd(from, to)
11432 int from;
11433 int to;
11434{
11435 int newfd;
11436
11437 newfd = fcntl(from, F_DUPFD, to);
11438 if (newfd < 0) {
11439 if (errno == EMFILE)
11440 return EMPTY;
11441 else
Eric Andersen2870d962001-07-02 17:27:21 +000011442 error("%d: %m", from);
Eric Andersencb57d552001-06-28 07:25:16 +000011443 }
11444 return newfd;
11445}
11446
11447/*
11448 * Open a file in noclobber mode.
11449 * The code was copied from bash.
11450 */
11451static int
Eric Andersen2870d962001-07-02 17:27:21 +000011452noclobberopen(const char *fname)
Eric Andersencb57d552001-06-28 07:25:16 +000011453{
11454 int r, fd;
11455 struct stat finfo, finfo2;
11456
11457 /*
11458 * If the file exists and is a regular file, return an error
11459 * immediately.
11460 */
11461 r = stat(fname, &finfo);
11462 if (r == 0 && S_ISREG(finfo.st_mode)) {
11463 errno = EEXIST;
11464 return -1;
11465 }
11466
11467 /*
11468 * If the file was not present (r != 0), make sure we open it
11469 * exclusively so that if it is created before we open it, our open
11470 * will fail. Make sure that we do not truncate an existing file.
11471 * Note that we don't turn on O_EXCL unless the stat failed -- if the
11472 * file was not a regular file, we leave O_EXCL off.
11473 */
11474 if (r != 0)
11475 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
11476 fd = open(fname, O_WRONLY|O_CREAT, 0666);
11477
11478 /* If the open failed, return the file descriptor right away. */
11479 if (fd < 0)
11480 return fd;
11481
11482 /*
11483 * OK, the open succeeded, but the file may have been changed from a
11484 * non-regular file to a regular file between the stat and the open.
11485 * We are assuming that the O_EXCL open handles the case where FILENAME
11486 * did not exist and is symlinked to an existing file between the stat
11487 * and open.
11488 */
11489
11490 /*
11491 * If we can open it and fstat the file descriptor, and neither check
11492 * revealed that it was a regular file, and the file has not been
11493 * replaced, return the file descriptor.
11494 */
11495 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
11496 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
Eric Andersen2870d962001-07-02 17:27:21 +000011497 return fd;
Eric Andersencb57d552001-06-28 07:25:16 +000011498
11499 /* The file has been replaced. badness. */
11500 close(fd);
11501 errno = EEXIST;
11502 return -1;
11503}
Eric Andersen2870d962001-07-02 17:27:21 +000011504/*#ifdef __weak_alias
Eric Andersencb57d552001-06-28 07:25:16 +000011505__weak_alias(getmode,_getmode)
11506__weak_alias(setmode,_setmode)
Eric Andersen2870d962001-07-02 17:27:21 +000011507#endif*/
Eric Andersencb57d552001-06-28 07:25:16 +000011508
11509#ifdef __GLIBC__
11510#define S_ISTXT __S_ISVTX
11511#endif
11512
Eric Andersen2870d962001-07-02 17:27:21 +000011513#define SET_LEN 6 /* initial # of bitcmd struct to malloc */
11514#define SET_LEN_INCR 4 /* # of bitcmd structs to add as needed */
Eric Andersencb57d552001-06-28 07:25:16 +000011515
11516typedef struct bitcmd {
Eric Andersen2870d962001-07-02 17:27:21 +000011517 char cmd;
11518 char cmd2;
11519 mode_t bits;
Eric Andersencb57d552001-06-28 07:25:16 +000011520} BITCMD;
11521
Eric Andersen2870d962001-07-02 17:27:21 +000011522#define CMD2_CLR 0x01
11523#define CMD2_SET 0x02
11524#define CMD2_GBITS 0x04
11525#define CMD2_OBITS 0x08
11526#define CMD2_UBITS 0x10
Eric Andersencb57d552001-06-28 07:25:16 +000011527
Eric Andersen2870d962001-07-02 17:27:21 +000011528static BITCMD *addcmd (BITCMD *, int, int, int, u_int);
11529static void compress_mode (BITCMD *);
Eric Andersencb57d552001-06-28 07:25:16 +000011530#ifdef SETMODE_DEBUG
Eric Andersen2870d962001-07-02 17:27:21 +000011531static void dumpmode (BITCMD *);
Eric Andersencb57d552001-06-28 07:25:16 +000011532#endif
11533
11534/*
11535 * Given the old mode and an array of bitcmd structures, apply the operations
11536 * described in the bitcmd structures to the old mode, and return the new mode.
11537 * Note that there is no '=' command; a strict assignment is just a '-' (clear
11538 * bits) followed by a '+' (set bits).
11539 */
Eric Andersen2870d962001-07-02 17:27:21 +000011540static mode_t
Eric Andersencb57d552001-06-28 07:25:16 +000011541getmode(bbox, omode)
11542 const void *bbox;
11543 mode_t omode;
11544{
11545 const BITCMD *set;
11546 mode_t clrval, newmode, value;
11547
11548 _DIAGASSERT(bbox != NULL);
11549
11550 set = (const BITCMD *)bbox;
11551 newmode = omode;
11552 for (value = 0;; set++)
11553 switch(set->cmd) {
11554 /*
11555 * When copying the user, group or other bits around, we "know"
11556 * where the bits are in the mode so that we can do shifts to
11557 * copy them around. If we don't use shifts, it gets real
11558 * grundgy with lots of single bit checks and bit sets.
11559 */
11560 case 'u':
11561 value = (newmode & S_IRWXU) >> 6;
11562 goto common;
11563
11564 case 'g':
11565 value = (newmode & S_IRWXG) >> 3;
11566 goto common;
11567
11568 case 'o':
11569 value = newmode & S_IRWXO;
Eric Andersen2870d962001-07-02 17:27:21 +000011570common: if (set->cmd2 & CMD2_CLR) {
Eric Andersencb57d552001-06-28 07:25:16 +000011571 clrval =
11572 (set->cmd2 & CMD2_SET) ? S_IRWXO : value;
11573 if (set->cmd2 & CMD2_UBITS)
11574 newmode &= ~((clrval<<6) & set->bits);
11575 if (set->cmd2 & CMD2_GBITS)
11576 newmode &= ~((clrval<<3) & set->bits);
11577 if (set->cmd2 & CMD2_OBITS)
11578 newmode &= ~(clrval & set->bits);
11579 }
11580 if (set->cmd2 & CMD2_SET) {
11581 if (set->cmd2 & CMD2_UBITS)
11582 newmode |= (value<<6) & set->bits;
11583 if (set->cmd2 & CMD2_GBITS)
11584 newmode |= (value<<3) & set->bits;
11585 if (set->cmd2 & CMD2_OBITS)
11586 newmode |= value & set->bits;
11587 }
11588 break;
11589
11590 case '+':
11591 newmode |= set->bits;
11592 break;
11593
11594 case '-':
11595 newmode &= ~set->bits;
11596 break;
11597
11598 case 'X':
11599 if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH))
11600 newmode |= set->bits;
11601 break;
11602
11603 case '\0':
11604 default:
11605#ifdef SETMODE_DEBUG
11606 (void)printf("getmode:%04o -> %04o\n", omode, newmode);
11607#endif
11608 return (newmode);
11609 }
11610}
11611
Eric Andersen2870d962001-07-02 17:27:21 +000011612#define ADDCMD(a, b, c, d) do { \
11613 if (set >= endset) { \
11614 BITCMD *newset; \
11615 setlen += SET_LEN_INCR; \
11616 newset = realloc(saveset, sizeof(BITCMD) * setlen); \
11617 if (newset == NULL) { \
11618 free(saveset); \
11619 return (NULL); \
11620 } \
11621 set = newset + (set - saveset); \
11622 saveset = newset; \
11623 endset = newset + (setlen - 2); \
11624 } \
11625 set = addcmd(set, (a), (b), (c), (d)); \
Eric Andersencb57d552001-06-28 07:25:16 +000011626} while (/*CONSTCOND*/0)
11627
Eric Andersen2870d962001-07-02 17:27:21 +000011628#define STANDARD_BITS (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
Eric Andersencb57d552001-06-28 07:25:16 +000011629
11630static void *
11631setmode(p)
11632 const char *p;
11633{
11634 int perm, who;
11635 char op, *ep;
11636 BITCMD *set, *saveset, *endset;
11637 sigset_t mysigset, sigoset;
11638 mode_t mask;
Eric Andersen2870d962001-07-02 17:27:21 +000011639 int equalopdone = 0; /* pacify gcc */
Eric Andersencb57d552001-06-28 07:25:16 +000011640 int permXbits, setlen;
11641
11642 if (!*p)
11643 return (NULL);
11644
11645 /*
11646 * Get a copy of the mask for the permissions that are mask relative.
11647 * Flip the bits, we want what's not set. Since it's possible that
11648 * the caller is opening files inside a signal handler, protect them
11649 * as best we can.
11650 */
11651 sigfillset(&mysigset);
11652 (void)sigprocmask(SIG_BLOCK, &mysigset, &sigoset);
11653 (void)umask(mask = umask(0));
11654 mask = ~mask;
11655 (void)sigprocmask(SIG_SETMASK, &sigoset, NULL);
11656
11657 setlen = SET_LEN + 2;
Eric Andersen2870d962001-07-02 17:27:21 +000011658
Eric Andersencb57d552001-06-28 07:25:16 +000011659 if ((set = malloc((u_int)(sizeof(BITCMD) * setlen))) == NULL)
11660 return (NULL);
11661 saveset = set;
11662 endset = set + (setlen - 2);
11663
11664 /*
11665 * If an absolute number, get it and return; disallow non-octal digits
11666 * or illegal bits.
11667 */
11668 if (isdigit((unsigned char)*p)) {
11669 perm = (mode_t)strtol(p, &ep, 8);
11670 if (*ep || perm & ~(STANDARD_BITS|S_ISTXT)) {
11671 free(saveset);
11672 return (NULL);
11673 }
11674 ADDCMD('=', (STANDARD_BITS|S_ISTXT), perm, mask);
11675 set->cmd = 0;
11676 return (saveset);
11677 }
11678
11679 /*
11680 * Build list of structures to set/clear/copy bits as described by
11681 * each clause of the symbolic mode.
11682 */
11683 for (;;) {
11684 /* First, find out which bits might be modified. */
11685 for (who = 0;; ++p) {
11686 switch (*p) {
11687 case 'a':
11688 who |= STANDARD_BITS;
11689 break;
11690 case 'u':
11691 who |= S_ISUID|S_IRWXU;
11692 break;
11693 case 'g':
11694 who |= S_ISGID|S_IRWXG;
11695 break;
11696 case 'o':
11697 who |= S_IRWXO;
11698 break;
11699 default:
11700 goto getop;
11701 }
11702 }
11703
Eric Andersen2870d962001-07-02 17:27:21 +000011704getop: if ((op = *p++) != '+' && op != '-' && op != '=') {
Eric Andersencb57d552001-06-28 07:25:16 +000011705 free(saveset);
11706 return (NULL);
11707 }
11708 if (op == '=')
11709 equalopdone = 0;
11710
11711 who &= ~S_ISTXT;
11712 for (perm = 0, permXbits = 0;; ++p) {
11713 switch (*p) {
11714 case 'r':
11715 perm |= S_IRUSR|S_IRGRP|S_IROTH;
11716 break;
11717 case 's':
11718 /*
Eric Andersen2870d962001-07-02 17:27:21 +000011719 * If specific bits where requested and
11720 * only "other" bits ignore set-id.
Eric Andersencb57d552001-06-28 07:25:16 +000011721 */
11722 if (who == 0 || (who & ~S_IRWXO))
11723 perm |= S_ISUID|S_ISGID;
11724 break;
11725 case 't':
11726 /*
Eric Andersen2870d962001-07-02 17:27:21 +000011727 * If specific bits where requested and
11728 * only "other" bits ignore set-id.
Eric Andersencb57d552001-06-28 07:25:16 +000011729 */
11730 if (who == 0 || (who & ~S_IRWXO)) {
11731 who |= S_ISTXT;
11732 perm |= S_ISTXT;
11733 }
11734 break;
11735 case 'w':
11736 perm |= S_IWUSR|S_IWGRP|S_IWOTH;
11737 break;
11738 case 'X':
11739 permXbits = S_IXUSR|S_IXGRP|S_IXOTH;
11740 break;
11741 case 'x':
11742 perm |= S_IXUSR|S_IXGRP|S_IXOTH;
11743 break;
11744 case 'u':
11745 case 'g':
11746 case 'o':
11747 /*
11748 * When ever we hit 'u', 'g', or 'o', we have
11749 * to flush out any partial mode that we have,
11750 * and then do the copying of the mode bits.
11751 */
11752 if (perm) {
11753 ADDCMD(op, who, perm, mask);
11754 perm = 0;
11755 }
11756 if (op == '=')
11757 equalopdone = 1;
11758 if (op == '+' && permXbits) {
11759 ADDCMD('X', who, permXbits, mask);
11760 permXbits = 0;
11761 }
11762 ADDCMD(*p, who, op, mask);
11763 break;
11764
11765 default:
11766 /*
11767 * Add any permissions that we haven't already
11768 * done.
11769 */
11770 if (perm || (op == '=' && !equalopdone)) {
11771 if (op == '=')
11772 equalopdone = 1;
11773 ADDCMD(op, who, perm, mask);
11774 perm = 0;
11775 }
11776 if (permXbits) {
11777 ADDCMD('X', who, permXbits, mask);
11778 permXbits = 0;
11779 }
11780 goto apply;
11781 }
11782 }
11783
Eric Andersen2870d962001-07-02 17:27:21 +000011784apply: if (!*p)
Eric Andersencb57d552001-06-28 07:25:16 +000011785 break;
11786 if (*p != ',')
11787 goto getop;
11788 ++p;
11789 }
11790 set->cmd = 0;
11791#ifdef SETMODE_DEBUG
11792 (void)printf("Before compress_mode()\n");
11793 dumpmode(saveset);
11794#endif
11795 compress_mode(saveset);
11796#ifdef SETMODE_DEBUG
11797 (void)printf("After compress_mode()\n");
11798 dumpmode(saveset);
11799#endif
11800 return (saveset);
11801}
11802
11803static BITCMD *
11804addcmd(set, op, who, oparg, mask)
11805 BITCMD *set;
11806 int oparg, who;
11807 int op;
11808 u_int mask;
11809{
11810
11811 _DIAGASSERT(set != NULL);
11812
11813 switch (op) {
11814 case '=':
11815 set->cmd = '-';
11816 set->bits = who ? who : STANDARD_BITS;
11817 set++;
11818
11819 op = '+';
11820 /* FALLTHROUGH */
11821 case '+':
11822 case '-':
11823 case 'X':
11824 set->cmd = op;
11825 set->bits = (who ? who : mask) & oparg;
11826 break;
11827
11828 case 'u':
11829 case 'g':
11830 case 'o':
11831 set->cmd = op;
11832 if (who) {
11833 set->cmd2 = ((who & S_IRUSR) ? CMD2_UBITS : 0) |
11834 ((who & S_IRGRP) ? CMD2_GBITS : 0) |
11835 ((who & S_IROTH) ? CMD2_OBITS : 0);
11836 set->bits = (mode_t)~0;
11837 } else {
11838 set->cmd2 = CMD2_UBITS | CMD2_GBITS | CMD2_OBITS;
11839 set->bits = mask;
11840 }
Eric Andersen2870d962001-07-02 17:27:21 +000011841
Eric Andersencb57d552001-06-28 07:25:16 +000011842 if (oparg == '+')
11843 set->cmd2 |= CMD2_SET;
11844 else if (oparg == '-')
11845 set->cmd2 |= CMD2_CLR;
11846 else if (oparg == '=')
11847 set->cmd2 |= CMD2_SET|CMD2_CLR;
11848 break;
11849 }
11850 return (set + 1);
11851}
11852
11853#ifdef SETMODE_DEBUG
11854static void
11855dumpmode(set)
11856 BITCMD *set;
11857{
11858
11859 _DIAGASSERT(set != NULL);
11860
11861 for (; set->cmd; ++set)
11862 (void)printf("cmd: '%c' bits %04o%s%s%s%s%s%s\n",
11863 set->cmd, set->bits, set->cmd2 ? " cmd2:" : "",
11864 set->cmd2 & CMD2_CLR ? " CLR" : "",
11865 set->cmd2 & CMD2_SET ? " SET" : "",
11866 set->cmd2 & CMD2_UBITS ? " UBITS" : "",
11867 set->cmd2 & CMD2_GBITS ? " GBITS" : "",
11868 set->cmd2 & CMD2_OBITS ? " OBITS" : "");
11869}
11870#endif
11871
11872/*
11873 * Given an array of bitcmd structures, compress by compacting consecutive
11874 * '+', '-' and 'X' commands into at most 3 commands, one of each. The 'u',
Eric Andersen2870d962001-07-02 17:27:21 +000011875 * 'g' and 'o' commands continue to be separate. They could probably be
Eric Andersencb57d552001-06-28 07:25:16 +000011876 * compacted, but it's not worth the effort.
11877 */
11878static void
11879compress_mode(set)
11880 BITCMD *set;
11881{
11882 BITCMD *nset;
11883 int setbits, clrbits, Xbits, op;
11884
11885 _DIAGASSERT(set != NULL);
11886
11887 for (nset = set;;) {
11888 /* Copy over any 'u', 'g' and 'o' commands. */
11889 while ((op = nset->cmd) != '+' && op != '-' && op != 'X') {
11890 *set++ = *nset++;
11891 if (!op)
11892 return;
11893 }
11894
11895 for (setbits = clrbits = Xbits = 0;; nset++) {
11896 if ((op = nset->cmd) == '-') {
11897 clrbits |= nset->bits;
11898 setbits &= ~nset->bits;
11899 Xbits &= ~nset->bits;
11900 } else if (op == '+') {
11901 setbits |= nset->bits;
11902 clrbits &= ~nset->bits;
11903 Xbits &= ~nset->bits;
11904 } else if (op == 'X')
11905 Xbits |= nset->bits & ~setbits;
11906 else
11907 break;
11908 }
11909 if (clrbits) {
11910 set->cmd = '-';
11911 set->cmd2 = 0;
11912 set->bits = clrbits;
11913 set++;
11914 }
11915 if (setbits) {
11916 set->cmd = '+';
11917 set->cmd2 = 0;
11918 set->bits = setbits;
11919 set++;
11920 }
11921 if (Xbits) {
11922 set->cmd = 'X';
11923 set->cmd2 = 0;
11924 set->bits = Xbits;
11925 set++;
11926 }
11927 }
11928}
Eric Andersencb57d552001-06-28 07:25:16 +000011929#ifdef DEBUG
Eric Andersen2870d962001-07-02 17:27:21 +000011930static void shtree (union node *, int, char *, FILE*);
11931static void shcmd (union node *, FILE *);
11932static void sharg (union node *, FILE *);
11933static void indent (int, char *, FILE *);
11934static void trstring (char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011935
11936
11937static void
11938showtree(n)
11939 union node *n;
11940{
11941 trputs("showtree called\n");
11942 shtree(n, 1, NULL, stdout);
11943}
11944
11945
11946static void
11947shtree(n, ind, pfx, fp)
11948 union node *n;
11949 int ind;
11950 char *pfx;
11951 FILE *fp;
11952{
11953 struct nodelist *lp;
11954 const char *s;
11955
11956 if (n == NULL)
11957 return;
11958
11959 indent(ind, pfx, fp);
11960 switch(n->type) {
11961 case NSEMI:
11962 s = "; ";
11963 goto binop;
11964 case NAND:
11965 s = " && ";
11966 goto binop;
11967 case NOR:
11968 s = " || ";
11969binop:
11970 shtree(n->nbinary.ch1, ind, NULL, fp);
11971 /* if (ind < 0) */
11972 fputs(s, fp);
11973 shtree(n->nbinary.ch2, ind, NULL, fp);
11974 break;
11975 case NCMD:
11976 shcmd(n, fp);
11977 if (ind >= 0)
11978 putc('\n', fp);
11979 break;
11980 case NPIPE:
11981 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
11982 shcmd(lp->n, fp);
11983 if (lp->next)
11984 fputs(" | ", fp);
11985 }
11986 if (n->npipe.backgnd)
11987 fputs(" &", fp);
11988 if (ind >= 0)
11989 putc('\n', fp);
11990 break;
11991 default:
11992 fprintf(fp, "<node type %d>", n->type);
11993 if (ind >= 0)
11994 putc('\n', fp);
11995 break;
11996 }
11997}
11998
11999
12000
12001static void
12002shcmd(cmd, fp)
12003 union node *cmd;
12004 FILE *fp;
12005{
12006 union node *np;
12007 int first;
12008 const char *s;
12009 int dftfd;
12010
12011 first = 1;
12012 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
12013 if (! first)
12014 putchar(' ');
12015 sharg(np, fp);
12016 first = 0;
12017 }
12018 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
12019 if (! first)
12020 putchar(' ');
12021 switch (np->nfile.type) {
Eric Andersen2870d962001-07-02 17:27:21 +000012022 case NTO: s = ">"; dftfd = 1; break;
12023 case NAPPEND: s = ">>"; dftfd = 1; break;
12024 case NTOFD: s = ">&"; dftfd = 1; break;
12025 case NTOOV: s = ">|"; dftfd = 1; break;
12026 case NFROM: s = "<"; dftfd = 0; break;
12027 case NFROMFD: s = "<&"; dftfd = 0; break;
12028 case NFROMTO: s = "<>"; dftfd = 0; break;
12029 default: s = "*error*"; dftfd = 0; break;
Eric Andersencb57d552001-06-28 07:25:16 +000012030 }
12031 if (np->nfile.fd != dftfd)
12032 fprintf(fp, "%d", np->nfile.fd);
12033 fputs(s, fp);
12034 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
12035 fprintf(fp, "%d", np->ndup.dupfd);
12036 } else {
12037 sharg(np->nfile.fname, fp);
12038 }
12039 first = 0;
12040 }
12041}
12042
12043
12044
12045static void
12046sharg(arg, fp)
12047 union node *arg;
12048 FILE *fp;
12049 {
12050 char *p;
12051 struct nodelist *bqlist;
12052 int subtype;
12053
12054 if (arg->type != NARG) {
12055 printf("<node type %d>\n", arg->type);
12056 fflush(stdout);
12057 abort();
12058 }
12059 bqlist = arg->narg.backquote;
12060 for (p = arg->narg.text ; *p ; p++) {
12061 switch (*p) {
12062 case CTLESC:
12063 putc(*++p, fp);
12064 break;
12065 case CTLVAR:
12066 putc('$', fp);
12067 putc('{', fp);
12068 subtype = *++p;
12069 if (subtype == VSLENGTH)
12070 putc('#', fp);
12071
12072 while (*p != '=')
12073 putc(*p++, fp);
12074
12075 if (subtype & VSNUL)
12076 putc(':', fp);
12077
12078 switch (subtype & VSTYPE) {
12079 case VSNORMAL:
12080 putc('}', fp);
12081 break;
12082 case VSMINUS:
12083 putc('-', fp);
12084 break;
12085 case VSPLUS:
12086 putc('+', fp);
12087 break;
12088 case VSQUESTION:
12089 putc('?', fp);
12090 break;
12091 case VSASSIGN:
12092 putc('=', fp);
12093 break;
12094 case VSTRIMLEFT:
12095 putc('#', fp);
12096 break;
12097 case VSTRIMLEFTMAX:
12098 putc('#', fp);
12099 putc('#', fp);
12100 break;
12101 case VSTRIMRIGHT:
12102 putc('%', fp);
12103 break;
12104 case VSTRIMRIGHTMAX:
12105 putc('%', fp);
12106 putc('%', fp);
12107 break;
12108 case VSLENGTH:
12109 break;
12110 default:
12111 printf("<subtype %d>", subtype);
12112 }
12113 break;
12114 case CTLENDVAR:
12115 putc('}', fp);
12116 break;
12117 case CTLBACKQ:
12118 case CTLBACKQ|CTLQUOTE:
12119 putc('$', fp);
12120 putc('(', fp);
12121 shtree(bqlist->n, -1, NULL, fp);
12122 putc(')', fp);
12123 break;
12124 default:
12125 putc(*p, fp);
12126 break;
12127 }
12128 }
12129}
12130
12131
12132static void
12133indent(amount, pfx, fp)
12134 int amount;
12135 char *pfx;
12136 FILE *fp;
12137{
12138 int i;
12139
12140 for (i = 0 ; i < amount ; i++) {
12141 if (pfx && i == amount - 1)
12142 fputs(pfx, fp);
12143 putc('\t', fp);
12144 }
12145}
12146#endif
12147
12148
12149
12150/*
12151 * Debugging stuff.
12152 */
12153
12154
12155#ifdef DEBUG
12156FILE *tracefile;
12157
12158#if DEBUG == 2
12159static int debug = 1;
12160#else
12161static int debug = 0;
12162#endif
12163
12164
12165static void
12166trputc(c)
12167 int c;
12168{
12169 if (tracefile == NULL)
12170 return;
12171 putc(c, tracefile);
12172 if (c == '\n')
12173 fflush(tracefile);
12174}
12175
12176static void
12177trace(const char *fmt, ...)
12178{
12179 va_list va;
12180#ifdef __STDC__
12181 va_start(va, fmt);
12182#else
12183 char *fmt;
12184 va_start(va);
12185 fmt = va_arg(va, char *);
12186#endif
12187 if (tracefile != NULL) {
12188 (void) vfprintf(tracefile, fmt, va);
12189 if (strchr(fmt, '\n'))
12190 (void) fflush(tracefile);
12191 }
12192 va_end(va);
12193}
12194
12195
12196static void
12197trputs(s)
12198 const char *s;
12199{
12200 if (tracefile == NULL)
12201 return;
12202 fputs(s, tracefile);
12203 if (strchr(s, '\n'))
12204 fflush(tracefile);
12205}
12206
12207
12208static void
12209trstring(s)
12210 char *s;
12211{
12212 char *p;
12213 char c;
12214
12215 if (tracefile == NULL)
12216 return;
12217 putc('"', tracefile);
12218 for (p = s ; *p ; p++) {
12219 switch (*p) {
12220 case '\n': c = 'n'; goto backslash;
12221 case '\t': c = 't'; goto backslash;
12222 case '\r': c = 'r'; goto backslash;
12223 case '"': c = '"'; goto backslash;
12224 case '\\': c = '\\'; goto backslash;
12225 case CTLESC: c = 'e'; goto backslash;
12226 case CTLVAR: c = 'v'; goto backslash;
12227 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
12228 case CTLBACKQ: c = 'q'; goto backslash;
12229 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
Eric Andersen2870d962001-07-02 17:27:21 +000012230backslash: putc('\\', tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000012231 putc(c, tracefile);
12232 break;
12233 default:
12234 if (*p >= ' ' && *p <= '~')
12235 putc(*p, tracefile);
12236 else {
12237 putc('\\', tracefile);
12238 putc(*p >> 6 & 03, tracefile);
12239 putc(*p >> 3 & 07, tracefile);
12240 putc(*p & 07, tracefile);
12241 }
12242 break;
12243 }
12244 }
12245 putc('"', tracefile);
12246}
12247
12248
12249static void
12250trargs(ap)
12251 char **ap;
12252{
12253 if (tracefile == NULL)
12254 return;
12255 while (*ap) {
12256 trstring(*ap++);
12257 if (*ap)
12258 putc(' ', tracefile);
12259 else
12260 putc('\n', tracefile);
12261 }
12262 fflush(tracefile);
12263}
12264
12265
12266static void
12267opentrace() {
12268 char s[100];
12269#ifdef O_APPEND
12270 int flags;
12271#endif
12272
12273 if (!debug)
12274 return;
12275#ifdef not_this_way
12276 {
12277 char *p;
12278 if ((p = getenv("HOME")) == NULL) {
12279 if (geteuid() == 0)
12280 p = "/";
12281 else
12282 p = "/tmp";
12283 }
Eric Andersen2870d962001-07-02 17:27:21 +000012284 strcpy(s, p);
Eric Andersencb57d552001-06-28 07:25:16 +000012285 strcat(s, "/trace");
12286 }
12287#else
Eric Andersen2870d962001-07-02 17:27:21 +000012288 strcpy(s, "./trace");
Eric Andersencb57d552001-06-28 07:25:16 +000012289#endif /* not_this_way */
12290 if ((tracefile = fopen(s, "a")) == NULL) {
12291 fprintf(stderr, "Can't open %s\n", s);
12292 return;
12293 }
12294#ifdef O_APPEND
12295 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
12296 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
12297#endif
12298 fputs("\nTracing started.\n", tracefile);
12299 fflush(tracefile);
12300}
12301#endif /* DEBUG */
12302
12303
12304/*
Eric Andersencb57d552001-06-28 07:25:16 +000012305 * The trap builtin.
12306 */
12307
12308static int
12309trapcmd(argc, argv)
12310 int argc;
12311 char **argv;
12312{
12313 char *action;
12314 char **ap;
12315 int signo;
12316
12317 if (argc <= 1) {
12318 for (signo = 0 ; signo < NSIG ; signo++) {
12319 if (trap[signo] != NULL) {
12320 char *p;
12321
12322 p = single_quote(trap[signo]);
12323 out1fmt("trap -- %s %s\n", p,
12324 signal_names[signo] + (signo ? 3 : 0)
12325 );
12326 stunalloc(p);
12327 }
12328 }
12329 return 0;
12330 }
12331 ap = argv + 1;
12332 if (argc == 2)
12333 action = NULL;
12334 else
12335 action = *ap++;
12336 while (*ap) {
12337 if ((signo = decode_signal(*ap, 0)) < 0)
12338 error("%s: bad trap", *ap);
12339 INTOFF;
12340 if (action) {
12341 if (action[0] == '-' && action[1] == '\0')
12342 action = NULL;
12343 else
12344 action = savestr(action);
12345 }
12346 if (trap[signo])
12347 ckfree(trap[signo]);
12348 trap[signo] = action;
12349 if (signo != 0)
12350 setsignal(signo);
12351 INTON;
12352 ap++;
12353 }
12354 return 0;
12355}
12356
12357
12358
Eric Andersencb57d552001-06-28 07:25:16 +000012359
12360
12361
12362/*
12363 * Set the signal handler for the specified signal. The routine figures
12364 * out what it should be set to.
12365 */
12366
12367static void
Eric Andersen2870d962001-07-02 17:27:21 +000012368setsignal(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000012369{
12370 int action;
12371 char *t;
12372 struct sigaction act;
12373
12374 if ((t = trap[signo]) == NULL)
12375 action = S_DFL;
12376 else if (*t != '\0')
12377 action = S_CATCH;
12378 else
12379 action = S_IGN;
12380 if (rootshell && action == S_DFL) {
12381 switch (signo) {
12382 case SIGINT:
12383 if (iflag || minusc || sflag == 0)
12384 action = S_CATCH;
12385 break;
12386 case SIGQUIT:
12387#ifdef DEBUG
12388 {
Eric Andersencb57d552001-06-28 07:25:16 +000012389
12390 if (debug)
12391 break;
12392 }
12393#endif
12394 /* FALLTHROUGH */
12395 case SIGTERM:
12396 if (iflag)
12397 action = S_IGN;
12398 break;
Eric Andersen2870d962001-07-02 17:27:21 +000012399#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000012400 case SIGTSTP:
12401 case SIGTTOU:
12402 if (mflag)
12403 action = S_IGN;
12404 break;
12405#endif
12406 }
12407 }
12408
12409 t = &sigmode[signo - 1];
12410 if (*t == 0) {
12411 /*
12412 * current setting unknown
12413 */
12414 if (sigaction(signo, 0, &act) == -1) {
12415 /*
12416 * Pretend it worked; maybe we should give a warning
12417 * here, but other shells don't. We don't alter
12418 * sigmode, so that we retry every time.
12419 */
12420 return;
12421 }
12422 if (act.sa_handler == SIG_IGN) {
12423 if (mflag && (signo == SIGTSTP ||
12424 signo == SIGTTIN || signo == SIGTTOU)) {
Eric Andersen2870d962001-07-02 17:27:21 +000012425 *t = S_IGN; /* don't hard ignore these */
Eric Andersencb57d552001-06-28 07:25:16 +000012426 } else
12427 *t = S_HARD_IGN;
12428 } else {
Eric Andersen2870d962001-07-02 17:27:21 +000012429 *t = S_RESET; /* force to be set */
Eric Andersencb57d552001-06-28 07:25:16 +000012430 }
12431 }
12432 if (*t == S_HARD_IGN || *t == action)
12433 return;
12434 switch (action) {
12435 case S_CATCH:
12436 act.sa_handler = onsig;
12437 break;
12438 case S_IGN:
12439 act.sa_handler = SIG_IGN;
12440 break;
12441 default:
12442 act.sa_handler = SIG_DFL;
12443 }
12444 *t = action;
12445 act.sa_flags = 0;
12446 sigemptyset(&act.sa_mask);
12447 sigaction(signo, &act, 0);
12448}
12449
12450/*
12451 * Ignore a signal.
12452 */
12453
12454static void
12455ignoresig(signo)
12456 int signo;
12457{
12458 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
12459 signal(signo, SIG_IGN);
12460 }
12461 sigmode[signo - 1] = S_HARD_IGN;
12462}
12463
12464
Eric Andersencb57d552001-06-28 07:25:16 +000012465/*
12466 * Signal handler.
12467 */
12468
12469static void
Eric Andersen2870d962001-07-02 17:27:21 +000012470onsig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000012471{
12472 if (signo == SIGINT && trap[SIGINT] == NULL) {
12473 onint();
12474 return;
12475 }
12476 gotsig[signo - 1] = 1;
12477 pendingsigs++;
12478}
12479
12480
Eric Andersencb57d552001-06-28 07:25:16 +000012481/*
12482 * Called to execute a trap. Perhaps we should avoid entering new trap
12483 * handlers while we are executing a trap handler.
12484 */
12485
12486static void
Eric Andersen2870d962001-07-02 17:27:21 +000012487dotrap(void)
12488{
Eric Andersencb57d552001-06-28 07:25:16 +000012489 int i;
12490 int savestatus;
12491
12492 for (;;) {
12493 for (i = 1 ; ; i++) {
12494 if (gotsig[i - 1])
12495 break;
12496 if (i >= NSIG - 1)
12497 goto done;
12498 }
12499 gotsig[i - 1] = 0;
12500 savestatus=exitstatus;
12501 evalstring(trap[i], 0);
12502 exitstatus=savestatus;
12503 }
12504done:
12505 pendingsigs = 0;
12506}
12507
Eric Andersencb57d552001-06-28 07:25:16 +000012508/*
12509 * Called to exit the shell.
12510 */
12511
12512static void
Eric Andersen2870d962001-07-02 17:27:21 +000012513exitshell(int status)
Eric Andersencb57d552001-06-28 07:25:16 +000012514{
12515 struct jmploc loc1, loc2;
12516 char *p;
12517
12518 TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
12519 if (setjmp(loc1.loc)) {
12520 goto l1;
12521 }
12522 if (setjmp(loc2.loc)) {
12523 goto l2;
12524 }
12525 handler = &loc1;
12526 if ((p = trap[0]) != NULL && *p != '\0') {
12527 trap[0] = NULL;
12528 evalstring(p, 0);
12529 }
Eric Andersen2870d962001-07-02 17:27:21 +000012530l1: handler = &loc2; /* probably unnecessary */
Eric Andersencb57d552001-06-28 07:25:16 +000012531 flushall();
Eric Andersen2870d962001-07-02 17:27:21 +000012532#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000012533 setjobctl(0);
12534#endif
12535l2: _exit(status);
12536 /* NOTREACHED */
12537}
12538
12539static int decode_signal(const char *string, int minsig)
12540{
12541 int signo;
12542
Eric Andersen2870d962001-07-02 17:27:21 +000012543 if (is_number(string, &signo)) {
Eric Andersencb57d552001-06-28 07:25:16 +000012544 if (signo >= NSIG) {
12545 return -1;
12546 }
12547 return signo;
12548 }
12549
12550 signo = minsig;
12551 if (!signo) {
12552 goto zero;
12553 }
12554 for (; signo < NSIG; signo++) {
12555 if (!strcasecmp(string, &(signal_names[signo])[3])) {
12556 return signo;
12557 }
12558zero:
12559 if (!strcasecmp(string, signal_names[signo])) {
12560 return signo;
12561 }
12562 }
12563
12564 return -1;
12565}
Eric Andersen2870d962001-07-02 17:27:21 +000012566static struct var **hashvar (const char *);
12567static void showvars (const char *, int, int);
12568static struct var **findvar (struct var **, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +000012569
12570/*
12571 * Initialize the varable symbol tables and import the environment
12572 */
12573
Eric Andersencb57d552001-06-28 07:25:16 +000012574/*
12575 * This routine initializes the builtin variables. It is called when the
12576 * shell is initialized and again when a shell procedure is spawned.
12577 */
12578
12579static void
12580initvar() {
12581 const struct varinit *ip;
12582 struct var *vp;
12583 struct var **vpp;
12584
12585 for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
12586 if ((vp->flags & VEXPORT) == 0) {
12587 vpp = hashvar(ip->text);
12588 vp->next = *vpp;
12589 *vpp = vp;
12590 vp->text = strdup(ip->text);
12591 vp->flags = ip->flags;
12592 vp->func = ip->func;
12593 }
12594 }
12595 /*
12596 * PS1 depends on uid
12597 */
12598 if ((vps1.flags & VEXPORT) == 0) {
12599 vpp = hashvar("PS1=");
12600 vps1.next = *vpp;
12601 *vpp = &vps1;
12602 vps1.text = strdup(geteuid() ? "PS1=$ " : "PS1=# ");
12603 vps1.flags = VSTRFIXED|VTEXTFIXED;
12604 }
12605}
12606
12607/*
12608 * Set the value of a variable. The flags argument is ored with the
12609 * flags of the variable. If val is NULL, the variable is unset.
12610 */
12611
12612static void
12613setvar(name, val, flags)
12614 const char *name, *val;
12615 int flags;
12616{
12617 const char *p;
12618 int len;
12619 int namelen;
12620 char *nameeq;
12621 int isbad;
12622 int vallen = 0;
12623
12624 isbad = 0;
12625 p = name;
12626 if (! is_name(*p))
12627 isbad = 1;
12628 p++;
12629 for (;;) {
12630 if (! is_in_name(*p)) {
12631 if (*p == '\0' || *p == '=')
12632 break;
12633 isbad = 1;
12634 }
12635 p++;
12636 }
12637 namelen = p - name;
12638 if (isbad)
12639 error("%.*s: bad variable name", namelen, name);
Eric Andersen2870d962001-07-02 17:27:21 +000012640 len = namelen + 2; /* 2 is space for '=' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +000012641 if (val == NULL) {
12642 flags |= VUNSET;
12643 } else {
12644 len += vallen = strlen(val);
12645 }
12646 INTOFF;
12647 nameeq = ckmalloc(len);
12648 memcpy(nameeq, name, namelen);
12649 nameeq[namelen] = '=';
12650 if (val) {
12651 memcpy(nameeq + namelen + 1, val, vallen + 1);
12652 } else {
12653 nameeq[namelen + 1] = '\0';
12654 }
12655 setvareq(nameeq, flags);
12656 INTON;
12657}
12658
12659
12660
12661/*
12662 * Same as setvar except that the variable and value are passed in
12663 * the first argument as name=value. Since the first argument will
12664 * be actually stored in the table, it should not be a string that
12665 * will go away.
12666 */
12667
12668static void
12669setvareq(s, flags)
12670 char *s;
12671 int flags;
12672{
12673 struct var *vp, **vpp;
12674
12675 vpp = hashvar(s);
12676 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
12677 if ((vp = *findvar(vpp, s))) {
12678 if (vp->flags & VREADONLY) {
12679 size_t len = strchr(s, '=') - s;
12680 error("%.*s: is read only", len, s);
12681 }
12682 INTOFF;
12683
12684 if (vp->func && (flags & VNOFUNC) == 0)
12685 (*vp->func)(strchr(s, '=') + 1);
12686
12687 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12688 ckfree(vp->text);
12689
12690 vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
12691 vp->flags |= flags;
12692 vp->text = s;
12693
12694 /*
12695 * We could roll this to a function, to handle it as
12696 * a regular variable function callback, but why bother?
12697 */
12698 if (iflag && (vp == &vmpath || (vp == &vmail && !mpathset())))
12699 chkmail(1);
12700 INTON;
12701 return;
12702 }
12703 /* not found */
12704 vp = ckmalloc(sizeof (*vp));
12705 vp->flags = flags;
12706 vp->text = s;
12707 vp->next = *vpp;
12708 vp->func = NULL;
12709 *vpp = vp;
12710}
12711
12712
12713
12714/*
12715 * Process a linked list of variable assignments.
12716 */
12717
12718static void
12719listsetvar(mylist)
12720 struct strlist *mylist;
12721 {
12722 struct strlist *lp;
12723
12724 INTOFF;
12725 for (lp = mylist ; lp ; lp = lp->next) {
12726 setvareq(savestr(lp->text), 0);
12727 }
12728 INTON;
12729}
12730
12731
12732
12733/*
12734 * Find the value of a variable. Returns NULL if not set.
12735 */
12736
12737static char *
12738lookupvar(name)
12739 const char *name;
12740 {
12741 struct var *v;
12742
12743 if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
12744 return strchr(v->text, '=') + 1;
12745 }
12746 return NULL;
12747}
12748
12749
12750
12751/*
12752 * Search the environment of a builtin command.
12753 */
12754
12755static char *
12756bltinlookup(name)
12757 const char *name;
12758{
12759 struct strlist *sp;
12760
12761 for (sp = cmdenviron ; sp ; sp = sp->next) {
12762 if (varequal(sp->text, name))
12763 return strchr(sp->text, '=') + 1;
12764 }
12765 return lookupvar(name);
12766}
12767
12768
12769
12770/*
12771 * Generate a list of exported variables. This routine is used to construct
12772 * the third argument to execve when executing a program.
12773 */
12774
12775static char **
12776environment() {
12777 int nenv;
12778 struct var **vpp;
12779 struct var *vp;
12780 char **env;
12781 char **ep;
12782
12783 nenv = 0;
12784 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12785 for (vp = *vpp ; vp ; vp = vp->next)
12786 if (vp->flags & VEXPORT)
12787 nenv++;
12788 }
12789 ep = env = stalloc((nenv + 1) * sizeof *env);
12790 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12791 for (vp = *vpp ; vp ; vp = vp->next)
12792 if (vp->flags & VEXPORT)
12793 *ep++ = vp->text;
12794 }
12795 *ep = NULL;
12796 return env;
12797}
12798
12799
12800/*
12801 * Called when a shell procedure is invoked to clear out nonexported
12802 * variables. It is also necessary to reallocate variables of with
12803 * VSTACK set since these are currently allocated on the stack.
12804 */
12805
Eric Andersencb57d552001-06-28 07:25:16 +000012806static void
Eric Andersen2870d962001-07-02 17:27:21 +000012807shprocvar(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000012808 struct var **vpp;
12809 struct var *vp, **prev;
12810
12811 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12812 for (prev = vpp ; (vp = *prev) != NULL ; ) {
12813 if ((vp->flags & VEXPORT) == 0) {
12814 *prev = vp->next;
12815 if ((vp->flags & VTEXTFIXED) == 0)
12816 ckfree(vp->text);
12817 if ((vp->flags & VSTRFIXED) == 0)
12818 ckfree(vp);
12819 } else {
12820 if (vp->flags & VSTACK) {
12821 vp->text = savestr(vp->text);
12822 vp->flags &=~ VSTACK;
12823 }
12824 prev = &vp->next;
12825 }
12826 }
12827 }
12828 initvar();
12829}
12830
12831
12832
12833/*
12834 * Command to list all variables which are set. Currently this command
12835 * is invoked from the set command when the set command is called without
12836 * any variables.
12837 */
12838
12839static int
12840showvarscmd(argc, argv)
12841 int argc;
12842 char **argv;
12843{
12844 showvars(nullstr, VUNSET, VUNSET);
12845 return 0;
12846}
12847
12848
12849
12850/*
12851 * The export and readonly commands.
12852 */
12853
12854static int
12855exportcmd(argc, argv)
12856 int argc;
12857 char **argv;
12858{
12859 struct var *vp;
12860 char *name;
12861 const char *p;
12862 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12863 int pflag;
12864
12865 listsetvar(cmdenviron);
12866 pflag = (nextopt("p") == 'p');
12867 if (argc > 1 && !pflag) {
12868 while ((name = *argptr++) != NULL) {
12869 if ((p = strchr(name, '=')) != NULL) {
12870 p++;
12871 } else {
12872 if ((vp = *findvar(hashvar(name), name))) {
12873 vp->flags |= flag;
12874 goto found;
12875 }
12876 }
12877 setvar(name, p, flag);
12878found:;
12879 }
12880 } else {
12881 showvars(argv[0], flag, 0);
12882 }
12883 return 0;
12884}
12885
12886
12887/*
12888 * The "local" command.
12889 */
12890
Eric Andersen2870d962001-07-02 17:27:21 +000012891/* funcnest nonzero if we are currently evaluating a function */
12892
Eric Andersencb57d552001-06-28 07:25:16 +000012893static int
12894localcmd(argc, argv)
12895 int argc;
12896 char **argv;
12897{
12898 char *name;
12899
Eric Andersen2870d962001-07-02 17:27:21 +000012900 if (! funcnest)
Eric Andersencb57d552001-06-28 07:25:16 +000012901 error("Not in a function");
12902 while ((name = *argptr++) != NULL) {
12903 mklocal(name);
12904 }
12905 return 0;
12906}
12907
12908
12909/*
12910 * Make a variable a local variable. When a variable is made local, it's
12911 * value and flags are saved in a localvar structure. The saved values
12912 * will be restored when the shell function returns. We handle the name
12913 * "-" as a special case.
12914 */
12915
12916static void
12917mklocal(name)
12918 char *name;
12919 {
12920 struct localvar *lvp;
12921 struct var **vpp;
12922 struct var *vp;
12923
12924 INTOFF;
12925 lvp = ckmalloc(sizeof (struct localvar));
12926 if (name[0] == '-' && name[1] == '\0') {
12927 char *p;
Eric Andersen2870d962001-07-02 17:27:21 +000012928 p = ckmalloc(sizeof optet_vals);
12929 lvp->text = memcpy(p, optet_vals, sizeof optet_vals);
Eric Andersencb57d552001-06-28 07:25:16 +000012930 vp = NULL;
12931 } else {
12932 vpp = hashvar(name);
12933 vp = *findvar(vpp, name);
12934 if (vp == NULL) {
12935 if (strchr(name, '='))
12936 setvareq(savestr(name), VSTRFIXED);
12937 else
12938 setvar(name, NULL, VSTRFIXED);
Eric Andersen2870d962001-07-02 17:27:21 +000012939 vp = *vpp; /* the new variable */
Eric Andersencb57d552001-06-28 07:25:16 +000012940 lvp->text = NULL;
12941 lvp->flags = VUNSET;
12942 } else {
12943 lvp->text = vp->text;
12944 lvp->flags = vp->flags;
12945 vp->flags |= VSTRFIXED|VTEXTFIXED;
12946 if (strchr(name, '='))
12947 setvareq(savestr(name), 0);
12948 }
12949 }
12950 lvp->vp = vp;
12951 lvp->next = localvars;
12952 localvars = lvp;
12953 INTON;
12954}
12955
12956
12957/*
12958 * Called after a function returns.
12959 */
12960
12961static void
12962poplocalvars() {
12963 struct localvar *lvp;
12964 struct var *vp;
12965
12966 while ((lvp = localvars) != NULL) {
12967 localvars = lvp->next;
12968 vp = lvp->vp;
Eric Andersen2870d962001-07-02 17:27:21 +000012969 if (vp == NULL) { /* $- saved */
12970 memcpy(optet_vals, lvp->text, sizeof optet_vals);
Eric Andersencb57d552001-06-28 07:25:16 +000012971 ckfree(lvp->text);
12972 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12973 (void)unsetvar(vp->text);
12974 } else {
12975 if ((vp->flags & VTEXTFIXED) == 0)
12976 ckfree(vp->text);
12977 vp->flags = lvp->flags;
12978 vp->text = lvp->text;
12979 }
12980 ckfree(lvp);
12981 }
12982}
12983
12984
12985static int
12986setvarcmd(argc, argv)
12987 int argc;
12988 char **argv;
12989{
12990 if (argc <= 2)
12991 return unsetcmd(argc, argv);
12992 else if (argc == 3)
12993 setvar(argv[1], argv[2], 0);
12994 else
12995 error("List assignment not implemented");
12996 return 0;
12997}
12998
12999
13000/*
13001 * The unset builtin command. We unset the function before we unset the
13002 * variable to allow a function to be unset when there is a readonly variable
13003 * with the same name.
13004 */
13005
13006static int
13007unsetcmd(argc, argv)
13008 int argc;
13009 char **argv;
13010{
13011 char **ap;
13012 int i;
13013 int flg_func = 0;
13014 int flg_var = 0;
13015 int ret = 0;
13016
13017 while ((i = nextopt("vf")) != '\0') {
13018 if (i == 'f')
13019 flg_func = 1;
13020 else
13021 flg_var = 1;
13022 }
13023 if (flg_func == 0 && flg_var == 0)
13024 flg_var = 1;
13025
13026 for (ap = argptr; *ap ; ap++) {
13027 if (flg_func)
13028 unsetfunc(*ap);
13029 if (flg_var)
13030 ret |= unsetvar(*ap);
13031 }
13032 return ret;
13033}
13034
13035
13036/*
13037 * Unset the specified variable.
13038 */
13039
13040static int
13041unsetvar(s)
13042 const char *s;
13043 {
13044 struct var **vpp;
13045 struct var *vp;
13046
13047 vpp = findvar(hashvar(s), s);
13048 vp = *vpp;
13049 if (vp) {
13050 if (vp->flags & VREADONLY)
13051 return (1);
13052 INTOFF;
13053 if (*(strchr(vp->text, '=') + 1) != '\0')
13054 setvar(s, nullstr, 0);
13055 vp->flags &= ~VEXPORT;
13056 vp->flags |= VUNSET;
13057 if ((vp->flags & VSTRFIXED) == 0) {
13058 if ((vp->flags & VTEXTFIXED) == 0)
13059 ckfree(vp->text);
13060 *vpp = vp->next;
13061 ckfree(vp);
13062 }
13063 INTON;
13064 return (0);
13065 }
13066
13067 return (0);
13068}
13069
13070
13071
13072/*
13073 * Find the appropriate entry in the hash table from the name.
13074 */
13075
13076static struct var **
13077hashvar(p)
13078 const char *p;
13079 {
13080 unsigned int hashval;
13081
13082 hashval = ((unsigned char) *p) << 4;
13083 while (*p && *p != '=')
13084 hashval += (unsigned char) *p++;
13085 return &vartab[hashval % VTABSIZE];
13086}
13087
13088
13089
13090/*
13091 * Returns true if the two strings specify the same varable. The first
13092 * variable name is terminated by '='; the second may be terminated by
13093 * either '=' or '\0'.
13094 */
13095
13096static int
13097varequal(p, q)
13098 const char *p, *q;
13099 {
13100 while (*p == *q++) {
13101 if (*p++ == '=')
13102 return 1;
13103 }
13104 if (*p == '=' && *(q - 1) == '\0')
13105 return 1;
13106 return 0;
13107}
13108
13109static void
13110showvars(const char *myprefix, int mask, int xor)
13111{
13112 struct var **vpp;
13113 struct var *vp;
13114 const char *sep = myprefix == nullstr ? myprefix : spcstr;
13115
13116 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
13117 for (vp = *vpp ; vp ; vp = vp->next) {
13118 if ((vp->flags & mask) ^ xor) {
13119 char *p;
13120 int len;
13121
13122 p = strchr(vp->text, '=') + 1;
13123 len = p - vp->text;
13124 p = single_quote(p);
13125
13126 out1fmt(
13127 "%s%s%.*s%s\n", myprefix, sep, len,
13128 vp->text, p
13129 );
13130 stunalloc(p);
13131 }
13132 }
13133 }
13134}
13135
13136static struct var **
13137findvar(struct var **vpp, const char *name)
13138{
13139 for (; *vpp; vpp = &(*vpp)->next) {
13140 if (varequal((*vpp)->text, name)) {
13141 break;
13142 }
13143 }
13144 return vpp;
13145}
13146
13147/*
13148 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
13149 * This file contains code for the times builtin.
Eric Andersen1c039232001-07-07 00:05:55 +000013150 * $Id: ash.c,v 1.7 2001/07/07 00:05:55 andersen Exp $
Eric Andersencb57d552001-06-28 07:25:16 +000013151 */
13152static int timescmd (int argc, char **argv)
13153{
13154 struct tms buf;
13155 long int clk_tck = sysconf(_SC_CLK_TCK);
13156
13157 times(&buf);
13158 printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
13159 (int) (buf.tms_utime / clk_tck / 60),
13160 ((double) buf.tms_utime) / clk_tck,
13161 (int) (buf.tms_stime / clk_tck / 60),
13162 ((double) buf.tms_stime) / clk_tck,
13163 (int) (buf.tms_cutime / clk_tck / 60),
13164 ((double) buf.tms_cutime) / clk_tck,
13165 (int) (buf.tms_cstime / clk_tck / 60),
13166 ((double) buf.tms_cstime) / clk_tck);
13167 return 0;
13168}
13169
Eric Andersendf82f612001-06-28 07:46:40 +000013170
13171/*-
13172 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013173 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013174 *
13175 * This code is derived from software contributed to Berkeley by
13176 * Kenneth Almquist.
13177 *
13178 * Redistribution and use in source and binary forms, with or without
13179 * modification, are permitted provided that the following conditions
13180 * are met:
13181 * 1. Redistributions of source code must retain the above copyright
13182 * notice, this list of conditions and the following disclaimer.
13183 * 2. Redistributions in binary form must reproduce the above copyright
13184 * notice, this list of conditions and the following disclaimer in the
13185 * documentation and/or other materials provided with the distribution.
13186 *
Eric Andersen2870d962001-07-02 17:27:21 +000013187 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
13188 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
Eric Andersendf82f612001-06-28 07:46:40 +000013189 *
13190 * 4. Neither the name of the University nor the names of its contributors
13191 * may be used to endorse or promote products derived from this software
13192 * without specific prior written permission.
13193 *
13194 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13195 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13196 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13197 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13198 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13199 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13200 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13201 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13202 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13203 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13204 * SUCH DAMAGE.
13205 */