blob: 99460d3d614e5edc3cb11e96bca80196d31576db [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 **);
1606static int jobscmd (int, char **);
1607static int localcmd (int, char **);
Eric Andersen3102ac42001-07-06 04:26:23 +00001608#ifndef BB_PWD
Eric Andersen2870d962001-07-02 17:27:21 +00001609static int pwdcmd (int, char **);
1610#endif
1611static int readcmd (int, char **);
1612static int returncmd (int, char **);
1613static int setcmd (int, char **);
1614static int setvarcmd (int, char **);
1615static int shiftcmd (int, char **);
1616static int trapcmd (int, char **);
1617static int umaskcmd (int, char **);
1618#ifdef ASH_ALIAS
1619static int aliascmd (int, char **);
1620static int unaliascmd (int, char **);
1621#endif
1622static int unsetcmd (int, char **);
1623static int waitcmd (int, char **);
1624static int ulimitcmd (int, char **);
1625static int timescmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001626#ifdef ASH_MATH_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00001627static int expcmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001628#endif
1629#ifdef ASH_TYPE
Eric Andersen2870d962001-07-02 17:27:21 +00001630static int typecmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001631#endif
1632#ifdef ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00001633static int getoptscmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001634#endif
1635
Eric Andersen2870d962001-07-02 17:27:21 +00001636#ifndef BB_TRUE_FALSE
1637# ifdef ASH_BBAPPS_AS_BUILTINS
1638static int true_main (int, char **);
1639static int false_main (int, char **);
1640# endif
1641#endif
1642
1643static void setpwd (const char *, int);
1644
1645
1646#define BUILTIN_NOSPEC "0"
1647#define BUILTIN_SPECIAL "1"
1648#define BUILTIN_REGULAR "2"
1649#define BUILTIN_ASSIGN "4"
1650#define BUILTIN_SPEC_ASSG "5"
1651#define BUILTIN_REG_ASSG "6"
1652
1653#define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1654#define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
1655#define IS_BUILTIN_ASSIGN(builtincmd) ((builtincmd)->name[0] & 4)
1656
1657struct builtincmd {
1658 const char *name;
1659 int (*const builtinfunc) (int, char **);
1660 //unsigned flags;
1661};
1662
Eric Andersencb57d552001-06-28 07:25:16 +00001663
1664/* It is CRUCIAL that this listing be kept in ascii order, otherwise
1665 * the binary search in find_builtin() will stop working. If you value
1666 * your kneecaps, you'll be sure to *make sure* that any changes made
1667 * to this array result in the listing remaining in ascii order. You
1668 * have been warned.
1669 */
1670static const struct builtincmd builtincmds[] = {
Eric Andersen2870d962001-07-02 17:27:21 +00001671 { BUILTIN_SPECIAL ".", dotcmd },
1672 { BUILTIN_SPECIAL ":", true_main },
1673#ifdef ASH_ALIAS
1674 { BUILTIN_REG_ASSG "alias", aliascmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001675#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001676#ifdef JOBS
1677 { BUILTIN_REGULAR "bg", bgcmd },
1678#endif
1679 { BUILTIN_SPECIAL "break", breakcmd },
Eric Andersen3102ac42001-07-06 04:26:23 +00001680 { BUILTIN_SPECIAL "builtin", bltincmd },
Eric Andersen2870d962001-07-02 17:27:21 +00001681 { BUILTIN_REGULAR "cd", cdcmd },
1682#ifdef ASH_BBAPPS_AS_BUILTINS
1683 { BUILTIN_NOSPEC "chdir", cdcmd },
1684#endif
1685#ifdef ASH_CMDCMD
1686 { BUILTIN_REGULAR "command", commandcmd },
1687#endif
1688 { BUILTIN_SPECIAL "continue", breakcmd },
1689 { BUILTIN_SPECIAL "eval", evalcmd },
1690 { BUILTIN_SPECIAL "exec", execcmd },
1691 { BUILTIN_SPECIAL "exit", exitcmd },
1692#ifdef ASH_MATH_SUPPORT
1693 { BUILTIN_NOSPEC "exp", expcmd },
1694#endif
1695 { BUILTIN_SPEC_ASSG "export", exportcmd },
1696#ifdef ASH_BBAPPS_AS_BUILTINS
1697 { BUILTIN_REGULAR "false", false_main },
1698#endif
1699 { BUILTIN_REGULAR "fc", histcmd },
1700#ifdef JOBS
1701 { BUILTIN_REGULAR "fg", fgcmd },
1702#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001703#ifdef ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00001704 { BUILTIN_REGULAR "getopts", getoptscmd },
1705#endif
1706 { BUILTIN_NOSPEC "hash", hashcmd },
1707 { BUILTIN_REGULAR "jobs", jobscmd },
1708#ifdef JOBS
1709 { BUILTIN_REGULAR "kill", killcmd },
1710#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001711#ifdef ASH_MATH_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00001712 { BUILTIN_NOSPEC "let", expcmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001713#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001714 { BUILTIN_ASSIGN "local", localcmd },
Eric Andersen3102ac42001-07-06 04:26:23 +00001715#ifndef BB_PWD
Eric Andersen2870d962001-07-02 17:27:21 +00001716 { BUILTIN_NOSPEC "pwd", pwdcmd },
1717#endif
1718 { BUILTIN_REGULAR "read", readcmd },
1719 { BUILTIN_SPEC_ASSG "readonly", exportcmd },
1720 { BUILTIN_SPECIAL "return", returncmd },
1721 { BUILTIN_SPECIAL "set", setcmd },
1722 { BUILTIN_NOSPEC "setvar", setvarcmd },
1723 { BUILTIN_SPECIAL "shift", shiftcmd },
1724 { BUILTIN_SPECIAL "times", timescmd },
1725 { BUILTIN_SPECIAL "trap", trapcmd },
1726#ifdef ASH_BBAPPS_AS_BUILTINS
1727 { BUILTIN_REGULAR "true", true_main },
1728#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001729#ifdef ASH_TYPE
Eric Andersen2870d962001-07-02 17:27:21 +00001730 { BUILTIN_NOSPEC "type", typecmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001731#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001732 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
1733 { BUILTIN_REGULAR "umask", umaskcmd },
1734#ifdef ASH_ALIAS
1735 { BUILTIN_REGULAR "unalias", unaliascmd },
1736#endif
1737 { BUILTIN_SPECIAL "unset", unsetcmd },
1738 { BUILTIN_REGULAR "wait", waitcmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001739};
1740#define NUMBUILTINS (sizeof (builtincmds) / sizeof (struct builtincmd) )
1741
Eric Andersen2870d962001-07-02 17:27:21 +00001742static const struct builtincmd *DOTCMD = &builtincmds[0];
1743static struct builtincmd *BLTINCMD;
1744static struct builtincmd *EXECCMD;
1745static struct builtincmd *EVALCMD;
Eric Andersencb57d552001-06-28 07:25:16 +00001746
Eric Andersen2870d962001-07-02 17:27:21 +00001747/* states */
1748#define JOBSTOPPED 1 /* all procs are stopped */
1749#define JOBDONE 2 /* all procs are completed */
Eric Andersencb57d552001-06-28 07:25:16 +00001750
Eric Andersen2870d962001-07-02 17:27:21 +00001751/*
1752 * A job structure contains information about a job. A job is either a
1753 * single process or a set of processes contained in a pipeline. In the
1754 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1755 * array of pids.
1756 */
Eric Andersencb57d552001-06-28 07:25:16 +00001757
Eric Andersen2870d962001-07-02 17:27:21 +00001758struct procstat {
1759 pid_t pid; /* process id */
1760 int status; /* status flags (defined above) */
1761 char *cmd; /* text of command being run */
1762};
Eric Andersencb57d552001-06-28 07:25:16 +00001763
Eric Andersen2870d962001-07-02 17:27:21 +00001764
1765static int job_warning; /* user was warned about stopped jobs */
1766
1767#ifdef JOBS
1768static void setjobctl(int enable);
1769#else
1770#define setjobctl(on) /* do nothing */
Eric Andersencb57d552001-06-28 07:25:16 +00001771#endif
1772
Eric Andersen2870d962001-07-02 17:27:21 +00001773
1774struct job {
1775 struct procstat ps0; /* status of process */
1776 struct procstat *ps; /* status or processes when more than one */
1777 short nprocs; /* number of processes */
1778 short pgrp; /* process group of this job */
1779 char state; /* true if job is finished */
1780 char used; /* true if this entry is in used */
1781 char changed; /* true if status has changed */
1782#ifdef JOBS
1783 char jobctl; /* job running under job control */
1784#endif
1785};
1786
1787static struct job *jobtab; /* array of jobs */
1788static int njobs; /* size of array */
1789static int backgndpid = -1; /* pid of last background process */
1790#ifdef JOBS
1791static int initialpgrp; /* pgrp of shell on invocation */
1792static int curjob; /* current job */
1793static int jobctl;
1794#endif
1795static int intreceived;
1796
1797static struct job *makejob (union node *, int);
1798static int forkshell (struct job *, union node *, int);
1799static int waitforjob (struct job *);
1800
1801static int docd (char *, int);
1802static char *getcomponent (void);
1803static void updatepwd (const char *);
1804static void getpwd (void);
1805
1806static char *padvance (const char **, const char *);
1807
1808static char nullstr[1]; /* zero length string */
1809static char *curdir = nullstr; /* current working directory */
1810static char *cdcomppath;
1811
Eric Andersencb57d552001-06-28 07:25:16 +00001812static int
1813cdcmd(argc, argv)
1814 int argc;
1815 char **argv;
1816{
1817 const char *dest;
1818 const char *path;
1819 char *p;
1820 struct stat statb;
1821 int print = 0;
1822
1823 nextopt(nullstr);
1824 if ((dest = *argptr) == NULL && (dest = bltinlookup("HOME")) == NULL)
1825 error("HOME not set");
1826 if (*dest == '\0')
Eric Andersen2870d962001-07-02 17:27:21 +00001827 dest = ".";
Eric Andersencb57d552001-06-28 07:25:16 +00001828 if (dest[0] == '-' && dest[1] == '\0') {
1829 dest = bltinlookup("OLDPWD");
1830 if (!dest || !*dest) {
1831 dest = curdir;
1832 }
1833 print = 1;
1834 if (dest)
Eric Andersen2870d962001-07-02 17:27:21 +00001835 print = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00001836 else
Eric Andersen2870d962001-07-02 17:27:21 +00001837 dest = ".";
Eric Andersencb57d552001-06-28 07:25:16 +00001838 }
1839 if (*dest == '/' || (path = bltinlookup("CDPATH")) == NULL)
1840 path = nullstr;
1841 while ((p = padvance(&path, dest)) != NULL) {
1842 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
1843 if (!print) {
1844 /*
1845 * XXX - rethink
1846 */
1847 if (p[0] == '.' && p[1] == '/' && p[2] != '\0')
1848 p += 2;
1849 print = strcmp(p, dest);
1850 }
1851 if (docd(p, print) >= 0)
1852 return 0;
1853
1854 }
1855 }
1856 error("can't cd to %s", dest);
1857 /* NOTREACHED */
1858}
1859
1860
1861/*
1862 * Actually do the chdir. In an interactive shell, print the
1863 * directory name if "print" is nonzero.
1864 */
1865
1866static int
1867docd(dest, print)
1868 char *dest;
1869 int print;
1870{
1871 char *p;
1872 char *q;
1873 char *component;
1874 struct stat statb;
1875 int first;
1876 int badstat;
1877
1878 TRACE(("docd(\"%s\", %d) called\n", dest, print));
1879
1880 /*
1881 * Check each component of the path. If we find a symlink or
1882 * something we can't stat, clear curdir to force a getcwd()
1883 * next time we get the value of the current directory.
1884 */
1885 badstat = 0;
1886 cdcomppath = sstrdup(dest);
1887 STARTSTACKSTR(p);
1888 if (*dest == '/') {
1889 STPUTC('/', p);
1890 cdcomppath++;
1891 }
1892 first = 1;
1893 while ((q = getcomponent()) != NULL) {
1894 if (q[0] == '\0' || (q[0] == '.' && q[1] == '\0'))
1895 continue;
1896 if (! first)
1897 STPUTC('/', p);
1898 first = 0;
1899 component = q;
1900 while (*q)
1901 STPUTC(*q++, p);
1902 if (equal(component, ".."))
1903 continue;
1904 STACKSTRNUL(p);
1905 if ((lstat(stackblock(), &statb) < 0)
1906 || (S_ISLNK(statb.st_mode))) {
1907 /* print = 1; */
1908 badstat = 1;
1909 break;
1910 }
1911 }
1912
1913 INTOFF;
1914 if (chdir(dest) < 0) {
1915 INTON;
1916 return -1;
1917 }
1918 updatepwd(badstat ? NULL : dest);
1919 INTON;
1920 if (print && iflag)
1921 out1fmt(snlfmt, curdir);
1922 return 0;
1923}
1924
1925
1926/*
1927 * Get the next component of the path name pointed to by cdcomppath.
1928 * This routine overwrites the string pointed to by cdcomppath.
1929 */
1930
1931static char *
1932getcomponent() {
1933 char *p;
1934 char *start;
1935
1936 if ((p = cdcomppath) == NULL)
1937 return NULL;
1938 start = cdcomppath;
1939 while (*p != '/' && *p != '\0')
1940 p++;
1941 if (*p == '\0') {
1942 cdcomppath = NULL;
1943 } else {
1944 *p++ = '\0';
1945 cdcomppath = p;
1946 }
1947 return start;
1948}
1949
1950
1951
1952/*
1953 * Update curdir (the name of the current directory) in response to a
1954 * cd command. We also call hashcd to let the routines in exec.c know
1955 * that the current directory has changed.
1956 */
1957
Eric Andersen2870d962001-07-02 17:27:21 +00001958static void hashcd (void);
1959
Eric Andersencb57d552001-06-28 07:25:16 +00001960static void
Eric Andersen2870d962001-07-02 17:27:21 +00001961updatepwd(const char *dir)
1962{
Eric Andersencb57d552001-06-28 07:25:16 +00001963 char *new;
1964 char *p;
1965 size_t len;
1966
Eric Andersen2870d962001-07-02 17:27:21 +00001967 hashcd(); /* update command hash table */
Eric Andersencb57d552001-06-28 07:25:16 +00001968
1969 /*
1970 * If our argument is NULL, we don't know the current directory
1971 * any more because we traversed a symbolic link or something
1972 * we couldn't stat().
1973 */
1974 if (dir == NULL || curdir == nullstr) {
1975 setpwd(0, 1);
1976 return;
1977 }
1978 len = strlen(dir);
1979 cdcomppath = sstrdup(dir);
1980 STARTSTACKSTR(new);
1981 if (*dir != '/') {
1982 p = curdir;
1983 while (*p)
1984 STPUTC(*p++, new);
1985 if (p[-1] == '/')
1986 STUNPUTC(new);
1987 }
1988 while ((p = getcomponent()) != NULL) {
1989 if (equal(p, "..")) {
1990 while (new > stackblock() && (STUNPUTC(new), *new) != '/');
1991 } else if (*p != '\0' && ! equal(p, ".")) {
1992 STPUTC('/', new);
1993 while (*p)
1994 STPUTC(*p++, new);
1995 }
1996 }
1997 if (new == stackblock())
1998 STPUTC('/', new);
1999 STACKSTRNUL(new);
2000 setpwd(stackblock(), 1);
2001}
2002
2003
Eric Andersen3102ac42001-07-06 04:26:23 +00002004#ifndef BB_PWD
Eric Andersencb57d552001-06-28 07:25:16 +00002005static int
2006pwdcmd(argc, argv)
2007 int argc;
2008 char **argv;
2009{
2010 out1fmt(snlfmt, curdir);
2011 return 0;
2012}
Eric Andersen2870d962001-07-02 17:27:21 +00002013#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002014
2015/*
2016 * Find out what the current directory is. If we already know the current
2017 * directory, this routine returns immediately.
2018 */
2019static void
Eric Andersen2870d962001-07-02 17:27:21 +00002020getpwd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00002021{
Eric Andersen2870d962001-07-02 17:27:21 +00002022 curdir = xgetcwd(0);
2023 if(curdir==0)
2024 curdir = nullstr;
Eric Andersencb57d552001-06-28 07:25:16 +00002025}
2026
2027static void
2028setpwd(const char *val, int setold)
2029{
2030 if (setold) {
2031 setvar("OLDPWD", curdir, VEXPORT);
2032 }
2033 INTOFF;
2034 if (curdir != nullstr) {
2035 free(curdir);
2036 curdir = nullstr;
2037 }
2038 if (!val) {
2039 getpwd();
2040 } else {
2041 curdir = savestr(val);
2042 }
2043 INTON;
2044 setvar("PWD", curdir, VEXPORT);
2045}
2046
Eric Andersencb57d552001-06-28 07:25:16 +00002047/*
2048 * Errors and exceptions.
2049 */
2050
2051/*
2052 * Code to handle exceptions in C.
2053 */
2054
Eric Andersen2870d962001-07-02 17:27:21 +00002055/*
2056 * We enclose jmp_buf in a structure so that we can declare pointers to
2057 * jump locations. The global variable handler contains the location to
2058 * jump to when an exception occurs, and the global variable exception
2059 * contains a code identifying the exeception. To implement nested
2060 * exception handlers, the user should save the value of handler on entry
2061 * to an inner scope, set handler to point to a jmploc structure for the
2062 * inner scope, and restore handler on exit from the scope.
2063 */
2064
2065struct jmploc {
2066 jmp_buf loc;
2067};
2068
2069/* exceptions */
2070#define EXINT 0 /* SIGINT received */
2071#define EXERROR 1 /* a generic error */
2072#define EXSHELLPROC 2 /* execute a shell procedure */
2073#define EXEXEC 3 /* command execution failed */
2074
2075static struct jmploc *handler;
Eric Andersencb57d552001-06-28 07:25:16 +00002076static int exception;
Eric Andersencb57d552001-06-28 07:25:16 +00002077
Eric Andersen2870d962001-07-02 17:27:21 +00002078static void exverror (int, const char *, va_list)
Eric Andersencb57d552001-06-28 07:25:16 +00002079 __attribute__((__noreturn__));
2080
2081/*
2082 * Called to raise an exception. Since C doesn't include exceptions, we
2083 * just do a longjmp to the exception handler. The type of exception is
2084 * stored in the global variable "exception".
2085 */
2086
Eric Andersen2870d962001-07-02 17:27:21 +00002087static void exraise (int) __attribute__((__noreturn__));
2088
Eric Andersencb57d552001-06-28 07:25:16 +00002089static void
Eric Andersen2870d962001-07-02 17:27:21 +00002090exraise(int e)
Eric Andersencb57d552001-06-28 07:25:16 +00002091{
2092#ifdef DEBUG
2093 if (handler == NULL)
2094 abort();
2095#endif
2096 exception = e;
2097 longjmp(handler->loc, 1);
2098}
2099
2100
2101/*
2102 * Called from trap.c when a SIGINT is received. (If the user specifies
2103 * that SIGINT is to be trapped or ignored using the trap builtin, then
2104 * this routine is not called.) Suppressint is nonzero when interrupts
2105 * are held using the INTOFF macro. The call to _exit is necessary because
2106 * there is a short period after a fork before the signal handlers are
2107 * set to the appropriate value for the child. (The test for iflag is
2108 * just defensive programming.)
2109 */
2110
2111static void
Eric Andersen2870d962001-07-02 17:27:21 +00002112onint(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00002113 sigset_t mysigset;
2114
2115 if (suppressint) {
2116 intpending++;
2117 return;
2118 }
2119 intpending = 0;
2120 sigemptyset(&mysigset);
2121 sigprocmask(SIG_SETMASK, &mysigset, NULL);
2122 if (rootshell && iflag)
2123 exraise(EXINT);
2124 else {
2125 signal(SIGINT, SIG_DFL);
2126 raise(SIGINT);
2127 }
2128 /* NOTREACHED */
2129}
2130
2131
Eric Andersen2870d962001-07-02 17:27:21 +00002132static char *commandname; /* currently executing command */
2133
Eric Andersencb57d552001-06-28 07:25:16 +00002134/*
2135 * Exverror is called to raise the error exception. If the first argument
2136 * is not NULL then error prints an error message using printf style
2137 * formatting. It then raises the error exception.
2138 */
2139static void
Eric Andersen2870d962001-07-02 17:27:21 +00002140exverror(int cond, const char *msg, va_list ap)
Eric Andersencb57d552001-06-28 07:25:16 +00002141{
2142 CLEAR_PENDING_INT;
2143 INTOFF;
2144
2145#ifdef DEBUG
2146 if (msg)
2147 TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid()));
2148 else
2149 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
2150#endif
2151 if (msg) {
2152 if (commandname)
Eric Andersen3102ac42001-07-06 04:26:23 +00002153 out2fmt("%s: ", commandname);
2154 vfprintf(stderr, msg, ap);
2155 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00002156 }
2157 flushall();
2158 exraise(cond);
2159 /* NOTREACHED */
2160}
2161
2162
2163#ifdef __STDC__
2164static void
2165error(const char *msg, ...)
2166#else
2167static void
2168error(va_alist)
2169 va_dcl
2170#endif
2171{
2172#ifndef __STDC__
2173 const char *msg;
2174#endif
2175 va_list ap;
2176#ifdef __STDC__
2177 va_start(ap, msg);
2178#else
2179 va_start(ap);
2180 msg = va_arg(ap, const char *);
2181#endif
2182 exverror(EXERROR, msg, ap);
2183 /* NOTREACHED */
2184 va_end(ap);
2185}
2186
2187
2188#ifdef __STDC__
2189static void
2190exerror(int cond, const char *msg, ...)
2191#else
2192static void
2193exerror(va_alist)
2194 va_dcl
2195#endif
2196{
2197#ifndef __STDC__
2198 int cond;
2199 const char *msg;
2200#endif
2201 va_list ap;
2202#ifdef __STDC__
2203 va_start(ap, msg);
2204#else
2205 va_start(ap);
2206 cond = va_arg(ap, int);
2207 msg = va_arg(ap, const char *);
2208#endif
2209 exverror(cond, msg, ap);
2210 /* NOTREACHED */
2211 va_end(ap);
2212}
2213
2214
2215
2216/*
2217 * Table of error messages.
2218 */
2219
2220struct errname {
Eric Andersen2870d962001-07-02 17:27:21 +00002221 short errcode; /* error number */
2222 short action; /* operation which encountered the error */
Eric Andersencb57d552001-06-28 07:25:16 +00002223};
2224
Eric Andersen2870d962001-07-02 17:27:21 +00002225/*
2226 * Types of operations (passed to the errmsg routine).
2227 */
2228
2229#define E_OPEN 01 /* opening a file */
2230#define E_CREAT 02 /* creating a file */
2231#define E_EXEC 04 /* executing a program */
Eric Andersencb57d552001-06-28 07:25:16 +00002232
2233#define ALL (E_OPEN|E_CREAT|E_EXEC)
2234
2235static const struct errname errormsg[] = {
Eric Andersen2870d962001-07-02 17:27:21 +00002236 { EINTR, ALL },
2237 { EACCES, ALL },
2238 { EIO, ALL },
2239 { ENOENT, E_OPEN },
2240 { ENOENT, E_CREAT },
2241 { ENOENT, E_EXEC },
2242 { ENOTDIR, E_OPEN },
2243 { ENOTDIR, E_CREAT },
2244 { ENOTDIR, E_EXEC },
2245 { EISDIR, ALL },
2246 { EEXIST, E_CREAT },
2247#ifdef EMFILE
2248 { EMFILE, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002249#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002250 { ENFILE, ALL },
2251 { ENOSPC, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002252#ifdef EDQUOT
Eric Andersen2870d962001-07-02 17:27:21 +00002253 { EDQUOT, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002254#endif
2255#ifdef ENOSR
Eric Andersen2870d962001-07-02 17:27:21 +00002256 { ENOSR, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002257#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002258 { ENXIO, ALL },
2259 { EROFS, ALL },
2260 { ETXTBSY, ALL },
2261#ifdef EAGAIN
2262 { EAGAIN, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002263#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002264 { ENOMEM, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002265#ifdef ENOLINK
Eric Andersen2870d962001-07-02 17:27:21 +00002266 { ENOLINK, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002267#endif
2268#ifdef EMULTIHOP
Eric Andersen2870d962001-07-02 17:27:21 +00002269 { EMULTIHOP, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002270#endif
2271#ifdef ECOMM
Eric Andersen2870d962001-07-02 17:27:21 +00002272 { ECOMM, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002273#endif
2274#ifdef ESTALE
Eric Andersen2870d962001-07-02 17:27:21 +00002275 { ESTALE, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002276#endif
2277#ifdef ETIMEDOUT
Eric Andersen2870d962001-07-02 17:27:21 +00002278 { ETIMEDOUT, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002279#endif
2280#ifdef ELOOP
Eric Andersen2870d962001-07-02 17:27:21 +00002281 { ELOOP, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002282#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002283 { E2BIG, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002284#ifdef ELIBACC
Eric Andersen2870d962001-07-02 17:27:21 +00002285 { ELIBACC, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002286#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002287};
2288
Eric Andersen2870d962001-07-02 17:27:21 +00002289#define ERRNAME_SIZE (sizeof(errormsg)/sizeof(struct errname))
Eric Andersencb57d552001-06-28 07:25:16 +00002290
2291/*
2292 * Return a string describing an error. The returned string may be a
2293 * pointer to a static buffer that will be overwritten on the next call.
2294 * Action describes the operation that got the error.
2295 */
2296
2297static const char *
Eric Andersen2870d962001-07-02 17:27:21 +00002298errmsg(int e, int action)
Eric Andersencb57d552001-06-28 07:25:16 +00002299{
2300 struct errname const *ep;
2301 static char buf[12];
2302
Eric Andersen2870d962001-07-02 17:27:21 +00002303 for (ep = errormsg ; ep < errormsg+ERRNAME_SIZE; ep++) {
Eric Andersencb57d552001-06-28 07:25:16 +00002304 if (ep->errcode == e && (ep->action & action) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00002305 return strerror(e);
Eric Andersencb57d552001-06-28 07:25:16 +00002306 }
Eric Andersen2870d962001-07-02 17:27:21 +00002307
Eric Andersen3102ac42001-07-06 04:26:23 +00002308 snprintf(buf, sizeof buf, "error %d", e);
Eric Andersencb57d552001-06-28 07:25:16 +00002309 return buf;
2310}
2311
2312
Eric Andersen3102ac42001-07-06 04:26:23 +00002313#ifdef ASH_OPTIMIZE_FOR_SIZE
Eric Andersencb57d552001-06-28 07:25:16 +00002314static void
2315__inton() {
2316 if (--suppressint == 0 && intpending) {
2317 onint();
2318 }
2319}
Eric Andersen3102ac42001-07-06 04:26:23 +00002320static void forceinton (void) {
2321 suppressint = 0;
2322 if (intpending)
2323 onint();
2324}
Eric Andersencb57d552001-06-28 07:25:16 +00002325#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002326
2327/* flags in argument to evaltree */
Eric Andersen2870d962001-07-02 17:27:21 +00002328#define EV_EXIT 01 /* exit after evaluating tree */
2329#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2330#define EV_BACKCMD 04 /* command executing within back quotes */
Eric Andersencb57d552001-06-28 07:25:16 +00002331
Eric Andersen2870d962001-07-02 17:27:21 +00002332static int evalskip; /* set if we are skipping commands */
2333static int skipcount; /* number of levels to skip */
2334static int loopnest; /* current loop nesting level */
2335static int funcnest; /* depth of function calls */
Eric Andersencb57d552001-06-28 07:25:16 +00002336
2337
Eric Andersen2870d962001-07-02 17:27:21 +00002338
2339static struct strlist *cmdenviron; /* environment for builtin command */
2340static int exitstatus; /* exit status of last command */
2341static int oexitstatus; /* saved exit status */
Eric Andersencb57d552001-06-28 07:25:16 +00002342
2343
Eric Andersen2870d962001-07-02 17:27:21 +00002344static void evalloop (union node *, int);
2345static void evalfor (union node *, int);
2346static void evalcase (union node *, int);
2347static void evalsubshell (union node *, int);
2348static void expredir (union node *);
2349static void evalpipe (union node *);
Eric Andersen2870d962001-07-02 17:27:21 +00002350static void evalcommand (union node *, int);
Eric Andersen2870d962001-07-02 17:27:21 +00002351static void prehash (union node *);
2352static void eprintlist (struct strlist *);
Eric Andersencb57d552001-06-28 07:25:16 +00002353
Eric Andersen2870d962001-07-02 17:27:21 +00002354static union node *parsecmd(int);
Eric Andersencb57d552001-06-28 07:25:16 +00002355/*
2356 * Called to reset things after an exception.
2357 */
2358
Eric Andersencb57d552001-06-28 07:25:16 +00002359/*
2360 * The eval commmand.
2361 */
Eric Andersen2870d962001-07-02 17:27:21 +00002362static void evalstring (char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00002363
2364static int
2365evalcmd(argc, argv)
2366 int argc;
2367 char **argv;
2368{
Eric Andersen2870d962001-07-02 17:27:21 +00002369 char *p;
2370 char *concat;
2371 char **ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002372
Eric Andersen2870d962001-07-02 17:27:21 +00002373 if (argc > 1) {
2374 p = argv[1];
2375 if (argc > 2) {
2376 STARTSTACKSTR(concat);
2377 ap = argv + 2;
2378 for (;;) {
2379 while (*p)
2380 STPUTC(*p++, concat);
2381 if ((p = *ap++) == NULL)
2382 break;
2383 STPUTC(' ', concat);
2384 }
2385 STPUTC('\0', concat);
2386 p = grabstackstr(concat);
2387 }
2388 evalstring(p, EV_TESTED);
2389 }
2390 return exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00002391}
2392
Eric Andersencb57d552001-06-28 07:25:16 +00002393/*
2394 * Execute a command or commands contained in a string.
2395 */
2396
Eric Andersen2870d962001-07-02 17:27:21 +00002397static void evaltree (union node *, int);
2398static void setinputstring (char *);
2399static void popfile (void);
2400static void setstackmark(struct stackmark *mark);
2401static void popstackmark(struct stackmark *mark);
2402
2403
Eric Andersencb57d552001-06-28 07:25:16 +00002404static void
Eric Andersen2870d962001-07-02 17:27:21 +00002405evalstring(char *s, int flag)
2406{
Eric Andersencb57d552001-06-28 07:25:16 +00002407 union node *n;
2408 struct stackmark smark;
2409
2410 setstackmark(&smark);
2411 setinputstring(s);
2412 while ((n = parsecmd(0)) != NEOF) {
2413 evaltree(n, flag);
2414 popstackmark(&smark);
2415 }
2416 popfile();
2417 popstackmark(&smark);
2418}
2419
Eric Andersencb57d552001-06-28 07:25:16 +00002420/*
2421 * Evaluate a parse tree. The value is left in the global variable
2422 * exitstatus.
2423 */
Eric Andersen2870d962001-07-02 17:27:21 +00002424static struct builtincmd *find_builtin (const char *);
2425static void defun (char *, union node *);
Eric Andersencb57d552001-06-28 07:25:16 +00002426
2427static void
2428evaltree(n, flags)
2429 union node *n;
2430 int flags;
2431{
2432 int checkexit = 0;
2433 if (n == NULL) {
2434 TRACE(("evaltree(NULL) called\n"));
2435 goto out;
2436 }
2437 TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type));
2438 switch (n->type) {
2439 case NSEMI:
2440 evaltree(n->nbinary.ch1, flags & EV_TESTED);
2441 if (evalskip)
2442 goto out;
2443 evaltree(n->nbinary.ch2, flags);
2444 break;
2445 case NAND:
2446 evaltree(n->nbinary.ch1, EV_TESTED);
2447 if (evalskip || exitstatus != 0)
2448 goto out;
2449 evaltree(n->nbinary.ch2, flags);
2450 break;
2451 case NOR:
2452 evaltree(n->nbinary.ch1, EV_TESTED);
2453 if (evalskip || exitstatus == 0)
2454 goto out;
2455 evaltree(n->nbinary.ch2, flags);
2456 break;
2457 case NREDIR:
2458 expredir(n->nredir.redirect);
2459 redirect(n->nredir.redirect, REDIR_PUSH);
2460 evaltree(n->nredir.n, flags);
2461 popredir();
2462 break;
2463 case NSUBSHELL:
2464 evalsubshell(n, flags);
2465 break;
2466 case NBACKGND:
2467 evalsubshell(n, flags);
2468 break;
2469 case NIF: {
2470 evaltree(n->nif.test, EV_TESTED);
2471 if (evalskip)
2472 goto out;
2473 if (exitstatus == 0)
2474 evaltree(n->nif.ifpart, flags);
2475 else if (n->nif.elsepart)
2476 evaltree(n->nif.elsepart, flags);
2477 else
2478 exitstatus = 0;
2479 break;
2480 }
2481 case NWHILE:
2482 case NUNTIL:
2483 evalloop(n, flags);
2484 break;
2485 case NFOR:
2486 evalfor(n, flags);
2487 break;
2488 case NCASE:
2489 evalcase(n, flags);
2490 break;
2491 case NDEFUN: {
2492 struct builtincmd *bcmd;
2493 if (
2494 (bcmd = find_builtin(n->narg.text)) &&
Eric Andersen2870d962001-07-02 17:27:21 +00002495 IS_BUILTIN_SPECIAL(bcmd)
Eric Andersencb57d552001-06-28 07:25:16 +00002496 ) {
Eric Andersen3102ac42001-07-06 04:26:23 +00002497 out2fmt("%s is a special built-in\n", n->narg.text);
Eric Andersencb57d552001-06-28 07:25:16 +00002498 exitstatus = 1;
2499 break;
2500 }
2501 defun(n->narg.text, n->narg.next);
2502 exitstatus = 0;
2503 break;
2504 }
2505 case NNOT:
2506 evaltree(n->nnot.com, EV_TESTED);
2507 exitstatus = !exitstatus;
2508 break;
2509
2510 case NPIPE:
2511 evalpipe(n);
2512 checkexit = 1;
2513 break;
2514 case NCMD:
Eric Andersencb57d552001-06-28 07:25:16 +00002515 evalcommand(n, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00002516 checkexit = 1;
2517 break;
2518#ifdef DEBUG
2519 default:
2520 out1fmt("Node type = %d\n", n->type);
Eric Andersencb57d552001-06-28 07:25:16 +00002521 break;
2522#endif
2523 }
2524out:
2525 if (pendingsigs)
2526 dotrap();
2527 if (
2528 flags & EV_EXIT ||
2529 (checkexit && eflag && exitstatus && !(flags & EV_TESTED))
2530 )
2531 exitshell(exitstatus);
2532}
2533
2534
2535static void
2536evalloop(n, flags)
2537 union node *n;
2538 int flags;
2539{
2540 int status;
2541
2542 loopnest++;
2543 status = 0;
2544 for (;;) {
2545 evaltree(n->nbinary.ch1, EV_TESTED);
2546 if (evalskip) {
Eric Andersen2870d962001-07-02 17:27:21 +00002547skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00002548 evalskip = 0;
2549 continue;
2550 }
2551 if (evalskip == SKIPBREAK && --skipcount <= 0)
2552 evalskip = 0;
2553 break;
2554 }
2555 if (n->type == NWHILE) {
2556 if (exitstatus != 0)
2557 break;
2558 } else {
2559 if (exitstatus == 0)
2560 break;
2561 }
2562 evaltree(n->nbinary.ch2, flags & EV_TESTED);
2563 status = exitstatus;
2564 if (evalskip)
2565 goto skipping;
2566 }
2567 loopnest--;
2568 exitstatus = status;
2569}
2570
Eric Andersen2870d962001-07-02 17:27:21 +00002571static void expandarg (union node *, struct arglist *, int);
2572static void fixredir(union node *n, const char *text, int err);
Eric Andersencb57d552001-06-28 07:25:16 +00002573
2574static void
2575evalfor(n, flags)
2576 union node *n;
2577 int flags;
2578{
2579 struct arglist arglist;
2580 union node *argp;
2581 struct strlist *sp;
2582 struct stackmark smark;
2583
2584 setstackmark(&smark);
2585 arglist.lastp = &arglist.list;
2586 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
2587 oexitstatus = exitstatus;
2588 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
2589 if (evalskip)
2590 goto out;
2591 }
2592 *arglist.lastp = NULL;
2593
2594 exitstatus = 0;
2595 loopnest++;
2596 for (sp = arglist.list ; sp ; sp = sp->next) {
2597 setvar(n->nfor.var, sp->text, 0);
2598 evaltree(n->nfor.body, flags & EV_TESTED);
2599 if (evalskip) {
2600 if (evalskip == SKIPCONT && --skipcount <= 0) {
2601 evalskip = 0;
2602 continue;
2603 }
2604 if (evalskip == SKIPBREAK && --skipcount <= 0)
2605 evalskip = 0;
2606 break;
2607 }
2608 }
2609 loopnest--;
2610out:
2611 popstackmark(&smark);
2612}
2613
2614
Eric Andersencb57d552001-06-28 07:25:16 +00002615static void
2616evalcase(n, flags)
2617 union node *n;
2618 int flags;
2619{
2620 union node *cp;
2621 union node *patp;
2622 struct arglist arglist;
2623 struct stackmark smark;
2624
2625 setstackmark(&smark);
2626 arglist.lastp = &arglist.list;
2627 oexitstatus = exitstatus;
2628 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
2629 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2630 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
2631 if (casematch(patp, arglist.list->text)) {
2632 if (evalskip == 0) {
2633 evaltree(cp->nclist.body, flags);
2634 }
2635 goto out;
2636 }
2637 }
2638 }
2639out:
2640 popstackmark(&smark);
2641}
2642
Eric Andersencb57d552001-06-28 07:25:16 +00002643/*
2644 * Kick off a subshell to evaluate a tree.
2645 */
2646
2647static void
2648evalsubshell(n, flags)
2649 union node *n;
2650 int flags;
2651{
2652 struct job *jp;
2653 int backgnd = (n->type == NBACKGND);
2654
2655 expredir(n->nredir.redirect);
2656 jp = makejob(n, 1);
2657 if (forkshell(jp, n, backgnd) == 0) {
2658 if (backgnd)
2659 flags &=~ EV_TESTED;
2660 redirect(n->nredir.redirect, 0);
Eric Andersen2870d962001-07-02 17:27:21 +00002661 evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00002662 }
2663 if (! backgnd) {
2664 INTOFF;
2665 exitstatus = waitforjob(jp);
2666 INTON;
2667 }
2668}
2669
2670
Eric Andersencb57d552001-06-28 07:25:16 +00002671/*
2672 * Compute the names of the files in a redirection list.
2673 */
2674
2675static void
2676expredir(n)
2677 union node *n;
2678{
2679 union node *redir;
2680
2681 for (redir = n ; redir ; redir = redir->nfile.next) {
2682 struct arglist fn;
2683 fn.lastp = &fn.list;
2684 oexitstatus = exitstatus;
2685 switch (redir->type) {
2686 case NFROMTO:
2687 case NFROM:
2688 case NTO:
2689 case NAPPEND:
2690 case NTOOV:
2691 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
2692 redir->nfile.expfname = fn.list->text;
2693 break;
2694 case NFROMFD:
2695 case NTOFD:
2696 if (redir->ndup.vname) {
2697 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
2698 fixredir(redir, fn.list->text, 1);
2699 }
2700 break;
2701 }
2702 }
2703}
2704
Eric Andersencb57d552001-06-28 07:25:16 +00002705/*
2706 * Evaluate a pipeline. All the processes in the pipeline are children
2707 * of the process creating the pipeline. (This differs from some versions
2708 * of the shell, which make the last process in a pipeline the parent
2709 * of all the rest.)
2710 */
2711
2712static void
2713evalpipe(n)
2714 union node *n;
2715{
2716 struct job *jp;
2717 struct nodelist *lp;
2718 int pipelen;
2719 int prevfd;
2720 int pip[2];
2721
2722 TRACE(("evalpipe(0x%lx) called\n", (long)n));
2723 pipelen = 0;
2724 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
2725 pipelen++;
2726 INTOFF;
2727 jp = makejob(n, pipelen);
2728 prevfd = -1;
2729 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
2730 prehash(lp->n);
2731 pip[1] = -1;
2732 if (lp->next) {
2733 if (pipe(pip) < 0) {
2734 close(prevfd);
2735 error("Pipe call failed");
2736 }
2737 }
2738 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
2739 INTON;
2740 if (prevfd > 0) {
2741 close(0);
2742 dup_as_newfd(prevfd, 0);
2743 close(prevfd);
2744 if (pip[0] == 0) {
2745 pip[0] = -1;
2746 }
2747 }
2748 if (pip[1] >= 0) {
2749 if (pip[0] >= 0) {
2750 close(pip[0]);
2751 }
2752 if (pip[1] != 1) {
2753 close(1);
2754 dup_as_newfd(pip[1], 1);
2755 close(pip[1]);
2756 }
2757 }
2758 evaltree(lp->n, EV_EXIT);
2759 }
2760 if (prevfd >= 0)
2761 close(prevfd);
2762 prevfd = pip[0];
2763 close(pip[1]);
2764 }
2765 INTON;
2766 if (n->npipe.backgnd == 0) {
2767 INTOFF;
2768 exitstatus = waitforjob(jp);
2769 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
2770 INTON;
2771 }
2772}
2773
2774
2775
2776/*
2777 * Execute a command inside back quotes. If it's a builtin command, we
2778 * want to save its output in a block obtained from malloc. Otherwise
2779 * we fork off a subprocess and get the output of the command via a pipe.
2780 * Should be called with interrupts off.
2781 */
2782
2783static void
Eric Andersen2870d962001-07-02 17:27:21 +00002784evalbackcmd(union node *n, struct backcmd *result)
Eric Andersencb57d552001-06-28 07:25:16 +00002785{
2786 int pip[2];
2787 struct job *jp;
Eric Andersen2870d962001-07-02 17:27:21 +00002788 struct stackmark smark; /* unnecessary */
Eric Andersencb57d552001-06-28 07:25:16 +00002789
2790 setstackmark(&smark);
2791 result->fd = -1;
2792 result->buf = NULL;
2793 result->nleft = 0;
2794 result->jp = NULL;
2795 if (n == NULL) {
2796 exitstatus = 0;
2797 goto out;
2798 }
Eric Andersen3102ac42001-07-06 04:26:23 +00002799 exitstatus = 0;
2800 if (pipe(pip) < 0)
2801 error("Pipe call failed");
2802 jp = makejob(n, 1);
2803 if (forkshell(jp, n, FORK_NOJOB) == 0) {
2804 FORCEINTON;
2805 close(pip[0]);
2806 if (pip[1] != 1) {
2807 close(1);
2808 dup_as_newfd(pip[1], 1);
2809 close(pip[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00002810 }
Eric Andersen3102ac42001-07-06 04:26:23 +00002811 eflag = 0;
2812 evaltree(n, EV_EXIT);
Eric Andersencb57d552001-06-28 07:25:16 +00002813 }
Eric Andersen3102ac42001-07-06 04:26:23 +00002814 close(pip[1]);
2815 result->fd = pip[0];
2816 result->jp = jp;
Eric Andersencb57d552001-06-28 07:25:16 +00002817out:
2818 popstackmark(&smark);
2819 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
2820 result->fd, result->buf, result->nleft, result->jp));
2821}
2822
2823
2824
2825/*
2826 * Execute a simple command.
2827 */
2828
Eric Andersen2870d962001-07-02 17:27:21 +00002829static void find_command (const char *, struct cmdentry *, int, const char *);
2830
2831static int
2832isassignment(const char *word) {
2833 if (!is_name(*word)) {
2834 return 0;
2835 }
2836 do {
2837 word++;
2838 } while (is_in_name(*word));
2839 return *word == '=';
2840}
2841
Eric Andersencb57d552001-06-28 07:25:16 +00002842static void
Eric Andersen3102ac42001-07-06 04:26:23 +00002843evalcommand(union node *cmd, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00002844{
2845 struct stackmark smark;
2846 union node *argp;
2847 struct arglist arglist;
2848 struct arglist varlist;
2849 char **argv;
2850 int argc;
2851 char **envp;
2852 struct strlist *sp;
2853 int mode;
Eric Andersencb57d552001-06-28 07:25:16 +00002854 struct cmdentry cmdentry;
2855 struct job *jp;
2856 char *volatile savecmdname;
2857 volatile struct shparam saveparam;
2858 struct localvar *volatile savelocalvars;
2859 volatile int e;
2860 char *lastarg;
2861 const char *path;
2862 const struct builtincmd *firstbltin;
2863 struct jmploc *volatile savehandler;
2864 struct jmploc jmploc;
2865#if __GNUC__
2866 /* Avoid longjmp clobbering */
2867 (void) &argv;
2868 (void) &argc;
2869 (void) &lastarg;
2870 (void) &flags;
2871#endif
2872
2873 /* First expand the arguments. */
2874 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
2875 setstackmark(&smark);
2876 arglist.lastp = &arglist.list;
2877 varlist.lastp = &varlist.list;
2878 arglist.list = 0;
2879 oexitstatus = exitstatus;
2880 exitstatus = 0;
2881 path = pathval();
2882 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
2883 expandarg(argp, &varlist, EXP_VARTILDE);
2884 }
2885 for (
2886 argp = cmd->ncmd.args; argp && !arglist.list;
2887 argp = argp->narg.next
2888 ) {
2889 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
2890 }
2891 if (argp) {
2892 struct builtincmd *bcmd;
2893 bool pseudovarflag;
2894 bcmd = find_builtin(arglist.list->text);
Eric Andersen2870d962001-07-02 17:27:21 +00002895 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
Eric Andersencb57d552001-06-28 07:25:16 +00002896 for (; argp; argp = argp->narg.next) {
2897 if (pseudovarflag && isassignment(argp->narg.text)) {
2898 expandarg(argp, &arglist, EXP_VARTILDE);
2899 continue;
2900 }
2901 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
2902 }
2903 }
2904 *arglist.lastp = NULL;
2905 *varlist.lastp = NULL;
2906 expredir(cmd->ncmd.redirect);
2907 argc = 0;
2908 for (sp = arglist.list ; sp ; sp = sp->next)
2909 argc++;
2910 argv = stalloc(sizeof (char *) * (argc + 1));
2911
2912 for (sp = arglist.list ; sp ; sp = sp->next) {
2913 TRACE(("evalcommand arg: %s\n", sp->text));
2914 *argv++ = sp->text;
2915 }
2916 *argv = NULL;
2917 lastarg = NULL;
2918 if (iflag && funcnest == 0 && argc > 0)
2919 lastarg = argv[-1];
2920 argv -= argc;
2921
2922 /* Print the command if xflag is set. */
2923 if (xflag) {
Eric Andersen3102ac42001-07-06 04:26:23 +00002924 out2c('+');
Eric Andersencb57d552001-06-28 07:25:16 +00002925 eprintlist(varlist.list);
2926 eprintlist(arglist.list);
Eric Andersen3102ac42001-07-06 04:26:23 +00002927 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00002928 }
2929
2930 /* Now locate the command. */
2931 if (argc == 0) {
2932 cmdentry.cmdtype = CMDBUILTIN;
2933 firstbltin = cmdentry.u.cmd = BLTINCMD;
2934 } else {
2935 const char *oldpath;
2936 int findflag = DO_ERR;
2937 int oldfindflag;
2938
2939 /*
2940 * Modify the command lookup path, if a PATH= assignment
2941 * is present
2942 */
2943 for (sp = varlist.list ; sp ; sp = sp->next)
2944 if (varequal(sp->text, defpathvar)) {
2945 path = sp->text + 5;
2946 findflag |= DO_BRUTE;
2947 }
2948 oldpath = path;
2949 oldfindflag = findflag;
2950 firstbltin = 0;
2951 for(;;) {
2952 find_command(argv[0], &cmdentry, findflag, path);
Eric Andersen2870d962001-07-02 17:27:21 +00002953 if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */
Eric Andersencb57d552001-06-28 07:25:16 +00002954 exitstatus = 127;
Eric Andersencb57d552001-06-28 07:25:16 +00002955 goto out;
2956 }
2957 /* implement bltin and command here */
2958 if (cmdentry.cmdtype != CMDBUILTIN) {
2959 break;
2960 }
2961 if (!firstbltin) {
2962 firstbltin = cmdentry.u.cmd;
2963 }
2964 if (cmdentry.u.cmd == BLTINCMD) {
2965 for(;;) {
2966 struct builtincmd *bcmd;
2967
2968 argv++;
2969 if (--argc == 0)
2970 goto found;
2971 if (!(bcmd = find_builtin(*argv))) {
Eric Andersen3102ac42001-07-06 04:26:23 +00002972 out2fmt("%s: not found\n", *argv);
Eric Andersencb57d552001-06-28 07:25:16 +00002973 exitstatus = 127;
Eric Andersencb57d552001-06-28 07:25:16 +00002974 goto out;
2975 }
2976 cmdentry.u.cmd = bcmd;
2977 if (bcmd != BLTINCMD)
2978 break;
2979 }
2980 }
Eric Andersen2870d962001-07-02 17:27:21 +00002981 if (cmdentry.u.cmd == find_builtin("command")) {
Eric Andersencb57d552001-06-28 07:25:16 +00002982 argv++;
2983 if (--argc == 0) {
2984 goto found;
2985 }
2986 if (*argv[0] == '-') {
2987 if (!equal(argv[0], "-p")) {
2988 argv--;
2989 argc++;
2990 break;
2991 }
2992 argv++;
2993 if (--argc == 0) {
2994 goto found;
2995 }
2996 path = defpath;
2997 findflag |= DO_BRUTE;
2998 } else {
2999 path = oldpath;
3000 findflag = oldfindflag;
3001 }
3002 findflag |= DO_NOFUN;
3003 continue;
3004 }
3005found:
3006 break;
3007 }
3008 }
3009
3010 /* Fork off a child process if necessary. */
3011 if (cmd->ncmd.backgnd
3012 || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0)
Eric Andersencb57d552001-06-28 07:25:16 +00003013 ) {
3014 jp = makejob(cmd, 1);
3015 mode = cmd->ncmd.backgnd;
Eric Andersencb57d552001-06-28 07:25:16 +00003016 if (forkshell(jp, cmd, mode) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00003017 goto parent; /* at end of routine */
Eric Andersencb57d552001-06-28 07:25:16 +00003018 flags |= EV_EXIT;
3019 }
3020
3021 /* This is the child process if a fork occurred. */
3022 /* Execute the command. */
3023 if (cmdentry.cmdtype == CMDFUNCTION) {
3024#ifdef DEBUG
3025 trputs("Shell function: "); trargs(argv);
3026#endif
3027 exitstatus = oexitstatus;
3028 redirect(cmd->ncmd.redirect, REDIR_PUSH);
3029 saveparam = shellparam;
3030 shellparam.malloc = 0;
3031 shellparam.nparam = argc - 1;
3032 shellparam.p = argv + 1;
3033 INTOFF;
3034 savelocalvars = localvars;
3035 localvars = NULL;
3036 INTON;
3037 if (setjmp(jmploc.loc)) {
3038 if (exception == EXSHELLPROC) {
3039 freeparam((volatile struct shparam *)
3040 &saveparam);
3041 } else {
3042 saveparam.optind = shellparam.optind;
3043 saveparam.optoff = shellparam.optoff;
3044 freeparam(&shellparam);
3045 shellparam = saveparam;
3046 }
3047 poplocalvars();
3048 localvars = savelocalvars;
3049 handler = savehandler;
3050 longjmp(handler->loc, 1);
3051 }
3052 savehandler = handler;
3053 handler = &jmploc;
3054 for (sp = varlist.list ; sp ; sp = sp->next)
3055 mklocal(sp->text);
3056 funcnest++;
3057 evaltree(cmdentry.u.func, flags & EV_TESTED);
3058 funcnest--;
3059 INTOFF;
3060 poplocalvars();
3061 localvars = savelocalvars;
3062 saveparam.optind = shellparam.optind;
3063 saveparam.optoff = shellparam.optoff;
3064 freeparam(&shellparam);
3065 shellparam = saveparam;
3066 handler = savehandler;
3067 popredir();
3068 INTON;
3069 if (evalskip == SKIPFUNC) {
3070 evalskip = 0;
3071 skipcount = 0;
3072 }
3073 if (flags & EV_EXIT)
3074 exitshell(exitstatus);
3075 } else if (cmdentry.cmdtype == CMDBUILTIN) {
3076#ifdef DEBUG
3077 trputs("builtin command: "); trargs(argv);
3078#endif
3079 mode = (cmdentry.u.cmd == EXECCMD)? 0 : REDIR_PUSH;
Eric Andersencb57d552001-06-28 07:25:16 +00003080 redirect(cmd->ncmd.redirect, mode);
3081 savecmdname = commandname;
Eric Andersen2870d962001-07-02 17:27:21 +00003082 if (IS_BUILTIN_SPECIAL(firstbltin)) {
Eric Andersencb57d552001-06-28 07:25:16 +00003083 listsetvar(varlist.list);
3084 } else {
3085 cmdenviron = varlist.list;
3086 }
3087 e = -1;
3088 if (setjmp(jmploc.loc)) {
3089 e = exception;
3090 exitstatus = (e == EXINT)? SIGINT+128 : 2;
3091 goto cmddone;
3092 }
3093 savehandler = handler;
3094 handler = &jmploc;
3095 commandname = argv[0];
3096 argptr = argv + 1;
Eric Andersen2870d962001-07-02 17:27:21 +00003097 optptr = NULL; /* initialize nextopt */
Eric Andersencb57d552001-06-28 07:25:16 +00003098 exitstatus = (*cmdentry.u.cmd->builtinfunc)(argc, argv);
3099 flushall();
3100cmddone:
Eric Andersencb57d552001-06-28 07:25:16 +00003101 cmdenviron = NULL;
3102 if (e != EXSHELLPROC) {
3103 commandname = savecmdname;
3104 if (flags & EV_EXIT)
3105 exitshell(exitstatus);
3106 }
3107 handler = savehandler;
3108 if (e != -1) {
3109 if ((e != EXERROR && e != EXEXEC)
3110 || cmdentry.u.cmd == BLTINCMD
3111 || cmdentry.u.cmd == DOTCMD
3112 || cmdentry.u.cmd == EVALCMD
3113 || cmdentry.u.cmd == EXECCMD)
3114 exraise(e);
3115 FORCEINTON;
3116 }
3117 if (cmdentry.u.cmd != EXECCMD)
3118 popredir();
Eric Andersencb57d552001-06-28 07:25:16 +00003119 } else {
3120#ifdef DEBUG
3121 trputs("normal command: "); trargs(argv);
3122#endif
3123 redirect(cmd->ncmd.redirect, 0);
3124 clearredir();
3125 for (sp = varlist.list ; sp ; sp = sp->next)
3126 setvareq(sp->text, VEXPORT|VSTACK);
3127 envp = environment();
3128 shellexec(argv, envp, path, cmdentry.u.index);
3129 }
3130 goto out;
3131
Eric Andersen2870d962001-07-02 17:27:21 +00003132parent: /* parent process gets here (if we forked) */
3133 if (mode == 0) { /* argument to fork */
Eric Andersencb57d552001-06-28 07:25:16 +00003134 INTOFF;
3135 exitstatus = waitforjob(jp);
3136 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00003137 }
3138
3139out:
3140 if (lastarg)
3141 setvar("_", lastarg, 0);
3142 popstackmark(&smark);
3143}
3144
3145
3146
3147/*
3148 * Search for a command. This is called before we fork so that the
3149 * location of the command will be available in the parent as well as
3150 * the child. The check for "goodname" is an overly conservative
3151 * check that the name will not be subject to expansion.
3152 */
3153
3154static void
3155prehash(n)
3156 union node *n;
3157{
3158 struct cmdentry entry;
3159
3160 if (n->type == NCMD && n->ncmd.args)
3161 if (goodname(n->ncmd.args->narg.text))
3162 find_command(n->ncmd.args->narg.text, &entry, 0,
3163 pathval());
3164}
3165
3166
3167
3168/*
3169 * Builtin commands. Builtin commands whose functions are closely
3170 * tied to evaluation are implemented here.
3171 */
3172
3173/*
3174 * No command given, or a bltin command with no arguments. Set the
3175 * specified variables.
3176 */
3177
3178int
3179bltincmd(argc, argv)
3180 int argc;
3181 char **argv;
3182{
3183 /*
3184 * Preserve exitstatus of a previous possible redirection
3185 * as POSIX mandates
3186 */
3187 return exitstatus;
3188}
3189
3190
3191/*
3192 * Handle break and continue commands. Break, continue, and return are
3193 * all handled by setting the evalskip flag. The evaluation routines
3194 * above all check this flag, and if it is set they start skipping
3195 * commands rather than executing them. The variable skipcount is
3196 * the number of loops to break/continue, or the number of function
3197 * levels to return. (The latter is always 1.) It should probably
3198 * be an error to break out of more loops than exist, but it isn't
3199 * in the standard shell so we don't make it one here.
3200 */
3201
3202static int
3203breakcmd(argc, argv)
3204 int argc;
3205 char **argv;
3206{
3207 int n = argc > 1 ? number(argv[1]) : 1;
3208
3209 if (n > loopnest)
3210 n = loopnest;
3211 if (n > 0) {
3212 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
3213 skipcount = n;
3214 }
3215 return 0;
3216}
3217
3218
3219/*
3220 * The return command.
3221 */
3222
3223static int
3224returncmd(argc, argv)
3225 int argc;
3226 char **argv;
3227{
3228 int ret = argc > 1 ? number(argv[1]) : oexitstatus;
3229
3230 if (funcnest) {
3231 evalskip = SKIPFUNC;
3232 skipcount = 1;
3233 return ret;
3234 }
3235 else {
3236 /* Do what ksh does; skip the rest of the file */
3237 evalskip = SKIPFILE;
3238 skipcount = 1;
3239 return ret;
3240 }
3241}
3242
3243
3244#ifndef BB_TRUE_FALSE
Eric Andersen2870d962001-07-02 17:27:21 +00003245#ifdef ASH_BBAPPS_AS_BUILTINS
Eric Andersencb57d552001-06-28 07:25:16 +00003246static int
3247false_main(argc, argv)
3248 int argc;
3249 char **argv;
3250{
3251 return 1;
3252}
3253
3254
3255static int
3256true_main(argc, argv)
3257 int argc;
3258 char **argv;
3259{
3260 return 0;
3261}
3262#endif
Eric Andersen2870d962001-07-02 17:27:21 +00003263#endif
3264
3265/*
3266 * Controls whether the shell is interactive or not.
3267 */
3268
3269static void setsignal(int signo);
3270static void chkmail(int silent);
3271
3272
3273static void
3274setinteractive(int on)
3275{
3276 static int is_interactive;
3277
3278 if (on == is_interactive)
3279 return;
3280 setsignal(SIGINT);
3281 setsignal(SIGQUIT);
3282 setsignal(SIGTERM);
3283 chkmail(1);
3284 is_interactive = on;
3285}
3286
3287static void
3288optschanged(void)
3289{
3290 setinteractive(iflag);
3291 setjobctl(mflag);
3292}
3293
Eric Andersencb57d552001-06-28 07:25:16 +00003294
3295static int
3296execcmd(argc, argv)
3297 int argc;
3298 char **argv;
3299{
3300 if (argc > 1) {
3301 struct strlist *sp;
3302
Eric Andersen2870d962001-07-02 17:27:21 +00003303 iflag = 0; /* exit on error */
Eric Andersencb57d552001-06-28 07:25:16 +00003304 mflag = 0;
3305 optschanged();
3306 for (sp = cmdenviron; sp ; sp = sp->next)
3307 setvareq(sp->text, VEXPORT|VSTACK);
3308 shellexec(argv + 1, environment(), pathval(), 0);
3309 }
3310 return 0;
3311}
3312
3313static void
3314eprintlist(struct strlist *sp)
3315{
3316 for (; sp; sp = sp->next) {
Eric Andersen3102ac42001-07-06 04:26:23 +00003317 out2fmt(" %s",sp->text);
Eric Andersencb57d552001-06-28 07:25:16 +00003318 }
3319}
Eric Andersencb57d552001-06-28 07:25:16 +00003320/*
3321 * When commands are first encountered, they are entered in a hash table.
3322 * This ensures that a full path search will not have to be done for them
3323 * on each invocation.
3324 *
3325 * We should investigate converting to a linear search, even though that
3326 * would make the command name "hash" a misnomer.
3327 */
Eric Andersen2870d962001-07-02 17:27:21 +00003328#define CMDTABLESIZE 31 /* should be prime */
3329#define ARB 1 /* actual size determined at run time */
Eric Andersencb57d552001-06-28 07:25:16 +00003330
3331
3332
3333struct tblentry {
Eric Andersen2870d962001-07-02 17:27:21 +00003334 struct tblentry *next; /* next entry in hash chain */
3335 union param param; /* definition of builtin function */
3336 short cmdtype; /* index identifying command */
3337 char rehash; /* if set, cd done since entry created */
3338 char cmdname[ARB]; /* name of command */
Eric Andersencb57d552001-06-28 07:25:16 +00003339};
3340
3341
3342static struct tblentry *cmdtable[CMDTABLESIZE];
Eric Andersen2870d962001-07-02 17:27:21 +00003343static int builtinloc = -1; /* index in path of %builtin, or -1 */
3344static int exerrno = 0; /* Last exec error */
Eric Andersencb57d552001-06-28 07:25:16 +00003345
3346
Eric Andersen2870d962001-07-02 17:27:21 +00003347static void tryexec (char *, char **, char **);
3348static void printentry (struct tblentry *, int);
3349static void clearcmdentry (int);
3350static struct tblentry *cmdlookup (const char *, int);
3351static void delete_cmd_entry (void);
Eric Andersencb57d552001-06-28 07:25:16 +00003352#ifdef ASH_TYPE
Eric Andersen2870d962001-07-02 17:27:21 +00003353static int describe_command (char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00003354#endif
Eric Andersen2870d962001-07-02 17:27:21 +00003355static int path_change (const char *, int *);
Eric Andersencb57d552001-06-28 07:25:16 +00003356
3357
3358/*
3359 * Exec a program. Never returns. If you change this routine, you may
3360 * have to change the find_command routine as well.
3361 */
3362
Eric Andersen2870d962001-07-02 17:27:21 +00003363static const char *pathopt; /* set by padvance */
3364
Eric Andersencb57d552001-06-28 07:25:16 +00003365static void
3366shellexec(argv, envp, path, idx)
3367 char **argv, **envp;
3368 const char *path;
3369 int idx;
3370{
3371 char *cmdname;
3372 int e;
3373
3374 if (strchr(argv[0], '/') != NULL) {
3375 tryexec(argv[0], argv, envp);
3376 e = errno;
3377 } else {
3378 e = ENOENT;
3379 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3380 if (--idx < 0 && pathopt == NULL) {
3381 tryexec(cmdname, argv, envp);
3382 if (errno != ENOENT && errno != ENOTDIR)
3383 e = errno;
3384 }
3385 stunalloc(cmdname);
3386 }
3387 }
3388
3389 /* Map to POSIX errors */
3390 switch (e) {
3391 case EACCES:
3392 exerrno = 126;
3393 break;
3394 case ENOENT:
3395 exerrno = 127;
3396 break;
3397 default:
3398 exerrno = 2;
3399 break;
3400 }
3401 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3402 /* NOTREACHED */
3403}
3404
Eric Andersen2870d962001-07-02 17:27:21 +00003405/*
3406 * Clear traps on a fork.
3407 */
3408static void
3409clear_traps(void) {
3410 char **tp;
3411
3412 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
3413 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
3414 INTOFF;
3415 ckfree(*tp);
3416 *tp = NULL;
3417 if (tp != &trap[0])
3418 setsignal(tp - trap);
3419 INTON;
3420 }
3421 }
3422}
3423
3424
3425static void
3426initshellproc(void) {
3427
3428#ifdef ASH_ALIAS
3429 /* from alias.c: */
3430 {
3431 rmaliases();
3432 }
3433#endif
3434 /* from eval.c: */
3435 {
3436 exitstatus = 0;
3437 }
3438
3439 /* from exec.c: */
3440 {
3441 deletefuncs();
3442 }
3443
3444 /* from jobs.c: */
3445 {
3446 backgndpid = -1;
3447#ifdef JOBS
3448 jobctl = 0;
3449#endif
3450 }
3451
3452 /* from options.c: */
3453 {
3454 int i;
3455
3456 for (i = 0; i < NOPTS; i++)
3457 optent_val(i) = 0;
3458 optschanged();
3459
3460 }
3461
3462 /* from redir.c: */
3463 {
3464 clearredir();
3465 }
3466
3467 /* from trap.c: */
3468 {
3469 char *sm;
3470
3471 clear_traps();
3472 for (sm = sigmode ; sm < sigmode + NSIG - 1; sm++) {
3473 if (*sm == S_IGN)
3474 *sm = S_HARD_IGN;
3475 }
3476 }
3477
3478 /* from var.c: */
3479 {
3480 shprocvar();
3481 }
3482}
3483
3484static int preadbuffer(void);
3485static void pushfile (void);
3486static int preadfd (void);
3487
3488/*
3489 * Read a character from the script, returning PEOF on end of file.
3490 * Nul characters in the input are silently discarded.
3491 */
3492
Eric Andersen3102ac42001-07-06 04:26:23 +00003493#ifndef ASH_OPTIMIZE_FOR_SIZE
Eric Andersen2870d962001-07-02 17:27:21 +00003494#define pgetc_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
3495static int
3496pgetc(void)
3497{
3498 return pgetc_macro();
3499}
3500#else
3501static int
3502pgetc_macro(void)
3503{
3504 return --parsenleft >= 0? *parsenextc++ : preadbuffer();
3505}
3506
3507static inline int
3508pgetc(void)
3509{
3510 return pgetc_macro();
3511}
3512#endif
3513
3514
3515/*
3516 * Undo the last call to pgetc. Only one character may be pushed back.
3517 * PEOF may be pushed back.
3518 */
3519
3520static void
3521pungetc() {
3522 parsenleft++;
3523 parsenextc--;
3524}
3525
3526
3527static void
3528popfile(void) {
3529 struct parsefile *pf = parsefile;
3530
3531 INTOFF;
3532 if (pf->fd >= 0)
3533 close(pf->fd);
3534 if (pf->buf)
3535 ckfree(pf->buf);
3536 while (pf->strpush)
3537 popstring();
3538 parsefile = pf->prev;
3539 ckfree(pf);
3540 parsenleft = parsefile->nleft;
3541 parselleft = parsefile->lleft;
3542 parsenextc = parsefile->nextc;
3543 plinno = parsefile->linno;
3544 INTON;
3545}
3546
3547
3548/*
3549 * Return to top level.
3550 */
3551
3552static void
3553popallfiles(void) {
3554 while (parsefile != &basepf)
3555 popfile();
3556}
3557
3558/*
3559 * Close the file(s) that the shell is reading commands from. Called
3560 * after a fork is done.
3561 */
3562
3563static void
3564closescript() {
3565 popallfiles();
3566 if (parsefile->fd > 0) {
3567 close(parsefile->fd);
3568 parsefile->fd = 0;
3569 }
3570}
3571
3572
3573/*
3574 * Like setinputfile, but takes an open file descriptor. Call this with
3575 * interrupts off.
3576 */
3577
3578static void
3579setinputfd(fd, push)
3580 int fd, push;
3581{
3582 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
3583 if (push) {
3584 pushfile();
3585 parsefile->buf = 0;
3586 } else {
3587 closescript();
3588 while (parsefile->strpush)
3589 popstring();
3590 }
3591 parsefile->fd = fd;
3592 if (parsefile->buf == NULL)
3593 parsefile->buf = ckmalloc(BUFSIZ);
3594 parselleft = parsenleft = 0;
3595 plinno = 1;
3596}
3597
3598
3599/*
3600 * Set the input to take input from a file. If push is set, push the
3601 * old input onto the stack first.
3602 */
3603
3604static void
3605setinputfile(const char *fname, int push)
3606{
3607 int fd;
3608 int myfileno2;
3609
3610 INTOFF;
3611 if ((fd = open(fname, O_RDONLY)) < 0)
3612 error("Can't open %s", fname);
3613 if (fd < 10) {
3614 myfileno2 = dup_as_newfd(fd, 10);
3615 close(fd);
3616 if (myfileno2 < 0)
3617 error("Out of file descriptors");
3618 fd = myfileno2;
3619 }
3620 setinputfd(fd, push);
3621 INTON;
3622}
3623
Eric Andersencb57d552001-06-28 07:25:16 +00003624
3625static void
3626tryexec(cmd, argv, envp)
3627 char *cmd;
3628 char **argv;
3629 char **envp;
3630 {
3631 int e;
Eric Andersencb57d552001-06-28 07:25:16 +00003632
Eric Andersen3102ac42001-07-06 04:26:23 +00003633#ifdef BB_FEATURE_SH_STANDALONE_SHELL
3634 char *name = cmd;
3635 char** argv_l=argv;
3636 int argc_l;
3637#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN
3638 name = get_last_path_component(name);
3639#endif
3640 argv_l=envp;
3641 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++)
3642 putenv(*argv_l);
3643 argv_l=argv;
3644 for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++);
3645 optind = 1;
3646 run_applet_by_name(name, argc_l, argv);
3647#endif
Eric Andersencb57d552001-06-28 07:25:16 +00003648 execve(cmd, argv, envp);
Eric Andersencb57d552001-06-28 07:25:16 +00003649 e = errno;
3650 if (e == ENOEXEC) {
3651 INTOFF;
3652 initshellproc();
3653 setinputfile(cmd, 0);
3654 commandname = arg0 = savestr(argv[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00003655 setparam(argv + 1);
3656 exraise(EXSHELLPROC);
3657 }
3658 errno = e;
3659}
3660
Eric Andersen2870d962001-07-02 17:27:21 +00003661static char *commandtext (const union node *);
Eric Andersencb57d552001-06-28 07:25:16 +00003662
3663/*
3664 * Do a path search. The variable path (passed by reference) should be
3665 * set to the start of the path before the first call; padvance will update
3666 * this value as it proceeds. Successive calls to padvance will return
3667 * the possible path expansions in sequence. If an option (indicated by
3668 * a percent sign) appears in the path entry then the global variable
3669 * pathopt will be set to point to it; otherwise pathopt will be set to
3670 * NULL.
3671 */
3672
3673static const char *pathopt;
3674
Eric Andersen2870d962001-07-02 17:27:21 +00003675static void growstackblock(void);
3676
3677
Eric Andersencb57d552001-06-28 07:25:16 +00003678static char *
Eric Andersen2870d962001-07-02 17:27:21 +00003679padvance(const char **path, const char *name)
3680{
Eric Andersencb57d552001-06-28 07:25:16 +00003681 const char *p;
3682 char *q;
3683 const char *start;
3684 int len;
3685
3686 if (*path == NULL)
3687 return NULL;
3688 start = *path;
3689 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
Eric Andersen2870d962001-07-02 17:27:21 +00003690 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +00003691 while (stackblocksize() < len)
3692 growstackblock();
3693 q = stackblock();
3694 if (p != start) {
3695 memcpy(q, start, p - start);
3696 q += p - start;
3697 *q++ = '/';
3698 }
3699 strcpy(q, name);
3700 pathopt = NULL;
3701 if (*p == '%') {
3702 pathopt = ++p;
3703 while (*p && *p != ':') p++;
3704 }
3705 if (*p == ':')
3706 *path = p + 1;
3707 else
3708 *path = NULL;
3709 return stalloc(len);
3710}
3711
3712
3713
3714/*** Command hashing code ***/
3715
3716
3717static int
3718hashcmd(argc, argv)
3719 int argc;
3720 char **argv;
3721{
3722 struct tblentry **pp;
3723 struct tblentry *cmdp;
3724 int c;
3725 int verbose;
3726 struct cmdentry entry;
3727 char *name;
3728
3729 verbose = 0;
3730 while ((c = nextopt("rv")) != '\0') {
3731 if (c == 'r') {
3732 clearcmdentry(0);
3733 return 0;
3734 } else if (c == 'v') {
3735 verbose++;
3736 }
3737 }
3738 if (*argptr == NULL) {
3739 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3740 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3741 if (cmdp->cmdtype != CMDBUILTIN) {
3742 printentry(cmdp, verbose);
3743 }
3744 }
3745 }
3746 return 0;
3747 }
3748 c = 0;
3749 while ((name = *argptr) != NULL) {
3750 if ((cmdp = cmdlookup(name, 0)) != NULL
3751 && (cmdp->cmdtype == CMDNORMAL
3752 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
3753 delete_cmd_entry();
3754 find_command(name, &entry, DO_ERR, pathval());
3755 if (entry.cmdtype == CMDUNKNOWN) c = 1;
3756 else if (verbose) {
3757 cmdp = cmdlookup(name, 0);
3758 if (cmdp) printentry(cmdp, verbose);
3759 flushall();
3760 }
3761 argptr++;
3762 }
3763 return c;
3764}
3765
3766
3767static void
3768printentry(cmdp, verbose)
3769 struct tblentry *cmdp;
3770 int verbose;
3771 {
3772 int idx;
3773 const char *path;
3774 char *name;
3775
3776 if (cmdp->cmdtype == CMDNORMAL) {
3777 idx = cmdp->param.index;
3778 path = pathval();
3779 do {
3780 name = padvance(&path, cmdp->cmdname);
3781 stunalloc(name);
3782 } while (--idx >= 0);
3783 out1str(name);
3784 } else if (cmdp->cmdtype == CMDBUILTIN) {
3785 out1fmt("builtin %s", cmdp->cmdname);
3786 } else if (cmdp->cmdtype == CMDFUNCTION) {
3787 out1fmt("function %s", cmdp->cmdname);
3788 if (verbose) {
3789 INTOFF;
3790 name = commandtext(cmdp->param.func);
3791 out1fmt(" %s", name);
3792 ckfree(name);
3793 INTON;
3794 }
3795#ifdef DEBUG
3796 } else {
3797 error("internal error: cmdtype %d", cmdp->cmdtype);
3798#endif
3799 }
3800 out1fmt(snlfmt, cmdp->rehash ? "*" : nullstr);
3801}
3802
3803
3804
3805/*
3806 * Resolve a command name. If you change this routine, you may have to
3807 * change the shellexec routine as well.
3808 */
3809
Eric Andersen2870d962001-07-02 17:27:21 +00003810static int prefix (const char *, const char *);
3811
Eric Andersencb57d552001-06-28 07:25:16 +00003812static void
Eric Andersen2870d962001-07-02 17:27:21 +00003813find_command(const char *name, struct cmdentry *entry, int act, const char *path)
Eric Andersencb57d552001-06-28 07:25:16 +00003814{
3815 struct tblentry *cmdp;
3816 int idx;
3817 int prev;
3818 char *fullname;
3819 struct stat statb;
3820 int e;
3821 int bltin;
3822 int firstchange;
3823 int updatetbl;
3824 bool regular;
3825 struct builtincmd *bcmd;
3826
3827 /* If name contains a slash, don't use the hash table */
3828 if (strchr(name, '/') != NULL) {
3829 if (act & DO_ABS) {
3830 while (stat(name, &statb) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003831 if (errno != ENOENT && errno != ENOTDIR)
3832 e = errno;
3833 entry->cmdtype = CMDUNKNOWN;
3834 entry->u.index = -1;
3835 return;
3836 }
3837 entry->cmdtype = CMDNORMAL;
3838 entry->u.index = -1;
3839 return;
3840 }
3841 entry->cmdtype = CMDNORMAL;
3842 entry->u.index = 0;
3843 return;
3844 }
3845
3846 updatetbl = 1;
3847 if (act & DO_BRUTE) {
3848 firstchange = path_change(path, &bltin);
3849 } else {
3850 bltin = builtinloc;
3851 firstchange = 9999;
3852 }
3853
3854 /* If name is in the table, and not invalidated by cd, we're done */
3855 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0) {
3856 if (cmdp->cmdtype == CMDFUNCTION) {
3857 if (act & DO_NOFUN) {
3858 updatetbl = 0;
3859 } else {
3860 goto success;
3861 }
3862 } else if (act & DO_BRUTE) {
3863 if ((cmdp->cmdtype == CMDNORMAL &&
3864 cmdp->param.index >= firstchange) ||
3865 (cmdp->cmdtype == CMDBUILTIN &&
3866 ((builtinloc < 0 && bltin >= 0) ?
3867 bltin : builtinloc) >= firstchange)) {
3868 /* need to recompute the entry */
3869 } else {
3870 goto success;
3871 }
3872 } else {
3873 goto success;
3874 }
3875 }
3876
3877 bcmd = find_builtin(name);
Eric Andersen2870d962001-07-02 17:27:21 +00003878 regular = bcmd && IS_BUILTIN_REGULAR(bcmd);
Eric Andersencb57d552001-06-28 07:25:16 +00003879
3880 if (regular) {
3881 if (cmdp && (cmdp->cmdtype == CMDBUILTIN)) {
Eric Andersen2870d962001-07-02 17:27:21 +00003882 goto success;
Eric Andersencb57d552001-06-28 07:25:16 +00003883 }
3884 } else if (act & DO_BRUTE) {
3885 if (firstchange == 0) {
3886 updatetbl = 0;
3887 }
3888 }
3889
3890 /* If %builtin not in path, check for builtin next */
3891 if (regular || (bltin < 0 && bcmd)) {
3892builtin:
3893 if (!updatetbl) {
3894 entry->cmdtype = CMDBUILTIN;
3895 entry->u.cmd = bcmd;
3896 return;
3897 }
3898 INTOFF;
3899 cmdp = cmdlookup(name, 1);
3900 cmdp->cmdtype = CMDBUILTIN;
3901 cmdp->param.cmd = bcmd;
3902 INTON;
3903 goto success;
3904 }
3905
3906 /* We have to search path. */
Eric Andersen2870d962001-07-02 17:27:21 +00003907 prev = -1; /* where to start */
3908 if (cmdp && cmdp->rehash) { /* doing a rehash */
Eric Andersencb57d552001-06-28 07:25:16 +00003909 if (cmdp->cmdtype == CMDBUILTIN)
3910 prev = builtinloc;
3911 else
3912 prev = cmdp->param.index;
3913 }
3914
3915 e = ENOENT;
3916 idx = -1;
3917loop:
3918 while ((fullname = padvance(&path, name)) != NULL) {
3919 stunalloc(fullname);
3920 idx++;
3921 if (idx >= firstchange) {
3922 updatetbl = 0;
3923 }
3924 if (pathopt) {
3925 if (prefix("builtin", pathopt)) {
3926 if ((bcmd = find_builtin(name))) {
3927 goto builtin;
3928 }
3929 continue;
3930 } else if (!(act & DO_NOFUN) &&
3931 prefix("func", pathopt)) {
3932 /* handled below */
3933 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00003934 continue; /* ignore unimplemented options */
Eric Andersencb57d552001-06-28 07:25:16 +00003935 }
3936 }
3937 /* if rehash, don't redo absolute path names */
3938 if (fullname[0] == '/' && idx <= prev &&
3939 idx < firstchange) {
3940 if (idx < prev)
3941 continue;
3942 TRACE(("searchexec \"%s\": no change\n", name));
3943 goto success;
3944 }
3945 while (stat(fullname, &statb) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003946 if (errno != ENOENT && errno != ENOTDIR)
3947 e = errno;
3948 goto loop;
3949 }
Eric Andersen2870d962001-07-02 17:27:21 +00003950 e = EACCES; /* if we fail, this will be the error */
Eric Andersencb57d552001-06-28 07:25:16 +00003951 if (!S_ISREG(statb.st_mode))
3952 continue;
Eric Andersen2870d962001-07-02 17:27:21 +00003953 if (pathopt) { /* this is a %func directory */
Eric Andersencb57d552001-06-28 07:25:16 +00003954 stalloc(strlen(fullname) + 1);
3955 readcmdfile(fullname);
3956 if ((cmdp = cmdlookup(name, 0)) == NULL || cmdp->cmdtype != CMDFUNCTION)
3957 error("%s not defined in %s", name, fullname);
3958 stunalloc(fullname);
3959 goto success;
3960 }
Eric Andersencb57d552001-06-28 07:25:16 +00003961 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
3962 /* If we aren't called with DO_BRUTE and cmdp is set, it must
3963 be a function and we're being called with DO_NOFUN */
3964 if (!updatetbl) {
3965 entry->cmdtype = CMDNORMAL;
3966 entry->u.index = idx;
3967 return;
3968 }
3969 INTOFF;
3970 cmdp = cmdlookup(name, 1);
3971 cmdp->cmdtype = CMDNORMAL;
3972 cmdp->param.index = idx;
3973 INTON;
3974 goto success;
3975 }
3976
3977 /* We failed. If there was an entry for this command, delete it */
3978 if (cmdp && updatetbl)
3979 delete_cmd_entry();
3980 if (act & DO_ERR)
Eric Andersen3102ac42001-07-06 04:26:23 +00003981 out2fmt("%s: %s\n", name, errmsg(e, E_EXEC));
Eric Andersencb57d552001-06-28 07:25:16 +00003982 entry->cmdtype = CMDUNKNOWN;
3983 return;
3984
3985success:
3986 cmdp->rehash = 0;
3987 entry->cmdtype = cmdp->cmdtype;
3988 entry->u = cmdp->param;
3989}
3990
3991
3992
3993/*
3994 * Search the table of builtin commands.
3995 */
3996
Eric Andersen2870d962001-07-02 17:27:21 +00003997static int
3998bstrcmp(const void *name, const void *b)
3999{
4000 return strcmp((const char *)name, (*(const char *const *) b)+1);
4001}
4002
4003static struct builtincmd *
4004find_builtin(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00004005{
4006 struct builtincmd *bp;
4007
Eric Andersen2870d962001-07-02 17:27:21 +00004008 bp = bsearch(name, builtincmds, NUMBUILTINS, sizeof(struct builtincmd),
4009 bstrcmp
Eric Andersencb57d552001-06-28 07:25:16 +00004010 );
4011 return bp;
4012}
4013
4014
4015/*
4016 * Called when a cd is done. Marks all commands so the next time they
4017 * are executed they will be rehashed.
4018 */
4019
4020static void
Eric Andersen2870d962001-07-02 17:27:21 +00004021hashcd(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00004022 struct tblentry **pp;
4023 struct tblentry *cmdp;
4024
4025 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4026 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4027 if (cmdp->cmdtype == CMDNORMAL
4028 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
4029 cmdp->rehash = 1;
4030 }
4031 }
4032}
4033
4034
4035
4036/*
4037 * Called before PATH is changed. The argument is the new value of PATH;
4038 * pathval() still returns the old value at this point. Called with
4039 * interrupts off.
4040 */
4041
4042static void
Eric Andersen2870d962001-07-02 17:27:21 +00004043changepath(const char *newval)
Eric Andersencb57d552001-06-28 07:25:16 +00004044{
4045 int firstchange;
4046 int bltin;
4047
4048 firstchange = path_change(newval, &bltin);
4049 if (builtinloc < 0 && bltin >= 0)
Eric Andersen2870d962001-07-02 17:27:21 +00004050 builtinloc = bltin; /* zap builtins */
Eric Andersencb57d552001-06-28 07:25:16 +00004051 clearcmdentry(firstchange);
4052 builtinloc = bltin;
4053}
4054
4055
4056/*
4057 * Clear out command entries. The argument specifies the first entry in
4058 * PATH which has changed.
4059 */
4060
4061static void
4062clearcmdentry(firstchange)
4063 int firstchange;
4064{
4065 struct tblentry **tblp;
4066 struct tblentry **pp;
4067 struct tblentry *cmdp;
4068
4069 INTOFF;
4070 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4071 pp = tblp;
4072 while ((cmdp = *pp) != NULL) {
4073 if ((cmdp->cmdtype == CMDNORMAL &&
4074 cmdp->param.index >= firstchange)
4075 || (cmdp->cmdtype == CMDBUILTIN &&
4076 builtinloc >= firstchange)) {
4077 *pp = cmdp->next;
4078 ckfree(cmdp);
4079 } else {
4080 pp = &cmdp->next;
4081 }
4082 }
4083 }
4084 INTON;
4085}
4086
Eric Andersen2870d962001-07-02 17:27:21 +00004087/*
4088 * Free a parse tree.
4089 */
4090
4091static void
4092freefunc(union node *n)
4093{
4094 if (n)
4095 ckfree(n);
4096}
4097
Eric Andersencb57d552001-06-28 07:25:16 +00004098
4099/*
4100 * Delete all functions.
4101 */
4102
Eric Andersencb57d552001-06-28 07:25:16 +00004103static void
Eric Andersen2870d962001-07-02 17:27:21 +00004104deletefuncs(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00004105 struct tblentry **tblp;
4106 struct tblentry **pp;
4107 struct tblentry *cmdp;
4108
4109 INTOFF;
4110 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4111 pp = tblp;
4112 while ((cmdp = *pp) != NULL) {
4113 if (cmdp->cmdtype == CMDFUNCTION) {
4114 *pp = cmdp->next;
4115 freefunc(cmdp->param.func);
4116 ckfree(cmdp);
4117 } else {
4118 pp = &cmdp->next;
4119 }
4120 }
4121 }
4122 INTON;
4123}
4124
4125
4126
4127/*
4128 * Locate a command in the command hash table. If "add" is nonzero,
4129 * add the command to the table if it is not already present. The
4130 * variable "lastcmdentry" is set to point to the address of the link
4131 * pointing to the entry, so that delete_cmd_entry can delete the
4132 * entry.
4133 */
4134
Eric Andersen2870d962001-07-02 17:27:21 +00004135static struct tblentry **lastcmdentry;
Eric Andersencb57d552001-06-28 07:25:16 +00004136
4137static struct tblentry *
Eric Andersen2870d962001-07-02 17:27:21 +00004138cmdlookup(const char *name, int add)
Eric Andersencb57d552001-06-28 07:25:16 +00004139{
4140 int hashval;
Eric Andersen2870d962001-07-02 17:27:21 +00004141 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00004142 struct tblentry *cmdp;
4143 struct tblentry **pp;
4144
4145 p = name;
4146 hashval = *p << 4;
4147 while (*p)
4148 hashval += *p++;
4149 hashval &= 0x7FFF;
4150 pp = &cmdtable[hashval % CMDTABLESIZE];
4151 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4152 if (equal(cmdp->cmdname, name))
4153 break;
4154 pp = &cmdp->next;
4155 }
4156 if (add && cmdp == NULL) {
4157 INTOFF;
4158 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4159 + strlen(name) + 1);
4160 cmdp->next = NULL;
4161 cmdp->cmdtype = CMDUNKNOWN;
4162 cmdp->rehash = 0;
4163 strcpy(cmdp->cmdname, name);
4164 INTON;
4165 }
4166 lastcmdentry = pp;
4167 return cmdp;
4168}
4169
4170/*
4171 * Delete the command entry returned on the last lookup.
4172 */
4173
4174static void
4175delete_cmd_entry() {
4176 struct tblentry *cmdp;
4177
4178 INTOFF;
4179 cmdp = *lastcmdentry;
4180 *lastcmdentry = cmdp->next;
4181 ckfree(cmdp);
4182 INTON;
4183}
4184
4185
4186
Eric Andersencb57d552001-06-28 07:25:16 +00004187/*
4188 * Add a new command entry, replacing any existing command entry for
4189 * the same name.
4190 */
4191
4192static void
Eric Andersen2870d962001-07-02 17:27:21 +00004193addcmdentry(char *name, struct cmdentry *entry)
4194{
Eric Andersencb57d552001-06-28 07:25:16 +00004195 struct tblentry *cmdp;
4196
4197 INTOFF;
4198 cmdp = cmdlookup(name, 1);
4199 if (cmdp->cmdtype == CMDFUNCTION) {
4200 freefunc(cmdp->param.func);
4201 }
4202 cmdp->cmdtype = entry->cmdtype;
4203 cmdp->param = entry->u;
4204 INTON;
4205}
4206
4207
4208/*
4209 * Define a shell function.
4210 */
4211
Eric Andersen2870d962001-07-02 17:27:21 +00004212static union node *copyfunc(union node *);
4213
Eric Andersencb57d552001-06-28 07:25:16 +00004214static void
Eric Andersen2870d962001-07-02 17:27:21 +00004215defun(char *name, union node *func)
4216{
Eric Andersencb57d552001-06-28 07:25:16 +00004217 struct cmdentry entry;
4218
4219 entry.cmdtype = CMDFUNCTION;
4220 entry.u.func = copyfunc(func);
4221 addcmdentry(name, &entry);
4222}
4223
4224
4225/*
4226 * Delete a function if it exists.
4227 */
4228
4229static void
Eric Andersen2870d962001-07-02 17:27:21 +00004230unsetfunc(char *name)
4231{
Eric Andersencb57d552001-06-28 07:25:16 +00004232 struct tblentry *cmdp;
4233
4234 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) {
4235 freefunc(cmdp->param.func);
4236 delete_cmd_entry();
4237 }
4238}
4239
Eric Andersen2870d962001-07-02 17:27:21 +00004240/*
4241 * Wrapper around strcmp for qsort/bsearch/...
4242 */
4243static int
4244pstrcmp(const void *a, const void *b)
4245{
4246 return strcmp((const char *) a, *(const char *const *) b);
4247}
4248
4249/*
4250 * Find a keyword is in a sorted array.
4251 */
4252
4253static const char *const *
4254findkwd(const char *s)
4255{
4256 return bsearch(s, parsekwd, sizeof(parsekwd) / sizeof(const char *),
4257 sizeof(const char *), pstrcmp);
4258}
4259
Eric Andersencb57d552001-06-28 07:25:16 +00004260#ifdef ASH_TYPE
4261/*
4262 * Locate and print what a word is...
4263 */
4264
4265static int
4266typecmd(argc, argv)
4267 int argc;
4268 char **argv;
4269{
4270 int i;
4271 int err = 0;
4272
4273 for (i = 1; i < argc; i++) {
4274 err |= describe_command(argv[i], 1);
4275 }
4276 return err;
4277}
4278
4279static int
Eric Andersen2870d962001-07-02 17:27:21 +00004280describe_command(char *command, int verbose)
Eric Andersencb57d552001-06-28 07:25:16 +00004281{
4282 struct cmdentry entry;
4283 struct tblentry *cmdp;
Eric Andersen2870d962001-07-02 17:27:21 +00004284#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00004285 const struct alias *ap;
Eric Andersen2870d962001-07-02 17:27:21 +00004286#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004287 const char *path = pathval();
4288
4289 if (verbose) {
4290 out1str(command);
4291 }
4292
4293 /* First look at the keywords */
4294 if (findkwd(command)) {
4295 out1str(verbose ? " is a shell keyword" : command);
4296 goto out;
4297 }
4298
Eric Andersen2870d962001-07-02 17:27:21 +00004299#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00004300 /* Then look at the aliases */
4301 if ((ap = lookupalias(command, 0)) != NULL) {
4302 if (verbose) {
4303 out1fmt(" is an alias for %s", ap->val);
4304 } else {
4305 printalias(ap);
4306 }
4307 goto out;
4308 }
Eric Andersen2870d962001-07-02 17:27:21 +00004309#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004310 /* Then check if it is a tracked alias */
4311 if ((cmdp = cmdlookup(command, 0)) != NULL) {
4312 entry.cmdtype = cmdp->cmdtype;
4313 entry.u = cmdp->param;
4314 } else {
4315 /* Finally use brute force */
4316 find_command(command, &entry, DO_ABS, path);
4317 }
4318
4319 switch (entry.cmdtype) {
4320 case CMDNORMAL: {
4321 int j = entry.u.index;
4322 char *p;
4323 if (j == -1) {
4324 p = command;
4325 } else {
4326 do {
4327 p = padvance(&path, command);
4328 stunalloc(p);
4329 } while (--j >= 0);
4330 }
4331 if (verbose) {
4332 out1fmt(
4333 " is%s %s",
4334 cmdp ? " a tracked alias for" : nullstr, p
4335 );
4336 } else {
4337 out1str(p);
4338 }
4339 break;
4340 }
4341
4342 case CMDFUNCTION:
4343 if (verbose) {
4344 out1str(" is a shell function");
4345 } else {
4346 out1str(command);
4347 }
4348 break;
4349
4350 case CMDBUILTIN:
4351 if (verbose) {
4352 out1fmt(
4353 " is a %sshell builtin",
Eric Andersen2870d962001-07-02 17:27:21 +00004354 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
Eric Andersencb57d552001-06-28 07:25:16 +00004355 "special " : nullstr
4356 );
4357 } else {
4358 out1str(command);
4359 }
4360 break;
4361
4362 default:
4363 if (verbose) {
4364 out1str(": not found\n");
4365 }
4366 return 127;
4367 }
4368
4369out:
Eric Andersen3102ac42001-07-06 04:26:23 +00004370 putchar('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00004371 return 0;
4372}
Eric Andersen2870d962001-07-02 17:27:21 +00004373#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004374
Eric Andersen2870d962001-07-02 17:27:21 +00004375#ifdef ASH_CMDCMD
Eric Andersencb57d552001-06-28 07:25:16 +00004376static int
4377commandcmd(argc, argv)
4378 int argc;
4379 char **argv;
4380{
4381 int c;
4382 int default_path = 0;
4383 int verify_only = 0;
4384 int verbose_verify_only = 0;
4385
4386 while ((c = nextopt("pvV")) != '\0')
4387 switch (c) {
4388 case 'p':
4389 default_path = 1;
4390 break;
4391 case 'v':
4392 verify_only = 1;
4393 break;
4394 case 'V':
4395 verbose_verify_only = 1;
4396 break;
4397 default:
Eric Andersen3102ac42001-07-06 04:26:23 +00004398 out2fmt(
Eric Andersencb57d552001-06-28 07:25:16 +00004399"command: nextopt returned character code 0%o\n", c);
4400 return EX_SOFTWARE;
4401 }
4402
4403 if (default_path + verify_only + verbose_verify_only > 1 ||
4404 !*argptr) {
Eric Andersen3102ac42001-07-06 04:26:23 +00004405 out2fmt(
Eric Andersencb57d552001-06-28 07:25:16 +00004406"command [-p] command [arg ...]\n");
Eric Andersen3102ac42001-07-06 04:26:23 +00004407 out2fmt(
Eric Andersencb57d552001-06-28 07:25:16 +00004408"command {-v|-V} command\n");
4409 return EX_USAGE;
4410 }
4411
4412#ifdef ASH_TYPE
4413 if (verify_only || verbose_verify_only) {
4414 return describe_command(*argptr, verbose_verify_only);
4415 }
Eric Andersen2870d962001-07-02 17:27:21 +00004416#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004417
4418 return 0;
4419}
Eric Andersen2870d962001-07-02 17:27:21 +00004420#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004421
4422static int
4423path_change(newval, bltin)
4424 const char *newval;
4425 int *bltin;
4426{
4427 const char *old, *new;
4428 int idx;
4429 int firstchange;
4430
4431 old = pathval();
4432 new = newval;
Eric Andersen2870d962001-07-02 17:27:21 +00004433 firstchange = 9999; /* assume no change */
Eric Andersencb57d552001-06-28 07:25:16 +00004434 idx = 0;
4435 *bltin = -1;
4436 for (;;) {
4437 if (*old != *new) {
4438 firstchange = idx;
4439 if ((*old == '\0' && *new == ':')
4440 || (*old == ':' && *new == '\0'))
4441 firstchange++;
Eric Andersen2870d962001-07-02 17:27:21 +00004442 old = new; /* ignore subsequent differences */
Eric Andersencb57d552001-06-28 07:25:16 +00004443 }
4444 if (*new == '\0')
4445 break;
4446 if (*new == '%' && *bltin < 0 && prefix("builtin", new + 1))
4447 *bltin = idx;
4448 if (*new == ':') {
4449 idx++;
4450 }
4451 new++, old++;
4452 }
4453 if (builtinloc >= 0 && *bltin < 0)
4454 firstchange = 0;
4455 return firstchange;
4456}
Eric Andersencb57d552001-06-28 07:25:16 +00004457/*
4458 * Routines to expand arguments to commands. We have to deal with
4459 * backquotes, shell variables, and file metacharacters.
4460 */
4461/*
4462 * _rmescape() flags
4463 */
Eric Andersen2870d962001-07-02 17:27:21 +00004464#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4465#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Eric Andersencb57d552001-06-28 07:25:16 +00004466
4467/*
4468 * Structure specifying which parts of the string should be searched
4469 * for IFS characters.
4470 */
4471
4472struct ifsregion {
Eric Andersen2870d962001-07-02 17:27:21 +00004473 struct ifsregion *next; /* next region in list */
4474 int begoff; /* offset of start of region */
4475 int endoff; /* offset of end of region */
4476 int nulonly; /* search for nul bytes only */
Eric Andersencb57d552001-06-28 07:25:16 +00004477};
4478
4479
Eric Andersen2870d962001-07-02 17:27:21 +00004480static char *expdest; /* output of current string */
4481static struct nodelist *argbackq; /* list of back quote expressions */
4482static struct ifsregion ifsfirst; /* first struct in list of ifs regions */
4483static struct ifsregion *ifslastp; /* last struct in list */
4484static struct arglist exparg; /* holds expanded arg list */
Eric Andersencb57d552001-06-28 07:25:16 +00004485
Eric Andersen2870d962001-07-02 17:27:21 +00004486static void argstr (char *, int);
4487static char *exptilde (char *, int);
4488static void expbackq (union node *, int, int);
4489static int subevalvar (char *, char *, int, int, int, int, int);
4490static char *evalvar (char *, int);
4491static int varisset (char *, int);
4492static void strtodest (const char *, const char *, int);
4493static void varvalue (char *, int, int);
4494static void recordregion (int, int, int);
4495static void removerecordregions (int);
4496static void ifsbreakup (char *, struct arglist *);
4497static void ifsfree (void);
4498static void expandmeta (struct strlist *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004499#if defined(__GLIBC__) && !defined(FNMATCH_BROKEN)
4500#define preglob(p) _rmescapes((p), RMESCAPE_ALLOC | RMESCAPE_GLOB)
4501#if !defined(GLOB_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00004502static void addglob (const glob_t *);
Eric Andersencb57d552001-06-28 07:25:16 +00004503#endif
4504#endif
4505#if !(defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersen2870d962001-07-02 17:27:21 +00004506static void expmeta (char *, char *);
Eric Andersencb57d552001-06-28 07:25:16 +00004507#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004508#if !(defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersen2870d962001-07-02 17:27:21 +00004509static struct strlist *expsort (struct strlist *);
4510static struct strlist *msort (struct strlist *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004511#endif
4512#if defined(__GLIBC__) && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00004513static int patmatch (char *, char *, int);
4514static int patmatch2 (char *, char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004515#else
Eric Andersen2870d962001-07-02 17:27:21 +00004516static int pmatch (char *, char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004517#define patmatch2 patmatch
4518#endif
Eric Andersen2870d962001-07-02 17:27:21 +00004519static char *cvtnum (int, char *);
Eric Andersencb57d552001-06-28 07:25:16 +00004520
4521/*
4522 * Expand shell variables and backquotes inside a here document.
4523 */
4524
Eric Andersen2870d962001-07-02 17:27:21 +00004525/* arg: the document, fd: where to write the expanded version */
Eric Andersencb57d552001-06-28 07:25:16 +00004526static void
Eric Andersen2870d962001-07-02 17:27:21 +00004527expandhere(union node *arg, int fd)
4528{
Eric Andersencb57d552001-06-28 07:25:16 +00004529 herefd = fd;
4530 expandarg(arg, (struct arglist *)NULL, 0);
4531 xwrite(fd, stackblock(), expdest - stackblock());
4532}
4533
4534
4535/*
4536 * Perform variable substitution and command substitution on an argument,
4537 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4538 * perform splitting and file name expansion. When arglist is NULL, perform
4539 * here document expansion.
4540 */
4541
4542static void
4543expandarg(arg, arglist, flag)
4544 union node *arg;
4545 struct arglist *arglist;
4546 int flag;
4547{
4548 struct strlist *sp;
4549 char *p;
4550
4551 argbackq = arg->narg.backquote;
4552 STARTSTACKSTR(expdest);
4553 ifsfirst.next = NULL;
4554 ifslastp = NULL;
4555 argstr(arg->narg.text, flag);
4556 if (arglist == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00004557 return; /* here document expanded */
Eric Andersencb57d552001-06-28 07:25:16 +00004558 }
4559 STPUTC('\0', expdest);
4560 p = grabstackstr(expdest);
4561 exparg.lastp = &exparg.list;
4562 /*
4563 * TODO - EXP_REDIR
4564 */
4565 if (flag & EXP_FULL) {
4566 ifsbreakup(p, &exparg);
4567 *exparg.lastp = NULL;
4568 exparg.lastp = &exparg.list;
4569 expandmeta(exparg.list, flag);
4570 } else {
4571 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
4572 rmescapes(p);
4573 sp = (struct strlist *)stalloc(sizeof (struct strlist));
4574 sp->text = p;
4575 *exparg.lastp = sp;
4576 exparg.lastp = &sp->next;
4577 }
4578 ifsfree();
4579 *exparg.lastp = NULL;
4580 if (exparg.list) {
4581 *arglist->lastp = exparg.list;
4582 arglist->lastp = exparg.lastp;
4583 }
4584}
4585
4586
4587
4588/*
4589 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4590 * characters to allow for further processing. Otherwise treat
4591 * $@ like $* since no splitting will be performed.
4592 */
4593
4594static void
4595argstr(p, flag)
4596 char *p;
4597 int flag;
4598{
4599 char c;
Eric Andersen2870d962001-07-02 17:27:21 +00004600 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
Eric Andersencb57d552001-06-28 07:25:16 +00004601 int firsteq = 1;
4602
4603 if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
4604 p = exptilde(p, flag);
4605 for (;;) {
4606 switch (c = *p++) {
4607 case '\0':
4608 case CTLENDVAR: /* ??? */
4609 goto breakloop;
4610 case CTLQUOTEMARK:
4611 /* "$@" syntax adherence hack */
4612 if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=')
4613 break;
4614 if ((flag & EXP_FULL) != 0)
4615 STPUTC(c, expdest);
4616 break;
4617 case CTLESC:
4618 if (quotes)
4619 STPUTC(c, expdest);
4620 c = *p++;
4621 STPUTC(c, expdest);
4622 break;
4623 case CTLVAR:
4624 p = evalvar(p, flag);
4625 break;
4626 case CTLBACKQ:
4627 case CTLBACKQ|CTLQUOTE:
4628 expbackq(argbackq->n, c & CTLQUOTE, flag);
4629 argbackq = argbackq->next;
4630 break;
4631#ifdef ASH_MATH_SUPPORT
4632 case CTLENDARI:
4633 expari(flag);
4634 break;
Eric Andersen2870d962001-07-02 17:27:21 +00004635#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004636 case ':':
4637 case '=':
4638 /*
4639 * sort of a hack - expand tildes in variable
4640 * assignments (after the first '=' and after ':'s).
4641 */
4642 STPUTC(c, expdest);
4643 if (flag & EXP_VARTILDE && *p == '~') {
4644 if (c == '=') {
4645 if (firsteq)
4646 firsteq = 0;
4647 else
4648 break;
4649 }
4650 p = exptilde(p, flag);
4651 }
4652 break;
4653 default:
4654 STPUTC(c, expdest);
4655 }
4656 }
4657breakloop:;
4658 return;
4659}
4660
4661static char *
4662exptilde(p, flag)
4663 char *p;
4664 int flag;
4665{
4666 char c, *startp = p;
4667 struct passwd *pw;
4668 const char *home;
4669 int quotes = flag & (EXP_FULL | EXP_CASE);
4670
4671 while ((c = *p) != '\0') {
4672 switch(c) {
4673 case CTLESC:
4674 return (startp);
4675 case CTLQUOTEMARK:
4676 return (startp);
4677 case ':':
4678 if (flag & EXP_VARTILDE)
4679 goto done;
4680 break;
4681 case '/':
4682 goto done;
4683 }
4684 p++;
4685 }
4686done:
4687 *p = '\0';
4688 if (*(startp+1) == '\0') {
4689 if ((home = lookupvar("HOME")) == NULL)
4690 goto lose;
4691 } else {
4692 if ((pw = getpwnam(startp+1)) == NULL)
4693 goto lose;
4694 home = pw->pw_dir;
4695 }
4696 if (*home == '\0')
4697 goto lose;
4698 *p = c;
4699 strtodest(home, SQSYNTAX, quotes);
4700 return (p);
4701lose:
4702 *p = c;
4703 return (startp);
4704}
4705
4706
Eric Andersen2870d962001-07-02 17:27:21 +00004707static void
4708removerecordregions(int endoff)
Eric Andersencb57d552001-06-28 07:25:16 +00004709{
4710 if (ifslastp == NULL)
4711 return;
4712
4713 if (ifsfirst.endoff > endoff) {
4714 while (ifsfirst.next != NULL) {
4715 struct ifsregion *ifsp;
4716 INTOFF;
4717 ifsp = ifsfirst.next->next;
4718 ckfree(ifsfirst.next);
4719 ifsfirst.next = ifsp;
4720 INTON;
4721 }
4722 if (ifsfirst.begoff > endoff)
4723 ifslastp = NULL;
4724 else {
4725 ifslastp = &ifsfirst;
4726 ifsfirst.endoff = endoff;
4727 }
4728 return;
4729 }
Eric Andersen2870d962001-07-02 17:27:21 +00004730
Eric Andersencb57d552001-06-28 07:25:16 +00004731 ifslastp = &ifsfirst;
4732 while (ifslastp->next && ifslastp->next->begoff < endoff)
4733 ifslastp=ifslastp->next;
4734 while (ifslastp->next != NULL) {
4735 struct ifsregion *ifsp;
4736 INTOFF;
4737 ifsp = ifslastp->next->next;
4738 ckfree(ifslastp->next);
4739 ifslastp->next = ifsp;
4740 INTON;
4741 }
4742 if (ifslastp->endoff > endoff)
4743 ifslastp->endoff = endoff;
4744}
4745
4746
4747#ifdef ASH_MATH_SUPPORT
4748/*
4749 * Expand arithmetic expression. Backup to start of expression,
4750 * evaluate, place result in (backed up) result, adjust string position.
4751 */
4752static void
Eric Andersen2870d962001-07-02 17:27:21 +00004753expari(int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004754{
4755 char *p, *start;
4756 int result;
4757 int begoff;
4758 int quotes = flag & (EXP_FULL | EXP_CASE);
4759 int quoted;
4760
Eric Andersen2870d962001-07-02 17:27:21 +00004761 /* ifsfree(); */
Eric Andersencb57d552001-06-28 07:25:16 +00004762
4763 /*
4764 * This routine is slightly over-complicated for
4765 * efficiency. First we make sure there is
4766 * enough space for the result, which may be bigger
4767 * than the expression if we add exponentation. Next we
4768 * scan backwards looking for the start of arithmetic. If the
4769 * next previous character is a CTLESC character, then we
4770 * have to rescan starting from the beginning since CTLESC
4771 * characters have to be processed left to right.
4772 */
4773 CHECKSTRSPACE(10, expdest);
4774 USTPUTC('\0', expdest);
4775 start = stackblock();
4776 p = expdest - 1;
4777 while (*p != CTLARI && p >= start)
4778 --p;
4779 if (*p != CTLARI)
4780 error("missing CTLARI (shouldn't happen)");
4781 if (p > start && *(p-1) == CTLESC)
4782 for (p = start; *p != CTLARI; p++)
4783 if (*p == CTLESC)
4784 p++;
4785
4786 if (p[1] == '"')
4787 quoted=1;
4788 else
4789 quoted=0;
4790 begoff = p - start;
4791 removerecordregions(begoff);
4792 if (quotes)
4793 rmescapes(p+2);
4794 result = arith(p+2);
Eric Andersen3102ac42001-07-06 04:26:23 +00004795 snprintf(p, 12, "%d", result);
Eric Andersencb57d552001-06-28 07:25:16 +00004796
4797 while (*p++)
4798 ;
4799
4800 if (quoted == 0)
4801 recordregion(begoff, p - 1 - start, 0);
4802 result = expdest - p + 1;
4803 STADJUST(-result, expdest);
4804}
Eric Andersen2870d962001-07-02 17:27:21 +00004805#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004806
4807/*
4808 * Expand stuff in backwards quotes.
4809 */
4810
4811static void
4812expbackq(cmd, quoted, flag)
4813 union node *cmd;
4814 int quoted;
4815 int flag;
4816{
4817 volatile struct backcmd in;
4818 int i;
4819 char buf[128];
4820 char *p;
4821 char *dest = expdest;
4822 volatile struct ifsregion saveifs;
4823 struct ifsregion *volatile savelastp;
4824 struct nodelist *volatile saveargbackq;
4825 char lastc;
4826 int startloc = dest - stackblock();
4827 char const *syntax = quoted? DQSYNTAX : BASESYNTAX;
4828 volatile int saveherefd;
4829 int quotes = flag & (EXP_FULL | EXP_CASE);
4830 struct jmploc jmploc;
4831 struct jmploc *volatile savehandler;
4832 int ex;
4833
4834#if __GNUC__
4835 /* Avoid longjmp clobbering */
4836 (void) &dest;
4837 (void) &syntax;
4838#endif
4839
4840 in.fd = -1;
4841 in.buf = 0;
4842 in.jp = 0;
4843
4844 INTOFF;
4845 saveifs = ifsfirst;
4846 savelastp = ifslastp;
4847 saveargbackq = argbackq;
4848 saveherefd = herefd;
4849 herefd = -1;
4850 if ((ex = setjmp(jmploc.loc))) {
4851 goto err1;
4852 }
4853 savehandler = handler;
4854 handler = &jmploc;
4855 INTON;
4856 p = grabstackstr(dest);
4857 evalbackcmd(cmd, (struct backcmd *) &in);
4858 ungrabstackstr(p, dest);
4859err1:
4860 INTOFF;
4861 ifsfirst = saveifs;
4862 ifslastp = savelastp;
4863 argbackq = saveargbackq;
4864 herefd = saveherefd;
4865 if (ex) {
4866 goto err2;
4867 }
4868
4869 p = in.buf;
4870 lastc = '\0';
4871 for (;;) {
4872 if (--in.nleft < 0) {
4873 if (in.fd < 0)
4874 break;
4875 while ((i = read(in.fd, buf, sizeof buf)) < 0 && errno == EINTR);
4876 TRACE(("expbackq: read returns %d\n", i));
4877 if (i <= 0)
4878 break;
4879 p = buf;
4880 in.nleft = i - 1;
4881 }
4882 lastc = *p++;
4883 if (lastc != '\0') {
4884 if (quotes && syntax[(int)lastc] == CCTL)
4885 STPUTC(CTLESC, dest);
4886 STPUTC(lastc, dest);
4887 }
4888 }
4889
4890 /* Eat all trailing newlines */
4891 for (; dest > stackblock() && dest[-1] == '\n';)
4892 STUNPUTC(dest);
4893
4894err2:
4895 if (in.fd >= 0)
4896 close(in.fd);
4897 if (in.buf)
4898 ckfree(in.buf);
4899 if (in.jp)
4900 exitstatus = waitforjob(in.jp);
4901 handler = savehandler;
4902 if (ex) {
4903 longjmp(handler->loc, 1);
4904 }
4905 if (quoted == 0)
4906 recordregion(startloc, dest - stackblock(), 0);
4907 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
4908 (dest - stackblock()) - startloc,
4909 (dest - stackblock()) - startloc,
4910 stackblock() + startloc));
4911 expdest = dest;
4912 INTON;
4913}
4914
Eric Andersencb57d552001-06-28 07:25:16 +00004915static int
4916subevalvar(p, str, strloc, subtype, startloc, varflags, quotes)
4917 char *p;
4918 char *str;
4919 int strloc;
4920 int subtype;
4921 int startloc;
4922 int varflags;
4923 int quotes;
4924{
4925 char *startp;
4926 char *loc = NULL;
4927 char *q;
4928 int c = 0;
4929 int saveherefd = herefd;
4930 struct nodelist *saveargbackq = argbackq;
4931 int amount;
4932
4933 herefd = -1;
4934 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
4935 STACKSTRNUL(expdest);
4936 herefd = saveherefd;
4937 argbackq = saveargbackq;
4938 startp = stackblock() + startloc;
4939 if (str == NULL)
4940 str = stackblock() + strloc;
4941
4942 switch (subtype) {
4943 case VSASSIGN:
4944 setvar(str, startp, 0);
4945 amount = startp - expdest;
4946 STADJUST(amount, expdest);
4947 varflags &= ~VSNUL;
4948 if (c != 0)
4949 *loc = c;
4950 return 1;
4951
4952 case VSQUESTION:
4953 if (*p != CTLENDVAR) {
Eric Andersen3102ac42001-07-06 04:26:23 +00004954 out2fmt(snlfmt, startp);
Eric Andersencb57d552001-06-28 07:25:16 +00004955 error((char *)NULL);
4956 }
4957 error("%.*s: parameter %snot set", p - str - 1,
4958 str, (varflags & VSNUL) ? "null or "
4959 : nullstr);
4960 /* NOTREACHED */
4961
4962 case VSTRIMLEFT:
4963 for (loc = startp; loc < str; loc++) {
4964 c = *loc;
4965 *loc = '\0';
4966 if (patmatch2(str, startp, quotes))
4967 goto recordleft;
4968 *loc = c;
4969 if (quotes && *loc == CTLESC)
Eric Andersen2870d962001-07-02 17:27:21 +00004970 loc++;
Eric Andersencb57d552001-06-28 07:25:16 +00004971 }
4972 return 0;
4973
4974 case VSTRIMLEFTMAX:
4975 for (loc = str - 1; loc >= startp;) {
4976 c = *loc;
4977 *loc = '\0';
4978 if (patmatch2(str, startp, quotes))
4979 goto recordleft;
4980 *loc = c;
4981 loc--;
4982 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
4983 for (q = startp; q < loc; q++)
4984 if (*q == CTLESC)
4985 q++;
4986 if (q > loc)
4987 loc--;
4988 }
4989 }
4990 return 0;
4991
4992 case VSTRIMRIGHT:
Eric Andersen2870d962001-07-02 17:27:21 +00004993 for (loc = str - 1; loc >= startp;) {
Eric Andersencb57d552001-06-28 07:25:16 +00004994 if (patmatch2(str, loc, quotes))
4995 goto recordright;
4996 loc--;
Eric Andersen2870d962001-07-02 17:27:21 +00004997 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
Eric Andersencb57d552001-06-28 07:25:16 +00004998 for (q = startp; q < loc; q++)
4999 if (*q == CTLESC)
5000 q++;
5001 if (q > loc)
5002 loc--;
5003 }
5004 }
5005 return 0;
5006
5007 case VSTRIMRIGHTMAX:
5008 for (loc = startp; loc < str - 1; loc++) {
5009 if (patmatch2(str, loc, quotes))
5010 goto recordright;
5011 if (quotes && *loc == CTLESC)
Eric Andersen2870d962001-07-02 17:27:21 +00005012 loc++;
Eric Andersencb57d552001-06-28 07:25:16 +00005013 }
5014 return 0;
5015
5016#ifdef DEBUG
5017 default:
5018 abort();
5019#endif
5020 }
5021
5022recordleft:
5023 *loc = c;
5024 amount = ((str - 1) - (loc - startp)) - expdest;
5025 STADJUST(amount, expdest);
5026 while (loc != str - 1)
5027 *startp++ = *loc++;
5028 return 1;
5029
5030recordright:
5031 amount = loc - expdest;
5032 STADJUST(amount, expdest);
5033 STPUTC('\0', expdest);
5034 STADJUST(-1, expdest);
5035 return 1;
5036}
5037
5038
5039/*
5040 * Expand a variable, and return a pointer to the next character in the
5041 * input string.
5042 */
5043
5044static char *
5045evalvar(p, flag)
5046 char *p;
5047 int flag;
5048{
5049 int subtype;
5050 int varflags;
5051 char *var;
5052 char *val;
5053 int patloc;
5054 int c;
5055 int set;
5056 int special;
5057 int startloc;
5058 int varlen;
5059 int easy;
5060 int quotes = flag & (EXP_FULL | EXP_CASE);
5061
5062 varflags = *p++;
5063 subtype = varflags & VSTYPE;
5064 var = p;
5065 special = 0;
5066 if (! is_name(*p))
5067 special = 1;
5068 p = strchr(p, '=') + 1;
5069again: /* jump here after setting a variable with ${var=text} */
5070 if (special) {
5071 set = varisset(var, varflags & VSNUL);
5072 val = NULL;
5073 } else {
5074 val = lookupvar(var);
5075 if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
5076 val = NULL;
5077 set = 0;
5078 } else
5079 set = 1;
5080 }
5081 varlen = 0;
5082 startloc = expdest - stackblock();
5083 if (set && subtype != VSPLUS) {
5084 /* insert the value of the variable */
5085 if (special) {
5086 varvalue(var, varflags & VSQUOTE, flag);
5087 if (subtype == VSLENGTH) {
5088 varlen = expdest - stackblock() - startloc;
5089 STADJUST(-varlen, expdest);
5090 }
5091 } else {
5092 if (subtype == VSLENGTH) {
5093 varlen = strlen(val);
5094 } else {
5095 strtodest(
5096 val,
5097 varflags & VSQUOTE ?
5098 DQSYNTAX : BASESYNTAX,
5099 quotes
5100 );
5101 }
5102 }
5103 }
5104
5105 if (subtype == VSPLUS)
5106 set = ! set;
5107
5108 easy = ((varflags & VSQUOTE) == 0 ||
5109 (*var == '@' && shellparam.nparam != 1));
5110
5111
5112 switch (subtype) {
5113 case VSLENGTH:
5114 expdest = cvtnum(varlen, expdest);
5115 goto record;
5116
5117 case VSNORMAL:
5118 if (!easy)
5119 break;
5120record:
5121 recordregion(startloc, expdest - stackblock(),
5122 varflags & VSQUOTE);
5123 break;
5124
5125 case VSPLUS:
5126 case VSMINUS:
5127 if (!set) {
Eric Andersen2870d962001-07-02 17:27:21 +00005128 argstr(p, flag);
Eric Andersencb57d552001-06-28 07:25:16 +00005129 break;
5130 }
5131 if (easy)
5132 goto record;
5133 break;
5134
5135 case VSTRIMLEFT:
5136 case VSTRIMLEFTMAX:
5137 case VSTRIMRIGHT:
5138 case VSTRIMRIGHTMAX:
5139 if (!set)
5140 break;
5141 /*
5142 * Terminate the string and start recording the pattern
5143 * right after it
5144 */
5145 STPUTC('\0', expdest);
5146 patloc = expdest - stackblock();
5147 if (subevalvar(p, NULL, patloc, subtype,
5148 startloc, varflags, quotes) == 0) {
5149 int amount = (expdest - stackblock() - patloc) + 1;
5150 STADJUST(-amount, expdest);
5151 }
5152 /* Remove any recorded regions beyond start of variable */
5153 removerecordregions(startloc);
5154 goto record;
5155
5156 case VSASSIGN:
5157 case VSQUESTION:
5158 if (!set) {
5159 if (subevalvar(p, var, 0, subtype, startloc,
5160 varflags, quotes)) {
5161 varflags &= ~VSNUL;
Eric Andersen2870d962001-07-02 17:27:21 +00005162 /*
5163 * Remove any recorded regions beyond
5164 * start of variable
Eric Andersencb57d552001-06-28 07:25:16 +00005165 */
5166 removerecordregions(startloc);
5167 goto again;
5168 }
5169 break;
5170 }
5171 if (easy)
5172 goto record;
5173 break;
5174
5175#ifdef DEBUG
5176 default:
5177 abort();
5178#endif
5179 }
5180
Eric Andersen2870d962001-07-02 17:27:21 +00005181 if (subtype != VSNORMAL) { /* skip to end of alternative */
Eric Andersencb57d552001-06-28 07:25:16 +00005182 int nesting = 1;
5183 for (;;) {
5184 if ((c = *p++) == CTLESC)
5185 p++;
5186 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
5187 if (set)
5188 argbackq = argbackq->next;
5189 } else if (c == CTLVAR) {
5190 if ((*p++ & VSTYPE) != VSNORMAL)
5191 nesting++;
5192 } else if (c == CTLENDVAR) {
5193 if (--nesting == 0)
5194 break;
5195 }
5196 }
5197 }
5198 return p;
5199}
5200
Eric Andersencb57d552001-06-28 07:25:16 +00005201/*
5202 * Test whether a specialized variable is set.
5203 */
5204
5205static int
5206varisset(name, nulok)
5207 char *name;
5208 int nulok;
5209{
5210 if (*name == '!')
5211 return backgndpid != -1;
5212 else if (*name == '@' || *name == '*') {
5213 if (*shellparam.p == NULL)
5214 return 0;
5215
5216 if (nulok) {
5217 char **av;
5218
5219 for (av = shellparam.p; *av; av++)
5220 if (**av != '\0')
5221 return 1;
5222 return 0;
5223 }
5224 } else if (is_digit(*name)) {
5225 char *ap;
5226 int num = atoi(name);
5227
5228 if (num > shellparam.nparam)
5229 return 0;
5230
5231 if (num == 0)
5232 ap = arg0;
5233 else
5234 ap = shellparam.p[num - 1];
5235
5236 if (nulok && (ap == NULL || *ap == '\0'))
5237 return 0;
5238 }
5239 return 1;
5240}
5241
Eric Andersencb57d552001-06-28 07:25:16 +00005242/*
5243 * Put a string on the stack.
5244 */
5245
5246static void
5247strtodest(p, syntax, quotes)
5248 const char *p;
5249 const char *syntax;
5250 int quotes;
5251{
5252 while (*p) {
5253 if (quotes && syntax[(int) *p] == CCTL)
5254 STPUTC(CTLESC, expdest);
5255 STPUTC(*p++, expdest);
5256 }
5257}
5258
Eric Andersencb57d552001-06-28 07:25:16 +00005259/*
5260 * Add the value of a specialized variable to the stack string.
5261 */
5262
5263static void
5264varvalue(name, quoted, flags)
5265 char *name;
5266 int quoted;
5267 int flags;
5268{
5269 int num;
5270 char *p;
5271 int i;
5272 int sep;
5273 int sepq = 0;
5274 char **ap;
5275 char const *syntax;
5276 int allow_split = flags & EXP_FULL;
5277 int quotes = flags & (EXP_FULL | EXP_CASE);
5278
5279 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5280 switch (*name) {
5281 case '$':
5282 num = rootpid;
5283 goto numvar;
5284 case '?':
5285 num = oexitstatus;
5286 goto numvar;
5287 case '#':
5288 num = shellparam.nparam;
5289 goto numvar;
5290 case '!':
5291 num = backgndpid;
5292numvar:
5293 expdest = cvtnum(num, expdest);
5294 break;
5295 case '-':
5296 for (i = 0 ; i < NOPTS ; i++) {
Eric Andersen2870d962001-07-02 17:27:21 +00005297 if (optent_val(i))
5298 STPUTC(optent_letter(optlist[i]), expdest);
Eric Andersencb57d552001-06-28 07:25:16 +00005299 }
5300 break;
5301 case '@':
5302 if (allow_split && quoted) {
5303 sep = 1 << CHAR_BIT;
5304 goto param;
5305 }
5306 /* fall through */
5307 case '*':
5308 sep = ifsset() ? ifsval()[0] : ' ';
5309 if (quotes) {
5310 sepq = syntax[(int) sep] == CCTL;
5311 }
5312param:
5313 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
5314 strtodest(p, syntax, quotes);
5315 if (*ap && sep) {
5316 if (sepq)
5317 STPUTC(CTLESC, expdest);
5318 STPUTC(sep, expdest);
5319 }
5320 }
5321 break;
5322 case '0':
5323 strtodest(arg0, syntax, quotes);
5324 break;
5325 default:
5326 num = atoi(name);
5327 if (num > 0 && num <= shellparam.nparam) {
5328 strtodest(shellparam.p[num - 1], syntax, quotes);
5329 }
5330 break;
5331 }
5332}
5333
5334
Eric Andersencb57d552001-06-28 07:25:16 +00005335/*
5336 * Record the fact that we have to scan this region of the
5337 * string for IFS characters.
5338 */
5339
5340static void
5341recordregion(start, end, nulonly)
5342 int start;
5343 int end;
5344 int nulonly;
5345{
5346 struct ifsregion *ifsp;
5347
5348 if (ifslastp == NULL) {
5349 ifsp = &ifsfirst;
5350 } else {
5351 INTOFF;
5352 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
5353 ifsp->next = NULL;
5354 ifslastp->next = ifsp;
5355 INTON;
5356 }
5357 ifslastp = ifsp;
5358 ifslastp->begoff = start;
5359 ifslastp->endoff = end;
5360 ifslastp->nulonly = nulonly;
5361}
5362
5363
5364
5365/*
5366 * Break the argument string into pieces based upon IFS and add the
5367 * strings to the argument list. The regions of the string to be
5368 * searched for IFS characters have been stored by recordregion.
5369 */
5370static void
5371ifsbreakup(string, arglist)
5372 char *string;
5373 struct arglist *arglist;
5374 {
5375 struct ifsregion *ifsp;
5376 struct strlist *sp;
5377 char *start;
5378 char *p;
5379 char *q;
5380 const char *ifs, *realifs;
5381 int ifsspc;
5382 int nulonly;
5383
5384
5385 start = string;
5386 ifsspc = 0;
5387 nulonly = 0;
5388 realifs = ifsset() ? ifsval() : defifs;
5389 if (ifslastp != NULL) {
5390 ifsp = &ifsfirst;
5391 do {
5392 p = string + ifsp->begoff;
5393 nulonly = ifsp->nulonly;
5394 ifs = nulonly ? nullstr : realifs;
5395 ifsspc = 0;
5396 while (p < string + ifsp->endoff) {
5397 q = p;
5398 if (*p == CTLESC)
5399 p++;
5400 if (strchr(ifs, *p)) {
5401 if (!nulonly)
5402 ifsspc = (strchr(defifs, *p) != NULL);
5403 /* Ignore IFS whitespace at start */
5404 if (q == start && ifsspc) {
5405 p++;
5406 start = p;
5407 continue;
5408 }
5409 *q = '\0';
5410 sp = (struct strlist *)stalloc(sizeof *sp);
5411 sp->text = start;
5412 *arglist->lastp = sp;
5413 arglist->lastp = &sp->next;
5414 p++;
5415 if (!nulonly) {
5416 for (;;) {
5417 if (p >= string + ifsp->endoff) {
5418 break;
5419 }
5420 q = p;
5421 if (*p == CTLESC)
5422 p++;
5423 if (strchr(ifs, *p) == NULL ) {
5424 p = q;
5425 break;
5426 } else if (strchr(defifs, *p) == NULL) {
5427 if (ifsspc) {
5428 p++;
5429 ifsspc = 0;
5430 } else {
5431 p = q;
5432 break;
5433 }
5434 } else
5435 p++;
5436 }
5437 }
5438 start = p;
5439 } else
5440 p++;
5441 }
5442 } while ((ifsp = ifsp->next) != NULL);
5443 if (!(*start || (!ifsspc && start > string && nulonly))) {
5444 return;
5445 }
5446 }
5447
5448 sp = (struct strlist *)stalloc(sizeof *sp);
5449 sp->text = start;
5450 *arglist->lastp = sp;
5451 arglist->lastp = &sp->next;
5452}
5453
5454static void
5455ifsfree()
5456{
5457 while (ifsfirst.next != NULL) {
5458 struct ifsregion *ifsp;
5459 INTOFF;
5460 ifsp = ifsfirst.next->next;
5461 ckfree(ifsfirst.next);
5462 ifsfirst.next = ifsp;
5463 INTON;
5464 }
5465 ifslastp = NULL;
5466 ifsfirst.next = NULL;
5467}
5468
Eric Andersen2870d962001-07-02 17:27:21 +00005469/*
5470 * Add a file name to the list.
5471 */
Eric Andersencb57d552001-06-28 07:25:16 +00005472
Eric Andersen2870d962001-07-02 17:27:21 +00005473static void
5474addfname(const char *name)
5475{
5476 char *p;
5477 struct strlist *sp;
5478
5479 p = sstrdup(name);
5480 sp = (struct strlist *)stalloc(sizeof *sp);
5481 sp->text = p;
5482 *exparg.lastp = sp;
5483 exparg.lastp = &sp->next;
5484}
Eric Andersencb57d552001-06-28 07:25:16 +00005485
5486/*
5487 * Expand shell metacharacters. At this point, the only control characters
5488 * should be escapes. The results are stored in the list exparg.
5489 */
5490
5491#if defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)
5492static void
5493expandmeta(str, flag)
5494 struct strlist *str;
5495 int flag;
5496{
5497 const char *p;
5498 glob_t pglob;
5499 /* TODO - EXP_REDIR */
5500
5501 while (str) {
5502 if (fflag)
5503 goto nometa;
5504 p = preglob(str->text);
5505 INTOFF;
5506 switch (glob(p, GLOB_NOMAGIC, 0, &pglob)) {
5507 case 0:
5508 if (!(pglob.gl_flags & GLOB_MAGCHAR))
5509 goto nometa2;
5510 addglob(&pglob);
5511 globfree(&pglob);
5512 INTON;
5513 break;
5514 case GLOB_NOMATCH:
5515nometa2:
5516 globfree(&pglob);
5517 INTON;
5518nometa:
5519 *exparg.lastp = str;
5520 rmescapes(str->text);
5521 exparg.lastp = &str->next;
5522 break;
Eric Andersen2870d962001-07-02 17:27:21 +00005523 default: /* GLOB_NOSPACE */
Eric Andersencb57d552001-06-28 07:25:16 +00005524 error("Out of space");
5525 }
5526 str = str->next;
5527 }
5528}
5529
5530
5531/*
5532 * Add the result of glob(3) to the list.
5533 */
5534
5535static void
5536addglob(pglob)
5537 const glob_t *pglob;
5538{
5539 char **p = pglob->gl_pathv;
5540
5541 do {
5542 addfname(*p);
5543 } while (*++p);
5544}
5545
5546
Eric Andersen2870d962001-07-02 17:27:21 +00005547#else /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
Eric Andersencb57d552001-06-28 07:25:16 +00005548static char *expdir;
5549
5550
5551static void
5552expandmeta(str, flag)
5553 struct strlist *str;
5554 int flag;
5555{
5556 char *p;
5557 struct strlist **savelastp;
5558 struct strlist *sp;
5559 char c;
5560 /* TODO - EXP_REDIR */
5561
5562 while (str) {
5563 if (fflag)
5564 goto nometa;
5565 p = str->text;
Eric Andersen2870d962001-07-02 17:27:21 +00005566 for (;;) { /* fast check for meta chars */
Eric Andersencb57d552001-06-28 07:25:16 +00005567 if ((c = *p++) == '\0')
5568 goto nometa;
5569 if (c == '*' || c == '?' || c == '[' || c == '!')
5570 break;
5571 }
5572 savelastp = exparg.lastp;
5573 INTOFF;
5574 if (expdir == NULL) {
5575 int i = strlen(str->text);
5576 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5577 }
5578
5579 expmeta(expdir, str->text);
5580 ckfree(expdir);
5581 expdir = NULL;
5582 INTON;
5583 if (exparg.lastp == savelastp) {
5584 /*
5585 * no matches
5586 */
5587nometa:
5588 *exparg.lastp = str;
5589 rmescapes(str->text);
5590 exparg.lastp = &str->next;
5591 } else {
5592 *exparg.lastp = NULL;
5593 *savelastp = sp = expsort(*savelastp);
5594 while (sp->next != NULL)
5595 sp = sp->next;
5596 exparg.lastp = &sp->next;
5597 }
5598 str = str->next;
5599 }
5600}
5601
5602
5603/*
5604 * Do metacharacter (i.e. *, ?, [...]) expansion.
5605 */
5606
5607static void
5608expmeta(enddir, name)
5609 char *enddir;
5610 char *name;
5611 {
5612 char *p;
5613 const char *cp;
5614 char *q;
5615 char *start;
5616 char *endname;
5617 int metaflag;
5618 struct stat statb;
5619 DIR *dirp;
5620 struct dirent *dp;
5621 int atend;
5622 int matchdot;
5623
5624 metaflag = 0;
5625 start = name;
5626 for (p = name ; ; p++) {
5627 if (*p == '*' || *p == '?')
5628 metaflag = 1;
5629 else if (*p == '[') {
5630 q = p + 1;
5631 if (*q == '!')
5632 q++;
5633 for (;;) {
5634 while (*q == CTLQUOTEMARK)
5635 q++;
5636 if (*q == CTLESC)
5637 q++;
5638 if (*q == '/' || *q == '\0')
5639 break;
5640 if (*++q == ']') {
5641 metaflag = 1;
5642 break;
5643 }
5644 }
Eric Andersen2870d962001-07-02 17:27:21 +00005645 } else if (*p == '!' && p[1] == '!' && (p == name || p[-1] == '/')) {
Eric Andersencb57d552001-06-28 07:25:16 +00005646 metaflag = 1;
5647 } else if (*p == '\0')
5648 break;
5649 else if (*p == CTLQUOTEMARK)
5650 continue;
5651 else if (*p == CTLESC)
5652 p++;
5653 if (*p == '/') {
5654 if (metaflag)
5655 break;
5656 start = p + 1;
5657 }
5658 }
Eric Andersen2870d962001-07-02 17:27:21 +00005659 if (metaflag == 0) { /* we've reached the end of the file name */
Eric Andersencb57d552001-06-28 07:25:16 +00005660 if (enddir != expdir)
5661 metaflag++;
5662 for (p = name ; ; p++) {
5663 if (*p == CTLQUOTEMARK)
5664 continue;
5665 if (*p == CTLESC)
5666 p++;
5667 *enddir++ = *p;
5668 if (*p == '\0')
5669 break;
5670 }
5671 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
5672 addfname(expdir);
5673 return;
5674 }
5675 endname = p;
5676 if (start != name) {
5677 p = name;
5678 while (p < start) {
5679 while (*p == CTLQUOTEMARK)
5680 p++;
5681 if (*p == CTLESC)
5682 p++;
5683 *enddir++ = *p++;
5684 }
5685 }
5686 if (enddir == expdir) {
5687 cp = ".";
5688 } else if (enddir == expdir + 1 && *expdir == '/') {
5689 cp = "/";
5690 } else {
5691 cp = expdir;
5692 enddir[-1] = '\0';
5693 }
5694 if ((dirp = opendir(cp)) == NULL)
5695 return;
5696 if (enddir != expdir)
5697 enddir[-1] = '/';
5698 if (*endname == 0) {
5699 atend = 1;
5700 } else {
5701 atend = 0;
5702 *endname++ = '\0';
5703 }
5704 matchdot = 0;
5705 p = start;
5706 while (*p == CTLQUOTEMARK)
5707 p++;
5708 if (*p == CTLESC)
5709 p++;
5710 if (*p == '.')
5711 matchdot++;
5712 while (! int_pending() && (dp = readdir(dirp)) != NULL) {
5713 if (dp->d_name[0] == '.' && ! matchdot)
5714 continue;
5715 if (patmatch(start, dp->d_name, 0)) {
5716 if (atend) {
Eric Andersen2870d962001-07-02 17:27:21 +00005717 strcpy(enddir, dp->d_name);
Eric Andersencb57d552001-06-28 07:25:16 +00005718 addfname(expdir);
5719 } else {
5720 for (p = enddir, cp = dp->d_name;
5721 (*p++ = *cp++) != '\0';)
5722 continue;
5723 p[-1] = '/';
5724 expmeta(p, endname);
5725 }
5726 }
5727 }
5728 closedir(dirp);
5729 if (! atend)
5730 endname[-1] = '/';
5731}
Eric Andersen2870d962001-07-02 17:27:21 +00005732#endif /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
Eric Andersencb57d552001-06-28 07:25:16 +00005733
5734
Eric Andersencb57d552001-06-28 07:25:16 +00005735
5736#if !(defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
5737/*
5738 * Sort the results of file name expansion. It calculates the number of
5739 * strings to sort and then calls msort (short for merge sort) to do the
5740 * work.
5741 */
5742
5743static struct strlist *
5744expsort(str)
5745 struct strlist *str;
5746 {
5747 int len;
5748 struct strlist *sp;
5749
5750 len = 0;
5751 for (sp = str ; sp ; sp = sp->next)
5752 len++;
5753 return msort(str, len);
5754}
5755
5756
5757static struct strlist *
5758msort(list, len)
5759 struct strlist *list;
5760 int len;
5761{
5762 struct strlist *p, *q = NULL;
5763 struct strlist **lpp;
5764 int half;
5765 int n;
5766
5767 if (len <= 1)
5768 return list;
5769 half = len >> 1;
5770 p = list;
5771 for (n = half ; --n >= 0 ; ) {
5772 q = p;
5773 p = p->next;
5774 }
Eric Andersen2870d962001-07-02 17:27:21 +00005775 q->next = NULL; /* terminate first half of list */
5776 q = msort(list, half); /* sort first half of list */
5777 p = msort(p, len - half); /* sort second half */
Eric Andersencb57d552001-06-28 07:25:16 +00005778 lpp = &list;
5779 for (;;) {
5780 if (strcmp(p->text, q->text) < 0) {
5781 *lpp = p;
5782 lpp = &p->next;
5783 if ((p = *lpp) == NULL) {
5784 *lpp = q;
5785 break;
5786 }
5787 } else {
5788 *lpp = q;
5789 lpp = &q->next;
5790 if ((q = *lpp) == NULL) {
5791 *lpp = p;
5792 break;
5793 }
5794 }
5795 }
5796 return list;
5797}
5798#endif
5799
5800
5801
5802/*
5803 * Returns true if the pattern matches the string.
5804 */
5805
5806#if defined(__GLIBC__) && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00005807/* squoted: string might have quote chars */
Eric Andersencb57d552001-06-28 07:25:16 +00005808static int
Eric Andersen2870d962001-07-02 17:27:21 +00005809patmatch(char *pattern, char *string, int squoted)
5810{
Eric Andersencb57d552001-06-28 07:25:16 +00005811 const char *p;
5812 char *q;
5813
5814 p = preglob(pattern);
5815 q = squoted ? _rmescapes(string, RMESCAPE_ALLOC) : string;
5816
5817 return !fnmatch(p, q, 0);
5818}
5819
5820
5821static int
Eric Andersen2870d962001-07-02 17:27:21 +00005822patmatch2(char *pattern, char *string, int squoted)
5823{
Eric Andersencb57d552001-06-28 07:25:16 +00005824 char *p;
5825 int res;
5826
5827 sstrnleft--;
5828 p = grabstackstr(expdest);
5829 res = patmatch(pattern, string, squoted);
5830 ungrabstackstr(p, expdest);
5831 return res;
5832}
5833#else
5834static int
Eric Andersen2870d962001-07-02 17:27:21 +00005835patmatch(char *pattern, char *string, int squoted) {
5836 return pmatch(pattern, string, squoted);
Eric Andersencb57d552001-06-28 07:25:16 +00005837}
5838
5839
5840static int
Eric Andersen2870d962001-07-02 17:27:21 +00005841pmatch(char *pattern, char *string, int squoted)
5842{
Eric Andersencb57d552001-06-28 07:25:16 +00005843 char *p, *q;
5844 char c;
5845
5846 p = pattern;
5847 q = string;
5848 for (;;) {
5849 switch (c = *p++) {
5850 case '\0':
5851 goto breakloop;
5852 case CTLESC:
5853 if (squoted && *q == CTLESC)
5854 q++;
5855 if (*q++ != *p++)
5856 return 0;
5857 break;
5858 case CTLQUOTEMARK:
5859 continue;
5860 case '?':
5861 if (squoted && *q == CTLESC)
5862 q++;
5863 if (*q++ == '\0')
5864 return 0;
5865 break;
5866 case '*':
5867 c = *p;
5868 while (c == CTLQUOTEMARK || c == '*')
5869 c = *++p;
5870 if (c != CTLESC && c != CTLQUOTEMARK &&
5871 c != '?' && c != '*' && c != '[') {
5872 while (*q != c) {
5873 if (squoted && *q == CTLESC &&
5874 q[1] == c)
5875 break;
5876 if (*q == '\0')
5877 return 0;
5878 if (squoted && *q == CTLESC)
5879 q++;
5880 q++;
5881 }
5882 }
5883 do {
5884 if (pmatch(p, q, squoted))
5885 return 1;
5886 if (squoted && *q == CTLESC)
5887 q++;
5888 } while (*q++ != '\0');
5889 return 0;
5890 case '[': {
5891 char *endp;
5892 int invert, found;
5893 char chr;
5894
5895 endp = p;
5896 if (*endp == '!')
5897 endp++;
5898 for (;;) {
5899 while (*endp == CTLQUOTEMARK)
5900 endp++;
5901 if (*endp == '\0')
Eric Andersen2870d962001-07-02 17:27:21 +00005902 goto dft; /* no matching ] */
Eric Andersencb57d552001-06-28 07:25:16 +00005903 if (*endp == CTLESC)
5904 endp++;
5905 if (*++endp == ']')
5906 break;
5907 }
5908 invert = 0;
5909 if (*p == '!') {
5910 invert++;
5911 p++;
5912 }
5913 found = 0;
5914 chr = *q++;
5915 if (squoted && chr == CTLESC)
5916 chr = *q++;
5917 if (chr == '\0')
5918 return 0;
5919 c = *p++;
5920 do {
5921 if (c == CTLQUOTEMARK)
5922 continue;
5923 if (c == CTLESC)
5924 c = *p++;
5925 if (*p == '-' && p[1] != ']') {
5926 p++;
5927 while (*p == CTLQUOTEMARK)
5928 p++;
5929 if (*p == CTLESC)
5930 p++;
5931 if (chr >= c && chr <= *p)
5932 found = 1;
5933 p++;
5934 } else {
5935 if (chr == c)
5936 found = 1;
5937 }
5938 } while ((c = *p++) != ']');
5939 if (found == invert)
5940 return 0;
5941 break;
5942 }
Eric Andersen2870d962001-07-02 17:27:21 +00005943dft: default:
Eric Andersencb57d552001-06-28 07:25:16 +00005944 if (squoted && *q == CTLESC)
5945 q++;
5946 if (*q++ != c)
5947 return 0;
5948 break;
5949 }
5950 }
5951breakloop:
5952 if (*q != '\0')
5953 return 0;
5954 return 1;
5955}
5956#endif
5957
5958
5959
5960/*
5961 * Remove any CTLESC characters from a string.
5962 */
5963
5964#if defined(__GLIBC__) && !defined(FNMATCH_BROKEN)
5965static char *
Eric Andersen2870d962001-07-02 17:27:21 +00005966_rmescapes(char *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00005967{
5968 char *p, *q, *r;
5969 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
5970
5971 p = strpbrk(str, qchars);
5972 if (!p) {
5973 return str;
5974 }
5975 q = p;
5976 r = str;
5977 if (flag & RMESCAPE_ALLOC) {
5978 size_t len = p - str;
5979 q = r = stalloc(strlen(p) + len + 1);
5980 if (len > 0) {
5981#ifdef _GNU_SOURCE
5982 q = mempcpy(q, str, len);
5983#else
5984 memcpy(q, str, len);
5985 q += len;
5986#endif
5987 }
5988 }
5989 while (*p) {
5990 if (*p == CTLQUOTEMARK) {
5991 p++;
5992 continue;
5993 }
5994 if (*p == CTLESC) {
5995 p++;
5996 if (flag & RMESCAPE_GLOB && *p != '/') {
5997 *q++ = '\\';
5998 }
5999 }
6000 *q++ = *p++;
6001 }
6002 *q = '\0';
6003 return r;
6004}
6005#else
6006static void
6007rmescapes(str)
6008 char *str;
6009{
6010 char *p, *q;
6011
6012 p = str;
6013 while (*p != CTLESC && *p != CTLQUOTEMARK) {
6014 if (*p++ == '\0')
6015 return;
6016 }
6017 q = p;
6018 while (*p) {
6019 if (*p == CTLQUOTEMARK) {
6020 p++;
6021 continue;
6022 }
6023 if (*p == CTLESC)
6024 p++;
6025 *q++ = *p++;
6026 }
6027 *q = '\0';
6028}
6029#endif
6030
6031
6032
6033/*
6034 * See if a pattern matches in a case statement.
6035 */
6036
6037static int
Eric Andersen2870d962001-07-02 17:27:21 +00006038casematch(union node *pattern, const char *val)
6039{
Eric Andersencb57d552001-06-28 07:25:16 +00006040 struct stackmark smark;
6041 int result;
6042 char *p;
6043
6044 setstackmark(&smark);
6045 argbackq = pattern->narg.backquote;
6046 STARTSTACKSTR(expdest);
6047 ifslastp = NULL;
6048 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
6049 STPUTC('\0', expdest);
6050 p = grabstackstr(expdest);
Eric Andersen2870d962001-07-02 17:27:21 +00006051 result = patmatch(p, (char *)val, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006052 popstackmark(&smark);
6053 return result;
6054}
6055
6056/*
6057 * Our own itoa().
6058 */
6059
6060static char *
6061cvtnum(num, buf)
6062 int num;
6063 char *buf;
6064 {
6065 int len;
6066
6067 CHECKSTRSPACE(32, buf);
6068 len = sprintf(buf, "%d", num);
6069 STADJUST(len, buf);
6070 return buf;
6071}
Eric Andersencb57d552001-06-28 07:25:16 +00006072/*
6073 * Editline and history functions (and glue).
6074 */
6075static int histcmd(argc, argv)
6076 int argc;
6077 char **argv;
6078{
6079 error("not compiled with history support");
6080 /* NOTREACHED */
6081}
6082
6083
Eric Andersen2870d962001-07-02 17:27:21 +00006084static int whichprompt; /* 1 == PS1, 2 == PS2 */
Eric Andersencb57d552001-06-28 07:25:16 +00006085
Eric Andersencb57d552001-06-28 07:25:16 +00006086
6087struct redirtab {
6088 struct redirtab *next;
6089 short renamed[10];
6090};
6091
Eric Andersen2870d962001-07-02 17:27:21 +00006092static struct redirtab *redirlist;
Eric Andersencb57d552001-06-28 07:25:16 +00006093
6094extern char **environ;
6095
6096
6097
6098/*
6099 * Initialization code.
6100 */
6101
6102static void
Eric Andersen2870d962001-07-02 17:27:21 +00006103init(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00006104
6105 /* from cd.c: */
6106 {
6107 setpwd(0, 0);
6108 }
6109
6110 /* from input.c: */
6111 {
6112 basepf.nextc = basepf.buf = basebuf;
6113 }
6114
Eric Andersencb57d552001-06-28 07:25:16 +00006115 /* from var.c: */
6116 {
6117 char **envp;
6118 char ppid[32];
6119
6120 initvar();
6121 for (envp = environ ; *envp ; envp++) {
6122 if (strchr(*envp, '=')) {
6123 setvareq(*envp, VEXPORT|VTEXTFIXED);
6124 }
6125 }
6126
Eric Andersen3102ac42001-07-06 04:26:23 +00006127 snprintf(ppid, sizeof(ppid), "%d", (int) getppid());
Eric Andersencb57d552001-06-28 07:25:16 +00006128 setvar("PPID", ppid, 0);
6129 }
6130}
6131
6132
6133
6134/*
6135 * This routine is called when an error or an interrupt occurs in an
6136 * interactive shell and control is returned to the main command loop.
6137 */
6138
Eric Andersen2870d962001-07-02 17:27:21 +00006139#ifdef ASH_ALIAS
6140/* 1 == check for aliases, 2 == also check for assignments */
6141static int checkalias;
6142#endif
6143
Eric Andersencb57d552001-06-28 07:25:16 +00006144static void
Eric Andersen2870d962001-07-02 17:27:21 +00006145reset(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00006146
6147 /* from eval.c: */
6148 {
6149 evalskip = 0;
6150 loopnest = 0;
6151 funcnest = 0;
6152 }
6153
6154 /* from input.c: */
6155 {
6156 if (exception != EXSHELLPROC)
Eric Andersen2870d962001-07-02 17:27:21 +00006157 parselleft = parsenleft = 0; /* clear input buffer */
Eric Andersencb57d552001-06-28 07:25:16 +00006158 popallfiles();
6159 }
6160
6161 /* from parser.c: */
6162 {
6163 tokpushback = 0;
6164 checkkwd = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00006165#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00006166 checkalias = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00006167#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006168 }
6169
6170 /* from redir.c: */
6171 {
6172 while (redirlist)
6173 popredir();
6174 }
6175
Eric Andersencb57d552001-06-28 07:25:16 +00006176}
6177
6178
6179
6180/*
Eric Andersencb57d552001-06-28 07:25:16 +00006181 * This file implements the input routines used by the parser.
6182 */
6183
6184#ifdef BB_FEATURE_COMMAND_EDITING
6185unsigned int shell_context;
6186static const char * cmdedit_prompt;
6187static inline void putprompt(const char *s) {
6188 cmdedit_prompt = s;
6189}
6190#else
6191static inline void putprompt(const char *s) {
6192 out2str(s);
6193}
6194#endif
6195
Eric Andersen2870d962001-07-02 17:27:21 +00006196#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
Eric Andersencb57d552001-06-28 07:25:16 +00006197
Eric Andersencb57d552001-06-28 07:25:16 +00006198
Eric Andersencb57d552001-06-28 07:25:16 +00006199
Eric Andersen2870d962001-07-02 17:27:21 +00006200/*
6201 * Same as pgetc(), but ignores PEOA.
6202 */
Eric Andersencb57d552001-06-28 07:25:16 +00006203
Eric Andersen2870d962001-07-02 17:27:21 +00006204#ifdef ASH_ALIAS
6205static int
6206pgetc2()
6207{
6208 int c;
6209 do {
6210 c = pgetc_macro();
6211 } while (c == PEOA);
6212 return c;
Eric Andersencb57d552001-06-28 07:25:16 +00006213}
Eric Andersen2870d962001-07-02 17:27:21 +00006214#else
6215static inline int pgetc2() { return pgetc_macro(); }
Eric Andersencb57d552001-06-28 07:25:16 +00006216#endif
6217
Eric Andersencb57d552001-06-28 07:25:16 +00006218/*
6219 * Read a line from the script.
6220 */
6221
6222static char *
Eric Andersen2870d962001-07-02 17:27:21 +00006223pfgets(char *line, int len)
Eric Andersencb57d552001-06-28 07:25:16 +00006224{
6225 char *p = line;
6226 int nleft = len;
6227 int c;
6228
6229 while (--nleft > 0) {
6230 c = pgetc2();
6231 if (c == PEOF) {
6232 if (p == line)
6233 return NULL;
6234 break;
6235 }
6236 *p++ = c;
6237 if (c == '\n')
6238 break;
6239 }
6240 *p = '\0';
6241 return line;
6242}
6243
Eric Andersencb57d552001-06-28 07:25:16 +00006244static int
Eric Andersen2870d962001-07-02 17:27:21 +00006245preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006246{
6247 int nr;
6248 char *buf = parsefile->buf;
6249 parsenextc = buf;
6250
6251retry:
6252#ifdef BB_FEATURE_COMMAND_EDITING
6253 {
6254 if (parsefile->fd)
6255 nr = read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersen2870d962001-07-02 17:27:21 +00006256 else {
Eric Andersencb57d552001-06-28 07:25:16 +00006257 do {
6258 cmdedit_read_input((char*)cmdedit_prompt, buf);
6259 nr = strlen(buf);
6260 } while (nr <=0 || shell_context);
6261 cmdedit_terminate();
6262 }
6263 }
6264#else
6265 nr = read(parsefile->fd, buf, BUFSIZ - 1);
6266#endif
6267
6268 if (nr < 0) {
6269 if (errno == EINTR)
6270 goto retry;
6271 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6272 int flags = fcntl(0, F_GETFL, 0);
6273 if (flags >= 0 && flags & O_NONBLOCK) {
6274 flags &=~ O_NONBLOCK;
6275 if (fcntl(0, F_SETFL, flags) >= 0) {
6276 out2str("sh: turning off NDELAY mode\n");
6277 goto retry;
6278 }
6279 }
6280 }
6281 }
6282 return nr;
6283}
6284
Eric Andersen2870d962001-07-02 17:27:21 +00006285static void
6286popstring(void)
6287{
6288 struct strpush *sp = parsefile->strpush;
6289
6290 INTOFF;
6291#ifdef ASH_ALIAS
6292 if (sp->ap) {
6293 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6294 if (!checkalias) {
6295 checkalias = 1;
6296 }
6297 }
6298 if (sp->string != sp->ap->val) {
6299 ckfree(sp->string);
6300 }
6301
6302 sp->ap->flag &= ~ALIASINUSE;
6303 if (sp->ap->flag & ALIASDEAD) {
6304 unalias(sp->ap->name);
6305 }
6306 }
6307#endif
6308 parsenextc = sp->prevstring;
6309 parsenleft = sp->prevnleft;
6310/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6311 parsefile->strpush = sp->prev;
6312 if (sp != &(parsefile->basestrpush))
6313 ckfree(sp);
6314 INTON;
6315}
6316
6317
Eric Andersencb57d552001-06-28 07:25:16 +00006318/*
6319 * Refill the input buffer and return the next input character:
6320 *
6321 * 1) If a string was pushed back on the input, pop it;
6322 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6323 * from a string so we can't refill the buffer, return EOF.
6324 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6325 * 4) Process input up to the next newline, deleting nul characters.
6326 */
6327
6328static int
Eric Andersen2870d962001-07-02 17:27:21 +00006329preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006330{
6331 char *p, *q;
6332 int more;
6333 char savec;
6334
6335 while (parsefile->strpush) {
Eric Andersen2870d962001-07-02 17:27:21 +00006336#ifdef ASH_ALIAS
6337 if (parsenleft == -1 && parsefile->strpush->ap &&
6338 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +00006339 return PEOA;
6340 }
Eric Andersen2870d962001-07-02 17:27:21 +00006341#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006342 popstring();
6343 if (--parsenleft >= 0)
6344 return (*parsenextc++);
6345 }
6346 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6347 return PEOF;
Eric Andersen3102ac42001-07-06 04:26:23 +00006348 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00006349
6350again:
6351 if (parselleft <= 0) {
6352 if ((parselleft = preadfd()) <= 0) {
6353 parselleft = parsenleft = EOF_NLEFT;
6354 return PEOF;
6355 }
6356 }
6357
6358 q = p = parsenextc;
6359
6360 /* delete nul characters */
6361 for (more = 1; more;) {
6362 switch (*p) {
6363 case '\0':
Eric Andersen2870d962001-07-02 17:27:21 +00006364 p++; /* Skip nul */
Eric Andersencb57d552001-06-28 07:25:16 +00006365 goto check;
6366
6367
6368 case '\n':
6369 parsenleft = q - parsenextc;
6370 more = 0; /* Stop processing here */
6371 break;
6372 }
6373
6374 *q++ = *p++;
6375check:
6376 if (--parselleft <= 0 && more) {
6377 parsenleft = q - parsenextc - 1;
6378 if (parsenleft < 0)
6379 goto again;
6380 more = 0;
6381 }
6382 }
6383
6384 savec = *q;
6385 *q = '\0';
6386
6387 if (vflag) {
6388 out2str(parsenextc);
Eric Andersencb57d552001-06-28 07:25:16 +00006389 }
6390
6391 *q = savec;
6392
6393 return *parsenextc++;
6394}
6395
Eric Andersencb57d552001-06-28 07:25:16 +00006396
6397/*
6398 * Push a string back onto the input at this current parsefile level.
6399 * We handle aliases this way.
6400 */
6401static void
Eric Andersen2870d962001-07-02 17:27:21 +00006402pushstring(char *s, int len, void *ap)
6403{
Eric Andersencb57d552001-06-28 07:25:16 +00006404 struct strpush *sp;
6405
6406 INTOFF;
6407/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6408 if (parsefile->strpush) {
6409 sp = ckmalloc(sizeof (struct strpush));
6410 sp->prev = parsefile->strpush;
6411 parsefile->strpush = sp;
6412 } else
6413 sp = parsefile->strpush = &(parsefile->basestrpush);
6414 sp->prevstring = parsenextc;
6415 sp->prevnleft = parsenleft;
Eric Andersen2870d962001-07-02 17:27:21 +00006416#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00006417 sp->ap = (struct alias *)ap;
6418 if (ap) {
6419 ((struct alias *)ap)->flag |= ALIASINUSE;
6420 sp->string = s;
6421 }
Eric Andersen2870d962001-07-02 17:27:21 +00006422#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006423 parsenextc = s;
6424 parsenleft = len;
6425 INTON;
6426}
6427
Eric Andersencb57d552001-06-28 07:25:16 +00006428
Eric Andersencb57d552001-06-28 07:25:16 +00006429
6430
6431/*
6432 * Like setinputfile, but takes input from a string.
6433 */
6434
6435static void
6436setinputstring(string)
6437 char *string;
6438 {
6439 INTOFF;
6440 pushfile();
6441 parsenextc = string;
6442 parsenleft = strlen(string);
6443 parsefile->buf = NULL;
6444 plinno = 1;
6445 INTON;
6446}
6447
6448
6449
6450/*
6451 * To handle the "." command, a stack of input files is used. Pushfile
6452 * adds a new entry to the stack and popfile restores the previous level.
6453 */
6454
6455static void
Eric Andersen2870d962001-07-02 17:27:21 +00006456pushfile(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00006457 struct parsefile *pf;
6458
6459 parsefile->nleft = parsenleft;
6460 parsefile->lleft = parselleft;
6461 parsefile->nextc = parsenextc;
6462 parsefile->linno = plinno;
6463 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
6464 pf->prev = parsefile;
6465 pf->fd = -1;
6466 pf->strpush = NULL;
6467 pf->basestrpush.prev = NULL;
6468 parsefile = pf;
6469}
6470
Eric Andersen2870d962001-07-02 17:27:21 +00006471#ifdef JOBS
6472static void restartjob (struct job *);
Eric Andersencb57d552001-06-28 07:25:16 +00006473#endif
Eric Andersen2870d962001-07-02 17:27:21 +00006474static void freejob (struct job *);
6475static struct job *getjob (const char *);
6476static int dowait (int, struct job *);
6477static int waitproc (int, int *);
Eric Andersencb57d552001-06-28 07:25:16 +00006478static void waitonint(int);
6479
6480
Eric Andersen2870d962001-07-02 17:27:21 +00006481/*
6482 * We keep track of whether or not fd0 has been redirected. This is for
6483 * background commands, where we want to redirect fd0 to /dev/null only
6484 * if it hasn't already been redirected.
6485*/
6486static int fd0_redirected = 0;
6487
6488/* Return true if fd 0 has already been redirected at least once. */
6489static inline int
6490fd0_redirected_p () {
6491 return fd0_redirected != 0;
6492}
6493
Eric Andersen2870d962001-07-02 17:27:21 +00006494static int openredirect (union node *);
6495static void dupredirect (union node *, int, char[10 ]);
6496static int openhere (union node *);
6497static int noclobberopen (const char *);
6498
6499
6500
6501#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006502/*
6503 * Turn job control on and off.
6504 *
6505 * Note: This code assumes that the third arg to ioctl is a character
6506 * pointer, which is true on Berkeley systems but not System V. Since
6507 * System V doesn't have job control yet, this isn't a problem now.
6508 */
6509
Eric Andersen2870d962001-07-02 17:27:21 +00006510
Eric Andersencb57d552001-06-28 07:25:16 +00006511
6512static void setjobctl(int enable)
6513{
6514#ifdef OLD_TTY_DRIVER
6515 int ldisc;
6516#endif
6517
6518 if (enable == jobctl || rootshell == 0)
6519 return;
6520 if (enable) {
6521 do { /* while we are in the background */
6522#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006523 if (ioctl(2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00006524#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006525 initialpgrp = tcgetpgrp(2);
Eric Andersencb57d552001-06-28 07:25:16 +00006526 if (initialpgrp < 0) {
6527#endif
6528 out2str("sh: can't access tty; job cenabletrol turned off\n");
6529 mflag = 0;
6530 return;
6531 }
6532 if (initialpgrp == -1)
6533 initialpgrp = getpgrp();
6534 else if (initialpgrp != getpgrp()) {
6535 killpg(initialpgrp, SIGTTIN);
6536 continue;
6537 }
6538 } while (0);
6539#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006540 if (ioctl(2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
Eric Andersencb57d552001-06-28 07:25:16 +00006541 out2str("sh: need new tty driver to run job cenabletrol; job cenabletrol turned off\n");
6542 mflag = 0;
6543 return;
6544 }
6545#endif
6546 setsignal(SIGTSTP);
6547 setsignal(SIGTTOU);
6548 setsignal(SIGTTIN);
6549 setpgid(0, rootpid);
6550#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006551 ioctl(2, TIOCSPGRP, (char *)&rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00006552#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006553 tcsetpgrp(2, rootpid);
Eric Andersencb57d552001-06-28 07:25:16 +00006554#endif
6555 } else { /* turning job cenabletrol off */
6556 setpgid(0, initialpgrp);
6557#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006558 ioctl(2, TIOCSPGRP, (char *)&initialpgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006559#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006560 tcsetpgrp(2, initialpgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006561#endif
6562 setsignal(SIGTSTP);
6563 setsignal(SIGTTOU);
6564 setsignal(SIGTTIN);
6565 }
6566 jobctl = enable;
6567}
6568#endif
6569
6570
Eric Andersencb57d552001-06-28 07:25:16 +00006571/* A translation list so we can be polite to our users. */
6572static char *signal_names[NSIG + 2] = {
6573 "EXIT",
6574 "SIGHUP",
6575 "SIGINT",
6576 "SIGQUIT",
6577 "SIGILL",
6578 "SIGTRAP",
6579 "SIGABRT",
6580 "SIGBUS",
6581 "SIGFPE",
6582 "SIGKILL",
6583 "SIGUSR1",
6584 "SIGSEGV",
6585 "SIGUSR2",
6586 "SIGPIPE",
6587 "SIGALRM",
6588 "SIGTERM",
6589 "SIGJUNK(16)",
6590 "SIGCHLD",
6591 "SIGCONT",
6592 "SIGSTOP",
6593 "SIGTSTP",
6594 "SIGTTIN",
6595 "SIGTTOU",
6596 "SIGURG",
6597 "SIGXCPU",
6598 "SIGXFSZ",
6599 "SIGVTALRM",
6600 "SIGPROF",
6601 "SIGWINCH",
6602 "SIGIO",
6603 "SIGPWR",
6604 "SIGSYS",
6605 "SIGRTMIN",
6606 "SIGRTMIN+1",
6607 "SIGRTMIN+2",
6608 "SIGRTMIN+3",
6609 "SIGRTMIN+4",
6610 "SIGRTMIN+5",
6611 "SIGRTMIN+6",
6612 "SIGRTMIN+7",
6613 "SIGRTMIN+8",
6614 "SIGRTMIN+9",
6615 "SIGRTMIN+10",
6616 "SIGRTMIN+11",
6617 "SIGRTMIN+12",
6618 "SIGRTMIN+13",
6619 "SIGRTMIN+14",
6620 "SIGRTMIN+15",
6621 "SIGRTMAX-15",
6622 "SIGRTMAX-14",
6623 "SIGRTMAX-13",
6624 "SIGRTMAX-12",
6625 "SIGRTMAX-11",
6626 "SIGRTMAX-10",
6627 "SIGRTMAX-9",
6628 "SIGRTMAX-8",
6629 "SIGRTMAX-7",
6630 "SIGRTMAX-6",
6631 "SIGRTMAX-5",
6632 "SIGRTMAX-4",
6633 "SIGRTMAX-3",
6634 "SIGRTMAX-2",
6635 "SIGRTMAX-1",
6636 "SIGRTMAX",
6637 "DEBUG",
6638 (char *)0x0,
6639};
6640
6641
6642
Eric Andersen2870d962001-07-02 17:27:21 +00006643#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006644static int
6645killcmd(argc, argv)
6646 int argc;
6647 char **argv;
6648{
6649 int signo = -1;
6650 int list = 0;
6651 int i;
6652 pid_t pid;
6653 struct job *jp;
6654
6655 if (argc <= 1) {
6656usage:
6657 error(
6658"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6659"kill -l [exitstatus]"
6660 );
6661 }
6662
6663 if (*argv[1] == '-') {
6664 signo = decode_signal(argv[1] + 1, 1);
6665 if (signo < 0) {
6666 int c;
6667
6668 while ((c = nextopt("ls:")) != '\0')
6669 switch (c) {
6670 case 'l':
6671 list = 1;
6672 break;
6673 case 's':
6674 signo = decode_signal(optionarg, 1);
6675 if (signo < 0) {
6676 error(
6677 "invalid signal number or name: %s",
6678 optionarg
6679 );
6680 }
Eric Andersen2870d962001-07-02 17:27:21 +00006681 break;
Eric Andersencb57d552001-06-28 07:25:16 +00006682#ifdef DEBUG
6683 default:
6684 error(
6685 "nextopt returned character code 0%o", c);
6686#endif
6687 }
6688 } else
6689 argptr++;
6690 }
6691
6692 if (!list && signo < 0)
6693 signo = SIGTERM;
6694
6695 if ((signo < 0 || !*argptr) ^ list) {
6696 goto usage;
6697 }
6698
6699 if (list) {
6700 if (!*argptr) {
6701 out1str("0\n");
6702 for (i = 1; i < NSIG; i++) {
6703 out1fmt(snlfmt, signal_names[i] + 3);
6704 }
6705 return 0;
6706 }
6707 signo = atoi(*argptr);
6708 if (signo > 128)
6709 signo -= 128;
6710 if (0 < signo && signo < NSIG)
6711 out1fmt(snlfmt, signal_names[signo] + 3);
6712 else
6713 error("invalid signal number or exit status: %s",
6714 *argptr);
6715 return 0;
6716 }
6717
6718 do {
6719 if (**argptr == '%') {
6720 jp = getjob(*argptr);
6721 if (jp->jobctl == 0)
6722 error("job %s not created under job control",
6723 *argptr);
6724 pid = -jp->ps[0].pid;
6725 } else
6726 pid = atoi(*argptr);
6727 if (kill(pid, signo) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00006728 error("%s: %m", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006729 } while (*++argptr);
6730
6731 return 0;
6732}
6733
6734static int
6735fgcmd(argc, argv)
6736 int argc;
6737 char **argv;
6738{
6739 struct job *jp;
6740 int pgrp;
6741 int status;
6742
6743 jp = getjob(argv[1]);
6744 if (jp->jobctl == 0)
6745 error("job not created under job control");
6746 pgrp = jp->ps[0].pid;
6747#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00006748 ioctl(2, TIOCSPGRP, (char *)&pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006749#else
Eric Andersen3102ac42001-07-06 04:26:23 +00006750 tcsetpgrp(2, pgrp);
Eric Andersencb57d552001-06-28 07:25:16 +00006751#endif
6752 restartjob(jp);
6753 INTOFF;
6754 status = waitforjob(jp);
6755 INTON;
6756 return status;
6757}
6758
6759
6760static int
6761bgcmd(argc, argv)
6762 int argc;
6763 char **argv;
6764{
6765 struct job *jp;
6766
6767 do {
6768 jp = getjob(*++argv);
6769 if (jp->jobctl == 0)
6770 error("job not created under job control");
6771 restartjob(jp);
6772 } while (--argc > 1);
6773 return 0;
6774}
6775
6776
6777static void
6778restartjob(jp)
6779 struct job *jp;
6780{
6781 struct procstat *ps;
6782 int i;
6783
6784 if (jp->state == JOBDONE)
6785 return;
6786 INTOFF;
6787 killpg(jp->ps[0].pid, SIGCONT);
6788 for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
6789 if (WIFSTOPPED(ps->status)) {
6790 ps->status = -1;
6791 jp->state = 0;
6792 }
6793 }
6794 INTON;
6795}
6796#endif
6797
Eric Andersen2870d962001-07-02 17:27:21 +00006798static void showjobs(int change);
6799
Eric Andersencb57d552001-06-28 07:25:16 +00006800
6801static int
6802jobscmd(argc, argv)
6803 int argc;
6804 char **argv;
6805{
6806 showjobs(0);
6807 return 0;
6808}
6809
6810
6811/*
6812 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6813 * statuses have changed since the last call to showjobs.
6814 *
6815 * If the shell is interrupted in the process of creating a job, the
6816 * result may be a job structure containing zero processes. Such structures
6817 * will be freed here.
6818 */
6819
6820static void
6821showjobs(change)
6822 int change;
6823{
6824 int jobno;
6825 int procno;
6826 int i;
6827 struct job *jp;
6828 struct procstat *ps;
6829 int col;
6830 char s[64];
6831
6832 TRACE(("showjobs(%d) called\n", change));
6833 while (dowait(0, (struct job *)NULL) > 0);
6834 for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
6835 if (! jp->used)
6836 continue;
6837 if (jp->nprocs == 0) {
6838 freejob(jp);
6839 continue;
6840 }
6841 if (change && ! jp->changed)
6842 continue;
6843 procno = jp->nprocs;
Eric Andersen2870d962001-07-02 17:27:21 +00006844 for (ps = jp->ps ; ; ps++) { /* for each process */
Eric Andersencb57d552001-06-28 07:25:16 +00006845 if (ps == jp->ps)
Eric Andersen3102ac42001-07-06 04:26:23 +00006846 snprintf(s, 64, "[%d] %ld ", jobno,
Eric Andersencb57d552001-06-28 07:25:16 +00006847 (long)ps->pid);
6848 else
Eric Andersen3102ac42001-07-06 04:26:23 +00006849 snprintf(s, 64, " %ld ",
Eric Andersencb57d552001-06-28 07:25:16 +00006850 (long)ps->pid);
6851 out1str(s);
6852 col = strlen(s);
6853 s[0] = '\0';
6854 if (ps->status == -1) {
6855 /* don't print anything */
6856 } else if (WIFEXITED(ps->status)) {
Eric Andersen3102ac42001-07-06 04:26:23 +00006857 snprintf(s, 64, "Exit %d",
Eric Andersencb57d552001-06-28 07:25:16 +00006858 WEXITSTATUS(ps->status));
6859 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00006860#ifdef JOBS
6861 if (WIFSTOPPED(ps->status))
Eric Andersencb57d552001-06-28 07:25:16 +00006862 i = WSTOPSIG(ps->status);
6863 else /* WIFSIGNALED(ps->status) */
6864#endif
6865 i = WTERMSIG(ps->status);
6866 if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F])
Eric Andersen2870d962001-07-02 17:27:21 +00006867 strcpy(s, sys_siglist[i & 0x7F]);
Eric Andersencb57d552001-06-28 07:25:16 +00006868 else
Eric Andersen3102ac42001-07-06 04:26:23 +00006869 snprintf(s, 64, "Signal %d", i & 0x7F);
Eric Andersencb57d552001-06-28 07:25:16 +00006870 if (WCOREDUMP(ps->status))
6871 strcat(s, " (core dumped)");
6872 }
6873 out1str(s);
6874 col += strlen(s);
6875 out1fmt(
6876 "%*c%s\n", 30 - col >= 0 ? 30 - col : 0, ' ',
6877 ps->cmd
6878 );
6879 if (--procno <= 0)
6880 break;
6881 }
6882 jp->changed = 0;
6883 if (jp->state == JOBDONE) {
6884 freejob(jp);
6885 }
6886 }
6887}
6888
6889
6890/*
6891 * Mark a job structure as unused.
6892 */
6893
6894static void
6895freejob(jp)
6896 struct job *jp;
6897 {
6898 struct procstat *ps;
6899 int i;
6900
6901 INTOFF;
6902 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
6903 if (ps->cmd != nullstr)
6904 ckfree(ps->cmd);
6905 }
6906 if (jp->ps != &jp->ps0)
6907 ckfree(jp->ps);
6908 jp->used = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00006909#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006910 if (curjob == jp - jobtab + 1)
6911 curjob = 0;
6912#endif
6913 INTON;
6914}
6915
6916
6917
6918static int
6919waitcmd(argc, argv)
6920 int argc;
6921 char **argv;
6922{
6923 struct job *job;
6924 int status, retval;
6925 struct job *jp;
6926
6927 if (--argc > 0) {
6928start:
6929 job = getjob(*++argv);
6930 } else {
6931 job = NULL;
6932 }
Eric Andersen2870d962001-07-02 17:27:21 +00006933 for (;;) { /* loop until process terminated or stopped */
Eric Andersencb57d552001-06-28 07:25:16 +00006934 if (job != NULL) {
6935 if (job->state) {
6936 status = job->ps[job->nprocs - 1].status;
6937 if (! iflag)
6938 freejob(job);
6939 if (--argc) {
6940 goto start;
6941 }
6942 if (WIFEXITED(status))
6943 retval = WEXITSTATUS(status);
Eric Andersen2870d962001-07-02 17:27:21 +00006944#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006945 else if (WIFSTOPPED(status))
6946 retval = WSTOPSIG(status) + 128;
6947#endif
6948 else {
6949 /* XXX: limits number of signals */
6950 retval = WTERMSIG(status) + 128;
6951 }
6952 return retval;
6953 }
6954 } else {
6955 for (jp = jobtab ; ; jp++) {
Eric Andersen2870d962001-07-02 17:27:21 +00006956 if (jp >= jobtab + njobs) { /* no running procs */
Eric Andersencb57d552001-06-28 07:25:16 +00006957 return 0;
6958 }
6959 if (jp->used && jp->state == 0)
6960 break;
6961 }
6962 }
6963 if (dowait(2, 0) < 0 && errno == EINTR) {
6964 return 129;
6965 }
6966 }
6967}
6968
6969
6970
6971/*
6972 * Convert a job name to a job structure.
6973 */
6974
6975static struct job *
Eric Andersen2870d962001-07-02 17:27:21 +00006976getjob(const char *name)
6977{
Eric Andersencb57d552001-06-28 07:25:16 +00006978 int jobno;
6979 struct job *jp;
6980 int pid;
6981 int i;
6982
6983 if (name == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00006984#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006985currentjob:
6986 if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0)
6987 error("No current job");
6988 return &jobtab[jobno - 1];
6989#else
6990 error("No current job");
6991#endif
6992 } else if (name[0] == '%') {
6993 if (is_digit(name[1])) {
6994 jobno = number(name + 1);
6995 if (jobno > 0 && jobno <= njobs
6996 && jobtab[jobno - 1].used != 0)
6997 return &jobtab[jobno - 1];
Eric Andersen2870d962001-07-02 17:27:21 +00006998#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006999 } else if (name[1] == '%' && name[2] == '\0') {
7000 goto currentjob;
7001#endif
7002 } else {
7003 struct job *found = NULL;
7004 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
7005 if (jp->used && jp->nprocs > 0
7006 && prefix(name + 1, jp->ps[0].cmd)) {
7007 if (found)
7008 error("%s: ambiguous", name);
7009 found = jp;
7010 }
7011 }
7012 if (found)
7013 return found;
7014 }
Eric Andersen2870d962001-07-02 17:27:21 +00007015 } else if (is_number(name, &pid)) {
Eric Andersencb57d552001-06-28 07:25:16 +00007016 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
7017 if (jp->used && jp->nprocs > 0
7018 && jp->ps[jp->nprocs - 1].pid == pid)
7019 return jp;
7020 }
7021 }
7022 error("No such job: %s", name);
7023 /* NOTREACHED */
7024}
7025
7026
7027
7028/*
7029 * Return a new job structure,
7030 */
7031
Eric Andersen2870d962001-07-02 17:27:21 +00007032static struct job *
Eric Andersencb57d552001-06-28 07:25:16 +00007033makejob(node, nprocs)
7034 union node *node;
7035 int nprocs;
7036{
7037 int i;
7038 struct job *jp;
7039
7040 for (i = njobs, jp = jobtab ; ; jp++) {
7041 if (--i < 0) {
7042 INTOFF;
7043 if (njobs == 0) {
7044 jobtab = ckmalloc(4 * sizeof jobtab[0]);
7045 } else {
7046 jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
7047 memcpy(jp, jobtab, njobs * sizeof jp[0]);
7048 /* Relocate `ps' pointers */
7049 for (i = 0; i < njobs; i++)
7050 if (jp[i].ps == &jobtab[i].ps0)
7051 jp[i].ps = &jp[i].ps0;
7052 ckfree(jobtab);
7053 jobtab = jp;
7054 }
7055 jp = jobtab + njobs;
7056 for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0);
7057 INTON;
7058 break;
7059 }
7060 if (jp->used == 0)
7061 break;
7062 }
7063 INTOFF;
7064 jp->state = 0;
7065 jp->used = 1;
7066 jp->changed = 0;
7067 jp->nprocs = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00007068#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007069 jp->jobctl = jobctl;
7070#endif
7071 if (nprocs > 1) {
7072 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
7073 } else {
7074 jp->ps = &jp->ps0;
7075 }
7076 INTON;
7077 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
7078 jp - jobtab + 1));
7079 return jp;
7080}
7081
7082
7083/*
7084 * Fork of a subshell. If we are doing job control, give the subshell its
7085 * own process group. Jp is a job structure that the job is to be added to.
7086 * N is the command that will be evaluated by the child. Both jp and n may
7087 * be NULL. The mode parameter can be one of the following:
Eric Andersen2870d962001-07-02 17:27:21 +00007088 * FORK_FG - Fork off a foreground process.
7089 * FORK_BG - Fork off a background process.
7090 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
7091 * process group even if job control is on.
Eric Andersencb57d552001-06-28 07:25:16 +00007092 *
7093 * When job control is turned off, background processes have their standard
7094 * input redirected to /dev/null (except for the second and later processes
7095 * in a pipeline).
7096 */
7097
Eric Andersen2870d962001-07-02 17:27:21 +00007098
7099
Eric Andersencb57d552001-06-28 07:25:16 +00007100static int
Eric Andersen2870d962001-07-02 17:27:21 +00007101forkshell(struct job *jp, union node *n, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00007102{
7103 int pid;
7104 int pgrp;
7105 const char *devnull = _PATH_DEVNULL;
7106 const char *nullerr = "Can't open %s";
7107
7108 TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long)n,
7109 mode));
7110 INTOFF;
7111 pid = fork();
7112 if (pid == -1) {
7113 TRACE(("Fork failed, errno=%d\n", errno));
7114 INTON;
7115 error("Cannot fork");
7116 }
7117 if (pid == 0) {
7118 struct job *p;
7119 int wasroot;
7120 int i;
7121
7122 TRACE(("Child shell %d\n", getpid()));
7123 wasroot = rootshell;
7124 rootshell = 0;
7125 closescript();
7126 INTON;
7127 clear_traps();
Eric Andersen2870d962001-07-02 17:27:21 +00007128#ifdef JOBS
7129 jobctl = 0; /* do job control only in root shell */
Eric Andersencb57d552001-06-28 07:25:16 +00007130 if (wasroot && mode != FORK_NOJOB && mflag) {
7131 if (jp == NULL || jp->nprocs == 0)
7132 pgrp = getpid();
7133 else
7134 pgrp = jp->ps[0].pid;
7135 setpgid(0, pgrp);
7136 if (mode == FORK_FG) {
7137 /*** this causes superfluous TIOCSPGRPS ***/
7138#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00007139 if (ioctl(2, TIOCSPGRP, (char *)&pgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007140 error("TIOCSPGRP failed, errno=%d", errno);
7141#else
Eric Andersen3102ac42001-07-06 04:26:23 +00007142 if (tcsetpgrp(2, pgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007143 error("tcsetpgrp failed, errno=%d", errno);
7144#endif
7145 }
7146 setsignal(SIGTSTP);
7147 setsignal(SIGTTOU);
7148 } else if (mode == FORK_BG) {
7149 ignoresig(SIGINT);
7150 ignoresig(SIGQUIT);
7151 if ((jp == NULL || jp->nprocs == 0) &&
7152 ! fd0_redirected_p ()) {
7153 close(0);
7154 if (open(devnull, O_RDONLY) != 0)
7155 error(nullerr, devnull);
7156 }
7157 }
7158#else
7159 if (mode == FORK_BG) {
7160 ignoresig(SIGINT);
7161 ignoresig(SIGQUIT);
7162 if ((jp == NULL || jp->nprocs == 0) &&
7163 ! fd0_redirected_p ()) {
7164 close(0);
7165 if (open(devnull, O_RDONLY) != 0)
7166 error(nullerr, devnull);
7167 }
7168 }
7169#endif
7170 for (i = njobs, p = jobtab ; --i >= 0 ; p++)
7171 if (p->used)
7172 freejob(p);
7173 if (wasroot && iflag) {
7174 setsignal(SIGINT);
7175 setsignal(SIGQUIT);
7176 setsignal(SIGTERM);
7177 }
7178 return pid;
7179 }
7180 if (rootshell && mode != FORK_NOJOB && mflag) {
7181 if (jp == NULL || jp->nprocs == 0)
7182 pgrp = pid;
7183 else
7184 pgrp = jp->ps[0].pid;
7185 setpgid(pid, pgrp);
7186 }
7187 if (mode == FORK_BG)
Eric Andersen2870d962001-07-02 17:27:21 +00007188 backgndpid = pid; /* set $! */
Eric Andersencb57d552001-06-28 07:25:16 +00007189 if (jp) {
7190 struct procstat *ps = &jp->ps[jp->nprocs++];
7191 ps->pid = pid;
7192 ps->status = -1;
7193 ps->cmd = nullstr;
7194 if (iflag && rootshell && n)
7195 ps->cmd = commandtext(n);
7196 }
7197 INTON;
7198 TRACE(("In parent shell: child = %d\n", pid));
7199 return pid;
7200}
7201
7202
7203
7204/*
7205 * Wait for job to finish.
7206 *
7207 * Under job control we have the problem that while a child process is
7208 * running interrupts generated by the user are sent to the child but not
7209 * to the shell. This means that an infinite loop started by an inter-
7210 * active user may be hard to kill. With job control turned off, an
7211 * interactive user may place an interactive program inside a loop. If
7212 * the interactive program catches interrupts, the user doesn't want
7213 * these interrupts to also abort the loop. The approach we take here
7214 * is to have the shell ignore interrupt signals while waiting for a
7215 * forground process to terminate, and then send itself an interrupt
7216 * signal if the child process was terminated by an interrupt signal.
7217 * Unfortunately, some programs want to do a bit of cleanup and then
7218 * exit on interrupt; unless these processes terminate themselves by
7219 * sending a signal to themselves (instead of calling exit) they will
7220 * confuse this approach.
7221 */
7222
7223static int
7224waitforjob(jp)
7225 struct job *jp;
7226 {
Eric Andersen2870d962001-07-02 17:27:21 +00007227#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007228 int mypgrp = getpgrp();
7229#endif
7230 int status;
7231 int st;
7232 struct sigaction act, oact;
7233
7234 INTOFF;
7235 intreceived = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00007236#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007237 if (!jobctl) {
7238#else
7239 if (!iflag) {
7240#endif
7241 sigaction(SIGINT, 0, &act);
7242 act.sa_handler = waitonint;
7243 sigaction(SIGINT, &act, &oact);
7244 }
7245 TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
7246 while (jp->state == 0) {
7247 dowait(1, jp);
7248 }
Eric Andersen2870d962001-07-02 17:27:21 +00007249#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007250 if (!jobctl) {
7251#else
7252 if (!iflag) {
7253#endif
7254 sigaction(SIGINT, &oact, 0);
7255 if (intreceived && trap[SIGINT]) kill(getpid(), SIGINT);
7256 }
Eric Andersen2870d962001-07-02 17:27:21 +00007257#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007258 if (jp->jobctl) {
7259#ifdef OLD_TTY_DRIVER
Eric Andersen3102ac42001-07-06 04:26:23 +00007260 if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007261 error("TIOCSPGRP failed, errno=%d\n", errno);
7262#else
Eric Andersen3102ac42001-07-06 04:26:23 +00007263 if (tcsetpgrp(2, mypgrp) < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00007264 error("tcsetpgrp failed, errno=%d\n", errno);
7265#endif
7266 }
7267 if (jp->state == JOBSTOPPED)
7268 curjob = jp - jobtab + 1;
7269#endif
7270 status = jp->ps[jp->nprocs - 1].status;
7271 /* convert to 8 bits */
7272 if (WIFEXITED(status))
7273 st = WEXITSTATUS(status);
Eric Andersen2870d962001-07-02 17:27:21 +00007274#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007275 else if (WIFSTOPPED(status))
7276 st = WSTOPSIG(status) + 128;
7277#endif
7278 else
7279 st = WTERMSIG(status) + 128;
Eric Andersen2870d962001-07-02 17:27:21 +00007280#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007281 if (jp->jobctl) {
7282 /*
7283 * This is truly gross.
7284 * If we're doing job control, then we did a TIOCSPGRP which
7285 * caused us (the shell) to no longer be in the controlling
7286 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7287 * intuit from the subprocess exit status whether a SIGINT
7288 * occured, and if so interrupt ourselves. Yuck. - mycroft
7289 */
7290 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
7291 raise(SIGINT);
7292 }
Eric Andersen2870d962001-07-02 17:27:21 +00007293 if (jp->state == JOBDONE)
7294
Eric Andersencb57d552001-06-28 07:25:16 +00007295#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007296 freejob(jp);
7297 INTON;
7298 return st;
7299}
7300
7301
7302
7303/*
7304 * Wait for a process to terminate.
7305 */
7306
7307static int
7308dowait(block, job)
7309 int block;
7310 struct job *job;
7311{
7312 int pid;
7313 int status;
7314 struct procstat *sp;
7315 struct job *jp;
7316 struct job *thisjob;
7317 int done;
7318 int stopped;
7319 int core;
7320 int sig;
7321
7322 TRACE(("dowait(%d) called\n", block));
7323 do {
7324 pid = waitproc(block, &status);
7325 TRACE(("wait returns %d, status=%d\n", pid, status));
7326 } while (!(block & 2) && pid == -1 && errno == EINTR);
7327 if (pid <= 0)
7328 return pid;
7329 INTOFF;
7330 thisjob = NULL;
7331 for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
7332 if (jp->used) {
7333 done = 1;
7334 stopped = 1;
7335 for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
7336 if (sp->pid == -1)
7337 continue;
7338 if (sp->pid == pid) {
7339 TRACE(("Changing status of proc %d from 0x%x to 0x%x\n", pid, sp->status, status));
7340 sp->status = status;
7341 thisjob = jp;
7342 }
7343 if (sp->status == -1)
7344 stopped = 0;
7345 else if (WIFSTOPPED(sp->status))
7346 done = 0;
7347 }
Eric Andersen2870d962001-07-02 17:27:21 +00007348 if (stopped) { /* stopped or done */
Eric Andersencb57d552001-06-28 07:25:16 +00007349 int state = done? JOBDONE : JOBSTOPPED;
7350 if (jp->state != state) {
7351 TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
7352 jp->state = state;
Eric Andersen2870d962001-07-02 17:27:21 +00007353#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007354 if (done && curjob == jp - jobtab + 1)
Eric Andersen2870d962001-07-02 17:27:21 +00007355 curjob = 0; /* no current job */
Eric Andersencb57d552001-06-28 07:25:16 +00007356#endif
7357 }
7358 }
7359 }
7360 }
7361 INTON;
7362 if (! rootshell || ! iflag || (job && thisjob == job)) {
7363 core = WCOREDUMP(status);
Eric Andersen2870d962001-07-02 17:27:21 +00007364#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007365 if (WIFSTOPPED(status)) sig = WSTOPSIG(status);
7366 else
7367#endif
7368 if (WIFEXITED(status)) sig = 0;
7369 else sig = WTERMSIG(status);
7370
7371 if (sig != 0 && sig != SIGINT && sig != SIGPIPE) {
7372 if (thisjob != job)
Eric Andersen3102ac42001-07-06 04:26:23 +00007373 out2fmt("%d: ", pid);
Eric Andersen2870d962001-07-02 17:27:21 +00007374#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007375 if (sig == SIGTSTP && rootshell && iflag)
Eric Andersen3102ac42001-07-06 04:26:23 +00007376 out2fmt("%%%ld ",
Eric Andersencb57d552001-06-28 07:25:16 +00007377 (long)(job - jobtab + 1));
7378#endif
7379 if (sig < NSIG && sys_siglist[sig])
7380 out2str(sys_siglist[sig]);
7381 else
Eric Andersen3102ac42001-07-06 04:26:23 +00007382 out2fmt("Signal %d", sig);
Eric Andersencb57d552001-06-28 07:25:16 +00007383 if (core)
7384 out2str(" - core dumped");
7385 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00007386 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00007387 TRACE(("Not printing status: status=%d, sig=%d\n",
Eric Andersencb57d552001-06-28 07:25:16 +00007388 status, sig));
7389 }
7390 } else {
7391 TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job));
7392 if (thisjob)
7393 thisjob->changed = 1;
7394 }
7395 return pid;
7396}
7397
7398
7399
7400/*
7401 * Do a wait system call. If job control is compiled in, we accept
7402 * stopped processes. If block is zero, we return a value of zero
7403 * rather than blocking.
7404 *
7405 * System V doesn't have a non-blocking wait system call. It does
7406 * have a SIGCLD signal that is sent to a process when one of it's
7407 * children dies. The obvious way to use SIGCLD would be to install
7408 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7409 * was received, and have waitproc bump another counter when it got
7410 * the status of a process. Waitproc would then know that a wait
7411 * system call would not block if the two counters were different.
7412 * This approach doesn't work because if a process has children that
7413 * have not been waited for, System V will send it a SIGCLD when it
7414 * installs a signal handler for SIGCLD. What this means is that when
7415 * a child exits, the shell will be sent SIGCLD signals continuously
7416 * until is runs out of stack space, unless it does a wait call before
7417 * restoring the signal handler. The code below takes advantage of
7418 * this (mis)feature by installing a signal handler for SIGCLD and
7419 * then checking to see whether it was called. If there are any
7420 * children to be waited for, it will be.
7421 *
Eric Andersencb57d552001-06-28 07:25:16 +00007422 */
7423
Eric Andersencb57d552001-06-28 07:25:16 +00007424static int
7425waitproc(block, status)
7426 int block;
7427 int *status;
7428{
Eric Andersencb57d552001-06-28 07:25:16 +00007429 int flags;
7430
7431 flags = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00007432#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007433 if (jobctl)
7434 flags |= WUNTRACED;
7435#endif
7436 if (block == 0)
7437 flags |= WNOHANG;
7438 return wait3(status, flags, (struct rusage *)NULL);
Eric Andersencb57d552001-06-28 07:25:16 +00007439}
7440
7441/*
7442 * return 1 if there are stopped jobs, otherwise 0
7443 */
Eric Andersencb57d552001-06-28 07:25:16 +00007444static int
Eric Andersen2870d962001-07-02 17:27:21 +00007445stoppedjobs(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007446{
7447 int jobno;
7448 struct job *jp;
7449
7450 if (job_warning)
7451 return (0);
7452 for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
7453 if (jp->used == 0)
7454 continue;
7455 if (jp->state == JOBSTOPPED) {
7456 out2str("You have stopped jobs.\n");
7457 job_warning = 2;
7458 return (1);
7459 }
7460 }
7461
7462 return (0);
7463}
7464
7465/*
7466 * Return a string identifying a command (to be printed by the
7467 * jobs command.
7468 */
7469
7470static char *cmdnextc;
7471static int cmdnleft;
Eric Andersen2870d962001-07-02 17:27:21 +00007472#define MAXCMDTEXT 200
Eric Andersencb57d552001-06-28 07:25:16 +00007473
Eric Andersen2870d962001-07-02 17:27:21 +00007474static void
7475cmdputs(const char *s)
7476{
7477 const char *p;
7478 char *q;
7479 char c;
7480 int subtype = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007481
Eric Andersen2870d962001-07-02 17:27:21 +00007482 if (cmdnleft <= 0)
7483 return;
7484 p = s;
7485 q = cmdnextc;
7486 while ((c = *p++) != '\0') {
7487 if (c == CTLESC)
7488 *q++ = *p++;
7489 else if (c == CTLVAR) {
7490 *q++ = '$';
7491 if (--cmdnleft > 0)
7492 *q++ = '{';
7493 subtype = *p++;
7494 } else if (c == '=' && subtype != 0) {
7495 *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
7496 subtype = 0;
7497 } else if (c == CTLENDVAR) {
7498 *q++ = '}';
7499 } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE)
7500 cmdnleft++; /* ignore it */
7501 else
7502 *q++ = c;
7503 if (--cmdnleft <= 0) {
7504 *q++ = '.';
7505 *q++ = '.';
7506 *q++ = '.';
7507 break;
7508 }
7509 }
7510 cmdnextc = q;
Eric Andersencb57d552001-06-28 07:25:16 +00007511}
7512
7513
7514static void
Eric Andersen2870d962001-07-02 17:27:21 +00007515cmdtxt(const union node *n)
7516{
Eric Andersencb57d552001-06-28 07:25:16 +00007517 union node *np;
7518 struct nodelist *lp;
7519 const char *p;
7520 int i;
7521 char s[2];
7522
7523 if (n == NULL)
7524 return;
7525 switch (n->type) {
7526 case NSEMI:
7527 cmdtxt(n->nbinary.ch1);
7528 cmdputs("; ");
7529 cmdtxt(n->nbinary.ch2);
7530 break;
7531 case NAND:
7532 cmdtxt(n->nbinary.ch1);
7533 cmdputs(" && ");
7534 cmdtxt(n->nbinary.ch2);
7535 break;
7536 case NOR:
7537 cmdtxt(n->nbinary.ch1);
7538 cmdputs(" || ");
7539 cmdtxt(n->nbinary.ch2);
7540 break;
7541 case NPIPE:
7542 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
7543 cmdtxt(lp->n);
7544 if (lp->next)
7545 cmdputs(" | ");
7546 }
7547 break;
7548 case NSUBSHELL:
7549 cmdputs("(");
7550 cmdtxt(n->nredir.n);
7551 cmdputs(")");
7552 break;
7553 case NREDIR:
7554 case NBACKGND:
7555 cmdtxt(n->nredir.n);
7556 break;
7557 case NIF:
7558 cmdputs("if ");
7559 cmdtxt(n->nif.test);
7560 cmdputs("; then ");
7561 cmdtxt(n->nif.ifpart);
7562 cmdputs("...");
7563 break;
7564 case NWHILE:
7565 cmdputs("while ");
7566 goto until;
7567 case NUNTIL:
7568 cmdputs("until ");
7569until:
7570 cmdtxt(n->nbinary.ch1);
7571 cmdputs("; do ");
7572 cmdtxt(n->nbinary.ch2);
7573 cmdputs("; done");
7574 break;
7575 case NFOR:
7576 cmdputs("for ");
7577 cmdputs(n->nfor.var);
7578 cmdputs(" in ...");
7579 break;
7580 case NCASE:
7581 cmdputs("case ");
7582 cmdputs(n->ncase.expr->narg.text);
7583 cmdputs(" in ...");
7584 break;
7585 case NDEFUN:
7586 cmdputs(n->narg.text);
7587 cmdputs("() ...");
7588 break;
7589 case NCMD:
7590 for (np = n->ncmd.args ; np ; np = np->narg.next) {
7591 cmdtxt(np);
7592 if (np->narg.next)
7593 cmdputs(spcstr);
7594 }
7595 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
7596 cmdputs(spcstr);
7597 cmdtxt(np);
7598 }
7599 break;
7600 case NARG:
7601 cmdputs(n->narg.text);
7602 break;
7603 case NTO:
7604 p = ">"; i = 1; goto redir;
7605 case NAPPEND:
7606 p = ">>"; i = 1; goto redir;
7607 case NTOFD:
7608 p = ">&"; i = 1; goto redir;
7609 case NTOOV:
7610 p = ">|"; i = 1; goto redir;
7611 case NFROM:
7612 p = "<"; i = 0; goto redir;
7613 case NFROMFD:
7614 p = "<&"; i = 0; goto redir;
7615 case NFROMTO:
7616 p = "<>"; i = 0; goto redir;
7617redir:
7618 if (n->nfile.fd != i) {
7619 s[0] = n->nfile.fd + '0';
7620 s[1] = '\0';
7621 cmdputs(s);
7622 }
7623 cmdputs(p);
7624 if (n->type == NTOFD || n->type == NFROMFD) {
7625 s[0] = n->ndup.dupfd + '0';
7626 s[1] = '\0';
7627 cmdputs(s);
7628 } else {
7629 cmdtxt(n->nfile.fname);
7630 }
7631 break;
7632 case NHERE:
7633 case NXHERE:
7634 cmdputs("<<...");
7635 break;
7636 default:
7637 cmdputs("???");
7638 break;
7639 }
7640}
7641
7642
Eric Andersen2870d962001-07-02 17:27:21 +00007643static char *
7644commandtext(const union node *n)
7645{
7646 char *name;
Eric Andersencb57d552001-06-28 07:25:16 +00007647
Eric Andersen2870d962001-07-02 17:27:21 +00007648 cmdnextc = name = ckmalloc(MAXCMDTEXT);
7649 cmdnleft = MAXCMDTEXT - 4;
7650 cmdtxt(n);
7651 *cmdnextc = '\0';
7652 return name;
Eric Andersencb57d552001-06-28 07:25:16 +00007653}
7654
Eric Andersen2870d962001-07-02 17:27:21 +00007655
Eric Andersencb57d552001-06-28 07:25:16 +00007656static void waitonint(int sig) {
7657 intreceived = 1;
7658 return;
7659}
Eric Andersencb57d552001-06-28 07:25:16 +00007660/*
7661 * Routines to check for mail. (Perhaps make part of main.c?)
7662 */
7663
7664
7665#define MAXMBOXES 10
7666
7667
Eric Andersen2870d962001-07-02 17:27:21 +00007668static int nmboxes; /* number of mailboxes */
7669static time_t mailtime[MAXMBOXES]; /* times of mailboxes */
Eric Andersencb57d552001-06-28 07:25:16 +00007670
7671
7672
7673/*
7674 * Print appropriate message(s) if mail has arrived. If the argument is
7675 * nozero, then the value of MAIL has changed, so we just update the
7676 * values.
7677 */
7678
7679static void
Eric Andersen2870d962001-07-02 17:27:21 +00007680chkmail(int silent)
Eric Andersencb57d552001-06-28 07:25:16 +00007681{
7682 int i;
7683 const char *mpath;
7684 char *p;
7685 char *q;
7686 struct stackmark smark;
7687 struct stat statb;
7688
7689 if (silent)
7690 nmboxes = 10;
7691 if (nmboxes == 0)
7692 return;
7693 setstackmark(&smark);
7694 mpath = mpathset()? mpathval() : mailval();
7695 for (i = 0 ; i < nmboxes ; i++) {
7696 p = padvance(&mpath, nullstr);
7697 if (p == NULL)
7698 break;
7699 if (*p == '\0')
7700 continue;
7701 for (q = p ; *q ; q++);
7702#ifdef DEBUG
7703 if (q[-1] != '/')
7704 abort();
7705#endif
Eric Andersen2870d962001-07-02 17:27:21 +00007706 q[-1] = '\0'; /* delete trailing '/' */
Eric Andersencb57d552001-06-28 07:25:16 +00007707 if (stat(p, &statb) < 0)
7708 statb.st_size = 0;
7709 if (statb.st_size > mailtime[i] && ! silent) {
Eric Andersen3102ac42001-07-06 04:26:23 +00007710 out2fmt(snlfmt,
7711 pathopt? pathopt : "you have mail");
Eric Andersencb57d552001-06-28 07:25:16 +00007712 }
7713 mailtime[i] = statb.st_size;
Eric Andersencb57d552001-06-28 07:25:16 +00007714 }
7715 nmboxes = i;
7716 popstackmark(&smark);
7717}
Eric Andersencb57d552001-06-28 07:25:16 +00007718
7719#define PROFILE 0
7720
Eric Andersencb57d552001-06-28 07:25:16 +00007721#if PROFILE
Eric Andersen2870d962001-07-02 17:27:21 +00007722static short profile_buf[16384];
Eric Andersencb57d552001-06-28 07:25:16 +00007723extern int etext();
7724#endif
7725
Eric Andersen2870d962001-07-02 17:27:21 +00007726static void read_profile (const char *);
7727static char *find_dot_file (char *);
7728static void cmdloop (int);
7729static void options (int);
7730static void minus_o (char *, int);
7731static void setoption (int, int);
7732static void procargs (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00007733
Eric Andersen2870d962001-07-02 17:27:21 +00007734
Eric Andersencb57d552001-06-28 07:25:16 +00007735/*
7736 * Main routine. We initialize things, parse the arguments, execute
7737 * profiles if we're a login shell, and then call cmdloop to execute
7738 * commands. The setjmp call sets up the location to jump to when an
7739 * exception occurs. When an exception occurs the variable "state"
7740 * is used to figure out how far we had gotten.
7741 */
7742
7743int
7744shell_main(argc, argv)
7745 int argc;
7746 char **argv;
7747{
7748 struct jmploc jmploc;
7749 struct stackmark smark;
7750 volatile int state;
7751 char *shinit;
7752
7753 DOTCMD = find_builtin(".");
7754 BLTINCMD = find_builtin("builtin");
Eric Andersencb57d552001-06-28 07:25:16 +00007755 EXECCMD = find_builtin("exec");
7756 EVALCMD = find_builtin("eval");
7757
7758#if PROFILE
7759 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7760#endif
7761#if defined(linux) || defined(__GNU__)
7762 signal(SIGCHLD, SIG_DFL);
7763#endif
7764 state = 0;
7765 if (setjmp(jmploc.loc)) {
7766 INTOFF;
7767 /*
7768 * When a shell procedure is executed, we raise the
7769 * exception EXSHELLPROC to clean up before executing
7770 * the shell procedure.
7771 */
7772 switch (exception) {
7773 case EXSHELLPROC:
7774 rootpid = getpid();
7775 rootshell = 1;
7776 minusc = NULL;
7777 state = 3;
7778 break;
7779
7780 case EXEXEC:
7781 exitstatus = exerrno;
7782 break;
7783
7784 case EXERROR:
7785 exitstatus = 2;
7786 break;
7787
7788 default:
7789 break;
7790 }
7791
7792 if (exception != EXSHELLPROC) {
7793 if (state == 0 || iflag == 0 || ! rootshell)
7794 exitshell(exitstatus);
7795 }
7796 reset();
Eric Andersen2870d962001-07-02 17:27:21 +00007797 if (exception == EXINT) {
Eric Andersencb57d552001-06-28 07:25:16 +00007798 out2c('\n');
Eric Andersencb57d552001-06-28 07:25:16 +00007799 }
7800 popstackmark(&smark);
Eric Andersen2870d962001-07-02 17:27:21 +00007801 FORCEINTON; /* enable interrupts */
Eric Andersencb57d552001-06-28 07:25:16 +00007802 if (state == 1)
7803 goto state1;
7804 else if (state == 2)
7805 goto state2;
7806 else if (state == 3)
7807 goto state3;
7808 else
7809 goto state4;
7810 }
7811 handler = &jmploc;
7812#ifdef DEBUG
7813 opentrace();
7814 trputs("Shell args: "); trargs(argv);
7815#endif
7816 rootpid = getpid();
7817 rootshell = 1;
7818 init();
7819 setstackmark(&smark);
7820 procargs(argc, argv);
7821 if (argv[0] && argv[0][0] == '-') {
7822 state = 1;
7823 read_profile("/etc/profile");
7824state1:
7825 state = 2;
7826 read_profile(".profile");
7827 }
7828state2:
7829 state = 3;
7830#ifndef linux
7831 if (getuid() == geteuid() && getgid() == getegid()) {
7832#endif
7833 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
7834 state = 3;
7835 read_profile(shinit);
7836 }
7837#ifndef linux
7838 }
7839#endif
7840state3:
7841 state = 4;
7842 if (sflag == 0 || minusc) {
7843 static int sigs[] = {
Eric Andersen2870d962001-07-02 17:27:21 +00007844 SIGINT, SIGQUIT, SIGHUP,
Eric Andersencb57d552001-06-28 07:25:16 +00007845#ifdef SIGTSTP
7846 SIGTSTP,
7847#endif
7848 SIGPIPE
7849 };
7850#define SIGSSIZE (sizeof(sigs)/sizeof(sigs[0]))
7851 int i;
7852
7853 for (i = 0; i < SIGSSIZE; i++)
7854 setsignal(sigs[i]);
7855 }
7856
7857 if (minusc)
7858 evalstring(minusc, 0);
7859
7860 if (sflag || minusc == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00007861state4: /* XXX ??? - why isn't this before the "if" statement */
Eric Andersencb57d552001-06-28 07:25:16 +00007862 cmdloop(1);
7863 }
7864#if PROFILE
7865 monitor(0);
7866#endif
7867 exitshell(exitstatus);
7868 /* NOTREACHED */
7869}
7870
7871
7872/*
7873 * Read and execute commands. "Top" is nonzero for the top level command
7874 * loop; it turns on prompting if the shell is interactive.
7875 */
7876
7877static void
Eric Andersen2870d962001-07-02 17:27:21 +00007878cmdloop(int top)
Eric Andersencb57d552001-06-28 07:25:16 +00007879{
7880 union node *n;
7881 struct stackmark smark;
7882 int inter;
7883 int numeof = 0;
7884
7885 TRACE(("cmdloop(%d) called\n", top));
7886 setstackmark(&smark);
7887 for (;;) {
7888 if (pendingsigs)
7889 dotrap();
7890 inter = 0;
7891 if (iflag && top) {
7892 inter++;
7893 showjobs(1);
7894 chkmail(0);
Eric Andersen3102ac42001-07-06 04:26:23 +00007895 flushall();
Eric Andersencb57d552001-06-28 07:25:16 +00007896 }
7897 n = parsecmd(inter);
7898 /* showtree(n); DEBUG */
7899 if (n == NEOF) {
7900 if (!top || numeof >= 50)
7901 break;
7902 if (!stoppedjobs()) {
7903 if (!Iflag)
7904 break;
7905 out2str("\nUse \"exit\" to leave shell.\n");
7906 }
7907 numeof++;
7908 } else if (n != NULL && nflag == 0) {
7909 job_warning = (job_warning == 2) ? 1 : 0;
7910 numeof = 0;
7911 evaltree(n, 0);
7912 }
7913 popstackmark(&smark);
7914 setstackmark(&smark);
7915 if (evalskip == SKIPFILE) {
7916 evalskip = 0;
7917 break;
7918 }
7919 }
7920 popstackmark(&smark);
7921}
7922
7923
7924
7925/*
7926 * Read /etc/profile or .profile. Return on error.
7927 */
7928
7929static void
7930read_profile(name)
7931 const char *name;
7932{
7933 int fd;
7934 int xflag_set = 0;
7935 int vflag_set = 0;
7936
7937 INTOFF;
7938 if ((fd = open(name, O_RDONLY)) >= 0)
7939 setinputfd(fd, 1);
7940 INTON;
7941 if (fd < 0)
7942 return;
7943 /* -q turns off -x and -v just when executing init files */
7944 if (qflag) {
7945 if (xflag)
7946 xflag = 0, xflag_set = 1;
7947 if (vflag)
7948 vflag = 0, vflag_set = 1;
7949 }
7950 cmdloop(0);
7951 if (qflag) {
7952 if (xflag_set)
7953 xflag = 1;
7954 if (vflag_set)
7955 vflag = 1;
7956 }
7957 popfile();
7958}
7959
7960
7961
7962/*
7963 * Read a file containing shell functions.
7964 */
7965
7966static void
Eric Andersen2870d962001-07-02 17:27:21 +00007967readcmdfile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00007968{
7969 int fd;
7970
7971 INTOFF;
7972 if ((fd = open(name, O_RDONLY)) >= 0)
7973 setinputfd(fd, 1);
7974 else
7975 error("Can't open %s", name);
7976 INTON;
7977 cmdloop(0);
7978 popfile();
7979}
7980
7981
7982
7983/*
7984 * Take commands from a file. To be compatable we should do a path
7985 * search for the file, which is necessary to find sub-commands.
7986 */
7987
7988
7989static char *
7990find_dot_file(mybasename)
7991 char *mybasename;
7992{
7993 char *fullname;
7994 const char *path = pathval();
7995 struct stat statb;
7996
7997 /* don't try this for absolute or relative paths */
7998 if (strchr(mybasename, '/'))
7999 return mybasename;
8000
8001 while ((fullname = padvance(&path, mybasename)) != NULL) {
8002 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
8003 /*
8004 * Don't bother freeing here, since it will
8005 * be freed by the caller.
8006 */
8007 return fullname;
8008 }
8009 stunalloc(fullname);
8010 }
8011
8012 /* not found in the PATH */
8013 error("%s: not found", mybasename);
8014 /* NOTREACHED */
8015}
8016
8017static int
8018dotcmd(argc, argv)
8019 int argc;
8020 char **argv;
8021{
8022 struct strlist *sp;
8023 exitstatus = 0;
8024
8025 for (sp = cmdenviron; sp ; sp = sp->next)
8026 setvareq(savestr(sp->text), VSTRFIXED|VTEXTFIXED);
8027
Eric Andersen2870d962001-07-02 17:27:21 +00008028 if (argc >= 2) { /* That's what SVR2 does */
Eric Andersencb57d552001-06-28 07:25:16 +00008029 char *fullname;
8030 struct stackmark smark;
8031
8032 setstackmark(&smark);
8033 fullname = find_dot_file(argv[1]);
8034 setinputfile(fullname, 1);
8035 commandname = fullname;
8036 cmdloop(0);
8037 popfile();
8038 popstackmark(&smark);
8039 }
8040 return exitstatus;
8041}
8042
8043
8044static int
8045exitcmd(argc, argv)
8046 int argc;
8047 char **argv;
8048{
8049 if (stoppedjobs())
8050 return 0;
8051 if (argc > 1)
8052 exitstatus = number(argv[1]);
8053 else
8054 exitstatus = oexitstatus;
8055 exitshell(exitstatus);
8056 /* NOTREACHED */
8057}
Eric Andersen2870d962001-07-02 17:27:21 +00008058static pointer
8059stalloc(int nbytes)
Eric Andersencb57d552001-06-28 07:25:16 +00008060{
8061 char *p;
8062
8063 nbytes = ALIGN(nbytes);
8064 if (nbytes > stacknleft) {
8065 int blocksize;
8066 struct stack_block *sp;
8067
8068 blocksize = nbytes;
8069 if (blocksize < MINSIZE)
8070 blocksize = MINSIZE;
8071 INTOFF;
8072 sp = ckmalloc(sizeof(struct stack_block) - MINSIZE + blocksize);
8073 sp->prev = stackp;
8074 stacknxt = sp->space;
8075 stacknleft = blocksize;
8076 stackp = sp;
8077 INTON;
8078 }
8079 p = stacknxt;
8080 stacknxt += nbytes;
8081 stacknleft -= nbytes;
8082 return p;
8083}
8084
8085
8086static void
Eric Andersen2870d962001-07-02 17:27:21 +00008087stunalloc(pointer p)
8088{
Eric Andersencb57d552001-06-28 07:25:16 +00008089#ifdef DEBUG
Eric Andersen2870d962001-07-02 17:27:21 +00008090 if (p == NULL) { /*DEBUG */
Eric Andersencb57d552001-06-28 07:25:16 +00008091 write(2, "stunalloc\n", 10);
8092 abort();
8093 }
8094#endif
8095 if (!(stacknxt >= (char *)p && (char *)p >= stackp->space)) {
8096 p = stackp->space;
8097 }
8098 stacknleft += stacknxt - (char *)p;
8099 stacknxt = p;
8100}
8101
8102
Eric Andersencb57d552001-06-28 07:25:16 +00008103static void
Eric Andersen2870d962001-07-02 17:27:21 +00008104setstackmark(struct stackmark *mark)
8105{
Eric Andersencb57d552001-06-28 07:25:16 +00008106 mark->stackp = stackp;
8107 mark->stacknxt = stacknxt;
8108 mark->stacknleft = stacknleft;
8109 mark->marknext = markp;
8110 markp = mark;
8111}
8112
8113
8114static void
Eric Andersen2870d962001-07-02 17:27:21 +00008115popstackmark(struct stackmark *mark)
8116{
Eric Andersencb57d552001-06-28 07:25:16 +00008117 struct stack_block *sp;
8118
8119 INTOFF;
8120 markp = mark->marknext;
8121 while (stackp != mark->stackp) {
8122 sp = stackp;
8123 stackp = sp->prev;
8124 ckfree(sp);
8125 }
8126 stacknxt = mark->stacknxt;
8127 stacknleft = mark->stacknleft;
8128 INTON;
8129}
8130
8131
8132/*
8133 * When the parser reads in a string, it wants to stick the string on the
8134 * stack and only adjust the stack pointer when it knows how big the
8135 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8136 * of space on top of the stack and stackblocklen returns the length of
8137 * this block. Growstackblock will grow this space by at least one byte,
8138 * possibly moving it (like realloc). Grabstackblock actually allocates the
8139 * part of the block that has been used.
8140 */
8141
8142static void
Eric Andersen2870d962001-07-02 17:27:21 +00008143growstackblock(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00008144 char *p;
8145 int newlen = ALIGN(stacknleft * 2 + 100);
8146 char *oldspace = stacknxt;
8147 int oldlen = stacknleft;
8148 struct stack_block *sp;
8149 struct stack_block *oldstackp;
8150
8151 if (stacknxt == stackp->space && stackp != &stackbase) {
8152 INTOFF;
8153 oldstackp = stackp;
8154 sp = stackp;
8155 stackp = sp->prev;
8156 sp = ckrealloc((pointer)sp, sizeof(struct stack_block) - MINSIZE + newlen);
8157 sp->prev = stackp;
8158 stackp = sp;
8159 stacknxt = sp->space;
8160 stacknleft = newlen;
8161 {
8162 /* Stack marks pointing to the start of the old block
Eric Andersen2870d962001-07-02 17:27:21 +00008163 * must be relocated to point to the new block
Eric Andersencb57d552001-06-28 07:25:16 +00008164 */
8165 struct stackmark *xmark;
8166 xmark = markp;
8167 while (xmark != NULL && xmark->stackp == oldstackp) {
8168 xmark->stackp = stackp;
8169 xmark->stacknxt = stacknxt;
8170 xmark->stacknleft = stacknleft;
8171 xmark = xmark->marknext;
8172 }
8173 }
8174 INTON;
8175 } else {
8176 p = stalloc(newlen);
8177 memcpy(p, oldspace, oldlen);
Eric Andersen2870d962001-07-02 17:27:21 +00008178 stacknxt = p; /* free the space */
8179 stacknleft += newlen; /* we just allocated */
Eric Andersencb57d552001-06-28 07:25:16 +00008180 }
8181}
8182
8183
8184
Eric Andersen2870d962001-07-02 17:27:21 +00008185static inline void
8186grabstackblock(int len)
Eric Andersencb57d552001-06-28 07:25:16 +00008187{
8188 len = ALIGN(len);
8189 stacknxt += len;
8190 stacknleft -= len;
8191}
8192
8193
8194
8195/*
8196 * The following routines are somewhat easier to use that the above.
8197 * The user declares a variable of type STACKSTR, which may be declared
8198 * to be a register. The macro STARTSTACKSTR initializes things. Then
8199 * the user uses the macro STPUTC to add characters to the string. In
8200 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8201 * grown as necessary. When the user is done, she can just leave the
8202 * string there and refer to it using stackblock(). Or she can allocate
8203 * the space for it using grabstackstr(). If it is necessary to allow
8204 * someone else to use the stack temporarily and then continue to grow
8205 * the string, the user should use grabstack to allocate the space, and
8206 * then call ungrabstr(p) to return to the previous mode of operation.
8207 *
8208 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8209 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8210 * is space for at least one character.
8211 */
8212
8213
8214static char *
Eric Andersen2870d962001-07-02 17:27:21 +00008215growstackstr(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00008216 int len = stackblocksize();
8217 if (herefd >= 0 && len >= 1024) {
8218 xwrite(herefd, stackblock(), len);
8219 sstrnleft = len - 1;
8220 return stackblock();
8221 }
8222 growstackblock();
8223 sstrnleft = stackblocksize() - len - 1;
8224 return stackblock() + len;
8225}
8226
8227
8228/*
8229 * Called from CHECKSTRSPACE.
8230 */
8231
8232static char *
8233makestrspace(size_t newlen) {
8234 int len = stackblocksize() - sstrnleft;
8235 do {
8236 growstackblock();
8237 sstrnleft = stackblocksize() - len;
8238 } while (sstrnleft < newlen);
8239 return stackblock() + len;
8240}
8241
8242
8243
8244static void
Eric Andersen2870d962001-07-02 17:27:21 +00008245ungrabstackstr(char *s, char *p)
8246{
Eric Andersencb57d552001-06-28 07:25:16 +00008247 stacknleft += stacknxt - s;
8248 stacknxt = s;
8249 sstrnleft = stacknleft - (p - s);
8250}
Eric Andersencb57d552001-06-28 07:25:16 +00008251/*
8252 * Miscelaneous builtins.
8253 */
8254
8255
8256#undef rflag
8257
8258#ifdef __GLIBC__
Eric Andersen2870d962001-07-02 17:27:21 +00008259static mode_t getmode(const void *, mode_t);
Eric Andersencb57d552001-06-28 07:25:16 +00008260static void *setmode(const char *);
8261
8262#if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
8263typedef enum __rlimit_resource rlim_t;
8264#endif
8265#endif
8266
8267
8268
8269/*
8270 * The read builtin. The -e option causes backslashes to escape the
8271 * following character.
8272 *
8273 * This uses unbuffered input, which may be avoidable in some cases.
8274 */
8275
8276static int
8277readcmd(argc, argv)
8278 int argc;
8279 char **argv;
8280{
8281 char **ap;
8282 int backslash;
8283 char c;
8284 int rflag;
8285 char *prompt;
8286 const char *ifs;
8287 char *p;
8288 int startword;
8289 int status;
8290 int i;
8291
8292 rflag = 0;
8293 prompt = NULL;
8294 while ((i = nextopt("p:r")) != '\0') {
8295 if (i == 'p')
8296 prompt = optionarg;
8297 else
8298 rflag = 1;
8299 }
8300 if (prompt && isatty(0)) {
8301 putprompt(prompt);
8302 flushall();
8303 }
8304 if (*(ap = argptr) == NULL)
8305 error("arg count");
8306 if ((ifs = bltinlookup("IFS")) == NULL)
8307 ifs = defifs;
8308 status = 0;
8309 startword = 1;
8310 backslash = 0;
8311 STARTSTACKSTR(p);
8312 for (;;) {
8313 if (read(0, &c, 1) != 1) {
8314 status = 1;
8315 break;
8316 }
8317 if (c == '\0')
8318 continue;
8319 if (backslash) {
8320 backslash = 0;
8321 if (c != '\n')
8322 STPUTC(c, p);
8323 continue;
8324 }
8325 if (!rflag && c == '\\') {
8326 backslash++;
8327 continue;
8328 }
8329 if (c == '\n')
8330 break;
8331 if (startword && *ifs == ' ' && strchr(ifs, c)) {
8332 continue;
8333 }
8334 startword = 0;
8335 if (backslash && c == '\\') {
8336 if (read(0, &c, 1) != 1) {
8337 status = 1;
8338 break;
8339 }
8340 STPUTC(c, p);
8341 } else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
8342 STACKSTRNUL(p);
8343 setvar(*ap, stackblock(), 0);
8344 ap++;
8345 startword = 1;
8346 STARTSTACKSTR(p);
8347 } else {
8348 STPUTC(c, p);
8349 }
8350 }
8351 STACKSTRNUL(p);
8352 /* Remove trailing blanks */
8353 while (stackblock() <= --p && strchr(ifs, *p) != NULL)
8354 *p = '\0';
8355 setvar(*ap, stackblock(), 0);
8356 while (*++ap != NULL)
8357 setvar(*ap, nullstr, 0);
8358 return status;
8359}
8360
8361
8362
8363static int
8364umaskcmd(argc, argv)
8365 int argc;
8366 char **argv;
8367{
8368 char *ap;
8369 int mask;
8370 int i;
8371 int symbolic_mode = 0;
8372
8373 while ((i = nextopt("S")) != '\0') {
8374 symbolic_mode = 1;
8375 }
8376
8377 INTOFF;
8378 mask = umask(0);
8379 umask(mask);
8380 INTON;
8381
8382 if ((ap = *argptr) == NULL) {
8383 if (symbolic_mode) {
8384 char u[4], g[4], o[4];
8385
8386 i = 0;
8387 if ((mask & S_IRUSR) == 0)
8388 u[i++] = 'r';
8389 if ((mask & S_IWUSR) == 0)
8390 u[i++] = 'w';
8391 if ((mask & S_IXUSR) == 0)
8392 u[i++] = 'x';
8393 u[i] = '\0';
8394
8395 i = 0;
8396 if ((mask & S_IRGRP) == 0)
8397 g[i++] = 'r';
8398 if ((mask & S_IWGRP) == 0)
8399 g[i++] = 'w';
8400 if ((mask & S_IXGRP) == 0)
8401 g[i++] = 'x';
8402 g[i] = '\0';
8403
8404 i = 0;
8405 if ((mask & S_IROTH) == 0)
8406 o[i++] = 'r';
8407 if ((mask & S_IWOTH) == 0)
8408 o[i++] = 'w';
8409 if ((mask & S_IXOTH) == 0)
8410 o[i++] = 'x';
8411 o[i] = '\0';
8412
8413 out1fmt("u=%s,g=%s,o=%s\n", u, g, o);
8414 } else {
8415 out1fmt("%.4o\n", mask);
8416 }
8417 } else {
8418 if (isdigit((unsigned char)*ap)) {
8419 mask = 0;
8420 do {
8421 if (*ap >= '8' || *ap < '0')
8422 error("Illegal number: %s", argv[1]);
8423 mask = (mask << 3) + (*ap - '0');
8424 } while (*++ap != '\0');
8425 umask(mask);
8426 } else {
8427 void *set;
8428
8429 INTOFF;
8430 if ((set = setmode(ap)) != 0) {
8431 mask = getmode(set, ~mask & 0777);
8432 ckfree(set);
8433 }
8434 INTON;
8435 if (!set)
8436 error("Illegal mode: %s", ap);
8437
8438 umask(~mask & 0777);
8439 }
8440 }
8441 return 0;
8442}
8443
8444/*
8445 * ulimit builtin
8446 *
8447 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
8448 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
8449 * ash by J.T. Conklin.
8450 *
8451 * Public domain.
8452 */
8453
8454struct limits {
8455 const char *name;
Eric Andersen2870d962001-07-02 17:27:21 +00008456 int cmd;
8457 int factor; /* multiply by to get rlim_{cur,max} values */
8458 char option;
Eric Andersencb57d552001-06-28 07:25:16 +00008459};
8460
8461static const struct limits limits[] = {
8462#ifdef RLIMIT_CPU
Eric Andersen2870d962001-07-02 17:27:21 +00008463 { "time(seconds)", RLIMIT_CPU, 1, 't' },
Eric Andersencb57d552001-06-28 07:25:16 +00008464#endif
8465#ifdef RLIMIT_FSIZE
Eric Andersen2870d962001-07-02 17:27:21 +00008466 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
Eric Andersencb57d552001-06-28 07:25:16 +00008467#endif
8468#ifdef RLIMIT_DATA
Eric Andersen2870d962001-07-02 17:27:21 +00008469 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
Eric Andersencb57d552001-06-28 07:25:16 +00008470#endif
8471#ifdef RLIMIT_STACK
Eric Andersen2870d962001-07-02 17:27:21 +00008472 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
Eric Andersencb57d552001-06-28 07:25:16 +00008473#endif
8474#ifdef RLIMIT_CORE
Eric Andersen2870d962001-07-02 17:27:21 +00008475 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
Eric Andersencb57d552001-06-28 07:25:16 +00008476#endif
8477#ifdef RLIMIT_RSS
Eric Andersen2870d962001-07-02 17:27:21 +00008478 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
Eric Andersencb57d552001-06-28 07:25:16 +00008479#endif
8480#ifdef RLIMIT_MEMLOCK
Eric Andersen2870d962001-07-02 17:27:21 +00008481 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
Eric Andersencb57d552001-06-28 07:25:16 +00008482#endif
8483#ifdef RLIMIT_NPROC
Eric Andersen2870d962001-07-02 17:27:21 +00008484 { "process(processes)", RLIMIT_NPROC, 1, 'p' },
Eric Andersencb57d552001-06-28 07:25:16 +00008485#endif
8486#ifdef RLIMIT_NOFILE
Eric Andersen2870d962001-07-02 17:27:21 +00008487 { "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' },
Eric Andersencb57d552001-06-28 07:25:16 +00008488#endif
8489#ifdef RLIMIT_VMEM
Eric Andersen2870d962001-07-02 17:27:21 +00008490 { "vmemory(kbytes)", RLIMIT_VMEM, 1024, 'v' },
Eric Andersencb57d552001-06-28 07:25:16 +00008491#endif
8492#ifdef RLIMIT_SWAP
Eric Andersen2870d962001-07-02 17:27:21 +00008493 { "swap(kbytes)", RLIMIT_SWAP, 1024, 'w' },
Eric Andersencb57d552001-06-28 07:25:16 +00008494#endif
Eric Andersen2870d962001-07-02 17:27:21 +00008495 { (char *) 0, 0, 0, '\0' }
Eric Andersencb57d552001-06-28 07:25:16 +00008496};
8497
8498static int
8499ulimitcmd(argc, argv)
8500 int argc;
8501 char **argv;
8502{
Eric Andersen2870d962001-07-02 17:27:21 +00008503 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00008504 rlim_t val = 0;
8505 enum { SOFT = 0x1, HARD = 0x2 }
8506 how = SOFT | HARD;
Eric Andersen2870d962001-07-02 17:27:21 +00008507 const struct limits *l;
8508 int set, all = 0;
8509 int optc, what;
8510 struct rlimit limit;
Eric Andersencb57d552001-06-28 07:25:16 +00008511
8512 what = 'f';
8513 while ((optc = nextopt("HSatfdsmcnpl")) != '\0')
8514 switch (optc) {
8515 case 'H':
8516 how = HARD;
8517 break;
8518 case 'S':
8519 how = SOFT;
8520 break;
8521 case 'a':
8522 all = 1;
8523 break;
8524 default:
8525 what = optc;
8526 }
8527
8528 for (l = limits; l->name && l->option != what; l++)
8529 ;
8530 if (!l->name)
8531 error("internal error (%c)", what);
8532
8533 set = *argptr ? 1 : 0;
8534 if (set) {
8535 char *p = *argptr;
8536
8537 if (all || argptr[1])
8538 error("too many arguments");
8539 if (strcmp(p, "unlimited") == 0)
8540 val = RLIM_INFINITY;
8541 else {
8542 val = (rlim_t) 0;
8543
8544 while ((c = *p++) >= '0' && c <= '9')
8545 {
8546 val = (val * 10) + (long)(c - '0');
8547 if (val < (rlim_t) 0)
8548 break;
8549 }
8550 if (c)
8551 error("bad number");
8552 val *= l->factor;
8553 }
8554 }
8555 if (all) {
8556 for (l = limits; l->name; l++) {
8557 getrlimit(l->cmd, &limit);
8558 if (how & SOFT)
8559 val = limit.rlim_cur;
8560 else if (how & HARD)
8561 val = limit.rlim_max;
8562
8563 out1fmt("%-20s ", l->name);
8564 if (val == RLIM_INFINITY)
8565 out1fmt("unlimited\n");
8566 else
8567 {
8568 val /= l->factor;
Eric Andersencb57d552001-06-28 07:25:16 +00008569 out1fmt("%lld\n", (long long) val);
Eric Andersencb57d552001-06-28 07:25:16 +00008570 }
8571 }
8572 return 0;
8573 }
8574
8575 getrlimit(l->cmd, &limit);
8576 if (set) {
8577 if (how & HARD)
8578 limit.rlim_max = val;
8579 if (how & SOFT)
8580 limit.rlim_cur = val;
8581 if (setrlimit(l->cmd, &limit) < 0)
Eric Andersen2870d962001-07-02 17:27:21 +00008582 error("error setting limit (%m)");
Eric Andersencb57d552001-06-28 07:25:16 +00008583 } else {
8584 if (how & SOFT)
8585 val = limit.rlim_cur;
8586 else if (how & HARD)
8587 val = limit.rlim_max;
8588
8589 if (val == RLIM_INFINITY)
8590 out1fmt("unlimited\n");
8591 else
8592 {
8593 val /= l->factor;
Eric Andersencb57d552001-06-28 07:25:16 +00008594 out1fmt("%lld\n", (long long) val);
Eric Andersencb57d552001-06-28 07:25:16 +00008595 }
8596 }
8597 return 0;
8598}
Eric Andersencb57d552001-06-28 07:25:16 +00008599/*
8600 * prefix -- see if pfx is a prefix of string.
8601 */
8602
8603static int
8604prefix(pfx, string)
8605 char const *pfx;
8606 char const *string;
8607 {
8608 while (*pfx) {
8609 if (*pfx++ != *string++)
8610 return 0;
8611 }
8612 return 1;
8613}
8614
Eric Andersen2870d962001-07-02 17:27:21 +00008615/*
8616 * Return true if s is a string of digits, and save munber in intptr
8617 * nagative is bad
8618 */
8619
8620static int
8621is_number(const char *p, int *intptr)
8622{
8623 int ret = 0;
8624
8625 do {
8626 if (! is_digit(*p))
8627 return 0;
8628 ret *= 10;
8629 ret += digit_val(*p);
8630 p++;
8631 } while (*p != '\0');
8632
8633 *intptr = ret;
8634 return 1;
8635}
Eric Andersencb57d552001-06-28 07:25:16 +00008636
8637/*
8638 * Convert a string of digits to an integer, printing an error message on
8639 * failure.
8640 */
8641
8642static int
Eric Andersen2870d962001-07-02 17:27:21 +00008643number(const char *s)
8644{
8645 int i;
8646 if (! is_number(s, &i))
Eric Andersencb57d552001-06-28 07:25:16 +00008647 error("Illegal number: %s", s);
Eric Andersen2870d962001-07-02 17:27:21 +00008648 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00008649}
8650
Eric Andersencb57d552001-06-28 07:25:16 +00008651/*
8652 * Produce a possibly single quoted string suitable as input to the shell.
8653 * The return string is allocated on the stack.
8654 */
8655
8656static char *
8657single_quote(const char *s) {
8658 char *p;
8659
8660 STARTSTACKSTR(p);
8661
8662 do {
8663 char *q = p;
8664 size_t len1, len1p, len2, len2p;
8665
8666 len1 = strcspn(s, "'");
8667 len2 = strspn(s + len1, "'");
8668
8669 len1p = len1 ? len1 + 2 : len1;
8670 switch (len2) {
8671 case 0:
8672 len2p = 0;
8673 break;
8674 case 1:
8675 len2p = 2;
8676 break;
8677 default:
8678 len2p = len2 + 2;
8679 }
8680
8681 CHECKSTRSPACE(len1p + len2p + 1, p);
8682
8683 if (len1) {
8684 *p = '\'';
8685#ifdef _GNU_SOURCE
8686 q = mempcpy(p + 1, s, len1);
8687#else
8688 q = p + 1 + len1;
8689 memcpy(p + 1, s, len1);
8690#endif
8691 *q++ = '\'';
8692 s += len1;
8693 }
8694
8695 switch (len2) {
8696 case 0:
8697 break;
8698 case 1:
8699 *q++ = '\\';
8700 *q = '\'';
8701 s++;
8702 break;
8703 default:
8704 *q = '"';
8705#ifdef _GNU_SOURCE
8706 *(char *) mempcpy(q + 1, s, len2) = '"';
8707#else
8708 q += 1 + len2;
8709 memcpy(q + 1, s, len2);
8710 *q = '"';
8711#endif
8712 s += len2;
8713 }
8714
8715 STADJUST(len1p + len2p, p);
8716 } while (*s);
8717
8718 USTPUTC(0, p);
8719
8720 return grabstackstr(p);
8721}
8722
8723/*
8724 * Like strdup but works with the ash stack.
8725 */
8726
8727static char *
8728sstrdup(const char *p)
8729{
8730 size_t len = strlen(p) + 1;
8731 return memcpy(stalloc(len), p, len);
8732}
8733
Eric Andersencb57d552001-06-28 07:25:16 +00008734
8735/*
Eric Andersencb57d552001-06-28 07:25:16 +00008736 * This file was generated by the mknodes program.
8737 */
8738
Eric Andersencb57d552001-06-28 07:25:16 +00008739/*
8740 * Routine for dealing with parsed shell commands.
8741 */
8742
8743
Eric Andersen2870d962001-07-02 17:27:21 +00008744static int funcblocksize; /* size of structures in function */
8745static int funcstringsize; /* size of strings in node */
8746static pointer funcblock; /* block to allocate function from */
8747static char *funcstring; /* block to allocate strings from */
Eric Andersencb57d552001-06-28 07:25:16 +00008748
8749static const short nodesize[26] = {
8750 ALIGN(sizeof (struct nbinary)),
8751 ALIGN(sizeof (struct ncmd)),
8752 ALIGN(sizeof (struct npipe)),
8753 ALIGN(sizeof (struct nredir)),
8754 ALIGN(sizeof (struct nredir)),
8755 ALIGN(sizeof (struct nredir)),
8756 ALIGN(sizeof (struct nbinary)),
8757 ALIGN(sizeof (struct nbinary)),
8758 ALIGN(sizeof (struct nif)),
8759 ALIGN(sizeof (struct nbinary)),
8760 ALIGN(sizeof (struct nbinary)),
8761 ALIGN(sizeof (struct nfor)),
8762 ALIGN(sizeof (struct ncase)),
8763 ALIGN(sizeof (struct nclist)),
8764 ALIGN(sizeof (struct narg)),
8765 ALIGN(sizeof (struct narg)),
8766 ALIGN(sizeof (struct nfile)),
8767 ALIGN(sizeof (struct nfile)),
8768 ALIGN(sizeof (struct nfile)),
8769 ALIGN(sizeof (struct nfile)),
8770 ALIGN(sizeof (struct nfile)),
8771 ALIGN(sizeof (struct ndup)),
8772 ALIGN(sizeof (struct ndup)),
8773 ALIGN(sizeof (struct nhere)),
8774 ALIGN(sizeof (struct nhere)),
8775 ALIGN(sizeof (struct nnot)),
8776};
8777
8778
Eric Andersen2870d962001-07-02 17:27:21 +00008779static void calcsize (union node *);
8780static void sizenodelist (struct nodelist *);
8781static union node *copynode (union node *);
8782static struct nodelist *copynodelist (struct nodelist *);
8783static char *nodesavestr (char *);
Eric Andersencb57d552001-06-28 07:25:16 +00008784
8785
8786
8787/*
8788 * Make a copy of a parse tree.
8789 */
8790
Eric Andersen2870d962001-07-02 17:27:21 +00008791static union node *
8792copyfunc(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008793{
8794 if (n == NULL)
8795 return NULL;
8796 funcblocksize = 0;
8797 funcstringsize = 0;
8798 calcsize(n);
8799 funcblock = ckmalloc(funcblocksize + funcstringsize);
8800 funcstring = (char *) funcblock + funcblocksize;
8801 return copynode(n);
8802}
8803
8804
8805
8806static void
8807calcsize(n)
8808 union node *n;
8809{
8810 if (n == NULL)
8811 return;
8812 funcblocksize += nodesize[n->type];
8813 switch (n->type) {
8814 case NSEMI:
8815 case NAND:
8816 case NOR:
8817 case NWHILE:
8818 case NUNTIL:
8819 calcsize(n->nbinary.ch2);
8820 calcsize(n->nbinary.ch1);
8821 break;
8822 case NCMD:
8823 calcsize(n->ncmd.redirect);
8824 calcsize(n->ncmd.args);
8825 calcsize(n->ncmd.assign);
8826 break;
8827 case NPIPE:
8828 sizenodelist(n->npipe.cmdlist);
8829 break;
8830 case NREDIR:
8831 case NBACKGND:
8832 case NSUBSHELL:
8833 calcsize(n->nredir.redirect);
8834 calcsize(n->nredir.n);
8835 break;
8836 case NIF:
8837 calcsize(n->nif.elsepart);
8838 calcsize(n->nif.ifpart);
8839 calcsize(n->nif.test);
8840 break;
8841 case NFOR:
8842 funcstringsize += strlen(n->nfor.var) + 1;
8843 calcsize(n->nfor.body);
8844 calcsize(n->nfor.args);
8845 break;
8846 case NCASE:
8847 calcsize(n->ncase.cases);
8848 calcsize(n->ncase.expr);
8849 break;
8850 case NCLIST:
8851 calcsize(n->nclist.body);
8852 calcsize(n->nclist.pattern);
8853 calcsize(n->nclist.next);
8854 break;
8855 case NDEFUN:
8856 case NARG:
8857 sizenodelist(n->narg.backquote);
8858 funcstringsize += strlen(n->narg.text) + 1;
8859 calcsize(n->narg.next);
8860 break;
8861 case NTO:
8862 case NFROM:
8863 case NFROMTO:
8864 case NAPPEND:
8865 case NTOOV:
8866 calcsize(n->nfile.fname);
8867 calcsize(n->nfile.next);
8868 break;
8869 case NTOFD:
8870 case NFROMFD:
8871 calcsize(n->ndup.vname);
8872 calcsize(n->ndup.next);
8873 break;
8874 case NHERE:
8875 case NXHERE:
8876 calcsize(n->nhere.doc);
8877 calcsize(n->nhere.next);
8878 break;
8879 case NNOT:
8880 calcsize(n->nnot.com);
8881 break;
8882 };
8883}
8884
8885
8886
8887static void
8888sizenodelist(lp)
8889 struct nodelist *lp;
8890{
8891 while (lp) {
8892 funcblocksize += ALIGN(sizeof(struct nodelist));
8893 calcsize(lp->n);
8894 lp = lp->next;
8895 }
8896}
8897
8898
8899
8900static union node *
8901copynode(n)
8902 union node *n;
8903{
8904 union node *new;
8905
8906 if (n == NULL)
8907 return NULL;
8908 new = funcblock;
8909 funcblock = (char *) funcblock + nodesize[n->type];
8910 switch (n->type) {
8911 case NSEMI:
8912 case NAND:
8913 case NOR:
8914 case NWHILE:
8915 case NUNTIL:
8916 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8917 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8918 break;
8919 case NCMD:
8920 new->ncmd.redirect = copynode(n->ncmd.redirect);
8921 new->ncmd.args = copynode(n->ncmd.args);
8922 new->ncmd.assign = copynode(n->ncmd.assign);
8923 new->ncmd.backgnd = n->ncmd.backgnd;
8924 break;
8925 case NPIPE:
8926 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
8927 new->npipe.backgnd = n->npipe.backgnd;
8928 break;
8929 case NREDIR:
8930 case NBACKGND:
8931 case NSUBSHELL:
8932 new->nredir.redirect = copynode(n->nredir.redirect);
8933 new->nredir.n = copynode(n->nredir.n);
8934 break;
8935 case NIF:
8936 new->nif.elsepart = copynode(n->nif.elsepart);
8937 new->nif.ifpart = copynode(n->nif.ifpart);
8938 new->nif.test = copynode(n->nif.test);
8939 break;
8940 case NFOR:
8941 new->nfor.var = nodesavestr(n->nfor.var);
8942 new->nfor.body = copynode(n->nfor.body);
8943 new->nfor.args = copynode(n->nfor.args);
8944 break;
8945 case NCASE:
8946 new->ncase.cases = copynode(n->ncase.cases);
8947 new->ncase.expr = copynode(n->ncase.expr);
8948 break;
8949 case NCLIST:
8950 new->nclist.body = copynode(n->nclist.body);
8951 new->nclist.pattern = copynode(n->nclist.pattern);
8952 new->nclist.next = copynode(n->nclist.next);
8953 break;
8954 case NDEFUN:
8955 case NARG:
8956 new->narg.backquote = copynodelist(n->narg.backquote);
8957 new->narg.text = nodesavestr(n->narg.text);
8958 new->narg.next = copynode(n->narg.next);
8959 break;
8960 case NTO:
8961 case NFROM:
8962 case NFROMTO:
8963 case NAPPEND:
8964 case NTOOV:
8965 new->nfile.fname = copynode(n->nfile.fname);
8966 new->nfile.fd = n->nfile.fd;
8967 new->nfile.next = copynode(n->nfile.next);
8968 break;
8969 case NTOFD:
8970 case NFROMFD:
8971 new->ndup.vname = copynode(n->ndup.vname);
8972 new->ndup.dupfd = n->ndup.dupfd;
8973 new->ndup.fd = n->ndup.fd;
8974 new->ndup.next = copynode(n->ndup.next);
8975 break;
8976 case NHERE:
8977 case NXHERE:
8978 new->nhere.doc = copynode(n->nhere.doc);
8979 new->nhere.fd = n->nhere.fd;
8980 new->nhere.next = copynode(n->nhere.next);
8981 break;
8982 case NNOT:
8983 new->nnot.com = copynode(n->nnot.com);
8984 break;
8985 };
8986 new->type = n->type;
8987 return new;
8988}
8989
8990
8991static struct nodelist *
8992copynodelist(lp)
8993 struct nodelist *lp;
8994{
8995 struct nodelist *start;
8996 struct nodelist **lpp;
8997
8998 lpp = &start;
8999 while (lp) {
9000 *lpp = funcblock;
9001 funcblock = (char *) funcblock + ALIGN(sizeof(struct nodelist));
9002 (*lpp)->n = copynode(lp->n);
9003 lp = lp->next;
9004 lpp = &(*lpp)->next;
9005 }
9006 *lpp = NULL;
9007 return start;
9008}
9009
9010
9011
9012static char *
9013nodesavestr(s)
9014 char *s;
9015{
9016#ifdef _GNU_SOURCE
9017 char *rtn = funcstring;
9018
9019 funcstring = stpcpy(funcstring, s) + 1;
9020 return rtn;
9021#else
9022 register char *p = s;
9023 register char *q = funcstring;
9024 char *rtn = funcstring;
9025
9026 while ((*q++ = *p++) != '\0')
9027 continue;
9028 funcstring = q;
9029 return rtn;
9030#endif
9031}
9032
Eric Andersencb57d552001-06-28 07:25:16 +00009033#ifdef ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00009034static int getopts (char *, char *, char **, int *, int *);
Eric Andersencb57d552001-06-28 07:25:16 +00009035#endif
9036
9037
9038/*
9039 * Process the shell command line arguments.
9040 */
9041
9042static void
9043procargs(argc, argv)
9044 int argc;
9045 char **argv;
9046{
9047 int i;
9048
9049 argptr = argv;
9050 if (argc > 0)
9051 argptr++;
9052 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00009053 optent_val(i) = 2;
Eric Andersencb57d552001-06-28 07:25:16 +00009054 options(1);
9055 if (*argptr == NULL && minusc == NULL)
9056 sflag = 1;
9057 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
9058 iflag = 1;
9059 if (mflag == 2)
9060 mflag = iflag;
9061 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00009062 if (optent_val(i) == 2)
9063 optent_val(i) = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009064 arg0 = argv[0];
9065 if (sflag == 0 && minusc == NULL) {
9066 commandname = argv[0];
9067 arg0 = *argptr++;
9068 setinputfile(arg0, 0);
9069 commandname = arg0;
9070 }
9071 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
9072 if (argptr && minusc && *argptr)
Eric Andersen2870d962001-07-02 17:27:21 +00009073 arg0 = *argptr++;
Eric Andersencb57d552001-06-28 07:25:16 +00009074
9075 shellparam.p = argptr;
9076 shellparam.optind = 1;
9077 shellparam.optoff = -1;
9078 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
9079 while (*argptr) {
9080 shellparam.nparam++;
9081 argptr++;
9082 }
9083 optschanged();
9084}
9085
9086
Eric Andersencb57d552001-06-28 07:25:16 +00009087
9088/*
9089 * Process shell options. The global variable argptr contains a pointer
9090 * to the argument list; we advance it past the options.
9091 */
9092
9093static void
9094options(cmdline)
9095 int cmdline;
9096{
9097 char *p;
9098 int val;
9099 int c;
9100
9101 if (cmdline)
9102 minusc = NULL;
9103 while ((p = *argptr) != NULL) {
9104 argptr++;
9105 if ((c = *p++) == '-') {
9106 val = 1;
Eric Andersen2870d962001-07-02 17:27:21 +00009107 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
9108 if (!cmdline) {
9109 /* "-" means turn off -x and -v */
9110 if (p[0] == '\0')
9111 xflag = vflag = 0;
9112 /* "--" means reset params */
9113 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00009114 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +00009115 }
9116 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +00009117 }
9118 } else if (c == '+') {
9119 val = 0;
9120 } else {
9121 argptr--;
9122 break;
9123 }
9124 while ((c = *p++) != '\0') {
9125 if (c == 'c' && cmdline) {
9126 char *q;
Eric Andersen2870d962001-07-02 17:27:21 +00009127#ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */
Eric Andersencb57d552001-06-28 07:25:16 +00009128 if (*p == '\0')
9129#endif
9130 q = *argptr++;
9131 if (q == NULL || minusc != NULL)
9132 error("Bad -c option");
9133 minusc = q;
9134#ifdef NOHACK
9135 break;
9136#endif
9137 } else if (c == 'o') {
9138 minus_o(*argptr, val);
9139 if (*argptr)
9140 argptr++;
9141 } else {
9142 setoption(c, val);
9143 }
9144 }
9145 }
9146}
9147
9148static void
9149minus_o(name, val)
9150 char *name;
9151 int val;
9152{
9153 int i;
9154
9155 if (name == NULL) {
9156 out1str("Current option settings\n");
9157 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00009158 out1fmt("%-16s%s\n", optent_name(optlist[i]),
9159 optent_val(i) ? "on" : "off");
Eric Andersencb57d552001-06-28 07:25:16 +00009160 } else {
9161 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00009162 if (equal(name, optent_name(optlist[i]))) {
9163 setoption(optent_letter(optlist[i]), val);
Eric Andersencb57d552001-06-28 07:25:16 +00009164 return;
9165 }
9166 error("Illegal option -o %s", name);
9167 }
9168}
9169
9170
9171static void
Eric Andersen2870d962001-07-02 17:27:21 +00009172setoption(int flag, int val)
9173{
Eric Andersencb57d552001-06-28 07:25:16 +00009174 int i;
9175
9176 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00009177 if (optent_letter(optlist[i]) == flag) {
9178 optent_val(i) = val;
Eric Andersencb57d552001-06-28 07:25:16 +00009179 if (val) {
9180 /* #%$ hack for ksh semantics */
9181 if (flag == 'V')
9182 Eflag = 0;
9183 else if (flag == 'E')
9184 Vflag = 0;
9185 }
9186 return;
9187 }
9188 error("Illegal option -%c", flag);
9189 /* NOTREACHED */
9190}
9191
9192
9193
Eric Andersencb57d552001-06-28 07:25:16 +00009194/*
9195 * Set the shell parameters.
9196 */
9197
9198static void
Eric Andersen2870d962001-07-02 17:27:21 +00009199setparam(char **argv)
9200{
Eric Andersencb57d552001-06-28 07:25:16 +00009201 char **newparam;
9202 char **ap;
9203 int nparam;
9204
9205 for (nparam = 0 ; argv[nparam] ; nparam++);
9206 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
9207 while (*argv) {
9208 *ap++ = savestr(*argv++);
9209 }
9210 *ap = NULL;
9211 freeparam(&shellparam);
9212 shellparam.malloc = 1;
9213 shellparam.nparam = nparam;
9214 shellparam.p = newparam;
9215 shellparam.optind = 1;
9216 shellparam.optoff = -1;
9217}
9218
9219
9220/*
9221 * Free the list of positional parameters.
9222 */
9223
9224static void
Eric Andersen2870d962001-07-02 17:27:21 +00009225freeparam(volatile struct shparam *param)
9226{
Eric Andersencb57d552001-06-28 07:25:16 +00009227 char **ap;
9228
9229 if (param->malloc) {
9230 for (ap = param->p ; *ap ; ap++)
9231 ckfree(*ap);
9232 ckfree(param->p);
9233 }
9234}
9235
9236
9237
9238/*
9239 * The shift builtin command.
9240 */
9241
9242static int
9243shiftcmd(argc, argv)
9244 int argc;
9245 char **argv;
9246{
9247 int n;
9248 char **ap1, **ap2;
9249
9250 n = 1;
9251 if (argc > 1)
9252 n = number(argv[1]);
9253 if (n > shellparam.nparam)
9254 error("can't shift that many");
9255 INTOFF;
9256 shellparam.nparam -= n;
9257 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
9258 if (shellparam.malloc)
9259 ckfree(*ap1);
9260 }
9261 ap2 = shellparam.p;
9262 while ((*ap2++ = *ap1++) != NULL);
9263 shellparam.optind = 1;
9264 shellparam.optoff = -1;
9265 INTON;
9266 return 0;
9267}
9268
9269
9270
9271/*
9272 * The set command builtin.
9273 */
9274
9275static int
9276setcmd(argc, argv)
9277 int argc;
9278 char **argv;
9279{
9280 if (argc == 1)
9281 return showvarscmd(argc, argv);
9282 INTOFF;
9283 options(0);
9284 optschanged();
9285 if (*argptr != NULL) {
9286 setparam(argptr);
9287 }
9288 INTON;
9289 return 0;
9290}
9291
9292
9293static void
Eric Andersen2870d962001-07-02 17:27:21 +00009294getoptsreset(const char *value)
Eric Andersencb57d552001-06-28 07:25:16 +00009295{
9296 shellparam.optind = number(value);
9297 shellparam.optoff = -1;
9298}
9299
Eric Andersen2870d962001-07-02 17:27:21 +00009300#ifdef BB_LOCALE_SUPPORT
9301static void change_lc_all(const char *value)
9302{
9303 if(value != 0 && *value != 0)
9304 setlocale(LC_ALL, value);
9305}
9306
9307static void change_lc_ctype(const char *value)
9308{
9309 if(value != 0 && *value != 0)
9310 setlocale(LC_CTYPE, value);
9311}
9312
9313#endif
9314
Eric Andersencb57d552001-06-28 07:25:16 +00009315#ifdef ASH_GETOPTS
9316/*
9317 * The getopts builtin. Shellparam.optnext points to the next argument
9318 * to be processed. Shellparam.optptr points to the next character to
9319 * be processed in the current argument. If shellparam.optnext is NULL,
9320 * then it's the first time getopts has been called.
9321 */
9322
9323static int
9324getoptscmd(argc, argv)
9325 int argc;
9326 char **argv;
9327{
9328 char **optbase;
9329
9330 if (argc < 3)
9331 error("Usage: getopts optstring var [arg]");
9332 else if (argc == 3) {
9333 optbase = shellparam.p;
9334 if (shellparam.optind > shellparam.nparam + 1) {
9335 shellparam.optind = 1;
9336 shellparam.optoff = -1;
9337 }
9338 }
9339 else {
9340 optbase = &argv[3];
9341 if (shellparam.optind > argc - 2) {
9342 shellparam.optind = 1;
9343 shellparam.optoff = -1;
9344 }
9345 }
9346
9347 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9348 &shellparam.optoff);
9349}
9350
9351/*
9352 * Safe version of setvar, returns 1 on success 0 on failure.
9353 */
9354
9355static int
9356setvarsafe(name, val, flags)
9357 const char *name, *val;
9358 int flags;
9359{
9360 struct jmploc jmploc;
9361 struct jmploc *volatile savehandler = handler;
9362 int err = 0;
9363#ifdef __GNUC__
9364 (void) &err;
9365#endif
9366
9367 if (setjmp(jmploc.loc))
9368 err = 1;
9369 else {
9370 handler = &jmploc;
9371 setvar(name, val, flags);
9372 }
9373 handler = savehandler;
9374 return err;
9375}
9376
9377static int
9378getopts(optstr, optvar, optfirst, myoptind, optoff)
9379 char *optstr;
9380 char *optvar;
9381 char **optfirst;
9382 int *myoptind;
9383 int *optoff;
9384{
9385 char *p, *q;
9386 char c = '?';
9387 int done = 0;
9388 int err = 0;
9389 char s[10];
9390 char **optnext = optfirst + *myoptind - 1;
9391
9392 if (*myoptind <= 1 || *optoff < 0 || !(*(optnext - 1)) ||
9393 strlen(*(optnext - 1)) < *optoff)
9394 p = NULL;
9395 else
9396 p = *(optnext - 1) + *optoff;
9397 if (p == NULL || *p == '\0') {
9398 /* Current word is done, advance */
9399 if (optnext == NULL)
9400 return 1;
9401 p = *optnext;
9402 if (p == NULL || *p != '-' || *++p == '\0') {
9403atend:
9404 *myoptind = optnext - optfirst + 1;
9405 p = NULL;
9406 done = 1;
9407 goto out;
9408 }
9409 optnext++;
Eric Andersen2870d962001-07-02 17:27:21 +00009410 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009411 goto atend;
9412 }
9413
9414 c = *p++;
9415 for (q = optstr; *q != c; ) {
9416 if (*q == '\0') {
9417 if (optstr[0] == ':') {
9418 s[0] = c;
9419 s[1] = '\0';
9420 err |= setvarsafe("OPTARG", s, 0);
9421 }
9422 else {
Eric Andersen3102ac42001-07-06 04:26:23 +00009423 out2fmt("Illegal option -%c\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009424 (void) unsetvar("OPTARG");
9425 }
9426 c = '?';
9427 goto bad;
9428 }
9429 if (*++q == ':')
9430 q++;
9431 }
9432
9433 if (*++q == ':') {
9434 if (*p == '\0' && (p = *optnext) == NULL) {
9435 if (optstr[0] == ':') {
9436 s[0] = c;
9437 s[1] = '\0';
9438 err |= setvarsafe("OPTARG", s, 0);
9439 c = ':';
9440 }
9441 else {
Eric Andersen3102ac42001-07-06 04:26:23 +00009442 out2fmt("No arg for -%c option\n", c);
Eric Andersencb57d552001-06-28 07:25:16 +00009443 (void) unsetvar("OPTARG");
9444 c = '?';
9445 }
9446 goto bad;
9447 }
9448
9449 if (p == *optnext)
9450 optnext++;
9451 setvarsafe("OPTARG", p, 0);
9452 p = NULL;
9453 }
9454 else
9455 setvarsafe("OPTARG", "", 0);
9456 *myoptind = optnext - optfirst + 1;
9457 goto out;
9458
9459bad:
9460 *myoptind = 1;
9461 p = NULL;
9462out:
9463 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersen3102ac42001-07-06 04:26:23 +00009464 snprintf(s, sizeof(s), "%d", *myoptind);
Eric Andersencb57d552001-06-28 07:25:16 +00009465 err |= setvarsafe("OPTIND", s, VNOFUNC);
9466 s[0] = c;
9467 s[1] = '\0';
9468 err |= setvarsafe(optvar, s, 0);
9469 if (err) {
9470 *myoptind = 1;
9471 *optoff = -1;
9472 flushall();
9473 exraise(EXERROR);
9474 }
9475 return done;
9476}
Eric Andersen2870d962001-07-02 17:27:21 +00009477#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009478
9479/*
9480 * XXX - should get rid of. have all builtins use getopt(3). the
9481 * library getopt must have the BSD extension static variable "optreset"
9482 * otherwise it can't be used within the shell safely.
9483 *
9484 * Standard option processing (a la getopt) for builtin routines. The
9485 * only argument that is passed to nextopt is the option string; the
9486 * other arguments are unnecessary. It return the character, or '\0' on
9487 * end of input.
9488 */
9489
9490static int
9491nextopt(optstring)
9492 const char *optstring;
9493 {
9494 char *p;
9495 const char *q;
9496 char c;
9497
9498 if ((p = optptr) == NULL || *p == '\0') {
9499 p = *argptr;
9500 if (p == NULL || *p != '-' || *++p == '\0')
9501 return '\0';
9502 argptr++;
Eric Andersen2870d962001-07-02 17:27:21 +00009503 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009504 return '\0';
9505 }
9506 c = *p++;
9507 for (q = optstring ; *q != c ; ) {
9508 if (*q == '\0')
9509 error("Illegal option -%c", c);
9510 if (*++q == ':')
9511 q++;
9512 }
9513 if (*++q == ':') {
9514 if (*p == '\0' && (p = *argptr++) == NULL)
9515 error("No arg for -%c option", c);
9516 optionarg = p;
9517 p = NULL;
9518 }
9519 optptr = p;
9520 return c;
9521}
9522
Eric Andersencb57d552001-06-28 07:25:16 +00009523static void
9524flushall() {
Eric Andersencb57d552001-06-28 07:25:16 +00009525 INTOFF;
Eric Andersen3102ac42001-07-06 04:26:23 +00009526 fflush(stdout);
Eric Andersencb57d552001-06-28 07:25:16 +00009527 INTON;
Eric Andersencb57d552001-06-28 07:25:16 +00009528}
9529
9530
9531static void
Eric Andersen3102ac42001-07-06 04:26:23 +00009532out2fmt(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00009533{
9534 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00009535 va_start(ap, fmt);
Eric Andersen3102ac42001-07-06 04:26:23 +00009536 vfprintf(stderr, fmt, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009537 va_end(ap);
9538}
9539
9540
9541static void
Eric Andersencb57d552001-06-28 07:25:16 +00009542out1fmt(const char *fmt, ...)
Eric Andersencb57d552001-06-28 07:25:16 +00009543{
9544 va_list ap;
Eric Andersencb57d552001-06-28 07:25:16 +00009545 va_start(ap, fmt);
Eric Andersen3102ac42001-07-06 04:26:23 +00009546 vfprintf(stdout, fmt, ap);
Eric Andersencb57d552001-06-28 07:25:16 +00009547 va_end(ap);
9548}
9549
Eric Andersencb57d552001-06-28 07:25:16 +00009550/*
9551 * Version of write which resumes after a signal is caught.
9552 */
9553
9554static int
Eric Andersen2870d962001-07-02 17:27:21 +00009555xwrite(int fd, const char *buf, int nbytes)
9556{
Eric Andersencb57d552001-06-28 07:25:16 +00009557 int ntry;
9558 int i;
9559 int n;
9560
9561 n = nbytes;
9562 ntry = 0;
9563 for (;;) {
9564 i = write(fd, buf, n);
9565 if (i > 0) {
9566 if ((n -= i) <= 0)
9567 return nbytes;
9568 buf += i;
9569 ntry = 0;
9570 } else if (i == 0) {
9571 if (++ntry > 10)
9572 return nbytes - n;
9573 } else if (errno != EINTR) {
9574 return -1;
9575 }
9576 }
9577}
9578
9579
Eric Andersencb57d552001-06-28 07:25:16 +00009580/*
9581 * Shell command parser.
9582 */
9583
9584#define EOFMARKLEN 79
9585
9586
9587
9588struct heredoc {
Eric Andersen2870d962001-07-02 17:27:21 +00009589 struct heredoc *next; /* next here document in list */
9590 union node *here; /* redirection node */
9591 char *eofmark; /* string indicating end of input */
9592 int striptabs; /* if set, strip leading tabs */
Eric Andersencb57d552001-06-28 07:25:16 +00009593};
9594
Eric Andersen2870d962001-07-02 17:27:21 +00009595static struct heredoc *heredoclist; /* list of here documents to read */
9596static int parsebackquote; /* nonzero if we are inside backquotes */
9597static int doprompt; /* if set, prompt the user */
9598static int needprompt; /* true if interactive and at start of line */
9599static int lasttoken; /* last token read */
Eric Andersencb57d552001-06-28 07:25:16 +00009600
Eric Andersen2870d962001-07-02 17:27:21 +00009601static char *wordtext; /* text of last word returned by readtoken */
Eric Andersencb57d552001-06-28 07:25:16 +00009602
Eric Andersen2870d962001-07-02 17:27:21 +00009603static struct nodelist *backquotelist;
9604static union node *redirnode;
Eric Andersencb57d552001-06-28 07:25:16 +00009605struct heredoc *heredoc;
Eric Andersen2870d962001-07-02 17:27:21 +00009606static int quoteflag; /* set if (part of) last token was quoted */
9607static int startlinno; /* line # where last token started */
Eric Andersencb57d552001-06-28 07:25:16 +00009608
9609
Eric Andersen2870d962001-07-02 17:27:21 +00009610static union node *list (int);
9611static union node *andor (void);
9612static union node *pipeline (void);
9613static union node *command (void);
9614static union node *simplecmd (void);
9615static void parsefname (void);
9616static void parseheredoc (void);
9617static int peektoken (void);
9618static int readtoken (void);
9619static int xxreadtoken (void);
9620static int readtoken1 (int, char const *, char *, int);
9621static int noexpand (char *);
9622static void synexpect (int) __attribute__((noreturn));
9623static void synerror (const char *) __attribute__((noreturn));
9624static void setprompt (int);
Eric Andersencb57d552001-06-28 07:25:16 +00009625
9626
9627/*
9628 * Read and parse a command. Returns NEOF on end of file. (NULL is a
9629 * valid parse tree indicating a blank line.)
9630 */
9631
Eric Andersen2870d962001-07-02 17:27:21 +00009632static union node *
Eric Andersencb57d552001-06-28 07:25:16 +00009633parsecmd(int interact)
9634{
9635 int t;
9636
9637 tokpushback = 0;
9638 doprompt = interact;
9639 if (doprompt)
9640 setprompt(1);
9641 else
9642 setprompt(0);
9643 needprompt = 0;
9644 t = readtoken();
9645 if (t == TEOF)
9646 return NEOF;
9647 if (t == TNL)
9648 return NULL;
9649 tokpushback++;
9650 return list(1);
9651}
9652
9653
9654static union node *
9655list(nlflag)
9656 int nlflag;
9657{
9658 union node *n1, *n2, *n3;
9659 int tok;
9660
9661 checkkwd = 2;
9662 if (nlflag == 0 && tokendlist[peektoken()])
9663 return NULL;
9664 n1 = NULL;
9665 for (;;) {
9666 n2 = andor();
9667 tok = readtoken();
9668 if (tok == TBACKGND) {
9669 if (n2->type == NCMD || n2->type == NPIPE) {
9670 n2->ncmd.backgnd = 1;
9671 } else if (n2->type == NREDIR) {
9672 n2->type = NBACKGND;
9673 } else {
9674 n3 = (union node *)stalloc(sizeof (struct nredir));
9675 n3->type = NBACKGND;
9676 n3->nredir.n = n2;
9677 n3->nredir.redirect = NULL;
9678 n2 = n3;
9679 }
9680 }
9681 if (n1 == NULL) {
9682 n1 = n2;
9683 }
9684 else {
9685 n3 = (union node *)stalloc(sizeof (struct nbinary));
9686 n3->type = NSEMI;
9687 n3->nbinary.ch1 = n1;
9688 n3->nbinary.ch2 = n2;
9689 n1 = n3;
9690 }
9691 switch (tok) {
9692 case TBACKGND:
9693 case TSEMI:
9694 tok = readtoken();
9695 /* fall through */
9696 case TNL:
9697 if (tok == TNL) {
9698 parseheredoc();
9699 if (nlflag)
9700 return n1;
9701 } else {
9702 tokpushback++;
9703 }
9704 checkkwd = 2;
9705 if (tokendlist[peektoken()])
9706 return n1;
9707 break;
9708 case TEOF:
9709 if (heredoclist)
9710 parseheredoc();
9711 else
Eric Andersen2870d962001-07-02 17:27:21 +00009712 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +00009713 return n1;
9714 default:
9715 if (nlflag)
9716 synexpect(-1);
9717 tokpushback++;
9718 return n1;
9719 }
9720 }
9721}
9722
9723
9724
9725static union node *
9726andor() {
9727 union node *n1, *n2, *n3;
9728 int t;
9729
9730 checkkwd = 1;
9731 n1 = pipeline();
9732 for (;;) {
9733 if ((t = readtoken()) == TAND) {
9734 t = NAND;
9735 } else if (t == TOR) {
9736 t = NOR;
9737 } else {
9738 tokpushback++;
9739 return n1;
9740 }
9741 checkkwd = 2;
9742 n2 = pipeline();
9743 n3 = (union node *)stalloc(sizeof (struct nbinary));
9744 n3->type = t;
9745 n3->nbinary.ch1 = n1;
9746 n3->nbinary.ch2 = n2;
9747 n1 = n3;
9748 }
9749}
9750
9751
9752
9753static union node *
9754pipeline() {
9755 union node *n1, *n2, *pipenode;
9756 struct nodelist *lp, *prev;
9757 int negate;
9758
9759 negate = 0;
9760 TRACE(("pipeline: entered\n"));
9761 if (readtoken() == TNOT) {
9762 negate = !negate;
9763 checkkwd = 1;
9764 } else
9765 tokpushback++;
9766 n1 = command();
9767 if (readtoken() == TPIPE) {
9768 pipenode = (union node *)stalloc(sizeof (struct npipe));
9769 pipenode->type = NPIPE;
9770 pipenode->npipe.backgnd = 0;
9771 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9772 pipenode->npipe.cmdlist = lp;
9773 lp->n = n1;
9774 do {
9775 prev = lp;
9776 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
9777 checkkwd = 2;
9778 lp->n = command();
9779 prev->next = lp;
9780 } while (readtoken() == TPIPE);
9781 lp->next = NULL;
9782 n1 = pipenode;
9783 }
9784 tokpushback++;
9785 if (negate) {
9786 n2 = (union node *)stalloc(sizeof (struct nnot));
9787 n2->type = NNOT;
9788 n2->nnot.com = n1;
9789 return n2;
9790 } else
9791 return n1;
9792}
9793
9794
9795
9796static union node *
9797command() {
9798 union node *n1, *n2;
9799 union node *ap, **app;
9800 union node *cp, **cpp;
9801 union node *redir, **rpp;
9802 int t;
9803
9804 redir = NULL;
9805 n1 = NULL;
9806 rpp = &redir;
9807
9808 switch (readtoken()) {
9809 case TIF:
9810 n1 = (union node *)stalloc(sizeof (struct nif));
9811 n1->type = NIF;
9812 n1->nif.test = list(0);
9813 if (readtoken() != TTHEN)
9814 synexpect(TTHEN);
9815 n1->nif.ifpart = list(0);
9816 n2 = n1;
9817 while (readtoken() == TELIF) {
9818 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
9819 n2 = n2->nif.elsepart;
9820 n2->type = NIF;
9821 n2->nif.test = list(0);
9822 if (readtoken() != TTHEN)
9823 synexpect(TTHEN);
9824 n2->nif.ifpart = list(0);
9825 }
9826 if (lasttoken == TELSE)
9827 n2->nif.elsepart = list(0);
9828 else {
9829 n2->nif.elsepart = NULL;
9830 tokpushback++;
9831 }
9832 if (readtoken() != TFI)
9833 synexpect(TFI);
9834 checkkwd = 1;
9835 break;
9836 case TWHILE:
9837 case TUNTIL: {
9838 int got;
9839 n1 = (union node *)stalloc(sizeof (struct nbinary));
9840 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
9841 n1->nbinary.ch1 = list(0);
9842 if ((got=readtoken()) != TDO) {
9843TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
9844 synexpect(TDO);
9845 }
9846 n1->nbinary.ch2 = list(0);
9847 if (readtoken() != TDONE)
9848 synexpect(TDONE);
9849 checkkwd = 1;
9850 break;
9851 }
9852 case TFOR:
9853 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
9854 synerror("Bad for loop variable");
9855 n1 = (union node *)stalloc(sizeof (struct nfor));
9856 n1->type = NFOR;
9857 n1->nfor.var = wordtext;
9858 checkkwd = 1;
9859 if (readtoken() == TIN) {
9860 app = &ap;
9861 while (readtoken() == TWORD) {
9862 n2 = (union node *)stalloc(sizeof (struct narg));
9863 n2->type = NARG;
9864 n2->narg.text = wordtext;
9865 n2->narg.backquote = backquotelist;
9866 *app = n2;
9867 app = &n2->narg.next;
9868 }
9869 *app = NULL;
9870 n1->nfor.args = ap;
9871 if (lasttoken != TNL && lasttoken != TSEMI)
9872 synexpect(-1);
9873 } else {
9874 static char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
9875 '@', '=', '\0'};
9876 n2 = (union node *)stalloc(sizeof (struct narg));
9877 n2->type = NARG;
9878 n2->narg.text = argvars;
9879 n2->narg.backquote = NULL;
9880 n2->narg.next = NULL;
9881 n1->nfor.args = n2;
9882 /*
9883 * Newline or semicolon here is optional (but note
9884 * that the original Bourne shell only allowed NL).
9885 */
9886 if (lasttoken != TNL && lasttoken != TSEMI)
9887 tokpushback++;
9888 }
9889 checkkwd = 2;
9890 if (readtoken() != TDO)
9891 synexpect(TDO);
9892 n1->nfor.body = list(0);
9893 if (readtoken() != TDONE)
9894 synexpect(TDONE);
9895 checkkwd = 1;
9896 break;
9897 case TCASE:
9898 n1 = (union node *)stalloc(sizeof (struct ncase));
9899 n1->type = NCASE;
9900 if (readtoken() != TWORD)
9901 synexpect(TWORD);
9902 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
9903 n2->type = NARG;
9904 n2->narg.text = wordtext;
9905 n2->narg.backquote = backquotelist;
9906 n2->narg.next = NULL;
9907 do {
9908 checkkwd = 1;
9909 } while (readtoken() == TNL);
9910 if (lasttoken != TIN)
9911 synerror("expecting \"in\"");
9912 cpp = &n1->ncase.cases;
9913 checkkwd = 2, readtoken();
9914 do {
9915 if (lasttoken == TLP)
9916 readtoken();
9917 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
9918 cp->type = NCLIST;
9919 app = &cp->nclist.pattern;
9920 for (;;) {
9921 *app = ap = (union node *)stalloc(sizeof (struct narg));
9922 ap->type = NARG;
9923 ap->narg.text = wordtext;
9924 ap->narg.backquote = backquotelist;
9925 if (checkkwd = 2, readtoken() != TPIPE)
9926 break;
9927 app = &ap->narg.next;
9928 readtoken();
9929 }
9930 ap->narg.next = NULL;
9931 if (lasttoken != TRP)
9932 synexpect(TRP);
9933 cp->nclist.body = list(0);
9934
9935 checkkwd = 2;
9936 if ((t = readtoken()) != TESAC) {
9937 if (t != TENDCASE)
9938 synexpect(TENDCASE);
9939 else
9940 checkkwd = 2, readtoken();
9941 }
9942 cpp = &cp->nclist.next;
9943 } while(lasttoken != TESAC);
9944 *cpp = NULL;
9945 checkkwd = 1;
9946 break;
9947 case TLP:
9948 n1 = (union node *)stalloc(sizeof (struct nredir));
9949 n1->type = NSUBSHELL;
9950 n1->nredir.n = list(0);
9951 n1->nredir.redirect = NULL;
9952 if (readtoken() != TRP)
9953 synexpect(TRP);
9954 checkkwd = 1;
9955 break;
9956 case TBEGIN:
9957 n1 = list(0);
9958 if (readtoken() != TEND)
9959 synexpect(TEND);
9960 checkkwd = 1;
9961 break;
9962 /* Handle an empty command like other simple commands. */
9963 case TSEMI:
9964 case TAND:
9965 case TOR:
9966 case TNL:
9967 case TEOF:
9968 case TRP:
9969 case TBACKGND:
9970 /*
9971 * An empty command before a ; doesn't make much sense, and
9972 * should certainly be disallowed in the case of `if ;'.
9973 */
9974 if (!redir)
9975 synexpect(-1);
9976 case TWORD:
9977 case TREDIR:
9978 tokpushback++;
9979 n1 = simplecmd();
9980 return n1;
9981 default:
9982 synexpect(-1);
9983 /* NOTREACHED */
9984 }
9985
9986 /* Now check for redirection which may follow command */
9987 while (readtoken() == TREDIR) {
9988 *rpp = n2 = redirnode;
9989 rpp = &n2->nfile.next;
9990 parsefname();
9991 }
9992 tokpushback++;
9993 *rpp = NULL;
9994 if (redir) {
9995 if (n1->type != NSUBSHELL) {
9996 n2 = (union node *)stalloc(sizeof (struct nredir));
9997 n2->type = NREDIR;
9998 n2->nredir.n = n1;
9999 n1 = n2;
10000 }
10001 n1->nredir.redirect = redir;
10002 }
10003
10004 return n1;
10005}
10006
10007
10008static union node *
10009simplecmd() {
10010 union node *args, **app;
10011 union node *n = NULL;
10012 union node *vars, **vpp;
10013 union node **rpp, *redir;
10014
10015 args = NULL;
10016 app = &args;
10017 vars = NULL;
10018 vpp = &vars;
10019 redir = NULL;
10020 rpp = &redir;
10021
Eric Andersen2870d962001-07-02 17:27:21 +000010022#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010023 checkalias = 2;
Eric Andersen2870d962001-07-02 17:27:21 +000010024#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010025 for (;;) {
10026 switch (readtoken()) {
10027 case TWORD:
10028 case TASSIGN:
10029 n = (union node *)stalloc(sizeof (struct narg));
10030 n->type = NARG;
10031 n->narg.text = wordtext;
10032 n->narg.backquote = backquotelist;
10033 if (lasttoken == TWORD) {
10034 *app = n;
10035 app = &n->narg.next;
10036 } else {
10037 *vpp = n;
10038 vpp = &n->narg.next;
10039 }
10040 break;
10041 case TREDIR:
10042 *rpp = n = redirnode;
10043 rpp = &n->nfile.next;
Eric Andersen2870d962001-07-02 17:27:21 +000010044 parsefname(); /* read name of redirection file */
Eric Andersencb57d552001-06-28 07:25:16 +000010045 break;
10046 case TLP:
10047 if (
10048 args && app == &args->narg.next &&
10049 !vars && !redir
10050 ) {
10051 /* We have a function */
10052 if (readtoken() != TRP)
10053 synexpect(TRP);
Eric Andersencb57d552001-06-28 07:25:16 +000010054 n->type = NDEFUN;
10055 checkkwd = 2;
10056 n->narg.next = command();
10057 return n;
10058 }
10059 /* fall through */
10060 default:
10061 tokpushback++;
10062 goto out;
10063 }
10064 }
10065out:
10066 *app = NULL;
10067 *vpp = NULL;
10068 *rpp = NULL;
10069 n = (union node *)stalloc(sizeof (struct ncmd));
10070 n->type = NCMD;
10071 n->ncmd.backgnd = 0;
10072 n->ncmd.args = args;
10073 n->ncmd.assign = vars;
10074 n->ncmd.redirect = redir;
10075 return n;
10076}
10077
10078static union node *
Eric Andersen2870d962001-07-02 17:27:21 +000010079makename(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000010080 union node *n;
10081
10082 n = (union node *)stalloc(sizeof (struct narg));
10083 n->type = NARG;
10084 n->narg.next = NULL;
10085 n->narg.text = wordtext;
10086 n->narg.backquote = backquotelist;
10087 return n;
10088}
10089
10090static void fixredir(union node *n, const char *text, int err)
Eric Andersen2870d962001-07-02 17:27:21 +000010091{
Eric Andersencb57d552001-06-28 07:25:16 +000010092 TRACE(("Fix redir %s %d\n", text, err));
10093 if (!err)
10094 n->ndup.vname = NULL;
10095
10096 if (is_digit(text[0]) && text[1] == '\0')
10097 n->ndup.dupfd = digit_val(text[0]);
10098 else if (text[0] == '-' && text[1] == '\0')
10099 n->ndup.dupfd = -1;
10100 else {
10101
10102 if (err)
10103 synerror("Bad fd number");
10104 else
10105 n->ndup.vname = makename();
10106 }
10107}
10108
10109
10110static void
Eric Andersen2870d962001-07-02 17:27:21 +000010111parsefname(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000010112 union node *n = redirnode;
10113
10114 if (readtoken() != TWORD)
10115 synexpect(-1);
10116 if (n->type == NHERE) {
10117 struct heredoc *here = heredoc;
10118 struct heredoc *p;
10119 int i;
10120
10121 if (quoteflag == 0)
10122 n->type = NXHERE;
10123 TRACE(("Here document %d\n", n->type));
10124 if (here->striptabs) {
10125 while (*wordtext == '\t')
10126 wordtext++;
10127 }
10128 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
10129 synerror("Illegal eof marker for << redirection");
10130 rmescapes(wordtext);
10131 here->eofmark = wordtext;
10132 here->next = NULL;
10133 if (heredoclist == NULL)
10134 heredoclist = here;
10135 else {
10136 for (p = heredoclist ; p->next ; p = p->next);
10137 p->next = here;
10138 }
10139 } else if (n->type == NTOFD || n->type == NFROMFD) {
10140 fixredir(n, wordtext, 0);
10141 } else {
10142 n->nfile.fname = makename();
10143 }
10144}
10145
10146
10147/*
10148 * Input any here documents.
10149 */
10150
10151static void
10152parseheredoc() {
10153 struct heredoc *here;
10154 union node *n;
10155
10156 while (heredoclist) {
10157 here = heredoclist;
10158 heredoclist = here->next;
10159 if (needprompt) {
10160 setprompt(2);
10161 needprompt = 0;
10162 }
10163 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
10164 here->eofmark, here->striptabs);
10165 n = (union node *)stalloc(sizeof (struct narg));
10166 n->narg.type = NARG;
10167 n->narg.next = NULL;
10168 n->narg.text = wordtext;
10169 n->narg.backquote = backquotelist;
10170 here->here->nhere.doc = n;
10171 }
10172}
10173
10174static int
10175peektoken() {
10176 int t;
10177
10178 t = readtoken();
10179 tokpushback++;
10180 return (t);
10181}
10182
10183static int
10184readtoken() {
10185 int t;
Eric Andersen2870d962001-07-02 17:27:21 +000010186#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010187 int savecheckkwd = checkkwd;
10188 int savecheckalias = checkalias;
10189 struct alias *ap;
Eric Andersen2870d962001-07-02 17:27:21 +000010190#endif
10191
Eric Andersencb57d552001-06-28 07:25:16 +000010192#ifdef DEBUG
10193 int alreadyseen = tokpushback;
10194#endif
10195
Eric Andersen2870d962001-07-02 17:27:21 +000010196#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010197top:
Eric Andersen2870d962001-07-02 17:27:21 +000010198#endif
10199
Eric Andersencb57d552001-06-28 07:25:16 +000010200 t = xxreadtoken();
Eric Andersen2870d962001-07-02 17:27:21 +000010201
10202#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010203 checkalias = savecheckalias;
Eric Andersen2870d962001-07-02 17:27:21 +000010204#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010205
10206 if (checkkwd) {
10207 /*
10208 * eat newlines
10209 */
10210 if (checkkwd == 2) {
10211 checkkwd = 0;
10212 while (t == TNL) {
10213 parseheredoc();
10214 t = xxreadtoken();
10215 }
10216 }
10217 checkkwd = 0;
10218 /*
10219 * check for keywords
10220 */
10221 if (t == TWORD && !quoteflag)
10222 {
10223 const char *const *pp;
10224
10225 if ((pp = findkwd(wordtext))) {
10226 lasttoken = t = pp - parsekwd + KWDOFFSET;
10227 TRACE(("keyword %s recognized\n", tokname[t]));
10228 goto out;
10229 }
10230 }
10231 }
10232
Eric Andersen2870d962001-07-02 17:27:21 +000010233#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010234 if (t != TWORD) {
10235 if (t != TREDIR) {
10236 checkalias = 0;
10237 }
10238 } else if (checkalias == 2 && isassignment(wordtext)) {
10239 lasttoken = t = TASSIGN;
10240 } else if (checkalias) {
10241 if (!quoteflag && (ap = lookupalias(wordtext, 1)) != NULL) {
10242 if (*ap->val) {
10243 pushstring(ap->val, strlen(ap->val), ap);
10244 }
10245 checkkwd = savecheckkwd;
10246 goto top;
10247 }
10248 checkalias = 0;
10249 }
Eric Andersen2870d962001-07-02 17:27:21 +000010250#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010251out:
10252#ifdef DEBUG
10253 if (!alreadyseen)
10254 TRACE(("token %s %s\n", tokname[t], t == TWORD || t == TASSIGN ? wordtext : ""));
10255 else
10256 TRACE(("reread token %s %s\n", tokname[t], t == TWORD || t == TASSIGN ? wordtext : ""));
10257#endif
10258 return (t);
10259}
10260
10261
10262/*
10263 * Read the next input token.
10264 * If the token is a word, we set backquotelist to the list of cmds in
Eric Andersen2870d962001-07-02 17:27:21 +000010265 * backquotes. We set quoteflag to true if any part of the word was
10266 * quoted.
Eric Andersencb57d552001-06-28 07:25:16 +000010267 * If the token is TREDIR, then we set redirnode to a structure containing
Eric Andersen2870d962001-07-02 17:27:21 +000010268 * the redirection.
Eric Andersencb57d552001-06-28 07:25:16 +000010269 * In all cases, the variable startlinno is set to the number of the line
Eric Andersen2870d962001-07-02 17:27:21 +000010270 * on which the token starts.
Eric Andersencb57d552001-06-28 07:25:16 +000010271 *
10272 * [Change comment: here documents and internal procedures]
10273 * [Readtoken shouldn't have any arguments. Perhaps we should make the
10274 * word parsing code into a separate routine. In this case, readtoken
10275 * doesn't need to have any internal procedures, but parseword does.
10276 * We could also make parseoperator in essence the main routine, and
10277 * have parseword (readtoken1?) handle both words and redirection.]
10278 */
10279
Eric Andersen2870d962001-07-02 17:27:21 +000010280#define RETURN(token) return lasttoken = token
Eric Andersencb57d552001-06-28 07:25:16 +000010281
10282static int
10283xxreadtoken() {
10284 int c;
10285
10286 if (tokpushback) {
10287 tokpushback = 0;
10288 return lasttoken;
10289 }
10290 if (needprompt) {
10291 setprompt(2);
10292 needprompt = 0;
10293 }
10294 startlinno = plinno;
Eric Andersen2870d962001-07-02 17:27:21 +000010295 for (;;) { /* until token or start of word found */
Eric Andersencb57d552001-06-28 07:25:16 +000010296 c = pgetc_macro();
10297 switch (c) {
10298 case ' ': case '\t':
Eric Andersen3102ac42001-07-06 04:26:23 +000010299#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010300 case PEOA:
Eric Andersen3102ac42001-07-06 04:26:23 +000010301#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010302 continue;
10303 case '#':
10304 while ((c = pgetc()) != '\n' && c != PEOF);
10305 pungetc();
10306 continue;
10307 case '\\':
10308 if (pgetc() == '\n') {
10309 startlinno = ++plinno;
10310 if (doprompt)
10311 setprompt(2);
10312 else
10313 setprompt(0);
10314 continue;
10315 }
10316 pungetc();
10317 goto breakloop;
10318 case '\n':
10319 plinno++;
10320 needprompt = doprompt;
10321 RETURN(TNL);
10322 case PEOF:
10323 RETURN(TEOF);
10324 case '&':
10325 if (pgetc() == '&')
10326 RETURN(TAND);
10327 pungetc();
10328 RETURN(TBACKGND);
10329 case '|':
10330 if (pgetc() == '|')
10331 RETURN(TOR);
10332 pungetc();
10333 RETURN(TPIPE);
10334 case ';':
10335 if (pgetc() == ';')
10336 RETURN(TENDCASE);
10337 pungetc();
10338 RETURN(TSEMI);
10339 case '(':
10340 RETURN(TLP);
10341 case ')':
10342 RETURN(TRP);
10343 default:
10344 goto breakloop;
10345 }
10346 }
10347breakloop:
10348 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10349#undef RETURN
10350}
10351
10352
10353
10354/*
10355 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10356 * is not NULL, read a here document. In the latter case, eofmark is the
10357 * word which marks the end of the document and striptabs is true if
10358 * leading tabs should be stripped from the document. The argument firstc
10359 * is the first character of the input token or document.
10360 *
10361 * Because C does not have internal subroutines, I have simulated them
10362 * using goto's to implement the subroutine linkage. The following macros
10363 * will run code that appears at the end of readtoken1.
10364 */
10365
Eric Andersen2870d962001-07-02 17:27:21 +000010366#define CHECKEND() {goto checkend; checkend_return:;}
10367#define PARSEREDIR() {goto parseredir; parseredir_return:;}
10368#define PARSESUB() {goto parsesub; parsesub_return:;}
10369#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10370#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10371#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000010372
10373static int
10374readtoken1(firstc, syntax, eofmark, striptabs)
10375 int firstc;
10376 char const *syntax;
10377 char *eofmark;
10378 int striptabs;
10379 {
10380 int c = firstc;
10381 char *out;
10382 int len;
10383 char line[EOFMARKLEN + 1];
10384 struct nodelist *bqlist;
10385 int quotef;
10386 int dblquote;
Eric Andersen2870d962001-07-02 17:27:21 +000010387 int varnest; /* levels of variables expansion */
10388 int arinest; /* levels of arithmetic expansion */
10389 int parenlevel; /* levels of parens in arithmetic */
10390 int dqvarnest; /* levels of variables expansion within double quotes */
Eric Andersencb57d552001-06-28 07:25:16 +000010391 int oldstyle;
Eric Andersen2870d962001-07-02 17:27:21 +000010392 char const *prevsyntax; /* syntax before arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010393#if __GNUC__
10394 /* Avoid longjmp clobbering */
10395 (void) &out;
10396 (void) &quotef;
10397 (void) &dblquote;
10398 (void) &varnest;
10399 (void) &arinest;
10400 (void) &parenlevel;
10401 (void) &dqvarnest;
10402 (void) &oldstyle;
10403 (void) &prevsyntax;
10404 (void) &syntax;
10405#endif
10406
10407 startlinno = plinno;
10408 dblquote = 0;
10409 if (syntax == DQSYNTAX)
10410 dblquote = 1;
10411 quotef = 0;
10412 bqlist = NULL;
10413 varnest = 0;
10414 arinest = 0;
10415 parenlevel = 0;
10416 dqvarnest = 0;
10417
10418 STARTSTACKSTR(out);
Eric Andersen2870d962001-07-02 17:27:21 +000010419 loop: { /* for each line, until end of word */
10420 CHECKEND(); /* set c to PEOF if at end of here document */
10421 for (;;) { /* until end of line or end of word */
10422 CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */
Eric Andersencb57d552001-06-28 07:25:16 +000010423 switch(syntax[c]) {
Eric Andersen2870d962001-07-02 17:27:21 +000010424 case CNL: /* '\n' */
Eric Andersencb57d552001-06-28 07:25:16 +000010425 if (syntax == BASESYNTAX)
Eric Andersen2870d962001-07-02 17:27:21 +000010426 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010427 USTPUTC(c, out);
10428 plinno++;
10429 if (doprompt)
10430 setprompt(2);
10431 else
10432 setprompt(0);
10433 c = pgetc();
Eric Andersen2870d962001-07-02 17:27:21 +000010434 goto loop; /* continue outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010435 case CWORD:
10436 USTPUTC(c, out);
10437 break;
10438 case CCTL:
10439 if ((eofmark == NULL || dblquote) &&
10440 dqvarnest == 0)
10441 USTPUTC(CTLESC, out);
10442 USTPUTC(c, out);
10443 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010444 case CBACK: /* backslash */
Eric Andersencb57d552001-06-28 07:25:16 +000010445 c = pgetc2();
10446 if (c == PEOF) {
10447 USTPUTC('\\', out);
10448 pungetc();
10449 } else if (c == '\n') {
10450 if (doprompt)
10451 setprompt(2);
10452 else
10453 setprompt(0);
10454 } else {
10455 if (dblquote && c != '\\' && c != '`' && c != '$'
10456 && (c != '"' || eofmark != NULL))
10457 USTPUTC('\\', out);
10458 if (SQSYNTAX[c] == CCTL)
10459 USTPUTC(CTLESC, out);
10460 else if (eofmark == NULL)
10461 USTPUTC(CTLQUOTEMARK, out);
10462 USTPUTC(c, out);
10463 quotef++;
10464 }
10465 break;
10466 case CSQUOTE:
10467 if (eofmark == NULL)
10468 USTPUTC(CTLQUOTEMARK, out);
10469 syntax = SQSYNTAX;
10470 break;
10471 case CDQUOTE:
10472 if (eofmark == NULL)
10473 USTPUTC(CTLQUOTEMARK, out);
10474 syntax = DQSYNTAX;
10475 dblquote = 1;
10476 break;
10477 case CENDQUOTE:
10478 if (eofmark != NULL && arinest == 0 &&
10479 varnest == 0) {
10480 USTPUTC(c, out);
10481 } else {
10482 if (arinest) {
10483 syntax = ARISYNTAX;
10484 dblquote = 0;
10485 } else if (eofmark == NULL &&
10486 dqvarnest == 0) {
10487 syntax = BASESYNTAX;
10488 dblquote = 0;
10489 }
10490 quotef++;
10491 }
10492 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010493 case CVAR: /* '$' */
10494 PARSESUB(); /* parse substitution */
Eric Andersencb57d552001-06-28 07:25:16 +000010495 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010496 case CENDVAR: /* '}' */
Eric Andersencb57d552001-06-28 07:25:16 +000010497 if (varnest > 0) {
10498 varnest--;
10499 if (dqvarnest > 0) {
10500 dqvarnest--;
10501 }
10502 USTPUTC(CTLENDVAR, out);
10503 } else {
10504 USTPUTC(c, out);
10505 }
10506 break;
10507#ifdef ASH_MATH_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +000010508 case CLP: /* '(' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010509 parenlevel++;
10510 USTPUTC(c, out);
10511 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010512 case CRP: /* ')' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010513 if (parenlevel > 0) {
10514 USTPUTC(c, out);
10515 --parenlevel;
10516 } else {
10517 if (pgetc() == ')') {
10518 if (--arinest == 0) {
10519 USTPUTC(CTLENDARI, out);
10520 syntax = prevsyntax;
10521 if (syntax == DQSYNTAX)
10522 dblquote = 1;
10523 else
10524 dblquote = 0;
10525 } else
10526 USTPUTC(')', out);
10527 } else {
10528 /*
10529 * unbalanced parens
10530 * (don't 2nd guess - no error)
10531 */
10532 pungetc();
10533 USTPUTC(')', out);
10534 }
10535 }
10536 break;
10537#endif
Eric Andersen2870d962001-07-02 17:27:21 +000010538 case CBQUOTE: /* '`' */
Eric Andersencb57d552001-06-28 07:25:16 +000010539 PARSEBACKQOLD();
10540 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010541 case CENDFILE:
10542 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010543 case CIGN:
10544 break;
10545 default:
10546 if (varnest == 0)
Eric Andersen2870d962001-07-02 17:27:21 +000010547 goto endword; /* exit outer loop */
Eric Andersen3102ac42001-07-06 04:26:23 +000010548#ifdef ASH_ALIAS
10549 if (c != PEOA)
10550#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010551 USTPUTC(c, out);
Eric Andersen3102ac42001-07-06 04:26:23 +000010552
Eric Andersencb57d552001-06-28 07:25:16 +000010553 }
10554 c = pgetc_macro();
10555 }
10556 }
10557endword:
10558 if (syntax == ARISYNTAX)
10559 synerror("Missing '))'");
10560 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10561 synerror("Unterminated quoted string");
10562 if (varnest != 0) {
10563 startlinno = plinno;
10564 synerror("Missing '}'");
10565 }
10566 USTPUTC('\0', out);
10567 len = out - stackblock();
10568 out = stackblock();
10569 if (eofmark == NULL) {
10570 if ((c == '>' || c == '<')
10571 && quotef == 0
10572 && len <= 2
10573 && (*out == '\0' || is_digit(*out))) {
10574 PARSEREDIR();
10575 return lasttoken = TREDIR;
10576 } else {
10577 pungetc();
10578 }
10579 }
10580 quoteflag = quotef;
10581 backquotelist = bqlist;
10582 grabstackblock(len);
10583 wordtext = out;
10584 return lasttoken = TWORD;
10585/* end of readtoken routine */
10586
10587
10588
10589/*
10590 * Check to see whether we are at the end of the here document. When this
10591 * is called, c is set to the first character of the next input line. If
10592 * we are at the end of the here document, this routine sets the c to PEOF.
10593 */
10594
10595checkend: {
10596 if (eofmark) {
Eric Andersen2870d962001-07-02 17:27:21 +000010597#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010598 if (c == PEOA) {
10599 c = pgetc2();
10600 }
Eric Andersen2870d962001-07-02 17:27:21 +000010601#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010602 if (striptabs) {
10603 while (c == '\t') {
10604 c = pgetc2();
10605 }
10606 }
10607 if (c == *eofmark) {
10608 if (pfgets(line, sizeof line) != NULL) {
10609 char *p, *q;
10610
10611 p = line;
10612 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
10613 if (*p == '\n' && *q == '\0') {
10614 c = PEOF;
10615 plinno++;
10616 needprompt = doprompt;
10617 } else {
10618 pushstring(line, strlen(line), NULL);
10619 }
10620 }
10621 }
10622 }
10623 goto checkend_return;
10624}
10625
10626
10627/*
10628 * Parse a redirection operator. The variable "out" points to a string
10629 * specifying the fd to be redirected. The variable "c" contains the
10630 * first character of the redirection operator.
10631 */
10632
10633parseredir: {
10634 char fd = *out;
10635 union node *np;
10636
10637 np = (union node *)stalloc(sizeof (struct nfile));
10638 if (c == '>') {
10639 np->nfile.fd = 1;
10640 c = pgetc();
10641 if (c == '>')
10642 np->type = NAPPEND;
10643 else if (c == '&')
10644 np->type = NTOFD;
10645 else if (c == '|')
10646 np->type = NTOOV;
10647 else {
10648 np->type = NTO;
10649 pungetc();
10650 }
Eric Andersen2870d962001-07-02 17:27:21 +000010651 } else { /* c == '<' */
Eric Andersencb57d552001-06-28 07:25:16 +000010652 np->nfile.fd = 0;
10653 switch (c = pgetc()) {
10654 case '<':
10655 if (sizeof (struct nfile) != sizeof (struct nhere)) {
10656 np = (union node *)stalloc(sizeof (struct nhere));
10657 np->nfile.fd = 0;
10658 }
10659 np->type = NHERE;
10660 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
10661 heredoc->here = np;
10662 if ((c = pgetc()) == '-') {
10663 heredoc->striptabs = 1;
10664 } else {
10665 heredoc->striptabs = 0;
10666 pungetc();
10667 }
10668 break;
10669
10670 case '&':
10671 np->type = NFROMFD;
10672 break;
10673
10674 case '>':
10675 np->type = NFROMTO;
10676 break;
10677
10678 default:
10679 np->type = NFROM;
10680 pungetc();
10681 break;
10682 }
10683 }
10684 if (fd != '\0')
10685 np->nfile.fd = digit_val(fd);
10686 redirnode = np;
10687 goto parseredir_return;
10688}
10689
10690
10691/*
10692 * Parse a substitution. At this point, we have read the dollar sign
10693 * and nothing else.
10694 */
10695
10696parsesub: {
10697 int subtype;
10698 int typeloc;
10699 int flags;
10700 char *p;
10701 static const char types[] = "}-+?=";
10702
10703 c = pgetc();
10704 if (
10705 c <= PEOA ||
10706 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
10707 ) {
10708 USTPUTC('$', out);
10709 pungetc();
Eric Andersen2870d962001-07-02 17:27:21 +000010710 } else if (c == '(') { /* $(command) or $((arith)) */
Eric Andersencb57d552001-06-28 07:25:16 +000010711 if (pgetc() == '(') {
10712 PARSEARITH();
10713 } else {
10714 pungetc();
10715 PARSEBACKQNEW();
10716 }
10717 } else {
10718 USTPUTC(CTLVAR, out);
10719 typeloc = out - stackblock();
10720 USTPUTC(VSNORMAL, out);
10721 subtype = VSNORMAL;
10722 if (c == '{') {
10723 c = pgetc();
10724 if (c == '#') {
10725 if ((c = pgetc()) == '}')
10726 c = '#';
10727 else
10728 subtype = VSLENGTH;
10729 }
10730 else
10731 subtype = 0;
10732 }
10733 if (c > PEOA && is_name(c)) {
10734 do {
10735 STPUTC(c, out);
10736 c = pgetc();
10737 } while (c > PEOA && is_in_name(c));
10738 } else if (is_digit(c)) {
10739 do {
10740 USTPUTC(c, out);
10741 c = pgetc();
10742 } while (is_digit(c));
10743 }
10744 else if (is_special(c)) {
10745 USTPUTC(c, out);
10746 c = pgetc();
10747 }
10748 else
Eric Andersen2870d962001-07-02 17:27:21 +000010749badsub: synerror("Bad substitution");
Eric Andersencb57d552001-06-28 07:25:16 +000010750
10751 STPUTC('=', out);
10752 flags = 0;
10753 if (subtype == 0) {
10754 switch (c) {
10755 case ':':
10756 flags = VSNUL;
10757 c = pgetc();
10758 /*FALLTHROUGH*/
10759 default:
10760 p = strchr(types, c);
10761 if (p == NULL)
10762 goto badsub;
10763 subtype = p - types + VSNORMAL;
10764 break;
10765 case '%':
10766 case '#':
10767 {
10768 int cc = c;
10769 subtype = c == '#' ? VSTRIMLEFT :
10770 VSTRIMRIGHT;
10771 c = pgetc();
10772 if (c == cc)
10773 subtype++;
10774 else
10775 pungetc();
10776 break;
10777 }
10778 }
10779 } else {
10780 pungetc();
10781 }
10782 if (dblquote || arinest)
10783 flags |= VSQUOTE;
10784 *(stackblock() + typeloc) = subtype | flags;
10785 if (subtype != VSNORMAL) {
10786 varnest++;
10787 if (dblquote) {
10788 dqvarnest++;
10789 }
10790 }
10791 }
10792 goto parsesub_return;
10793}
10794
10795
10796/*
10797 * Called to parse command substitutions. Newstyle is set if the command
10798 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
10799 * list of commands (passed by reference), and savelen is the number of
10800 * characters on the top of the stack which must be preserved.
10801 */
10802
10803parsebackq: {
10804 struct nodelist **nlpp;
10805 int savepbq;
10806 union node *n;
10807 char *volatile str;
10808 struct jmploc jmploc;
10809 struct jmploc *volatile savehandler;
10810 int savelen;
10811 int saveprompt;
10812#ifdef __GNUC__
10813 (void) &saveprompt;
10814#endif
10815
10816 savepbq = parsebackquote;
10817 if (setjmp(jmploc.loc)) {
10818 if (str)
10819 ckfree(str);
10820 parsebackquote = 0;
10821 handler = savehandler;
10822 longjmp(handler->loc, 1);
10823 }
10824 INTOFF;
10825 str = NULL;
10826 savelen = out - stackblock();
10827 if (savelen > 0) {
10828 str = ckmalloc(savelen);
10829 memcpy(str, stackblock(), savelen);
10830 }
10831 savehandler = handler;
10832 handler = &jmploc;
10833 INTON;
Eric Andersen2870d962001-07-02 17:27:21 +000010834 if (oldstyle) {
10835 /* We must read until the closing backquote, giving special
10836 treatment to some slashes, and then push the string and
10837 reread it as input, interpreting it normally. */
10838 char *pout;
10839 int pc;
10840 int psavelen;
10841 char *pstr;
Eric Andersencb57d552001-06-28 07:25:16 +000010842
10843
Eric Andersen2870d962001-07-02 17:27:21 +000010844 STARTSTACKSTR(pout);
Eric Andersencb57d552001-06-28 07:25:16 +000010845 for (;;) {
10846 if (needprompt) {
10847 setprompt(2);
10848 needprompt = 0;
10849 }
10850 switch (pc = pgetc()) {
10851 case '`':
10852 goto done;
10853
10854 case '\\':
Eric Andersen2870d962001-07-02 17:27:21 +000010855 if ((pc = pgetc()) == '\n') {
Eric Andersencb57d552001-06-28 07:25:16 +000010856 plinno++;
10857 if (doprompt)
10858 setprompt(2);
10859 else
10860 setprompt(0);
10861 /*
10862 * If eating a newline, avoid putting
10863 * the newline into the new character
10864 * stream (via the STPUTC after the
10865 * switch).
10866 */
10867 continue;
10868 }
Eric Andersen2870d962001-07-02 17:27:21 +000010869 if (pc != '\\' && pc != '`' && pc != '$'
10870 && (!dblquote || pc != '"'))
10871 STPUTC('\\', pout);
Eric Andersencb57d552001-06-28 07:25:16 +000010872 if (pc > PEOA) {
10873 break;
10874 }
10875 /* fall through */
10876
10877 case PEOF:
Eric Andersen2870d962001-07-02 17:27:21 +000010878#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010879 case PEOA:
Eric Andersen2870d962001-07-02 17:27:21 +000010880#endif
10881 startlinno = plinno;
Eric Andersencb57d552001-06-28 07:25:16 +000010882 synerror("EOF in backquote substitution");
10883
10884 case '\n':
10885 plinno++;
10886 needprompt = doprompt;
10887 break;
10888
10889 default:
10890 break;
10891 }
10892 STPUTC(pc, pout);
Eric Andersen2870d962001-07-02 17:27:21 +000010893 }
Eric Andersencb57d552001-06-28 07:25:16 +000010894done:
Eric Andersen2870d962001-07-02 17:27:21 +000010895 STPUTC('\0', pout);
10896 psavelen = pout - stackblock();
10897 if (psavelen > 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000010898 pstr = grabstackstr(pout);
10899 setinputstring(pstr);
Eric Andersen2870d962001-07-02 17:27:21 +000010900 }
10901 }
Eric Andersencb57d552001-06-28 07:25:16 +000010902 nlpp = &bqlist;
10903 while (*nlpp)
10904 nlpp = &(*nlpp)->next;
10905 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10906 (*nlpp)->next = NULL;
10907 parsebackquote = oldstyle;
10908
10909 if (oldstyle) {
10910 saveprompt = doprompt;
10911 doprompt = 0;
10912 }
10913
10914 n = list(0);
10915
10916 if (oldstyle)
10917 doprompt = saveprompt;
10918 else {
10919 if (readtoken() != TRP)
10920 synexpect(TRP);
10921 }
10922
10923 (*nlpp)->n = n;
Eric Andersen2870d962001-07-02 17:27:21 +000010924 if (oldstyle) {
Eric Andersencb57d552001-06-28 07:25:16 +000010925 /*
10926 * Start reading from old file again, ignoring any pushed back
10927 * tokens left from the backquote parsing
10928 */
Eric Andersen2870d962001-07-02 17:27:21 +000010929 popfile();
Eric Andersencb57d552001-06-28 07:25:16 +000010930 tokpushback = 0;
10931 }
10932 while (stackblocksize() <= savelen)
10933 growstackblock();
10934 STARTSTACKSTR(out);
10935 if (str) {
10936 memcpy(out, str, savelen);
10937 STADJUST(savelen, out);
10938 INTOFF;
10939 ckfree(str);
10940 str = NULL;
10941 INTON;
10942 }
10943 parsebackquote = savepbq;
10944 handler = savehandler;
10945 if (arinest || dblquote)
10946 USTPUTC(CTLBACKQ | CTLQUOTE, out);
10947 else
10948 USTPUTC(CTLBACKQ, out);
10949 if (oldstyle)
10950 goto parsebackq_oldreturn;
10951 else
10952 goto parsebackq_newreturn;
10953}
10954
10955/*
10956 * Parse an arithmetic expansion (indicate start of one and set state)
10957 */
10958parsearith: {
10959
10960 if (++arinest == 1) {
10961 prevsyntax = syntax;
10962 syntax = ARISYNTAX;
10963 USTPUTC(CTLARI, out);
10964 if (dblquote)
10965 USTPUTC('"',out);
10966 else
10967 USTPUTC(' ',out);
10968 } else {
10969 /*
10970 * we collapse embedded arithmetic expansion to
10971 * parenthesis, which should be equivalent
10972 */
10973 USTPUTC('(', out);
10974 }
10975 goto parsearith_return;
10976}
10977
10978} /* end of readtoken */
10979
10980
Eric Andersencb57d552001-06-28 07:25:16 +000010981/*
10982 * Returns true if the text contains nothing to expand (no dollar signs
10983 * or backquotes).
10984 */
10985
10986static int
10987noexpand(text)
10988 char *text;
10989 {
10990 char *p;
10991 char c;
10992
10993 p = text;
10994 while ((c = *p++) != '\0') {
10995 if (c == CTLQUOTEMARK)
10996 continue;
10997 if (c == CTLESC)
10998 p++;
10999 else if (BASESYNTAX[(int)c] == CCTL)
11000 return 0;
11001 }
11002 return 1;
11003}
11004
11005
11006/*
11007 * Return true if the argument is a legal variable name (a letter or
11008 * underscore followed by zero or more letters, underscores, and digits).
11009 */
11010
11011static int
Eric Andersen2870d962001-07-02 17:27:21 +000011012goodname(const char *name)
11013{
11014 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +000011015
11016 p = name;
11017 if (! is_name(*p))
11018 return 0;
11019 while (*++p) {
11020 if (! is_in_name(*p))
11021 return 0;
11022 }
11023 return 1;
11024}
11025
11026
11027/*
11028 * Called when an unexpected token is read during the parse. The argument
11029 * is the token that is expected, or -1 if more than one type of token can
11030 * occur at this point.
11031 */
11032
11033static void
11034synexpect(token)
11035 int token;
11036{
11037 char msg[64];
11038
11039 if (token >= 0) {
Eric Andersen3102ac42001-07-06 04:26:23 +000011040 snprintf(msg, 64, "%s unexpected (expecting %s)",
Eric Andersencb57d552001-06-28 07:25:16 +000011041 tokname[lasttoken], tokname[token]);
11042 } else {
Eric Andersen3102ac42001-07-06 04:26:23 +000011043 snprintf(msg, 64, "%s unexpected", tokname[lasttoken]);
Eric Andersencb57d552001-06-28 07:25:16 +000011044 }
11045 synerror(msg);
11046 /* NOTREACHED */
11047}
11048
11049
11050static void
Eric Andersen2870d962001-07-02 17:27:21 +000011051synerror(const char *msg)
11052{
Eric Andersencb57d552001-06-28 07:25:16 +000011053 if (commandname)
Eric Andersen3102ac42001-07-06 04:26:23 +000011054 out2fmt("%s: %d: ", commandname, startlinno);
11055 out2fmt("Syntax error: %s\n", msg);
Eric Andersencb57d552001-06-28 07:25:16 +000011056 error((char *)NULL);
11057 /* NOTREACHED */
11058}
11059
Eric Andersencb57d552001-06-28 07:25:16 +000011060
11061/*
11062 * called by editline -- any expansions to the prompt
11063 * should be added here.
11064 */
Eric Andersen3102ac42001-07-06 04:26:23 +000011065static inline const char *
Eric Andersencb57d552001-06-28 07:25:16 +000011066getprompt(void *unused)
Eric Andersen2870d962001-07-02 17:27:21 +000011067{
Eric Andersencb57d552001-06-28 07:25:16 +000011068 switch (whichprompt) {
11069 case 0:
11070 return "";
11071 case 1:
11072 return ps1val();
11073 case 2:
11074 return ps2val();
11075 default:
11076 return "<internal prompt error>";
11077 }
11078}
11079
Eric Andersen2870d962001-07-02 17:27:21 +000011080static void
11081setprompt(int which)
11082{
11083 whichprompt = which;
11084 putprompt(getprompt(NULL));
Eric Andersencb57d552001-06-28 07:25:16 +000011085}
11086
Eric Andersencb57d552001-06-28 07:25:16 +000011087
Eric Andersencb57d552001-06-28 07:25:16 +000011088/*
11089 * Code for dealing with input/output redirection.
11090 */
11091
Eric Andersen2870d962001-07-02 17:27:21 +000011092#define EMPTY -2 /* marks an unused slot in redirtab */
Eric Andersencb57d552001-06-28 07:25:16 +000011093#ifndef PIPE_BUF
Eric Andersen2870d962001-07-02 17:27:21 +000011094# define PIPESIZE 4096 /* amount of buffering in a pipe */
Eric Andersencb57d552001-06-28 07:25:16 +000011095#else
11096# define PIPESIZE PIPE_BUF
11097#endif
11098
11099
Eric Andersencb57d552001-06-28 07:25:16 +000011100
11101/*
11102 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11103 * old file descriptors are stashed away so that the redirection can be
11104 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11105 * standard output, and the standard error if it becomes a duplicate of
Eric Andersen3102ac42001-07-06 04:26:23 +000011106 * stdout.
Eric Andersencb57d552001-06-28 07:25:16 +000011107 */
11108
11109static void
11110redirect(redir, flags)
11111 union node *redir;
11112 int flags;
11113 {
11114 union node *n;
11115 struct redirtab *sv = NULL;
11116 int i;
11117 int fd;
11118 int newfd;
11119 int try;
Eric Andersen2870d962001-07-02 17:27:21 +000011120 char memory[10]; /* file descriptors to write to memory */
Eric Andersencb57d552001-06-28 07:25:16 +000011121
11122 for (i = 10 ; --i >= 0 ; )
11123 memory[i] = 0;
11124 memory[1] = flags & REDIR_BACKQ;
11125 if (flags & REDIR_PUSH) {
11126 sv = ckmalloc(sizeof (struct redirtab));
11127 for (i = 0 ; i < 10 ; i++)
11128 sv->renamed[i] = EMPTY;
11129 sv->next = redirlist;
11130 redirlist = sv;
11131 }
11132 for (n = redir ; n ; n = n->nfile.next) {
11133 fd = n->nfile.fd;
11134 try = 0;
11135 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
11136 n->ndup.dupfd == fd)
11137 continue; /* redirect from/to same file descriptor */
11138
11139 INTOFF;
11140 newfd = openredirect(n);
Eric Andersen3102ac42001-07-06 04:26:23 +000011141 if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
Eric Andersencb57d552001-06-28 07:25:16 +000011142 if (newfd == fd) {
11143 try++;
11144 } else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
11145 switch (errno) {
11146 case EBADF:
11147 if (!try) {
11148 dupredirect(n, newfd, memory);
11149 try++;
11150 break;
11151 }
11152 /* FALLTHROUGH*/
11153 default:
11154 if (newfd >= 0) {
11155 close(newfd);
11156 }
11157 INTON;
Eric Andersen2870d962001-07-02 17:27:21 +000011158 error("%d: %m", fd);
Eric Andersencb57d552001-06-28 07:25:16 +000011159 /* NOTREACHED */
11160 }
11161 }
11162 if (!try) {
11163 close(fd);
11164 if (flags & REDIR_PUSH) {
11165 sv->renamed[fd] = i;
11166 }
Eric Andersencb57d552001-06-28 07:25:16 +000011167 }
11168 } else if (fd != newfd) {
11169 close(fd);
11170 }
Eric Andersen2870d962001-07-02 17:27:21 +000011171 if (fd == 0)
11172 fd0_redirected++;
Eric Andersencb57d552001-06-28 07:25:16 +000011173 if (!try)
11174 dupredirect(n, newfd, memory);
11175 INTON;
11176 }
Eric Andersencb57d552001-06-28 07:25:16 +000011177}
11178
11179
11180static int
11181openredirect(redir)
11182 union node *redir;
11183 {
11184 char *fname;
11185 int f;
11186
11187 switch (redir->nfile.type) {
11188 case NFROM:
11189 fname = redir->nfile.expfname;
11190 if ((f = open(fname, O_RDONLY)) < 0)
11191 goto eopen;
11192 break;
11193 case NFROMTO:
11194 fname = redir->nfile.expfname;
11195 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
11196 goto ecreate;
11197 break;
11198 case NTO:
11199 /* Take care of noclobber mode. */
11200 if (Cflag) {
11201 fname = redir->nfile.expfname;
11202 if ((f = noclobberopen(fname)) < 0)
11203 goto ecreate;
11204 break;
11205 }
11206 case NTOOV:
11207 fname = redir->nfile.expfname;
11208#ifdef O_CREAT
11209 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
11210 goto ecreate;
11211#else
11212 if ((f = creat(fname, 0666)) < 0)
11213 goto ecreate;
11214#endif
11215 break;
11216 case NAPPEND:
11217 fname = redir->nfile.expfname;
11218#ifdef O_APPEND
11219 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
11220 goto ecreate;
11221#else
11222 if ((f = open(fname, O_WRONLY)) < 0
11223 && (f = creat(fname, 0666)) < 0)
11224 goto ecreate;
11225 lseek(f, (off_t)0, 2);
11226#endif
11227 break;
11228 default:
11229#ifdef DEBUG
11230 abort();
11231#endif
11232 /* Fall through to eliminate warning. */
11233 case NTOFD:
11234 case NFROMFD:
11235 f = -1;
11236 break;
11237 case NHERE:
11238 case NXHERE:
11239 f = openhere(redir);
11240 break;
11241 }
11242
11243 return f;
11244ecreate:
11245 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
11246eopen:
11247 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11248}
11249
11250
11251static void
Eric Andersen2870d962001-07-02 17:27:21 +000011252dupredirect(union node *redir, int f, char memory[10])
11253{
Eric Andersencb57d552001-06-28 07:25:16 +000011254 int fd = redir->nfile.fd;
11255
11256 memory[fd] = 0;
11257 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Eric Andersen2870d962001-07-02 17:27:21 +000011258 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
Eric Andersencb57d552001-06-28 07:25:16 +000011259 if (memory[redir->ndup.dupfd])
11260 memory[fd] = 1;
11261 else
11262 dup_as_newfd(redir->ndup.dupfd, fd);
11263 }
11264 return;
11265 }
11266
11267 if (f != fd) {
11268 dup_as_newfd(f, fd);
11269 close(f);
11270 }
11271 return;
11272}
11273
11274
11275/*
11276 * Handle here documents. Normally we fork off a process to write the
11277 * data to a pipe. If the document is short, we can stuff the data in
11278 * the pipe without forking.
11279 */
11280
11281static int
11282openhere(redir)
11283 union node *redir;
11284 {
11285 int pip[2];
11286 int len = 0;
11287
11288 if (pipe(pip) < 0)
11289 error("Pipe call failed");
11290 if (redir->type == NHERE) {
11291 len = strlen(redir->nhere.doc->narg.text);
11292 if (len <= PIPESIZE) {
11293 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11294 goto out;
11295 }
11296 }
11297 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
11298 close(pip[0]);
11299 signal(SIGINT, SIG_IGN);
11300 signal(SIGQUIT, SIG_IGN);
11301 signal(SIGHUP, SIG_IGN);
11302#ifdef SIGTSTP
11303 signal(SIGTSTP, SIG_IGN);
11304#endif
11305 signal(SIGPIPE, SIG_DFL);
11306 if (redir->type == NHERE)
11307 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11308 else
11309 expandhere(redir->nhere.doc, pip[1]);
11310 _exit(0);
11311 }
11312out:
11313 close(pip[1]);
11314 return pip[0];
11315}
11316
11317
Eric Andersencb57d552001-06-28 07:25:16 +000011318/*
11319 * Undo the effects of the last redirection.
11320 */
11321
11322static void
Eric Andersen2870d962001-07-02 17:27:21 +000011323popredir(void)
11324{
Eric Andersencb57d552001-06-28 07:25:16 +000011325 struct redirtab *rp = redirlist;
11326 int i;
11327
11328 INTOFF;
11329 for (i = 0 ; i < 10 ; i++) {
11330 if (rp->renamed[i] != EMPTY) {
Eric Andersen2870d962001-07-02 17:27:21 +000011331 if (i == 0)
11332 fd0_redirected--;
Eric Andersencb57d552001-06-28 07:25:16 +000011333 close(i);
11334 if (rp->renamed[i] >= 0) {
11335 dup_as_newfd(rp->renamed[i], i);
11336 close(rp->renamed[i]);
11337 }
Eric Andersencb57d552001-06-28 07:25:16 +000011338 }
11339 }
11340 redirlist = rp->next;
11341 ckfree(rp);
11342 INTON;
11343}
11344
11345/*
Eric Andersencb57d552001-06-28 07:25:16 +000011346 * Discard all saved file descriptors.
11347 */
11348
11349static void
Eric Andersen2870d962001-07-02 17:27:21 +000011350clearredir(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000011351 struct redirtab *rp;
11352 int i;
11353
11354 for (rp = redirlist ; rp ; rp = rp->next) {
11355 for (i = 0 ; i < 10 ; i++) {
11356 if (rp->renamed[i] >= 0) {
11357 close(rp->renamed[i]);
Eric Andersencb57d552001-06-28 07:25:16 +000011358 }
11359 rp->renamed[i] = EMPTY;
11360 }
11361 }
Eric Andersencb57d552001-06-28 07:25:16 +000011362}
11363
11364
Eric Andersencb57d552001-06-28 07:25:16 +000011365/*
11366 * Copy a file descriptor to be >= to. Returns -1
11367 * if the source file descriptor is closed, EMPTY if there are no unused
11368 * file descriptors left.
11369 */
11370
11371static int
11372dup_as_newfd(from, to)
11373 int from;
11374 int to;
11375{
11376 int newfd;
11377
11378 newfd = fcntl(from, F_DUPFD, to);
11379 if (newfd < 0) {
11380 if (errno == EMFILE)
11381 return EMPTY;
11382 else
Eric Andersen2870d962001-07-02 17:27:21 +000011383 error("%d: %m", from);
Eric Andersencb57d552001-06-28 07:25:16 +000011384 }
11385 return newfd;
11386}
11387
11388/*
11389 * Open a file in noclobber mode.
11390 * The code was copied from bash.
11391 */
11392static int
Eric Andersen2870d962001-07-02 17:27:21 +000011393noclobberopen(const char *fname)
Eric Andersencb57d552001-06-28 07:25:16 +000011394{
11395 int r, fd;
11396 struct stat finfo, finfo2;
11397
11398 /*
11399 * If the file exists and is a regular file, return an error
11400 * immediately.
11401 */
11402 r = stat(fname, &finfo);
11403 if (r == 0 && S_ISREG(finfo.st_mode)) {
11404 errno = EEXIST;
11405 return -1;
11406 }
11407
11408 /*
11409 * If the file was not present (r != 0), make sure we open it
11410 * exclusively so that if it is created before we open it, our open
11411 * will fail. Make sure that we do not truncate an existing file.
11412 * Note that we don't turn on O_EXCL unless the stat failed -- if the
11413 * file was not a regular file, we leave O_EXCL off.
11414 */
11415 if (r != 0)
11416 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
11417 fd = open(fname, O_WRONLY|O_CREAT, 0666);
11418
11419 /* If the open failed, return the file descriptor right away. */
11420 if (fd < 0)
11421 return fd;
11422
11423 /*
11424 * OK, the open succeeded, but the file may have been changed from a
11425 * non-regular file to a regular file between the stat and the open.
11426 * We are assuming that the O_EXCL open handles the case where FILENAME
11427 * did not exist and is symlinked to an existing file between the stat
11428 * and open.
11429 */
11430
11431 /*
11432 * If we can open it and fstat the file descriptor, and neither check
11433 * revealed that it was a regular file, and the file has not been
11434 * replaced, return the file descriptor.
11435 */
11436 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
11437 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
Eric Andersen2870d962001-07-02 17:27:21 +000011438 return fd;
Eric Andersencb57d552001-06-28 07:25:16 +000011439
11440 /* The file has been replaced. badness. */
11441 close(fd);
11442 errno = EEXIST;
11443 return -1;
11444}
Eric Andersen2870d962001-07-02 17:27:21 +000011445/*#ifdef __weak_alias
Eric Andersencb57d552001-06-28 07:25:16 +000011446__weak_alias(getmode,_getmode)
11447__weak_alias(setmode,_setmode)
Eric Andersen2870d962001-07-02 17:27:21 +000011448#endif*/
Eric Andersencb57d552001-06-28 07:25:16 +000011449
11450#ifdef __GLIBC__
11451#define S_ISTXT __S_ISVTX
11452#endif
11453
Eric Andersen2870d962001-07-02 17:27:21 +000011454#define SET_LEN 6 /* initial # of bitcmd struct to malloc */
11455#define SET_LEN_INCR 4 /* # of bitcmd structs to add as needed */
Eric Andersencb57d552001-06-28 07:25:16 +000011456
11457typedef struct bitcmd {
Eric Andersen2870d962001-07-02 17:27:21 +000011458 char cmd;
11459 char cmd2;
11460 mode_t bits;
Eric Andersencb57d552001-06-28 07:25:16 +000011461} BITCMD;
11462
Eric Andersen2870d962001-07-02 17:27:21 +000011463#define CMD2_CLR 0x01
11464#define CMD2_SET 0x02
11465#define CMD2_GBITS 0x04
11466#define CMD2_OBITS 0x08
11467#define CMD2_UBITS 0x10
Eric Andersencb57d552001-06-28 07:25:16 +000011468
Eric Andersen2870d962001-07-02 17:27:21 +000011469static BITCMD *addcmd (BITCMD *, int, int, int, u_int);
11470static void compress_mode (BITCMD *);
Eric Andersencb57d552001-06-28 07:25:16 +000011471#ifdef SETMODE_DEBUG
Eric Andersen2870d962001-07-02 17:27:21 +000011472static void dumpmode (BITCMD *);
Eric Andersencb57d552001-06-28 07:25:16 +000011473#endif
11474
11475/*
11476 * Given the old mode and an array of bitcmd structures, apply the operations
11477 * described in the bitcmd structures to the old mode, and return the new mode.
11478 * Note that there is no '=' command; a strict assignment is just a '-' (clear
11479 * bits) followed by a '+' (set bits).
11480 */
Eric Andersen2870d962001-07-02 17:27:21 +000011481static mode_t
Eric Andersencb57d552001-06-28 07:25:16 +000011482getmode(bbox, omode)
11483 const void *bbox;
11484 mode_t omode;
11485{
11486 const BITCMD *set;
11487 mode_t clrval, newmode, value;
11488
11489 _DIAGASSERT(bbox != NULL);
11490
11491 set = (const BITCMD *)bbox;
11492 newmode = omode;
11493 for (value = 0;; set++)
11494 switch(set->cmd) {
11495 /*
11496 * When copying the user, group or other bits around, we "know"
11497 * where the bits are in the mode so that we can do shifts to
11498 * copy them around. If we don't use shifts, it gets real
11499 * grundgy with lots of single bit checks and bit sets.
11500 */
11501 case 'u':
11502 value = (newmode & S_IRWXU) >> 6;
11503 goto common;
11504
11505 case 'g':
11506 value = (newmode & S_IRWXG) >> 3;
11507 goto common;
11508
11509 case 'o':
11510 value = newmode & S_IRWXO;
Eric Andersen2870d962001-07-02 17:27:21 +000011511common: if (set->cmd2 & CMD2_CLR) {
Eric Andersencb57d552001-06-28 07:25:16 +000011512 clrval =
11513 (set->cmd2 & CMD2_SET) ? S_IRWXO : value;
11514 if (set->cmd2 & CMD2_UBITS)
11515 newmode &= ~((clrval<<6) & set->bits);
11516 if (set->cmd2 & CMD2_GBITS)
11517 newmode &= ~((clrval<<3) & set->bits);
11518 if (set->cmd2 & CMD2_OBITS)
11519 newmode &= ~(clrval & set->bits);
11520 }
11521 if (set->cmd2 & CMD2_SET) {
11522 if (set->cmd2 & CMD2_UBITS)
11523 newmode |= (value<<6) & set->bits;
11524 if (set->cmd2 & CMD2_GBITS)
11525 newmode |= (value<<3) & set->bits;
11526 if (set->cmd2 & CMD2_OBITS)
11527 newmode |= value & set->bits;
11528 }
11529 break;
11530
11531 case '+':
11532 newmode |= set->bits;
11533 break;
11534
11535 case '-':
11536 newmode &= ~set->bits;
11537 break;
11538
11539 case 'X':
11540 if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH))
11541 newmode |= set->bits;
11542 break;
11543
11544 case '\0':
11545 default:
11546#ifdef SETMODE_DEBUG
11547 (void)printf("getmode:%04o -> %04o\n", omode, newmode);
11548#endif
11549 return (newmode);
11550 }
11551}
11552
Eric Andersen2870d962001-07-02 17:27:21 +000011553#define ADDCMD(a, b, c, d) do { \
11554 if (set >= endset) { \
11555 BITCMD *newset; \
11556 setlen += SET_LEN_INCR; \
11557 newset = realloc(saveset, sizeof(BITCMD) * setlen); \
11558 if (newset == NULL) { \
11559 free(saveset); \
11560 return (NULL); \
11561 } \
11562 set = newset + (set - saveset); \
11563 saveset = newset; \
11564 endset = newset + (setlen - 2); \
11565 } \
11566 set = addcmd(set, (a), (b), (c), (d)); \
Eric Andersencb57d552001-06-28 07:25:16 +000011567} while (/*CONSTCOND*/0)
11568
Eric Andersen2870d962001-07-02 17:27:21 +000011569#define STANDARD_BITS (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
Eric Andersencb57d552001-06-28 07:25:16 +000011570
11571static void *
11572setmode(p)
11573 const char *p;
11574{
11575 int perm, who;
11576 char op, *ep;
11577 BITCMD *set, *saveset, *endset;
11578 sigset_t mysigset, sigoset;
11579 mode_t mask;
Eric Andersen2870d962001-07-02 17:27:21 +000011580 int equalopdone = 0; /* pacify gcc */
Eric Andersencb57d552001-06-28 07:25:16 +000011581 int permXbits, setlen;
11582
11583 if (!*p)
11584 return (NULL);
11585
11586 /*
11587 * Get a copy of the mask for the permissions that are mask relative.
11588 * Flip the bits, we want what's not set. Since it's possible that
11589 * the caller is opening files inside a signal handler, protect them
11590 * as best we can.
11591 */
11592 sigfillset(&mysigset);
11593 (void)sigprocmask(SIG_BLOCK, &mysigset, &sigoset);
11594 (void)umask(mask = umask(0));
11595 mask = ~mask;
11596 (void)sigprocmask(SIG_SETMASK, &sigoset, NULL);
11597
11598 setlen = SET_LEN + 2;
Eric Andersen2870d962001-07-02 17:27:21 +000011599
Eric Andersencb57d552001-06-28 07:25:16 +000011600 if ((set = malloc((u_int)(sizeof(BITCMD) * setlen))) == NULL)
11601 return (NULL);
11602 saveset = set;
11603 endset = set + (setlen - 2);
11604
11605 /*
11606 * If an absolute number, get it and return; disallow non-octal digits
11607 * or illegal bits.
11608 */
11609 if (isdigit((unsigned char)*p)) {
11610 perm = (mode_t)strtol(p, &ep, 8);
11611 if (*ep || perm & ~(STANDARD_BITS|S_ISTXT)) {
11612 free(saveset);
11613 return (NULL);
11614 }
11615 ADDCMD('=', (STANDARD_BITS|S_ISTXT), perm, mask);
11616 set->cmd = 0;
11617 return (saveset);
11618 }
11619
11620 /*
11621 * Build list of structures to set/clear/copy bits as described by
11622 * each clause of the symbolic mode.
11623 */
11624 for (;;) {
11625 /* First, find out which bits might be modified. */
11626 for (who = 0;; ++p) {
11627 switch (*p) {
11628 case 'a':
11629 who |= STANDARD_BITS;
11630 break;
11631 case 'u':
11632 who |= S_ISUID|S_IRWXU;
11633 break;
11634 case 'g':
11635 who |= S_ISGID|S_IRWXG;
11636 break;
11637 case 'o':
11638 who |= S_IRWXO;
11639 break;
11640 default:
11641 goto getop;
11642 }
11643 }
11644
Eric Andersen2870d962001-07-02 17:27:21 +000011645getop: if ((op = *p++) != '+' && op != '-' && op != '=') {
Eric Andersencb57d552001-06-28 07:25:16 +000011646 free(saveset);
11647 return (NULL);
11648 }
11649 if (op == '=')
11650 equalopdone = 0;
11651
11652 who &= ~S_ISTXT;
11653 for (perm = 0, permXbits = 0;; ++p) {
11654 switch (*p) {
11655 case 'r':
11656 perm |= S_IRUSR|S_IRGRP|S_IROTH;
11657 break;
11658 case 's':
11659 /*
Eric Andersen2870d962001-07-02 17:27:21 +000011660 * If specific bits where requested and
11661 * only "other" bits ignore set-id.
Eric Andersencb57d552001-06-28 07:25:16 +000011662 */
11663 if (who == 0 || (who & ~S_IRWXO))
11664 perm |= S_ISUID|S_ISGID;
11665 break;
11666 case 't':
11667 /*
Eric Andersen2870d962001-07-02 17:27:21 +000011668 * If specific bits where requested and
11669 * only "other" bits ignore set-id.
Eric Andersencb57d552001-06-28 07:25:16 +000011670 */
11671 if (who == 0 || (who & ~S_IRWXO)) {
11672 who |= S_ISTXT;
11673 perm |= S_ISTXT;
11674 }
11675 break;
11676 case 'w':
11677 perm |= S_IWUSR|S_IWGRP|S_IWOTH;
11678 break;
11679 case 'X':
11680 permXbits = S_IXUSR|S_IXGRP|S_IXOTH;
11681 break;
11682 case 'x':
11683 perm |= S_IXUSR|S_IXGRP|S_IXOTH;
11684 break;
11685 case 'u':
11686 case 'g':
11687 case 'o':
11688 /*
11689 * When ever we hit 'u', 'g', or 'o', we have
11690 * to flush out any partial mode that we have,
11691 * and then do the copying of the mode bits.
11692 */
11693 if (perm) {
11694 ADDCMD(op, who, perm, mask);
11695 perm = 0;
11696 }
11697 if (op == '=')
11698 equalopdone = 1;
11699 if (op == '+' && permXbits) {
11700 ADDCMD('X', who, permXbits, mask);
11701 permXbits = 0;
11702 }
11703 ADDCMD(*p, who, op, mask);
11704 break;
11705
11706 default:
11707 /*
11708 * Add any permissions that we haven't already
11709 * done.
11710 */
11711 if (perm || (op == '=' && !equalopdone)) {
11712 if (op == '=')
11713 equalopdone = 1;
11714 ADDCMD(op, who, perm, mask);
11715 perm = 0;
11716 }
11717 if (permXbits) {
11718 ADDCMD('X', who, permXbits, mask);
11719 permXbits = 0;
11720 }
11721 goto apply;
11722 }
11723 }
11724
Eric Andersen2870d962001-07-02 17:27:21 +000011725apply: if (!*p)
Eric Andersencb57d552001-06-28 07:25:16 +000011726 break;
11727 if (*p != ',')
11728 goto getop;
11729 ++p;
11730 }
11731 set->cmd = 0;
11732#ifdef SETMODE_DEBUG
11733 (void)printf("Before compress_mode()\n");
11734 dumpmode(saveset);
11735#endif
11736 compress_mode(saveset);
11737#ifdef SETMODE_DEBUG
11738 (void)printf("After compress_mode()\n");
11739 dumpmode(saveset);
11740#endif
11741 return (saveset);
11742}
11743
11744static BITCMD *
11745addcmd(set, op, who, oparg, mask)
11746 BITCMD *set;
11747 int oparg, who;
11748 int op;
11749 u_int mask;
11750{
11751
11752 _DIAGASSERT(set != NULL);
11753
11754 switch (op) {
11755 case '=':
11756 set->cmd = '-';
11757 set->bits = who ? who : STANDARD_BITS;
11758 set++;
11759
11760 op = '+';
11761 /* FALLTHROUGH */
11762 case '+':
11763 case '-':
11764 case 'X':
11765 set->cmd = op;
11766 set->bits = (who ? who : mask) & oparg;
11767 break;
11768
11769 case 'u':
11770 case 'g':
11771 case 'o':
11772 set->cmd = op;
11773 if (who) {
11774 set->cmd2 = ((who & S_IRUSR) ? CMD2_UBITS : 0) |
11775 ((who & S_IRGRP) ? CMD2_GBITS : 0) |
11776 ((who & S_IROTH) ? CMD2_OBITS : 0);
11777 set->bits = (mode_t)~0;
11778 } else {
11779 set->cmd2 = CMD2_UBITS | CMD2_GBITS | CMD2_OBITS;
11780 set->bits = mask;
11781 }
Eric Andersen2870d962001-07-02 17:27:21 +000011782
Eric Andersencb57d552001-06-28 07:25:16 +000011783 if (oparg == '+')
11784 set->cmd2 |= CMD2_SET;
11785 else if (oparg == '-')
11786 set->cmd2 |= CMD2_CLR;
11787 else if (oparg == '=')
11788 set->cmd2 |= CMD2_SET|CMD2_CLR;
11789 break;
11790 }
11791 return (set + 1);
11792}
11793
11794#ifdef SETMODE_DEBUG
11795static void
11796dumpmode(set)
11797 BITCMD *set;
11798{
11799
11800 _DIAGASSERT(set != NULL);
11801
11802 for (; set->cmd; ++set)
11803 (void)printf("cmd: '%c' bits %04o%s%s%s%s%s%s\n",
11804 set->cmd, set->bits, set->cmd2 ? " cmd2:" : "",
11805 set->cmd2 & CMD2_CLR ? " CLR" : "",
11806 set->cmd2 & CMD2_SET ? " SET" : "",
11807 set->cmd2 & CMD2_UBITS ? " UBITS" : "",
11808 set->cmd2 & CMD2_GBITS ? " GBITS" : "",
11809 set->cmd2 & CMD2_OBITS ? " OBITS" : "");
11810}
11811#endif
11812
11813/*
11814 * Given an array of bitcmd structures, compress by compacting consecutive
11815 * '+', '-' and 'X' commands into at most 3 commands, one of each. The 'u',
Eric Andersen2870d962001-07-02 17:27:21 +000011816 * 'g' and 'o' commands continue to be separate. They could probably be
Eric Andersencb57d552001-06-28 07:25:16 +000011817 * compacted, but it's not worth the effort.
11818 */
11819static void
11820compress_mode(set)
11821 BITCMD *set;
11822{
11823 BITCMD *nset;
11824 int setbits, clrbits, Xbits, op;
11825
11826 _DIAGASSERT(set != NULL);
11827
11828 for (nset = set;;) {
11829 /* Copy over any 'u', 'g' and 'o' commands. */
11830 while ((op = nset->cmd) != '+' && op != '-' && op != 'X') {
11831 *set++ = *nset++;
11832 if (!op)
11833 return;
11834 }
11835
11836 for (setbits = clrbits = Xbits = 0;; nset++) {
11837 if ((op = nset->cmd) == '-') {
11838 clrbits |= nset->bits;
11839 setbits &= ~nset->bits;
11840 Xbits &= ~nset->bits;
11841 } else if (op == '+') {
11842 setbits |= nset->bits;
11843 clrbits &= ~nset->bits;
11844 Xbits &= ~nset->bits;
11845 } else if (op == 'X')
11846 Xbits |= nset->bits & ~setbits;
11847 else
11848 break;
11849 }
11850 if (clrbits) {
11851 set->cmd = '-';
11852 set->cmd2 = 0;
11853 set->bits = clrbits;
11854 set++;
11855 }
11856 if (setbits) {
11857 set->cmd = '+';
11858 set->cmd2 = 0;
11859 set->bits = setbits;
11860 set++;
11861 }
11862 if (Xbits) {
11863 set->cmd = 'X';
11864 set->cmd2 = 0;
11865 set->bits = Xbits;
11866 set++;
11867 }
11868 }
11869}
Eric Andersencb57d552001-06-28 07:25:16 +000011870#ifdef DEBUG
Eric Andersen2870d962001-07-02 17:27:21 +000011871static void shtree (union node *, int, char *, FILE*);
11872static void shcmd (union node *, FILE *);
11873static void sharg (union node *, FILE *);
11874static void indent (int, char *, FILE *);
11875static void trstring (char *);
Eric Andersencb57d552001-06-28 07:25:16 +000011876
11877
11878static void
11879showtree(n)
11880 union node *n;
11881{
11882 trputs("showtree called\n");
11883 shtree(n, 1, NULL, stdout);
11884}
11885
11886
11887static void
11888shtree(n, ind, pfx, fp)
11889 union node *n;
11890 int ind;
11891 char *pfx;
11892 FILE *fp;
11893{
11894 struct nodelist *lp;
11895 const char *s;
11896
11897 if (n == NULL)
11898 return;
11899
11900 indent(ind, pfx, fp);
11901 switch(n->type) {
11902 case NSEMI:
11903 s = "; ";
11904 goto binop;
11905 case NAND:
11906 s = " && ";
11907 goto binop;
11908 case NOR:
11909 s = " || ";
11910binop:
11911 shtree(n->nbinary.ch1, ind, NULL, fp);
11912 /* if (ind < 0) */
11913 fputs(s, fp);
11914 shtree(n->nbinary.ch2, ind, NULL, fp);
11915 break;
11916 case NCMD:
11917 shcmd(n, fp);
11918 if (ind >= 0)
11919 putc('\n', fp);
11920 break;
11921 case NPIPE:
11922 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
11923 shcmd(lp->n, fp);
11924 if (lp->next)
11925 fputs(" | ", fp);
11926 }
11927 if (n->npipe.backgnd)
11928 fputs(" &", fp);
11929 if (ind >= 0)
11930 putc('\n', fp);
11931 break;
11932 default:
11933 fprintf(fp, "<node type %d>", n->type);
11934 if (ind >= 0)
11935 putc('\n', fp);
11936 break;
11937 }
11938}
11939
11940
11941
11942static void
11943shcmd(cmd, fp)
11944 union node *cmd;
11945 FILE *fp;
11946{
11947 union node *np;
11948 int first;
11949 const char *s;
11950 int dftfd;
11951
11952 first = 1;
11953 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
11954 if (! first)
11955 putchar(' ');
11956 sharg(np, fp);
11957 first = 0;
11958 }
11959 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
11960 if (! first)
11961 putchar(' ');
11962 switch (np->nfile.type) {
Eric Andersen2870d962001-07-02 17:27:21 +000011963 case NTO: s = ">"; dftfd = 1; break;
11964 case NAPPEND: s = ">>"; dftfd = 1; break;
11965 case NTOFD: s = ">&"; dftfd = 1; break;
11966 case NTOOV: s = ">|"; dftfd = 1; break;
11967 case NFROM: s = "<"; dftfd = 0; break;
11968 case NFROMFD: s = "<&"; dftfd = 0; break;
11969 case NFROMTO: s = "<>"; dftfd = 0; break;
11970 default: s = "*error*"; dftfd = 0; break;
Eric Andersencb57d552001-06-28 07:25:16 +000011971 }
11972 if (np->nfile.fd != dftfd)
11973 fprintf(fp, "%d", np->nfile.fd);
11974 fputs(s, fp);
11975 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
11976 fprintf(fp, "%d", np->ndup.dupfd);
11977 } else {
11978 sharg(np->nfile.fname, fp);
11979 }
11980 first = 0;
11981 }
11982}
11983
11984
11985
11986static void
11987sharg(arg, fp)
11988 union node *arg;
11989 FILE *fp;
11990 {
11991 char *p;
11992 struct nodelist *bqlist;
11993 int subtype;
11994
11995 if (arg->type != NARG) {
11996 printf("<node type %d>\n", arg->type);
11997 fflush(stdout);
11998 abort();
11999 }
12000 bqlist = arg->narg.backquote;
12001 for (p = arg->narg.text ; *p ; p++) {
12002 switch (*p) {
12003 case CTLESC:
12004 putc(*++p, fp);
12005 break;
12006 case CTLVAR:
12007 putc('$', fp);
12008 putc('{', fp);
12009 subtype = *++p;
12010 if (subtype == VSLENGTH)
12011 putc('#', fp);
12012
12013 while (*p != '=')
12014 putc(*p++, fp);
12015
12016 if (subtype & VSNUL)
12017 putc(':', fp);
12018
12019 switch (subtype & VSTYPE) {
12020 case VSNORMAL:
12021 putc('}', fp);
12022 break;
12023 case VSMINUS:
12024 putc('-', fp);
12025 break;
12026 case VSPLUS:
12027 putc('+', fp);
12028 break;
12029 case VSQUESTION:
12030 putc('?', fp);
12031 break;
12032 case VSASSIGN:
12033 putc('=', fp);
12034 break;
12035 case VSTRIMLEFT:
12036 putc('#', fp);
12037 break;
12038 case VSTRIMLEFTMAX:
12039 putc('#', fp);
12040 putc('#', fp);
12041 break;
12042 case VSTRIMRIGHT:
12043 putc('%', fp);
12044 break;
12045 case VSTRIMRIGHTMAX:
12046 putc('%', fp);
12047 putc('%', fp);
12048 break;
12049 case VSLENGTH:
12050 break;
12051 default:
12052 printf("<subtype %d>", subtype);
12053 }
12054 break;
12055 case CTLENDVAR:
12056 putc('}', fp);
12057 break;
12058 case CTLBACKQ:
12059 case CTLBACKQ|CTLQUOTE:
12060 putc('$', fp);
12061 putc('(', fp);
12062 shtree(bqlist->n, -1, NULL, fp);
12063 putc(')', fp);
12064 break;
12065 default:
12066 putc(*p, fp);
12067 break;
12068 }
12069 }
12070}
12071
12072
12073static void
12074indent(amount, pfx, fp)
12075 int amount;
12076 char *pfx;
12077 FILE *fp;
12078{
12079 int i;
12080
12081 for (i = 0 ; i < amount ; i++) {
12082 if (pfx && i == amount - 1)
12083 fputs(pfx, fp);
12084 putc('\t', fp);
12085 }
12086}
12087#endif
12088
12089
12090
12091/*
12092 * Debugging stuff.
12093 */
12094
12095
12096#ifdef DEBUG
12097FILE *tracefile;
12098
12099#if DEBUG == 2
12100static int debug = 1;
12101#else
12102static int debug = 0;
12103#endif
12104
12105
12106static void
12107trputc(c)
12108 int c;
12109{
12110 if (tracefile == NULL)
12111 return;
12112 putc(c, tracefile);
12113 if (c == '\n')
12114 fflush(tracefile);
12115}
12116
12117static void
12118trace(const char *fmt, ...)
12119{
12120 va_list va;
12121#ifdef __STDC__
12122 va_start(va, fmt);
12123#else
12124 char *fmt;
12125 va_start(va);
12126 fmt = va_arg(va, char *);
12127#endif
12128 if (tracefile != NULL) {
12129 (void) vfprintf(tracefile, fmt, va);
12130 if (strchr(fmt, '\n'))
12131 (void) fflush(tracefile);
12132 }
12133 va_end(va);
12134}
12135
12136
12137static void
12138trputs(s)
12139 const char *s;
12140{
12141 if (tracefile == NULL)
12142 return;
12143 fputs(s, tracefile);
12144 if (strchr(s, '\n'))
12145 fflush(tracefile);
12146}
12147
12148
12149static void
12150trstring(s)
12151 char *s;
12152{
12153 char *p;
12154 char c;
12155
12156 if (tracefile == NULL)
12157 return;
12158 putc('"', tracefile);
12159 for (p = s ; *p ; p++) {
12160 switch (*p) {
12161 case '\n': c = 'n'; goto backslash;
12162 case '\t': c = 't'; goto backslash;
12163 case '\r': c = 'r'; goto backslash;
12164 case '"': c = '"'; goto backslash;
12165 case '\\': c = '\\'; goto backslash;
12166 case CTLESC: c = 'e'; goto backslash;
12167 case CTLVAR: c = 'v'; goto backslash;
12168 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
12169 case CTLBACKQ: c = 'q'; goto backslash;
12170 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
Eric Andersen2870d962001-07-02 17:27:21 +000012171backslash: putc('\\', tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000012172 putc(c, tracefile);
12173 break;
12174 default:
12175 if (*p >= ' ' && *p <= '~')
12176 putc(*p, tracefile);
12177 else {
12178 putc('\\', tracefile);
12179 putc(*p >> 6 & 03, tracefile);
12180 putc(*p >> 3 & 07, tracefile);
12181 putc(*p & 07, tracefile);
12182 }
12183 break;
12184 }
12185 }
12186 putc('"', tracefile);
12187}
12188
12189
12190static void
12191trargs(ap)
12192 char **ap;
12193{
12194 if (tracefile == NULL)
12195 return;
12196 while (*ap) {
12197 trstring(*ap++);
12198 if (*ap)
12199 putc(' ', tracefile);
12200 else
12201 putc('\n', tracefile);
12202 }
12203 fflush(tracefile);
12204}
12205
12206
12207static void
12208opentrace() {
12209 char s[100];
12210#ifdef O_APPEND
12211 int flags;
12212#endif
12213
12214 if (!debug)
12215 return;
12216#ifdef not_this_way
12217 {
12218 char *p;
12219 if ((p = getenv("HOME")) == NULL) {
12220 if (geteuid() == 0)
12221 p = "/";
12222 else
12223 p = "/tmp";
12224 }
Eric Andersen2870d962001-07-02 17:27:21 +000012225 strcpy(s, p);
Eric Andersencb57d552001-06-28 07:25:16 +000012226 strcat(s, "/trace");
12227 }
12228#else
Eric Andersen2870d962001-07-02 17:27:21 +000012229 strcpy(s, "./trace");
Eric Andersencb57d552001-06-28 07:25:16 +000012230#endif /* not_this_way */
12231 if ((tracefile = fopen(s, "a")) == NULL) {
12232 fprintf(stderr, "Can't open %s\n", s);
12233 return;
12234 }
12235#ifdef O_APPEND
12236 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
12237 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
12238#endif
12239 fputs("\nTracing started.\n", tracefile);
12240 fflush(tracefile);
12241}
12242#endif /* DEBUG */
12243
12244
12245/*
Eric Andersencb57d552001-06-28 07:25:16 +000012246 * The trap builtin.
12247 */
12248
12249static int
12250trapcmd(argc, argv)
12251 int argc;
12252 char **argv;
12253{
12254 char *action;
12255 char **ap;
12256 int signo;
12257
12258 if (argc <= 1) {
12259 for (signo = 0 ; signo < NSIG ; signo++) {
12260 if (trap[signo] != NULL) {
12261 char *p;
12262
12263 p = single_quote(trap[signo]);
12264 out1fmt("trap -- %s %s\n", p,
12265 signal_names[signo] + (signo ? 3 : 0)
12266 );
12267 stunalloc(p);
12268 }
12269 }
12270 return 0;
12271 }
12272 ap = argv + 1;
12273 if (argc == 2)
12274 action = NULL;
12275 else
12276 action = *ap++;
12277 while (*ap) {
12278 if ((signo = decode_signal(*ap, 0)) < 0)
12279 error("%s: bad trap", *ap);
12280 INTOFF;
12281 if (action) {
12282 if (action[0] == '-' && action[1] == '\0')
12283 action = NULL;
12284 else
12285 action = savestr(action);
12286 }
12287 if (trap[signo])
12288 ckfree(trap[signo]);
12289 trap[signo] = action;
12290 if (signo != 0)
12291 setsignal(signo);
12292 INTON;
12293 ap++;
12294 }
12295 return 0;
12296}
12297
12298
12299
Eric Andersencb57d552001-06-28 07:25:16 +000012300
12301
12302
12303/*
12304 * Set the signal handler for the specified signal. The routine figures
12305 * out what it should be set to.
12306 */
12307
12308static void
Eric Andersen2870d962001-07-02 17:27:21 +000012309setsignal(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000012310{
12311 int action;
12312 char *t;
12313 struct sigaction act;
12314
12315 if ((t = trap[signo]) == NULL)
12316 action = S_DFL;
12317 else if (*t != '\0')
12318 action = S_CATCH;
12319 else
12320 action = S_IGN;
12321 if (rootshell && action == S_DFL) {
12322 switch (signo) {
12323 case SIGINT:
12324 if (iflag || minusc || sflag == 0)
12325 action = S_CATCH;
12326 break;
12327 case SIGQUIT:
12328#ifdef DEBUG
12329 {
Eric Andersencb57d552001-06-28 07:25:16 +000012330
12331 if (debug)
12332 break;
12333 }
12334#endif
12335 /* FALLTHROUGH */
12336 case SIGTERM:
12337 if (iflag)
12338 action = S_IGN;
12339 break;
Eric Andersen2870d962001-07-02 17:27:21 +000012340#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000012341 case SIGTSTP:
12342 case SIGTTOU:
12343 if (mflag)
12344 action = S_IGN;
12345 break;
12346#endif
12347 }
12348 }
12349
12350 t = &sigmode[signo - 1];
12351 if (*t == 0) {
12352 /*
12353 * current setting unknown
12354 */
12355 if (sigaction(signo, 0, &act) == -1) {
12356 /*
12357 * Pretend it worked; maybe we should give a warning
12358 * here, but other shells don't. We don't alter
12359 * sigmode, so that we retry every time.
12360 */
12361 return;
12362 }
12363 if (act.sa_handler == SIG_IGN) {
12364 if (mflag && (signo == SIGTSTP ||
12365 signo == SIGTTIN || signo == SIGTTOU)) {
Eric Andersen2870d962001-07-02 17:27:21 +000012366 *t = S_IGN; /* don't hard ignore these */
Eric Andersencb57d552001-06-28 07:25:16 +000012367 } else
12368 *t = S_HARD_IGN;
12369 } else {
Eric Andersen2870d962001-07-02 17:27:21 +000012370 *t = S_RESET; /* force to be set */
Eric Andersencb57d552001-06-28 07:25:16 +000012371 }
12372 }
12373 if (*t == S_HARD_IGN || *t == action)
12374 return;
12375 switch (action) {
12376 case S_CATCH:
12377 act.sa_handler = onsig;
12378 break;
12379 case S_IGN:
12380 act.sa_handler = SIG_IGN;
12381 break;
12382 default:
12383 act.sa_handler = SIG_DFL;
12384 }
12385 *t = action;
12386 act.sa_flags = 0;
12387 sigemptyset(&act.sa_mask);
12388 sigaction(signo, &act, 0);
12389}
12390
12391/*
12392 * Ignore a signal.
12393 */
12394
12395static void
12396ignoresig(signo)
12397 int signo;
12398{
12399 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
12400 signal(signo, SIG_IGN);
12401 }
12402 sigmode[signo - 1] = S_HARD_IGN;
12403}
12404
12405
Eric Andersencb57d552001-06-28 07:25:16 +000012406/*
12407 * Signal handler.
12408 */
12409
12410static void
Eric Andersen2870d962001-07-02 17:27:21 +000012411onsig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000012412{
12413 if (signo == SIGINT && trap[SIGINT] == NULL) {
12414 onint();
12415 return;
12416 }
12417 gotsig[signo - 1] = 1;
12418 pendingsigs++;
12419}
12420
12421
Eric Andersencb57d552001-06-28 07:25:16 +000012422/*
12423 * Called to execute a trap. Perhaps we should avoid entering new trap
12424 * handlers while we are executing a trap handler.
12425 */
12426
12427static void
Eric Andersen2870d962001-07-02 17:27:21 +000012428dotrap(void)
12429{
Eric Andersencb57d552001-06-28 07:25:16 +000012430 int i;
12431 int savestatus;
12432
12433 for (;;) {
12434 for (i = 1 ; ; i++) {
12435 if (gotsig[i - 1])
12436 break;
12437 if (i >= NSIG - 1)
12438 goto done;
12439 }
12440 gotsig[i - 1] = 0;
12441 savestatus=exitstatus;
12442 evalstring(trap[i], 0);
12443 exitstatus=savestatus;
12444 }
12445done:
12446 pendingsigs = 0;
12447}
12448
Eric Andersencb57d552001-06-28 07:25:16 +000012449/*
12450 * Called to exit the shell.
12451 */
12452
12453static void
Eric Andersen2870d962001-07-02 17:27:21 +000012454exitshell(int status)
Eric Andersencb57d552001-06-28 07:25:16 +000012455{
12456 struct jmploc loc1, loc2;
12457 char *p;
12458
12459 TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
12460 if (setjmp(loc1.loc)) {
12461 goto l1;
12462 }
12463 if (setjmp(loc2.loc)) {
12464 goto l2;
12465 }
12466 handler = &loc1;
12467 if ((p = trap[0]) != NULL && *p != '\0') {
12468 trap[0] = NULL;
12469 evalstring(p, 0);
12470 }
Eric Andersen2870d962001-07-02 17:27:21 +000012471l1: handler = &loc2; /* probably unnecessary */
Eric Andersencb57d552001-06-28 07:25:16 +000012472 flushall();
Eric Andersen2870d962001-07-02 17:27:21 +000012473#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000012474 setjobctl(0);
12475#endif
12476l2: _exit(status);
12477 /* NOTREACHED */
12478}
12479
12480static int decode_signal(const char *string, int minsig)
12481{
12482 int signo;
12483
Eric Andersen2870d962001-07-02 17:27:21 +000012484 if (is_number(string, &signo)) {
Eric Andersencb57d552001-06-28 07:25:16 +000012485 if (signo >= NSIG) {
12486 return -1;
12487 }
12488 return signo;
12489 }
12490
12491 signo = minsig;
12492 if (!signo) {
12493 goto zero;
12494 }
12495 for (; signo < NSIG; signo++) {
12496 if (!strcasecmp(string, &(signal_names[signo])[3])) {
12497 return signo;
12498 }
12499zero:
12500 if (!strcasecmp(string, signal_names[signo])) {
12501 return signo;
12502 }
12503 }
12504
12505 return -1;
12506}
Eric Andersen2870d962001-07-02 17:27:21 +000012507static struct var **hashvar (const char *);
12508static void showvars (const char *, int, int);
12509static struct var **findvar (struct var **, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +000012510
12511/*
12512 * Initialize the varable symbol tables and import the environment
12513 */
12514
Eric Andersencb57d552001-06-28 07:25:16 +000012515/*
12516 * This routine initializes the builtin variables. It is called when the
12517 * shell is initialized and again when a shell procedure is spawned.
12518 */
12519
12520static void
12521initvar() {
12522 const struct varinit *ip;
12523 struct var *vp;
12524 struct var **vpp;
12525
12526 for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
12527 if ((vp->flags & VEXPORT) == 0) {
12528 vpp = hashvar(ip->text);
12529 vp->next = *vpp;
12530 *vpp = vp;
12531 vp->text = strdup(ip->text);
12532 vp->flags = ip->flags;
12533 vp->func = ip->func;
12534 }
12535 }
12536 /*
12537 * PS1 depends on uid
12538 */
12539 if ((vps1.flags & VEXPORT) == 0) {
12540 vpp = hashvar("PS1=");
12541 vps1.next = *vpp;
12542 *vpp = &vps1;
12543 vps1.text = strdup(geteuid() ? "PS1=$ " : "PS1=# ");
12544 vps1.flags = VSTRFIXED|VTEXTFIXED;
12545 }
12546}
12547
12548/*
12549 * Set the value of a variable. The flags argument is ored with the
12550 * flags of the variable. If val is NULL, the variable is unset.
12551 */
12552
12553static void
12554setvar(name, val, flags)
12555 const char *name, *val;
12556 int flags;
12557{
12558 const char *p;
12559 int len;
12560 int namelen;
12561 char *nameeq;
12562 int isbad;
12563 int vallen = 0;
12564
12565 isbad = 0;
12566 p = name;
12567 if (! is_name(*p))
12568 isbad = 1;
12569 p++;
12570 for (;;) {
12571 if (! is_in_name(*p)) {
12572 if (*p == '\0' || *p == '=')
12573 break;
12574 isbad = 1;
12575 }
12576 p++;
12577 }
12578 namelen = p - name;
12579 if (isbad)
12580 error("%.*s: bad variable name", namelen, name);
Eric Andersen2870d962001-07-02 17:27:21 +000012581 len = namelen + 2; /* 2 is space for '=' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +000012582 if (val == NULL) {
12583 flags |= VUNSET;
12584 } else {
12585 len += vallen = strlen(val);
12586 }
12587 INTOFF;
12588 nameeq = ckmalloc(len);
12589 memcpy(nameeq, name, namelen);
12590 nameeq[namelen] = '=';
12591 if (val) {
12592 memcpy(nameeq + namelen + 1, val, vallen + 1);
12593 } else {
12594 nameeq[namelen + 1] = '\0';
12595 }
12596 setvareq(nameeq, flags);
12597 INTON;
12598}
12599
12600
12601
12602/*
12603 * Same as setvar except that the variable and value are passed in
12604 * the first argument as name=value. Since the first argument will
12605 * be actually stored in the table, it should not be a string that
12606 * will go away.
12607 */
12608
12609static void
12610setvareq(s, flags)
12611 char *s;
12612 int flags;
12613{
12614 struct var *vp, **vpp;
12615
12616 vpp = hashvar(s);
12617 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
12618 if ((vp = *findvar(vpp, s))) {
12619 if (vp->flags & VREADONLY) {
12620 size_t len = strchr(s, '=') - s;
12621 error("%.*s: is read only", len, s);
12622 }
12623 INTOFF;
12624
12625 if (vp->func && (flags & VNOFUNC) == 0)
12626 (*vp->func)(strchr(s, '=') + 1);
12627
12628 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
12629 ckfree(vp->text);
12630
12631 vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
12632 vp->flags |= flags;
12633 vp->text = s;
12634
12635 /*
12636 * We could roll this to a function, to handle it as
12637 * a regular variable function callback, but why bother?
12638 */
12639 if (iflag && (vp == &vmpath || (vp == &vmail && !mpathset())))
12640 chkmail(1);
12641 INTON;
12642 return;
12643 }
12644 /* not found */
12645 vp = ckmalloc(sizeof (*vp));
12646 vp->flags = flags;
12647 vp->text = s;
12648 vp->next = *vpp;
12649 vp->func = NULL;
12650 *vpp = vp;
12651}
12652
12653
12654
12655/*
12656 * Process a linked list of variable assignments.
12657 */
12658
12659static void
12660listsetvar(mylist)
12661 struct strlist *mylist;
12662 {
12663 struct strlist *lp;
12664
12665 INTOFF;
12666 for (lp = mylist ; lp ; lp = lp->next) {
12667 setvareq(savestr(lp->text), 0);
12668 }
12669 INTON;
12670}
12671
12672
12673
12674/*
12675 * Find the value of a variable. Returns NULL if not set.
12676 */
12677
12678static char *
12679lookupvar(name)
12680 const char *name;
12681 {
12682 struct var *v;
12683
12684 if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
12685 return strchr(v->text, '=') + 1;
12686 }
12687 return NULL;
12688}
12689
12690
12691
12692/*
12693 * Search the environment of a builtin command.
12694 */
12695
12696static char *
12697bltinlookup(name)
12698 const char *name;
12699{
12700 struct strlist *sp;
12701
12702 for (sp = cmdenviron ; sp ; sp = sp->next) {
12703 if (varequal(sp->text, name))
12704 return strchr(sp->text, '=') + 1;
12705 }
12706 return lookupvar(name);
12707}
12708
12709
12710
12711/*
12712 * Generate a list of exported variables. This routine is used to construct
12713 * the third argument to execve when executing a program.
12714 */
12715
12716static char **
12717environment() {
12718 int nenv;
12719 struct var **vpp;
12720 struct var *vp;
12721 char **env;
12722 char **ep;
12723
12724 nenv = 0;
12725 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12726 for (vp = *vpp ; vp ; vp = vp->next)
12727 if (vp->flags & VEXPORT)
12728 nenv++;
12729 }
12730 ep = env = stalloc((nenv + 1) * sizeof *env);
12731 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12732 for (vp = *vpp ; vp ; vp = vp->next)
12733 if (vp->flags & VEXPORT)
12734 *ep++ = vp->text;
12735 }
12736 *ep = NULL;
12737 return env;
12738}
12739
12740
12741/*
12742 * Called when a shell procedure is invoked to clear out nonexported
12743 * variables. It is also necessary to reallocate variables of with
12744 * VSTACK set since these are currently allocated on the stack.
12745 */
12746
Eric Andersencb57d552001-06-28 07:25:16 +000012747static void
Eric Andersen2870d962001-07-02 17:27:21 +000012748shprocvar(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000012749 struct var **vpp;
12750 struct var *vp, **prev;
12751
12752 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
12753 for (prev = vpp ; (vp = *prev) != NULL ; ) {
12754 if ((vp->flags & VEXPORT) == 0) {
12755 *prev = vp->next;
12756 if ((vp->flags & VTEXTFIXED) == 0)
12757 ckfree(vp->text);
12758 if ((vp->flags & VSTRFIXED) == 0)
12759 ckfree(vp);
12760 } else {
12761 if (vp->flags & VSTACK) {
12762 vp->text = savestr(vp->text);
12763 vp->flags &=~ VSTACK;
12764 }
12765 prev = &vp->next;
12766 }
12767 }
12768 }
12769 initvar();
12770}
12771
12772
12773
12774/*
12775 * Command to list all variables which are set. Currently this command
12776 * is invoked from the set command when the set command is called without
12777 * any variables.
12778 */
12779
12780static int
12781showvarscmd(argc, argv)
12782 int argc;
12783 char **argv;
12784{
12785 showvars(nullstr, VUNSET, VUNSET);
12786 return 0;
12787}
12788
12789
12790
12791/*
12792 * The export and readonly commands.
12793 */
12794
12795static int
12796exportcmd(argc, argv)
12797 int argc;
12798 char **argv;
12799{
12800 struct var *vp;
12801 char *name;
12802 const char *p;
12803 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
12804 int pflag;
12805
12806 listsetvar(cmdenviron);
12807 pflag = (nextopt("p") == 'p');
12808 if (argc > 1 && !pflag) {
12809 while ((name = *argptr++) != NULL) {
12810 if ((p = strchr(name, '=')) != NULL) {
12811 p++;
12812 } else {
12813 if ((vp = *findvar(hashvar(name), name))) {
12814 vp->flags |= flag;
12815 goto found;
12816 }
12817 }
12818 setvar(name, p, flag);
12819found:;
12820 }
12821 } else {
12822 showvars(argv[0], flag, 0);
12823 }
12824 return 0;
12825}
12826
12827
12828/*
12829 * The "local" command.
12830 */
12831
Eric Andersen2870d962001-07-02 17:27:21 +000012832/* funcnest nonzero if we are currently evaluating a function */
12833
Eric Andersencb57d552001-06-28 07:25:16 +000012834static int
12835localcmd(argc, argv)
12836 int argc;
12837 char **argv;
12838{
12839 char *name;
12840
Eric Andersen2870d962001-07-02 17:27:21 +000012841 if (! funcnest)
Eric Andersencb57d552001-06-28 07:25:16 +000012842 error("Not in a function");
12843 while ((name = *argptr++) != NULL) {
12844 mklocal(name);
12845 }
12846 return 0;
12847}
12848
12849
12850/*
12851 * Make a variable a local variable. When a variable is made local, it's
12852 * value and flags are saved in a localvar structure. The saved values
12853 * will be restored when the shell function returns. We handle the name
12854 * "-" as a special case.
12855 */
12856
12857static void
12858mklocal(name)
12859 char *name;
12860 {
12861 struct localvar *lvp;
12862 struct var **vpp;
12863 struct var *vp;
12864
12865 INTOFF;
12866 lvp = ckmalloc(sizeof (struct localvar));
12867 if (name[0] == '-' && name[1] == '\0') {
12868 char *p;
Eric Andersen2870d962001-07-02 17:27:21 +000012869 p = ckmalloc(sizeof optet_vals);
12870 lvp->text = memcpy(p, optet_vals, sizeof optet_vals);
Eric Andersencb57d552001-06-28 07:25:16 +000012871 vp = NULL;
12872 } else {
12873 vpp = hashvar(name);
12874 vp = *findvar(vpp, name);
12875 if (vp == NULL) {
12876 if (strchr(name, '='))
12877 setvareq(savestr(name), VSTRFIXED);
12878 else
12879 setvar(name, NULL, VSTRFIXED);
Eric Andersen2870d962001-07-02 17:27:21 +000012880 vp = *vpp; /* the new variable */
Eric Andersencb57d552001-06-28 07:25:16 +000012881 lvp->text = NULL;
12882 lvp->flags = VUNSET;
12883 } else {
12884 lvp->text = vp->text;
12885 lvp->flags = vp->flags;
12886 vp->flags |= VSTRFIXED|VTEXTFIXED;
12887 if (strchr(name, '='))
12888 setvareq(savestr(name), 0);
12889 }
12890 }
12891 lvp->vp = vp;
12892 lvp->next = localvars;
12893 localvars = lvp;
12894 INTON;
12895}
12896
12897
12898/*
12899 * Called after a function returns.
12900 */
12901
12902static void
12903poplocalvars() {
12904 struct localvar *lvp;
12905 struct var *vp;
12906
12907 while ((lvp = localvars) != NULL) {
12908 localvars = lvp->next;
12909 vp = lvp->vp;
Eric Andersen2870d962001-07-02 17:27:21 +000012910 if (vp == NULL) { /* $- saved */
12911 memcpy(optet_vals, lvp->text, sizeof optet_vals);
Eric Andersencb57d552001-06-28 07:25:16 +000012912 ckfree(lvp->text);
12913 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
12914 (void)unsetvar(vp->text);
12915 } else {
12916 if ((vp->flags & VTEXTFIXED) == 0)
12917 ckfree(vp->text);
12918 vp->flags = lvp->flags;
12919 vp->text = lvp->text;
12920 }
12921 ckfree(lvp);
12922 }
12923}
12924
12925
12926static int
12927setvarcmd(argc, argv)
12928 int argc;
12929 char **argv;
12930{
12931 if (argc <= 2)
12932 return unsetcmd(argc, argv);
12933 else if (argc == 3)
12934 setvar(argv[1], argv[2], 0);
12935 else
12936 error("List assignment not implemented");
12937 return 0;
12938}
12939
12940
12941/*
12942 * The unset builtin command. We unset the function before we unset the
12943 * variable to allow a function to be unset when there is a readonly variable
12944 * with the same name.
12945 */
12946
12947static int
12948unsetcmd(argc, argv)
12949 int argc;
12950 char **argv;
12951{
12952 char **ap;
12953 int i;
12954 int flg_func = 0;
12955 int flg_var = 0;
12956 int ret = 0;
12957
12958 while ((i = nextopt("vf")) != '\0') {
12959 if (i == 'f')
12960 flg_func = 1;
12961 else
12962 flg_var = 1;
12963 }
12964 if (flg_func == 0 && flg_var == 0)
12965 flg_var = 1;
12966
12967 for (ap = argptr; *ap ; ap++) {
12968 if (flg_func)
12969 unsetfunc(*ap);
12970 if (flg_var)
12971 ret |= unsetvar(*ap);
12972 }
12973 return ret;
12974}
12975
12976
12977/*
12978 * Unset the specified variable.
12979 */
12980
12981static int
12982unsetvar(s)
12983 const char *s;
12984 {
12985 struct var **vpp;
12986 struct var *vp;
12987
12988 vpp = findvar(hashvar(s), s);
12989 vp = *vpp;
12990 if (vp) {
12991 if (vp->flags & VREADONLY)
12992 return (1);
12993 INTOFF;
12994 if (*(strchr(vp->text, '=') + 1) != '\0')
12995 setvar(s, nullstr, 0);
12996 vp->flags &= ~VEXPORT;
12997 vp->flags |= VUNSET;
12998 if ((vp->flags & VSTRFIXED) == 0) {
12999 if ((vp->flags & VTEXTFIXED) == 0)
13000 ckfree(vp->text);
13001 *vpp = vp->next;
13002 ckfree(vp);
13003 }
13004 INTON;
13005 return (0);
13006 }
13007
13008 return (0);
13009}
13010
13011
13012
13013/*
13014 * Find the appropriate entry in the hash table from the name.
13015 */
13016
13017static struct var **
13018hashvar(p)
13019 const char *p;
13020 {
13021 unsigned int hashval;
13022
13023 hashval = ((unsigned char) *p) << 4;
13024 while (*p && *p != '=')
13025 hashval += (unsigned char) *p++;
13026 return &vartab[hashval % VTABSIZE];
13027}
13028
13029
13030
13031/*
13032 * Returns true if the two strings specify the same varable. The first
13033 * variable name is terminated by '='; the second may be terminated by
13034 * either '=' or '\0'.
13035 */
13036
13037static int
13038varequal(p, q)
13039 const char *p, *q;
13040 {
13041 while (*p == *q++) {
13042 if (*p++ == '=')
13043 return 1;
13044 }
13045 if (*p == '=' && *(q - 1) == '\0')
13046 return 1;
13047 return 0;
13048}
13049
13050static void
13051showvars(const char *myprefix, int mask, int xor)
13052{
13053 struct var **vpp;
13054 struct var *vp;
13055 const char *sep = myprefix == nullstr ? myprefix : spcstr;
13056
13057 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
13058 for (vp = *vpp ; vp ; vp = vp->next) {
13059 if ((vp->flags & mask) ^ xor) {
13060 char *p;
13061 int len;
13062
13063 p = strchr(vp->text, '=') + 1;
13064 len = p - vp->text;
13065 p = single_quote(p);
13066
13067 out1fmt(
13068 "%s%s%.*s%s\n", myprefix, sep, len,
13069 vp->text, p
13070 );
13071 stunalloc(p);
13072 }
13073 }
13074 }
13075}
13076
13077static struct var **
13078findvar(struct var **vpp, const char *name)
13079{
13080 for (; *vpp; vpp = &(*vpp)->next) {
13081 if (varequal((*vpp)->text, name)) {
13082 break;
13083 }
13084 }
13085 return vpp;
13086}
13087
13088/*
13089 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
13090 * This file contains code for the times builtin.
Eric Andersen3102ac42001-07-06 04:26:23 +000013091 * $Id: ash.c,v 1.6 2001/07/06 04:26:23 andersen Exp $
Eric Andersencb57d552001-06-28 07:25:16 +000013092 */
13093static int timescmd (int argc, char **argv)
13094{
13095 struct tms buf;
13096 long int clk_tck = sysconf(_SC_CLK_TCK);
13097
13098 times(&buf);
13099 printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
13100 (int) (buf.tms_utime / clk_tck / 60),
13101 ((double) buf.tms_utime) / clk_tck,
13102 (int) (buf.tms_stime / clk_tck / 60),
13103 ((double) buf.tms_stime) / clk_tck,
13104 (int) (buf.tms_cutime / clk_tck / 60),
13105 ((double) buf.tms_cutime) / clk_tck,
13106 (int) (buf.tms_cstime / clk_tck / 60),
13107 ((double) buf.tms_cstime) / clk_tck);
13108 return 0;
13109}
13110
Eric Andersendf82f612001-06-28 07:46:40 +000013111
13112/*-
13113 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013114 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013115 *
13116 * This code is derived from software contributed to Berkeley by
13117 * Kenneth Almquist.
13118 *
13119 * Redistribution and use in source and binary forms, with or without
13120 * modification, are permitted provided that the following conditions
13121 * are met:
13122 * 1. Redistributions of source code must retain the above copyright
13123 * notice, this list of conditions and the following disclaimer.
13124 * 2. Redistributions in binary form must reproduce the above copyright
13125 * notice, this list of conditions and the following disclaimer in the
13126 * documentation and/or other materials provided with the distribution.
13127 *
Eric Andersen2870d962001-07-02 17:27:21 +000013128 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
13129 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
Eric Andersendf82f612001-06-28 07:46:40 +000013130 *
13131 * 4. Neither the name of the University nor the names of its contributors
13132 * may be used to endorse or promote products derived from this software
13133 * without specific prior written permission.
13134 *
13135 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13136 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13137 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13138 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13139 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13140 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13141 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13142 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13143 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13144 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13145 * SUCH DAMAGE.
13146 */