blob: e7f3516083dc8d35bc3a2d6893d1ef1a1ec96ffb [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
45 * it completely useless for is all you are doing is running scripts.
46 * 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
82/* Enable this to compile in extra debugging noise. When debugging is
83 * on, debugging info will be written to $HOME/trace and a quit signal
84 * will generate a core dump. */
85#undef DEBUG
86
87
88
89/* These are here to work with glibc -- Don't change these... */
Eric Andersendf82f612001-06-28 07:46:40 +000090#undef FNMATCH_BROKEN
91#undef GLOB_BROKEN
Eric Andersen2870d962001-07-02 17:27:21 +000092#undef _GNU_SOURCE
Eric Andersencb57d552001-06-28 07:25:16 +000093
94#include <assert.h>
95#include <ctype.h>
96#include <dirent.h>
97#include <errno.h>
98#include <fcntl.h>
99#include <limits.h>
100#include <paths.h>
101#include <pwd.h>
102#include <setjmp.h>
103#include <signal.h>
104#include <stdarg.h>
105#include <stdbool.h>
106#include <stdio.h>
107#include <stdlib.h>
108#include <string.h>
109#include <sysexits.h>
110#include <unistd.h>
111#include <sys/stat.h>
112#include <sys/cdefs.h>
113#include <sys/ioctl.h>
114#include <sys/param.h>
115#include <sys/resource.h>
116#include <sys/time.h>
117#include <sys/times.h>
118#include <sys/types.h>
119#include <sys/wait.h>
120
121
122#if !defined(FNMATCH_BROKEN)
123#include <fnmatch.h>
124#endif
125#if !defined(GLOB_BROKEN)
126#include <glob.h>
127#endif
128
Eric Andersen2870d962001-07-02 17:27:21 +0000129#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +0000130#include <termios.h>
Eric Andersencb57d552001-06-28 07:25:16 +0000131#endif
132
Eric Andersencb57d552001-06-28 07:25:16 +0000133#include "busybox.h"
Eric Andersen2870d962001-07-02 17:27:21 +0000134#include "cmdedit.h"
135
136/* if BB_PWD is defined, then disable ASH_PWD to save space */
137#ifdef BB_PWD
138#undef ASH_PWD
139#endif
140
141
142/*
143 * This file was generated by the mksyntax program.
144 */
145
146/* Syntax classes */
147#define CWORD 0 /* character is nothing special */
148#define CNL 1 /* newline character */
149#define CBACK 2 /* a backslash character */
150#define CSQUOTE 3 /* single quote */
151#define CDQUOTE 4 /* double quote */
152#define CENDQUOTE 5 /* a terminating quote */
153#define CBQUOTE 6 /* backwards single quote */
154#define CVAR 7 /* a dollar sign */
155#define CENDVAR 8 /* a '}' character */
156#define CLP 9 /* a left paren in arithmetic */
157#define CRP 10 /* a right paren in arithmetic */
158#define CENDFILE 11 /* end of file */
159#define CCTL 12 /* like CWORD, except it must be escaped */
160#define CSPCL 13 /* these terminate a word */
161#define CIGN 14 /* character should be ignored */
162
163/* Syntax classes for is_ functions */
164#define ISDIGIT 01 /* a digit */
165#define ISUPPER 02 /* an upper case letter */
166#define ISLOWER 04 /* a lower case letter */
167#define ISUNDER 010 /* an underscore */
168#define ISSPECL 020 /* the name of a special parameter */
169
170#define SYNBASE 130
171#define PEOF -130
172
173#define PEOA -129
174
175#define TEOF 0
176#define TNL 1
177#define TSEMI 2
178#define TBACKGND 3
179#define TAND 4
180#define TOR 5
181#define TPIPE 6
182#define TLP 7
183#define TRP 8
184#define TENDCASE 9
185#define TENDBQUOTE 10
186#define TREDIR 11
187#define TWORD 12
188#define TASSIGN 13
189#define TNOT 14
190#define TCASE 15
191#define TDO 16
192#define TDONE 17
193#define TELIF 18
194#define TELSE 19
195#define TESAC 20
196#define TFI 21
197#define TFOR 22
198#define TIF 23
199#define TIN 24
200#define TTHEN 25
201#define TUNTIL 26
202#define TWHILE 27
203#define TBEGIN 28
204#define TEND 29
205
206
207#define BASESYNTAX (basesyntax + SYNBASE)
208#define DQSYNTAX (dqsyntax + SYNBASE)
209#define SQSYNTAX (sqsyntax + SYNBASE)
210#define ARISYNTAX (arisyntax + SYNBASE)
211
212/* control characters in argument strings */
213#define CTLESC '\201'
214#define CTLVAR '\202'
215#define CTLENDVAR '\203'
216#define CTLBACKQ '\204'
217#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
218/* CTLBACKQ | CTLQUOTE == '\205' */
219#define CTLARI '\206'
220#define CTLENDARI '\207'
221#define CTLQUOTEMARK '\210'
222
223#define is_digit(c) ((((unsigned char)(c)) - '0') <= 9)
224#define is_alpha(c) (((c) < CTLESC || (c) > CTLENDARI) && isalpha((unsigned char) (c)))
225#define is_name(c) (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalpha((unsigned char) (c))))
226#define is_in_name(c) (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalnum((unsigned char) (c))))
227#define is_special(c) ((is_type+SYNBASE)[c] & (ISSPECL|ISDIGIT))
228#define digit_val(c) ((c) - '0')
Eric Andersencb57d552001-06-28 07:25:16 +0000229
230
231#define _DIAGASSERT(x)
232
233#define ATABSIZE 39
234
Eric Andersen2870d962001-07-02 17:27:21 +0000235#define S_DFL 1 /* default signal handling (SIG_DFL) */
236#define S_CATCH 2 /* signal is caught */
237#define S_IGN 3 /* signal is ignored (SIG_IGN) */
238#define S_HARD_IGN 4 /* signal is ignored permenantly */
239#define S_RESET 5 /* temporary - to reset a hard ignored sig */
Eric Andersencb57d552001-06-28 07:25:16 +0000240
241
Eric Andersen2870d962001-07-02 17:27:21 +0000242/* variable substitution byte (follows CTLVAR) */
243#define VSTYPE 0x0f /* type of variable substitution */
244#define VSNUL 0x10 /* colon--treat the empty string as unset */
245#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
Eric Andersencb57d552001-06-28 07:25:16 +0000246
Eric Andersen2870d962001-07-02 17:27:21 +0000247/* values of VSTYPE field */
248#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
249#define VSMINUS 0x2 /* ${var-text} */
250#define VSPLUS 0x3 /* ${var+text} */
251#define VSQUESTION 0x4 /* ${var?message} */
252#define VSASSIGN 0x5 /* ${var=text} */
253#define VSTRIMLEFT 0x6 /* ${var#pattern} */
254#define VSTRIMLEFTMAX 0x7 /* ${var##pattern} */
255#define VSTRIMRIGHT 0x8 /* ${var%pattern} */
256#define VSTRIMRIGHTMAX 0x9 /* ${var%%pattern} */
257#define VSLENGTH 0xa /* ${#var} */
Eric Andersencb57d552001-06-28 07:25:16 +0000258
Eric Andersen2870d962001-07-02 17:27:21 +0000259/* flags passed to redirect */
260#define REDIR_PUSH 01 /* save previous values of file descriptors */
261#define REDIR_BACKQ 02 /* save the command output in memory */
Eric Andersencb57d552001-06-28 07:25:16 +0000262
Eric Andersen2870d962001-07-02 17:27:21 +0000263/*
264 * BSD setjmp saves the signal mask, which violates ANSI C and takes time,
265 * so we use _setjmp instead.
266 */
267
268#if !defined(__GLIBC__)
269#define setjmp(jmploc) _setjmp(jmploc)
270#define longjmp(jmploc, val) _longjmp(jmploc, val)
271#endif
272
273/*
274 * Most machines require the value returned from malloc to be aligned
275 * in some way. The following macro will get this right on many machines.
276 */
277
278#ifndef ALIGN
279union align {
280 int i;
281 char *cp;
282};
283
284#define ALIGN(nbytes) (((nbytes) + sizeof(union align) - 1) & ~(sizeof(union align) - 1))
285#endif
286
287#ifdef BB_LOCALE_SUPPORT
288#include <locale.h>
289static void change_lc_all(const char *value);
290static void change_lc_ctype(const char *value);
291#endif
292
293/*
294 * These macros allow the user to suspend the handling of interrupt signals
295 * over a period of time. This is similar to SIGHOLD to or sigblock, but
296 * much more efficient and portable. (But hacking the kernel is so much
297 * more fun than worrying about efficiency and portability. :-))
298 */
299
300static void onint (void);
301static volatile int suppressint;
302static volatile int intpending;
303
304#define INTOFF suppressint++
305#ifdef ASH_BBAPPS_AS_BUILTINS
306#define INTON { if (--suppressint == 0 && intpending) onint(); }
307#else
308static void __inton (void);
309#define INTON __inton()
310#endif
311#define FORCEINTON {suppressint = 0; if (intpending) onint();}
312#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);
329static char *sstrdup (const char *);
330
331/*
332 * Parse trees for commands are allocated in lifo order, so we use a stack
333 * to make this more efficient, and also to avoid all sorts of exception
334 * handling code to handle interrupts in the middle of a parse.
335 *
336 * The size 504 was chosen because the Ultrix malloc handles that size
337 * well.
338 */
339
340#define MINSIZE 504 /* minimum size of a block */
341
342
343struct stack_block {
344 struct stack_block *prev;
345 char space[MINSIZE];
346};
347
348static struct stack_block stackbase;
349static struct stack_block *stackp = &stackbase;
350static struct stackmark *markp;
351static char *stacknxt = stackbase.space;
352static int stacknleft = MINSIZE;
353
354
355#define equal(s1, s2) (strcmp(s1, s2) == 0)
356
357#define stackblock() stacknxt
358#define stackblocksize() stacknleft
359#define STARTSTACKSTR(p) p = stackblock(), sstrnleft = stackblocksize()
360#define STPUTC(c, p) (--sstrnleft >= 0? (*p++ = (c)) : (p = growstackstr(), *p++ = (c)))
361#define CHECKSTRSPACE(n, p) { if (sstrnleft < n) p = makestrspace(n); }
362#define USTPUTC(c, p) (--sstrnleft, *p++ = (c))
363#define STACKSTRNUL(p) (sstrnleft == 0? (p = growstackstr(), *p = '\0') : (*p = '\0'))
364#define STUNPUTC(p) (++sstrnleft, --p)
365#define STTOPC(p) p[-1]
366#define STADJUST(amount, p) (p += (amount), sstrnleft -= (amount))
367#define grabstackstr(p) stalloc(stackblocksize() - sstrnleft)
368
369#define ckfree(p) free((pointer)(p))
370
371static char * makestrspace(size_t newlen);
372
373#ifdef DEBUG
374#define TRACE(param) trace param
375static void trace (const char *, ...);
376static void trargs (char **);
377static void showtree (union node *);
378static void trputc (int);
379static void trputs (const char *);
380static void opentrace (void);
381#else
382#define TRACE(param)
383#endif
384
385#define NSEMI 0
386#define NCMD 1
387#define NPIPE 2
388#define NREDIR 3
389#define NBACKGND 4
390#define NSUBSHELL 5
391#define NAND 6
392#define NOR 7
393#define NIF 8
394#define NWHILE 9
395#define NUNTIL 10
396#define NFOR 11
397#define NCASE 12
398#define NCLIST 13
399#define NDEFUN 14
400#define NARG 15
401#define NTO 16
402#define NFROM 17
403#define NFROMTO 18
404#define NAPPEND 19
405#define NTOOV 20
406#define NTOFD 21
407#define NFROMFD 22
408#define NHERE 23
409#define NXHERE 24
410#define NNOT 25
411
412/*
413 * expandarg() flags
414 */
415#define EXP_FULL 0x1 /* perform word splitting & file globbing */
416#define EXP_TILDE 0x2 /* do normal tilde expansion */
417#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
418#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
419#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
420#define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
421
422
423#define NOPTS 16
424
425static char optet_vals[NOPTS];
426
427static const char * const optlist[NOPTS] = {
428 "e" "errexit",
429 "f" "noglob",
430 "I" "ignoreeof",
431 "i" "interactive",
432 "m" "monitor",
433 "n" "noexec",
434 "s" "stdin",
435 "x" "xtrace",
436 "v" "verbose",
437 "V" "vi",
438 "E" "emacs",
439 "C" "noclobber",
440 "a" "allexport",
441 "b" "notify",
442 "u" "nounset",
443 "q" "quietprofile"
444};
445
446#define optent_name(optent) (optent+1)
447#define optent_letter(optent) optent[0]
448#define optent_val(optent) optet_vals[optent]
449
450#define eflag optent_val(0)
451#define fflag optent_val(1)
452#define Iflag optent_val(2)
453#define iflag optent_val(3)
454#define mflag optent_val(4)
455#define nflag optent_val(5)
456#define sflag optent_val(6)
457#define xflag optent_val(7)
458#define vflag optent_val(8)
459#define Vflag optent_val(9)
460#define Eflag optent_val(10)
461#define Cflag optent_val(11)
462#define aflag optent_val(12)
463#define bflag optent_val(13)
464#define uflag optent_val(14)
465#define qflag optent_val(15)
466
467
468/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
469#define FORK_FG 0
470#define FORK_BG 1
471#define FORK_NOJOB 2
472
473
474struct nbinary {
475 int type;
476 union node *ch1;
477 union node *ch2;
478};
479
480
481struct ncmd {
482 int type;
483 int backgnd;
484 union node *assign;
485 union node *args;
486 union node *redirect;
487};
488
489
490struct npipe {
491 int type;
492 int backgnd;
493 struct nodelist *cmdlist;
494};
495
496
497struct nredir {
498 int type;
499 union node *n;
500 union node *redirect;
501};
502
503
504struct nif {
505 int type;
506 union node *test;
507 union node *ifpart;
508 union node *elsepart;
509};
510
511
512struct nfor {
513 int type;
514 union node *args;
515 union node *body;
516 char *var;
517};
518
519
520struct ncase {
521 int type;
522 union node *expr;
523 union node *cases;
524};
525
526
527struct nclist {
528 int type;
529 union node *next;
530 union node *pattern;
531 union node *body;
532};
533
534
535struct narg {
536 int type;
537 union node *next;
538 char *text;
539 struct nodelist *backquote;
540};
541
542
543struct nfile {
544 int type;
545 union node *next;
546 int fd;
547 union node *fname;
548 char *expfname;
549};
550
551
552struct ndup {
553 int type;
554 union node *next;
555 int fd;
556 int dupfd;
557 union node *vname;
558};
559
560
561struct nhere {
562 int type;
563 union node *next;
564 int fd;
565 union node *doc;
566};
567
568
569struct nnot {
570 int type;
571 union node *com;
572};
573
574
575union node {
576 int type;
577 struct nbinary nbinary;
578 struct ncmd ncmd;
579 struct npipe npipe;
580 struct nredir nredir;
581 struct nif nif;
582 struct nfor nfor;
583 struct ncase ncase;
584 struct nclist nclist;
585 struct narg narg;
586 struct nfile nfile;
587 struct ndup ndup;
588 struct nhere nhere;
589 struct nnot nnot;
590};
591
592
593struct nodelist {
594 struct nodelist *next;
595 union node *n;
596};
597
598struct backcmd { /* result of evalbackcmd */
599 int fd; /* file descriptor to read from */
600 char *buf; /* buffer */
601 int nleft; /* number of chars in buffer */
602 struct job *jp; /* job structure for command */
603};
604
605struct cmdentry {
606 int cmdtype;
607 union param {
608 int index;
609 union node *func;
610 const struct builtincmd *cmd;
611 } u;
612};
613
614struct strlist {
615 struct strlist *next;
616 char *text;
617};
618
619
620struct arglist {
621 struct strlist *list;
622 struct strlist **lastp;
623};
624
625struct strpush {
626 struct strpush *prev; /* preceding string on stack */
627 char *prevstring;
628 int prevnleft;
629#ifdef ASH_ALIAS
630 struct alias *ap; /* if push was associated with an alias */
631#endif
632 char *string; /* remember the string since it may change */
633};
634
635struct parsefile {
636 struct parsefile *prev; /* preceding file on stack */
637 int linno; /* current line */
638 int fd; /* file descriptor (or -1 if string) */
639 int nleft; /* number of chars left in this line */
640 int lleft; /* number of chars left in this buffer */
641 char *nextc; /* next char in buffer */
642 char *buf; /* input buffer */
643 struct strpush *strpush; /* for pushing strings at this level */
644 struct strpush basestrpush; /* so pushing one is fast */
645};
646
647struct stackmark {
648 struct stack_block *stackp;
649 char *stacknxt;
650 int stacknleft;
651 struct stackmark *marknext;
652};
653
654struct shparam {
655 int nparam; /* # of positional parameters (without $0) */
656 unsigned char malloc; /* if parameter list dynamically allocated */
657 char **p; /* parameter list */
658 int optind; /* next parameter to be processed by getopts */
659 int optoff; /* used by getopts */
660};
661
662struct output {
663#ifdef USE_GLIBC_STDIO
664 FILE *stream;
665#endif
666 char *nextc;
667 int nleft;
668 char *buf;
669 int bufsize;
670 int fd;
671 short flags;
672};
673
674#define OUTBUFSIZ BUFSIZ
675#define MEM_OUT -3 /* output to dynamically allocated memory */
676
677
678#ifdef USE_GLIBC_STDIO
679static struct output output = {NULL, NULL, 0, NULL, 0, 1, 0};
680static struct output errout = {NULL, NULL, 0, NULL, 0, 2, 0};
681static struct output memout = {NULL, NULL, 0, NULL, 0, MEM_OUT, 0};
682#else
683static struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0};
684static struct output errout = {NULL, 0, NULL, 0, 2, 0};
685static struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0};
686#endif
687static struct output *out1 = &output;
688static struct output *out2 = &errout;
689
690#ifndef USE_GLIBC_STDIO
691static void outcslow (char, struct output *);
692#endif
693static void flushall (void);
694static void flushout (struct output *);
695static void freestdout (void);
696static void outfmt (struct output *, const char *, ...)
697 __attribute__((__format__(__printf__,2,3)));
698static void out1fmt (const char *, ...)
699 __attribute__((__format__(__printf__,1,2)));
700static void fmtstr (char *, size_t, const char *, ...)
701 __attribute__((__format__(__printf__,3,4)));
702#ifndef USE_GLIBC_STDIO
703static void doformat (struct output *, const char *, va_list);
704#endif
705static int xwrite (int, const char *, int);
706#ifdef USE_GLIBC_STDIO
707static void initstreams (void);
708static void openmemout (void);
709static int __closememout (void);
710#endif
711
712static void outstr(const char *p, struct output *file);
713
714#define OUTPUT_ERR 01 /* error occurred on output */
715
716#ifdef USE_GLIBC_STDIO
717#define outc(c, o) putc((c), (o)->stream)
718#define doformat(d, f, a) vfprintf((d)->stream, (f), (a))
719#else
720#define outc(c, file) (--(file)->nleft < 0? outcslow((c), (file)) : (*(file)->nextc = (c), (file)->nextc++))
721#endif
722#define out1c(c) outc((c), out1)
723#define out2c(c) outc((c), out2)
724#define out1str(s) outstr((s), out1)
725#define out2str(s) outstr((s), out2)
726#define outerr(f) ((f)->flags & OUTPUT_ERR)
727
728/* syntax table used when not in quotes */
729static const char basesyntax[257] = {
730 CENDFILE, CSPCL, CWORD, CCTL,
731 CCTL, CCTL, CCTL, CCTL,
732 CCTL, CCTL, CCTL, CWORD,
733 CWORD, CWORD, CWORD, CWORD,
734 CWORD, CWORD, CWORD, CWORD,
735 CWORD, CWORD, CWORD, CWORD,
736 CWORD, CWORD, CWORD, 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, CWORD, CWORD,
744 CWORD, CWORD, CWORD, CWORD,
745 CWORD, CWORD, CWORD, CWORD,
746 CWORD, CWORD, CWORD, CWORD,
747 CWORD, CWORD, CWORD, CWORD,
748 CWORD, CWORD, CWORD, CWORD,
749 CWORD, CWORD, CWORD, CWORD,
750 CWORD, CWORD, CWORD, CWORD,
751 CWORD, CWORD, CWORD, 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, CSPCL,
765 CNL, 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, CSPCL, CWORD,
771 CDQUOTE, CWORD, CVAR, CWORD,
772 CSPCL, CSQUOTE, CSPCL, CSPCL,
773 CWORD, CWORD, CWORD, CWORD,
774 CWORD, CWORD, CWORD, CWORD,
775 CWORD, CWORD, CWORD, CWORD,
776 CWORD, CWORD, CWORD, CWORD,
777 CWORD, CSPCL, CSPCL, CWORD,
778 CSPCL, 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 CWORD, CWORD, CWORD, CWORD,
785 CWORD, CWORD, CBACK, CWORD,
786 CWORD, CWORD, CBQUOTE, CWORD,
787 CWORD, CWORD, CWORD, CWORD,
788 CWORD, CWORD, CWORD, CWORD,
789 CWORD, CWORD, CWORD, CWORD,
790 CWORD, CWORD, CWORD, CWORD,
791 CWORD, CWORD, CWORD, CWORD,
792 CWORD, CWORD, CWORD, CWORD,
793 CWORD, CWORD, CSPCL, CENDVAR,
794 CWORD
795};
796
797/* syntax table used when in double quotes */
798static const char dqsyntax[257] = {
799 CENDFILE, CIGN, CWORD, CCTL,
800 CCTL, CCTL, CCTL, CCTL,
801 CCTL, CCTL, CCTL, CWORD,
802 CWORD, CWORD, CWORD, CWORD,
803 CWORD, CWORD, CWORD, CWORD,
804 CWORD, CWORD, CWORD, CWORD,
805 CWORD, CWORD, CWORD, 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, CWORD,
813 CWORD, CWORD, CWORD, CWORD,
814 CWORD, CWORD, CWORD, CWORD,
815 CWORD, CWORD, CWORD, CWORD,
816 CWORD, CWORD, CWORD, CWORD,
817 CWORD, CWORD, CWORD, CWORD,
818 CWORD, CWORD, CWORD, CWORD,
819 CWORD, CWORD, CWORD, CWORD,
820 CWORD, CWORD, CWORD, 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 CNL, 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, CCTL,
840 CENDQUOTE,CWORD, CVAR, CWORD,
841 CWORD, CWORD, CWORD, CWORD,
842 CCTL, CWORD, CWORD, CCTL,
843 CWORD, CCTL, CWORD, CWORD,
844 CWORD, CWORD, CWORD, CWORD,
845 CWORD, CWORD, CWORD, CWORD,
846 CCTL, CWORD, CWORD, CCTL,
847 CWORD, CCTL, 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 CWORD, CWORD, CWORD, CWORD,
854 CWORD, CCTL, CBACK, CCTL,
855 CWORD, CWORD, CBQUOTE, CWORD,
856 CWORD, CWORD, CWORD, CWORD,
857 CWORD, CWORD, CWORD, CWORD,
858 CWORD, CWORD, CWORD, CWORD,
859 CWORD, CWORD, CWORD, CWORD,
860 CWORD, CWORD, CWORD, CWORD,
861 CWORD, CWORD, CWORD, CWORD,
862 CWORD, CWORD, CWORD, CENDVAR,
863 CCTL
864};
865
866/* syntax table used when in single quotes */
867static const char sqsyntax[257] = {
868 CENDFILE, CIGN, CWORD, CCTL,
869 CCTL, CCTL, CCTL, CCTL,
870 CCTL, CCTL, CCTL, CWORD,
871 CWORD, CWORD, CWORD, CWORD,
872 CWORD, CWORD, CWORD, CWORD,
873 CWORD, CWORD, CWORD, CWORD,
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 CWORD, CWORD, CWORD, CWORD,
883 CWORD, CWORD, CWORD, CWORD,
884 CWORD, CWORD, CWORD, CWORD,
885 CWORD, CWORD, CWORD, CWORD,
886 CWORD, CWORD, CWORD, CWORD,
887 CWORD, CWORD, CWORD, CWORD,
888 CWORD, CWORD, CWORD, CWORD,
889 CWORD, CWORD, CWORD, 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 CNL, 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, CCTL,
909 CWORD, CWORD, CWORD, CWORD,
910 CWORD, CENDQUOTE,CWORD, CWORD,
911 CCTL, CWORD, CWORD, CCTL,
912 CWORD, CCTL, CWORD, CWORD,
913 CWORD, CWORD, CWORD, CWORD,
914 CWORD, CWORD, CWORD, CWORD,
915 CCTL, CWORD, CWORD, CCTL,
916 CWORD, CCTL, 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 CWORD, CWORD, CWORD, CWORD,
923 CWORD, CCTL, CCTL, CCTL,
924 CWORD, CWORD, CWORD, CWORD,
925 CWORD, CWORD, CWORD, CWORD,
926 CWORD, CWORD, CWORD, CWORD,
927 CWORD, CWORD, CWORD, CWORD,
928 CWORD, CWORD, CWORD, CWORD,
929 CWORD, CWORD, CWORD, CWORD,
930 CWORD, CWORD, CWORD, CWORD,
931 CWORD, CWORD, CWORD, CWORD,
932 CCTL
933};
934
935/* syntax table used when in arithmetic */
936static const char arisyntax[257] = {
937 CENDFILE, CIGN, CWORD, CCTL,
938 CCTL, CCTL, CCTL, CCTL,
939 CCTL, CCTL, CCTL, CWORD,
940 CWORD, CWORD, CWORD, CWORD,
941 CWORD, CWORD, CWORD, CWORD,
942 CWORD, CWORD, CWORD, CWORD,
943 CWORD, CWORD, CWORD, 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, CWORD,
951 CWORD, CWORD, CWORD, CWORD,
952 CWORD, CWORD, CWORD, CWORD,
953 CWORD, CWORD, CWORD, CWORD,
954 CWORD, CWORD, CWORD, CWORD,
955 CWORD, CWORD, CWORD, CWORD,
956 CWORD, CWORD, CWORD, CWORD,
957 CWORD, CWORD, CWORD, CWORD,
958 CWORD, CWORD, CWORD, CWORD,
959 CWORD, CWORD, CWORD, CWORD,
960 CWORD, CWORD, CWORD, CWORD,
961 CWORD, CWORD, CWORD, CWORD,
962 CWORD, CWORD, CWORD, CWORD,
963 CWORD, CWORD, CWORD, CWORD,
964 CWORD, CWORD, CWORD, CWORD,
965 CWORD, CWORD, CWORD, CWORD,
966 CWORD, CWORD, CWORD, CWORD,
967 CWORD, CWORD, CWORD, CWORD,
968 CWORD, CWORD, CWORD, CWORD,
969 CWORD, CWORD, CWORD, CWORD,
970 CWORD, CWORD, CWORD, CWORD,
971 CWORD, CWORD, CWORD, CWORD,
972 CNL, CWORD, CWORD, CWORD,
973 CWORD, CWORD, CWORD, CWORD,
974 CWORD, CWORD, CWORD, CWORD,
975 CWORD, CWORD, CWORD, CWORD,
976 CWORD, CWORD, CWORD, CWORD,
977 CWORD, CWORD, CWORD, CWORD,
978 CDQUOTE, CWORD, CVAR, CWORD,
979 CWORD, CSQUOTE, CLP, CRP,
980 CWORD, CWORD, CWORD, CWORD,
981 CWORD, CWORD, CWORD, CWORD,
982 CWORD, CWORD, CWORD, CWORD,
983 CWORD, CWORD, CWORD, CWORD,
984 CWORD, CWORD, CWORD, CWORD,
985 CWORD, CWORD, CWORD, CWORD,
986 CWORD, CWORD, CWORD, CWORD,
987 CWORD, CWORD, CWORD, CWORD,
988 CWORD, CWORD, CWORD, CWORD,
989 CWORD, CWORD, CWORD, CWORD,
990 CWORD, CWORD, CWORD, CWORD,
991 CWORD, CWORD, CWORD, CWORD,
992 CWORD, CWORD, CBACK, CWORD,
993 CWORD, CWORD, CBQUOTE, CWORD,
994 CWORD, CWORD, CWORD, CWORD,
995 CWORD, CWORD, CWORD, CWORD,
996 CWORD, CWORD, CWORD, CWORD,
997 CWORD, CWORD, CWORD, CWORD,
998 CWORD, CWORD, CWORD, CWORD,
999 CWORD, CWORD, CWORD, CWORD,
1000 CWORD, CWORD, CWORD, CENDVAR,
1001 CWORD
1002};
1003
1004/* character classification table */
1005static const char is_type[257] = {
1006 0, 0, 0, 0,
1007 0, 0, 0, 0,
1008 0, 0, 0, 0,
1009 0, 0, 0, 0,
1010 0, 0, 0, 0,
1011 0, 0, 0, 0,
1012 0, 0, 0, 0,
1013 0, 0, 0, 0,
1014 0, 0, 0, 0,
1015 0, 0, 0, 0,
1016 0, 0, 0, 0,
1017 0, 0, 0, 0,
1018 0, 0, 0, 0,
1019 0, 0, 0, 0,
1020 0, 0, 0, 0,
1021 0, 0, 0, 0,
1022 0, 0, 0, 0,
1023 0, 0, 0, 0,
1024 0, 0, 0, 0,
1025 0, 0, 0, 0,
1026 0, 0, 0, 0,
1027 0, 0, 0, 0,
1028 0, 0, 0, 0,
1029 0, 0, 0, 0,
1030 0, 0, 0, 0,
1031 0, 0, 0, 0,
1032 0, 0, 0, 0,
1033 0, 0, 0, 0,
1034 0, 0, 0, 0,
1035 0, 0, 0, 0,
1036 0, 0, 0, 0,
1037 0, 0, 0, 0,
1038 0, 0, 0, 0,
1039 0, 0, 0, 0,
1040 0, 0, 0, 0,
1041 0, 0, 0, 0,
1042 0, 0, 0, 0,
1043 0, 0, 0, 0,
1044 0, 0, 0, 0,
1045 0, 0, 0, 0,
1046 0, 0, 0, ISSPECL,
1047 0, ISSPECL, ISSPECL, 0,
1048 0, 0, 0, 0,
1049 ISSPECL, 0, 0, ISSPECL,
1050 0, 0, ISDIGIT, ISDIGIT,
1051 ISDIGIT, ISDIGIT, ISDIGIT, ISDIGIT,
1052 ISDIGIT, ISDIGIT, ISDIGIT, ISDIGIT,
1053 0, 0, 0, 0,
1054 0, ISSPECL, ISSPECL, ISUPPER,
1055 ISUPPER, ISUPPER, ISUPPER, ISUPPER,
1056 ISUPPER, ISUPPER, ISUPPER, ISUPPER,
1057 ISUPPER, ISUPPER, ISUPPER, ISUPPER,
1058 ISUPPER, ISUPPER, ISUPPER, ISUPPER,
1059 ISUPPER, ISUPPER, ISUPPER, ISUPPER,
1060 ISUPPER, ISUPPER, ISUPPER, ISUPPER,
1061 ISUPPER, 0, 0, 0,
1062 0, ISUNDER, 0, ISLOWER,
1063 ISLOWER, ISLOWER, ISLOWER, ISLOWER,
1064 ISLOWER, ISLOWER, ISLOWER, ISLOWER,
1065 ISLOWER, ISLOWER, ISLOWER, ISLOWER,
1066 ISLOWER, ISLOWER, ISLOWER, ISLOWER,
1067 ISLOWER, ISLOWER, ISLOWER, ISLOWER,
1068 ISLOWER, ISLOWER, ISLOWER, ISLOWER,
1069 ISLOWER, 0, 0, 0,
1070 0
1071};
1072
1073/* Array indicating which tokens mark the end of a list */
1074static const char tokendlist[] = {
1075 1,
1076 0,
1077 0,
1078 0,
1079 0,
1080 0,
1081 0,
1082 0,
1083 1,
1084 1,
1085 1,
1086 0,
1087 0,
1088 0,
1089 0,
1090 0,
1091 1,
1092 1,
1093 1,
1094 1,
1095 1,
1096 1,
1097 0,
1098 0,
1099 0,
1100 1,
1101 0,
1102 0,
1103 0,
1104 1,
1105};
1106
1107static const char *const tokname[] = {
1108 "end of file",
1109 "newline",
1110 "\";\"",
1111 "\"&\"",
1112 "\"&&\"",
1113 "\"||\"",
1114 "\"|\"",
1115 "\"(\"",
1116 "\")\"",
1117 "\";;\"",
1118 "\"`\"",
1119 "redirection",
1120 "word",
1121 "assignment",
1122 "\"!\"",
1123 "\"case\"",
1124 "\"do\"",
1125 "\"done\"",
1126 "\"elif\"",
1127 "\"else\"",
1128 "\"esac\"",
1129 "\"fi\"",
1130 "\"for\"",
1131 "\"if\"",
1132 "\"in\"",
1133 "\"then\"",
1134 "\"until\"",
1135 "\"while\"",
1136 "\"{\"",
1137 "\"}\"",
1138};
1139
1140#define KWDOFFSET 14
1141
1142static const char *const parsekwd[] = {
1143 "!",
1144 "case",
1145 "do",
1146 "done",
1147 "elif",
1148 "else",
1149 "esac",
1150 "fi",
1151 "for",
1152 "if",
1153 "in",
1154 "then",
1155 "until",
1156 "while",
1157 "{",
1158 "}"
1159};
1160
1161
1162static int plinno = 1; /* input line number */
1163
1164static int parselleft; /* copy of parsefile->lleft */
1165
1166static struct parsefile basepf; /* top level input file */
1167static char basebuf[BUFSIZ]; /* buffer for top level input file */
1168static struct parsefile *parsefile = &basepf; /* current input file */
1169
1170/*
1171 * NEOF is returned by parsecmd when it encounters an end of file. It
1172 * must be distinct from NULL, so we use the address of a variable that
1173 * happens to be handy.
1174 */
1175
1176static int tokpushback; /* last token pushed back */
1177#define NEOF ((union node *)&tokpushback)
1178static int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */
1179
1180
1181static void error (const char *, ...) __attribute__((__noreturn__));
1182static void exerror (int, const char *, ...) __attribute__((__noreturn__));
1183static void shellexec (char **, char **, const char *, int)
1184 __attribute__((noreturn));
1185static void exitshell (int) __attribute__((noreturn));
1186
1187static int goodname(const char *);
1188static void ignoresig (int);
1189static void onsig (int);
1190static void dotrap (void);
1191static int decode_signal (const char *, int);
1192
1193static void shprocvar(void);
1194static void deletefuncs(void);
1195static void setparam (char **);
1196static void freeparam (volatile struct shparam *);
1197
1198/* reasons for skipping commands (see comment on breakcmd routine) */
1199#define SKIPBREAK 1
1200#define SKIPCONT 2
1201#define SKIPFUNC 3
1202#define SKIPFILE 4
1203
1204/* values of cmdtype */
1205#define CMDUNKNOWN -1 /* no entry in table for command */
1206#define CMDNORMAL 0 /* command is an executable program */
1207#define CMDBUILTIN 1 /* command is a shell builtin */
1208#define CMDFUNCTION 2 /* command is a shell function */
1209
1210#define DO_ERR 1 /* find_command prints errors */
1211#define DO_ABS 2 /* find_command checks absolute paths */
1212#define DO_NOFUN 4 /* find_command ignores functions */
1213#define DO_BRUTE 8 /* find_command ignores hash table */
1214
1215/*
1216 * Shell variables.
1217 */
1218
1219/* flags */
1220#define VEXPORT 0x01 /* variable is exported */
1221#define VREADONLY 0x02 /* variable cannot be modified */
1222#define VSTRFIXED 0x04 /* variable struct is staticly allocated */
1223#define VTEXTFIXED 0x08 /* text is staticly allocated */
1224#define VSTACK 0x10 /* text is allocated on the stack */
1225#define VUNSET 0x20 /* the variable is not set */
1226#define VNOFUNC 0x40 /* don't call the callback function */
1227
1228
1229struct var {
1230 struct var *next; /* next entry in hash list */
1231 int flags; /* flags are defined above */
1232 char *text; /* name=value */
1233 void (*func) (const char *);
1234 /* function to be called when */
1235 /* the variable gets set/unset */
1236};
1237
1238struct localvar {
1239 struct localvar *next; /* next local variable in list */
1240 struct var *vp; /* the variable that was made local */
1241 int flags; /* saved flags */
1242 char *text; /* saved text */
1243};
1244
1245
1246#if defined(__GLIBC__) && !defined(FNMATCH_BROKEN)
1247#define rmescapes(p) _rmescapes((p), 0)
1248static char *_rmescapes (char *, int);
1249#else
1250static void rmescapes (char *);
1251#endif
1252
1253static int casematch (union node *, const char *);
1254static void clearredir(void);
1255static void popstring(void);
1256static void readcmdfile (const char *);
1257
1258static int number (const char *);
1259static int is_number (const char *, int *num);
1260static char *single_quote (const char *);
1261static int nextopt (const char *);
1262
1263static void redirect (union node *, int);
1264static void popredir (void);
1265static int dup_as_newfd (int, int);
1266
1267static void changepath(const char *newval);
1268static void getoptsreset(const char *value);
1269
1270
1271static int parsenleft; /* copy of parsefile->nleft */
1272static char *parsenextc; /* copy of parsefile->nextc */
1273static int rootpid; /* pid of main shell */
1274static int rootshell; /* true if we aren't a child of the main shell */
1275
1276static const char spcstr[] = " ";
1277static const char snlfmt[] = "%s\n";
1278
1279static int sstrnleft;
1280static int herefd = -1;
1281
1282static struct localvar *localvars;
1283
1284static struct var vifs;
1285static struct var vmail;
1286static struct var vmpath;
1287static struct var vpath;
1288static struct var vps1;
1289static struct var vps2;
1290static struct var voptind;
1291#ifdef BB_LOCALE_SUPPORT
1292static struct var vlc_all;
1293static struct var vlc_ctype;
1294#endif
1295
1296struct varinit {
1297 struct var *var;
1298 int flags;
1299 const char *text;
1300 void (*func) (const char *);
1301};
1302
1303static const char defpathvar[] =
1304 "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
1305#define defpath (defpathvar + 5)
1306
1307#ifdef IFS_BROKEN
1308static const char defifsvar[] = "IFS= \t\n";
1309#define defifs (defifsvar + 4)
1310#else
1311static const char defifs[] = " \t\n";
1312#endif
1313
1314static const struct varinit varinit[] = {
1315#ifdef IFS_BROKEN
1316 { &vifs, VSTRFIXED|VTEXTFIXED, defifsvar,
1317#else
1318 { &vifs, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS=",
1319#endif
1320 NULL },
1321 { &vmail, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL=",
1322 NULL },
1323 { &vmpath, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH=",
1324 NULL },
1325 { &vpath, VSTRFIXED|VTEXTFIXED, defpathvar,
1326 changepath },
1327 /*
1328 * vps1 depends on uid
1329 */
1330 { &vps2, VSTRFIXED|VTEXTFIXED, "PS2=> ",
1331 NULL },
1332 { &voptind, VSTRFIXED|VTEXTFIXED, "OPTIND=1",
1333 getoptsreset },
1334#ifdef BB_LOCALE_SUPPORT
1335 { &vlc_all, VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL=",
1336 change_lc_all },
1337 { &vlc_ctype, VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE=",
1338 change_lc_ctype },
1339#endif
1340 { NULL, 0, NULL,
1341 NULL }
1342};
1343
1344#define VTABSIZE 39
1345
1346static struct var *vartab[VTABSIZE];
1347
1348/*
1349 * The following macros access the values of the above variables.
1350 * They have to skip over the name. They return the null string
1351 * for unset variables.
1352 */
1353
1354#define ifsval() (vifs.text + 4)
1355#define ifsset() ((vifs.flags & VUNSET) == 0)
1356#define mailval() (vmail.text + 5)
1357#define mpathval() (vmpath.text + 9)
1358#define pathval() (vpath.text + 5)
1359#define ps1val() (vps1.text + 4)
1360#define ps2val() (vps2.text + 4)
1361#define optindval() (voptind.text + 7)
1362
1363#define mpathset() ((vmpath.flags & VUNSET) == 0)
1364
1365static void initvar (void);
1366static void setvar (const char *, const char *, int);
1367static void setvareq (char *, int);
1368static void listsetvar (struct strlist *);
1369static char *lookupvar (const char *);
1370static char *bltinlookup (const char *);
1371static char **environment (void);
1372static int showvarscmd (int, char **);
1373static void mklocal (char *);
1374static void poplocalvars (void);
1375static int unsetvar (const char *);
1376static int varequal (const char *, const char *);
1377
1378
1379static char *arg0; /* value of $0 */
1380static struct shparam shellparam; /* current positional parameters */
1381static char **argptr; /* argument list for builtin commands */
1382static char *optionarg; /* set by nextopt (like getopt) */
1383static char *optptr; /* used by nextopt */
1384static char *minusc; /* argument to -c option */
1385
1386
1387#ifdef ASH_ALIAS
1388
1389#define ALIASINUSE 1
1390#define ALIASDEAD 2
1391
1392struct alias {
1393 struct alias *next;
1394 char *name;
1395 char *val;
1396 int flag;
1397};
1398
1399static struct alias *atab[ATABSIZE];
1400
1401static void setalias (char *, char *);
1402static struct alias **hashalias (const char *);
1403static struct alias *freealias (struct alias *);
1404static struct alias **__lookupalias (const char *);
Eric Andersencb57d552001-06-28 07:25:16 +00001405
1406static void
1407setalias(name, val)
1408 char *name, *val;
1409{
1410 struct alias *ap, **app;
1411
1412 app = __lookupalias(name);
1413 ap = *app;
1414 INTOFF;
1415 if (ap) {
1416 if (!(ap->flag & ALIASINUSE)) {
1417 ckfree(ap->val);
1418 }
Eric Andersen2870d962001-07-02 17:27:21 +00001419 ap->val = savestr(val);
Eric Andersencb57d552001-06-28 07:25:16 +00001420 ap->flag &= ~ALIASDEAD;
1421 } else {
1422 /* not found */
1423 ap = ckmalloc(sizeof (struct alias));
1424 ap->name = savestr(name);
1425 ap->val = savestr(val);
1426 ap->flag = 0;
1427 ap->next = 0;
1428 *app = ap;
1429 }
1430 INTON;
1431}
1432
1433static int
Eric Andersen2870d962001-07-02 17:27:21 +00001434unalias(char *name)
1435{
Eric Andersencb57d552001-06-28 07:25:16 +00001436 struct alias **app;
1437
1438 app = __lookupalias(name);
1439
1440 if (*app) {
1441 INTOFF;
1442 *app = freealias(*app);
1443 INTON;
1444 return (0);
1445 }
1446
1447 return (1);
1448}
1449
Eric Andersencb57d552001-06-28 07:25:16 +00001450static void
Eric Andersen2870d962001-07-02 17:27:21 +00001451rmaliases(void)
1452{
Eric Andersencb57d552001-06-28 07:25:16 +00001453 struct alias *ap, **app;
1454 int i;
1455
1456 INTOFF;
1457 for (i = 0; i < ATABSIZE; i++) {
1458 app = &atab[i];
1459 for (ap = *app; ap; ap = *app) {
1460 *app = freealias(*app);
1461 if (ap == *app) {
1462 app = &ap->next;
1463 }
1464 }
1465 }
1466 INTON;
1467}
1468
Eric Andersen2870d962001-07-02 17:27:21 +00001469static struct alias *
1470lookupalias(const char *name, int check)
Eric Andersencb57d552001-06-28 07:25:16 +00001471{
1472 struct alias *ap = *__lookupalias(name);
1473
1474 if (check && ap && (ap->flag & ALIASINUSE))
1475 return (NULL);
1476 return (ap);
1477}
1478
Eric Andersen2870d962001-07-02 17:27:21 +00001479static void
1480printalias(const struct alias *ap) {
1481 char *p;
1482
1483 p = single_quote(ap->val);
1484 out1fmt("alias %s=%s\n", ap->name, p);
1485 stunalloc(p);
1486}
1487
Eric Andersencb57d552001-06-28 07:25:16 +00001488
1489/*
1490 * TODO - sort output
1491 */
1492static int
Eric Andersen2870d962001-07-02 17:27:21 +00001493aliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00001494{
1495 char *n, *v;
1496 int ret = 0;
1497 struct alias *ap;
1498
1499 if (argc == 1) {
1500 int i;
1501
1502 for (i = 0; i < ATABSIZE; i++)
1503 for (ap = atab[i]; ap; ap = ap->next) {
1504 printalias(ap);
1505 }
1506 return (0);
1507 }
1508 while ((n = *++argv) != NULL) {
1509 if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */
1510 if ((ap = *__lookupalias(n)) == NULL) {
1511 outfmt(out2, "%s: %s not found\n", "alias", n);
1512 ret = 1;
1513 } else
1514 printalias(ap);
1515 }
1516 else {
1517 *v++ = '\0';
1518 setalias(n, v);
1519 }
1520 }
1521
1522 return (ret);
1523}
1524
1525static int
Eric Andersen2870d962001-07-02 17:27:21 +00001526unaliascmd(int argc, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00001527{
1528 int i;
1529
1530 while ((i = nextopt("a")) != '\0') {
1531 if (i == 'a') {
1532 rmaliases();
1533 return (0);
1534 }
1535 }
1536 for (i = 0; *argptr; argptr++) {
1537 if (unalias(*argptr)) {
1538 outfmt(out2, "%s: %s not found\n", "unalias", *argptr);
1539 i = 1;
1540 }
1541 }
1542
1543 return (i);
1544}
1545
1546static struct alias **
1547hashalias(p)
1548 const char *p;
1549 {
1550 unsigned int hashval;
1551
1552 hashval = *p << 4;
1553 while (*p)
1554 hashval+= *p++;
1555 return &atab[hashval % ATABSIZE];
1556}
1557
1558static struct alias *
1559freealias(struct alias *ap) {
1560 struct alias *next;
1561
1562 if (ap->flag & ALIASINUSE) {
1563 ap->flag |= ALIASDEAD;
1564 return ap;
1565 }
1566
1567 next = ap->next;
1568 ckfree(ap->name);
1569 ckfree(ap->val);
1570 ckfree(ap);
1571 return next;
1572}
1573
Eric Andersencb57d552001-06-28 07:25:16 +00001574
1575static struct alias **
1576__lookupalias(const char *name) {
1577 struct alias **app = hashalias(name);
1578
1579 for (; *app; app = &(*app)->next) {
1580 if (equal(name, (*app)->name)) {
1581 break;
1582 }
1583 }
1584
1585 return app;
1586}
Eric Andersen2870d962001-07-02 17:27:21 +00001587#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001588
1589#ifdef ASH_MATH_SUPPORT
1590/* The generated file arith.c has been snipped. If you want this
1591 * stuff back in, feel free to add it to your own copy. */
Eric Andersen2870d962001-07-02 17:27:21 +00001592#define ARITH_NUM 257
1593#define ARITH_LPAREN 258
1594#define ARITH_RPAREN 259
1595#define ARITH_OR 260
1596#define ARITH_AND 261
1597#define ARITH_BOR 262
1598#define ARITH_BXOR 263
1599#define ARITH_BAND 264
1600#define ARITH_EQ 265
1601#define ARITH_NE 266
1602#define ARITH_LT 267
1603#define ARITH_GT 268
1604#define ARITH_GE 269
1605#define ARITH_LE 270
1606#define ARITH_LSHIFT 271
1607#define ARITH_RSHIFT 272
1608#define ARITH_ADD 273
1609#define ARITH_SUB 274
1610#define ARITH_MUL 275
1611#define ARITH_DIV 276
1612#define ARITH_REM 277
1613#define ARITH_UNARYMINUS 278
1614#define ARITH_UNARYPLUS 279
1615#define ARITH_NOT 280
1616#define ARITH_BNOT 281
1617
1618static void expari (int);
1619/* From arith.y */
1620static int arith (const char *);
1621static int expcmd (int , char **);
1622static void arith_lex_reset (void);
1623static int yylex (void);
1624
Eric Andersencb57d552001-06-28 07:25:16 +00001625#endif
1626
Eric Andersen2870d962001-07-02 17:27:21 +00001627static char *trap[NSIG]; /* trap handler commands */
1628static char sigmode[NSIG - 1]; /* current value of signal */
1629static char gotsig[NSIG - 1]; /* indicates specified signal received */
1630static int pendingsigs; /* indicates some signal received */
1631
Eric Andersencb57d552001-06-28 07:25:16 +00001632/*
1633 * This file was generated by the mkbuiltins program.
1634 */
1635
Eric Andersen2870d962001-07-02 17:27:21 +00001636#ifdef JOBS
1637static int bgcmd (int, char **);
1638static int fgcmd (int, char **);
1639static int killcmd (int, char **);
1640#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001641static int bltincmd (int, char **);
Eric Andersen2870d962001-07-02 17:27:21 +00001642static int cdcmd (int, char **);
1643static int breakcmd (int, char **);
1644#ifdef ASH_CMDCMD
1645static int commandcmd (int, char **);
1646#endif
1647static int dotcmd (int, char **);
1648static int evalcmd (int, char **);
1649static int execcmd (int, char **);
1650static int exitcmd (int, char **);
1651static int exportcmd (int, char **);
1652static int histcmd (int, char **);
1653static int hashcmd (int, char **);
1654static int jobscmd (int, char **);
1655static int localcmd (int, char **);
1656#ifdef ASH_PWD
1657static int pwdcmd (int, char **);
1658#endif
1659static int readcmd (int, char **);
1660static int returncmd (int, char **);
1661static int setcmd (int, char **);
1662static int setvarcmd (int, char **);
1663static int shiftcmd (int, char **);
1664static int trapcmd (int, char **);
1665static int umaskcmd (int, char **);
1666#ifdef ASH_ALIAS
1667static int aliascmd (int, char **);
1668static int unaliascmd (int, char **);
1669#endif
1670static int unsetcmd (int, char **);
1671static int waitcmd (int, char **);
1672static int ulimitcmd (int, char **);
1673static int timescmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001674#ifdef ASH_MATH_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00001675static int expcmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001676#endif
1677#ifdef ASH_TYPE
Eric Andersen2870d962001-07-02 17:27:21 +00001678static int typecmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001679#endif
1680#ifdef ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00001681static int getoptscmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001682#endif
1683
Eric Andersen2870d962001-07-02 17:27:21 +00001684#ifndef BB_TRUE_FALSE
1685# ifdef ASH_BBAPPS_AS_BUILTINS
1686static int true_main (int, char **);
1687static int false_main (int, char **);
1688# endif
1689#endif
1690
1691static void setpwd (const char *, int);
1692
1693
1694#define BUILTIN_NOSPEC "0"
1695#define BUILTIN_SPECIAL "1"
1696#define BUILTIN_REGULAR "2"
1697#define BUILTIN_ASSIGN "4"
1698#define BUILTIN_SPEC_ASSG "5"
1699#define BUILTIN_REG_ASSG "6"
1700
1701#define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1702#define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
1703#define IS_BUILTIN_ASSIGN(builtincmd) ((builtincmd)->name[0] & 4)
1704
1705struct builtincmd {
1706 const char *name;
1707 int (*const builtinfunc) (int, char **);
1708 //unsigned flags;
1709};
1710
Eric Andersencb57d552001-06-28 07:25:16 +00001711
1712/* It is CRUCIAL that this listing be kept in ascii order, otherwise
1713 * the binary search in find_builtin() will stop working. If you value
1714 * your kneecaps, you'll be sure to *make sure* that any changes made
1715 * to this array result in the listing remaining in ascii order. You
1716 * have been warned.
1717 */
1718static const struct builtincmd builtincmds[] = {
Eric Andersen2870d962001-07-02 17:27:21 +00001719 { BUILTIN_SPECIAL ".", dotcmd },
1720 { BUILTIN_SPECIAL ":", true_main },
1721#ifdef ASH_ALIAS
1722 { BUILTIN_REG_ASSG "alias", aliascmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001723#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001724#ifdef JOBS
1725 { BUILTIN_REGULAR "bg", bgcmd },
1726#endif
1727 { BUILTIN_SPECIAL "break", breakcmd },
Eric Andersen8df319b2001-07-05 05:24:12 +00001728 { BUILTIN_SPECIAL "builtin", bltincmd }, /* Do not disable this builtin ever or bad things happen */
Eric Andersen2870d962001-07-02 17:27:21 +00001729 { BUILTIN_REGULAR "cd", cdcmd },
1730#ifdef ASH_BBAPPS_AS_BUILTINS
1731 { BUILTIN_NOSPEC "chdir", cdcmd },
1732#endif
1733#ifdef ASH_CMDCMD
1734 { BUILTIN_REGULAR "command", commandcmd },
1735#endif
1736 { BUILTIN_SPECIAL "continue", breakcmd },
1737 { BUILTIN_SPECIAL "eval", evalcmd },
1738 { BUILTIN_SPECIAL "exec", execcmd },
1739 { BUILTIN_SPECIAL "exit", exitcmd },
1740#ifdef ASH_MATH_SUPPORT
1741 { BUILTIN_NOSPEC "exp", expcmd },
1742#endif
1743 { BUILTIN_SPEC_ASSG "export", exportcmd },
1744#ifdef ASH_BBAPPS_AS_BUILTINS
1745 { BUILTIN_REGULAR "false", false_main },
1746#endif
1747 { BUILTIN_REGULAR "fc", histcmd },
1748#ifdef JOBS
1749 { BUILTIN_REGULAR "fg", fgcmd },
1750#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001751#ifdef ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00001752 { BUILTIN_REGULAR "getopts", getoptscmd },
1753#endif
1754 { BUILTIN_NOSPEC "hash", hashcmd },
1755 { BUILTIN_REGULAR "jobs", jobscmd },
1756#ifdef JOBS
1757 { BUILTIN_REGULAR "kill", killcmd },
1758#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001759#ifdef ASH_MATH_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00001760 { BUILTIN_NOSPEC "let", expcmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001761#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001762 { BUILTIN_ASSIGN "local", localcmd },
1763#ifdef ASH_PWD
1764 { BUILTIN_NOSPEC "pwd", pwdcmd },
1765#endif
1766 { BUILTIN_REGULAR "read", readcmd },
1767 { BUILTIN_SPEC_ASSG "readonly", exportcmd },
1768 { BUILTIN_SPECIAL "return", returncmd },
1769 { BUILTIN_SPECIAL "set", setcmd },
1770 { BUILTIN_NOSPEC "setvar", setvarcmd },
1771 { BUILTIN_SPECIAL "shift", shiftcmd },
1772 { BUILTIN_SPECIAL "times", timescmd },
1773 { BUILTIN_SPECIAL "trap", trapcmd },
1774#ifdef ASH_BBAPPS_AS_BUILTINS
1775 { BUILTIN_REGULAR "true", true_main },
1776#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001777#ifdef ASH_TYPE
Eric Andersen2870d962001-07-02 17:27:21 +00001778 { BUILTIN_NOSPEC "type", typecmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001779#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001780 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
1781 { BUILTIN_REGULAR "umask", umaskcmd },
1782#ifdef ASH_ALIAS
1783 { BUILTIN_REGULAR "unalias", unaliascmd },
1784#endif
1785 { BUILTIN_SPECIAL "unset", unsetcmd },
1786 { BUILTIN_REGULAR "wait", waitcmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001787};
1788#define NUMBUILTINS (sizeof (builtincmds) / sizeof (struct builtincmd) )
1789
Eric Andersen2870d962001-07-02 17:27:21 +00001790static const struct builtincmd *DOTCMD = &builtincmds[0];
1791static struct builtincmd *BLTINCMD;
1792static struct builtincmd *EXECCMD;
1793static struct builtincmd *EVALCMD;
Eric Andersencb57d552001-06-28 07:25:16 +00001794
Eric Andersen2870d962001-07-02 17:27:21 +00001795/* states */
1796#define JOBSTOPPED 1 /* all procs are stopped */
1797#define JOBDONE 2 /* all procs are completed */
Eric Andersencb57d552001-06-28 07:25:16 +00001798
Eric Andersen2870d962001-07-02 17:27:21 +00001799/*
1800 * A job structure contains information about a job. A job is either a
1801 * single process or a set of processes contained in a pipeline. In the
1802 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1803 * array of pids.
1804 */
Eric Andersencb57d552001-06-28 07:25:16 +00001805
Eric Andersen2870d962001-07-02 17:27:21 +00001806struct procstat {
1807 pid_t pid; /* process id */
1808 int status; /* status flags (defined above) */
1809 char *cmd; /* text of command being run */
1810};
Eric Andersencb57d552001-06-28 07:25:16 +00001811
Eric Andersen2870d962001-07-02 17:27:21 +00001812
1813static int job_warning; /* user was warned about stopped jobs */
1814
1815#ifdef JOBS
1816static void setjobctl(int enable);
1817#else
1818#define setjobctl(on) /* do nothing */
Eric Andersencb57d552001-06-28 07:25:16 +00001819#endif
1820
Eric Andersen2870d962001-07-02 17:27:21 +00001821
1822struct job {
1823 struct procstat ps0; /* status of process */
1824 struct procstat *ps; /* status or processes when more than one */
1825 short nprocs; /* number of processes */
1826 short pgrp; /* process group of this job */
1827 char state; /* true if job is finished */
1828 char used; /* true if this entry is in used */
1829 char changed; /* true if status has changed */
1830#ifdef JOBS
1831 char jobctl; /* job running under job control */
1832#endif
1833};
1834
1835static struct job *jobtab; /* array of jobs */
1836static int njobs; /* size of array */
1837static int backgndpid = -1; /* pid of last background process */
1838#ifdef JOBS
1839static int initialpgrp; /* pgrp of shell on invocation */
1840static int curjob; /* current job */
1841static int jobctl;
1842#endif
1843static int intreceived;
1844
1845static struct job *makejob (union node *, int);
1846static int forkshell (struct job *, union node *, int);
1847static int waitforjob (struct job *);
1848
1849static int docd (char *, int);
1850static char *getcomponent (void);
1851static void updatepwd (const char *);
1852static void getpwd (void);
1853
1854static char *padvance (const char **, const char *);
1855
1856static char nullstr[1]; /* zero length string */
1857static char *curdir = nullstr; /* current working directory */
1858static char *cdcomppath;
1859
Eric Andersencb57d552001-06-28 07:25:16 +00001860static int
1861cdcmd(argc, argv)
1862 int argc;
1863 char **argv;
1864{
1865 const char *dest;
1866 const char *path;
1867 char *p;
1868 struct stat statb;
1869 int print = 0;
1870
1871 nextopt(nullstr);
1872 if ((dest = *argptr) == NULL && (dest = bltinlookup("HOME")) == NULL)
1873 error("HOME not set");
1874 if (*dest == '\0')
Eric Andersen2870d962001-07-02 17:27:21 +00001875 dest = ".";
Eric Andersencb57d552001-06-28 07:25:16 +00001876 if (dest[0] == '-' && dest[1] == '\0') {
1877 dest = bltinlookup("OLDPWD");
1878 if (!dest || !*dest) {
1879 dest = curdir;
1880 }
1881 print = 1;
1882 if (dest)
Eric Andersen2870d962001-07-02 17:27:21 +00001883 print = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00001884 else
Eric Andersen2870d962001-07-02 17:27:21 +00001885 dest = ".";
Eric Andersencb57d552001-06-28 07:25:16 +00001886 }
1887 if (*dest == '/' || (path = bltinlookup("CDPATH")) == NULL)
1888 path = nullstr;
1889 while ((p = padvance(&path, dest)) != NULL) {
1890 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
1891 if (!print) {
1892 /*
1893 * XXX - rethink
1894 */
1895 if (p[0] == '.' && p[1] == '/' && p[2] != '\0')
1896 p += 2;
1897 print = strcmp(p, dest);
1898 }
1899 if (docd(p, print) >= 0)
1900 return 0;
1901
1902 }
1903 }
1904 error("can't cd to %s", dest);
1905 /* NOTREACHED */
1906}
1907
1908
1909/*
1910 * Actually do the chdir. In an interactive shell, print the
1911 * directory name if "print" is nonzero.
1912 */
1913
1914static int
1915docd(dest, print)
1916 char *dest;
1917 int print;
1918{
1919 char *p;
1920 char *q;
1921 char *component;
1922 struct stat statb;
1923 int first;
1924 int badstat;
1925
1926 TRACE(("docd(\"%s\", %d) called\n", dest, print));
1927
1928 /*
1929 * Check each component of the path. If we find a symlink or
1930 * something we can't stat, clear curdir to force a getcwd()
1931 * next time we get the value of the current directory.
1932 */
1933 badstat = 0;
1934 cdcomppath = sstrdup(dest);
1935 STARTSTACKSTR(p);
1936 if (*dest == '/') {
1937 STPUTC('/', p);
1938 cdcomppath++;
1939 }
1940 first = 1;
1941 while ((q = getcomponent()) != NULL) {
1942 if (q[0] == '\0' || (q[0] == '.' && q[1] == '\0'))
1943 continue;
1944 if (! first)
1945 STPUTC('/', p);
1946 first = 0;
1947 component = q;
1948 while (*q)
1949 STPUTC(*q++, p);
1950 if (equal(component, ".."))
1951 continue;
1952 STACKSTRNUL(p);
1953 if ((lstat(stackblock(), &statb) < 0)
1954 || (S_ISLNK(statb.st_mode))) {
1955 /* print = 1; */
1956 badstat = 1;
1957 break;
1958 }
1959 }
1960
1961 INTOFF;
1962 if (chdir(dest) < 0) {
1963 INTON;
1964 return -1;
1965 }
1966 updatepwd(badstat ? NULL : dest);
1967 INTON;
1968 if (print && iflag)
1969 out1fmt(snlfmt, curdir);
1970 return 0;
1971}
1972
1973
1974/*
1975 * Get the next component of the path name pointed to by cdcomppath.
1976 * This routine overwrites the string pointed to by cdcomppath.
1977 */
1978
1979static char *
1980getcomponent() {
1981 char *p;
1982 char *start;
1983
1984 if ((p = cdcomppath) == NULL)
1985 return NULL;
1986 start = cdcomppath;
1987 while (*p != '/' && *p != '\0')
1988 p++;
1989 if (*p == '\0') {
1990 cdcomppath = NULL;
1991 } else {
1992 *p++ = '\0';
1993 cdcomppath = p;
1994 }
1995 return start;
1996}
1997
1998
1999
2000/*
2001 * Update curdir (the name of the current directory) in response to a
2002 * cd command. We also call hashcd to let the routines in exec.c know
2003 * that the current directory has changed.
2004 */
2005
Eric Andersen2870d962001-07-02 17:27:21 +00002006static void hashcd (void);
2007
Eric Andersencb57d552001-06-28 07:25:16 +00002008static void
Eric Andersen2870d962001-07-02 17:27:21 +00002009updatepwd(const char *dir)
2010{
Eric Andersencb57d552001-06-28 07:25:16 +00002011 char *new;
2012 char *p;
2013 size_t len;
2014
Eric Andersen2870d962001-07-02 17:27:21 +00002015 hashcd(); /* update command hash table */
Eric Andersencb57d552001-06-28 07:25:16 +00002016
2017 /*
2018 * If our argument is NULL, we don't know the current directory
2019 * any more because we traversed a symbolic link or something
2020 * we couldn't stat().
2021 */
2022 if (dir == NULL || curdir == nullstr) {
2023 setpwd(0, 1);
2024 return;
2025 }
2026 len = strlen(dir);
2027 cdcomppath = sstrdup(dir);
2028 STARTSTACKSTR(new);
2029 if (*dir != '/') {
2030 p = curdir;
2031 while (*p)
2032 STPUTC(*p++, new);
2033 if (p[-1] == '/')
2034 STUNPUTC(new);
2035 }
2036 while ((p = getcomponent()) != NULL) {
2037 if (equal(p, "..")) {
2038 while (new > stackblock() && (STUNPUTC(new), *new) != '/');
2039 } else if (*p != '\0' && ! equal(p, ".")) {
2040 STPUTC('/', new);
2041 while (*p)
2042 STPUTC(*p++, new);
2043 }
2044 }
2045 if (new == stackblock())
2046 STPUTC('/', new);
2047 STACKSTRNUL(new);
2048 setpwd(stackblock(), 1);
2049}
2050
2051
Eric Andersen2870d962001-07-02 17:27:21 +00002052#ifdef ASH_PWD
Eric Andersencb57d552001-06-28 07:25:16 +00002053static int
2054pwdcmd(argc, argv)
2055 int argc;
2056 char **argv;
2057{
2058 out1fmt(snlfmt, curdir);
2059 return 0;
2060}
Eric Andersen2870d962001-07-02 17:27:21 +00002061#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002062
2063/*
2064 * Find out what the current directory is. If we already know the current
2065 * directory, this routine returns immediately.
2066 */
2067static void
Eric Andersen2870d962001-07-02 17:27:21 +00002068getpwd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00002069{
Eric Andersen2870d962001-07-02 17:27:21 +00002070 curdir = xgetcwd(0);
2071 if(curdir==0)
2072 curdir = nullstr;
Eric Andersencb57d552001-06-28 07:25:16 +00002073}
2074
2075static void
2076setpwd(const char *val, int setold)
2077{
2078 if (setold) {
2079 setvar("OLDPWD", curdir, VEXPORT);
2080 }
2081 INTOFF;
2082 if (curdir != nullstr) {
2083 free(curdir);
2084 curdir = nullstr;
2085 }
2086 if (!val) {
2087 getpwd();
2088 } else {
2089 curdir = savestr(val);
2090 }
2091 INTON;
2092 setvar("PWD", curdir, VEXPORT);
2093}
2094
Eric Andersencb57d552001-06-28 07:25:16 +00002095/*
2096 * Errors and exceptions.
2097 */
2098
2099/*
2100 * Code to handle exceptions in C.
2101 */
2102
Eric Andersen2870d962001-07-02 17:27:21 +00002103/*
2104 * We enclose jmp_buf in a structure so that we can declare pointers to
2105 * jump locations. The global variable handler contains the location to
2106 * jump to when an exception occurs, and the global variable exception
2107 * contains a code identifying the exeception. To implement nested
2108 * exception handlers, the user should save the value of handler on entry
2109 * to an inner scope, set handler to point to a jmploc structure for the
2110 * inner scope, and restore handler on exit from the scope.
2111 */
2112
2113struct jmploc {
2114 jmp_buf loc;
2115};
2116
2117/* exceptions */
2118#define EXINT 0 /* SIGINT received */
2119#define EXERROR 1 /* a generic error */
2120#define EXSHELLPROC 2 /* execute a shell procedure */
2121#define EXEXEC 3 /* command execution failed */
2122
2123static struct jmploc *handler;
Eric Andersencb57d552001-06-28 07:25:16 +00002124static int exception;
Eric Andersencb57d552001-06-28 07:25:16 +00002125
Eric Andersen2870d962001-07-02 17:27:21 +00002126static void exverror (int, const char *, va_list)
Eric Andersencb57d552001-06-28 07:25:16 +00002127 __attribute__((__noreturn__));
2128
2129/*
2130 * Called to raise an exception. Since C doesn't include exceptions, we
2131 * just do a longjmp to the exception handler. The type of exception is
2132 * stored in the global variable "exception".
2133 */
2134
Eric Andersen2870d962001-07-02 17:27:21 +00002135static void exraise (int) __attribute__((__noreturn__));
2136
Eric Andersencb57d552001-06-28 07:25:16 +00002137static void
Eric Andersen2870d962001-07-02 17:27:21 +00002138exraise(int e)
Eric Andersencb57d552001-06-28 07:25:16 +00002139{
2140#ifdef DEBUG
2141 if (handler == NULL)
2142 abort();
2143#endif
2144 exception = e;
2145 longjmp(handler->loc, 1);
2146}
2147
2148
2149/*
2150 * Called from trap.c when a SIGINT is received. (If the user specifies
2151 * that SIGINT is to be trapped or ignored using the trap builtin, then
2152 * this routine is not called.) Suppressint is nonzero when interrupts
2153 * are held using the INTOFF macro. The call to _exit is necessary because
2154 * there is a short period after a fork before the signal handlers are
2155 * set to the appropriate value for the child. (The test for iflag is
2156 * just defensive programming.)
2157 */
2158
2159static void
Eric Andersen2870d962001-07-02 17:27:21 +00002160onint(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00002161 sigset_t mysigset;
2162
2163 if (suppressint) {
2164 intpending++;
2165 return;
2166 }
2167 intpending = 0;
2168 sigemptyset(&mysigset);
2169 sigprocmask(SIG_SETMASK, &mysigset, NULL);
2170 if (rootshell && iflag)
2171 exraise(EXINT);
2172 else {
2173 signal(SIGINT, SIG_DFL);
2174 raise(SIGINT);
2175 }
2176 /* NOTREACHED */
2177}
2178
2179
Eric Andersen2870d962001-07-02 17:27:21 +00002180static char *commandname; /* currently executing command */
2181
Eric Andersencb57d552001-06-28 07:25:16 +00002182/*
2183 * Exverror is called to raise the error exception. If the first argument
2184 * is not NULL then error prints an error message using printf style
2185 * formatting. It then raises the error exception.
2186 */
2187static void
Eric Andersen2870d962001-07-02 17:27:21 +00002188exverror(int cond, const char *msg, va_list ap)
Eric Andersencb57d552001-06-28 07:25:16 +00002189{
2190 CLEAR_PENDING_INT;
2191 INTOFF;
2192
2193#ifdef DEBUG
2194 if (msg)
2195 TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid()));
2196 else
2197 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
2198#endif
2199 if (msg) {
2200 if (commandname)
2201 outfmt(&errout, "%s: ", commandname);
2202 doformat(&errout, msg, ap);
2203#if FLUSHERR
2204 outc('\n', &errout);
2205#else
2206 outcslow('\n', &errout);
2207#endif
2208 }
2209 flushall();
2210 exraise(cond);
2211 /* NOTREACHED */
2212}
2213
2214
2215#ifdef __STDC__
2216static void
2217error(const char *msg, ...)
2218#else
2219static void
2220error(va_alist)
2221 va_dcl
2222#endif
2223{
2224#ifndef __STDC__
2225 const char *msg;
2226#endif
2227 va_list ap;
2228#ifdef __STDC__
2229 va_start(ap, msg);
2230#else
2231 va_start(ap);
2232 msg = va_arg(ap, const char *);
2233#endif
2234 exverror(EXERROR, msg, ap);
2235 /* NOTREACHED */
2236 va_end(ap);
2237}
2238
2239
2240#ifdef __STDC__
2241static void
2242exerror(int cond, const char *msg, ...)
2243#else
2244static void
2245exerror(va_alist)
2246 va_dcl
2247#endif
2248{
2249#ifndef __STDC__
2250 int cond;
2251 const char *msg;
2252#endif
2253 va_list ap;
2254#ifdef __STDC__
2255 va_start(ap, msg);
2256#else
2257 va_start(ap);
2258 cond = va_arg(ap, int);
2259 msg = va_arg(ap, const char *);
2260#endif
2261 exverror(cond, msg, ap);
2262 /* NOTREACHED */
2263 va_end(ap);
2264}
2265
2266
2267
2268/*
2269 * Table of error messages.
2270 */
2271
2272struct errname {
Eric Andersen2870d962001-07-02 17:27:21 +00002273 short errcode; /* error number */
2274 short action; /* operation which encountered the error */
Eric Andersencb57d552001-06-28 07:25:16 +00002275};
2276
Eric Andersen2870d962001-07-02 17:27:21 +00002277/*
2278 * Types of operations (passed to the errmsg routine).
2279 */
2280
2281#define E_OPEN 01 /* opening a file */
2282#define E_CREAT 02 /* creating a file */
2283#define E_EXEC 04 /* executing a program */
Eric Andersencb57d552001-06-28 07:25:16 +00002284
2285#define ALL (E_OPEN|E_CREAT|E_EXEC)
2286
2287static const struct errname errormsg[] = {
Eric Andersen2870d962001-07-02 17:27:21 +00002288 { EINTR, ALL },
2289 { EACCES, ALL },
2290 { EIO, ALL },
2291 { ENOENT, E_OPEN },
2292 { ENOENT, E_CREAT },
2293 { ENOENT, E_EXEC },
2294 { ENOTDIR, E_OPEN },
2295 { ENOTDIR, E_CREAT },
2296 { ENOTDIR, E_EXEC },
2297 { EISDIR, ALL },
2298 { EEXIST, E_CREAT },
2299#ifdef EMFILE
2300 { EMFILE, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002301#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002302 { ENFILE, ALL },
2303 { ENOSPC, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002304#ifdef EDQUOT
Eric Andersen2870d962001-07-02 17:27:21 +00002305 { EDQUOT, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002306#endif
2307#ifdef ENOSR
Eric Andersen2870d962001-07-02 17:27:21 +00002308 { ENOSR, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002309#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002310 { ENXIO, ALL },
2311 { EROFS, ALL },
2312 { ETXTBSY, ALL },
2313#ifdef EAGAIN
2314 { EAGAIN, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002315#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002316 { ENOMEM, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002317#ifdef ENOLINK
Eric Andersen2870d962001-07-02 17:27:21 +00002318 { ENOLINK, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002319#endif
2320#ifdef EMULTIHOP
Eric Andersen2870d962001-07-02 17:27:21 +00002321 { EMULTIHOP, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002322#endif
2323#ifdef ECOMM
Eric Andersen2870d962001-07-02 17:27:21 +00002324 { ECOMM, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002325#endif
2326#ifdef ESTALE
Eric Andersen2870d962001-07-02 17:27:21 +00002327 { ESTALE, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002328#endif
2329#ifdef ETIMEDOUT
Eric Andersen2870d962001-07-02 17:27:21 +00002330 { ETIMEDOUT, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002331#endif
2332#ifdef ELOOP
Eric Andersen2870d962001-07-02 17:27:21 +00002333 { ELOOP, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002334#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002335 { E2BIG, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002336#ifdef ELIBACC
Eric Andersen2870d962001-07-02 17:27:21 +00002337 { ELIBACC, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002338#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002339};
2340
Eric Andersen2870d962001-07-02 17:27:21 +00002341#define ERRNAME_SIZE (sizeof(errormsg)/sizeof(struct errname))
Eric Andersencb57d552001-06-28 07:25:16 +00002342
2343/*
2344 * Return a string describing an error. The returned string may be a
2345 * pointer to a static buffer that will be overwritten on the next call.
2346 * Action describes the operation that got the error.
2347 */
2348
2349static const char *
Eric Andersen2870d962001-07-02 17:27:21 +00002350errmsg(int e, int action)
Eric Andersencb57d552001-06-28 07:25:16 +00002351{
2352 struct errname const *ep;
2353 static char buf[12];
2354
Eric Andersen2870d962001-07-02 17:27:21 +00002355 for (ep = errormsg ; ep < errormsg+ERRNAME_SIZE; ep++) {
Eric Andersencb57d552001-06-28 07:25:16 +00002356 if (ep->errcode == e && (ep->action & action) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00002357 return strerror(e);
Eric Andersencb57d552001-06-28 07:25:16 +00002358 }
Eric Andersen2870d962001-07-02 17:27:21 +00002359
Eric Andersencb57d552001-06-28 07:25:16 +00002360 fmtstr(buf, sizeof buf, "error %d", e);
2361 return buf;
2362}
2363
2364
Eric Andersen2870d962001-07-02 17:27:21 +00002365#ifndef ASH_BBAPPS_AS_BUILTINS
Eric Andersencb57d552001-06-28 07:25:16 +00002366static void
2367__inton() {
2368 if (--suppressint == 0 && intpending) {
2369 onint();
2370 }
2371}
2372#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002373
2374/* flags in argument to evaltree */
Eric Andersen2870d962001-07-02 17:27:21 +00002375#define EV_EXIT 01 /* exit after evaluating tree */
2376#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2377#define EV_BACKCMD 04 /* command executing within back quotes */
Eric Andersencb57d552001-06-28 07:25:16 +00002378
Eric Andersen2870d962001-07-02 17:27:21 +00002379static int evalskip; /* set if we are skipping commands */
2380static int skipcount; /* number of levels to skip */
2381static int loopnest; /* current loop nesting level */
2382static int funcnest; /* depth of function calls */
Eric Andersencb57d552001-06-28 07:25:16 +00002383
2384
Eric Andersen2870d962001-07-02 17:27:21 +00002385
2386static struct strlist *cmdenviron; /* environment for builtin command */
2387static int exitstatus; /* exit status of last command */
2388static int oexitstatus; /* saved exit status */
Eric Andersencb57d552001-06-28 07:25:16 +00002389
2390
Eric Andersen2870d962001-07-02 17:27:21 +00002391static void evalloop (union node *, int);
2392static void evalfor (union node *, int);
2393static void evalcase (union node *, int);
2394static void evalsubshell (union node *, int);
2395static void expredir (union node *);
2396static void evalpipe (union node *);
Eric Andersencb57d552001-06-28 07:25:16 +00002397#ifdef notyet
Eric Andersen2870d962001-07-02 17:27:21 +00002398static void evalcommand (union node *, int, struct backcmd *);
Eric Andersencb57d552001-06-28 07:25:16 +00002399#else
Eric Andersen2870d962001-07-02 17:27:21 +00002400static void evalcommand (union node *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00002401#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002402static void prehash (union node *);
2403static void eprintlist (struct strlist *);
Eric Andersencb57d552001-06-28 07:25:16 +00002404
Eric Andersen2870d962001-07-02 17:27:21 +00002405static union node *parsecmd(int);
Eric Andersencb57d552001-06-28 07:25:16 +00002406/*
2407 * Called to reset things after an exception.
2408 */
2409
Eric Andersencb57d552001-06-28 07:25:16 +00002410/*
2411 * The eval commmand.
2412 */
Eric Andersen2870d962001-07-02 17:27:21 +00002413static void evalstring (char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00002414
2415static int
2416evalcmd(argc, argv)
2417 int argc;
2418 char **argv;
2419{
Eric Andersen2870d962001-07-02 17:27:21 +00002420 char *p;
2421 char *concat;
2422 char **ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002423
Eric Andersen2870d962001-07-02 17:27:21 +00002424 if (argc > 1) {
2425 p = argv[1];
2426 if (argc > 2) {
2427 STARTSTACKSTR(concat);
2428 ap = argv + 2;
2429 for (;;) {
2430 while (*p)
2431 STPUTC(*p++, concat);
2432 if ((p = *ap++) == NULL)
2433 break;
2434 STPUTC(' ', concat);
2435 }
2436 STPUTC('\0', concat);
2437 p = grabstackstr(concat);
2438 }
2439 evalstring(p, EV_TESTED);
2440 }
2441 return exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00002442}
2443
Eric Andersencb57d552001-06-28 07:25:16 +00002444/*
2445 * Execute a command or commands contained in a string.
2446 */
2447
Eric Andersen2870d962001-07-02 17:27:21 +00002448static void evaltree (union node *, int);
2449static void setinputstring (char *);
2450static void popfile (void);
2451static void setstackmark(struct stackmark *mark);
2452static void popstackmark(struct stackmark *mark);
2453
2454
Eric Andersencb57d552001-06-28 07:25:16 +00002455static void
Eric Andersen2870d962001-07-02 17:27:21 +00002456evalstring(char *s, int flag)
2457{
Eric Andersencb57d552001-06-28 07:25:16 +00002458 union node *n;
2459 struct stackmark smark;
2460
2461 setstackmark(&smark);
2462 setinputstring(s);
2463 while ((n = parsecmd(0)) != NEOF) {
2464 evaltree(n, flag);
2465 popstackmark(&smark);
2466 }
2467 popfile();
2468 popstackmark(&smark);
2469}
2470
Eric Andersencb57d552001-06-28 07:25:16 +00002471/*
2472 * Evaluate a parse tree. The value is left in the global variable
2473 * exitstatus.
2474 */
Eric Andersen2870d962001-07-02 17:27:21 +00002475static struct builtincmd *find_builtin (const char *);
2476static void defun (char *, union node *);
Eric Andersencb57d552001-06-28 07:25:16 +00002477
2478static void
2479evaltree(n, flags)
2480 union node *n;
2481 int flags;
2482{
2483 int checkexit = 0;
2484 if (n == NULL) {
2485 TRACE(("evaltree(NULL) called\n"));
2486 goto out;
2487 }
2488 TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type));
2489 switch (n->type) {
2490 case NSEMI:
2491 evaltree(n->nbinary.ch1, flags & EV_TESTED);
2492 if (evalskip)
2493 goto out;
2494 evaltree(n->nbinary.ch2, flags);
2495 break;
2496 case NAND:
2497 evaltree(n->nbinary.ch1, EV_TESTED);
2498 if (evalskip || exitstatus != 0)
2499 goto out;
2500 evaltree(n->nbinary.ch2, flags);
2501 break;
2502 case NOR:
2503 evaltree(n->nbinary.ch1, EV_TESTED);
2504 if (evalskip || exitstatus == 0)
2505 goto out;
2506 evaltree(n->nbinary.ch2, flags);
2507 break;
2508 case NREDIR:
2509 expredir(n->nredir.redirect);
2510 redirect(n->nredir.redirect, REDIR_PUSH);
2511 evaltree(n->nredir.n, flags);
2512 popredir();
2513 break;
2514 case NSUBSHELL:
2515 evalsubshell(n, flags);
2516 break;
2517 case NBACKGND:
2518 evalsubshell(n, flags);
2519 break;
2520 case NIF: {
2521 evaltree(n->nif.test, EV_TESTED);
2522 if (evalskip)
2523 goto out;
2524 if (exitstatus == 0)
2525 evaltree(n->nif.ifpart, flags);
2526 else if (n->nif.elsepart)
2527 evaltree(n->nif.elsepart, flags);
2528 else
2529 exitstatus = 0;
2530 break;
2531 }
2532 case NWHILE:
2533 case NUNTIL:
2534 evalloop(n, flags);
2535 break;
2536 case NFOR:
2537 evalfor(n, flags);
2538 break;
2539 case NCASE:
2540 evalcase(n, flags);
2541 break;
2542 case NDEFUN: {
2543 struct builtincmd *bcmd;
2544 if (
2545 (bcmd = find_builtin(n->narg.text)) &&
Eric Andersen2870d962001-07-02 17:27:21 +00002546 IS_BUILTIN_SPECIAL(bcmd)
Eric Andersencb57d552001-06-28 07:25:16 +00002547 ) {
2548 outfmt(out2, "%s is a special built-in\n", n->narg.text);
2549 exitstatus = 1;
2550 break;
2551 }
2552 defun(n->narg.text, n->narg.next);
2553 exitstatus = 0;
2554 break;
2555 }
2556 case NNOT:
2557 evaltree(n->nnot.com, EV_TESTED);
2558 exitstatus = !exitstatus;
2559 break;
2560
2561 case NPIPE:
2562 evalpipe(n);
2563 checkexit = 1;
2564 break;
2565 case NCMD:
2566#ifdef notyet
2567 evalcommand(n, flags, (struct backcmd *)NULL);
2568#else
2569 evalcommand(n, flags);
2570#endif
2571 checkexit = 1;
2572 break;
2573#ifdef DEBUG
2574 default:
2575 out1fmt("Node type = %d\n", n->type);
2576#ifndef USE_GLIBC_STDIO
2577 flushout(out1);
2578#endif
2579 break;
2580#endif
2581 }
2582out:
2583 if (pendingsigs)
2584 dotrap();
2585 if (
2586 flags & EV_EXIT ||
2587 (checkexit && eflag && exitstatus && !(flags & EV_TESTED))
2588 )
2589 exitshell(exitstatus);
2590}
2591
2592
2593static void
2594evalloop(n, flags)
2595 union node *n;
2596 int flags;
2597{
2598 int status;
2599
2600 loopnest++;
2601 status = 0;
2602 for (;;) {
2603 evaltree(n->nbinary.ch1, EV_TESTED);
2604 if (evalskip) {
Eric Andersen2870d962001-07-02 17:27:21 +00002605skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00002606 evalskip = 0;
2607 continue;
2608 }
2609 if (evalskip == SKIPBREAK && --skipcount <= 0)
2610 evalskip = 0;
2611 break;
2612 }
2613 if (n->type == NWHILE) {
2614 if (exitstatus != 0)
2615 break;
2616 } else {
2617 if (exitstatus == 0)
2618 break;
2619 }
2620 evaltree(n->nbinary.ch2, flags & EV_TESTED);
2621 status = exitstatus;
2622 if (evalskip)
2623 goto skipping;
2624 }
2625 loopnest--;
2626 exitstatus = status;
2627}
2628
Eric Andersen2870d962001-07-02 17:27:21 +00002629static void expandarg (union node *, struct arglist *, int);
2630static void fixredir(union node *n, const char *text, int err);
Eric Andersencb57d552001-06-28 07:25:16 +00002631
2632static void
2633evalfor(n, flags)
2634 union node *n;
2635 int flags;
2636{
2637 struct arglist arglist;
2638 union node *argp;
2639 struct strlist *sp;
2640 struct stackmark smark;
2641
2642 setstackmark(&smark);
2643 arglist.lastp = &arglist.list;
2644 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
2645 oexitstatus = exitstatus;
2646 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
2647 if (evalskip)
2648 goto out;
2649 }
2650 *arglist.lastp = NULL;
2651
2652 exitstatus = 0;
2653 loopnest++;
2654 for (sp = arglist.list ; sp ; sp = sp->next) {
2655 setvar(n->nfor.var, sp->text, 0);
2656 evaltree(n->nfor.body, flags & EV_TESTED);
2657 if (evalskip) {
2658 if (evalskip == SKIPCONT && --skipcount <= 0) {
2659 evalskip = 0;
2660 continue;
2661 }
2662 if (evalskip == SKIPBREAK && --skipcount <= 0)
2663 evalskip = 0;
2664 break;
2665 }
2666 }
2667 loopnest--;
2668out:
2669 popstackmark(&smark);
2670}
2671
2672
Eric Andersencb57d552001-06-28 07:25:16 +00002673static void
2674evalcase(n, flags)
2675 union node *n;
2676 int flags;
2677{
2678 union node *cp;
2679 union node *patp;
2680 struct arglist arglist;
2681 struct stackmark smark;
2682
2683 setstackmark(&smark);
2684 arglist.lastp = &arglist.list;
2685 oexitstatus = exitstatus;
2686 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
2687 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2688 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
2689 if (casematch(patp, arglist.list->text)) {
2690 if (evalskip == 0) {
2691 evaltree(cp->nclist.body, flags);
2692 }
2693 goto out;
2694 }
2695 }
2696 }
2697out:
2698 popstackmark(&smark);
2699}
2700
Eric Andersencb57d552001-06-28 07:25:16 +00002701/*
2702 * Kick off a subshell to evaluate a tree.
2703 */
2704
2705static void
2706evalsubshell(n, flags)
2707 union node *n;
2708 int flags;
2709{
2710 struct job *jp;
2711 int backgnd = (n->type == NBACKGND);
2712
2713 expredir(n->nredir.redirect);
2714 jp = makejob(n, 1);
2715 if (forkshell(jp, n, backgnd) == 0) {
2716 if (backgnd)
2717 flags &=~ EV_TESTED;
2718 redirect(n->nredir.redirect, 0);
Eric Andersen2870d962001-07-02 17:27:21 +00002719 evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00002720 }
2721 if (! backgnd) {
2722 INTOFF;
2723 exitstatus = waitforjob(jp);
2724 INTON;
2725 }
2726}
2727
2728
2729
2730/*
2731 * Compute the names of the files in a redirection list.
2732 */
2733
2734static void
2735expredir(n)
2736 union node *n;
2737{
2738 union node *redir;
2739
2740 for (redir = n ; redir ; redir = redir->nfile.next) {
2741 struct arglist fn;
2742 fn.lastp = &fn.list;
2743 oexitstatus = exitstatus;
2744 switch (redir->type) {
2745 case NFROMTO:
2746 case NFROM:
2747 case NTO:
2748 case NAPPEND:
2749 case NTOOV:
2750 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
2751 redir->nfile.expfname = fn.list->text;
2752 break;
2753 case NFROMFD:
2754 case NTOFD:
2755 if (redir->ndup.vname) {
2756 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
2757 fixredir(redir, fn.list->text, 1);
2758 }
2759 break;
2760 }
2761 }
2762}
2763
Eric Andersencb57d552001-06-28 07:25:16 +00002764/*
2765 * Evaluate a pipeline. All the processes in the pipeline are children
2766 * of the process creating the pipeline. (This differs from some versions
2767 * of the shell, which make the last process in a pipeline the parent
2768 * of all the rest.)
2769 */
2770
2771static void
2772evalpipe(n)
2773 union node *n;
2774{
2775 struct job *jp;
2776 struct nodelist *lp;
2777 int pipelen;
2778 int prevfd;
2779 int pip[2];
2780
2781 TRACE(("evalpipe(0x%lx) called\n", (long)n));
2782 pipelen = 0;
2783 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
2784 pipelen++;
2785 INTOFF;
2786 jp = makejob(n, pipelen);
2787 prevfd = -1;
2788 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
2789 prehash(lp->n);
2790 pip[1] = -1;
2791 if (lp->next) {
2792 if (pipe(pip) < 0) {
2793 close(prevfd);
2794 error("Pipe call failed");
2795 }
2796 }
2797 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
2798 INTON;
2799 if (prevfd > 0) {
2800 close(0);
2801 dup_as_newfd(prevfd, 0);
2802 close(prevfd);
2803 if (pip[0] == 0) {
2804 pip[0] = -1;
2805 }
2806 }
2807 if (pip[1] >= 0) {
2808 if (pip[0] >= 0) {
2809 close(pip[0]);
2810 }
2811 if (pip[1] != 1) {
2812 close(1);
2813 dup_as_newfd(pip[1], 1);
2814 close(pip[1]);
2815 }
2816 }
2817 evaltree(lp->n, EV_EXIT);
2818 }
2819 if (prevfd >= 0)
2820 close(prevfd);
2821 prevfd = pip[0];
2822 close(pip[1]);
2823 }
2824 INTON;
2825 if (n->npipe.backgnd == 0) {
2826 INTOFF;
2827 exitstatus = waitforjob(jp);
2828 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
2829 INTON;
2830 }
2831}
2832
2833
2834
2835/*
2836 * Execute a command inside back quotes. If it's a builtin command, we
2837 * want to save its output in a block obtained from malloc. Otherwise
2838 * we fork off a subprocess and get the output of the command via a pipe.
2839 * Should be called with interrupts off.
2840 */
2841
2842static void
Eric Andersen2870d962001-07-02 17:27:21 +00002843evalbackcmd(union node *n, struct backcmd *result)
Eric Andersencb57d552001-06-28 07:25:16 +00002844{
2845 int pip[2];
2846 struct job *jp;
Eric Andersen2870d962001-07-02 17:27:21 +00002847 struct stackmark smark; /* unnecessary */
Eric Andersencb57d552001-06-28 07:25:16 +00002848
2849 setstackmark(&smark);
2850 result->fd = -1;
2851 result->buf = NULL;
2852 result->nleft = 0;
2853 result->jp = NULL;
2854 if (n == NULL) {
2855 exitstatus = 0;
2856 goto out;
2857 }
2858#ifdef notyet
2859 /*
2860 * For now we disable executing builtins in the same
2861 * context as the shell, because we are not keeping
2862 * enough state to recover from changes that are
2863 * supposed only to affect subshells. eg. echo "`cd /`"
2864 */
2865 if (n->type == NCMD) {
2866 exitstatus = oexitstatus;
2867 evalcommand(n, EV_BACKCMD, result);
2868 } else
2869#endif
2870 {
2871 exitstatus = 0;
2872 if (pipe(pip) < 0)
2873 error("Pipe call failed");
2874 jp = makejob(n, 1);
2875 if (forkshell(jp, n, FORK_NOJOB) == 0) {
2876 FORCEINTON;
2877 close(pip[0]);
2878 if (pip[1] != 1) {
2879 close(1);
2880 dup_as_newfd(pip[1], 1);
2881 close(pip[1]);
2882 }
2883 eflag = 0;
2884 evaltree(n, EV_EXIT);
2885 }
2886 close(pip[1]);
2887 result->fd = pip[0];
2888 result->jp = jp;
2889 }
2890out:
2891 popstackmark(&smark);
2892 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
2893 result->fd, result->buf, result->nleft, result->jp));
2894}
2895
2896
2897
2898/*
2899 * Execute a simple command.
2900 */
2901
Eric Andersen2870d962001-07-02 17:27:21 +00002902static void find_command (const char *, struct cmdentry *, int, const char *);
2903
2904static int
2905isassignment(const char *word) {
2906 if (!is_name(*word)) {
2907 return 0;
2908 }
2909 do {
2910 word++;
2911 } while (is_in_name(*word));
2912 return *word == '=';
2913}
2914
Eric Andersencb57d552001-06-28 07:25:16 +00002915static void
2916#ifdef notyet
2917evalcommand(cmd, flags, backcmd)
2918 union node *cmd;
2919 int flags;
2920 struct backcmd *backcmd;
2921#else
2922evalcommand(cmd, flags)
2923 union node *cmd;
2924 int flags;
2925#endif
2926{
2927 struct stackmark smark;
2928 union node *argp;
2929 struct arglist arglist;
2930 struct arglist varlist;
2931 char **argv;
2932 int argc;
2933 char **envp;
2934 struct strlist *sp;
2935 int mode;
2936#ifdef notyet
2937 int pip[2];
2938#endif
2939 struct cmdentry cmdentry;
2940 struct job *jp;
2941 char *volatile savecmdname;
2942 volatile struct shparam saveparam;
2943 struct localvar *volatile savelocalvars;
2944 volatile int e;
2945 char *lastarg;
2946 const char *path;
2947 const struct builtincmd *firstbltin;
2948 struct jmploc *volatile savehandler;
2949 struct jmploc jmploc;
2950#if __GNUC__
2951 /* Avoid longjmp clobbering */
2952 (void) &argv;
2953 (void) &argc;
2954 (void) &lastarg;
2955 (void) &flags;
2956#endif
2957
2958 /* First expand the arguments. */
2959 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
2960 setstackmark(&smark);
2961 arglist.lastp = &arglist.list;
2962 varlist.lastp = &varlist.list;
2963 arglist.list = 0;
2964 oexitstatus = exitstatus;
2965 exitstatus = 0;
2966 path = pathval();
2967 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
2968 expandarg(argp, &varlist, EXP_VARTILDE);
2969 }
2970 for (
2971 argp = cmd->ncmd.args; argp && !arglist.list;
2972 argp = argp->narg.next
2973 ) {
2974 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
2975 }
2976 if (argp) {
2977 struct builtincmd *bcmd;
2978 bool pseudovarflag;
2979 bcmd = find_builtin(arglist.list->text);
Eric Andersen2870d962001-07-02 17:27:21 +00002980 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
Eric Andersencb57d552001-06-28 07:25:16 +00002981 for (; argp; argp = argp->narg.next) {
2982 if (pseudovarflag && isassignment(argp->narg.text)) {
2983 expandarg(argp, &arglist, EXP_VARTILDE);
2984 continue;
2985 }
2986 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
2987 }
2988 }
2989 *arglist.lastp = NULL;
2990 *varlist.lastp = NULL;
2991 expredir(cmd->ncmd.redirect);
2992 argc = 0;
2993 for (sp = arglist.list ; sp ; sp = sp->next)
2994 argc++;
2995 argv = stalloc(sizeof (char *) * (argc + 1));
2996
2997 for (sp = arglist.list ; sp ; sp = sp->next) {
2998 TRACE(("evalcommand arg: %s\n", sp->text));
2999 *argv++ = sp->text;
3000 }
3001 *argv = NULL;
3002 lastarg = NULL;
3003 if (iflag && funcnest == 0 && argc > 0)
3004 lastarg = argv[-1];
3005 argv -= argc;
3006
3007 /* Print the command if xflag is set. */
3008 if (xflag) {
3009#ifdef FLUSHERR
3010 outc('+', &errout);
3011#else
3012 outcslow('+', &errout);
3013#endif
3014 eprintlist(varlist.list);
3015 eprintlist(arglist.list);
3016#ifdef FLUSHERR
3017 outc('\n', &errout);
3018 flushout(&errout);
3019#else
3020 outcslow('\n', &errout);
3021#endif
3022 }
3023
3024 /* Now locate the command. */
3025 if (argc == 0) {
3026 cmdentry.cmdtype = CMDBUILTIN;
3027 firstbltin = cmdentry.u.cmd = BLTINCMD;
3028 } else {
3029 const char *oldpath;
3030 int findflag = DO_ERR;
3031 int oldfindflag;
3032
3033 /*
3034 * Modify the command lookup path, if a PATH= assignment
3035 * is present
3036 */
3037 for (sp = varlist.list ; sp ; sp = sp->next)
3038 if (varequal(sp->text, defpathvar)) {
3039 path = sp->text + 5;
3040 findflag |= DO_BRUTE;
3041 }
3042 oldpath = path;
3043 oldfindflag = findflag;
3044 firstbltin = 0;
3045 for(;;) {
3046 find_command(argv[0], &cmdentry, findflag, path);
Eric Andersen2870d962001-07-02 17:27:21 +00003047 if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */
Eric Andersencb57d552001-06-28 07:25:16 +00003048 exitstatus = 127;
3049#ifdef FLUSHERR
3050 flushout(&errout);
3051#endif
3052 goto out;
3053 }
3054 /* implement bltin and command here */
3055 if (cmdentry.cmdtype != CMDBUILTIN) {
3056 break;
3057 }
3058 if (!firstbltin) {
3059 firstbltin = cmdentry.u.cmd;
3060 }
3061 if (cmdentry.u.cmd == BLTINCMD) {
3062 for(;;) {
3063 struct builtincmd *bcmd;
3064
3065 argv++;
3066 if (--argc == 0)
3067 goto found;
3068 if (!(bcmd = find_builtin(*argv))) {
3069 outfmt(&errout, "%s: not found\n", *argv);
3070 exitstatus = 127;
3071#ifdef FLUSHERR
3072 flushout(&errout);
3073#endif
3074 goto out;
3075 }
3076 cmdentry.u.cmd = bcmd;
3077 if (bcmd != BLTINCMD)
3078 break;
3079 }
3080 }
Eric Andersen2870d962001-07-02 17:27:21 +00003081 if (cmdentry.u.cmd == find_builtin("command")) {
Eric Andersencb57d552001-06-28 07:25:16 +00003082 argv++;
3083 if (--argc == 0) {
3084 goto found;
3085 }
3086 if (*argv[0] == '-') {
3087 if (!equal(argv[0], "-p")) {
3088 argv--;
3089 argc++;
3090 break;
3091 }
3092 argv++;
3093 if (--argc == 0) {
3094 goto found;
3095 }
3096 path = defpath;
3097 findflag |= DO_BRUTE;
3098 } else {
3099 path = oldpath;
3100 findflag = oldfindflag;
3101 }
3102 findflag |= DO_NOFUN;
3103 continue;
3104 }
3105found:
3106 break;
3107 }
3108 }
3109
3110 /* Fork off a child process if necessary. */
3111 if (cmd->ncmd.backgnd
3112 || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0)
3113#ifdef notyet
3114 || ((flags & EV_BACKCMD) != 0
3115 && (cmdentry.cmdtype != CMDBUILTIN
3116 || cmdentry.u.bcmd == DOTCMD
3117 || cmdentry.u.bcmd == EVALCMD))
3118#endif
3119 ) {
3120 jp = makejob(cmd, 1);
3121 mode = cmd->ncmd.backgnd;
3122#ifdef notyet
3123 if (flags & EV_BACKCMD) {
3124 mode = FORK_NOJOB;
3125 if (pipe(pip) < 0)
3126 error("Pipe call failed");
3127 }
3128#endif
3129 if (forkshell(jp, cmd, mode) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00003130 goto parent; /* at end of routine */
Eric Andersencb57d552001-06-28 07:25:16 +00003131#ifdef notyet
3132 if (flags & EV_BACKCMD) {
3133 FORCEINTON;
3134 close(pip[0]);
3135 if (pip[1] != 1) {
3136 close(1);
3137 dup_as_newfd(pip[1], 1);
3138 close(pip[1]);
3139 }
3140 }
3141#endif
3142 flags |= EV_EXIT;
3143 }
3144
3145 /* This is the child process if a fork occurred. */
3146 /* Execute the command. */
3147 if (cmdentry.cmdtype == CMDFUNCTION) {
3148#ifdef DEBUG
3149 trputs("Shell function: "); trargs(argv);
3150#endif
3151 exitstatus = oexitstatus;
3152 redirect(cmd->ncmd.redirect, REDIR_PUSH);
3153 saveparam = shellparam;
3154 shellparam.malloc = 0;
3155 shellparam.nparam = argc - 1;
3156 shellparam.p = argv + 1;
3157 INTOFF;
3158 savelocalvars = localvars;
3159 localvars = NULL;
3160 INTON;
3161 if (setjmp(jmploc.loc)) {
3162 if (exception == EXSHELLPROC) {
3163 freeparam((volatile struct shparam *)
3164 &saveparam);
3165 } else {
3166 saveparam.optind = shellparam.optind;
3167 saveparam.optoff = shellparam.optoff;
3168 freeparam(&shellparam);
3169 shellparam = saveparam;
3170 }
3171 poplocalvars();
3172 localvars = savelocalvars;
3173 handler = savehandler;
3174 longjmp(handler->loc, 1);
3175 }
3176 savehandler = handler;
3177 handler = &jmploc;
3178 for (sp = varlist.list ; sp ; sp = sp->next)
3179 mklocal(sp->text);
3180 funcnest++;
3181 evaltree(cmdentry.u.func, flags & EV_TESTED);
3182 funcnest--;
3183 INTOFF;
3184 poplocalvars();
3185 localvars = savelocalvars;
3186 saveparam.optind = shellparam.optind;
3187 saveparam.optoff = shellparam.optoff;
3188 freeparam(&shellparam);
3189 shellparam = saveparam;
3190 handler = savehandler;
3191 popredir();
3192 INTON;
3193 if (evalskip == SKIPFUNC) {
3194 evalskip = 0;
3195 skipcount = 0;
3196 }
3197 if (flags & EV_EXIT)
3198 exitshell(exitstatus);
3199 } else if (cmdentry.cmdtype == CMDBUILTIN) {
3200#ifdef DEBUG
3201 trputs("builtin command: "); trargs(argv);
3202#endif
3203 mode = (cmdentry.u.cmd == EXECCMD)? 0 : REDIR_PUSH;
3204#ifdef notyet
3205 if (flags == EV_BACKCMD) {
3206#ifdef USE_GLIBC_STDIO
3207 openmemout();
3208#else
3209 memout.nleft = 0;
3210 memout.nextc = memout.buf;
3211 memout.bufsize = 64;
3212#endif
3213 mode |= REDIR_BACKQ;
3214 }
3215#endif
3216 redirect(cmd->ncmd.redirect, mode);
3217 savecmdname = commandname;
Eric Andersen2870d962001-07-02 17:27:21 +00003218 if (IS_BUILTIN_SPECIAL(firstbltin)) {
Eric Andersencb57d552001-06-28 07:25:16 +00003219 listsetvar(varlist.list);
3220 } else {
3221 cmdenviron = varlist.list;
3222 }
3223 e = -1;
3224 if (setjmp(jmploc.loc)) {
3225 e = exception;
3226 exitstatus = (e == EXINT)? SIGINT+128 : 2;
3227 goto cmddone;
3228 }
3229 savehandler = handler;
3230 handler = &jmploc;
3231 commandname = argv[0];
3232 argptr = argv + 1;
Eric Andersen2870d962001-07-02 17:27:21 +00003233 optptr = NULL; /* initialize nextopt */
Eric Andersencb57d552001-06-28 07:25:16 +00003234 exitstatus = (*cmdentry.u.cmd->builtinfunc)(argc, argv);
3235 flushall();
3236cmddone:
3237 exitstatus |= outerr(out1);
3238 out1 = &output;
3239 out2 = &errout;
3240 freestdout();
3241 cmdenviron = NULL;
3242 if (e != EXSHELLPROC) {
3243 commandname = savecmdname;
3244 if (flags & EV_EXIT)
3245 exitshell(exitstatus);
3246 }
3247 handler = savehandler;
3248 if (e != -1) {
3249 if ((e != EXERROR && e != EXEXEC)
3250 || cmdentry.u.cmd == BLTINCMD
3251 || cmdentry.u.cmd == DOTCMD
3252 || cmdentry.u.cmd == EVALCMD
3253 || cmdentry.u.cmd == EXECCMD)
3254 exraise(e);
3255 FORCEINTON;
3256 }
3257 if (cmdentry.u.cmd != EXECCMD)
3258 popredir();
3259#ifdef notyet
3260 if (flags == EV_BACKCMD) {
3261 INTOFF;
3262#ifdef USE_GLIBC_STDIO
Eric Andersen2870d962001-07-02 17:27:21 +00003263 if (__closememout())
3264 error("__closememout() failed: %m");
Eric Andersencb57d552001-06-28 07:25:16 +00003265#endif
3266 backcmd->buf = memout.buf;
3267#ifdef USE_GLIBC_STDIO
3268 backcmd->nleft = memout.bufsize;
3269#else
3270 backcmd->nleft = memout.nextc - memout.buf;
3271#endif
3272 memout.buf = NULL;
3273 INTON;
3274 }
3275#endif
3276 } else {
3277#ifdef DEBUG
3278 trputs("normal command: "); trargs(argv);
3279#endif
3280 redirect(cmd->ncmd.redirect, 0);
3281 clearredir();
3282 for (sp = varlist.list ; sp ; sp = sp->next)
3283 setvareq(sp->text, VEXPORT|VSTACK);
3284 envp = environment();
3285 shellexec(argv, envp, path, cmdentry.u.index);
3286 }
3287 goto out;
3288
Eric Andersen2870d962001-07-02 17:27:21 +00003289parent: /* parent process gets here (if we forked) */
3290 if (mode == 0) { /* argument to fork */
Eric Andersencb57d552001-06-28 07:25:16 +00003291 INTOFF;
3292 exitstatus = waitforjob(jp);
3293 INTON;
3294#ifdef notyet
3295 } else if (mode == 2) {
3296 backcmd->fd = pip[0];
3297 close(pip[1]);
3298 backcmd->jp = jp;
3299#endif
3300 }
3301
3302out:
3303 if (lastarg)
3304 setvar("_", lastarg, 0);
3305 popstackmark(&smark);
3306}
3307
3308
3309
3310/*
3311 * Search for a command. This is called before we fork so that the
3312 * location of the command will be available in the parent as well as
3313 * the child. The check for "goodname" is an overly conservative
3314 * check that the name will not be subject to expansion.
3315 */
3316
3317static void
3318prehash(n)
3319 union node *n;
3320{
3321 struct cmdentry entry;
3322
3323 if (n->type == NCMD && n->ncmd.args)
3324 if (goodname(n->ncmd.args->narg.text))
3325 find_command(n->ncmd.args->narg.text, &entry, 0,
3326 pathval());
3327}
3328
3329
3330
3331/*
3332 * Builtin commands. Builtin commands whose functions are closely
3333 * tied to evaluation are implemented here.
3334 */
3335
3336/*
3337 * No command given, or a bltin command with no arguments. Set the
3338 * specified variables.
3339 */
3340
3341int
3342bltincmd(argc, argv)
3343 int argc;
3344 char **argv;
3345{
3346 /*
3347 * Preserve exitstatus of a previous possible redirection
3348 * as POSIX mandates
3349 */
3350 return exitstatus;
3351}
3352
3353
3354/*
3355 * Handle break and continue commands. Break, continue, and return are
3356 * all handled by setting the evalskip flag. The evaluation routines
3357 * above all check this flag, and if it is set they start skipping
3358 * commands rather than executing them. The variable skipcount is
3359 * the number of loops to break/continue, or the number of function
3360 * levels to return. (The latter is always 1.) It should probably
3361 * be an error to break out of more loops than exist, but it isn't
3362 * in the standard shell so we don't make it one here.
3363 */
3364
3365static int
3366breakcmd(argc, argv)
3367 int argc;
3368 char **argv;
3369{
3370 int n = argc > 1 ? number(argv[1]) : 1;
3371
3372 if (n > loopnest)
3373 n = loopnest;
3374 if (n > 0) {
3375 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
3376 skipcount = n;
3377 }
3378 return 0;
3379}
3380
3381
3382/*
3383 * The return command.
3384 */
3385
3386static int
3387returncmd(argc, argv)
3388 int argc;
3389 char **argv;
3390{
3391 int ret = argc > 1 ? number(argv[1]) : oexitstatus;
3392
3393 if (funcnest) {
3394 evalskip = SKIPFUNC;
3395 skipcount = 1;
3396 return ret;
3397 }
3398 else {
3399 /* Do what ksh does; skip the rest of the file */
3400 evalskip = SKIPFILE;
3401 skipcount = 1;
3402 return ret;
3403 }
3404}
3405
3406
3407#ifndef BB_TRUE_FALSE
Eric Andersen2870d962001-07-02 17:27:21 +00003408#ifdef ASH_BBAPPS_AS_BUILTINS
Eric Andersencb57d552001-06-28 07:25:16 +00003409static int
3410false_main(argc, argv)
3411 int argc;
3412 char **argv;
3413{
3414 return 1;
3415}
3416
3417
3418static int
3419true_main(argc, argv)
3420 int argc;
3421 char **argv;
3422{
3423 return 0;
3424}
3425#endif
Eric Andersen2870d962001-07-02 17:27:21 +00003426#endif
3427
3428/*
3429 * Controls whether the shell is interactive or not.
3430 */
3431
3432static void setsignal(int signo);
3433static void chkmail(int silent);
3434
3435
3436static void
3437setinteractive(int on)
3438{
3439 static int is_interactive;
3440
3441 if (on == is_interactive)
3442 return;
3443 setsignal(SIGINT);
3444 setsignal(SIGQUIT);
3445 setsignal(SIGTERM);
3446 chkmail(1);
3447 is_interactive = on;
3448}
3449
3450static void
3451optschanged(void)
3452{
3453 setinteractive(iflag);
3454 setjobctl(mflag);
3455}
3456
Eric Andersencb57d552001-06-28 07:25:16 +00003457
3458static int
3459execcmd(argc, argv)
3460 int argc;
3461 char **argv;
3462{
3463 if (argc > 1) {
3464 struct strlist *sp;
3465
Eric Andersen2870d962001-07-02 17:27:21 +00003466 iflag = 0; /* exit on error */
Eric Andersencb57d552001-06-28 07:25:16 +00003467 mflag = 0;
3468 optschanged();
3469 for (sp = cmdenviron; sp ; sp = sp->next)
3470 setvareq(sp->text, VEXPORT|VSTACK);
3471 shellexec(argv + 1, environment(), pathval(), 0);
3472 }
3473 return 0;
3474}
3475
3476static void
3477eprintlist(struct strlist *sp)
3478{
3479 for (; sp; sp = sp->next) {
3480 outfmt(&errout, " %s",sp->text);
3481 }
3482}
Eric Andersencb57d552001-06-28 07:25:16 +00003483/*
3484 * When commands are first encountered, they are entered in a hash table.
3485 * This ensures that a full path search will not have to be done for them
3486 * on each invocation.
3487 *
3488 * We should investigate converting to a linear search, even though that
3489 * would make the command name "hash" a misnomer.
3490 */
Eric Andersen2870d962001-07-02 17:27:21 +00003491#define CMDTABLESIZE 31 /* should be prime */
3492#define ARB 1 /* actual size determined at run time */
Eric Andersencb57d552001-06-28 07:25:16 +00003493
3494
3495
3496struct tblentry {
Eric Andersen2870d962001-07-02 17:27:21 +00003497 struct tblentry *next; /* next entry in hash chain */
3498 union param param; /* definition of builtin function */
3499 short cmdtype; /* index identifying command */
3500 char rehash; /* if set, cd done since entry created */
3501 char cmdname[ARB]; /* name of command */
Eric Andersencb57d552001-06-28 07:25:16 +00003502};
3503
3504
3505static struct tblentry *cmdtable[CMDTABLESIZE];
Eric Andersen2870d962001-07-02 17:27:21 +00003506static int builtinloc = -1; /* index in path of %builtin, or -1 */
3507static int exerrno = 0; /* Last exec error */
Eric Andersencb57d552001-06-28 07:25:16 +00003508
3509
Eric Andersen2870d962001-07-02 17:27:21 +00003510static void tryexec (char *, char **, char **);
3511static void printentry (struct tblentry *, int);
3512static void clearcmdentry (int);
3513static struct tblentry *cmdlookup (const char *, int);
3514static void delete_cmd_entry (void);
Eric Andersencb57d552001-06-28 07:25:16 +00003515#ifdef ASH_TYPE
Eric Andersen2870d962001-07-02 17:27:21 +00003516static int describe_command (char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00003517#endif
Eric Andersen2870d962001-07-02 17:27:21 +00003518static int path_change (const char *, int *);
Eric Andersencb57d552001-06-28 07:25:16 +00003519
3520
3521/*
3522 * Exec a program. Never returns. If you change this routine, you may
3523 * have to change the find_command routine as well.
3524 */
3525
Eric Andersen2870d962001-07-02 17:27:21 +00003526static const char *pathopt; /* set by padvance */
3527
Eric Andersencb57d552001-06-28 07:25:16 +00003528static void
3529shellexec(argv, envp, path, idx)
3530 char **argv, **envp;
3531 const char *path;
3532 int idx;
3533{
3534 char *cmdname;
3535 int e;
3536
3537 if (strchr(argv[0], '/') != NULL) {
3538 tryexec(argv[0], argv, envp);
3539 e = errno;
3540 } else {
3541 e = ENOENT;
3542 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3543 if (--idx < 0 && pathopt == NULL) {
3544 tryexec(cmdname, argv, envp);
3545 if (errno != ENOENT && errno != ENOTDIR)
3546 e = errno;
3547 }
3548 stunalloc(cmdname);
3549 }
3550 }
3551
3552 /* Map to POSIX errors */
3553 switch (e) {
3554 case EACCES:
3555 exerrno = 126;
3556 break;
3557 case ENOENT:
3558 exerrno = 127;
3559 break;
3560 default:
3561 exerrno = 2;
3562 break;
3563 }
3564 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3565 /* NOTREACHED */
3566}
3567
Eric Andersen2870d962001-07-02 17:27:21 +00003568/*
3569 * Clear traps on a fork.
3570 */
3571static void
3572clear_traps(void) {
3573 char **tp;
3574
3575 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
3576 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
3577 INTOFF;
3578 ckfree(*tp);
3579 *tp = NULL;
3580 if (tp != &trap[0])
3581 setsignal(tp - trap);
3582 INTON;
3583 }
3584 }
3585}
3586
3587
3588static void
3589initshellproc(void) {
3590
3591#ifdef ASH_ALIAS
3592 /* from alias.c: */
3593 {
3594 rmaliases();
3595 }
3596#endif
3597 /* from eval.c: */
3598 {
3599 exitstatus = 0;
3600 }
3601
3602 /* from exec.c: */
3603 {
3604 deletefuncs();
3605 }
3606
3607 /* from jobs.c: */
3608 {
3609 backgndpid = -1;
3610#ifdef JOBS
3611 jobctl = 0;
3612#endif
3613 }
3614
3615 /* from options.c: */
3616 {
3617 int i;
3618
3619 for (i = 0; i < NOPTS; i++)
3620 optent_val(i) = 0;
3621 optschanged();
3622
3623 }
3624
3625 /* from redir.c: */
3626 {
3627 clearredir();
3628 }
3629
3630 /* from trap.c: */
3631 {
3632 char *sm;
3633
3634 clear_traps();
3635 for (sm = sigmode ; sm < sigmode + NSIG - 1; sm++) {
3636 if (*sm == S_IGN)
3637 *sm = S_HARD_IGN;
3638 }
3639 }
3640
3641 /* from var.c: */
3642 {
3643 shprocvar();
3644 }
3645}
3646
3647static int preadbuffer(void);
3648static void pushfile (void);
3649static int preadfd (void);
3650
3651/*
3652 * Read a character from the script, returning PEOF on end of file.
3653 * Nul characters in the input are silently discarded.
3654 */
3655
3656#ifdef ASH_BBAPPS_AS_BUILTINS
3657#define pgetc_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
3658static int
3659pgetc(void)
3660{
3661 return pgetc_macro();
3662}
3663#else
3664static int
3665pgetc_macro(void)
3666{
3667 return --parsenleft >= 0? *parsenextc++ : preadbuffer();
3668}
3669
3670static inline int
3671pgetc(void)
3672{
3673 return pgetc_macro();
3674}
3675#endif
3676
3677
3678/*
3679 * Undo the last call to pgetc. Only one character may be pushed back.
3680 * PEOF may be pushed back.
3681 */
3682
3683static void
3684pungetc() {
3685 parsenleft++;
3686 parsenextc--;
3687}
3688
3689
3690static void
3691popfile(void) {
3692 struct parsefile *pf = parsefile;
3693
3694 INTOFF;
3695 if (pf->fd >= 0)
3696 close(pf->fd);
3697 if (pf->buf)
3698 ckfree(pf->buf);
3699 while (pf->strpush)
3700 popstring();
3701 parsefile = pf->prev;
3702 ckfree(pf);
3703 parsenleft = parsefile->nleft;
3704 parselleft = parsefile->lleft;
3705 parsenextc = parsefile->nextc;
3706 plinno = parsefile->linno;
3707 INTON;
3708}
3709
3710
3711/*
3712 * Return to top level.
3713 */
3714
3715static void
3716popallfiles(void) {
3717 while (parsefile != &basepf)
3718 popfile();
3719}
3720
3721/*
3722 * Close the file(s) that the shell is reading commands from. Called
3723 * after a fork is done.
3724 */
3725
3726static void
3727closescript() {
3728 popallfiles();
3729 if (parsefile->fd > 0) {
3730 close(parsefile->fd);
3731 parsefile->fd = 0;
3732 }
3733}
3734
3735
3736/*
3737 * Like setinputfile, but takes an open file descriptor. Call this with
3738 * interrupts off.
3739 */
3740
3741static void
3742setinputfd(fd, push)
3743 int fd, push;
3744{
3745 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
3746 if (push) {
3747 pushfile();
3748 parsefile->buf = 0;
3749 } else {
3750 closescript();
3751 while (parsefile->strpush)
3752 popstring();
3753 }
3754 parsefile->fd = fd;
3755 if (parsefile->buf == NULL)
3756 parsefile->buf = ckmalloc(BUFSIZ);
3757 parselleft = parsenleft = 0;
3758 plinno = 1;
3759}
3760
3761
3762/*
3763 * Set the input to take input from a file. If push is set, push the
3764 * old input onto the stack first.
3765 */
3766
3767static void
3768setinputfile(const char *fname, int push)
3769{
3770 int fd;
3771 int myfileno2;
3772
3773 INTOFF;
3774 if ((fd = open(fname, O_RDONLY)) < 0)
3775 error("Can't open %s", fname);
3776 if (fd < 10) {
3777 myfileno2 = dup_as_newfd(fd, 10);
3778 close(fd);
3779 if (myfileno2 < 0)
3780 error("Out of file descriptors");
3781 fd = myfileno2;
3782 }
3783 setinputfd(fd, push);
3784 INTON;
3785}
3786
Eric Andersencb57d552001-06-28 07:25:16 +00003787
3788static void
3789tryexec(cmd, argv, envp)
3790 char *cmd;
3791 char **argv;
3792 char **envp;
3793 {
3794 int e;
Eric Andersencb57d552001-06-28 07:25:16 +00003795
Eric Andersencb57d552001-06-28 07:25:16 +00003796 execve(cmd, argv, envp);
Eric Andersencb57d552001-06-28 07:25:16 +00003797 e = errno;
3798 if (e == ENOEXEC) {
3799 INTOFF;
3800 initshellproc();
3801 setinputfile(cmd, 0);
3802 commandname = arg0 = savestr(argv[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00003803 setparam(argv + 1);
3804 exraise(EXSHELLPROC);
3805 }
3806 errno = e;
3807}
3808
Eric Andersen2870d962001-07-02 17:27:21 +00003809static char *commandtext (const union node *);
Eric Andersencb57d552001-06-28 07:25:16 +00003810
3811/*
3812 * Do a path search. The variable path (passed by reference) should be
3813 * set to the start of the path before the first call; padvance will update
3814 * this value as it proceeds. Successive calls to padvance will return
3815 * the possible path expansions in sequence. If an option (indicated by
3816 * a percent sign) appears in the path entry then the global variable
3817 * pathopt will be set to point to it; otherwise pathopt will be set to
3818 * NULL.
3819 */
3820
3821static const char *pathopt;
3822
Eric Andersen2870d962001-07-02 17:27:21 +00003823static void growstackblock(void);
3824
3825
Eric Andersencb57d552001-06-28 07:25:16 +00003826static char *
Eric Andersen2870d962001-07-02 17:27:21 +00003827padvance(const char **path, const char *name)
3828{
Eric Andersencb57d552001-06-28 07:25:16 +00003829 const char *p;
3830 char *q;
3831 const char *start;
3832 int len;
3833
3834 if (*path == NULL)
3835 return NULL;
3836 start = *path;
3837 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
Eric Andersen2870d962001-07-02 17:27:21 +00003838 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +00003839 while (stackblocksize() < len)
3840 growstackblock();
3841 q = stackblock();
3842 if (p != start) {
3843 memcpy(q, start, p - start);
3844 q += p - start;
3845 *q++ = '/';
3846 }
3847 strcpy(q, name);
3848 pathopt = NULL;
3849 if (*p == '%') {
3850 pathopt = ++p;
3851 while (*p && *p != ':') p++;
3852 }
3853 if (*p == ':')
3854 *path = p + 1;
3855 else
3856 *path = NULL;
3857 return stalloc(len);
3858}
3859
3860
3861
3862/*** Command hashing code ***/
3863
3864
3865static int
3866hashcmd(argc, argv)
3867 int argc;
3868 char **argv;
3869{
3870 struct tblentry **pp;
3871 struct tblentry *cmdp;
3872 int c;
3873 int verbose;
3874 struct cmdentry entry;
3875 char *name;
3876
3877 verbose = 0;
3878 while ((c = nextopt("rv")) != '\0') {
3879 if (c == 'r') {
3880 clearcmdentry(0);
3881 return 0;
3882 } else if (c == 'v') {
3883 verbose++;
3884 }
3885 }
3886 if (*argptr == NULL) {
3887 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3888 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3889 if (cmdp->cmdtype != CMDBUILTIN) {
3890 printentry(cmdp, verbose);
3891 }
3892 }
3893 }
3894 return 0;
3895 }
3896 c = 0;
3897 while ((name = *argptr) != NULL) {
3898 if ((cmdp = cmdlookup(name, 0)) != NULL
3899 && (cmdp->cmdtype == CMDNORMAL
3900 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
3901 delete_cmd_entry();
3902 find_command(name, &entry, DO_ERR, pathval());
3903 if (entry.cmdtype == CMDUNKNOWN) c = 1;
3904 else if (verbose) {
3905 cmdp = cmdlookup(name, 0);
3906 if (cmdp) printentry(cmdp, verbose);
3907 flushall();
3908 }
3909 argptr++;
3910 }
3911 return c;
3912}
3913
3914
3915static void
3916printentry(cmdp, verbose)
3917 struct tblentry *cmdp;
3918 int verbose;
3919 {
3920 int idx;
3921 const char *path;
3922 char *name;
3923
3924 if (cmdp->cmdtype == CMDNORMAL) {
3925 idx = cmdp->param.index;
3926 path = pathval();
3927 do {
3928 name = padvance(&path, cmdp->cmdname);
3929 stunalloc(name);
3930 } while (--idx >= 0);
3931 out1str(name);
3932 } else if (cmdp->cmdtype == CMDBUILTIN) {
3933 out1fmt("builtin %s", cmdp->cmdname);
3934 } else if (cmdp->cmdtype == CMDFUNCTION) {
3935 out1fmt("function %s", cmdp->cmdname);
3936 if (verbose) {
3937 INTOFF;
3938 name = commandtext(cmdp->param.func);
3939 out1fmt(" %s", name);
3940 ckfree(name);
3941 INTON;
3942 }
3943#ifdef DEBUG
3944 } else {
3945 error("internal error: cmdtype %d", cmdp->cmdtype);
3946#endif
3947 }
3948 out1fmt(snlfmt, cmdp->rehash ? "*" : nullstr);
3949}
3950
3951
3952
3953/*
3954 * Resolve a command name. If you change this routine, you may have to
3955 * change the shellexec routine as well.
3956 */
3957
Eric Andersen2870d962001-07-02 17:27:21 +00003958static int prefix (const char *, const char *);
3959
Eric Andersencb57d552001-06-28 07:25:16 +00003960static void
Eric Andersen2870d962001-07-02 17:27:21 +00003961find_command(const char *name, struct cmdentry *entry, int act, const char *path)
Eric Andersencb57d552001-06-28 07:25:16 +00003962{
3963 struct tblentry *cmdp;
3964 int idx;
3965 int prev;
3966 char *fullname;
3967 struct stat statb;
3968 int e;
3969 int bltin;
3970 int firstchange;
3971 int updatetbl;
3972 bool regular;
3973 struct builtincmd *bcmd;
3974
3975 /* If name contains a slash, don't use the hash table */
3976 if (strchr(name, '/') != NULL) {
3977 if (act & DO_ABS) {
3978 while (stat(name, &statb) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003979 if (errno != ENOENT && errno != ENOTDIR)
3980 e = errno;
3981 entry->cmdtype = CMDUNKNOWN;
3982 entry->u.index = -1;
3983 return;
3984 }
3985 entry->cmdtype = CMDNORMAL;
3986 entry->u.index = -1;
3987 return;
3988 }
3989 entry->cmdtype = CMDNORMAL;
3990 entry->u.index = 0;
3991 return;
3992 }
3993
3994 updatetbl = 1;
3995 if (act & DO_BRUTE) {
3996 firstchange = path_change(path, &bltin);
3997 } else {
3998 bltin = builtinloc;
3999 firstchange = 9999;
4000 }
4001
4002 /* If name is in the table, and not invalidated by cd, we're done */
4003 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0) {
4004 if (cmdp->cmdtype == CMDFUNCTION) {
4005 if (act & DO_NOFUN) {
4006 updatetbl = 0;
4007 } else {
4008 goto success;
4009 }
4010 } else if (act & DO_BRUTE) {
4011 if ((cmdp->cmdtype == CMDNORMAL &&
4012 cmdp->param.index >= firstchange) ||
4013 (cmdp->cmdtype == CMDBUILTIN &&
4014 ((builtinloc < 0 && bltin >= 0) ?
4015 bltin : builtinloc) >= firstchange)) {
4016 /* need to recompute the entry */
4017 } else {
4018 goto success;
4019 }
4020 } else {
4021 goto success;
4022 }
4023 }
4024
4025 bcmd = find_builtin(name);
Eric Andersen2870d962001-07-02 17:27:21 +00004026 regular = bcmd && IS_BUILTIN_REGULAR(bcmd);
Eric Andersencb57d552001-06-28 07:25:16 +00004027
4028 if (regular) {
4029 if (cmdp && (cmdp->cmdtype == CMDBUILTIN)) {
Eric Andersen2870d962001-07-02 17:27:21 +00004030 goto success;
Eric Andersencb57d552001-06-28 07:25:16 +00004031 }
4032 } else if (act & DO_BRUTE) {
4033 if (firstchange == 0) {
4034 updatetbl = 0;
4035 }
4036 }
4037
4038 /* If %builtin not in path, check for builtin next */
4039 if (regular || (bltin < 0 && bcmd)) {
4040builtin:
4041 if (!updatetbl) {
4042 entry->cmdtype = CMDBUILTIN;
4043 entry->u.cmd = bcmd;
4044 return;
4045 }
4046 INTOFF;
4047 cmdp = cmdlookup(name, 1);
4048 cmdp->cmdtype = CMDBUILTIN;
4049 cmdp->param.cmd = bcmd;
4050 INTON;
4051 goto success;
4052 }
4053
4054 /* We have to search path. */
Eric Andersen2870d962001-07-02 17:27:21 +00004055 prev = -1; /* where to start */
4056 if (cmdp && cmdp->rehash) { /* doing a rehash */
Eric Andersencb57d552001-06-28 07:25:16 +00004057 if (cmdp->cmdtype == CMDBUILTIN)
4058 prev = builtinloc;
4059 else
4060 prev = cmdp->param.index;
4061 }
4062
4063 e = ENOENT;
4064 idx = -1;
4065loop:
4066 while ((fullname = padvance(&path, name)) != NULL) {
4067 stunalloc(fullname);
4068 idx++;
4069 if (idx >= firstchange) {
4070 updatetbl = 0;
4071 }
4072 if (pathopt) {
4073 if (prefix("builtin", pathopt)) {
4074 if ((bcmd = find_builtin(name))) {
4075 goto builtin;
4076 }
4077 continue;
4078 } else if (!(act & DO_NOFUN) &&
4079 prefix("func", pathopt)) {
4080 /* handled below */
4081 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00004082 continue; /* ignore unimplemented options */
Eric Andersencb57d552001-06-28 07:25:16 +00004083 }
4084 }
4085 /* if rehash, don't redo absolute path names */
4086 if (fullname[0] == '/' && idx <= prev &&
4087 idx < firstchange) {
4088 if (idx < prev)
4089 continue;
4090 TRACE(("searchexec \"%s\": no change\n", name));
4091 goto success;
4092 }
4093 while (stat(fullname, &statb) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00004094 if (errno != ENOENT && errno != ENOTDIR)
4095 e = errno;
4096 goto loop;
4097 }
Eric Andersen2870d962001-07-02 17:27:21 +00004098 e = EACCES; /* if we fail, this will be the error */
Eric Andersencb57d552001-06-28 07:25:16 +00004099 if (!S_ISREG(statb.st_mode))
4100 continue;
Eric Andersen2870d962001-07-02 17:27:21 +00004101 if (pathopt) { /* this is a %func directory */
Eric Andersencb57d552001-06-28 07:25:16 +00004102 stalloc(strlen(fullname) + 1);
4103 readcmdfile(fullname);
4104 if ((cmdp = cmdlookup(name, 0)) == NULL || cmdp->cmdtype != CMDFUNCTION)
4105 error("%s not defined in %s", name, fullname);
4106 stunalloc(fullname);
4107 goto success;
4108 }
Eric Andersencb57d552001-06-28 07:25:16 +00004109 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
4110 /* If we aren't called with DO_BRUTE and cmdp is set, it must
4111 be a function and we're being called with DO_NOFUN */
4112 if (!updatetbl) {
4113 entry->cmdtype = CMDNORMAL;
4114 entry->u.index = idx;
4115 return;
4116 }
4117 INTOFF;
4118 cmdp = cmdlookup(name, 1);
4119 cmdp->cmdtype = CMDNORMAL;
4120 cmdp->param.index = idx;
4121 INTON;
4122 goto success;
4123 }
4124
4125 /* We failed. If there was an entry for this command, delete it */
4126 if (cmdp && updatetbl)
4127 delete_cmd_entry();
4128 if (act & DO_ERR)
4129 outfmt(out2, "%s: %s\n", name, errmsg(e, E_EXEC));
4130 entry->cmdtype = CMDUNKNOWN;
4131 return;
4132
4133success:
4134 cmdp->rehash = 0;
4135 entry->cmdtype = cmdp->cmdtype;
4136 entry->u = cmdp->param;
4137}
4138
4139
4140
4141/*
4142 * Search the table of builtin commands.
4143 */
4144
Eric Andersen2870d962001-07-02 17:27:21 +00004145static int
4146bstrcmp(const void *name, const void *b)
4147{
4148 return strcmp((const char *)name, (*(const char *const *) b)+1);
4149}
4150
4151static struct builtincmd *
4152find_builtin(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00004153{
4154 struct builtincmd *bp;
4155
Eric Andersen2870d962001-07-02 17:27:21 +00004156 bp = bsearch(name, builtincmds, NUMBUILTINS, sizeof(struct builtincmd),
4157 bstrcmp
Eric Andersencb57d552001-06-28 07:25:16 +00004158 );
4159 return bp;
4160}
4161
4162
4163/*
4164 * Called when a cd is done. Marks all commands so the next time they
4165 * are executed they will be rehashed.
4166 */
4167
4168static void
Eric Andersen2870d962001-07-02 17:27:21 +00004169hashcd(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00004170 struct tblentry **pp;
4171 struct tblentry *cmdp;
4172
4173 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4174 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4175 if (cmdp->cmdtype == CMDNORMAL
4176 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
4177 cmdp->rehash = 1;
4178 }
4179 }
4180}
4181
4182
4183
4184/*
4185 * Called before PATH is changed. The argument is the new value of PATH;
4186 * pathval() still returns the old value at this point. Called with
4187 * interrupts off.
4188 */
4189
4190static void
Eric Andersen2870d962001-07-02 17:27:21 +00004191changepath(const char *newval)
Eric Andersencb57d552001-06-28 07:25:16 +00004192{
4193 int firstchange;
4194 int bltin;
4195
4196 firstchange = path_change(newval, &bltin);
4197 if (builtinloc < 0 && bltin >= 0)
Eric Andersen2870d962001-07-02 17:27:21 +00004198 builtinloc = bltin; /* zap builtins */
Eric Andersencb57d552001-06-28 07:25:16 +00004199 clearcmdentry(firstchange);
4200 builtinloc = bltin;
4201}
4202
4203
4204/*
4205 * Clear out command entries. The argument specifies the first entry in
4206 * PATH which has changed.
4207 */
4208
4209static void
4210clearcmdentry(firstchange)
4211 int firstchange;
4212{
4213 struct tblentry **tblp;
4214 struct tblentry **pp;
4215 struct tblentry *cmdp;
4216
4217 INTOFF;
4218 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4219 pp = tblp;
4220 while ((cmdp = *pp) != NULL) {
4221 if ((cmdp->cmdtype == CMDNORMAL &&
4222 cmdp->param.index >= firstchange)
4223 || (cmdp->cmdtype == CMDBUILTIN &&
4224 builtinloc >= firstchange)) {
4225 *pp = cmdp->next;
4226 ckfree(cmdp);
4227 } else {
4228 pp = &cmdp->next;
4229 }
4230 }
4231 }
4232 INTON;
4233}
4234
Eric Andersen2870d962001-07-02 17:27:21 +00004235/*
4236 * Free a parse tree.
4237 */
4238
4239static void
4240freefunc(union node *n)
4241{
4242 if (n)
4243 ckfree(n);
4244}
4245
Eric Andersencb57d552001-06-28 07:25:16 +00004246
4247/*
4248 * Delete all functions.
4249 */
4250
Eric Andersencb57d552001-06-28 07:25:16 +00004251static void
Eric Andersen2870d962001-07-02 17:27:21 +00004252deletefuncs(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00004253 struct tblentry **tblp;
4254 struct tblentry **pp;
4255 struct tblentry *cmdp;
4256
4257 INTOFF;
4258 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4259 pp = tblp;
4260 while ((cmdp = *pp) != NULL) {
4261 if (cmdp->cmdtype == CMDFUNCTION) {
4262 *pp = cmdp->next;
4263 freefunc(cmdp->param.func);
4264 ckfree(cmdp);
4265 } else {
4266 pp = &cmdp->next;
4267 }
4268 }
4269 }
4270 INTON;
4271}
4272
4273
4274
4275/*
4276 * Locate a command in the command hash table. If "add" is nonzero,
4277 * add the command to the table if it is not already present. The
4278 * variable "lastcmdentry" is set to point to the address of the link
4279 * pointing to the entry, so that delete_cmd_entry can delete the
4280 * entry.
4281 */
4282
Eric Andersen2870d962001-07-02 17:27:21 +00004283static struct tblentry **lastcmdentry;
Eric Andersencb57d552001-06-28 07:25:16 +00004284
4285static struct tblentry *
Eric Andersen2870d962001-07-02 17:27:21 +00004286cmdlookup(const char *name, int add)
Eric Andersencb57d552001-06-28 07:25:16 +00004287{
4288 int hashval;
Eric Andersen2870d962001-07-02 17:27:21 +00004289 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00004290 struct tblentry *cmdp;
4291 struct tblentry **pp;
4292
4293 p = name;
4294 hashval = *p << 4;
4295 while (*p)
4296 hashval += *p++;
4297 hashval &= 0x7FFF;
4298 pp = &cmdtable[hashval % CMDTABLESIZE];
4299 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4300 if (equal(cmdp->cmdname, name))
4301 break;
4302 pp = &cmdp->next;
4303 }
4304 if (add && cmdp == NULL) {
4305 INTOFF;
4306 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4307 + strlen(name) + 1);
4308 cmdp->next = NULL;
4309 cmdp->cmdtype = CMDUNKNOWN;
4310 cmdp->rehash = 0;
4311 strcpy(cmdp->cmdname, name);
4312 INTON;
4313 }
4314 lastcmdentry = pp;
4315 return cmdp;
4316}
4317
4318/*
4319 * Delete the command entry returned on the last lookup.
4320 */
4321
4322static void
4323delete_cmd_entry() {
4324 struct tblentry *cmdp;
4325
4326 INTOFF;
4327 cmdp = *lastcmdentry;
4328 *lastcmdentry = cmdp->next;
4329 ckfree(cmdp);
4330 INTON;
4331}
4332
4333
4334
Eric Andersencb57d552001-06-28 07:25:16 +00004335/*
4336 * Add a new command entry, replacing any existing command entry for
4337 * the same name.
4338 */
4339
4340static void
Eric Andersen2870d962001-07-02 17:27:21 +00004341addcmdentry(char *name, struct cmdentry *entry)
4342{
Eric Andersencb57d552001-06-28 07:25:16 +00004343 struct tblentry *cmdp;
4344
4345 INTOFF;
4346 cmdp = cmdlookup(name, 1);
4347 if (cmdp->cmdtype == CMDFUNCTION) {
4348 freefunc(cmdp->param.func);
4349 }
4350 cmdp->cmdtype = entry->cmdtype;
4351 cmdp->param = entry->u;
4352 INTON;
4353}
4354
4355
4356/*
4357 * Define a shell function.
4358 */
4359
Eric Andersen2870d962001-07-02 17:27:21 +00004360static union node *copyfunc(union node *);
4361
Eric Andersencb57d552001-06-28 07:25:16 +00004362static void
Eric Andersen2870d962001-07-02 17:27:21 +00004363defun(char *name, union node *func)
4364{
Eric Andersencb57d552001-06-28 07:25:16 +00004365 struct cmdentry entry;
4366
4367 entry.cmdtype = CMDFUNCTION;
4368 entry.u.func = copyfunc(func);
4369 addcmdentry(name, &entry);
4370}
4371
4372
4373/*
4374 * Delete a function if it exists.
4375 */
4376
4377static void
Eric Andersen2870d962001-07-02 17:27:21 +00004378unsetfunc(char *name)
4379{
Eric Andersencb57d552001-06-28 07:25:16 +00004380 struct tblentry *cmdp;
4381
4382 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) {
4383 freefunc(cmdp->param.func);
4384 delete_cmd_entry();
4385 }
4386}
4387
Eric Andersen2870d962001-07-02 17:27:21 +00004388/*
4389 * Wrapper around strcmp for qsort/bsearch/...
4390 */
4391static int
4392pstrcmp(const void *a, const void *b)
4393{
4394 return strcmp((const char *) a, *(const char *const *) b);
4395}
4396
4397/*
4398 * Find a keyword is in a sorted array.
4399 */
4400
4401static const char *const *
4402findkwd(const char *s)
4403{
4404 return bsearch(s, parsekwd, sizeof(parsekwd) / sizeof(const char *),
4405 sizeof(const char *), pstrcmp);
4406}
4407
Eric Andersencb57d552001-06-28 07:25:16 +00004408#ifdef ASH_TYPE
4409/*
4410 * Locate and print what a word is...
4411 */
4412
4413static int
4414typecmd(argc, argv)
4415 int argc;
4416 char **argv;
4417{
4418 int i;
4419 int err = 0;
4420
4421 for (i = 1; i < argc; i++) {
4422 err |= describe_command(argv[i], 1);
4423 }
4424 return err;
4425}
4426
4427static int
Eric Andersen2870d962001-07-02 17:27:21 +00004428describe_command(char *command, int verbose)
Eric Andersencb57d552001-06-28 07:25:16 +00004429{
4430 struct cmdentry entry;
4431 struct tblentry *cmdp;
Eric Andersen2870d962001-07-02 17:27:21 +00004432#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00004433 const struct alias *ap;
Eric Andersen2870d962001-07-02 17:27:21 +00004434#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004435 const char *path = pathval();
4436
4437 if (verbose) {
4438 out1str(command);
4439 }
4440
4441 /* First look at the keywords */
4442 if (findkwd(command)) {
4443 out1str(verbose ? " is a shell keyword" : command);
4444 goto out;
4445 }
4446
Eric Andersen2870d962001-07-02 17:27:21 +00004447#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00004448 /* Then look at the aliases */
4449 if ((ap = lookupalias(command, 0)) != NULL) {
4450 if (verbose) {
4451 out1fmt(" is an alias for %s", ap->val);
4452 } else {
4453 printalias(ap);
4454 }
4455 goto out;
4456 }
Eric Andersen2870d962001-07-02 17:27:21 +00004457#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004458 /* Then check if it is a tracked alias */
4459 if ((cmdp = cmdlookup(command, 0)) != NULL) {
4460 entry.cmdtype = cmdp->cmdtype;
4461 entry.u = cmdp->param;
4462 } else {
4463 /* Finally use brute force */
4464 find_command(command, &entry, DO_ABS, path);
4465 }
4466
4467 switch (entry.cmdtype) {
4468 case CMDNORMAL: {
4469 int j = entry.u.index;
4470 char *p;
4471 if (j == -1) {
4472 p = command;
4473 } else {
4474 do {
4475 p = padvance(&path, command);
4476 stunalloc(p);
4477 } while (--j >= 0);
4478 }
4479 if (verbose) {
4480 out1fmt(
4481 " is%s %s",
4482 cmdp ? " a tracked alias for" : nullstr, p
4483 );
4484 } else {
4485 out1str(p);
4486 }
4487 break;
4488 }
4489
4490 case CMDFUNCTION:
4491 if (verbose) {
4492 out1str(" is a shell function");
4493 } else {
4494 out1str(command);
4495 }
4496 break;
4497
4498 case CMDBUILTIN:
4499 if (verbose) {
4500 out1fmt(
4501 " is a %sshell builtin",
Eric Andersen2870d962001-07-02 17:27:21 +00004502 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
Eric Andersencb57d552001-06-28 07:25:16 +00004503 "special " : nullstr
4504 );
4505 } else {
4506 out1str(command);
4507 }
4508 break;
4509
4510 default:
4511 if (verbose) {
4512 out1str(": not found\n");
4513 }
4514 return 127;
4515 }
4516
4517out:
4518 out1c('\n');
4519 return 0;
4520}
Eric Andersen2870d962001-07-02 17:27:21 +00004521#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004522
Eric Andersen2870d962001-07-02 17:27:21 +00004523#ifdef ASH_CMDCMD
Eric Andersencb57d552001-06-28 07:25:16 +00004524static int
4525commandcmd(argc, argv)
4526 int argc;
4527 char **argv;
4528{
4529 int c;
4530 int default_path = 0;
4531 int verify_only = 0;
4532 int verbose_verify_only = 0;
4533
4534 while ((c = nextopt("pvV")) != '\0')
4535 switch (c) {
4536 case 'p':
4537 default_path = 1;
4538 break;
4539 case 'v':
4540 verify_only = 1;
4541 break;
4542 case 'V':
4543 verbose_verify_only = 1;
4544 break;
4545 default:
4546 outfmt(out2,
4547"command: nextopt returned character code 0%o\n", c);
4548 return EX_SOFTWARE;
4549 }
4550
4551 if (default_path + verify_only + verbose_verify_only > 1 ||
4552 !*argptr) {
4553 outfmt(out2,
4554"command [-p] command [arg ...]\n");
4555 outfmt(out2,
4556"command {-v|-V} command\n");
4557 return EX_USAGE;
4558 }
4559
4560#ifdef ASH_TYPE
4561 if (verify_only || verbose_verify_only) {
4562 return describe_command(*argptr, verbose_verify_only);
4563 }
Eric Andersen2870d962001-07-02 17:27:21 +00004564#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004565
4566 return 0;
4567}
Eric Andersen2870d962001-07-02 17:27:21 +00004568#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004569
4570static int
4571path_change(newval, bltin)
4572 const char *newval;
4573 int *bltin;
4574{
4575 const char *old, *new;
4576 int idx;
4577 int firstchange;
4578
4579 old = pathval();
4580 new = newval;
Eric Andersen2870d962001-07-02 17:27:21 +00004581 firstchange = 9999; /* assume no change */
Eric Andersencb57d552001-06-28 07:25:16 +00004582 idx = 0;
4583 *bltin = -1;
4584 for (;;) {
4585 if (*old != *new) {
4586 firstchange = idx;
4587 if ((*old == '\0' && *new == ':')
4588 || (*old == ':' && *new == '\0'))
4589 firstchange++;
Eric Andersen2870d962001-07-02 17:27:21 +00004590 old = new; /* ignore subsequent differences */
Eric Andersencb57d552001-06-28 07:25:16 +00004591 }
4592 if (*new == '\0')
4593 break;
4594 if (*new == '%' && *bltin < 0 && prefix("builtin", new + 1))
4595 *bltin = idx;
4596 if (*new == ':') {
4597 idx++;
4598 }
4599 new++, old++;
4600 }
4601 if (builtinloc >= 0 && *bltin < 0)
4602 firstchange = 0;
4603 return firstchange;
4604}
Eric Andersencb57d552001-06-28 07:25:16 +00004605/*
4606 * Routines to expand arguments to commands. We have to deal with
4607 * backquotes, shell variables, and file metacharacters.
4608 */
4609/*
4610 * _rmescape() flags
4611 */
Eric Andersen2870d962001-07-02 17:27:21 +00004612#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4613#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Eric Andersencb57d552001-06-28 07:25:16 +00004614
4615/*
4616 * Structure specifying which parts of the string should be searched
4617 * for IFS characters.
4618 */
4619
4620struct ifsregion {
Eric Andersen2870d962001-07-02 17:27:21 +00004621 struct ifsregion *next; /* next region in list */
4622 int begoff; /* offset of start of region */
4623 int endoff; /* offset of end of region */
4624 int nulonly; /* search for nul bytes only */
Eric Andersencb57d552001-06-28 07:25:16 +00004625};
4626
4627
Eric Andersen2870d962001-07-02 17:27:21 +00004628static char *expdest; /* output of current string */
4629static struct nodelist *argbackq; /* list of back quote expressions */
4630static struct ifsregion ifsfirst; /* first struct in list of ifs regions */
4631static struct ifsregion *ifslastp; /* last struct in list */
4632static struct arglist exparg; /* holds expanded arg list */
Eric Andersencb57d552001-06-28 07:25:16 +00004633
Eric Andersen2870d962001-07-02 17:27:21 +00004634static void argstr (char *, int);
4635static char *exptilde (char *, int);
4636static void expbackq (union node *, int, int);
4637static int subevalvar (char *, char *, int, int, int, int, int);
4638static char *evalvar (char *, int);
4639static int varisset (char *, int);
4640static void strtodest (const char *, const char *, int);
4641static void varvalue (char *, int, int);
4642static void recordregion (int, int, int);
4643static void removerecordregions (int);
4644static void ifsbreakup (char *, struct arglist *);
4645static void ifsfree (void);
4646static void expandmeta (struct strlist *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004647#if defined(__GLIBC__) && !defined(FNMATCH_BROKEN)
4648#define preglob(p) _rmescapes((p), RMESCAPE_ALLOC | RMESCAPE_GLOB)
4649#if !defined(GLOB_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00004650static void addglob (const glob_t *);
Eric Andersencb57d552001-06-28 07:25:16 +00004651#endif
4652#endif
4653#if !(defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersen2870d962001-07-02 17:27:21 +00004654static void expmeta (char *, char *);
Eric Andersencb57d552001-06-28 07:25:16 +00004655#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004656#if !(defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersen2870d962001-07-02 17:27:21 +00004657static struct strlist *expsort (struct strlist *);
4658static struct strlist *msort (struct strlist *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004659#endif
4660#if defined(__GLIBC__) && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00004661static int patmatch (char *, char *, int);
4662static int patmatch2 (char *, char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004663#else
Eric Andersen2870d962001-07-02 17:27:21 +00004664static int pmatch (char *, char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004665#define patmatch2 patmatch
4666#endif
Eric Andersen2870d962001-07-02 17:27:21 +00004667static char *cvtnum (int, char *);
Eric Andersencb57d552001-06-28 07:25:16 +00004668
4669/*
4670 * Expand shell variables and backquotes inside a here document.
4671 */
4672
Eric Andersen2870d962001-07-02 17:27:21 +00004673/* arg: the document, fd: where to write the expanded version */
Eric Andersencb57d552001-06-28 07:25:16 +00004674static void
Eric Andersen2870d962001-07-02 17:27:21 +00004675expandhere(union node *arg, int fd)
4676{
Eric Andersencb57d552001-06-28 07:25:16 +00004677 herefd = fd;
4678 expandarg(arg, (struct arglist *)NULL, 0);
4679 xwrite(fd, stackblock(), expdest - stackblock());
4680}
4681
4682
4683/*
4684 * Perform variable substitution and command substitution on an argument,
4685 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4686 * perform splitting and file name expansion. When arglist is NULL, perform
4687 * here document expansion.
4688 */
4689
4690static void
4691expandarg(arg, arglist, flag)
4692 union node *arg;
4693 struct arglist *arglist;
4694 int flag;
4695{
4696 struct strlist *sp;
4697 char *p;
4698
4699 argbackq = arg->narg.backquote;
4700 STARTSTACKSTR(expdest);
4701 ifsfirst.next = NULL;
4702 ifslastp = NULL;
4703 argstr(arg->narg.text, flag);
4704 if (arglist == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00004705 return; /* here document expanded */
Eric Andersencb57d552001-06-28 07:25:16 +00004706 }
4707 STPUTC('\0', expdest);
4708 p = grabstackstr(expdest);
4709 exparg.lastp = &exparg.list;
4710 /*
4711 * TODO - EXP_REDIR
4712 */
4713 if (flag & EXP_FULL) {
4714 ifsbreakup(p, &exparg);
4715 *exparg.lastp = NULL;
4716 exparg.lastp = &exparg.list;
4717 expandmeta(exparg.list, flag);
4718 } else {
4719 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
4720 rmescapes(p);
4721 sp = (struct strlist *)stalloc(sizeof (struct strlist));
4722 sp->text = p;
4723 *exparg.lastp = sp;
4724 exparg.lastp = &sp->next;
4725 }
4726 ifsfree();
4727 *exparg.lastp = NULL;
4728 if (exparg.list) {
4729 *arglist->lastp = exparg.list;
4730 arglist->lastp = exparg.lastp;
4731 }
4732}
4733
4734
4735
4736/*
4737 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4738 * characters to allow for further processing. Otherwise treat
4739 * $@ like $* since no splitting will be performed.
4740 */
4741
4742static void
4743argstr(p, flag)
4744 char *p;
4745 int flag;
4746{
4747 char c;
Eric Andersen2870d962001-07-02 17:27:21 +00004748 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
Eric Andersencb57d552001-06-28 07:25:16 +00004749 int firsteq = 1;
4750
4751 if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
4752 p = exptilde(p, flag);
4753 for (;;) {
4754 switch (c = *p++) {
4755 case '\0':
4756 case CTLENDVAR: /* ??? */
4757 goto breakloop;
4758 case CTLQUOTEMARK:
4759 /* "$@" syntax adherence hack */
4760 if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=')
4761 break;
4762 if ((flag & EXP_FULL) != 0)
4763 STPUTC(c, expdest);
4764 break;
4765 case CTLESC:
4766 if (quotes)
4767 STPUTC(c, expdest);
4768 c = *p++;
4769 STPUTC(c, expdest);
4770 break;
4771 case CTLVAR:
4772 p = evalvar(p, flag);
4773 break;
4774 case CTLBACKQ:
4775 case CTLBACKQ|CTLQUOTE:
4776 expbackq(argbackq->n, c & CTLQUOTE, flag);
4777 argbackq = argbackq->next;
4778 break;
4779#ifdef ASH_MATH_SUPPORT
4780 case CTLENDARI:
4781 expari(flag);
4782 break;
Eric Andersen2870d962001-07-02 17:27:21 +00004783#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004784 case ':':
4785 case '=':
4786 /*
4787 * sort of a hack - expand tildes in variable
4788 * assignments (after the first '=' and after ':'s).
4789 */
4790 STPUTC(c, expdest);
4791 if (flag & EXP_VARTILDE && *p == '~') {
4792 if (c == '=') {
4793 if (firsteq)
4794 firsteq = 0;
4795 else
4796 break;
4797 }
4798 p = exptilde(p, flag);
4799 }
4800 break;
4801 default:
4802 STPUTC(c, expdest);
4803 }
4804 }
4805breakloop:;
4806 return;
4807}
4808
4809static char *
4810exptilde(p, flag)
4811 char *p;
4812 int flag;
4813{
4814 char c, *startp = p;
4815 struct passwd *pw;
4816 const char *home;
4817 int quotes = flag & (EXP_FULL | EXP_CASE);
4818
4819 while ((c = *p) != '\0') {
4820 switch(c) {
4821 case CTLESC:
4822 return (startp);
4823 case CTLQUOTEMARK:
4824 return (startp);
4825 case ':':
4826 if (flag & EXP_VARTILDE)
4827 goto done;
4828 break;
4829 case '/':
4830 goto done;
4831 }
4832 p++;
4833 }
4834done:
4835 *p = '\0';
4836 if (*(startp+1) == '\0') {
4837 if ((home = lookupvar("HOME")) == NULL)
4838 goto lose;
4839 } else {
4840 if ((pw = getpwnam(startp+1)) == NULL)
4841 goto lose;
4842 home = pw->pw_dir;
4843 }
4844 if (*home == '\0')
4845 goto lose;
4846 *p = c;
4847 strtodest(home, SQSYNTAX, quotes);
4848 return (p);
4849lose:
4850 *p = c;
4851 return (startp);
4852}
4853
4854
Eric Andersen2870d962001-07-02 17:27:21 +00004855static void
4856removerecordregions(int endoff)
Eric Andersencb57d552001-06-28 07:25:16 +00004857{
4858 if (ifslastp == NULL)
4859 return;
4860
4861 if (ifsfirst.endoff > endoff) {
4862 while (ifsfirst.next != NULL) {
4863 struct ifsregion *ifsp;
4864 INTOFF;
4865 ifsp = ifsfirst.next->next;
4866 ckfree(ifsfirst.next);
4867 ifsfirst.next = ifsp;
4868 INTON;
4869 }
4870 if (ifsfirst.begoff > endoff)
4871 ifslastp = NULL;
4872 else {
4873 ifslastp = &ifsfirst;
4874 ifsfirst.endoff = endoff;
4875 }
4876 return;
4877 }
Eric Andersen2870d962001-07-02 17:27:21 +00004878
Eric Andersencb57d552001-06-28 07:25:16 +00004879 ifslastp = &ifsfirst;
4880 while (ifslastp->next && ifslastp->next->begoff < endoff)
4881 ifslastp=ifslastp->next;
4882 while (ifslastp->next != NULL) {
4883 struct ifsregion *ifsp;
4884 INTOFF;
4885 ifsp = ifslastp->next->next;
4886 ckfree(ifslastp->next);
4887 ifslastp->next = ifsp;
4888 INTON;
4889 }
4890 if (ifslastp->endoff > endoff)
4891 ifslastp->endoff = endoff;
4892}
4893
4894
4895#ifdef ASH_MATH_SUPPORT
4896/*
4897 * Expand arithmetic expression. Backup to start of expression,
4898 * evaluate, place result in (backed up) result, adjust string position.
4899 */
4900static void
Eric Andersen2870d962001-07-02 17:27:21 +00004901expari(int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004902{
4903 char *p, *start;
4904 int result;
4905 int begoff;
4906 int quotes = flag & (EXP_FULL | EXP_CASE);
4907 int quoted;
4908
Eric Andersen2870d962001-07-02 17:27:21 +00004909 /* ifsfree(); */
Eric Andersencb57d552001-06-28 07:25:16 +00004910
4911 /*
4912 * This routine is slightly over-complicated for
4913 * efficiency. First we make sure there is
4914 * enough space for the result, which may be bigger
4915 * than the expression if we add exponentation. Next we
4916 * scan backwards looking for the start of arithmetic. If the
4917 * next previous character is a CTLESC character, then we
4918 * have to rescan starting from the beginning since CTLESC
4919 * characters have to be processed left to right.
4920 */
4921 CHECKSTRSPACE(10, expdest);
4922 USTPUTC('\0', expdest);
4923 start = stackblock();
4924 p = expdest - 1;
4925 while (*p != CTLARI && p >= start)
4926 --p;
4927 if (*p != CTLARI)
4928 error("missing CTLARI (shouldn't happen)");
4929 if (p > start && *(p-1) == CTLESC)
4930 for (p = start; *p != CTLARI; p++)
4931 if (*p == CTLESC)
4932 p++;
4933
4934 if (p[1] == '"')
4935 quoted=1;
4936 else
4937 quoted=0;
4938 begoff = p - start;
4939 removerecordregions(begoff);
4940 if (quotes)
4941 rmescapes(p+2);
4942 result = arith(p+2);
4943 fmtstr(p, 12, "%d", result);
4944
4945 while (*p++)
4946 ;
4947
4948 if (quoted == 0)
4949 recordregion(begoff, p - 1 - start, 0);
4950 result = expdest - p + 1;
4951 STADJUST(-result, expdest);
4952}
Eric Andersen2870d962001-07-02 17:27:21 +00004953#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004954
4955/*
4956 * Expand stuff in backwards quotes.
4957 */
4958
4959static void
4960expbackq(cmd, quoted, flag)
4961 union node *cmd;
4962 int quoted;
4963 int flag;
4964{
4965 volatile struct backcmd in;
4966 int i;
4967 char buf[128];
4968 char *p;
4969 char *dest = expdest;
4970 volatile struct ifsregion saveifs;
4971 struct ifsregion *volatile savelastp;
4972 struct nodelist *volatile saveargbackq;
4973 char lastc;
4974 int startloc = dest - stackblock();
4975 char const *syntax = quoted? DQSYNTAX : BASESYNTAX;
4976 volatile int saveherefd;
4977 int quotes = flag & (EXP_FULL | EXP_CASE);
4978 struct jmploc jmploc;
4979 struct jmploc *volatile savehandler;
4980 int ex;
4981
4982#if __GNUC__
4983 /* Avoid longjmp clobbering */
4984 (void) &dest;
4985 (void) &syntax;
4986#endif
4987
4988 in.fd = -1;
4989 in.buf = 0;
4990 in.jp = 0;
4991
4992 INTOFF;
4993 saveifs = ifsfirst;
4994 savelastp = ifslastp;
4995 saveargbackq = argbackq;
4996 saveherefd = herefd;
4997 herefd = -1;
4998 if ((ex = setjmp(jmploc.loc))) {
4999 goto err1;
5000 }
5001 savehandler = handler;
5002 handler = &jmploc;
5003 INTON;
5004 p = grabstackstr(dest);
5005 evalbackcmd(cmd, (struct backcmd *) &in);
5006 ungrabstackstr(p, dest);
5007err1:
5008 INTOFF;
5009 ifsfirst = saveifs;
5010 ifslastp = savelastp;
5011 argbackq = saveargbackq;
5012 herefd = saveherefd;
5013 if (ex) {
5014 goto err2;
5015 }
5016
5017 p = in.buf;
5018 lastc = '\0';
5019 for (;;) {
5020 if (--in.nleft < 0) {
5021 if (in.fd < 0)
5022 break;
5023 while ((i = read(in.fd, buf, sizeof buf)) < 0 && errno == EINTR);
5024 TRACE(("expbackq: read returns %d\n", i));
5025 if (i <= 0)
5026 break;
5027 p = buf;
5028 in.nleft = i - 1;
5029 }
5030 lastc = *p++;
5031 if (lastc != '\0') {
5032 if (quotes && syntax[(int)lastc] == CCTL)
5033 STPUTC(CTLESC, dest);
5034 STPUTC(lastc, dest);
5035 }
5036 }
5037
5038 /* Eat all trailing newlines */
5039 for (; dest > stackblock() && dest[-1] == '\n';)
5040 STUNPUTC(dest);
5041
5042err2:
5043 if (in.fd >= 0)
5044 close(in.fd);
5045 if (in.buf)
5046 ckfree(in.buf);
5047 if (in.jp)
5048 exitstatus = waitforjob(in.jp);
5049 handler = savehandler;
5050 if (ex) {
5051 longjmp(handler->loc, 1);
5052 }
5053 if (quoted == 0)
5054 recordregion(startloc, dest - stackblock(), 0);
5055 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
5056 (dest - stackblock()) - startloc,
5057 (dest - stackblock()) - startloc,
5058 stackblock() + startloc));
5059 expdest = dest;
5060 INTON;
5061}
5062
Eric Andersencb57d552001-06-28 07:25:16 +00005063static int
5064subevalvar(p, str, strloc, subtype, startloc, varflags, quotes)
5065 char *p;
5066 char *str;
5067 int strloc;
5068 int subtype;
5069 int startloc;
5070 int varflags;
5071 int quotes;
5072{
5073 char *startp;
5074 char *loc = NULL;
5075 char *q;
5076 int c = 0;
5077 int saveherefd = herefd;
5078 struct nodelist *saveargbackq = argbackq;
5079 int amount;
5080
5081 herefd = -1;
5082 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
5083 STACKSTRNUL(expdest);
5084 herefd = saveherefd;
5085 argbackq = saveargbackq;
5086 startp = stackblock() + startloc;
5087 if (str == NULL)
5088 str = stackblock() + strloc;
5089
5090 switch (subtype) {
5091 case VSASSIGN:
5092 setvar(str, startp, 0);
5093 amount = startp - expdest;
5094 STADJUST(amount, expdest);
5095 varflags &= ~VSNUL;
5096 if (c != 0)
5097 *loc = c;
5098 return 1;
5099
5100 case VSQUESTION:
5101 if (*p != CTLENDVAR) {
5102 outfmt(&errout, snlfmt, startp);
5103 error((char *)NULL);
5104 }
5105 error("%.*s: parameter %snot set", p - str - 1,
5106 str, (varflags & VSNUL) ? "null or "
5107 : nullstr);
5108 /* NOTREACHED */
5109
5110 case VSTRIMLEFT:
5111 for (loc = startp; loc < str; loc++) {
5112 c = *loc;
5113 *loc = '\0';
5114 if (patmatch2(str, startp, quotes))
5115 goto recordleft;
5116 *loc = c;
5117 if (quotes && *loc == CTLESC)
Eric Andersen2870d962001-07-02 17:27:21 +00005118 loc++;
Eric Andersencb57d552001-06-28 07:25:16 +00005119 }
5120 return 0;
5121
5122 case VSTRIMLEFTMAX:
5123 for (loc = str - 1; loc >= startp;) {
5124 c = *loc;
5125 *loc = '\0';
5126 if (patmatch2(str, startp, quotes))
5127 goto recordleft;
5128 *loc = c;
5129 loc--;
5130 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
5131 for (q = startp; q < loc; q++)
5132 if (*q == CTLESC)
5133 q++;
5134 if (q > loc)
5135 loc--;
5136 }
5137 }
5138 return 0;
5139
5140 case VSTRIMRIGHT:
Eric Andersen2870d962001-07-02 17:27:21 +00005141 for (loc = str - 1; loc >= startp;) {
Eric Andersencb57d552001-06-28 07:25:16 +00005142 if (patmatch2(str, loc, quotes))
5143 goto recordright;
5144 loc--;
Eric Andersen2870d962001-07-02 17:27:21 +00005145 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
Eric Andersencb57d552001-06-28 07:25:16 +00005146 for (q = startp; q < loc; q++)
5147 if (*q == CTLESC)
5148 q++;
5149 if (q > loc)
5150 loc--;
5151 }
5152 }
5153 return 0;
5154
5155 case VSTRIMRIGHTMAX:
5156 for (loc = startp; loc < str - 1; loc++) {
5157 if (patmatch2(str, loc, quotes))
5158 goto recordright;
5159 if (quotes && *loc == CTLESC)
Eric Andersen2870d962001-07-02 17:27:21 +00005160 loc++;
Eric Andersencb57d552001-06-28 07:25:16 +00005161 }
5162 return 0;
5163
5164#ifdef DEBUG
5165 default:
5166 abort();
5167#endif
5168 }
5169
5170recordleft:
5171 *loc = c;
5172 amount = ((str - 1) - (loc - startp)) - expdest;
5173 STADJUST(amount, expdest);
5174 while (loc != str - 1)
5175 *startp++ = *loc++;
5176 return 1;
5177
5178recordright:
5179 amount = loc - expdest;
5180 STADJUST(amount, expdest);
5181 STPUTC('\0', expdest);
5182 STADJUST(-1, expdest);
5183 return 1;
5184}
5185
5186
5187/*
5188 * Expand a variable, and return a pointer to the next character in the
5189 * input string.
5190 */
5191
5192static char *
5193evalvar(p, flag)
5194 char *p;
5195 int flag;
5196{
5197 int subtype;
5198 int varflags;
5199 char *var;
5200 char *val;
5201 int patloc;
5202 int c;
5203 int set;
5204 int special;
5205 int startloc;
5206 int varlen;
5207 int easy;
5208 int quotes = flag & (EXP_FULL | EXP_CASE);
5209
5210 varflags = *p++;
5211 subtype = varflags & VSTYPE;
5212 var = p;
5213 special = 0;
5214 if (! is_name(*p))
5215 special = 1;
5216 p = strchr(p, '=') + 1;
5217again: /* jump here after setting a variable with ${var=text} */
5218 if (special) {
5219 set = varisset(var, varflags & VSNUL);
5220 val = NULL;
5221 } else {
5222 val = lookupvar(var);
5223 if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
5224 val = NULL;
5225 set = 0;
5226 } else
5227 set = 1;
5228 }
5229 varlen = 0;
5230 startloc = expdest - stackblock();
5231 if (set && subtype != VSPLUS) {
5232 /* insert the value of the variable */
5233 if (special) {
5234 varvalue(var, varflags & VSQUOTE, flag);
5235 if (subtype == VSLENGTH) {
5236 varlen = expdest - stackblock() - startloc;
5237 STADJUST(-varlen, expdest);
5238 }
5239 } else {
5240 if (subtype == VSLENGTH) {
5241 varlen = strlen(val);
5242 } else {
5243 strtodest(
5244 val,
5245 varflags & VSQUOTE ?
5246 DQSYNTAX : BASESYNTAX,
5247 quotes
5248 );
5249 }
5250 }
5251 }
5252
5253 if (subtype == VSPLUS)
5254 set = ! set;
5255
5256 easy = ((varflags & VSQUOTE) == 0 ||
5257 (*var == '@' && shellparam.nparam != 1));
5258
5259
5260 switch (subtype) {
5261 case VSLENGTH:
5262 expdest = cvtnum(varlen, expdest);
5263 goto record;
5264
5265 case VSNORMAL:
5266 if (!easy)
5267 break;
5268record:
5269 recordregion(startloc, expdest - stackblock(),
5270 varflags & VSQUOTE);
5271 break;
5272
5273 case VSPLUS:
5274 case VSMINUS:
5275 if (!set) {
Eric Andersen2870d962001-07-02 17:27:21 +00005276 argstr(p, flag);
Eric Andersencb57d552001-06-28 07:25:16 +00005277 break;
5278 }
5279 if (easy)
5280 goto record;
5281 break;
5282
5283 case VSTRIMLEFT:
5284 case VSTRIMLEFTMAX:
5285 case VSTRIMRIGHT:
5286 case VSTRIMRIGHTMAX:
5287 if (!set)
5288 break;
5289 /*
5290 * Terminate the string and start recording the pattern
5291 * right after it
5292 */
5293 STPUTC('\0', expdest);
5294 patloc = expdest - stackblock();
5295 if (subevalvar(p, NULL, patloc, subtype,
5296 startloc, varflags, quotes) == 0) {
5297 int amount = (expdest - stackblock() - patloc) + 1;
5298 STADJUST(-amount, expdest);
5299 }
5300 /* Remove any recorded regions beyond start of variable */
5301 removerecordregions(startloc);
5302 goto record;
5303
5304 case VSASSIGN:
5305 case VSQUESTION:
5306 if (!set) {
5307 if (subevalvar(p, var, 0, subtype, startloc,
5308 varflags, quotes)) {
5309 varflags &= ~VSNUL;
Eric Andersen2870d962001-07-02 17:27:21 +00005310 /*
5311 * Remove any recorded regions beyond
5312 * start of variable
Eric Andersencb57d552001-06-28 07:25:16 +00005313 */
5314 removerecordregions(startloc);
5315 goto again;
5316 }
5317 break;
5318 }
5319 if (easy)
5320 goto record;
5321 break;
5322
5323#ifdef DEBUG
5324 default:
5325 abort();
5326#endif
5327 }
5328
Eric Andersen2870d962001-07-02 17:27:21 +00005329 if (subtype != VSNORMAL) { /* skip to end of alternative */
Eric Andersencb57d552001-06-28 07:25:16 +00005330 int nesting = 1;
5331 for (;;) {
5332 if ((c = *p++) == CTLESC)
5333 p++;
5334 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
5335 if (set)
5336 argbackq = argbackq->next;
5337 } else if (c == CTLVAR) {
5338 if ((*p++ & VSTYPE) != VSNORMAL)
5339 nesting++;
5340 } else if (c == CTLENDVAR) {
5341 if (--nesting == 0)
5342 break;
5343 }
5344 }
5345 }
5346 return p;
5347}
5348
Eric Andersencb57d552001-06-28 07:25:16 +00005349/*
5350 * Test whether a specialized variable is set.
5351 */
5352
5353static int
5354varisset(name, nulok)
5355 char *name;
5356 int nulok;
5357{
5358 if (*name == '!')
5359 return backgndpid != -1;
5360 else if (*name == '@' || *name == '*') {
5361 if (*shellparam.p == NULL)
5362 return 0;
5363
5364 if (nulok) {
5365 char **av;
5366
5367 for (av = shellparam.p; *av; av++)
5368 if (**av != '\0')
5369 return 1;
5370 return 0;
5371 }
5372 } else if (is_digit(*name)) {
5373 char *ap;
5374 int num = atoi(name);
5375
5376 if (num > shellparam.nparam)
5377 return 0;
5378
5379 if (num == 0)
5380 ap = arg0;
5381 else
5382 ap = shellparam.p[num - 1];
5383
5384 if (nulok && (ap == NULL || *ap == '\0'))
5385 return 0;
5386 }
5387 return 1;
5388}
5389
Eric Andersencb57d552001-06-28 07:25:16 +00005390/*
5391 * Put a string on the stack.
5392 */
5393
5394static void
5395strtodest(p, syntax, quotes)
5396 const char *p;
5397 const char *syntax;
5398 int quotes;
5399{
5400 while (*p) {
5401 if (quotes && syntax[(int) *p] == CCTL)
5402 STPUTC(CTLESC, expdest);
5403 STPUTC(*p++, expdest);
5404 }
5405}
5406
Eric Andersencb57d552001-06-28 07:25:16 +00005407/*
5408 * Add the value of a specialized variable to the stack string.
5409 */
5410
5411static void
5412varvalue(name, quoted, flags)
5413 char *name;
5414 int quoted;
5415 int flags;
5416{
5417 int num;
5418 char *p;
5419 int i;
5420 int sep;
5421 int sepq = 0;
5422 char **ap;
5423 char const *syntax;
5424 int allow_split = flags & EXP_FULL;
5425 int quotes = flags & (EXP_FULL | EXP_CASE);
5426
5427 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5428 switch (*name) {
5429 case '$':
5430 num = rootpid;
5431 goto numvar;
5432 case '?':
5433 num = oexitstatus;
5434 goto numvar;
5435 case '#':
5436 num = shellparam.nparam;
5437 goto numvar;
5438 case '!':
5439 num = backgndpid;
5440numvar:
5441 expdest = cvtnum(num, expdest);
5442 break;
5443 case '-':
5444 for (i = 0 ; i < NOPTS ; i++) {
Eric Andersen2870d962001-07-02 17:27:21 +00005445 if (optent_val(i))
5446 STPUTC(optent_letter(optlist[i]), expdest);
Eric Andersencb57d552001-06-28 07:25:16 +00005447 }
5448 break;
5449 case '@':
5450 if (allow_split && quoted) {
5451 sep = 1 << CHAR_BIT;
5452 goto param;
5453 }
5454 /* fall through */
5455 case '*':
5456 sep = ifsset() ? ifsval()[0] : ' ';
5457 if (quotes) {
5458 sepq = syntax[(int) sep] == CCTL;
5459 }
5460param:
5461 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
5462 strtodest(p, syntax, quotes);
5463 if (*ap && sep) {
5464 if (sepq)
5465 STPUTC(CTLESC, expdest);
5466 STPUTC(sep, expdest);
5467 }
5468 }
5469 break;
5470 case '0':
5471 strtodest(arg0, syntax, quotes);
5472 break;
5473 default:
5474 num = atoi(name);
5475 if (num > 0 && num <= shellparam.nparam) {
5476 strtodest(shellparam.p[num - 1], syntax, quotes);
5477 }
5478 break;
5479 }
5480}
5481
5482
Eric Andersencb57d552001-06-28 07:25:16 +00005483/*
5484 * Record the fact that we have to scan this region of the
5485 * string for IFS characters.
5486 */
5487
5488static void
5489recordregion(start, end, nulonly)
5490 int start;
5491 int end;
5492 int nulonly;
5493{
5494 struct ifsregion *ifsp;
5495
5496 if (ifslastp == NULL) {
5497 ifsp = &ifsfirst;
5498 } else {
5499 INTOFF;
5500 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
5501 ifsp->next = NULL;
5502 ifslastp->next = ifsp;
5503 INTON;
5504 }
5505 ifslastp = ifsp;
5506 ifslastp->begoff = start;
5507 ifslastp->endoff = end;
5508 ifslastp->nulonly = nulonly;
5509}
5510
5511
5512
5513/*
5514 * Break the argument string into pieces based upon IFS and add the
5515 * strings to the argument list. The regions of the string to be
5516 * searched for IFS characters have been stored by recordregion.
5517 */
5518static void
5519ifsbreakup(string, arglist)
5520 char *string;
5521 struct arglist *arglist;
5522 {
5523 struct ifsregion *ifsp;
5524 struct strlist *sp;
5525 char *start;
5526 char *p;
5527 char *q;
5528 const char *ifs, *realifs;
5529 int ifsspc;
5530 int nulonly;
5531
5532
5533 start = string;
5534 ifsspc = 0;
5535 nulonly = 0;
5536 realifs = ifsset() ? ifsval() : defifs;
5537 if (ifslastp != NULL) {
5538 ifsp = &ifsfirst;
5539 do {
5540 p = string + ifsp->begoff;
5541 nulonly = ifsp->nulonly;
5542 ifs = nulonly ? nullstr : realifs;
5543 ifsspc = 0;
5544 while (p < string + ifsp->endoff) {
5545 q = p;
5546 if (*p == CTLESC)
5547 p++;
5548 if (strchr(ifs, *p)) {
5549 if (!nulonly)
5550 ifsspc = (strchr(defifs, *p) != NULL);
5551 /* Ignore IFS whitespace at start */
5552 if (q == start && ifsspc) {
5553 p++;
5554 start = p;
5555 continue;
5556 }
5557 *q = '\0';
5558 sp = (struct strlist *)stalloc(sizeof *sp);
5559 sp->text = start;
5560 *arglist->lastp = sp;
5561 arglist->lastp = &sp->next;
5562 p++;
5563 if (!nulonly) {
5564 for (;;) {
5565 if (p >= string + ifsp->endoff) {
5566 break;
5567 }
5568 q = p;
5569 if (*p == CTLESC)
5570 p++;
5571 if (strchr(ifs, *p) == NULL ) {
5572 p = q;
5573 break;
5574 } else if (strchr(defifs, *p) == NULL) {
5575 if (ifsspc) {
5576 p++;
5577 ifsspc = 0;
5578 } else {
5579 p = q;
5580 break;
5581 }
5582 } else
5583 p++;
5584 }
5585 }
5586 start = p;
5587 } else
5588 p++;
5589 }
5590 } while ((ifsp = ifsp->next) != NULL);
5591 if (!(*start || (!ifsspc && start > string && nulonly))) {
5592 return;
5593 }
5594 }
5595
5596 sp = (struct strlist *)stalloc(sizeof *sp);
5597 sp->text = start;
5598 *arglist->lastp = sp;
5599 arglist->lastp = &sp->next;
5600}
5601
5602static void
5603ifsfree()
5604{
5605 while (ifsfirst.next != NULL) {
5606 struct ifsregion *ifsp;
5607 INTOFF;
5608 ifsp = ifsfirst.next->next;
5609 ckfree(ifsfirst.next);
5610 ifsfirst.next = ifsp;
5611 INTON;
5612 }
5613 ifslastp = NULL;
5614 ifsfirst.next = NULL;
5615}
5616
Eric Andersen2870d962001-07-02 17:27:21 +00005617/*
5618 * Add a file name to the list.
5619 */
Eric Andersencb57d552001-06-28 07:25:16 +00005620
Eric Andersen2870d962001-07-02 17:27:21 +00005621static void
5622addfname(const char *name)
5623{
5624 char *p;
5625 struct strlist *sp;
5626
5627 p = sstrdup(name);
5628 sp = (struct strlist *)stalloc(sizeof *sp);
5629 sp->text = p;
5630 *exparg.lastp = sp;
5631 exparg.lastp = &sp->next;
5632}
Eric Andersencb57d552001-06-28 07:25:16 +00005633
5634/*
5635 * Expand shell metacharacters. At this point, the only control characters
5636 * should be escapes. The results are stored in the list exparg.
5637 */
5638
5639#if defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)
5640static void
5641expandmeta(str, flag)
5642 struct strlist *str;
5643 int flag;
5644{
5645 const char *p;
5646 glob_t pglob;
5647 /* TODO - EXP_REDIR */
5648
5649 while (str) {
5650 if (fflag)
5651 goto nometa;
5652 p = preglob(str->text);
5653 INTOFF;
5654 switch (glob(p, GLOB_NOMAGIC, 0, &pglob)) {
5655 case 0:
5656 if (!(pglob.gl_flags & GLOB_MAGCHAR))
5657 goto nometa2;
5658 addglob(&pglob);
5659 globfree(&pglob);
5660 INTON;
5661 break;
5662 case GLOB_NOMATCH:
5663nometa2:
5664 globfree(&pglob);
5665 INTON;
5666nometa:
5667 *exparg.lastp = str;
5668 rmescapes(str->text);
5669 exparg.lastp = &str->next;
5670 break;
Eric Andersen2870d962001-07-02 17:27:21 +00005671 default: /* GLOB_NOSPACE */
Eric Andersencb57d552001-06-28 07:25:16 +00005672 error("Out of space");
5673 }
5674 str = str->next;
5675 }
5676}
5677
5678
5679/*
5680 * Add the result of glob(3) to the list.
5681 */
5682
5683static void
5684addglob(pglob)
5685 const glob_t *pglob;
5686{
5687 char **p = pglob->gl_pathv;
5688
5689 do {
5690 addfname(*p);
5691 } while (*++p);
5692}
5693
5694
Eric Andersen2870d962001-07-02 17:27:21 +00005695#else /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
Eric Andersencb57d552001-06-28 07:25:16 +00005696static char *expdir;
5697
5698
5699static void
5700expandmeta(str, flag)
5701 struct strlist *str;
5702 int flag;
5703{
5704 char *p;
5705 struct strlist **savelastp;
5706 struct strlist *sp;
5707 char c;
5708 /* TODO - EXP_REDIR */
5709
5710 while (str) {
5711 if (fflag)
5712 goto nometa;
5713 p = str->text;
Eric Andersen2870d962001-07-02 17:27:21 +00005714 for (;;) { /* fast check for meta chars */
Eric Andersencb57d552001-06-28 07:25:16 +00005715 if ((c = *p++) == '\0')
5716 goto nometa;
5717 if (c == '*' || c == '?' || c == '[' || c == '!')
5718 break;
5719 }
5720 savelastp = exparg.lastp;
5721 INTOFF;
5722 if (expdir == NULL) {
5723 int i = strlen(str->text);
5724 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5725 }
5726
5727 expmeta(expdir, str->text);
5728 ckfree(expdir);
5729 expdir = NULL;
5730 INTON;
5731 if (exparg.lastp == savelastp) {
5732 /*
5733 * no matches
5734 */
5735nometa:
5736 *exparg.lastp = str;
5737 rmescapes(str->text);
5738 exparg.lastp = &str->next;
5739 } else {
5740 *exparg.lastp = NULL;
5741 *savelastp = sp = expsort(*savelastp);
5742 while (sp->next != NULL)
5743 sp = sp->next;
5744 exparg.lastp = &sp->next;
5745 }
5746 str = str->next;
5747 }
5748}
5749
5750
5751/*
5752 * Do metacharacter (i.e. *, ?, [...]) expansion.
5753 */
5754
5755static void
5756expmeta(enddir, name)
5757 char *enddir;
5758 char *name;
5759 {
5760 char *p;
5761 const char *cp;
5762 char *q;
5763 char *start;
5764 char *endname;
5765 int metaflag;
5766 struct stat statb;
5767 DIR *dirp;
5768 struct dirent *dp;
5769 int atend;
5770 int matchdot;
5771
5772 metaflag = 0;
5773 start = name;
5774 for (p = name ; ; p++) {
5775 if (*p == '*' || *p == '?')
5776 metaflag = 1;
5777 else if (*p == '[') {
5778 q = p + 1;
5779 if (*q == '!')
5780 q++;
5781 for (;;) {
5782 while (*q == CTLQUOTEMARK)
5783 q++;
5784 if (*q == CTLESC)
5785 q++;
5786 if (*q == '/' || *q == '\0')
5787 break;
5788 if (*++q == ']') {
5789 metaflag = 1;
5790 break;
5791 }
5792 }
Eric Andersen2870d962001-07-02 17:27:21 +00005793 } else if (*p == '!' && p[1] == '!' && (p == name || p[-1] == '/')) {
Eric Andersencb57d552001-06-28 07:25:16 +00005794 metaflag = 1;
5795 } else if (*p == '\0')
5796 break;
5797 else if (*p == CTLQUOTEMARK)
5798 continue;
5799 else if (*p == CTLESC)
5800 p++;
5801 if (*p == '/') {
5802 if (metaflag)
5803 break;
5804 start = p + 1;
5805 }
5806 }
Eric Andersen2870d962001-07-02 17:27:21 +00005807 if (metaflag == 0) { /* we've reached the end of the file name */
Eric Andersencb57d552001-06-28 07:25:16 +00005808 if (enddir != expdir)
5809 metaflag++;
5810 for (p = name ; ; p++) {
5811 if (*p == CTLQUOTEMARK)
5812 continue;
5813 if (*p == CTLESC)
5814 p++;
5815 *enddir++ = *p;
5816 if (*p == '\0')
5817 break;
5818 }
5819 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
5820 addfname(expdir);
5821 return;
5822 }
5823 endname = p;
5824 if (start != name) {
5825 p = name;
5826 while (p < start) {
5827 while (*p == CTLQUOTEMARK)
5828 p++;
5829 if (*p == CTLESC)
5830 p++;
5831 *enddir++ = *p++;
5832 }
5833 }
5834 if (enddir == expdir) {
5835 cp = ".";
5836 } else if (enddir == expdir + 1 && *expdir == '/') {
5837 cp = "/";
5838 } else {
5839 cp = expdir;
5840 enddir[-1] = '\0';
5841 }
5842 if ((dirp = opendir(cp)) == NULL)
5843 return;
5844 if (enddir != expdir)
5845 enddir[-1] = '/';
5846 if (*endname == 0) {
5847 atend = 1;
5848 } else {
5849 atend = 0;
5850 *endname++ = '\0';
5851 }
5852 matchdot = 0;
5853 p = start;
5854 while (*p == CTLQUOTEMARK)
5855 p++;
5856 if (*p == CTLESC)
5857 p++;
5858 if (*p == '.')
5859 matchdot++;
5860 while (! int_pending() && (dp = readdir(dirp)) != NULL) {
5861 if (dp->d_name[0] == '.' && ! matchdot)
5862 continue;
5863 if (patmatch(start, dp->d_name, 0)) {
5864 if (atend) {
Eric Andersen2870d962001-07-02 17:27:21 +00005865 strcpy(enddir, dp->d_name);
Eric Andersencb57d552001-06-28 07:25:16 +00005866 addfname(expdir);
5867 } else {
5868 for (p = enddir, cp = dp->d_name;
5869 (*p++ = *cp++) != '\0';)
5870 continue;
5871 p[-1] = '/';
5872 expmeta(p, endname);
5873 }
5874 }
5875 }
5876 closedir(dirp);
5877 if (! atend)
5878 endname[-1] = '/';
5879}
Eric Andersen2870d962001-07-02 17:27:21 +00005880#endif /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
Eric Andersencb57d552001-06-28 07:25:16 +00005881
5882
Eric Andersencb57d552001-06-28 07:25:16 +00005883
5884#if !(defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
5885/*
5886 * Sort the results of file name expansion. It calculates the number of
5887 * strings to sort and then calls msort (short for merge sort) to do the
5888 * work.
5889 */
5890
5891static struct strlist *
5892expsort(str)
5893 struct strlist *str;
5894 {
5895 int len;
5896 struct strlist *sp;
5897
5898 len = 0;
5899 for (sp = str ; sp ; sp = sp->next)
5900 len++;
5901 return msort(str, len);
5902}
5903
5904
5905static struct strlist *
5906msort(list, len)
5907 struct strlist *list;
5908 int len;
5909{
5910 struct strlist *p, *q = NULL;
5911 struct strlist **lpp;
5912 int half;
5913 int n;
5914
5915 if (len <= 1)
5916 return list;
5917 half = len >> 1;
5918 p = list;
5919 for (n = half ; --n >= 0 ; ) {
5920 q = p;
5921 p = p->next;
5922 }
Eric Andersen2870d962001-07-02 17:27:21 +00005923 q->next = NULL; /* terminate first half of list */
5924 q = msort(list, half); /* sort first half of list */
5925 p = msort(p, len - half); /* sort second half */
Eric Andersencb57d552001-06-28 07:25:16 +00005926 lpp = &list;
5927 for (;;) {
5928 if (strcmp(p->text, q->text) < 0) {
5929 *lpp = p;
5930 lpp = &p->next;
5931 if ((p = *lpp) == NULL) {
5932 *lpp = q;
5933 break;
5934 }
5935 } else {
5936 *lpp = q;
5937 lpp = &q->next;
5938 if ((q = *lpp) == NULL) {
5939 *lpp = p;
5940 break;
5941 }
5942 }
5943 }
5944 return list;
5945}
5946#endif
5947
5948
5949
5950/*
5951 * Returns true if the pattern matches the string.
5952 */
5953
5954#if defined(__GLIBC__) && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00005955/* squoted: string might have quote chars */
Eric Andersencb57d552001-06-28 07:25:16 +00005956static int
Eric Andersen2870d962001-07-02 17:27:21 +00005957patmatch(char *pattern, char *string, int squoted)
5958{
Eric Andersencb57d552001-06-28 07:25:16 +00005959 const char *p;
5960 char *q;
5961
5962 p = preglob(pattern);
5963 q = squoted ? _rmescapes(string, RMESCAPE_ALLOC) : string;
5964
5965 return !fnmatch(p, q, 0);
5966}
5967
5968
5969static int
Eric Andersen2870d962001-07-02 17:27:21 +00005970patmatch2(char *pattern, char *string, int squoted)
5971{
Eric Andersencb57d552001-06-28 07:25:16 +00005972 char *p;
5973 int res;
5974
5975 sstrnleft--;
5976 p = grabstackstr(expdest);
5977 res = patmatch(pattern, string, squoted);
5978 ungrabstackstr(p, expdest);
5979 return res;
5980}
5981#else
5982static int
Eric Andersen2870d962001-07-02 17:27:21 +00005983patmatch(char *pattern, char *string, int squoted) {
5984 return pmatch(pattern, string, squoted);
Eric Andersencb57d552001-06-28 07:25:16 +00005985}
5986
5987
5988static int
Eric Andersen2870d962001-07-02 17:27:21 +00005989pmatch(char *pattern, char *string, int squoted)
5990{
Eric Andersencb57d552001-06-28 07:25:16 +00005991 char *p, *q;
5992 char c;
5993
5994 p = pattern;
5995 q = string;
5996 for (;;) {
5997 switch (c = *p++) {
5998 case '\0':
5999 goto breakloop;
6000 case CTLESC:
6001 if (squoted && *q == CTLESC)
6002 q++;
6003 if (*q++ != *p++)
6004 return 0;
6005 break;
6006 case CTLQUOTEMARK:
6007 continue;
6008 case '?':
6009 if (squoted && *q == CTLESC)
6010 q++;
6011 if (*q++ == '\0')
6012 return 0;
6013 break;
6014 case '*':
6015 c = *p;
6016 while (c == CTLQUOTEMARK || c == '*')
6017 c = *++p;
6018 if (c != CTLESC && c != CTLQUOTEMARK &&
6019 c != '?' && c != '*' && c != '[') {
6020 while (*q != c) {
6021 if (squoted && *q == CTLESC &&
6022 q[1] == c)
6023 break;
6024 if (*q == '\0')
6025 return 0;
6026 if (squoted && *q == CTLESC)
6027 q++;
6028 q++;
6029 }
6030 }
6031 do {
6032 if (pmatch(p, q, squoted))
6033 return 1;
6034 if (squoted && *q == CTLESC)
6035 q++;
6036 } while (*q++ != '\0');
6037 return 0;
6038 case '[': {
6039 char *endp;
6040 int invert, found;
6041 char chr;
6042
6043 endp = p;
6044 if (*endp == '!')
6045 endp++;
6046 for (;;) {
6047 while (*endp == CTLQUOTEMARK)
6048 endp++;
6049 if (*endp == '\0')
Eric Andersen2870d962001-07-02 17:27:21 +00006050 goto dft; /* no matching ] */
Eric Andersencb57d552001-06-28 07:25:16 +00006051 if (*endp == CTLESC)
6052 endp++;
6053 if (*++endp == ']')
6054 break;
6055 }
6056 invert = 0;
6057 if (*p == '!') {
6058 invert++;
6059 p++;
6060 }
6061 found = 0;
6062 chr = *q++;
6063 if (squoted && chr == CTLESC)
6064 chr = *q++;
6065 if (chr == '\0')
6066 return 0;
6067 c = *p++;
6068 do {
6069 if (c == CTLQUOTEMARK)
6070 continue;
6071 if (c == CTLESC)
6072 c = *p++;
6073 if (*p == '-' && p[1] != ']') {
6074 p++;
6075 while (*p == CTLQUOTEMARK)
6076 p++;
6077 if (*p == CTLESC)
6078 p++;
6079 if (chr >= c && chr <= *p)
6080 found = 1;
6081 p++;
6082 } else {
6083 if (chr == c)
6084 found = 1;
6085 }
6086 } while ((c = *p++) != ']');
6087 if (found == invert)
6088 return 0;
6089 break;
6090 }
Eric Andersen2870d962001-07-02 17:27:21 +00006091dft: default:
Eric Andersencb57d552001-06-28 07:25:16 +00006092 if (squoted && *q == CTLESC)
6093 q++;
6094 if (*q++ != c)
6095 return 0;
6096 break;
6097 }
6098 }
6099breakloop:
6100 if (*q != '\0')
6101 return 0;
6102 return 1;
6103}
6104#endif
6105
6106
6107
6108/*
6109 * Remove any CTLESC characters from a string.
6110 */
6111
6112#if defined(__GLIBC__) && !defined(FNMATCH_BROKEN)
6113static char *
Eric Andersen2870d962001-07-02 17:27:21 +00006114_rmescapes(char *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00006115{
6116 char *p, *q, *r;
6117 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
6118
6119 p = strpbrk(str, qchars);
6120 if (!p) {
6121 return str;
6122 }
6123 q = p;
6124 r = str;
6125 if (flag & RMESCAPE_ALLOC) {
6126 size_t len = p - str;
6127 q = r = stalloc(strlen(p) + len + 1);
6128 if (len > 0) {
6129#ifdef _GNU_SOURCE
6130 q = mempcpy(q, str, len);
6131#else
6132 memcpy(q, str, len);
6133 q += len;
6134#endif
6135 }
6136 }
6137 while (*p) {
6138 if (*p == CTLQUOTEMARK) {
6139 p++;
6140 continue;
6141 }
6142 if (*p == CTLESC) {
6143 p++;
6144 if (flag & RMESCAPE_GLOB && *p != '/') {
6145 *q++ = '\\';
6146 }
6147 }
6148 *q++ = *p++;
6149 }
6150 *q = '\0';
6151 return r;
6152}
6153#else
6154static void
6155rmescapes(str)
6156 char *str;
6157{
6158 char *p, *q;
6159
6160 p = str;
6161 while (*p != CTLESC && *p != CTLQUOTEMARK) {
6162 if (*p++ == '\0')
6163 return;
6164 }
6165 q = p;
6166 while (*p) {
6167 if (*p == CTLQUOTEMARK) {
6168 p++;
6169 continue;
6170 }
6171 if (*p == CTLESC)
6172 p++;
6173 *q++ = *p++;
6174 }
6175 *q = '\0';
6176}
6177#endif
6178
6179
6180
6181/*
6182 * See if a pattern matches in a case statement.
6183 */
6184
6185static int
Eric Andersen2870d962001-07-02 17:27:21 +00006186casematch(union node *pattern, const char *val)
6187{
Eric Andersencb57d552001-06-28 07:25:16 +00006188 struct stackmark smark;
6189 int result;
6190 char *p;
6191
6192 setstackmark(&smark);
6193 argbackq = pattern->narg.backquote;
6194 STARTSTACKSTR(expdest);
6195 ifslastp = NULL;
6196 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
6197 STPUTC('\0', expdest);
6198 p = grabstackstr(expdest);
Eric Andersen2870d962001-07-02 17:27:21 +00006199 result = patmatch(p, (char *)val, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006200 popstackmark(&smark);
6201 return result;
6202}
6203
6204/*
6205 * Our own itoa().
6206 */
6207
6208static char *
6209cvtnum(num, buf)
6210 int num;
6211 char *buf;
6212 {
6213 int len;
6214
6215 CHECKSTRSPACE(32, buf);
6216 len = sprintf(buf, "%d", num);
6217 STADJUST(len, buf);
6218 return buf;
6219}
Eric Andersencb57d552001-06-28 07:25:16 +00006220/*
6221 * Editline and history functions (and glue).
6222 */
6223static int histcmd(argc, argv)
6224 int argc;
6225 char **argv;
6226{
6227 error("not compiled with history support");
6228 /* NOTREACHED */
6229}
6230
6231
Eric Andersen2870d962001-07-02 17:27:21 +00006232static int whichprompt; /* 1 == PS1, 2 == PS2 */
Eric Andersencb57d552001-06-28 07:25:16 +00006233
Eric Andersencb57d552001-06-28 07:25:16 +00006234
6235struct redirtab {
6236 struct redirtab *next;
6237 short renamed[10];
6238};
6239
Eric Andersen2870d962001-07-02 17:27:21 +00006240static struct redirtab *redirlist;
Eric Andersencb57d552001-06-28 07:25:16 +00006241
6242extern char **environ;
6243
6244
6245
6246/*
6247 * Initialization code.
6248 */
6249
6250static void
Eric Andersen2870d962001-07-02 17:27:21 +00006251init(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00006252
6253 /* from cd.c: */
6254 {
6255 setpwd(0, 0);
6256 }
6257
6258 /* from input.c: */
6259 {
6260 basepf.nextc = basepf.buf = basebuf;
6261 }
6262
6263 /* from output.c: */
6264 {
6265#ifdef USE_GLIBC_STDIO
6266 initstreams();
6267#endif
6268 }
6269
6270 /* from var.c: */
6271 {
6272 char **envp;
6273 char ppid[32];
6274
6275 initvar();
6276 for (envp = environ ; *envp ; envp++) {
6277 if (strchr(*envp, '=')) {
6278 setvareq(*envp, VEXPORT|VTEXTFIXED);
6279 }
6280 }
6281
6282 fmtstr(ppid, sizeof(ppid), "%d", (int) getppid());
6283 setvar("PPID", ppid, 0);
6284 }
6285}
6286
6287
6288
6289/*
6290 * This routine is called when an error or an interrupt occurs in an
6291 * interactive shell and control is returned to the main command loop.
6292 */
6293
Eric Andersen2870d962001-07-02 17:27:21 +00006294#ifdef ASH_ALIAS
6295/* 1 == check for aliases, 2 == also check for assignments */
6296static int checkalias;
6297#endif
6298
Eric Andersencb57d552001-06-28 07:25:16 +00006299static void
Eric Andersen2870d962001-07-02 17:27:21 +00006300reset(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00006301
6302 /* from eval.c: */
6303 {
6304 evalskip = 0;
6305 loopnest = 0;
6306 funcnest = 0;
6307 }
6308
6309 /* from input.c: */
6310 {
6311 if (exception != EXSHELLPROC)
Eric Andersen2870d962001-07-02 17:27:21 +00006312 parselleft = parsenleft = 0; /* clear input buffer */
Eric Andersencb57d552001-06-28 07:25:16 +00006313 popallfiles();
6314 }
6315
6316 /* from parser.c: */
6317 {
6318 tokpushback = 0;
6319 checkkwd = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00006320#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00006321 checkalias = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00006322#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006323 }
6324
6325 /* from redir.c: */
6326 {
6327 while (redirlist)
6328 popredir();
6329 }
6330
6331 /* from output.c: */
6332 {
6333 out1 = &output;
6334 out2 = &errout;
6335#ifdef USE_GLIBC_STDIO
6336 if (memout.stream != NULL)
6337 __closememout();
6338#endif
6339 if (memout.buf != NULL) {
6340 ckfree(memout.buf);
6341 memout.buf = NULL;
6342 }
6343 }
6344}
6345
6346
6347
6348/*
Eric Andersencb57d552001-06-28 07:25:16 +00006349 * This file implements the input routines used by the parser.
6350 */
6351
6352#ifdef BB_FEATURE_COMMAND_EDITING
6353unsigned int shell_context;
6354static const char * cmdedit_prompt;
6355static inline void putprompt(const char *s) {
6356 cmdedit_prompt = s;
6357}
6358#else
6359static inline void putprompt(const char *s) {
6360 out2str(s);
6361}
6362#endif
6363
Eric Andersen2870d962001-07-02 17:27:21 +00006364#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
Eric Andersencb57d552001-06-28 07:25:16 +00006365
Eric Andersencb57d552001-06-28 07:25:16 +00006366
Eric Andersencb57d552001-06-28 07:25:16 +00006367
Eric Andersen2870d962001-07-02 17:27:21 +00006368/*
6369 * Same as pgetc(), but ignores PEOA.
6370 */
Eric Andersencb57d552001-06-28 07:25:16 +00006371
Eric Andersen2870d962001-07-02 17:27:21 +00006372#ifdef ASH_ALIAS
6373static int
6374pgetc2()
6375{
6376 int c;
6377 do {
6378 c = pgetc_macro();
6379 } while (c == PEOA);
6380 return c;
Eric Andersencb57d552001-06-28 07:25:16 +00006381}
Eric Andersen2870d962001-07-02 17:27:21 +00006382#else
6383static inline int pgetc2() { return pgetc_macro(); }
Eric Andersencb57d552001-06-28 07:25:16 +00006384#endif
6385
Eric Andersencb57d552001-06-28 07:25:16 +00006386/*
6387 * Read a line from the script.
6388 */
6389
6390static char *
Eric Andersen2870d962001-07-02 17:27:21 +00006391pfgets(char *line, int len)
Eric Andersencb57d552001-06-28 07:25:16 +00006392{
6393 char *p = line;
6394 int nleft = len;
6395 int c;
6396
6397 while (--nleft > 0) {
6398 c = pgetc2();
6399 if (c == PEOF) {
6400 if (p == line)
6401 return NULL;
6402 break;
6403 }
6404 *p++ = c;
6405 if (c == '\n')
6406 break;
6407 }
6408 *p = '\0';
6409 return line;
6410}
6411
Eric Andersencb57d552001-06-28 07:25:16 +00006412static int
Eric Andersen2870d962001-07-02 17:27:21 +00006413preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006414{
6415 int nr;
6416 char *buf = parsefile->buf;
6417 parsenextc = buf;
6418
6419retry:
6420#ifdef BB_FEATURE_COMMAND_EDITING
6421 {
6422 if (parsefile->fd)
6423 nr = read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersen2870d962001-07-02 17:27:21 +00006424 else {
Eric Andersencb57d552001-06-28 07:25:16 +00006425 do {
6426 cmdedit_read_input((char*)cmdedit_prompt, buf);
6427 nr = strlen(buf);
6428 } while (nr <=0 || shell_context);
6429 cmdedit_terminate();
6430 }
6431 }
6432#else
6433 nr = read(parsefile->fd, buf, BUFSIZ - 1);
6434#endif
6435
6436 if (nr < 0) {
6437 if (errno == EINTR)
6438 goto retry;
6439 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6440 int flags = fcntl(0, F_GETFL, 0);
6441 if (flags >= 0 && flags & O_NONBLOCK) {
6442 flags &=~ O_NONBLOCK;
6443 if (fcntl(0, F_SETFL, flags) >= 0) {
6444 out2str("sh: turning off NDELAY mode\n");
6445 goto retry;
6446 }
6447 }
6448 }
6449 }
6450 return nr;
6451}
6452
Eric Andersen2870d962001-07-02 17:27:21 +00006453static void
6454popstring(void)
6455{
6456 struct strpush *sp = parsefile->strpush;
6457
6458 INTOFF;
6459#ifdef ASH_ALIAS
6460 if (sp->ap) {
6461 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6462 if (!checkalias) {
6463 checkalias = 1;
6464 }
6465 }
6466 if (sp->string != sp->ap->val) {
6467 ckfree(sp->string);
6468 }
6469
6470 sp->ap->flag &= ~ALIASINUSE;
6471 if (sp->ap->flag & ALIASDEAD) {
6472 unalias(sp->ap->name);
6473 }
6474 }
6475#endif
6476 parsenextc = sp->prevstring;
6477 parsenleft = sp->prevnleft;
6478/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6479 parsefile->strpush = sp->prev;
6480 if (sp != &(parsefile->basestrpush))
6481 ckfree(sp);
6482 INTON;
6483}
6484
6485
Eric Andersencb57d552001-06-28 07:25:16 +00006486/*
6487 * Refill the input buffer and return the next input character:
6488 *
6489 * 1) If a string was pushed back on the input, pop it;
6490 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6491 * from a string so we can't refill the buffer, return EOF.
6492 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6493 * 4) Process input up to the next newline, deleting nul characters.
6494 */
6495
6496static int
Eric Andersen2870d962001-07-02 17:27:21 +00006497preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006498{
6499 char *p, *q;
6500 int more;
6501 char savec;
6502
6503 while (parsefile->strpush) {
Eric Andersen2870d962001-07-02 17:27:21 +00006504#ifdef ASH_ALIAS
6505 if (parsenleft == -1 && parsefile->strpush->ap &&
6506 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +00006507 return PEOA;
6508 }
Eric Andersen2870d962001-07-02 17:27:21 +00006509#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006510 popstring();
6511 if (--parsenleft >= 0)
6512 return (*parsenextc++);
6513 }
6514 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6515 return PEOF;
6516 flushout(&output);
6517#ifdef FLUSHERR
6518 flushout(&errout);
6519#endif
6520
6521again:
6522 if (parselleft <= 0) {
6523 if ((parselleft = preadfd()) <= 0) {
6524 parselleft = parsenleft = EOF_NLEFT;
6525 return PEOF;
6526 }
6527 }
6528
6529 q = p = parsenextc;
6530
6531 /* delete nul characters */
6532 for (more = 1; more;) {
6533 switch (*p) {
6534 case '\0':
Eric Andersen2870d962001-07-02 17:27:21 +00006535 p++; /* Skip nul */
Eric Andersencb57d552001-06-28 07:25:16 +00006536 goto check;
6537
6538
6539 case '\n':
6540 parsenleft = q - parsenextc;
6541 more = 0; /* Stop processing here */
6542 break;
6543 }
6544
6545 *q++ = *p++;
6546check:
6547 if (--parselleft <= 0 && more) {
6548 parsenleft = q - parsenextc - 1;
6549 if (parsenleft < 0)
6550 goto again;
6551 more = 0;
6552 }
6553 }
6554
6555 savec = *q;
6556 *q = '\0';
6557
6558 if (vflag) {
6559 out2str(parsenextc);
6560#ifdef FLUSHERR
6561 flushout(out2);
6562#endif
6563 }
6564
6565 *q = savec;
6566
6567 return *parsenextc++;
6568}
6569
Eric Andersencb57d552001-06-28 07:25:16 +00006570
6571/*
6572 * Push a string back onto the input at this current parsefile level.
6573 * We handle aliases this way.
6574 */
6575static void
Eric Andersen2870d962001-07-02 17:27:21 +00006576pushstring(char *s, int len, void *ap)
6577{
Eric Andersencb57d552001-06-28 07:25:16 +00006578 struct strpush *sp;
6579
6580 INTOFF;
6581/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6582 if (parsefile->strpush) {
6583 sp = ckmalloc(sizeof (struct strpush));
6584 sp->prev = parsefile->strpush;
6585 parsefile->strpush = sp;
6586 } else
6587 sp = parsefile->strpush = &(parsefile->basestrpush);
6588 sp->prevstring = parsenextc;
6589 sp->prevnleft = parsenleft;
Eric Andersen2870d962001-07-02 17:27:21 +00006590#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00006591 sp->ap = (struct alias *)ap;
6592 if (ap) {
6593 ((struct alias *)ap)->flag |= ALIASINUSE;
6594 sp->string = s;
6595 }
Eric Andersen2870d962001-07-02 17:27:21 +00006596#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006597 parsenextc = s;
6598 parsenleft = len;
6599 INTON;
6600}
6601
Eric Andersencb57d552001-06-28 07:25:16 +00006602
Eric Andersencb57d552001-06-28 07:25:16 +00006603
6604
6605/*
6606 * Like setinputfile, but takes input from a string.
6607 */
6608
6609static void
6610setinputstring(string)
6611 char *string;
6612 {
6613 INTOFF;
6614 pushfile();
6615 parsenextc = string;
6616 parsenleft = strlen(string);
6617 parsefile->buf = NULL;
6618 plinno = 1;
6619 INTON;
6620}
6621
6622
6623
6624/*
6625 * To handle the "." command, a stack of input files is used. Pushfile
6626 * adds a new entry to the stack and popfile restores the previous level.
6627 */
6628
6629static void
Eric Andersen2870d962001-07-02 17:27:21 +00006630pushfile(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00006631 struct parsefile *pf;
6632
6633 parsefile->nleft = parsenleft;
6634 parsefile->lleft = parselleft;
6635 parsefile->nextc = parsenextc;
6636 parsefile->linno = plinno;
6637 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
6638 pf->prev = parsefile;
6639 pf->fd = -1;
6640 pf->strpush = NULL;
6641 pf->basestrpush.prev = NULL;
6642 parsefile = pf;
6643}
6644
Eric Andersen2870d962001-07-02 17:27:21 +00006645#ifdef JOBS
6646static void restartjob (struct job *);
Eric Andersencb57d552001-06-28 07:25:16 +00006647#endif
Eric Andersen2870d962001-07-02 17:27:21 +00006648static void freejob (struct job *);
6649static struct job *getjob (const char *);
6650static int dowait (int, struct job *);
6651static int waitproc (int, int *);
Eric Andersencb57d552001-06-28 07:25:16 +00006652static void waitonint(int);
6653
6654
Eric Andersen2870d962001-07-02 17:27:21 +00006655/*
6656 * We keep track of whether or not fd0 has been redirected. This is for
6657 * background commands, where we want to redirect fd0 to /dev/null only
6658 * if it hasn't already been redirected.
6659*/
6660static int fd0_redirected = 0;
6661
6662/* Return true if fd 0 has already been redirected at least once. */
6663static inline int
6664fd0_redirected_p () {
6665 return fd0_redirected != 0;
6666}
6667
6668/*
6669 * We also keep track of where fileno2 goes.
6670 */
6671static int fileno2 = 2;
6672
6673static int openredirect (union node *);
6674static void dupredirect (union node *, int, char[10 ]);
6675static int openhere (union node *);
6676static int noclobberopen (const char *);
6677
6678
6679
6680#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006681/*
6682 * Turn job control on and off.
6683 *
6684 * Note: This code assumes that the third arg to ioctl is a character
6685 * pointer, which is true on Berkeley systems but not System V. Since
6686 * System V doesn't have job control yet, this isn't a problem now.
6687 */
6688
Eric Andersen2870d962001-07-02 17:27:21 +00006689
Eric Andersencb57d552001-06-28 07:25:16 +00006690
6691static void setjobctl(int enable)
6692{
6693#ifdef OLD_TTY_DRIVER
6694 int ldisc;
6695#endif
6696
6697 if (enable == jobctl || rootshell == 0)
6698 return;
6699 if (enable) {
6700 do { /* while we are in the background */
6701#ifdef OLD_TTY_DRIVER
6702 if (ioctl(fileno2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
6703#else
6704 initialpgrp = tcgetpgrp(fileno2);
6705 if (initialpgrp < 0) {
6706#endif
6707 out2str("sh: can't access tty; job cenabletrol turned off\n");
6708 mflag = 0;
6709 return;
6710 }
6711 if (initialpgrp == -1)
6712 initialpgrp = getpgrp();
6713 else if (initialpgrp != getpgrp()) {
6714 killpg(initialpgrp, SIGTTIN);
6715 continue;
6716 }
6717 } while (0);
6718#ifdef OLD_TTY_DRIVER
6719 if (ioctl(fileno2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
6720 out2str("sh: need new tty driver to run job cenabletrol; job cenabletrol turned off\n");
6721 mflag = 0;
6722 return;
6723 }
6724#endif
6725 setsignal(SIGTSTP);
6726 setsignal(SIGTTOU);
6727 setsignal(SIGTTIN);
6728 setpgid(0, rootpid);
6729#ifdef OLD_TTY_DRIVER
6730 ioctl(fileno2, TIOCSPGRP, (char *)&rootpid);
6731#else
6732 tcsetpgrp(fileno2, rootpid);
6733#endif
6734 } else { /* turning job cenabletrol off */
6735 setpgid(0, initialpgrp);
6736#ifdef OLD_TTY_DRIVER
6737 ioctl(fileno2, TIOCSPGRP, (char *)&initialpgrp);
6738#else
6739 tcsetpgrp(fileno2, initialpgrp);
6740#endif
6741 setsignal(SIGTSTP);
6742 setsignal(SIGTTOU);
6743 setsignal(SIGTTIN);
6744 }
6745 jobctl = enable;
6746}
6747#endif
6748
6749
Eric Andersencb57d552001-06-28 07:25:16 +00006750/* A translation list so we can be polite to our users. */
6751static char *signal_names[NSIG + 2] = {
6752 "EXIT",
6753 "SIGHUP",
6754 "SIGINT",
6755 "SIGQUIT",
6756 "SIGILL",
6757 "SIGTRAP",
6758 "SIGABRT",
6759 "SIGBUS",
6760 "SIGFPE",
6761 "SIGKILL",
6762 "SIGUSR1",
6763 "SIGSEGV",
6764 "SIGUSR2",
6765 "SIGPIPE",
6766 "SIGALRM",
6767 "SIGTERM",
6768 "SIGJUNK(16)",
6769 "SIGCHLD",
6770 "SIGCONT",
6771 "SIGSTOP",
6772 "SIGTSTP",
6773 "SIGTTIN",
6774 "SIGTTOU",
6775 "SIGURG",
6776 "SIGXCPU",
6777 "SIGXFSZ",
6778 "SIGVTALRM",
6779 "SIGPROF",
6780 "SIGWINCH",
6781 "SIGIO",
6782 "SIGPWR",
6783 "SIGSYS",
6784 "SIGRTMIN",
6785 "SIGRTMIN+1",
6786 "SIGRTMIN+2",
6787 "SIGRTMIN+3",
6788 "SIGRTMIN+4",
6789 "SIGRTMIN+5",
6790 "SIGRTMIN+6",
6791 "SIGRTMIN+7",
6792 "SIGRTMIN+8",
6793 "SIGRTMIN+9",
6794 "SIGRTMIN+10",
6795 "SIGRTMIN+11",
6796 "SIGRTMIN+12",
6797 "SIGRTMIN+13",
6798 "SIGRTMIN+14",
6799 "SIGRTMIN+15",
6800 "SIGRTMAX-15",
6801 "SIGRTMAX-14",
6802 "SIGRTMAX-13",
6803 "SIGRTMAX-12",
6804 "SIGRTMAX-11",
6805 "SIGRTMAX-10",
6806 "SIGRTMAX-9",
6807 "SIGRTMAX-8",
6808 "SIGRTMAX-7",
6809 "SIGRTMAX-6",
6810 "SIGRTMAX-5",
6811 "SIGRTMAX-4",
6812 "SIGRTMAX-3",
6813 "SIGRTMAX-2",
6814 "SIGRTMAX-1",
6815 "SIGRTMAX",
6816 "DEBUG",
6817 (char *)0x0,
6818};
6819
6820
6821
Eric Andersen2870d962001-07-02 17:27:21 +00006822#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006823static int
6824killcmd(argc, argv)
6825 int argc;
6826 char **argv;
6827{
6828 int signo = -1;
6829 int list = 0;
6830 int i;
6831 pid_t pid;
6832 struct job *jp;
6833
6834 if (argc <= 1) {
6835usage:
6836 error(
6837"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6838"kill -l [exitstatus]"
6839 );
6840 }
6841
6842 if (*argv[1] == '-') {
6843 signo = decode_signal(argv[1] + 1, 1);
6844 if (signo < 0) {
6845 int c;
6846
6847 while ((c = nextopt("ls:")) != '\0')
6848 switch (c) {
6849 case 'l':
6850 list = 1;
6851 break;
6852 case 's':
6853 signo = decode_signal(optionarg, 1);
6854 if (signo < 0) {
6855 error(
6856 "invalid signal number or name: %s",
6857 optionarg
6858 );
6859 }
Eric Andersen2870d962001-07-02 17:27:21 +00006860 break;
Eric Andersencb57d552001-06-28 07:25:16 +00006861#ifdef DEBUG
6862 default:
6863 error(
6864 "nextopt returned character code 0%o", c);
6865#endif
6866 }
6867 } else
6868 argptr++;
6869 }
6870
6871 if (!list && signo < 0)
6872 signo = SIGTERM;
6873
6874 if ((signo < 0 || !*argptr) ^ list) {
6875 goto usage;
6876 }
6877
6878 if (list) {
6879 if (!*argptr) {
6880 out1str("0\n");
6881 for (i = 1; i < NSIG; i++) {
6882 out1fmt(snlfmt, signal_names[i] + 3);
6883 }
6884 return 0;
6885 }
6886 signo = atoi(*argptr);
6887 if (signo > 128)
6888 signo -= 128;
6889 if (0 < signo && signo < NSIG)
6890 out1fmt(snlfmt, signal_names[signo] + 3);
6891 else
6892 error("invalid signal number or exit status: %s",
6893 *argptr);
6894 return 0;
6895 }
6896
6897 do {
6898 if (**argptr == '%') {
6899 jp = getjob(*argptr);
6900 if (jp->jobctl == 0)
6901 error("job %s not created under job control",
6902 *argptr);
6903 pid = -jp->ps[0].pid;
6904 } else
6905 pid = atoi(*argptr);
6906 if (kill(pid, signo) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00006907 error("%s: %m", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006908 } while (*++argptr);
6909
6910 return 0;
6911}
6912
6913static int
6914fgcmd(argc, argv)
6915 int argc;
6916 char **argv;
6917{
6918 struct job *jp;
6919 int pgrp;
6920 int status;
6921
6922 jp = getjob(argv[1]);
6923 if (jp->jobctl == 0)
6924 error("job not created under job control");
6925 pgrp = jp->ps[0].pid;
6926#ifdef OLD_TTY_DRIVER
6927 ioctl(fileno2, TIOCSPGRP, (char *)&pgrp);
6928#else
6929 tcsetpgrp(fileno2, pgrp);
6930#endif
6931 restartjob(jp);
6932 INTOFF;
6933 status = waitforjob(jp);
6934 INTON;
6935 return status;
6936}
6937
6938
6939static int
6940bgcmd(argc, argv)
6941 int argc;
6942 char **argv;
6943{
6944 struct job *jp;
6945
6946 do {
6947 jp = getjob(*++argv);
6948 if (jp->jobctl == 0)
6949 error("job not created under job control");
6950 restartjob(jp);
6951 } while (--argc > 1);
6952 return 0;
6953}
6954
6955
6956static void
6957restartjob(jp)
6958 struct job *jp;
6959{
6960 struct procstat *ps;
6961 int i;
6962
6963 if (jp->state == JOBDONE)
6964 return;
6965 INTOFF;
6966 killpg(jp->ps[0].pid, SIGCONT);
6967 for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
6968 if (WIFSTOPPED(ps->status)) {
6969 ps->status = -1;
6970 jp->state = 0;
6971 }
6972 }
6973 INTON;
6974}
6975#endif
6976
Eric Andersen2870d962001-07-02 17:27:21 +00006977static void showjobs(int change);
6978
Eric Andersencb57d552001-06-28 07:25:16 +00006979
6980static int
6981jobscmd(argc, argv)
6982 int argc;
6983 char **argv;
6984{
6985 showjobs(0);
6986 return 0;
6987}
6988
6989
6990/*
6991 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6992 * statuses have changed since the last call to showjobs.
6993 *
6994 * If the shell is interrupted in the process of creating a job, the
6995 * result may be a job structure containing zero processes. Such structures
6996 * will be freed here.
6997 */
6998
6999static void
7000showjobs(change)
7001 int change;
7002{
7003 int jobno;
7004 int procno;
7005 int i;
7006 struct job *jp;
7007 struct procstat *ps;
7008 int col;
7009 char s[64];
7010
7011 TRACE(("showjobs(%d) called\n", change));
7012 while (dowait(0, (struct job *)NULL) > 0);
7013 for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
7014 if (! jp->used)
7015 continue;
7016 if (jp->nprocs == 0) {
7017 freejob(jp);
7018 continue;
7019 }
7020 if (change && ! jp->changed)
7021 continue;
7022 procno = jp->nprocs;
Eric Andersen2870d962001-07-02 17:27:21 +00007023 for (ps = jp->ps ; ; ps++) { /* for each process */
Eric Andersencb57d552001-06-28 07:25:16 +00007024 if (ps == jp->ps)
Eric Andersen2870d962001-07-02 17:27:21 +00007025 fmtstr(s, 64, "[%d] %ld ", jobno,
Eric Andersencb57d552001-06-28 07:25:16 +00007026 (long)ps->pid);
7027 else
Eric Andersen2870d962001-07-02 17:27:21 +00007028 fmtstr(s, 64, " %ld ",
Eric Andersencb57d552001-06-28 07:25:16 +00007029 (long)ps->pid);
7030 out1str(s);
7031 col = strlen(s);
7032 s[0] = '\0';
7033 if (ps->status == -1) {
7034 /* don't print anything */
7035 } else if (WIFEXITED(ps->status)) {
Eric Andersen2870d962001-07-02 17:27:21 +00007036 fmtstr(s, 64, "Exit %d",
Eric Andersencb57d552001-06-28 07:25:16 +00007037 WEXITSTATUS(ps->status));
7038 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00007039#ifdef JOBS
7040 if (WIFSTOPPED(ps->status))
Eric Andersencb57d552001-06-28 07:25:16 +00007041 i = WSTOPSIG(ps->status);
7042 else /* WIFSIGNALED(ps->status) */
7043#endif
7044 i = WTERMSIG(ps->status);
7045 if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F])
Eric Andersen2870d962001-07-02 17:27:21 +00007046 strcpy(s, sys_siglist[i & 0x7F]);
Eric Andersencb57d552001-06-28 07:25:16 +00007047 else
7048 fmtstr(s, 64, "Signal %d", i & 0x7F);
7049 if (WCOREDUMP(ps->status))
7050 strcat(s, " (core dumped)");
7051 }
7052 out1str(s);
7053 col += strlen(s);
7054 out1fmt(
7055 "%*c%s\n", 30 - col >= 0 ? 30 - col : 0, ' ',
7056 ps->cmd
7057 );
7058 if (--procno <= 0)
7059 break;
7060 }
7061 jp->changed = 0;
7062 if (jp->state == JOBDONE) {
7063 freejob(jp);
7064 }
7065 }
7066}
7067
7068
7069/*
7070 * Mark a job structure as unused.
7071 */
7072
7073static void
7074freejob(jp)
7075 struct job *jp;
7076 {
7077 struct procstat *ps;
7078 int i;
7079
7080 INTOFF;
7081 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
7082 if (ps->cmd != nullstr)
7083 ckfree(ps->cmd);
7084 }
7085 if (jp->ps != &jp->ps0)
7086 ckfree(jp->ps);
7087 jp->used = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00007088#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007089 if (curjob == jp - jobtab + 1)
7090 curjob = 0;
7091#endif
7092 INTON;
7093}
7094
7095
7096
7097static int
7098waitcmd(argc, argv)
7099 int argc;
7100 char **argv;
7101{
7102 struct job *job;
7103 int status, retval;
7104 struct job *jp;
7105
7106 if (--argc > 0) {
7107start:
7108 job = getjob(*++argv);
7109 } else {
7110 job = NULL;
7111 }
Eric Andersen2870d962001-07-02 17:27:21 +00007112 for (;;) { /* loop until process terminated or stopped */
Eric Andersencb57d552001-06-28 07:25:16 +00007113 if (job != NULL) {
7114 if (job->state) {
7115 status = job->ps[job->nprocs - 1].status;
7116 if (! iflag)
7117 freejob(job);
7118 if (--argc) {
7119 goto start;
7120 }
7121 if (WIFEXITED(status))
7122 retval = WEXITSTATUS(status);
Eric Andersen2870d962001-07-02 17:27:21 +00007123#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007124 else if (WIFSTOPPED(status))
7125 retval = WSTOPSIG(status) + 128;
7126#endif
7127 else {
7128 /* XXX: limits number of signals */
7129 retval = WTERMSIG(status) + 128;
7130 }
7131 return retval;
7132 }
7133 } else {
7134 for (jp = jobtab ; ; jp++) {
Eric Andersen2870d962001-07-02 17:27:21 +00007135 if (jp >= jobtab + njobs) { /* no running procs */
Eric Andersencb57d552001-06-28 07:25:16 +00007136 return 0;
7137 }
7138 if (jp->used && jp->state == 0)
7139 break;
7140 }
7141 }
7142 if (dowait(2, 0) < 0 && errno == EINTR) {
7143 return 129;
7144 }
7145 }
7146}
7147
7148
7149
7150/*
7151 * Convert a job name to a job structure.
7152 */
7153
7154static struct job *
Eric Andersen2870d962001-07-02 17:27:21 +00007155getjob(const char *name)
7156{
Eric Andersencb57d552001-06-28 07:25:16 +00007157 int jobno;
7158 struct job *jp;
7159 int pid;
7160 int i;
7161
7162 if (name == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00007163#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007164currentjob:
7165 if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0)
7166 error("No current job");
7167 return &jobtab[jobno - 1];
7168#else
7169 error("No current job");
7170#endif
7171 } else if (name[0] == '%') {
7172 if (is_digit(name[1])) {
7173 jobno = number(name + 1);
7174 if (jobno > 0 && jobno <= njobs
7175 && jobtab[jobno - 1].used != 0)
7176 return &jobtab[jobno - 1];
Eric Andersen2870d962001-07-02 17:27:21 +00007177#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007178 } else if (name[1] == '%' && name[2] == '\0') {
7179 goto currentjob;
7180#endif
7181 } else {
7182 struct job *found = NULL;
7183 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
7184 if (jp->used && jp->nprocs > 0
7185 && prefix(name + 1, jp->ps[0].cmd)) {
7186 if (found)
7187 error("%s: ambiguous", name);
7188 found = jp;
7189 }
7190 }
7191 if (found)
7192 return found;
7193 }
Eric Andersen2870d962001-07-02 17:27:21 +00007194 } else if (is_number(name, &pid)) {
Eric Andersencb57d552001-06-28 07:25:16 +00007195 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
7196 if (jp->used && jp->nprocs > 0
7197 && jp->ps[jp->nprocs - 1].pid == pid)
7198 return jp;
7199 }
7200 }
7201 error("No such job: %s", name);
7202 /* NOTREACHED */
7203}
7204
7205
7206
7207/*
7208 * Return a new job structure,
7209 */
7210
Eric Andersen2870d962001-07-02 17:27:21 +00007211static struct job *
Eric Andersencb57d552001-06-28 07:25:16 +00007212makejob(node, nprocs)
7213 union node *node;
7214 int nprocs;
7215{
7216 int i;
7217 struct job *jp;
7218
7219 for (i = njobs, jp = jobtab ; ; jp++) {
7220 if (--i < 0) {
7221 INTOFF;
7222 if (njobs == 0) {
7223 jobtab = ckmalloc(4 * sizeof jobtab[0]);
7224 } else {
7225 jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
7226 memcpy(jp, jobtab, njobs * sizeof jp[0]);
7227 /* Relocate `ps' pointers */
7228 for (i = 0; i < njobs; i++)
7229 if (jp[i].ps == &jobtab[i].ps0)
7230 jp[i].ps = &jp[i].ps0;
7231 ckfree(jobtab);
7232 jobtab = jp;
7233 }
7234 jp = jobtab + njobs;
7235 for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0);
7236 INTON;
7237 break;
7238 }
7239 if (jp->used == 0)
7240 break;
7241 }
7242 INTOFF;
7243 jp->state = 0;
7244 jp->used = 1;
7245 jp->changed = 0;
7246 jp->nprocs = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00007247#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007248 jp->jobctl = jobctl;
7249#endif
7250 if (nprocs > 1) {
7251 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
7252 } else {
7253 jp->ps = &jp->ps0;
7254 }
7255 INTON;
7256 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
7257 jp - jobtab + 1));
7258 return jp;
7259}
7260
7261
7262/*
7263 * Fork of a subshell. If we are doing job control, give the subshell its
7264 * own process group. Jp is a job structure that the job is to be added to.
7265 * N is the command that will be evaluated by the child. Both jp and n may
7266 * be NULL. The mode parameter can be one of the following:
Eric Andersen2870d962001-07-02 17:27:21 +00007267 * FORK_FG - Fork off a foreground process.
7268 * FORK_BG - Fork off a background process.
7269 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
7270 * process group even if job control is on.
Eric Andersencb57d552001-06-28 07:25:16 +00007271 *
7272 * When job control is turned off, background processes have their standard
7273 * input redirected to /dev/null (except for the second and later processes
7274 * in a pipeline).
7275 */
7276
Eric Andersen2870d962001-07-02 17:27:21 +00007277
7278
Eric Andersencb57d552001-06-28 07:25:16 +00007279static int
Eric Andersen2870d962001-07-02 17:27:21 +00007280forkshell(struct job *jp, union node *n, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00007281{
7282 int pid;
7283 int pgrp;
7284 const char *devnull = _PATH_DEVNULL;
7285 const char *nullerr = "Can't open %s";
7286
7287 TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long)n,
7288 mode));
7289 INTOFF;
7290 pid = fork();
7291 if (pid == -1) {
7292 TRACE(("Fork failed, errno=%d\n", errno));
7293 INTON;
7294 error("Cannot fork");
7295 }
7296 if (pid == 0) {
7297 struct job *p;
7298 int wasroot;
7299 int i;
7300
7301 TRACE(("Child shell %d\n", getpid()));
7302 wasroot = rootshell;
7303 rootshell = 0;
7304 closescript();
7305 INTON;
7306 clear_traps();
Eric Andersen2870d962001-07-02 17:27:21 +00007307#ifdef JOBS
7308 jobctl = 0; /* do job control only in root shell */
Eric Andersencb57d552001-06-28 07:25:16 +00007309 if (wasroot && mode != FORK_NOJOB && mflag) {
7310 if (jp == NULL || jp->nprocs == 0)
7311 pgrp = getpid();
7312 else
7313 pgrp = jp->ps[0].pid;
7314 setpgid(0, pgrp);
7315 if (mode == FORK_FG) {
7316 /*** this causes superfluous TIOCSPGRPS ***/
7317#ifdef OLD_TTY_DRIVER
7318 if (ioctl(fileno2, TIOCSPGRP, (char *)&pgrp) < 0)
7319 error("TIOCSPGRP failed, errno=%d", errno);
7320#else
7321 if (tcsetpgrp(fileno2, pgrp) < 0)
7322 error("tcsetpgrp failed, errno=%d", errno);
7323#endif
7324 }
7325 setsignal(SIGTSTP);
7326 setsignal(SIGTTOU);
7327 } else if (mode == FORK_BG) {
7328 ignoresig(SIGINT);
7329 ignoresig(SIGQUIT);
7330 if ((jp == NULL || jp->nprocs == 0) &&
7331 ! fd0_redirected_p ()) {
7332 close(0);
7333 if (open(devnull, O_RDONLY) != 0)
7334 error(nullerr, devnull);
7335 }
7336 }
7337#else
7338 if (mode == FORK_BG) {
7339 ignoresig(SIGINT);
7340 ignoresig(SIGQUIT);
7341 if ((jp == NULL || jp->nprocs == 0) &&
7342 ! fd0_redirected_p ()) {
7343 close(0);
7344 if (open(devnull, O_RDONLY) != 0)
7345 error(nullerr, devnull);
7346 }
7347 }
7348#endif
7349 for (i = njobs, p = jobtab ; --i >= 0 ; p++)
7350 if (p->used)
7351 freejob(p);
7352 if (wasroot && iflag) {
7353 setsignal(SIGINT);
7354 setsignal(SIGQUIT);
7355 setsignal(SIGTERM);
7356 }
7357 return pid;
7358 }
7359 if (rootshell && mode != FORK_NOJOB && mflag) {
7360 if (jp == NULL || jp->nprocs == 0)
7361 pgrp = pid;
7362 else
7363 pgrp = jp->ps[0].pid;
7364 setpgid(pid, pgrp);
7365 }
7366 if (mode == FORK_BG)
Eric Andersen2870d962001-07-02 17:27:21 +00007367 backgndpid = pid; /* set $! */
Eric Andersencb57d552001-06-28 07:25:16 +00007368 if (jp) {
7369 struct procstat *ps = &jp->ps[jp->nprocs++];
7370 ps->pid = pid;
7371 ps->status = -1;
7372 ps->cmd = nullstr;
7373 if (iflag && rootshell && n)
7374 ps->cmd = commandtext(n);
7375 }
7376 INTON;
7377 TRACE(("In parent shell: child = %d\n", pid));
7378 return pid;
7379}
7380
7381
7382
7383/*
7384 * Wait for job to finish.
7385 *
7386 * Under job control we have the problem that while a child process is
7387 * running interrupts generated by the user are sent to the child but not
7388 * to the shell. This means that an infinite loop started by an inter-
7389 * active user may be hard to kill. With job control turned off, an
7390 * interactive user may place an interactive program inside a loop. If
7391 * the interactive program catches interrupts, the user doesn't want
7392 * these interrupts to also abort the loop. The approach we take here
7393 * is to have the shell ignore interrupt signals while waiting for a
7394 * forground process to terminate, and then send itself an interrupt
7395 * signal if the child process was terminated by an interrupt signal.
7396 * Unfortunately, some programs want to do a bit of cleanup and then
7397 * exit on interrupt; unless these processes terminate themselves by
7398 * sending a signal to themselves (instead of calling exit) they will
7399 * confuse this approach.
7400 */
7401
7402static int
7403waitforjob(jp)
7404 struct job *jp;
7405 {
Eric Andersen2870d962001-07-02 17:27:21 +00007406#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007407 int mypgrp = getpgrp();
7408#endif
7409 int status;
7410 int st;
7411 struct sigaction act, oact;
7412
7413 INTOFF;
7414 intreceived = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00007415#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007416 if (!jobctl) {
7417#else
7418 if (!iflag) {
7419#endif
7420 sigaction(SIGINT, 0, &act);
7421 act.sa_handler = waitonint;
7422 sigaction(SIGINT, &act, &oact);
7423 }
7424 TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
7425 while (jp->state == 0) {
7426 dowait(1, jp);
7427 }
Eric Andersen2870d962001-07-02 17:27:21 +00007428#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007429 if (!jobctl) {
7430#else
7431 if (!iflag) {
7432#endif
7433 sigaction(SIGINT, &oact, 0);
7434 if (intreceived && trap[SIGINT]) kill(getpid(), SIGINT);
7435 }
Eric Andersen2870d962001-07-02 17:27:21 +00007436#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007437 if (jp->jobctl) {
7438#ifdef OLD_TTY_DRIVER
7439 if (ioctl(fileno2, TIOCSPGRP, (char *)&mypgrp) < 0)
7440 error("TIOCSPGRP failed, errno=%d\n", errno);
7441#else
7442 if (tcsetpgrp(fileno2, mypgrp) < 0)
7443 error("tcsetpgrp failed, errno=%d\n", errno);
7444#endif
7445 }
7446 if (jp->state == JOBSTOPPED)
7447 curjob = jp - jobtab + 1;
7448#endif
7449 status = jp->ps[jp->nprocs - 1].status;
7450 /* convert to 8 bits */
7451 if (WIFEXITED(status))
7452 st = WEXITSTATUS(status);
Eric Andersen2870d962001-07-02 17:27:21 +00007453#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007454 else if (WIFSTOPPED(status))
7455 st = WSTOPSIG(status) + 128;
7456#endif
7457 else
7458 st = WTERMSIG(status) + 128;
Eric Andersen2870d962001-07-02 17:27:21 +00007459#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007460 if (jp->jobctl) {
7461 /*
7462 * This is truly gross.
7463 * If we're doing job control, then we did a TIOCSPGRP which
7464 * caused us (the shell) to no longer be in the controlling
7465 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7466 * intuit from the subprocess exit status whether a SIGINT
7467 * occured, and if so interrupt ourselves. Yuck. - mycroft
7468 */
7469 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
7470 raise(SIGINT);
7471 }
Eric Andersen2870d962001-07-02 17:27:21 +00007472 if (jp->state == JOBDONE)
7473
Eric Andersencb57d552001-06-28 07:25:16 +00007474#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007475 freejob(jp);
7476 INTON;
7477 return st;
7478}
7479
7480
7481
7482/*
7483 * Wait for a process to terminate.
7484 */
7485
7486static int
7487dowait(block, job)
7488 int block;
7489 struct job *job;
7490{
7491 int pid;
7492 int status;
7493 struct procstat *sp;
7494 struct job *jp;
7495 struct job *thisjob;
7496 int done;
7497 int stopped;
7498 int core;
7499 int sig;
7500
7501 TRACE(("dowait(%d) called\n", block));
7502 do {
7503 pid = waitproc(block, &status);
7504 TRACE(("wait returns %d, status=%d\n", pid, status));
7505 } while (!(block & 2) && pid == -1 && errno == EINTR);
7506 if (pid <= 0)
7507 return pid;
7508 INTOFF;
7509 thisjob = NULL;
7510 for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
7511 if (jp->used) {
7512 done = 1;
7513 stopped = 1;
7514 for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
7515 if (sp->pid == -1)
7516 continue;
7517 if (sp->pid == pid) {
7518 TRACE(("Changing status of proc %d from 0x%x to 0x%x\n", pid, sp->status, status));
7519 sp->status = status;
7520 thisjob = jp;
7521 }
7522 if (sp->status == -1)
7523 stopped = 0;
7524 else if (WIFSTOPPED(sp->status))
7525 done = 0;
7526 }
Eric Andersen2870d962001-07-02 17:27:21 +00007527 if (stopped) { /* stopped or done */
Eric Andersencb57d552001-06-28 07:25:16 +00007528 int state = done? JOBDONE : JOBSTOPPED;
7529 if (jp->state != state) {
7530 TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
7531 jp->state = state;
Eric Andersen2870d962001-07-02 17:27:21 +00007532#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007533 if (done && curjob == jp - jobtab + 1)
Eric Andersen2870d962001-07-02 17:27:21 +00007534 curjob = 0; /* no current job */
Eric Andersencb57d552001-06-28 07:25:16 +00007535#endif
7536 }
7537 }
7538 }
7539 }
7540 INTON;
7541 if (! rootshell || ! iflag || (job && thisjob == job)) {
7542 core = WCOREDUMP(status);
Eric Andersen2870d962001-07-02 17:27:21 +00007543#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007544 if (WIFSTOPPED(status)) sig = WSTOPSIG(status);
7545 else
7546#endif
7547 if (WIFEXITED(status)) sig = 0;
7548 else sig = WTERMSIG(status);
7549
7550 if (sig != 0 && sig != SIGINT && sig != SIGPIPE) {
7551 if (thisjob != job)
7552 outfmt(out2, "%d: ", pid);
Eric Andersen2870d962001-07-02 17:27:21 +00007553#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007554 if (sig == SIGTSTP && rootshell && iflag)
7555 outfmt(out2, "%%%ld ",
7556 (long)(job - jobtab + 1));
7557#endif
7558 if (sig < NSIG && sys_siglist[sig])
7559 out2str(sys_siglist[sig]);
7560 else
7561 outfmt(out2, "Signal %d", sig);
7562 if (core)
7563 out2str(" - core dumped");
7564 out2c('\n');
7565#ifdef FLUSHERR
7566 flushout(&errout);
7567#endif
7568 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00007569 TRACE(("Not printing status: status=%d, sig=%d\n",
Eric Andersencb57d552001-06-28 07:25:16 +00007570 status, sig));
7571 }
7572 } else {
7573 TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job));
7574 if (thisjob)
7575 thisjob->changed = 1;
7576 }
7577 return pid;
7578}
7579
7580
7581
7582/*
7583 * Do a wait system call. If job control is compiled in, we accept
7584 * stopped processes. If block is zero, we return a value of zero
7585 * rather than blocking.
7586 *
7587 * System V doesn't have a non-blocking wait system call. It does
7588 * have a SIGCLD signal that is sent to a process when one of it's
7589 * children dies. The obvious way to use SIGCLD would be to install
7590 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7591 * was received, and have waitproc bump another counter when it got
7592 * the status of a process. Waitproc would then know that a wait
7593 * system call would not block if the two counters were different.
7594 * This approach doesn't work because if a process has children that
7595 * have not been waited for, System V will send it a SIGCLD when it
7596 * installs a signal handler for SIGCLD. What this means is that when
7597 * a child exits, the shell will be sent SIGCLD signals continuously
7598 * until is runs out of stack space, unless it does a wait call before
7599 * restoring the signal handler. The code below takes advantage of
7600 * this (mis)feature by installing a signal handler for SIGCLD and
7601 * then checking to see whether it was called. If there are any
7602 * children to be waited for, it will be.
7603 *
Eric Andersencb57d552001-06-28 07:25:16 +00007604 */
7605
Eric Andersencb57d552001-06-28 07:25:16 +00007606static int
7607waitproc(block, status)
7608 int block;
7609 int *status;
7610{
Eric Andersencb57d552001-06-28 07:25:16 +00007611 int flags;
7612
7613 flags = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00007614#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007615 if (jobctl)
7616 flags |= WUNTRACED;
7617#endif
7618 if (block == 0)
7619 flags |= WNOHANG;
7620 return wait3(status, flags, (struct rusage *)NULL);
Eric Andersencb57d552001-06-28 07:25:16 +00007621}
7622
7623/*
7624 * return 1 if there are stopped jobs, otherwise 0
7625 */
Eric Andersencb57d552001-06-28 07:25:16 +00007626static int
Eric Andersen2870d962001-07-02 17:27:21 +00007627stoppedjobs(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007628{
7629 int jobno;
7630 struct job *jp;
7631
7632 if (job_warning)
7633 return (0);
7634 for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
7635 if (jp->used == 0)
7636 continue;
7637 if (jp->state == JOBSTOPPED) {
7638 out2str("You have stopped jobs.\n");
7639 job_warning = 2;
7640 return (1);
7641 }
7642 }
7643
7644 return (0);
7645}
7646
7647/*
7648 * Return a string identifying a command (to be printed by the
7649 * jobs command.
7650 */
7651
7652static char *cmdnextc;
7653static int cmdnleft;
Eric Andersen2870d962001-07-02 17:27:21 +00007654#define MAXCMDTEXT 200
Eric Andersencb57d552001-06-28 07:25:16 +00007655
Eric Andersen2870d962001-07-02 17:27:21 +00007656static void
7657cmdputs(const char *s)
7658{
7659 const char *p;
7660 char *q;
7661 char c;
7662 int subtype = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007663
Eric Andersen2870d962001-07-02 17:27:21 +00007664 if (cmdnleft <= 0)
7665 return;
7666 p = s;
7667 q = cmdnextc;
7668 while ((c = *p++) != '\0') {
7669 if (c == CTLESC)
7670 *q++ = *p++;
7671 else if (c == CTLVAR) {
7672 *q++ = '$';
7673 if (--cmdnleft > 0)
7674 *q++ = '{';
7675 subtype = *p++;
7676 } else if (c == '=' && subtype != 0) {
7677 *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
7678 subtype = 0;
7679 } else if (c == CTLENDVAR) {
7680 *q++ = '}';
7681 } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE)
7682 cmdnleft++; /* ignore it */
7683 else
7684 *q++ = c;
7685 if (--cmdnleft <= 0) {
7686 *q++ = '.';
7687 *q++ = '.';
7688 *q++ = '.';
7689 break;
7690 }
7691 }
7692 cmdnextc = q;
Eric Andersencb57d552001-06-28 07:25:16 +00007693}
7694
7695
7696static void
Eric Andersen2870d962001-07-02 17:27:21 +00007697cmdtxt(const union node *n)
7698{
Eric Andersencb57d552001-06-28 07:25:16 +00007699 union node *np;
7700 struct nodelist *lp;
7701 const char *p;
7702 int i;
7703 char s[2];
7704
7705 if (n == NULL)
7706 return;
7707 switch (n->type) {
7708 case NSEMI:
7709 cmdtxt(n->nbinary.ch1);
7710 cmdputs("; ");
7711 cmdtxt(n->nbinary.ch2);
7712 break;
7713 case NAND:
7714 cmdtxt(n->nbinary.ch1);
7715 cmdputs(" && ");
7716 cmdtxt(n->nbinary.ch2);
7717 break;
7718 case NOR:
7719 cmdtxt(n->nbinary.ch1);
7720 cmdputs(" || ");
7721 cmdtxt(n->nbinary.ch2);
7722 break;
7723 case NPIPE:
7724 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
7725 cmdtxt(lp->n);
7726 if (lp->next)
7727 cmdputs(" | ");
7728 }
7729 break;
7730 case NSUBSHELL:
7731 cmdputs("(");
7732 cmdtxt(n->nredir.n);
7733 cmdputs(")");
7734 break;
7735 case NREDIR:
7736 case NBACKGND:
7737 cmdtxt(n->nredir.n);
7738 break;
7739 case NIF:
7740 cmdputs("if ");
7741 cmdtxt(n->nif.test);
7742 cmdputs("; then ");
7743 cmdtxt(n->nif.ifpart);
7744 cmdputs("...");
7745 break;
7746 case NWHILE:
7747 cmdputs("while ");
7748 goto until;
7749 case NUNTIL:
7750 cmdputs("until ");
7751until:
7752 cmdtxt(n->nbinary.ch1);
7753 cmdputs("; do ");
7754 cmdtxt(n->nbinary.ch2);
7755 cmdputs("; done");
7756 break;
7757 case NFOR:
7758 cmdputs("for ");
7759 cmdputs(n->nfor.var);
7760 cmdputs(" in ...");
7761 break;
7762 case NCASE:
7763 cmdputs("case ");
7764 cmdputs(n->ncase.expr->narg.text);
7765 cmdputs(" in ...");
7766 break;
7767 case NDEFUN:
7768 cmdputs(n->narg.text);
7769 cmdputs("() ...");
7770 break;
7771 case NCMD:
7772 for (np = n->ncmd.args ; np ; np = np->narg.next) {
7773 cmdtxt(np);
7774 if (np->narg.next)
7775 cmdputs(spcstr);
7776 }
7777 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
7778 cmdputs(spcstr);
7779 cmdtxt(np);
7780 }
7781 break;
7782 case NARG:
7783 cmdputs(n->narg.text);
7784 break;
7785 case NTO:
7786 p = ">"; i = 1; goto redir;
7787 case NAPPEND:
7788 p = ">>"; i = 1; goto redir;
7789 case NTOFD:
7790 p = ">&"; i = 1; goto redir;
7791 case NTOOV:
7792 p = ">|"; i = 1; goto redir;
7793 case NFROM:
7794 p = "<"; i = 0; goto redir;
7795 case NFROMFD:
7796 p = "<&"; i = 0; goto redir;
7797 case NFROMTO:
7798 p = "<>"; i = 0; goto redir;
7799redir:
7800 if (n->nfile.fd != i) {
7801 s[0] = n->nfile.fd + '0';
7802 s[1] = '\0';
7803 cmdputs(s);
7804 }
7805 cmdputs(p);
7806 if (n->type == NTOFD || n->type == NFROMFD) {
7807 s[0] = n->ndup.dupfd + '0';
7808 s[1] = '\0';
7809 cmdputs(s);
7810 } else {
7811 cmdtxt(n->nfile.fname);
7812 }
7813 break;
7814 case NHERE:
7815 case NXHERE:
7816 cmdputs("<<...");
7817 break;
7818 default:
7819 cmdputs("???");
7820 break;
7821 }
7822}
7823
7824
Eric Andersen2870d962001-07-02 17:27:21 +00007825static char *
7826commandtext(const union node *n)
7827{
7828 char *name;
Eric Andersencb57d552001-06-28 07:25:16 +00007829
Eric Andersen2870d962001-07-02 17:27:21 +00007830 cmdnextc = name = ckmalloc(MAXCMDTEXT);
7831 cmdnleft = MAXCMDTEXT - 4;
7832 cmdtxt(n);
7833 *cmdnextc = '\0';
7834 return name;
Eric Andersencb57d552001-06-28 07:25:16 +00007835}
7836
Eric Andersen2870d962001-07-02 17:27:21 +00007837
Eric Andersencb57d552001-06-28 07:25:16 +00007838static void waitonint(int sig) {
7839 intreceived = 1;
7840 return;
7841}
Eric Andersencb57d552001-06-28 07:25:16 +00007842/*
7843 * Routines to check for mail. (Perhaps make part of main.c?)
7844 */
7845
7846
7847#define MAXMBOXES 10
7848
7849
Eric Andersen2870d962001-07-02 17:27:21 +00007850static int nmboxes; /* number of mailboxes */
7851static time_t mailtime[MAXMBOXES]; /* times of mailboxes */
Eric Andersencb57d552001-06-28 07:25:16 +00007852
7853
7854
7855/*
7856 * Print appropriate message(s) if mail has arrived. If the argument is
7857 * nozero, then the value of MAIL has changed, so we just update the
7858 * values.
7859 */
7860
7861static void
Eric Andersen2870d962001-07-02 17:27:21 +00007862chkmail(int silent)
Eric Andersencb57d552001-06-28 07:25:16 +00007863{
7864 int i;
7865 const char *mpath;
7866 char *p;
7867 char *q;
7868 struct stackmark smark;
7869 struct stat statb;
7870
7871 if (silent)
7872 nmboxes = 10;
7873 if (nmboxes == 0)
7874 return;
7875 setstackmark(&smark);
7876 mpath = mpathset()? mpathval() : mailval();
7877 for (i = 0 ; i < nmboxes ; i++) {
7878 p = padvance(&mpath, nullstr);
7879 if (p == NULL)
7880 break;
7881 if (*p == '\0')
7882 continue;
7883 for (q = p ; *q ; q++);
7884#ifdef DEBUG
7885 if (q[-1] != '/')
7886 abort();
7887#endif
Eric Andersen2870d962001-07-02 17:27:21 +00007888 q[-1] = '\0'; /* delete trailing '/' */
Eric Andersencb57d552001-06-28 07:25:16 +00007889 if (stat(p, &statb) < 0)
7890 statb.st_size = 0;
7891 if (statb.st_size > mailtime[i] && ! silent) {
7892 outfmt(
7893 &errout, snlfmt,
7894 pathopt? pathopt : "you have mail"
7895 );
7896 }
7897 mailtime[i] = statb.st_size;
Eric Andersencb57d552001-06-28 07:25:16 +00007898 }
7899 nmboxes = i;
7900 popstackmark(&smark);
7901}
Eric Andersencb57d552001-06-28 07:25:16 +00007902
7903#define PROFILE 0
7904
Eric Andersencb57d552001-06-28 07:25:16 +00007905#if PROFILE
Eric Andersen2870d962001-07-02 17:27:21 +00007906static short profile_buf[16384];
Eric Andersencb57d552001-06-28 07:25:16 +00007907extern int etext();
7908#endif
7909
Eric Andersen2870d962001-07-02 17:27:21 +00007910static void read_profile (const char *);
7911static char *find_dot_file (char *);
7912static void cmdloop (int);
7913static void options (int);
7914static void minus_o (char *, int);
7915static void setoption (int, int);
7916static void procargs (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00007917
Eric Andersen2870d962001-07-02 17:27:21 +00007918
Eric Andersencb57d552001-06-28 07:25:16 +00007919/*
7920 * Main routine. We initialize things, parse the arguments, execute
7921 * profiles if we're a login shell, and then call cmdloop to execute
7922 * commands. The setjmp call sets up the location to jump to when an
7923 * exception occurs. When an exception occurs the variable "state"
7924 * is used to figure out how far we had gotten.
7925 */
7926
7927int
7928shell_main(argc, argv)
7929 int argc;
7930 char **argv;
7931{
7932 struct jmploc jmploc;
7933 struct stackmark smark;
7934 volatile int state;
7935 char *shinit;
7936
7937 DOTCMD = find_builtin(".");
7938 BLTINCMD = find_builtin("builtin");
Eric Andersencb57d552001-06-28 07:25:16 +00007939 EXECCMD = find_builtin("exec");
7940 EVALCMD = find_builtin("eval");
7941
7942#if PROFILE
7943 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7944#endif
7945#if defined(linux) || defined(__GNU__)
7946 signal(SIGCHLD, SIG_DFL);
7947#endif
7948 state = 0;
7949 if (setjmp(jmploc.loc)) {
7950 INTOFF;
7951 /*
7952 * When a shell procedure is executed, we raise the
7953 * exception EXSHELLPROC to clean up before executing
7954 * the shell procedure.
7955 */
7956 switch (exception) {
7957 case EXSHELLPROC:
7958 rootpid = getpid();
7959 rootshell = 1;
7960 minusc = NULL;
7961 state = 3;
7962 break;
7963
7964 case EXEXEC:
7965 exitstatus = exerrno;
7966 break;
7967
7968 case EXERROR:
7969 exitstatus = 2;
7970 break;
7971
7972 default:
7973 break;
7974 }
7975
7976 if (exception != EXSHELLPROC) {
7977 if (state == 0 || iflag == 0 || ! rootshell)
7978 exitshell(exitstatus);
7979 }
7980 reset();
Eric Andersen2870d962001-07-02 17:27:21 +00007981 if (exception == EXINT) {
Eric Andersencb57d552001-06-28 07:25:16 +00007982 out2c('\n');
7983#ifdef FLUSHERR
7984 flushout(out2);
7985#endif
7986 }
7987 popstackmark(&smark);
Eric Andersen2870d962001-07-02 17:27:21 +00007988 FORCEINTON; /* enable interrupts */
Eric Andersencb57d552001-06-28 07:25:16 +00007989 if (state == 1)
7990 goto state1;
7991 else if (state == 2)
7992 goto state2;
7993 else if (state == 3)
7994 goto state3;
7995 else
7996 goto state4;
7997 }
7998 handler = &jmploc;
7999#ifdef DEBUG
8000 opentrace();
8001 trputs("Shell args: "); trargs(argv);
8002#endif
8003 rootpid = getpid();
8004 rootshell = 1;
8005 init();
8006 setstackmark(&smark);
8007 procargs(argc, argv);
8008 if (argv[0] && argv[0][0] == '-') {
8009 state = 1;
8010 read_profile("/etc/profile");
8011state1:
8012 state = 2;
8013 read_profile(".profile");
8014 }
8015state2:
8016 state = 3;
8017#ifndef linux
8018 if (getuid() == geteuid() && getgid() == getegid()) {
8019#endif
8020 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
8021 state = 3;
8022 read_profile(shinit);
8023 }
8024#ifndef linux
8025 }
8026#endif
8027state3:
8028 state = 4;
8029 if (sflag == 0 || minusc) {
8030 static int sigs[] = {
Eric Andersen2870d962001-07-02 17:27:21 +00008031 SIGINT, SIGQUIT, SIGHUP,
Eric Andersencb57d552001-06-28 07:25:16 +00008032#ifdef SIGTSTP
8033 SIGTSTP,
8034#endif
8035 SIGPIPE
8036 };
8037#define SIGSSIZE (sizeof(sigs)/sizeof(sigs[0]))
8038 int i;
8039
8040 for (i = 0; i < SIGSSIZE; i++)
8041 setsignal(sigs[i]);
8042 }
8043
8044 if (minusc)
8045 evalstring(minusc, 0);
8046
8047 if (sflag || minusc == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00008048state4: /* XXX ??? - why isn't this before the "if" statement */
Eric Andersencb57d552001-06-28 07:25:16 +00008049 cmdloop(1);
8050 }
8051#if PROFILE
8052 monitor(0);
8053#endif
8054 exitshell(exitstatus);
8055 /* NOTREACHED */
8056}
8057
8058
8059/*
8060 * Read and execute commands. "Top" is nonzero for the top level command
8061 * loop; it turns on prompting if the shell is interactive.
8062 */
8063
8064static void
Eric Andersen2870d962001-07-02 17:27:21 +00008065cmdloop(int top)
Eric Andersencb57d552001-06-28 07:25:16 +00008066{
8067 union node *n;
8068 struct stackmark smark;
8069 int inter;
8070 int numeof = 0;
8071
8072 TRACE(("cmdloop(%d) called\n", top));
8073 setstackmark(&smark);
8074 for (;;) {
8075 if (pendingsigs)
8076 dotrap();
8077 inter = 0;
8078 if (iflag && top) {
8079 inter++;
8080 showjobs(1);
8081 chkmail(0);
8082 flushout(&output);
8083 }
8084 n = parsecmd(inter);
8085 /* showtree(n); DEBUG */
8086 if (n == NEOF) {
8087 if (!top || numeof >= 50)
8088 break;
8089 if (!stoppedjobs()) {
8090 if (!Iflag)
8091 break;
8092 out2str("\nUse \"exit\" to leave shell.\n");
8093 }
8094 numeof++;
8095 } else if (n != NULL && nflag == 0) {
8096 job_warning = (job_warning == 2) ? 1 : 0;
8097 numeof = 0;
8098 evaltree(n, 0);
8099 }
8100 popstackmark(&smark);
8101 setstackmark(&smark);
8102 if (evalskip == SKIPFILE) {
8103 evalskip = 0;
8104 break;
8105 }
8106 }
8107 popstackmark(&smark);
8108}
8109
8110
8111
8112/*
8113 * Read /etc/profile or .profile. Return on error.
8114 */
8115
8116static void
8117read_profile(name)
8118 const char *name;
8119{
8120 int fd;
8121 int xflag_set = 0;
8122 int vflag_set = 0;
8123
8124 INTOFF;
8125 if ((fd = open(name, O_RDONLY)) >= 0)
8126 setinputfd(fd, 1);
8127 INTON;
8128 if (fd < 0)
8129 return;
8130 /* -q turns off -x and -v just when executing init files */
8131 if (qflag) {
8132 if (xflag)
8133 xflag = 0, xflag_set = 1;
8134 if (vflag)
8135 vflag = 0, vflag_set = 1;
8136 }
8137 cmdloop(0);
8138 if (qflag) {
8139 if (xflag_set)
8140 xflag = 1;
8141 if (vflag_set)
8142 vflag = 1;
8143 }
8144 popfile();
8145}
8146
8147
8148
8149/*
8150 * Read a file containing shell functions.
8151 */
8152
8153static void
Eric Andersen2870d962001-07-02 17:27:21 +00008154readcmdfile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008155{
8156 int fd;
8157
8158 INTOFF;
8159 if ((fd = open(name, O_RDONLY)) >= 0)
8160 setinputfd(fd, 1);
8161 else
8162 error("Can't open %s", name);
8163 INTON;
8164 cmdloop(0);
8165 popfile();
8166}
8167
8168
8169
8170/*
8171 * Take commands from a file. To be compatable we should do a path
8172 * search for the file, which is necessary to find sub-commands.
8173 */
8174
8175
8176static char *
8177find_dot_file(mybasename)
8178 char *mybasename;
8179{
8180 char *fullname;
8181 const char *path = pathval();
8182 struct stat statb;
8183
8184 /* don't try this for absolute or relative paths */
8185 if (strchr(mybasename, '/'))
8186 return mybasename;
8187
8188 while ((fullname = padvance(&path, mybasename)) != NULL) {
8189 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
8190 /*
8191 * Don't bother freeing here, since it will
8192 * be freed by the caller.
8193 */
8194 return fullname;
8195 }
8196 stunalloc(fullname);
8197 }
8198
8199 /* not found in the PATH */
8200 error("%s: not found", mybasename);
8201 /* NOTREACHED */
8202}
8203
8204static int
8205dotcmd(argc, argv)
8206 int argc;
8207 char **argv;
8208{
8209 struct strlist *sp;
8210 exitstatus = 0;
8211
8212 for (sp = cmdenviron; sp ; sp = sp->next)
8213 setvareq(savestr(sp->text), VSTRFIXED|VTEXTFIXED);
8214
Eric Andersen2870d962001-07-02 17:27:21 +00008215 if (argc >= 2) { /* That's what SVR2 does */
Eric Andersencb57d552001-06-28 07:25:16 +00008216 char *fullname;
8217 struct stackmark smark;
8218
8219 setstackmark(&smark);
8220 fullname = find_dot_file(argv[1]);
8221 setinputfile(fullname, 1);
8222 commandname = fullname;
8223 cmdloop(0);
8224 popfile();
8225 popstackmark(&smark);
8226 }
8227 return exitstatus;
8228}
8229
8230
8231static int
8232exitcmd(argc, argv)
8233 int argc;
8234 char **argv;
8235{
8236 if (stoppedjobs())
8237 return 0;
8238 if (argc > 1)
8239 exitstatus = number(argv[1]);
8240 else
8241 exitstatus = oexitstatus;
8242 exitshell(exitstatus);
8243 /* NOTREACHED */
8244}
Eric Andersen2870d962001-07-02 17:27:21 +00008245static pointer
8246stalloc(int nbytes)
Eric Andersencb57d552001-06-28 07:25:16 +00008247{
8248 char *p;
8249
8250 nbytes = ALIGN(nbytes);
8251 if (nbytes > stacknleft) {
8252 int blocksize;
8253 struct stack_block *sp;
8254
8255 blocksize = nbytes;
8256 if (blocksize < MINSIZE)
8257 blocksize = MINSIZE;
8258 INTOFF;
8259 sp = ckmalloc(sizeof(struct stack_block) - MINSIZE + blocksize);
8260 sp->prev = stackp;
8261 stacknxt = sp->space;
8262 stacknleft = blocksize;
8263 stackp = sp;
8264 INTON;
8265 }
8266 p = stacknxt;
8267 stacknxt += nbytes;
8268 stacknleft -= nbytes;
8269 return p;
8270}
8271
8272
8273static void
Eric Andersen2870d962001-07-02 17:27:21 +00008274stunalloc(pointer p)
8275{
Eric Andersencb57d552001-06-28 07:25:16 +00008276#ifdef DEBUG
Eric Andersen2870d962001-07-02 17:27:21 +00008277 if (p == NULL) { /*DEBUG */
Eric Andersencb57d552001-06-28 07:25:16 +00008278 write(2, "stunalloc\n", 10);
8279 abort();
8280 }
8281#endif
8282 if (!(stacknxt >= (char *)p && (char *)p >= stackp->space)) {
8283 p = stackp->space;
8284 }
8285 stacknleft += stacknxt - (char *)p;
8286 stacknxt = p;
8287}
8288
8289
Eric Andersencb57d552001-06-28 07:25:16 +00008290static void
Eric Andersen2870d962001-07-02 17:27:21 +00008291setstackmark(struct stackmark *mark)
8292{
Eric Andersencb57d552001-06-28 07:25:16 +00008293 mark->stackp = stackp;
8294 mark->stacknxt = stacknxt;
8295 mark->stacknleft = stacknleft;
8296 mark->marknext = markp;
8297 markp = mark;
8298}
8299
8300
8301static void
Eric Andersen2870d962001-07-02 17:27:21 +00008302popstackmark(struct stackmark *mark)
8303{
Eric Andersencb57d552001-06-28 07:25:16 +00008304 struct stack_block *sp;
8305
8306 INTOFF;
8307 markp = mark->marknext;
8308 while (stackp != mark->stackp) {
8309 sp = stackp;
8310 stackp = sp->prev;
8311 ckfree(sp);
8312 }
8313 stacknxt = mark->stacknxt;
8314 stacknleft = mark->stacknleft;
8315 INTON;
8316}
8317
8318
8319/*
8320 * When the parser reads in a string, it wants to stick the string on the
8321 * stack and only adjust the stack pointer when it knows how big the
8322 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8323 * of space on top of the stack and stackblocklen returns the length of
8324 * this block. Growstackblock will grow this space by at least one byte,
8325 * possibly moving it (like realloc). Grabstackblock actually allocates the
8326 * part of the block that has been used.
8327 */
8328
8329static void
Eric Andersen2870d962001-07-02 17:27:21 +00008330growstackblock(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00008331 char *p;
8332 int newlen = ALIGN(stacknleft * 2 + 100);
8333 char *oldspace = stacknxt;
8334 int oldlen = stacknleft;
8335 struct stack_block *sp;
8336 struct stack_block *oldstackp;
8337
8338 if (stacknxt == stackp->space && stackp != &stackbase) {
8339 INTOFF;
8340 oldstackp = stackp;
8341 sp = stackp;
8342 stackp = sp->prev;
8343 sp = ckrealloc((pointer)sp, sizeof(struct stack_block) - MINSIZE + newlen);
8344 sp->prev = stackp;
8345 stackp = sp;
8346 stacknxt = sp->space;
8347 stacknleft = newlen;
8348 {
8349 /* Stack marks pointing to the start of the old block
Eric Andersen2870d962001-07-02 17:27:21 +00008350 * must be relocated to point to the new block
Eric Andersencb57d552001-06-28 07:25:16 +00008351 */
8352 struct stackmark *xmark;
8353 xmark = markp;
8354 while (xmark != NULL && xmark->stackp == oldstackp) {
8355 xmark->stackp = stackp;
8356 xmark->stacknxt = stacknxt;
8357 xmark->stacknleft = stacknleft;
8358 xmark = xmark->marknext;
8359 }
8360 }
8361 INTON;
8362 } else {
8363 p = stalloc(newlen);
8364 memcpy(p, oldspace, oldlen);
Eric Andersen2870d962001-07-02 17:27:21 +00008365 stacknxt = p; /* free the space */
8366 stacknleft += newlen; /* we just allocated */
Eric Andersencb57d552001-06-28 07:25:16 +00008367 }
8368}
8369
8370
8371
Eric Andersen2870d962001-07-02 17:27:21 +00008372static inline void
8373grabstackblock(int len)
Eric Andersencb57d552001-06-28 07:25:16 +00008374{
8375 len = ALIGN(len);
8376 stacknxt += len;
8377 stacknleft -= len;
8378}
8379
8380
8381
8382/*
8383 * The following routines are somewhat easier to use that the above.
8384 * The user declares a variable of type STACKSTR, which may be declared
8385 * to be a register. The macro STARTSTACKSTR initializes things. Then
8386 * the user uses the macro STPUTC to add characters to the string. In
8387 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8388 * grown as necessary. When the user is done, she can just leave the
8389 * string there and refer to it using stackblock(). Or she can allocate
8390 * the space for it using grabstackstr(). If it is necessary to allow
8391 * someone else to use the stack temporarily and then continue to grow
8392 * the string, the user should use grabstack to allocate the space, and
8393 * then call ungrabstr(p) to return to the previous mode of operation.
8394 *
8395 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8396 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8397 * is space for at least one character.
8398 */
8399
8400
8401static char *
Eric Andersen2870d962001-07-02 17:27:21 +00008402growstackstr(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00008403 int len = stackblocksize();
8404 if (herefd >= 0 && len >= 1024) {
8405 xwrite(herefd, stackblock(), len);
8406 sstrnleft = len - 1;
8407 return stackblock();
8408 }
8409 growstackblock();
8410 sstrnleft = stackblocksize() - len - 1;
8411 return stackblock() + len;
8412}
8413
8414
8415/*
8416 * Called from CHECKSTRSPACE.
8417 */
8418
8419static char *
8420makestrspace(size_t newlen) {
8421 int len = stackblocksize() - sstrnleft;
8422 do {
8423 growstackblock();
8424 sstrnleft = stackblocksize() - len;
8425 } while (sstrnleft < newlen);
8426 return stackblock() + len;
8427}
8428
8429
8430
8431static void
Eric Andersen2870d962001-07-02 17:27:21 +00008432ungrabstackstr(char *s, char *p)
8433{
Eric Andersencb57d552001-06-28 07:25:16 +00008434 stacknleft += stacknxt - s;
8435 stacknxt = s;
8436 sstrnleft = stacknleft - (p - s);
8437}
Eric Andersencb57d552001-06-28 07:25:16 +00008438/*
8439 * Miscelaneous builtins.
8440 */
8441
8442
8443#undef rflag
8444
8445#ifdef __GLIBC__
Eric Andersen2870d962001-07-02 17:27:21 +00008446static mode_t getmode(const void *, mode_t);
Eric Andersencb57d552001-06-28 07:25:16 +00008447static void *setmode(const char *);
8448
8449#if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
8450typedef enum __rlimit_resource rlim_t;
8451#endif
8452#endif
8453
8454
8455
8456/*
8457 * The read builtin. The -e option causes backslashes to escape the
8458 * following character.
8459 *
8460 * This uses unbuffered input, which may be avoidable in some cases.
8461 */
8462
8463static int
8464readcmd(argc, argv)
8465 int argc;
8466 char **argv;
8467{
8468 char **ap;
8469 int backslash;
8470 char c;
8471 int rflag;
8472 char *prompt;
8473 const char *ifs;
8474 char *p;
8475 int startword;
8476 int status;
8477 int i;
8478
8479 rflag = 0;
8480 prompt = NULL;
8481 while ((i = nextopt("p:r")) != '\0') {
8482 if (i == 'p')
8483 prompt = optionarg;
8484 else
8485 rflag = 1;
8486 }
8487 if (prompt && isatty(0)) {
8488 putprompt(prompt);
8489 flushall();
8490 }
8491 if (*(ap = argptr) == NULL)
8492 error("arg count");
8493 if ((ifs = bltinlookup("IFS")) == NULL)
8494 ifs = defifs;
8495 status = 0;
8496 startword = 1;
8497 backslash = 0;
8498 STARTSTACKSTR(p);
8499 for (;;) {
8500 if (read(0, &c, 1) != 1) {
8501 status = 1;
8502 break;
8503 }
8504 if (c == '\0')
8505 continue;
8506 if (backslash) {
8507 backslash = 0;
8508 if (c != '\n')
8509 STPUTC(c, p);
8510 continue;
8511 }
8512 if (!rflag && c == '\\') {
8513 backslash++;
8514 continue;
8515 }
8516 if (c == '\n')
8517 break;
8518 if (startword && *ifs == ' ' && strchr(ifs, c)) {
8519 continue;
8520 }
8521 startword = 0;
8522 if (backslash && c == '\\') {
8523 if (read(0, &c, 1) != 1) {
8524 status = 1;
8525 break;
8526 }
8527 STPUTC(c, p);
8528 } else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
8529 STACKSTRNUL(p);
8530 setvar(*ap, stackblock(), 0);
8531 ap++;
8532 startword = 1;
8533 STARTSTACKSTR(p);
8534 } else {
8535 STPUTC(c, p);
8536 }
8537 }
8538 STACKSTRNUL(p);
8539 /* Remove trailing blanks */
8540 while (stackblock() <= --p && strchr(ifs, *p) != NULL)
8541 *p = '\0';
8542 setvar(*ap, stackblock(), 0);
8543 while (*++ap != NULL)
8544 setvar(*ap, nullstr, 0);
8545 return status;
8546}
8547
8548
8549
8550static int
8551umaskcmd(argc, argv)
8552 int argc;
8553 char **argv;
8554{
8555 char *ap;
8556 int mask;
8557 int i;
8558 int symbolic_mode = 0;
8559
8560 while ((i = nextopt("S")) != '\0') {
8561 symbolic_mode = 1;
8562 }
8563
8564 INTOFF;
8565 mask = umask(0);
8566 umask(mask);
8567 INTON;
8568
8569 if ((ap = *argptr) == NULL) {
8570 if (symbolic_mode) {
8571 char u[4], g[4], o[4];
8572
8573 i = 0;
8574 if ((mask & S_IRUSR) == 0)
8575 u[i++] = 'r';
8576 if ((mask & S_IWUSR) == 0)
8577 u[i++] = 'w';
8578 if ((mask & S_IXUSR) == 0)
8579 u[i++] = 'x';
8580 u[i] = '\0';
8581
8582 i = 0;
8583 if ((mask & S_IRGRP) == 0)
8584 g[i++] = 'r';
8585 if ((mask & S_IWGRP) == 0)
8586 g[i++] = 'w';
8587 if ((mask & S_IXGRP) == 0)
8588 g[i++] = 'x';
8589 g[i] = '\0';
8590
8591 i = 0;
8592 if ((mask & S_IROTH) == 0)
8593 o[i++] = 'r';
8594 if ((mask & S_IWOTH) == 0)
8595 o[i++] = 'w';
8596 if ((mask & S_IXOTH) == 0)
8597 o[i++] = 'x';
8598 o[i] = '\0';
8599
8600 out1fmt("u=%s,g=%s,o=%s\n", u, g, o);
8601 } else {
8602 out1fmt("%.4o\n", mask);
8603 }
8604 } else {
8605 if (isdigit((unsigned char)*ap)) {
8606 mask = 0;
8607 do {
8608 if (*ap >= '8' || *ap < '0')
8609 error("Illegal number: %s", argv[1]);
8610 mask = (mask << 3) + (*ap - '0');
8611 } while (*++ap != '\0');
8612 umask(mask);
8613 } else {
8614 void *set;
8615
8616 INTOFF;
8617 if ((set = setmode(ap)) != 0) {
8618 mask = getmode(set, ~mask & 0777);
8619 ckfree(set);
8620 }
8621 INTON;
8622 if (!set)
8623 error("Illegal mode: %s", ap);
8624
8625 umask(~mask & 0777);
8626 }
8627 }
8628 return 0;
8629}
8630
8631/*
8632 * ulimit builtin
8633 *
8634 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
8635 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
8636 * ash by J.T. Conklin.
8637 *
8638 * Public domain.
8639 */
8640
8641struct limits {
8642 const char *name;
Eric Andersen2870d962001-07-02 17:27:21 +00008643 int cmd;
8644 int factor; /* multiply by to get rlim_{cur,max} values */
8645 char option;
Eric Andersencb57d552001-06-28 07:25:16 +00008646};
8647
8648static const struct limits limits[] = {
8649#ifdef RLIMIT_CPU
Eric Andersen2870d962001-07-02 17:27:21 +00008650 { "time(seconds)", RLIMIT_CPU, 1, 't' },
Eric Andersencb57d552001-06-28 07:25:16 +00008651#endif
8652#ifdef RLIMIT_FSIZE
Eric Andersen2870d962001-07-02 17:27:21 +00008653 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
Eric Andersencb57d552001-06-28 07:25:16 +00008654#endif
8655#ifdef RLIMIT_DATA
Eric Andersen2870d962001-07-02 17:27:21 +00008656 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
Eric Andersencb57d552001-06-28 07:25:16 +00008657#endif
8658#ifdef RLIMIT_STACK
Eric Andersen2870d962001-07-02 17:27:21 +00008659 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
Eric Andersencb57d552001-06-28 07:25:16 +00008660#endif
8661#ifdef RLIMIT_CORE
Eric Andersen2870d962001-07-02 17:27:21 +00008662 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
Eric Andersencb57d552001-06-28 07:25:16 +00008663#endif
8664#ifdef RLIMIT_RSS
Eric Andersen2870d962001-07-02 17:27:21 +00008665 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
Eric Andersencb57d552001-06-28 07:25:16 +00008666#endif
8667#ifdef RLIMIT_MEMLOCK
Eric Andersen2870d962001-07-02 17:27:21 +00008668 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
Eric Andersencb57d552001-06-28 07:25:16 +00008669#endif
8670#ifdef RLIMIT_NPROC
Eric Andersen2870d962001-07-02 17:27:21 +00008671 { "process(processes)", RLIMIT_NPROC, 1, 'p' },
Eric Andersencb57d552001-06-28 07:25:16 +00008672#endif
8673#ifdef RLIMIT_NOFILE
Eric Andersen2870d962001-07-02 17:27:21 +00008674 { "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' },
Eric Andersencb57d552001-06-28 07:25:16 +00008675#endif
8676#ifdef RLIMIT_VMEM
Eric Andersen2870d962001-07-02 17:27:21 +00008677 { "vmemory(kbytes)", RLIMIT_VMEM, 1024, 'v' },
Eric Andersencb57d552001-06-28 07:25:16 +00008678#endif
8679#ifdef RLIMIT_SWAP
Eric Andersen2870d962001-07-02 17:27:21 +00008680 { "swap(kbytes)", RLIMIT_SWAP, 1024, 'w' },
Eric Andersencb57d552001-06-28 07:25:16 +00008681#endif
Eric Andersen2870d962001-07-02 17:27:21 +00008682 { (char *) 0, 0, 0, '\0' }
Eric Andersencb57d552001-06-28 07:25:16 +00008683};
8684
8685static int
8686ulimitcmd(argc, argv)
8687 int argc;
8688 char **argv;
8689{
Eric Andersen2870d962001-07-02 17:27:21 +00008690 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00008691 rlim_t val = 0;
8692 enum { SOFT = 0x1, HARD = 0x2 }
8693 how = SOFT | HARD;
Eric Andersen2870d962001-07-02 17:27:21 +00008694 const struct limits *l;
8695 int set, all = 0;
8696 int optc, what;
8697 struct rlimit limit;
Eric Andersencb57d552001-06-28 07:25:16 +00008698
8699 what = 'f';
8700 while ((optc = nextopt("HSatfdsmcnpl")) != '\0')
8701 switch (optc) {
8702 case 'H':
8703 how = HARD;
8704 break;
8705 case 'S':
8706 how = SOFT;
8707 break;
8708 case 'a':
8709 all = 1;
8710 break;
8711 default:
8712 what = optc;
8713 }
8714
8715 for (l = limits; l->name && l->option != what; l++)
8716 ;
8717 if (!l->name)
8718 error("internal error (%c)", what);
8719
8720 set = *argptr ? 1 : 0;
8721 if (set) {
8722 char *p = *argptr;
8723
8724 if (all || argptr[1])
8725 error("too many arguments");
8726 if (strcmp(p, "unlimited") == 0)
8727 val = RLIM_INFINITY;
8728 else {
8729 val = (rlim_t) 0;
8730
8731 while ((c = *p++) >= '0' && c <= '9')
8732 {
8733 val = (val * 10) + (long)(c - '0');
8734 if (val < (rlim_t) 0)
8735 break;
8736 }
8737 if (c)
8738 error("bad number");
8739 val *= l->factor;
8740 }
8741 }
8742 if (all) {
8743 for (l = limits; l->name; l++) {
8744 getrlimit(l->cmd, &limit);
8745 if (how & SOFT)
8746 val = limit.rlim_cur;
8747 else if (how & HARD)
8748 val = limit.rlim_max;
8749
8750 out1fmt("%-20s ", l->name);
8751 if (val == RLIM_INFINITY)
8752 out1fmt("unlimited\n");
8753 else
8754 {
8755 val /= l->factor;
Eric Andersencb57d552001-06-28 07:25:16 +00008756 out1fmt("%lld\n", (long long) val);
Eric Andersencb57d552001-06-28 07:25:16 +00008757 }
8758 }
8759 return 0;
8760 }
8761
8762 getrlimit(l->cmd, &limit);
8763 if (set) {
8764 if (how & HARD)
8765 limit.rlim_max = val;
8766 if (how & SOFT)
8767 limit.rlim_cur = val;
8768 if (setrlimit(l->cmd, &limit) < 0)
Eric Andersen2870d962001-07-02 17:27:21 +00008769 error("error setting limit (%m)");
Eric Andersencb57d552001-06-28 07:25:16 +00008770 } else {
8771 if (how & SOFT)
8772 val = limit.rlim_cur;
8773 else if (how & HARD)
8774 val = limit.rlim_max;
8775
8776 if (val == RLIM_INFINITY)
8777 out1fmt("unlimited\n");
8778 else
8779 {
8780 val /= l->factor;
Eric Andersencb57d552001-06-28 07:25:16 +00008781 out1fmt("%lld\n", (long long) val);
Eric Andersencb57d552001-06-28 07:25:16 +00008782 }
8783 }
8784 return 0;
8785}
Eric Andersencb57d552001-06-28 07:25:16 +00008786/*
8787 * prefix -- see if pfx is a prefix of string.
8788 */
8789
8790static int
8791prefix(pfx, string)
8792 char const *pfx;
8793 char const *string;
8794 {
8795 while (*pfx) {
8796 if (*pfx++ != *string++)
8797 return 0;
8798 }
8799 return 1;
8800}
8801
Eric Andersen2870d962001-07-02 17:27:21 +00008802/*
8803 * Return true if s is a string of digits, and save munber in intptr
8804 * nagative is bad
8805 */
8806
8807static int
8808is_number(const char *p, int *intptr)
8809{
8810 int ret = 0;
8811
8812 do {
8813 if (! is_digit(*p))
8814 return 0;
8815 ret *= 10;
8816 ret += digit_val(*p);
8817 p++;
8818 } while (*p != '\0');
8819
8820 *intptr = ret;
8821 return 1;
8822}
Eric Andersencb57d552001-06-28 07:25:16 +00008823
8824/*
8825 * Convert a string of digits to an integer, printing an error message on
8826 * failure.
8827 */
8828
8829static int
Eric Andersen2870d962001-07-02 17:27:21 +00008830number(const char *s)
8831{
8832 int i;
8833 if (! is_number(s, &i))
Eric Andersencb57d552001-06-28 07:25:16 +00008834 error("Illegal number: %s", s);
Eric Andersen2870d962001-07-02 17:27:21 +00008835 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00008836}
8837
Eric Andersencb57d552001-06-28 07:25:16 +00008838/*
8839 * Produce a possibly single quoted string suitable as input to the shell.
8840 * The return string is allocated on the stack.
8841 */
8842
8843static char *
8844single_quote(const char *s) {
8845 char *p;
8846
8847 STARTSTACKSTR(p);
8848
8849 do {
8850 char *q = p;
8851 size_t len1, len1p, len2, len2p;
8852
8853 len1 = strcspn(s, "'");
8854 len2 = strspn(s + len1, "'");
8855
8856 len1p = len1 ? len1 + 2 : len1;
8857 switch (len2) {
8858 case 0:
8859 len2p = 0;
8860 break;
8861 case 1:
8862 len2p = 2;
8863 break;
8864 default:
8865 len2p = len2 + 2;
8866 }
8867
8868 CHECKSTRSPACE(len1p + len2p + 1, p);
8869
8870 if (len1) {
8871 *p = '\'';
8872#ifdef _GNU_SOURCE
8873 q = mempcpy(p + 1, s, len1);
8874#else
8875 q = p + 1 + len1;
8876 memcpy(p + 1, s, len1);
8877#endif
8878 *q++ = '\'';
8879 s += len1;
8880 }
8881
8882 switch (len2) {
8883 case 0:
8884 break;
8885 case 1:
8886 *q++ = '\\';
8887 *q = '\'';
8888 s++;
8889 break;
8890 default:
8891 *q = '"';
8892#ifdef _GNU_SOURCE
8893 *(char *) mempcpy(q + 1, s, len2) = '"';
8894#else
8895 q += 1 + len2;
8896 memcpy(q + 1, s, len2);
8897 *q = '"';
8898#endif
8899 s += len2;
8900 }
8901
8902 STADJUST(len1p + len2p, p);
8903 } while (*s);
8904
8905 USTPUTC(0, p);
8906
8907 return grabstackstr(p);
8908}
8909
8910/*
8911 * Like strdup but works with the ash stack.
8912 */
8913
8914static char *
8915sstrdup(const char *p)
8916{
8917 size_t len = strlen(p) + 1;
8918 return memcpy(stalloc(len), p, len);
8919}
8920
Eric Andersencb57d552001-06-28 07:25:16 +00008921
8922/*
Eric Andersencb57d552001-06-28 07:25:16 +00008923 * This file was generated by the mknodes program.
8924 */
8925
Eric Andersencb57d552001-06-28 07:25:16 +00008926/*
8927 * Routine for dealing with parsed shell commands.
8928 */
8929
8930
Eric Andersen2870d962001-07-02 17:27:21 +00008931static int funcblocksize; /* size of structures in function */
8932static int funcstringsize; /* size of strings in node */
8933static pointer funcblock; /* block to allocate function from */
8934static char *funcstring; /* block to allocate strings from */
Eric Andersencb57d552001-06-28 07:25:16 +00008935
8936static const short nodesize[26] = {
8937 ALIGN(sizeof (struct nbinary)),
8938 ALIGN(sizeof (struct ncmd)),
8939 ALIGN(sizeof (struct npipe)),
8940 ALIGN(sizeof (struct nredir)),
8941 ALIGN(sizeof (struct nredir)),
8942 ALIGN(sizeof (struct nredir)),
8943 ALIGN(sizeof (struct nbinary)),
8944 ALIGN(sizeof (struct nbinary)),
8945 ALIGN(sizeof (struct nif)),
8946 ALIGN(sizeof (struct nbinary)),
8947 ALIGN(sizeof (struct nbinary)),
8948 ALIGN(sizeof (struct nfor)),
8949 ALIGN(sizeof (struct ncase)),
8950 ALIGN(sizeof (struct nclist)),
8951 ALIGN(sizeof (struct narg)),
8952 ALIGN(sizeof (struct narg)),
8953 ALIGN(sizeof (struct nfile)),
8954 ALIGN(sizeof (struct nfile)),
8955 ALIGN(sizeof (struct nfile)),
8956 ALIGN(sizeof (struct nfile)),
8957 ALIGN(sizeof (struct nfile)),
8958 ALIGN(sizeof (struct ndup)),
8959 ALIGN(sizeof (struct ndup)),
8960 ALIGN(sizeof (struct nhere)),
8961 ALIGN(sizeof (struct nhere)),
8962 ALIGN(sizeof (struct nnot)),
8963};
8964
8965
Eric Andersen2870d962001-07-02 17:27:21 +00008966static void calcsize (union node *);
8967static void sizenodelist (struct nodelist *);
8968static union node *copynode (union node *);
8969static struct nodelist *copynodelist (struct nodelist *);
8970static char *nodesavestr (char *);
Eric Andersencb57d552001-06-28 07:25:16 +00008971
8972
8973
8974/*
8975 * Make a copy of a parse tree.
8976 */
8977
Eric Andersen2870d962001-07-02 17:27:21 +00008978static union node *
8979copyfunc(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008980{
8981 if (n == NULL)
8982 return NULL;
8983 funcblocksize = 0;
8984 funcstringsize = 0;
8985 calcsize(n);
8986 funcblock = ckmalloc(funcblocksize + funcstringsize);
8987 funcstring = (char *) funcblock + funcblocksize;
8988 return copynode(n);
8989}
8990
8991
8992
8993static void
8994calcsize(n)
8995 union node *n;
8996{
8997 if (n == NULL)
8998 return;
8999 funcblocksize += nodesize[n->type];
9000 switch (n->type) {
9001 case NSEMI:
9002 case NAND:
9003 case NOR:
9004 case NWHILE:
9005 case NUNTIL:
9006 calcsize(n->nbinary.ch2);
9007 calcsize(n->nbinary.ch1);
9008 break;
9009 case NCMD:
9010 calcsize(n->ncmd.redirect);
9011 calcsize(n->ncmd.args);
9012 calcsize(n->ncmd.assign);
9013 break;
9014 case NPIPE:
9015 sizenodelist(n->npipe.cmdlist);
9016 break;
9017 case NREDIR:
9018 case NBACKGND:
9019 case NSUBSHELL:
9020 calcsize(n->nredir.redirect);
9021 calcsize(n->nredir.n);
9022 break;
9023 case NIF:
9024 calcsize(n->nif.elsepart);
9025 calcsize(n->nif.ifpart);
9026 calcsize(n->nif.test);
9027 break;
9028 case NFOR:
9029 funcstringsize += strlen(n->nfor.var) + 1;
9030 calcsize(n->nfor.body);
9031 calcsize(n->nfor.args);
9032 break;
9033 case NCASE:
9034 calcsize(n->ncase.cases);
9035 calcsize(n->ncase.expr);
9036 break;
9037 case NCLIST:
9038 calcsize(n->nclist.body);
9039 calcsize(n->nclist.pattern);
9040 calcsize(n->nclist.next);
9041 break;
9042 case NDEFUN:
9043 case NARG:
9044 sizenodelist(n->narg.backquote);
9045 funcstringsize += strlen(n->narg.text) + 1;
9046 calcsize(n->narg.next);
9047 break;
9048 case NTO:
9049 case NFROM:
9050 case NFROMTO:
9051 case NAPPEND:
9052 case NTOOV:
9053 calcsize(n->nfile.fname);
9054 calcsize(n->nfile.next);
9055 break;
9056 case NTOFD:
9057 case NFROMFD:
9058 calcsize(n->ndup.vname);
9059 calcsize(n->ndup.next);
9060 break;
9061 case NHERE:
9062 case NXHERE:
9063 calcsize(n->nhere.doc);
9064 calcsize(n->nhere.next);
9065 break;
9066 case NNOT:
9067 calcsize(n->nnot.com);
9068 break;
9069 };
9070}
9071
9072
9073
9074static void
9075sizenodelist(lp)
9076 struct nodelist *lp;
9077{
9078 while (lp) {
9079 funcblocksize += ALIGN(sizeof(struct nodelist));
9080 calcsize(lp->n);
9081 lp = lp->next;
9082 }
9083}
9084
9085
9086
9087static union node *
9088copynode(n)
9089 union node *n;
9090{
9091 union node *new;
9092
9093 if (n == NULL)
9094 return NULL;
9095 new = funcblock;
9096 funcblock = (char *) funcblock + nodesize[n->type];
9097 switch (n->type) {
9098 case NSEMI:
9099 case NAND:
9100 case NOR:
9101 case NWHILE:
9102 case NUNTIL:
9103 new->nbinary.ch2 = copynode(n->nbinary.ch2);
9104 new->nbinary.ch1 = copynode(n->nbinary.ch1);
9105 break;
9106 case NCMD:
9107 new->ncmd.redirect = copynode(n->ncmd.redirect);
9108 new->ncmd.args = copynode(n->ncmd.args);
9109 new->ncmd.assign = copynode(n->ncmd.assign);
9110 new->ncmd.backgnd = n->ncmd.backgnd;
9111 break;
9112 case NPIPE:
9113 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
9114 new->npipe.backgnd = n->npipe.backgnd;
9115 break;
9116 case NREDIR:
9117 case NBACKGND:
9118 case NSUBSHELL:
9119 new->nredir.redirect = copynode(n->nredir.redirect);
9120 new->nredir.n = copynode(n->nredir.n);
9121 break;
9122 case NIF:
9123 new->nif.elsepart = copynode(n->nif.elsepart);
9124 new->nif.ifpart = copynode(n->nif.ifpart);
9125 new->nif.test = copynode(n->nif.test);
9126 break;
9127 case NFOR:
9128 new->nfor.var = nodesavestr(n->nfor.var);
9129 new->nfor.body = copynode(n->nfor.body);
9130 new->nfor.args = copynode(n->nfor.args);
9131 break;
9132 case NCASE:
9133 new->ncase.cases = copynode(n->ncase.cases);
9134 new->ncase.expr = copynode(n->ncase.expr);
9135 break;
9136 case NCLIST:
9137 new->nclist.body = copynode(n->nclist.body);
9138 new->nclist.pattern = copynode(n->nclist.pattern);
9139 new->nclist.next = copynode(n->nclist.next);
9140 break;
9141 case NDEFUN:
9142 case NARG:
9143 new->narg.backquote = copynodelist(n->narg.backquote);
9144 new->narg.text = nodesavestr(n->narg.text);
9145 new->narg.next = copynode(n->narg.next);
9146 break;
9147 case NTO:
9148 case NFROM:
9149 case NFROMTO:
9150 case NAPPEND:
9151 case NTOOV:
9152 new->nfile.fname = copynode(n->nfile.fname);
9153 new->nfile.fd = n->nfile.fd;
9154 new->nfile.next = copynode(n->nfile.next);
9155 break;
9156 case NTOFD:
9157 case NFROMFD:
9158 new->ndup.vname = copynode(n->ndup.vname);
9159 new->ndup.dupfd = n->ndup.dupfd;
9160 new->ndup.fd = n->ndup.fd;
9161 new->ndup.next = copynode(n->ndup.next);
9162 break;
9163 case NHERE:
9164 case NXHERE:
9165 new->nhere.doc = copynode(n->nhere.doc);
9166 new->nhere.fd = n->nhere.fd;
9167 new->nhere.next = copynode(n->nhere.next);
9168 break;
9169 case NNOT:
9170 new->nnot.com = copynode(n->nnot.com);
9171 break;
9172 };
9173 new->type = n->type;
9174 return new;
9175}
9176
9177
9178static struct nodelist *
9179copynodelist(lp)
9180 struct nodelist *lp;
9181{
9182 struct nodelist *start;
9183 struct nodelist **lpp;
9184
9185 lpp = &start;
9186 while (lp) {
9187 *lpp = funcblock;
9188 funcblock = (char *) funcblock + ALIGN(sizeof(struct nodelist));
9189 (*lpp)->n = copynode(lp->n);
9190 lp = lp->next;
9191 lpp = &(*lpp)->next;
9192 }
9193 *lpp = NULL;
9194 return start;
9195}
9196
9197
9198
9199static char *
9200nodesavestr(s)
9201 char *s;
9202{
9203#ifdef _GNU_SOURCE
9204 char *rtn = funcstring;
9205
9206 funcstring = stpcpy(funcstring, s) + 1;
9207 return rtn;
9208#else
9209 register char *p = s;
9210 register char *q = funcstring;
9211 char *rtn = funcstring;
9212
9213 while ((*q++ = *p++) != '\0')
9214 continue;
9215 funcstring = q;
9216 return rtn;
9217#endif
9218}
9219
Eric Andersencb57d552001-06-28 07:25:16 +00009220#ifdef ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00009221static int getopts (char *, char *, char **, int *, int *);
Eric Andersencb57d552001-06-28 07:25:16 +00009222#endif
9223
9224
9225/*
9226 * Process the shell command line arguments.
9227 */
9228
9229static void
9230procargs(argc, argv)
9231 int argc;
9232 char **argv;
9233{
9234 int i;
9235
9236 argptr = argv;
9237 if (argc > 0)
9238 argptr++;
9239 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00009240 optent_val(i) = 2;
Eric Andersencb57d552001-06-28 07:25:16 +00009241 options(1);
9242 if (*argptr == NULL && minusc == NULL)
9243 sflag = 1;
9244 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
9245 iflag = 1;
9246 if (mflag == 2)
9247 mflag = iflag;
9248 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00009249 if (optent_val(i) == 2)
9250 optent_val(i) = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009251 arg0 = argv[0];
9252 if (sflag == 0 && minusc == NULL) {
9253 commandname = argv[0];
9254 arg0 = *argptr++;
9255 setinputfile(arg0, 0);
9256 commandname = arg0;
9257 }
9258 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
9259 if (argptr && minusc && *argptr)
Eric Andersen2870d962001-07-02 17:27:21 +00009260 arg0 = *argptr++;
Eric Andersencb57d552001-06-28 07:25:16 +00009261
9262 shellparam.p = argptr;
9263 shellparam.optind = 1;
9264 shellparam.optoff = -1;
9265 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
9266 while (*argptr) {
9267 shellparam.nparam++;
9268 argptr++;
9269 }
9270 optschanged();
9271}
9272
9273
Eric Andersencb57d552001-06-28 07:25:16 +00009274
9275/*
9276 * Process shell options. The global variable argptr contains a pointer
9277 * to the argument list; we advance it past the options.
9278 */
9279
9280static void
9281options(cmdline)
9282 int cmdline;
9283{
9284 char *p;
9285 int val;
9286 int c;
9287
9288 if (cmdline)
9289 minusc = NULL;
9290 while ((p = *argptr) != NULL) {
9291 argptr++;
9292 if ((c = *p++) == '-') {
9293 val = 1;
Eric Andersen2870d962001-07-02 17:27:21 +00009294 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
9295 if (!cmdline) {
9296 /* "-" means turn off -x and -v */
9297 if (p[0] == '\0')
9298 xflag = vflag = 0;
9299 /* "--" means reset params */
9300 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00009301 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +00009302 }
9303 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +00009304 }
9305 } else if (c == '+') {
9306 val = 0;
9307 } else {
9308 argptr--;
9309 break;
9310 }
9311 while ((c = *p++) != '\0') {
9312 if (c == 'c' && cmdline) {
9313 char *q;
Eric Andersen2870d962001-07-02 17:27:21 +00009314#ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */
Eric Andersencb57d552001-06-28 07:25:16 +00009315 if (*p == '\0')
9316#endif
9317 q = *argptr++;
9318 if (q == NULL || minusc != NULL)
9319 error("Bad -c option");
9320 minusc = q;
9321#ifdef NOHACK
9322 break;
9323#endif
9324 } else if (c == 'o') {
9325 minus_o(*argptr, val);
9326 if (*argptr)
9327 argptr++;
9328 } else {
9329 setoption(c, val);
9330 }
9331 }
9332 }
9333}
9334
9335static void
9336minus_o(name, val)
9337 char *name;
9338 int val;
9339{
9340 int i;
9341
9342 if (name == NULL) {
9343 out1str("Current option settings\n");
9344 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00009345 out1fmt("%-16s%s\n", optent_name(optlist[i]),
9346 optent_val(i) ? "on" : "off");
Eric Andersencb57d552001-06-28 07:25:16 +00009347 } else {
9348 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00009349 if (equal(name, optent_name(optlist[i]))) {
9350 setoption(optent_letter(optlist[i]), val);
Eric Andersencb57d552001-06-28 07:25:16 +00009351 return;
9352 }
9353 error("Illegal option -o %s", name);
9354 }
9355}
9356
9357
9358static void
Eric Andersen2870d962001-07-02 17:27:21 +00009359setoption(int flag, int val)
9360{
Eric Andersencb57d552001-06-28 07:25:16 +00009361 int i;
9362
9363 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00009364 if (optent_letter(optlist[i]) == flag) {
9365 optent_val(i) = val;
Eric Andersencb57d552001-06-28 07:25:16 +00009366 if (val) {
9367 /* #%$ hack for ksh semantics */
9368 if (flag == 'V')
9369 Eflag = 0;
9370 else if (flag == 'E')
9371 Vflag = 0;
9372 }
9373 return;
9374 }
9375 error("Illegal option -%c", flag);
9376 /* NOTREACHED */
9377}
9378
9379
9380
Eric Andersencb57d552001-06-28 07:25:16 +00009381/*
9382 * Set the shell parameters.
9383 */
9384
9385static void
Eric Andersen2870d962001-07-02 17:27:21 +00009386setparam(char **argv)
9387{
Eric Andersencb57d552001-06-28 07:25:16 +00009388 char **newparam;
9389 char **ap;
9390 int nparam;
9391
9392 for (nparam = 0 ; argv[nparam] ; nparam++);
9393 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
9394 while (*argv) {
9395 *ap++ = savestr(*argv++);
9396 }
9397 *ap = NULL;
9398 freeparam(&shellparam);
9399 shellparam.malloc = 1;
9400 shellparam.nparam = nparam;
9401 shellparam.p = newparam;
9402 shellparam.optind = 1;
9403 shellparam.optoff = -1;
9404}
9405
9406
9407/*
9408 * Free the list of positional parameters.
9409 */
9410
9411static void
Eric Andersen2870d962001-07-02 17:27:21 +00009412freeparam(volatile struct shparam *param)
9413{
Eric Andersencb57d552001-06-28 07:25:16 +00009414 char **ap;
9415
9416 if (param->malloc) {
9417 for (ap = param->p ; *ap ; ap++)
9418 ckfree(*ap);
9419 ckfree(param->p);
9420 }
9421}
9422
9423
9424
9425/*
9426 * The shift builtin command.
9427 */
9428
9429static int
9430shiftcmd(argc, argv)
9431 int argc;
9432 char **argv;
9433{
9434 int n;
9435 char **ap1, **ap2;
9436
9437 n = 1;
9438 if (argc > 1)
9439 n = number(argv[1]);
9440 if (n > shellparam.nparam)
9441 error("can't shift that many");
9442 INTOFF;
9443 shellparam.nparam -= n;
9444 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
9445 if (shellparam.malloc)
9446 ckfree(*ap1);
9447 }
9448 ap2 = shellparam.p;
9449 while ((*ap2++ = *ap1++) != NULL);
9450 shellparam.optind = 1;
9451 shellparam.optoff = -1;
9452 INTON;
9453 return 0;
9454}
9455
9456
9457
9458/*
9459 * The set command builtin.
9460 */
9461
9462static int
9463setcmd(argc, argv)
9464 int argc;
9465 char **argv;
9466{
9467 if (argc == 1)
9468 return showvarscmd(argc, argv);
9469 INTOFF;
9470 options(0);
9471 optschanged();
9472 if (*argptr != NULL) {
9473 setparam(argptr);
9474 }
9475 INTON;
9476 return 0;
9477}
9478
9479
9480static void
Eric Andersen2870d962001-07-02 17:27:21 +00009481getoptsreset(const char *value)
Eric Andersencb57d552001-06-28 07:25:16 +00009482{
9483 shellparam.optind = number(value);
9484 shellparam.optoff = -1;
9485}
9486
Eric Andersen2870d962001-07-02 17:27:21 +00009487#ifdef BB_LOCALE_SUPPORT
9488static void change_lc_all(const char *value)
9489{
9490 if(value != 0 && *value != 0)
9491 setlocale(LC_ALL, value);
9492}
9493
9494static void change_lc_ctype(const char *value)
9495{
9496 if(value != 0 && *value != 0)
9497 setlocale(LC_CTYPE, value);
9498}
9499
9500#endif
9501
Eric Andersencb57d552001-06-28 07:25:16 +00009502#ifdef ASH_GETOPTS
9503/*
9504 * The getopts builtin. Shellparam.optnext points to the next argument
9505 * to be processed. Shellparam.optptr points to the next character to
9506 * be processed in the current argument. If shellparam.optnext is NULL,
9507 * then it's the first time getopts has been called.
9508 */
9509
9510static int
9511getoptscmd(argc, argv)
9512 int argc;
9513 char **argv;
9514{
9515 char **optbase;
9516
9517 if (argc < 3)
9518 error("Usage: getopts optstring var [arg]");
9519 else if (argc == 3) {
9520 optbase = shellparam.p;
9521 if (shellparam.optind > shellparam.nparam + 1) {
9522 shellparam.optind = 1;
9523 shellparam.optoff = -1;
9524 }
9525 }
9526 else {
9527 optbase = &argv[3];
9528 if (shellparam.optind > argc - 2) {
9529 shellparam.optind = 1;
9530 shellparam.optoff = -1;
9531 }
9532 }
9533
9534 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9535 &shellparam.optoff);
9536}
9537
9538/*
9539 * Safe version of setvar, returns 1 on success 0 on failure.
9540 */
9541
9542static int
9543setvarsafe(name, val, flags)
9544 const char *name, *val;
9545 int flags;
9546{
9547 struct jmploc jmploc;
9548 struct jmploc *volatile savehandler = handler;
9549 int err = 0;
9550#ifdef __GNUC__
9551 (void) &err;
9552#endif
9553
9554 if (setjmp(jmploc.loc))
9555 err = 1;
9556 else {
9557 handler = &jmploc;
9558 setvar(name, val, flags);
9559 }
9560 handler = savehandler;
9561 return err;
9562}
9563
9564static int
9565getopts(optstr, optvar, optfirst, myoptind, optoff)
9566 char *optstr;
9567 char *optvar;
9568 char **optfirst;
9569 int *myoptind;
9570 int *optoff;
9571{
9572 char *p, *q;
9573 char c = '?';
9574 int done = 0;
9575 int err = 0;
9576 char s[10];
9577 char **optnext = optfirst + *myoptind - 1;
9578
9579 if (*myoptind <= 1 || *optoff < 0 || !(*(optnext - 1)) ||
9580 strlen(*(optnext - 1)) < *optoff)
9581 p = NULL;
9582 else
9583 p = *(optnext - 1) + *optoff;
9584 if (p == NULL || *p == '\0') {
9585 /* Current word is done, advance */
9586 if (optnext == NULL)
9587 return 1;
9588 p = *optnext;
9589 if (p == NULL || *p != '-' || *++p == '\0') {
9590atend:
9591 *myoptind = optnext - optfirst + 1;
9592 p = NULL;
9593 done = 1;
9594 goto out;
9595 }
9596 optnext++;
Eric Andersen2870d962001-07-02 17:27:21 +00009597 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009598 goto atend;
9599 }
9600
9601 c = *p++;
9602 for (q = optstr; *q != c; ) {
9603 if (*q == '\0') {
9604 if (optstr[0] == ':') {
9605 s[0] = c;
9606 s[1] = '\0';
9607 err |= setvarsafe("OPTARG", s, 0);
9608 }
9609 else {
9610 outfmt(&errout, "Illegal option -%c\n", c);
9611 (void) unsetvar("OPTARG");
9612 }
9613 c = '?';
9614 goto bad;
9615 }
9616 if (*++q == ':')
9617 q++;
9618 }
9619
9620 if (*++q == ':') {
9621 if (*p == '\0' && (p = *optnext) == NULL) {
9622 if (optstr[0] == ':') {
9623 s[0] = c;
9624 s[1] = '\0';
9625 err |= setvarsafe("OPTARG", s, 0);
9626 c = ':';
9627 }
9628 else {
9629 outfmt(&errout, "No arg for -%c option\n", c);
9630 (void) unsetvar("OPTARG");
9631 c = '?';
9632 }
9633 goto bad;
9634 }
9635
9636 if (p == *optnext)
9637 optnext++;
9638 setvarsafe("OPTARG", p, 0);
9639 p = NULL;
9640 }
9641 else
9642 setvarsafe("OPTARG", "", 0);
9643 *myoptind = optnext - optfirst + 1;
9644 goto out;
9645
9646bad:
9647 *myoptind = 1;
9648 p = NULL;
9649out:
9650 *optoff = p ? p - *(optnext - 1) : -1;
9651 fmtstr(s, sizeof(s), "%d", *myoptind);
9652 err |= setvarsafe("OPTIND", s, VNOFUNC);
9653 s[0] = c;
9654 s[1] = '\0';
9655 err |= setvarsafe(optvar, s, 0);
9656 if (err) {
9657 *myoptind = 1;
9658 *optoff = -1;
9659 flushall();
9660 exraise(EXERROR);
9661 }
9662 return done;
9663}
Eric Andersen2870d962001-07-02 17:27:21 +00009664#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009665
9666/*
9667 * XXX - should get rid of. have all builtins use getopt(3). the
9668 * library getopt must have the BSD extension static variable "optreset"
9669 * otherwise it can't be used within the shell safely.
9670 *
9671 * Standard option processing (a la getopt) for builtin routines. The
9672 * only argument that is passed to nextopt is the option string; the
9673 * other arguments are unnecessary. It return the character, or '\0' on
9674 * end of input.
9675 */
9676
9677static int
9678nextopt(optstring)
9679 const char *optstring;
9680 {
9681 char *p;
9682 const char *q;
9683 char c;
9684
9685 if ((p = optptr) == NULL || *p == '\0') {
9686 p = *argptr;
9687 if (p == NULL || *p != '-' || *++p == '\0')
9688 return '\0';
9689 argptr++;
Eric Andersen2870d962001-07-02 17:27:21 +00009690 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009691 return '\0';
9692 }
9693 c = *p++;
9694 for (q = optstring ; *q != c ; ) {
9695 if (*q == '\0')
9696 error("Illegal option -%c", c);
9697 if (*++q == ':')
9698 q++;
9699 }
9700 if (*++q == ':') {
9701 if (*p == '\0' && (p = *argptr++) == NULL)
9702 error("No arg for -%c option", c);
9703 optionarg = p;
9704 p = NULL;
9705 }
9706 optptr = p;
9707 return c;
9708}
9709
9710
Eric Andersencb57d552001-06-28 07:25:16 +00009711/*
9712 * Shell output routines. We use our own output routines because:
Eric Andersen2870d962001-07-02 17:27:21 +00009713 * When a builtin command is interrupted we have to discard
9714 * any pending output.
9715 * When a builtin command appears in back quotes, we want to
9716 * save the output of the command in a region obtained
9717 * via malloc, rather than doing a fork and reading the
9718 * output of the command via a pipe.
9719 * Our output routines may be smaller than the stdio routines.
Eric Andersencb57d552001-06-28 07:25:16 +00009720 */
9721
9722
Eric Andersencb57d552001-06-28 07:25:16 +00009723
9724#ifndef USE_GLIBC_STDIO
Eric Andersen2870d962001-07-02 17:27:21 +00009725static void __outstr (const char *, size_t, struct output*);
Eric Andersencb57d552001-06-28 07:25:16 +00009726#endif
9727
9728
9729#ifndef USE_GLIBC_STDIO
9730static void
9731__outstr(const char *p, size_t len, struct output *dest) {
9732 if (!dest->bufsize) {
9733 dest->nleft = 0;
9734 } else if (dest->buf == NULL) {
9735 if (len > dest->bufsize && dest->fd == MEM_OUT) {
9736 dest->bufsize = len;
9737 }
9738 INTOFF;
9739 dest->buf = ckmalloc(dest->bufsize);
9740 dest->nextc = dest->buf;
9741 dest->nleft = dest->bufsize;
9742 INTON;
9743 } else if (dest->fd == MEM_OUT) {
9744 int offset;
9745
9746 offset = dest->bufsize;
9747 INTOFF;
9748 if (dest->bufsize >= len) {
9749 dest->bufsize <<= 1;
9750 } else {
9751 dest->bufsize += len;
9752 }
9753 dest->buf = ckrealloc(dest->buf, dest->bufsize);
9754 dest->nleft = dest->bufsize - offset;
9755 dest->nextc = dest->buf + offset;
9756 INTON;
9757 } else {
9758 flushout(dest);
9759 }
9760
9761 if (len < dest->nleft) {
9762 dest->nleft -= len;
9763 memcpy(dest->nextc, p, len);
9764 dest->nextc += len;
9765 return;
9766 }
9767
9768 if (xwrite(dest->fd, p, len) < len)
9769 dest->flags |= OUTPUT_ERR;
9770}
9771#endif
9772
9773
9774static void
Eric Andersen2870d962001-07-02 17:27:21 +00009775outstr(const char *p, struct output *file)
9776{
Eric Andersencb57d552001-06-28 07:25:16 +00009777#ifdef USE_GLIBC_STDIO
9778 INTOFF;
9779 fputs(p, file->stream);
9780 INTON;
9781#else
9782 size_t len;
9783
9784 if (!*p) {
9785 return;
9786 }
9787 len = strlen(p);
9788 if ((file->nleft -= len) > 0) {
9789 memcpy(file->nextc, p, len);
9790 file->nextc += len;
9791 return;
9792 }
9793 __outstr(p, len, file);
9794#endif
9795}
9796
9797
9798#ifndef USE_GLIBC_STDIO
9799
9800
9801static void
9802outcslow(c, dest)
9803 char c;
9804 struct output *dest;
9805 {
9806 __outstr(&c, 1, dest);
9807}
9808#endif
9809
9810
9811static void
9812flushall() {
9813 flushout(&output);
9814#ifdef FLUSHERR
9815 flushout(&errout);
9816#endif
9817}
9818
9819
9820static void
9821flushout(dest)
9822 struct output *dest;
9823 {
9824#ifdef USE_GLIBC_STDIO
9825 INTOFF;
9826 fflush(dest->stream);
9827 INTON;
9828#else
9829 size_t len;
9830
9831 len = dest->nextc - dest->buf;
9832 if (dest->buf == NULL || !len || dest->fd < 0)
9833 return;
9834 dest->nextc = dest->buf;
9835 dest->nleft = dest->bufsize;
9836 if (xwrite(dest->fd, dest->buf, len) < len)
9837 dest->flags |= OUTPUT_ERR;
9838#endif
9839}
9840
9841
9842static void
9843freestdout() {
9844 if (output.buf) {
9845 INTOFF;
9846 ckfree(output.buf);
9847 output.buf = NULL;
9848 output.nleft = 0;
9849 INTON;
9850 }
9851 output.flags = 0;
9852}
9853
9854
9855static void
9856#ifdef __STDC__
9857outfmt(struct output *file, const char *fmt, ...)
9858#else
9859static void
9860outfmt(va_alist)
9861 va_dcl
9862#endif
9863{
9864 va_list ap;
9865#ifndef __STDC__
9866 struct output *file;
9867 const char *fmt;
9868
9869 va_start(ap);
9870 file = va_arg(ap, struct output *);
9871 fmt = va_arg(ap, const char *);
9872#else
9873 va_start(ap, fmt);
9874#endif
9875 doformat(file, fmt, ap);
9876 va_end(ap);
9877}
9878
9879
9880static void
9881#ifdef __STDC__
9882out1fmt(const char *fmt, ...)
9883#else
9884out1fmt(va_alist)
9885 va_dcl
9886#endif
9887{
9888 va_list ap;
9889#ifndef __STDC__
9890 const char *fmt;
9891
9892 va_start(ap);
9893 fmt = va_arg(ap, const char *);
9894#else
9895 va_start(ap, fmt);
9896#endif
9897 doformat(out1, fmt, ap);
9898 va_end(ap);
9899}
9900
9901static void
9902#ifdef __STDC__
9903fmtstr(char *outbuf, size_t length, const char *fmt, ...)
9904#else
9905fmtstr(va_alist)
9906 va_dcl
9907#endif
9908{
9909 va_list ap;
9910#ifndef __STDC__
9911 char *outbuf;
9912 size_t length;
9913 const char *fmt;
9914
9915 va_start(ap);
9916 outbuf = va_arg(ap, char *);
9917 length = va_arg(ap, size_t);
9918 fmt = va_arg(ap, const char *);
9919#else
9920 va_start(ap, fmt);
9921#endif
9922 INTOFF;
9923 vsnprintf(outbuf, length, fmt, ap);
9924 INTON;
9925}
9926
9927#ifndef USE_GLIBC_STDIO
Eric Andersencb57d552001-06-28 07:25:16 +00009928
9929static void
Eric Andersen2870d962001-07-02 17:27:21 +00009930doformat(struct output *dest, const char *f, va_list ap)
Eric Andersencb57d552001-06-28 07:25:16 +00009931{
Eric Andersen2870d962001-07-02 17:27:21 +00009932 char *pm;
9933 int size = BUFSIZ;
Eric Andersencb57d552001-06-28 07:25:16 +00009934
Eric Andersen2870d962001-07-02 17:27:21 +00009935 while(size) {
9936 int nchars;
Eric Andersencb57d552001-06-28 07:25:16 +00009937
Eric Andersen2870d962001-07-02 17:27:21 +00009938 pm = xmalloc(size);
9939 nchars = vsnprintf(pm, size, f, ap);
9940 if(nchars > -1) {
9941 outstr(pm, dest);
9942 size = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009943 }
Eric Andersen2870d962001-07-02 17:27:21 +00009944 else
9945 size *= 2;
9946 free(pm);
Eric Andersencb57d552001-06-28 07:25:16 +00009947 }
Eric Andersencb57d552001-06-28 07:25:16 +00009948}
9949#endif
9950
9951
9952
9953/*
9954 * Version of write which resumes after a signal is caught.
9955 */
9956
9957static int
Eric Andersen2870d962001-07-02 17:27:21 +00009958xwrite(int fd, const char *buf, int nbytes)
9959{
Eric Andersencb57d552001-06-28 07:25:16 +00009960 int ntry;
9961 int i;
9962 int n;
9963
9964 n = nbytes;
9965 ntry = 0;
9966 for (;;) {
9967 i = write(fd, buf, n);
9968 if (i > 0) {
9969 if ((n -= i) <= 0)
9970 return nbytes;
9971 buf += i;
9972 ntry = 0;
9973 } else if (i == 0) {
9974 if (++ntry > 10)
9975 return nbytes - n;
9976 } else if (errno != EINTR) {
9977 return -1;
9978 }
9979 }
9980}
9981
9982
Eric Andersencb57d552001-06-28 07:25:16 +00009983#ifdef USE_GLIBC_STDIO
9984static void initstreams() {
9985 output.stream = stdout;
9986 errout.stream = stderr;
9987}
9988
9989
9990static void
9991openmemout() {
9992 INTOFF;
9993 memout.stream = open_memstream(&memout.buf, &memout.bufsize);
9994 INTON;
9995}
9996
9997
9998static int
9999__closememout() {
10000 int error;
10001 error = fclose(memout.stream);
10002 memout.stream = NULL;
10003 return error;
10004}
10005#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010006/*
10007 * Shell command parser.
10008 */
10009
10010#define EOFMARKLEN 79
10011
10012
10013
10014struct heredoc {
Eric Andersen2870d962001-07-02 17:27:21 +000010015 struct heredoc *next; /* next here document in list */
10016 union node *here; /* redirection node */
10017 char *eofmark; /* string indicating end of input */
10018 int striptabs; /* if set, strip leading tabs */
Eric Andersencb57d552001-06-28 07:25:16 +000010019};
10020
Eric Andersen2870d962001-07-02 17:27:21 +000010021static struct heredoc *heredoclist; /* list of here documents to read */
10022static int parsebackquote; /* nonzero if we are inside backquotes */
10023static int doprompt; /* if set, prompt the user */
10024static int needprompt; /* true if interactive and at start of line */
10025static int lasttoken; /* last token read */
Eric Andersencb57d552001-06-28 07:25:16 +000010026
Eric Andersen2870d962001-07-02 17:27:21 +000010027static char *wordtext; /* text of last word returned by readtoken */
Eric Andersencb57d552001-06-28 07:25:16 +000010028
Eric Andersen2870d962001-07-02 17:27:21 +000010029static struct nodelist *backquotelist;
10030static union node *redirnode;
Eric Andersencb57d552001-06-28 07:25:16 +000010031struct heredoc *heredoc;
Eric Andersen2870d962001-07-02 17:27:21 +000010032static int quoteflag; /* set if (part of) last token was quoted */
10033static int startlinno; /* line # where last token started */
Eric Andersencb57d552001-06-28 07:25:16 +000010034
10035
Eric Andersen2870d962001-07-02 17:27:21 +000010036static union node *list (int);
10037static union node *andor (void);
10038static union node *pipeline (void);
10039static union node *command (void);
10040static union node *simplecmd (void);
10041static void parsefname (void);
10042static void parseheredoc (void);
10043static int peektoken (void);
10044static int readtoken (void);
10045static int xxreadtoken (void);
10046static int readtoken1 (int, char const *, char *, int);
10047static int noexpand (char *);
10048static void synexpect (int) __attribute__((noreturn));
10049static void synerror (const char *) __attribute__((noreturn));
10050static void setprompt (int);
Eric Andersencb57d552001-06-28 07:25:16 +000010051
10052
10053/*
10054 * Read and parse a command. Returns NEOF on end of file. (NULL is a
10055 * valid parse tree indicating a blank line.)
10056 */
10057
Eric Andersen2870d962001-07-02 17:27:21 +000010058static union node *
Eric Andersencb57d552001-06-28 07:25:16 +000010059parsecmd(int interact)
10060{
10061 int t;
10062
10063 tokpushback = 0;
10064 doprompt = interact;
10065 if (doprompt)
10066 setprompt(1);
10067 else
10068 setprompt(0);
10069 needprompt = 0;
10070 t = readtoken();
10071 if (t == TEOF)
10072 return NEOF;
10073 if (t == TNL)
10074 return NULL;
10075 tokpushback++;
10076 return list(1);
10077}
10078
10079
10080static union node *
10081list(nlflag)
10082 int nlflag;
10083{
10084 union node *n1, *n2, *n3;
10085 int tok;
10086
10087 checkkwd = 2;
10088 if (nlflag == 0 && tokendlist[peektoken()])
10089 return NULL;
10090 n1 = NULL;
10091 for (;;) {
10092 n2 = andor();
10093 tok = readtoken();
10094 if (tok == TBACKGND) {
10095 if (n2->type == NCMD || n2->type == NPIPE) {
10096 n2->ncmd.backgnd = 1;
10097 } else if (n2->type == NREDIR) {
10098 n2->type = NBACKGND;
10099 } else {
10100 n3 = (union node *)stalloc(sizeof (struct nredir));
10101 n3->type = NBACKGND;
10102 n3->nredir.n = n2;
10103 n3->nredir.redirect = NULL;
10104 n2 = n3;
10105 }
10106 }
10107 if (n1 == NULL) {
10108 n1 = n2;
10109 }
10110 else {
10111 n3 = (union node *)stalloc(sizeof (struct nbinary));
10112 n3->type = NSEMI;
10113 n3->nbinary.ch1 = n1;
10114 n3->nbinary.ch2 = n2;
10115 n1 = n3;
10116 }
10117 switch (tok) {
10118 case TBACKGND:
10119 case TSEMI:
10120 tok = readtoken();
10121 /* fall through */
10122 case TNL:
10123 if (tok == TNL) {
10124 parseheredoc();
10125 if (nlflag)
10126 return n1;
10127 } else {
10128 tokpushback++;
10129 }
10130 checkkwd = 2;
10131 if (tokendlist[peektoken()])
10132 return n1;
10133 break;
10134 case TEOF:
10135 if (heredoclist)
10136 parseheredoc();
10137 else
Eric Andersen2870d962001-07-02 17:27:21 +000010138 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +000010139 return n1;
10140 default:
10141 if (nlflag)
10142 synexpect(-1);
10143 tokpushback++;
10144 return n1;
10145 }
10146 }
10147}
10148
10149
10150
10151static union node *
10152andor() {
10153 union node *n1, *n2, *n3;
10154 int t;
10155
10156 checkkwd = 1;
10157 n1 = pipeline();
10158 for (;;) {
10159 if ((t = readtoken()) == TAND) {
10160 t = NAND;
10161 } else if (t == TOR) {
10162 t = NOR;
10163 } else {
10164 tokpushback++;
10165 return n1;
10166 }
10167 checkkwd = 2;
10168 n2 = pipeline();
10169 n3 = (union node *)stalloc(sizeof (struct nbinary));
10170 n3->type = t;
10171 n3->nbinary.ch1 = n1;
10172 n3->nbinary.ch2 = n2;
10173 n1 = n3;
10174 }
10175}
10176
10177
10178
10179static union node *
10180pipeline() {
10181 union node *n1, *n2, *pipenode;
10182 struct nodelist *lp, *prev;
10183 int negate;
10184
10185 negate = 0;
10186 TRACE(("pipeline: entered\n"));
10187 if (readtoken() == TNOT) {
10188 negate = !negate;
10189 checkkwd = 1;
10190 } else
10191 tokpushback++;
10192 n1 = command();
10193 if (readtoken() == TPIPE) {
10194 pipenode = (union node *)stalloc(sizeof (struct npipe));
10195 pipenode->type = NPIPE;
10196 pipenode->npipe.backgnd = 0;
10197 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10198 pipenode->npipe.cmdlist = lp;
10199 lp->n = n1;
10200 do {
10201 prev = lp;
10202 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10203 checkkwd = 2;
10204 lp->n = command();
10205 prev->next = lp;
10206 } while (readtoken() == TPIPE);
10207 lp->next = NULL;
10208 n1 = pipenode;
10209 }
10210 tokpushback++;
10211 if (negate) {
10212 n2 = (union node *)stalloc(sizeof (struct nnot));
10213 n2->type = NNOT;
10214 n2->nnot.com = n1;
10215 return n2;
10216 } else
10217 return n1;
10218}
10219
10220
10221
10222static union node *
10223command() {
10224 union node *n1, *n2;
10225 union node *ap, **app;
10226 union node *cp, **cpp;
10227 union node *redir, **rpp;
10228 int t;
10229
10230 redir = NULL;
10231 n1 = NULL;
10232 rpp = &redir;
10233
10234 switch (readtoken()) {
10235 case TIF:
10236 n1 = (union node *)stalloc(sizeof (struct nif));
10237 n1->type = NIF;
10238 n1->nif.test = list(0);
10239 if (readtoken() != TTHEN)
10240 synexpect(TTHEN);
10241 n1->nif.ifpart = list(0);
10242 n2 = n1;
10243 while (readtoken() == TELIF) {
10244 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
10245 n2 = n2->nif.elsepart;
10246 n2->type = NIF;
10247 n2->nif.test = list(0);
10248 if (readtoken() != TTHEN)
10249 synexpect(TTHEN);
10250 n2->nif.ifpart = list(0);
10251 }
10252 if (lasttoken == TELSE)
10253 n2->nif.elsepart = list(0);
10254 else {
10255 n2->nif.elsepart = NULL;
10256 tokpushback++;
10257 }
10258 if (readtoken() != TFI)
10259 synexpect(TFI);
10260 checkkwd = 1;
10261 break;
10262 case TWHILE:
10263 case TUNTIL: {
10264 int got;
10265 n1 = (union node *)stalloc(sizeof (struct nbinary));
10266 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
10267 n1->nbinary.ch1 = list(0);
10268 if ((got=readtoken()) != TDO) {
10269TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
10270 synexpect(TDO);
10271 }
10272 n1->nbinary.ch2 = list(0);
10273 if (readtoken() != TDONE)
10274 synexpect(TDONE);
10275 checkkwd = 1;
10276 break;
10277 }
10278 case TFOR:
10279 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
10280 synerror("Bad for loop variable");
10281 n1 = (union node *)stalloc(sizeof (struct nfor));
10282 n1->type = NFOR;
10283 n1->nfor.var = wordtext;
10284 checkkwd = 1;
10285 if (readtoken() == TIN) {
10286 app = &ap;
10287 while (readtoken() == TWORD) {
10288 n2 = (union node *)stalloc(sizeof (struct narg));
10289 n2->type = NARG;
10290 n2->narg.text = wordtext;
10291 n2->narg.backquote = backquotelist;
10292 *app = n2;
10293 app = &n2->narg.next;
10294 }
10295 *app = NULL;
10296 n1->nfor.args = ap;
10297 if (lasttoken != TNL && lasttoken != TSEMI)
10298 synexpect(-1);
10299 } else {
10300 static char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
10301 '@', '=', '\0'};
10302 n2 = (union node *)stalloc(sizeof (struct narg));
10303 n2->type = NARG;
10304 n2->narg.text = argvars;
10305 n2->narg.backquote = NULL;
10306 n2->narg.next = NULL;
10307 n1->nfor.args = n2;
10308 /*
10309 * Newline or semicolon here is optional (but note
10310 * that the original Bourne shell only allowed NL).
10311 */
10312 if (lasttoken != TNL && lasttoken != TSEMI)
10313 tokpushback++;
10314 }
10315 checkkwd = 2;
10316 if (readtoken() != TDO)
10317 synexpect(TDO);
10318 n1->nfor.body = list(0);
10319 if (readtoken() != TDONE)
10320 synexpect(TDONE);
10321 checkkwd = 1;
10322 break;
10323 case TCASE:
10324 n1 = (union node *)stalloc(sizeof (struct ncase));
10325 n1->type = NCASE;
10326 if (readtoken() != TWORD)
10327 synexpect(TWORD);
10328 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
10329 n2->type = NARG;
10330 n2->narg.text = wordtext;
10331 n2->narg.backquote = backquotelist;
10332 n2->narg.next = NULL;
10333 do {
10334 checkkwd = 1;
10335 } while (readtoken() == TNL);
10336 if (lasttoken != TIN)
10337 synerror("expecting \"in\"");
10338 cpp = &n1->ncase.cases;
10339 checkkwd = 2, readtoken();
10340 do {
10341 if (lasttoken == TLP)
10342 readtoken();
10343 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
10344 cp->type = NCLIST;
10345 app = &cp->nclist.pattern;
10346 for (;;) {
10347 *app = ap = (union node *)stalloc(sizeof (struct narg));
10348 ap->type = NARG;
10349 ap->narg.text = wordtext;
10350 ap->narg.backquote = backquotelist;
10351 if (checkkwd = 2, readtoken() != TPIPE)
10352 break;
10353 app = &ap->narg.next;
10354 readtoken();
10355 }
10356 ap->narg.next = NULL;
10357 if (lasttoken != TRP)
10358 synexpect(TRP);
10359 cp->nclist.body = list(0);
10360
10361 checkkwd = 2;
10362 if ((t = readtoken()) != TESAC) {
10363 if (t != TENDCASE)
10364 synexpect(TENDCASE);
10365 else
10366 checkkwd = 2, readtoken();
10367 }
10368 cpp = &cp->nclist.next;
10369 } while(lasttoken != TESAC);
10370 *cpp = NULL;
10371 checkkwd = 1;
10372 break;
10373 case TLP:
10374 n1 = (union node *)stalloc(sizeof (struct nredir));
10375 n1->type = NSUBSHELL;
10376 n1->nredir.n = list(0);
10377 n1->nredir.redirect = NULL;
10378 if (readtoken() != TRP)
10379 synexpect(TRP);
10380 checkkwd = 1;
10381 break;
10382 case TBEGIN:
10383 n1 = list(0);
10384 if (readtoken() != TEND)
10385 synexpect(TEND);
10386 checkkwd = 1;
10387 break;
10388 /* Handle an empty command like other simple commands. */
10389 case TSEMI:
10390 case TAND:
10391 case TOR:
10392 case TNL:
10393 case TEOF:
10394 case TRP:
10395 case TBACKGND:
10396 /*
10397 * An empty command before a ; doesn't make much sense, and
10398 * should certainly be disallowed in the case of `if ;'.
10399 */
10400 if (!redir)
10401 synexpect(-1);
10402 case TWORD:
10403 case TREDIR:
10404 tokpushback++;
10405 n1 = simplecmd();
10406 return n1;
10407 default:
10408 synexpect(-1);
10409 /* NOTREACHED */
10410 }
10411
10412 /* Now check for redirection which may follow command */
10413 while (readtoken() == TREDIR) {
10414 *rpp = n2 = redirnode;
10415 rpp = &n2->nfile.next;
10416 parsefname();
10417 }
10418 tokpushback++;
10419 *rpp = NULL;
10420 if (redir) {
10421 if (n1->type != NSUBSHELL) {
10422 n2 = (union node *)stalloc(sizeof (struct nredir));
10423 n2->type = NREDIR;
10424 n2->nredir.n = n1;
10425 n1 = n2;
10426 }
10427 n1->nredir.redirect = redir;
10428 }
10429
10430 return n1;
10431}
10432
10433
10434static union node *
10435simplecmd() {
10436 union node *args, **app;
10437 union node *n = NULL;
10438 union node *vars, **vpp;
10439 union node **rpp, *redir;
10440
10441 args = NULL;
10442 app = &args;
10443 vars = NULL;
10444 vpp = &vars;
10445 redir = NULL;
10446 rpp = &redir;
10447
Eric Andersen2870d962001-07-02 17:27:21 +000010448#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010449 checkalias = 2;
Eric Andersen2870d962001-07-02 17:27:21 +000010450#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010451 for (;;) {
10452 switch (readtoken()) {
10453 case TWORD:
10454 case TASSIGN:
10455 n = (union node *)stalloc(sizeof (struct narg));
10456 n->type = NARG;
10457 n->narg.text = wordtext;
10458 n->narg.backquote = backquotelist;
10459 if (lasttoken == TWORD) {
10460 *app = n;
10461 app = &n->narg.next;
10462 } else {
10463 *vpp = n;
10464 vpp = &n->narg.next;
10465 }
10466 break;
10467 case TREDIR:
10468 *rpp = n = redirnode;
10469 rpp = &n->nfile.next;
Eric Andersen2870d962001-07-02 17:27:21 +000010470 parsefname(); /* read name of redirection file */
Eric Andersencb57d552001-06-28 07:25:16 +000010471 break;
10472 case TLP:
10473 if (
10474 args && app == &args->narg.next &&
10475 !vars && !redir
10476 ) {
10477 /* We have a function */
10478 if (readtoken() != TRP)
10479 synexpect(TRP);
Eric Andersencb57d552001-06-28 07:25:16 +000010480 n->type = NDEFUN;
10481 checkkwd = 2;
10482 n->narg.next = command();
10483 return n;
10484 }
10485 /* fall through */
10486 default:
10487 tokpushback++;
10488 goto out;
10489 }
10490 }
10491out:
10492 *app = NULL;
10493 *vpp = NULL;
10494 *rpp = NULL;
10495 n = (union node *)stalloc(sizeof (struct ncmd));
10496 n->type = NCMD;
10497 n->ncmd.backgnd = 0;
10498 n->ncmd.args = args;
10499 n->ncmd.assign = vars;
10500 n->ncmd.redirect = redir;
10501 return n;
10502}
10503
10504static union node *
Eric Andersen2870d962001-07-02 17:27:21 +000010505makename(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000010506 union node *n;
10507
10508 n = (union node *)stalloc(sizeof (struct narg));
10509 n->type = NARG;
10510 n->narg.next = NULL;
10511 n->narg.text = wordtext;
10512 n->narg.backquote = backquotelist;
10513 return n;
10514}
10515
10516static void fixredir(union node *n, const char *text, int err)
Eric Andersen2870d962001-07-02 17:27:21 +000010517{
Eric Andersencb57d552001-06-28 07:25:16 +000010518 TRACE(("Fix redir %s %d\n", text, err));
10519 if (!err)
10520 n->ndup.vname = NULL;
10521
10522 if (is_digit(text[0]) && text[1] == '\0')
10523 n->ndup.dupfd = digit_val(text[0]);
10524 else if (text[0] == '-' && text[1] == '\0')
10525 n->ndup.dupfd = -1;
10526 else {
10527
10528 if (err)
10529 synerror("Bad fd number");
10530 else
10531 n->ndup.vname = makename();
10532 }
10533}
10534
10535
10536static void
Eric Andersen2870d962001-07-02 17:27:21 +000010537parsefname(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000010538 union node *n = redirnode;
10539
10540 if (readtoken() != TWORD)
10541 synexpect(-1);
10542 if (n->type == NHERE) {
10543 struct heredoc *here = heredoc;
10544 struct heredoc *p;
10545 int i;
10546
10547 if (quoteflag == 0)
10548 n->type = NXHERE;
10549 TRACE(("Here document %d\n", n->type));
10550 if (here->striptabs) {
10551 while (*wordtext == '\t')
10552 wordtext++;
10553 }
10554 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
10555 synerror("Illegal eof marker for << redirection");
10556 rmescapes(wordtext);
10557 here->eofmark = wordtext;
10558 here->next = NULL;
10559 if (heredoclist == NULL)
10560 heredoclist = here;
10561 else {
10562 for (p = heredoclist ; p->next ; p = p->next);
10563 p->next = here;
10564 }
10565 } else if (n->type == NTOFD || n->type == NFROMFD) {
10566 fixredir(n, wordtext, 0);
10567 } else {
10568 n->nfile.fname = makename();
10569 }
10570}
10571
10572
10573/*
10574 * Input any here documents.
10575 */
10576
10577static void
10578parseheredoc() {
10579 struct heredoc *here;
10580 union node *n;
10581
10582 while (heredoclist) {
10583 here = heredoclist;
10584 heredoclist = here->next;
10585 if (needprompt) {
10586 setprompt(2);
10587 needprompt = 0;
10588 }
10589 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
10590 here->eofmark, here->striptabs);
10591 n = (union node *)stalloc(sizeof (struct narg));
10592 n->narg.type = NARG;
10593 n->narg.next = NULL;
10594 n->narg.text = wordtext;
10595 n->narg.backquote = backquotelist;
10596 here->here->nhere.doc = n;
10597 }
10598}
10599
10600static int
10601peektoken() {
10602 int t;
10603
10604 t = readtoken();
10605 tokpushback++;
10606 return (t);
10607}
10608
10609static int
10610readtoken() {
10611 int t;
Eric Andersen2870d962001-07-02 17:27:21 +000010612#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010613 int savecheckkwd = checkkwd;
10614 int savecheckalias = checkalias;
10615 struct alias *ap;
Eric Andersen2870d962001-07-02 17:27:21 +000010616#endif
10617
Eric Andersencb57d552001-06-28 07:25:16 +000010618#ifdef DEBUG
10619 int alreadyseen = tokpushback;
10620#endif
10621
Eric Andersen2870d962001-07-02 17:27:21 +000010622#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010623top:
Eric Andersen2870d962001-07-02 17:27:21 +000010624#endif
10625
Eric Andersencb57d552001-06-28 07:25:16 +000010626 t = xxreadtoken();
Eric Andersen2870d962001-07-02 17:27:21 +000010627
10628#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010629 checkalias = savecheckalias;
Eric Andersen2870d962001-07-02 17:27:21 +000010630#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010631
10632 if (checkkwd) {
10633 /*
10634 * eat newlines
10635 */
10636 if (checkkwd == 2) {
10637 checkkwd = 0;
10638 while (t == TNL) {
10639 parseheredoc();
10640 t = xxreadtoken();
10641 }
10642 }
10643 checkkwd = 0;
10644 /*
10645 * check for keywords
10646 */
10647 if (t == TWORD && !quoteflag)
10648 {
10649 const char *const *pp;
10650
10651 if ((pp = findkwd(wordtext))) {
10652 lasttoken = t = pp - parsekwd + KWDOFFSET;
10653 TRACE(("keyword %s recognized\n", tokname[t]));
10654 goto out;
10655 }
10656 }
10657 }
10658
Eric Andersen2870d962001-07-02 17:27:21 +000010659#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010660 if (t != TWORD) {
10661 if (t != TREDIR) {
10662 checkalias = 0;
10663 }
10664 } else if (checkalias == 2 && isassignment(wordtext)) {
10665 lasttoken = t = TASSIGN;
10666 } else if (checkalias) {
10667 if (!quoteflag && (ap = lookupalias(wordtext, 1)) != NULL) {
10668 if (*ap->val) {
10669 pushstring(ap->val, strlen(ap->val), ap);
10670 }
10671 checkkwd = savecheckkwd;
10672 goto top;
10673 }
10674 checkalias = 0;
10675 }
Eric Andersen2870d962001-07-02 17:27:21 +000010676#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010677out:
10678#ifdef DEBUG
10679 if (!alreadyseen)
10680 TRACE(("token %s %s\n", tokname[t], t == TWORD || t == TASSIGN ? wordtext : ""));
10681 else
10682 TRACE(("reread token %s %s\n", tokname[t], t == TWORD || t == TASSIGN ? wordtext : ""));
10683#endif
10684 return (t);
10685}
10686
10687
10688/*
10689 * Read the next input token.
10690 * If the token is a word, we set backquotelist to the list of cmds in
Eric Andersen2870d962001-07-02 17:27:21 +000010691 * backquotes. We set quoteflag to true if any part of the word was
10692 * quoted.
Eric Andersencb57d552001-06-28 07:25:16 +000010693 * If the token is TREDIR, then we set redirnode to a structure containing
Eric Andersen2870d962001-07-02 17:27:21 +000010694 * the redirection.
Eric Andersencb57d552001-06-28 07:25:16 +000010695 * In all cases, the variable startlinno is set to the number of the line
Eric Andersen2870d962001-07-02 17:27:21 +000010696 * on which the token starts.
Eric Andersencb57d552001-06-28 07:25:16 +000010697 *
10698 * [Change comment: here documents and internal procedures]
10699 * [Readtoken shouldn't have any arguments. Perhaps we should make the
10700 * word parsing code into a separate routine. In this case, readtoken
10701 * doesn't need to have any internal procedures, but parseword does.
10702 * We could also make parseoperator in essence the main routine, and
10703 * have parseword (readtoken1?) handle both words and redirection.]
10704 */
10705
Eric Andersen2870d962001-07-02 17:27:21 +000010706#define RETURN(token) return lasttoken = token
Eric Andersencb57d552001-06-28 07:25:16 +000010707
10708static int
10709xxreadtoken() {
10710 int c;
10711
10712 if (tokpushback) {
10713 tokpushback = 0;
10714 return lasttoken;
10715 }
10716 if (needprompt) {
10717 setprompt(2);
10718 needprompt = 0;
10719 }
10720 startlinno = plinno;
Eric Andersen2870d962001-07-02 17:27:21 +000010721 for (;;) { /* until token or start of word found */
Eric Andersencb57d552001-06-28 07:25:16 +000010722 c = pgetc_macro();
10723 switch (c) {
10724 case ' ': case '\t':
10725 case PEOA:
10726 continue;
10727 case '#':
10728 while ((c = pgetc()) != '\n' && c != PEOF);
10729 pungetc();
10730 continue;
10731 case '\\':
10732 if (pgetc() == '\n') {
10733 startlinno = ++plinno;
10734 if (doprompt)
10735 setprompt(2);
10736 else
10737 setprompt(0);
10738 continue;
10739 }
10740 pungetc();
10741 goto breakloop;
10742 case '\n':
10743 plinno++;
10744 needprompt = doprompt;
10745 RETURN(TNL);
10746 case PEOF:
10747 RETURN(TEOF);
10748 case '&':
10749 if (pgetc() == '&')
10750 RETURN(TAND);
10751 pungetc();
10752 RETURN(TBACKGND);
10753 case '|':
10754 if (pgetc() == '|')
10755 RETURN(TOR);
10756 pungetc();
10757 RETURN(TPIPE);
10758 case ';':
10759 if (pgetc() == ';')
10760 RETURN(TENDCASE);
10761 pungetc();
10762 RETURN(TSEMI);
10763 case '(':
10764 RETURN(TLP);
10765 case ')':
10766 RETURN(TRP);
10767 default:
10768 goto breakloop;
10769 }
10770 }
10771breakloop:
10772 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10773#undef RETURN
10774}
10775
10776
10777
10778/*
10779 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10780 * is not NULL, read a here document. In the latter case, eofmark is the
10781 * word which marks the end of the document and striptabs is true if
10782 * leading tabs should be stripped from the document. The argument firstc
10783 * is the first character of the input token or document.
10784 *
10785 * Because C does not have internal subroutines, I have simulated them
10786 * using goto's to implement the subroutine linkage. The following macros
10787 * will run code that appears at the end of readtoken1.
10788 */
10789
Eric Andersen2870d962001-07-02 17:27:21 +000010790#define CHECKEND() {goto checkend; checkend_return:;}
10791#define PARSEREDIR() {goto parseredir; parseredir_return:;}
10792#define PARSESUB() {goto parsesub; parsesub_return:;}
10793#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10794#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10795#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000010796
10797static int
10798readtoken1(firstc, syntax, eofmark, striptabs)
10799 int firstc;
10800 char const *syntax;
10801 char *eofmark;
10802 int striptabs;
10803 {
10804 int c = firstc;
10805 char *out;
10806 int len;
10807 char line[EOFMARKLEN + 1];
10808 struct nodelist *bqlist;
10809 int quotef;
10810 int dblquote;
Eric Andersen2870d962001-07-02 17:27:21 +000010811 int varnest; /* levels of variables expansion */
10812 int arinest; /* levels of arithmetic expansion */
10813 int parenlevel; /* levels of parens in arithmetic */
10814 int dqvarnest; /* levels of variables expansion within double quotes */
Eric Andersencb57d552001-06-28 07:25:16 +000010815 int oldstyle;
Eric Andersen2870d962001-07-02 17:27:21 +000010816 char const *prevsyntax; /* syntax before arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010817#if __GNUC__
10818 /* Avoid longjmp clobbering */
10819 (void) &out;
10820 (void) &quotef;
10821 (void) &dblquote;
10822 (void) &varnest;
10823 (void) &arinest;
10824 (void) &parenlevel;
10825 (void) &dqvarnest;
10826 (void) &oldstyle;
10827 (void) &prevsyntax;
10828 (void) &syntax;
10829#endif
10830
10831 startlinno = plinno;
10832 dblquote = 0;
10833 if (syntax == DQSYNTAX)
10834 dblquote = 1;
10835 quotef = 0;
10836 bqlist = NULL;
10837 varnest = 0;
10838 arinest = 0;
10839 parenlevel = 0;
10840 dqvarnest = 0;
10841
10842 STARTSTACKSTR(out);
Eric Andersen2870d962001-07-02 17:27:21 +000010843 loop: { /* for each line, until end of word */
10844 CHECKEND(); /* set c to PEOF if at end of here document */
10845 for (;;) { /* until end of line or end of word */
10846 CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */
Eric Andersencb57d552001-06-28 07:25:16 +000010847 switch(syntax[c]) {
Eric Andersen2870d962001-07-02 17:27:21 +000010848 case CNL: /* '\n' */
Eric Andersencb57d552001-06-28 07:25:16 +000010849 if (syntax == BASESYNTAX)
Eric Andersen2870d962001-07-02 17:27:21 +000010850 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010851 USTPUTC(c, out);
10852 plinno++;
10853 if (doprompt)
10854 setprompt(2);
10855 else
10856 setprompt(0);
10857 c = pgetc();
Eric Andersen2870d962001-07-02 17:27:21 +000010858 goto loop; /* continue outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010859 case CWORD:
10860 USTPUTC(c, out);
10861 break;
10862 case CCTL:
10863 if ((eofmark == NULL || dblquote) &&
10864 dqvarnest == 0)
10865 USTPUTC(CTLESC, out);
10866 USTPUTC(c, out);
10867 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010868 case CBACK: /* backslash */
Eric Andersencb57d552001-06-28 07:25:16 +000010869 c = pgetc2();
10870 if (c == PEOF) {
10871 USTPUTC('\\', out);
10872 pungetc();
10873 } else if (c == '\n') {
10874 if (doprompt)
10875 setprompt(2);
10876 else
10877 setprompt(0);
10878 } else {
10879 if (dblquote && c != '\\' && c != '`' && c != '$'
10880 && (c != '"' || eofmark != NULL))
10881 USTPUTC('\\', out);
10882 if (SQSYNTAX[c] == CCTL)
10883 USTPUTC(CTLESC, out);
10884 else if (eofmark == NULL)
10885 USTPUTC(CTLQUOTEMARK, out);
10886 USTPUTC(c, out);
10887 quotef++;
10888 }
10889 break;
10890 case CSQUOTE:
10891 if (eofmark == NULL)
10892 USTPUTC(CTLQUOTEMARK, out);
10893 syntax = SQSYNTAX;
10894 break;
10895 case CDQUOTE:
10896 if (eofmark == NULL)
10897 USTPUTC(CTLQUOTEMARK, out);
10898 syntax = DQSYNTAX;
10899 dblquote = 1;
10900 break;
10901 case CENDQUOTE:
10902 if (eofmark != NULL && arinest == 0 &&
10903 varnest == 0) {
10904 USTPUTC(c, out);
10905 } else {
10906 if (arinest) {
10907 syntax = ARISYNTAX;
10908 dblquote = 0;
10909 } else if (eofmark == NULL &&
10910 dqvarnest == 0) {
10911 syntax = BASESYNTAX;
10912 dblquote = 0;
10913 }
10914 quotef++;
10915 }
10916 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010917 case CVAR: /* '$' */
10918 PARSESUB(); /* parse substitution */
Eric Andersencb57d552001-06-28 07:25:16 +000010919 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010920 case CENDVAR: /* '}' */
Eric Andersencb57d552001-06-28 07:25:16 +000010921 if (varnest > 0) {
10922 varnest--;
10923 if (dqvarnest > 0) {
10924 dqvarnest--;
10925 }
10926 USTPUTC(CTLENDVAR, out);
10927 } else {
10928 USTPUTC(c, out);
10929 }
10930 break;
10931#ifdef ASH_MATH_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +000010932 case CLP: /* '(' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010933 parenlevel++;
10934 USTPUTC(c, out);
10935 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010936 case CRP: /* ')' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010937 if (parenlevel > 0) {
10938 USTPUTC(c, out);
10939 --parenlevel;
10940 } else {
10941 if (pgetc() == ')') {
10942 if (--arinest == 0) {
10943 USTPUTC(CTLENDARI, out);
10944 syntax = prevsyntax;
10945 if (syntax == DQSYNTAX)
10946 dblquote = 1;
10947 else
10948 dblquote = 0;
10949 } else
10950 USTPUTC(')', out);
10951 } else {
10952 /*
10953 * unbalanced parens
10954 * (don't 2nd guess - no error)
10955 */
10956 pungetc();
10957 USTPUTC(')', out);
10958 }
10959 }
10960 break;
10961#endif
Eric Andersen2870d962001-07-02 17:27:21 +000010962 case CBQUOTE: /* '`' */
Eric Andersencb57d552001-06-28 07:25:16 +000010963 PARSEBACKQOLD();
10964 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010965 case CENDFILE:
10966 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010967 case CIGN:
10968 break;
10969 default:
10970 if (varnest == 0)
Eric Andersen2870d962001-07-02 17:27:21 +000010971 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010972 if (c != PEOA) {
10973 USTPUTC(c, out);
10974 }
10975 }
10976 c = pgetc_macro();
10977 }
10978 }
10979endword:
10980 if (syntax == ARISYNTAX)
10981 synerror("Missing '))'");
10982 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10983 synerror("Unterminated quoted string");
10984 if (varnest != 0) {
10985 startlinno = plinno;
10986 synerror("Missing '}'");
10987 }
10988 USTPUTC('\0', out);
10989 len = out - stackblock();
10990 out = stackblock();
10991 if (eofmark == NULL) {
10992 if ((c == '>' || c == '<')
10993 && quotef == 0
10994 && len <= 2
10995 && (*out == '\0' || is_digit(*out))) {
10996 PARSEREDIR();
10997 return lasttoken = TREDIR;
10998 } else {
10999 pungetc();
11000 }
11001 }
11002 quoteflag = quotef;
11003 backquotelist = bqlist;
11004 grabstackblock(len);
11005 wordtext = out;
11006 return lasttoken = TWORD;
11007/* end of readtoken routine */
11008
11009
11010
11011/*
11012 * Check to see whether we are at the end of the here document. When this
11013 * is called, c is set to the first character of the next input line. If
11014 * we are at the end of the here document, this routine sets the c to PEOF.
11015 */
11016
11017checkend: {
11018 if (eofmark) {
Eric Andersen2870d962001-07-02 17:27:21 +000011019#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000011020 if (c == PEOA) {
11021 c = pgetc2();
11022 }
Eric Andersen2870d962001-07-02 17:27:21 +000011023#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011024 if (striptabs) {
11025 while (c == '\t') {
11026 c = pgetc2();
11027 }
11028 }
11029 if (c == *eofmark) {
11030 if (pfgets(line, sizeof line) != NULL) {
11031 char *p, *q;
11032
11033 p = line;
11034 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
11035 if (*p == '\n' && *q == '\0') {
11036 c = PEOF;
11037 plinno++;
11038 needprompt = doprompt;
11039 } else {
11040 pushstring(line, strlen(line), NULL);
11041 }
11042 }
11043 }
11044 }
11045 goto checkend_return;
11046}
11047
11048
11049/*
11050 * Parse a redirection operator. The variable "out" points to a string
11051 * specifying the fd to be redirected. The variable "c" contains the
11052 * first character of the redirection operator.
11053 */
11054
11055parseredir: {
11056 char fd = *out;
11057 union node *np;
11058
11059 np = (union node *)stalloc(sizeof (struct nfile));
11060 if (c == '>') {
11061 np->nfile.fd = 1;
11062 c = pgetc();
11063 if (c == '>')
11064 np->type = NAPPEND;
11065 else if (c == '&')
11066 np->type = NTOFD;
11067 else if (c == '|')
11068 np->type = NTOOV;
11069 else {
11070 np->type = NTO;
11071 pungetc();
11072 }
Eric Andersen2870d962001-07-02 17:27:21 +000011073 } else { /* c == '<' */
Eric Andersencb57d552001-06-28 07:25:16 +000011074 np->nfile.fd = 0;
11075 switch (c = pgetc()) {
11076 case '<':
11077 if (sizeof (struct nfile) != sizeof (struct nhere)) {
11078 np = (union node *)stalloc(sizeof (struct nhere));
11079 np->nfile.fd = 0;
11080 }
11081 np->type = NHERE;
11082 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
11083 heredoc->here = np;
11084 if ((c = pgetc()) == '-') {
11085 heredoc->striptabs = 1;
11086 } else {
11087 heredoc->striptabs = 0;
11088 pungetc();
11089 }
11090 break;
11091
11092 case '&':
11093 np->type = NFROMFD;
11094 break;
11095
11096 case '>':
11097 np->type = NFROMTO;
11098 break;
11099
11100 default:
11101 np->type = NFROM;
11102 pungetc();
11103 break;
11104 }
11105 }
11106 if (fd != '\0')
11107 np->nfile.fd = digit_val(fd);
11108 redirnode = np;
11109 goto parseredir_return;
11110}
11111
11112
11113/*
11114 * Parse a substitution. At this point, we have read the dollar sign
11115 * and nothing else.
11116 */
11117
11118parsesub: {
11119 int subtype;
11120 int typeloc;
11121 int flags;
11122 char *p;
11123 static const char types[] = "}-+?=";
11124
11125 c = pgetc();
11126 if (
11127 c <= PEOA ||
11128 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
11129 ) {
11130 USTPUTC('$', out);
11131 pungetc();
Eric Andersen2870d962001-07-02 17:27:21 +000011132 } else if (c == '(') { /* $(command) or $((arith)) */
Eric Andersencb57d552001-06-28 07:25:16 +000011133 if (pgetc() == '(') {
11134 PARSEARITH();
11135 } else {
11136 pungetc();
11137 PARSEBACKQNEW();
11138 }
11139 } else {
11140 USTPUTC(CTLVAR, out);
11141 typeloc = out - stackblock();
11142 USTPUTC(VSNORMAL, out);
11143 subtype = VSNORMAL;
11144 if (c == '{') {
11145 c = pgetc();
11146 if (c == '#') {
11147 if ((c = pgetc()) == '}')
11148 c = '#';
11149 else
11150 subtype = VSLENGTH;
11151 }
11152 else
11153 subtype = 0;
11154 }
11155 if (c > PEOA && is_name(c)) {
11156 do {
11157 STPUTC(c, out);
11158 c = pgetc();
11159 } while (c > PEOA && is_in_name(c));
11160 } else if (is_digit(c)) {
11161 do {
11162 USTPUTC(c, out);
11163 c = pgetc();
11164 } while (is_digit(c));
11165 }
11166 else if (is_special(c)) {
11167 USTPUTC(c, out);
11168 c = pgetc();
11169 }
11170 else
Eric Andersen2870d962001-07-02 17:27:21 +000011171badsub: synerror("Bad substitution");
Eric Andersencb57d552001-06-28 07:25:16 +000011172
11173 STPUTC('=', out);
11174 flags = 0;
11175 if (subtype == 0) {
11176 switch (c) {
11177 case ':':
11178 flags = VSNUL;
11179 c = pgetc();
11180 /*FALLTHROUGH*/
11181 default:
11182 p = strchr(types, c);
11183 if (p == NULL)
11184 goto badsub;
11185 subtype = p - types + VSNORMAL;
11186 break;
11187 case '%':
11188 case '#':
11189 {
11190 int cc = c;
11191 subtype = c == '#' ? VSTRIMLEFT :
11192 VSTRIMRIGHT;
11193 c = pgetc();
11194 if (c == cc)
11195 subtype++;
11196 else
11197 pungetc();
11198 break;
11199 }
11200 }
11201 } else {
11202 pungetc();
11203 }
11204 if (dblquote || arinest)
11205 flags |= VSQUOTE;
11206 *(stackblock() + typeloc) = subtype | flags;
11207 if (subtype != VSNORMAL) {
11208 varnest++;
11209 if (dblquote) {
11210 dqvarnest++;
11211 }
11212 }
11213 }
11214 goto parsesub_return;
11215}
11216
11217
11218/*
11219 * Called to parse command substitutions. Newstyle is set if the command
11220 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
11221 * list of commands (passed by reference), and savelen is the number of
11222 * characters on the top of the stack which must be preserved.
11223 */
11224
11225parsebackq: {
11226 struct nodelist **nlpp;
11227 int savepbq;
11228 union node *n;
11229 char *volatile str;
11230 struct jmploc jmploc;
11231 struct jmploc *volatile savehandler;
11232 int savelen;
11233 int saveprompt;
11234#ifdef __GNUC__
11235 (void) &saveprompt;
11236#endif
11237
11238 savepbq = parsebackquote;
11239 if (setjmp(jmploc.loc)) {
11240 if (str)
11241 ckfree(str);
11242 parsebackquote = 0;
11243 handler = savehandler;
11244 longjmp(handler->loc, 1);
11245 }
11246 INTOFF;
11247 str = NULL;
11248 savelen = out - stackblock();
11249 if (savelen > 0) {
11250 str = ckmalloc(savelen);
11251 memcpy(str, stackblock(), savelen);
11252 }
11253 savehandler = handler;
11254 handler = &jmploc;
11255 INTON;
Eric Andersen2870d962001-07-02 17:27:21 +000011256 if (oldstyle) {
11257 /* We must read until the closing backquote, giving special
11258 treatment to some slashes, and then push the string and
11259 reread it as input, interpreting it normally. */
11260 char *pout;
11261 int pc;
11262 int psavelen;
11263 char *pstr;
Eric Andersencb57d552001-06-28 07:25:16 +000011264
11265
Eric Andersen2870d962001-07-02 17:27:21 +000011266 STARTSTACKSTR(pout);
Eric Andersencb57d552001-06-28 07:25:16 +000011267 for (;;) {
11268 if (needprompt) {
11269 setprompt(2);
11270 needprompt = 0;
11271 }
11272 switch (pc = pgetc()) {
11273 case '`':
11274 goto done;
11275
11276 case '\\':
Eric Andersen2870d962001-07-02 17:27:21 +000011277 if ((pc = pgetc()) == '\n') {
Eric Andersencb57d552001-06-28 07:25:16 +000011278 plinno++;
11279 if (doprompt)
11280 setprompt(2);
11281 else
11282 setprompt(0);
11283 /*
11284 * If eating a newline, avoid putting
11285 * the newline into the new character
11286 * stream (via the STPUTC after the
11287 * switch).
11288 */
11289 continue;
11290 }
Eric Andersen2870d962001-07-02 17:27:21 +000011291 if (pc != '\\' && pc != '`' && pc != '$'
11292 && (!dblquote || pc != '"'))
11293 STPUTC('\\', pout);
Eric Andersencb57d552001-06-28 07:25:16 +000011294 if (pc > PEOA) {
11295 break;
11296 }
11297 /* fall through */
11298
11299 case PEOF:
Eric Andersen2870d962001-07-02 17:27:21 +000011300#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000011301 case PEOA:
Eric Andersen2870d962001-07-02 17:27:21 +000011302#endif
11303 startlinno = plinno;
Eric Andersencb57d552001-06-28 07:25:16 +000011304 synerror("EOF in backquote substitution");
11305
11306 case '\n':
11307 plinno++;
11308 needprompt = doprompt;
11309 break;
11310
11311 default:
11312 break;
11313 }
11314 STPUTC(pc, pout);
Eric Andersen2870d962001-07-02 17:27:21 +000011315 }
Eric Andersencb57d552001-06-28 07:25:16 +000011316done:
Eric Andersen2870d962001-07-02 17:27:21 +000011317 STPUTC('\0', pout);
11318 psavelen = pout - stackblock();
11319 if (psavelen > 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000011320 pstr = grabstackstr(pout);
11321 setinputstring(pstr);
Eric Andersen2870d962001-07-02 17:27:21 +000011322 }
11323 }
Eric Andersencb57d552001-06-28 07:25:16 +000011324 nlpp = &bqlist;
11325 while (*nlpp)
11326 nlpp = &(*nlpp)->next;
11327 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
11328 (*nlpp)->next = NULL;
11329 parsebackquote = oldstyle;
11330
11331 if (oldstyle) {
11332 saveprompt = doprompt;
11333 doprompt = 0;
11334 }
11335
11336 n = list(0);
11337
11338 if (oldstyle)
11339 doprompt = saveprompt;
11340 else {
11341 if (readtoken() != TRP)
11342 synexpect(TRP);
11343 }
11344
11345 (*nlpp)->n = n;
Eric Andersen2870d962001-07-02 17:27:21 +000011346 if (oldstyle) {
Eric Andersencb57d552001-06-28 07:25:16 +000011347 /*
11348 * Start reading from old file again, ignoring any pushed back
11349 * tokens left from the backquote parsing
11350 */
Eric Andersen2870d962001-07-02 17:27:21 +000011351 popfile();
Eric Andersencb57d552001-06-28 07:25:16 +000011352 tokpushback = 0;
11353 }
11354 while (stackblocksize() <= savelen)
11355 growstackblock();
11356 STARTSTACKSTR(out);
11357 if (str) {
11358 memcpy(out, str, savelen);
11359 STADJUST(savelen, out);
11360 INTOFF;
11361 ckfree(str);
11362 str = NULL;
11363 INTON;
11364 }
11365 parsebackquote = savepbq;
11366 handler = savehandler;
11367 if (arinest || dblquote)
11368 USTPUTC(CTLBACKQ | CTLQUOTE, out);
11369 else
11370 USTPUTC(CTLBACKQ, out);
11371 if (oldstyle)
11372 goto parsebackq_oldreturn;
11373 else
11374 goto parsebackq_newreturn;
11375}
11376
11377/*
11378 * Parse an arithmetic expansion (indicate start of one and set state)
11379 */
11380parsearith: {
11381
11382 if (++arinest == 1) {
11383 prevsyntax = syntax;
11384 syntax = ARISYNTAX;
11385 USTPUTC(CTLARI, out);
11386 if (dblquote)
11387 USTPUTC('"',out);
11388 else
11389 USTPUTC(' ',out);
11390 } else {
11391 /*
11392 * we collapse embedded arithmetic expansion to
11393 * parenthesis, which should be equivalent
11394 */
11395 USTPUTC('(', out);
11396 }
11397 goto parsearith_return;
11398}
11399
11400} /* end of readtoken */
11401
11402
Eric Andersencb57d552001-06-28 07:25:16 +000011403/*
11404 * Returns true if the text contains nothing to expand (no dollar signs
11405 * or backquotes).
11406 */
11407
11408static int
11409noexpand(text)
11410 char *text;
11411 {
11412 char *p;
11413 char c;
11414
11415 p = text;
11416 while ((c = *p++) != '\0') {
11417 if (c == CTLQUOTEMARK)
11418 continue;
11419 if (c == CTLESC)
11420 p++;
11421 else if (BASESYNTAX[(int)c] == CCTL)
11422 return 0;
11423 }
11424 return 1;
11425}
11426
11427
11428/*
11429 * Return true if the argument is a legal variable name (a letter or
11430 * underscore followed by zero or more letters, underscores, and digits).
11431 */
11432
11433static int
Eric Andersen2870d962001-07-02 17:27:21 +000011434goodname(const char *name)
11435{
11436 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +000011437
11438 p = name;
11439 if (! is_name(*p))
11440 return 0;
11441 while (*++p) {
11442 if (! is_in_name(*p))
11443 return 0;
11444 }
11445 return 1;
11446}
11447
11448
11449/*
11450 * Called when an unexpected token is read during the parse. The argument
11451 * is the token that is expected, or -1 if more than one type of token can
11452 * occur at this point.
11453 */
11454
11455static void
11456synexpect(token)
11457 int token;
11458{
11459 char msg[64];
11460
11461 if (token >= 0) {
11462 fmtstr(msg, 64, "%s unexpected (expecting %s)",
11463 tokname[lasttoken], tokname[token]);
11464 } else {
11465 fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]);
11466 }
11467 synerror(msg);
11468 /* NOTREACHED */
11469}
11470
11471
11472static void
Eric Andersen2870d962001-07-02 17:27:21 +000011473synerror(const char *msg)
11474{
Eric Andersencb57d552001-06-28 07:25:16 +000011475 if (commandname)
11476 outfmt(&errout, "%s: %d: ", commandname, startlinno);
11477 outfmt(&errout, "Syntax error: %s\n", msg);
11478 error((char *)NULL);
11479 /* NOTREACHED */
11480}
11481
Eric Andersencb57d552001-06-28 07:25:16 +000011482
11483/*
11484 * called by editline -- any expansions to the prompt
11485 * should be added here.
11486 */
11487static const char *
11488getprompt(void *unused)
Eric Andersen2870d962001-07-02 17:27:21 +000011489{
Eric Andersencb57d552001-06-28 07:25:16 +000011490 switch (whichprompt) {
11491 case 0:
11492 return "";
11493 case 1:
11494 return ps1val();
11495 case 2:
11496 return ps2val();
11497 default:
11498 return "<internal prompt error>";
11499 }
11500}
11501
Eric Andersen2870d962001-07-02 17:27:21 +000011502static void
11503setprompt(int which)
11504{
11505 whichprompt = which;
11506 putprompt(getprompt(NULL));
Eric Andersencb57d552001-06-28 07:25:16 +000011507}
11508
Eric Andersencb57d552001-06-28 07:25:16 +000011509
Eric Andersencb57d552001-06-28 07:25:16 +000011510/*
11511 * Code for dealing with input/output redirection.
11512 */
11513
Eric Andersen2870d962001-07-02 17:27:21 +000011514#define EMPTY -2 /* marks an unused slot in redirtab */
Eric Andersencb57d552001-06-28 07:25:16 +000011515#ifndef PIPE_BUF
Eric Andersen2870d962001-07-02 17:27:21 +000011516# define PIPESIZE 4096 /* amount of buffering in a pipe */
Eric Andersencb57d552001-06-28 07:25:16 +000011517#else
11518# define PIPESIZE PIPE_BUF
11519#endif
11520
11521
Eric Andersencb57d552001-06-28 07:25:16 +000011522
11523/*
11524 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11525 * old file descriptors are stashed away so that the redirection can be
11526 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11527 * standard output, and the standard error if it becomes a duplicate of
11528 * stdout, is saved in memory.
11529 */
11530
11531static void
11532redirect(redir, flags)
11533 union node *redir;
11534 int flags;
11535 {
11536 union node *n;
11537 struct redirtab *sv = NULL;
11538 int i;
11539 int fd;
11540 int newfd;
11541 int try;
Eric Andersen2870d962001-07-02 17:27:21 +000011542 char memory[10]; /* file descriptors to write to memory */
Eric Andersencb57d552001-06-28 07:25:16 +000011543
11544 for (i = 10 ; --i >= 0 ; )
11545 memory[i] = 0;
11546 memory[1] = flags & REDIR_BACKQ;
11547 if (flags & REDIR_PUSH) {
11548 sv = ckmalloc(sizeof (struct redirtab));
11549 for (i = 0 ; i < 10 ; i++)
11550 sv->renamed[i] = EMPTY;
11551 sv->next = redirlist;
11552 redirlist = sv;
11553 }
11554 for (n = redir ; n ; n = n->nfile.next) {
11555 fd = n->nfile.fd;
11556 try = 0;
11557 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
11558 n->ndup.dupfd == fd)
11559 continue; /* redirect from/to same file descriptor */
11560
11561 INTOFF;
11562 newfd = openredirect(n);
11563 if (((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) ||
11564 (fd == fileno2)) {
11565 if (newfd == fd) {
11566 try++;
11567 } else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
11568 switch (errno) {
11569 case EBADF:
11570 if (!try) {
11571 dupredirect(n, newfd, memory);
11572 try++;
11573 break;
11574 }
11575 /* FALLTHROUGH*/
11576 default:
11577 if (newfd >= 0) {
11578 close(newfd);
11579 }
11580 INTON;
Eric Andersen2870d962001-07-02 17:27:21 +000011581 error("%d: %m", fd);
Eric Andersencb57d552001-06-28 07:25:16 +000011582 /* NOTREACHED */
11583 }
11584 }
11585 if (!try) {
11586 close(fd);
11587 if (flags & REDIR_PUSH) {
11588 sv->renamed[fd] = i;
11589 }
11590 if (fd == fileno2) {
11591 fileno2 = i;
11592 }
11593 }
11594 } else if (fd != newfd) {
11595 close(fd);
11596 }
Eric Andersen2870d962001-07-02 17:27:21 +000011597 if (fd == 0)
11598 fd0_redirected++;
Eric Andersencb57d552001-06-28 07:25:16 +000011599 if (!try)
11600 dupredirect(n, newfd, memory);
11601 INTON;
11602 }
11603 if (memory[1])
11604 out1 = &memout;
11605 if (memory[2])
11606 out2 = &memout;
11607}
11608
11609
11610static int
11611openredirect(redir)
11612 union node *redir;
11613 {
11614 char *fname;
11615 int f;
11616
11617 switch (redir->nfile.type) {
11618 case NFROM:
11619 fname = redir->nfile.expfname;
11620 if ((f = open(fname, O_RDONLY)) < 0)
11621 goto eopen;
11622 break;
11623 case NFROMTO:
11624 fname = redir->nfile.expfname;
11625 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
11626 goto ecreate;
11627 break;
11628 case NTO:
11629 /* Take care of noclobber mode. */
11630 if (Cflag) {
11631 fname = redir->nfile.expfname;
11632 if ((f = noclobberopen(fname)) < 0)
11633 goto ecreate;
11634 break;
11635 }
11636 case NTOOV:
11637 fname = redir->nfile.expfname;
11638#ifdef O_CREAT
11639 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
11640 goto ecreate;
11641#else
11642 if ((f = creat(fname, 0666)) < 0)
11643 goto ecreate;
11644#endif
11645 break;
11646 case NAPPEND:
11647 fname = redir->nfile.expfname;
11648#ifdef O_APPEND
11649 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
11650 goto ecreate;
11651#else
11652 if ((f = open(fname, O_WRONLY)) < 0
11653 && (f = creat(fname, 0666)) < 0)
11654 goto ecreate;
11655 lseek(f, (off_t)0, 2);
11656#endif
11657 break;
11658 default:
11659#ifdef DEBUG
11660 abort();
11661#endif
11662 /* Fall through to eliminate warning. */
11663 case NTOFD:
11664 case NFROMFD:
11665 f = -1;
11666 break;
11667 case NHERE:
11668 case NXHERE:
11669 f = openhere(redir);
11670 break;
11671 }
11672
11673 return f;
11674ecreate:
11675 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
11676eopen:
11677 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11678}
11679
11680
11681static void
Eric Andersen2870d962001-07-02 17:27:21 +000011682dupredirect(union node *redir, int f, char memory[10])
11683{
Eric Andersencb57d552001-06-28 07:25:16 +000011684 int fd = redir->nfile.fd;
11685
11686 memory[fd] = 0;
11687 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Eric Andersen2870d962001-07-02 17:27:21 +000011688 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
Eric Andersencb57d552001-06-28 07:25:16 +000011689 if (memory[redir->ndup.dupfd])
11690 memory[fd] = 1;
11691 else
11692 dup_as_newfd(redir->ndup.dupfd, fd);
11693 }
11694 return;
11695 }
11696
11697 if (f != fd) {
11698 dup_as_newfd(f, fd);
11699 close(f);
11700 }
11701 return;
11702}
11703
11704
11705/*
11706 * Handle here documents. Normally we fork off a process to write the
11707 * data to a pipe. If the document is short, we can stuff the data in
11708 * the pipe without forking.
11709 */
11710
11711static int
11712openhere(redir)
11713 union node *redir;
11714 {
11715 int pip[2];
11716 int len = 0;
11717
11718 if (pipe(pip) < 0)
11719 error("Pipe call failed");
11720 if (redir->type == NHERE) {
11721 len = strlen(redir->nhere.doc->narg.text);
11722 if (len <= PIPESIZE) {
11723 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11724 goto out;
11725 }
11726 }
11727 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
11728 close(pip[0]);
11729 signal(SIGINT, SIG_IGN);
11730 signal(SIGQUIT, SIG_IGN);
11731 signal(SIGHUP, SIG_IGN);
11732#ifdef SIGTSTP
11733 signal(SIGTSTP, SIG_IGN);
11734#endif
11735 signal(SIGPIPE, SIG_DFL);
11736 if (redir->type == NHERE)
11737 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11738 else
11739 expandhere(redir->nhere.doc, pip[1]);
11740 _exit(0);
11741 }
11742out:
11743 close(pip[1]);
11744 return pip[0];
11745}
11746
11747
Eric Andersencb57d552001-06-28 07:25:16 +000011748/*
11749 * Undo the effects of the last redirection.
11750 */
11751
11752static void
Eric Andersen2870d962001-07-02 17:27:21 +000011753popredir(void)
11754{
Eric Andersencb57d552001-06-28 07:25:16 +000011755 struct redirtab *rp = redirlist;
11756 int i;
11757
11758 INTOFF;
11759 for (i = 0 ; i < 10 ; i++) {
11760 if (rp->renamed[i] != EMPTY) {
Eric Andersen2870d962001-07-02 17:27:21 +000011761 if (i == 0)
11762 fd0_redirected--;
Eric Andersencb57d552001-06-28 07:25:16 +000011763 close(i);
11764 if (rp->renamed[i] >= 0) {
11765 dup_as_newfd(rp->renamed[i], i);
11766 close(rp->renamed[i]);
11767 }
11768 if (rp->renamed[i] == fileno2) {
11769 fileno2 = i;
11770 }
11771 }
11772 }
11773 redirlist = rp->next;
11774 ckfree(rp);
11775 INTON;
11776}
11777
11778/*
Eric Andersencb57d552001-06-28 07:25:16 +000011779 * Discard all saved file descriptors.
11780 */
11781
11782static void
Eric Andersen2870d962001-07-02 17:27:21 +000011783clearredir(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000011784 struct redirtab *rp;
11785 int i;
11786
11787 for (rp = redirlist ; rp ; rp = rp->next) {
11788 for (i = 0 ; i < 10 ; i++) {
11789 if (rp->renamed[i] >= 0) {
11790 close(rp->renamed[i]);
11791 if (rp->renamed[i] == fileno2) {
11792 fileno2 = -1;
11793 }
11794 }
11795 rp->renamed[i] = EMPTY;
11796 }
11797 }
11798 if (fileno2 != 2 && fileno2 >= 0) {
11799 close(fileno2);
11800 fileno2 = -1;
11801 }
11802}
11803
11804
Eric Andersencb57d552001-06-28 07:25:16 +000011805/*
11806 * Copy a file descriptor to be >= to. Returns -1
11807 * if the source file descriptor is closed, EMPTY if there are no unused
11808 * file descriptors left.
11809 */
11810
11811static int
11812dup_as_newfd(from, to)
11813 int from;
11814 int to;
11815{
11816 int newfd;
11817
11818 newfd = fcntl(from, F_DUPFD, to);
11819 if (newfd < 0) {
11820 if (errno == EMFILE)
11821 return EMPTY;
11822 else
Eric Andersen2870d962001-07-02 17:27:21 +000011823 error("%d: %m", from);
Eric Andersencb57d552001-06-28 07:25:16 +000011824 }
11825 return newfd;
11826}
11827
11828/*
11829 * Open a file in noclobber mode.
11830 * The code was copied from bash.
11831 */
11832static int
Eric Andersen2870d962001-07-02 17:27:21 +000011833noclobberopen(const char *fname)
Eric Andersencb57d552001-06-28 07:25:16 +000011834{
11835 int r, fd;
11836 struct stat finfo, finfo2;
11837
11838 /*
11839 * If the file exists and is a regular file, return an error
11840 * immediately.
11841 */
11842 r = stat(fname, &finfo);
11843 if (r == 0 && S_ISREG(finfo.st_mode)) {
11844 errno = EEXIST;
11845 return -1;
11846 }
11847
11848 /*
11849 * If the file was not present (r != 0), make sure we open it
11850 * exclusively so that if it is created before we open it, our open
11851 * will fail. Make sure that we do not truncate an existing file.
11852 * Note that we don't turn on O_EXCL unless the stat failed -- if the
11853 * file was not a regular file, we leave O_EXCL off.
11854 */
11855 if (r != 0)
11856 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
11857 fd = open(fname, O_WRONLY|O_CREAT, 0666);
11858
11859 /* If the open failed, return the file descriptor right away. */
11860 if (fd < 0)
11861 return fd;
11862
11863 /*
11864 * OK, the open succeeded, but the file may have been changed from a
11865 * non-regular file to a regular file between the stat and the open.
11866 * We are assuming that the O_EXCL open handles the case where FILENAME
11867 * did not exist and is symlinked to an existing file between the stat
11868 * and open.
11869 */
11870
11871 /*
11872 * If we can open it and fstat the file descriptor, and neither check
11873 * revealed that it was a regular file, and the file has not been
11874 * replaced, return the file descriptor.
11875 */
11876 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
11877 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
Eric Andersen2870d962001-07-02 17:27:21 +000011878 return fd;
Eric Andersencb57d552001-06-28 07:25:16 +000011879
11880 /* The file has been replaced. badness. */
11881 close(fd);
11882 errno = EEXIST;
11883 return -1;
11884}
Eric Andersen2870d962001-07-02 17:27:21 +000011885/*#ifdef __weak_alias
Eric Andersencb57d552001-06-28 07:25:16 +000011886__weak_alias(getmode,_getmode)
11887__weak_alias(setmode,_setmode)
Eric Andersen2870d962001-07-02 17:27:21 +000011888#endif*/
Eric Andersencb57d552001-06-28 07:25:16 +000011889
11890#ifdef __GLIBC__
11891#define S_ISTXT __S_ISVTX
11892#endif
11893
Eric Andersen2870d962001-07-02 17:27:21 +000011894#define SET_LEN 6 /* initial # of bitcmd struct to malloc */
11895#define SET_LEN_INCR 4 /* # of bitcmd structs to add as needed */
Eric Andersencb57d552001-06-28 07:25:16 +000011896
11897typedef struct bitcmd {
Eric Andersen2870d962001-07-02 17:27:21 +000011898 char cmd;
11899 char cmd2;
11900 mode_t bits;
Eric Andersencb57d552001-06-28 07:25:16 +000011901} BITCMD;
11902
Eric Andersen2870d962001-07-02 17:27:21 +000011903#define CMD2_CLR 0x01
11904#define CMD2_SET 0x02
11905#define CMD2_GBITS 0x04
11906#define CMD2_OBITS 0x08
11907#define CMD2_UBITS 0x10
Eric Andersencb57d552001-06-28 07:25:16 +000011908
Eric Andersen2870d962001-07-02 17:27:21 +000011909static BITCMD *addcmd (BITCMD *, int, int, int, u_int);
11910static void compress_mode (BITCMD *);
Eric Andersencb57d552001-06-28 07:25:16 +000011911#ifdef SETMODE_DEBUG
Eric Andersen2870d962001-07-02 17:27:21 +000011912static void dumpmode (BITCMD *);
Eric Andersencb57d552001-06-28 07:25:16 +000011913#endif
11914
11915/*
11916 * Given the old mode and an array of bitcmd structures, apply the operations
11917 * described in the bitcmd structures to the old mode, and return the new mode.
11918 * Note that there is no '=' command; a strict assignment is just a '-' (clear
11919 * bits) followed by a '+' (set bits).
11920 */
Eric Andersen2870d962001-07-02 17:27:21 +000011921static mode_t
Eric Andersencb57d552001-06-28 07:25:16 +000011922getmode(bbox, omode)
11923 const void *bbox;
11924 mode_t omode;
11925{
11926 const BITCMD *set;
11927 mode_t clrval, newmode, value;
11928
11929 _DIAGASSERT(bbox != NULL);
11930
11931 set = (const BITCMD *)bbox;
11932 newmode = omode;
11933 for (value = 0;; set++)
11934 switch(set->cmd) {
11935 /*
11936 * When copying the user, group or other bits around, we "know"
11937 * where the bits are in the mode so that we can do shifts to
11938 * copy them around. If we don't use shifts, it gets real
11939 * grundgy with lots of single bit checks and bit sets.
11940 */
11941 case 'u':
11942 value = (newmode & S_IRWXU) >> 6;
11943 goto common;
11944
11945 case 'g':
11946 value = (newmode & S_IRWXG) >> 3;
11947 goto common;
11948
11949 case 'o':
11950 value = newmode & S_IRWXO;
Eric Andersen2870d962001-07-02 17:27:21 +000011951common: if (set->cmd2 & CMD2_CLR) {
Eric Andersencb57d552001-06-28 07:25:16 +000011952 clrval =
11953 (set->cmd2 & CMD2_SET) ? S_IRWXO : value;
11954 if (set->cmd2 & CMD2_UBITS)
11955 newmode &= ~((clrval<<6) & set->bits);
11956 if (set->cmd2 & CMD2_GBITS)
11957 newmode &= ~((clrval<<3) & set->bits);
11958 if (set->cmd2 & CMD2_OBITS)
11959 newmode &= ~(clrval & set->bits);
11960 }
11961 if (set->cmd2 & CMD2_SET) {
11962 if (set->cmd2 & CMD2_UBITS)
11963 newmode |= (value<<6) & set->bits;
11964 if (set->cmd2 & CMD2_GBITS)
11965 newmode |= (value<<3) & set->bits;
11966 if (set->cmd2 & CMD2_OBITS)
11967 newmode |= value & set->bits;
11968 }
11969 break;
11970
11971 case '+':
11972 newmode |= set->bits;
11973 break;
11974
11975 case '-':
11976 newmode &= ~set->bits;
11977 break;
11978
11979 case 'X':
11980 if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH))
11981 newmode |= set->bits;
11982 break;
11983
11984 case '\0':
11985 default:
11986#ifdef SETMODE_DEBUG
11987 (void)printf("getmode:%04o -> %04o\n", omode, newmode);
11988#endif
11989 return (newmode);
11990 }
11991}
11992
Eric Andersen2870d962001-07-02 17:27:21 +000011993#define ADDCMD(a, b, c, d) do { \
11994 if (set >= endset) { \
11995 BITCMD *newset; \
11996 setlen += SET_LEN_INCR; \
11997 newset = realloc(saveset, sizeof(BITCMD) * setlen); \
11998 if (newset == NULL) { \
11999 free(saveset); \
12000 return (NULL); \
12001 } \
12002 set = newset + (set - saveset); \
12003 saveset = newset; \
12004 endset = newset + (setlen - 2); \
12005 } \
12006 set = addcmd(set, (a), (b), (c), (d)); \
Eric Andersencb57d552001-06-28 07:25:16 +000012007} while (/*CONSTCOND*/0)
12008
Eric Andersen2870d962001-07-02 17:27:21 +000012009#define STANDARD_BITS (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
Eric Andersencb57d552001-06-28 07:25:16 +000012010
12011static void *
12012setmode(p)
12013 const char *p;
12014{
12015 int perm, who;
12016 char op, *ep;
12017 BITCMD *set, *saveset, *endset;
12018 sigset_t mysigset, sigoset;
12019 mode_t mask;
Eric Andersen2870d962001-07-02 17:27:21 +000012020 int equalopdone = 0; /* pacify gcc */
Eric Andersencb57d552001-06-28 07:25:16 +000012021 int permXbits, setlen;
12022
12023 if (!*p)
12024 return (NULL);
12025
12026 /*
12027 * Get a copy of the mask for the permissions that are mask relative.
12028 * Flip the bits, we want what's not set. Since it's possible that
12029 * the caller is opening files inside a signal handler, protect them
12030 * as best we can.
12031 */
12032 sigfillset(&mysigset);
12033 (void)sigprocmask(SIG_BLOCK, &mysigset, &sigoset);
12034 (void)umask(mask = umask(0));
12035 mask = ~mask;
12036 (void)sigprocmask(SIG_SETMASK, &sigoset, NULL);
12037
12038 setlen = SET_LEN + 2;
Eric Andersen2870d962001-07-02 17:27:21 +000012039
Eric Andersencb57d552001-06-28 07:25:16 +000012040 if ((set = malloc((u_int)(sizeof(BITCMD) * setlen))) == NULL)
12041 return (NULL);
12042 saveset = set;
12043 endset = set + (setlen - 2);
12044
12045 /*
12046 * If an absolute number, get it and return; disallow non-octal digits
12047 * or illegal bits.
12048 */
12049 if (isdigit((unsigned char)*p)) {
12050 perm = (mode_t)strtol(p, &ep, 8);
12051 if (*ep || perm & ~(STANDARD_BITS|S_ISTXT)) {
12052 free(saveset);
12053 return (NULL);
12054 }
12055 ADDCMD('=', (STANDARD_BITS|S_ISTXT), perm, mask);
12056 set->cmd = 0;
12057 return (saveset);
12058 }
12059
12060 /*
12061 * Build list of structures to set/clear/copy bits as described by
12062 * each clause of the symbolic mode.
12063 */
12064 for (;;) {
12065 /* First, find out which bits might be modified. */
12066 for (who = 0;; ++p) {
12067 switch (*p) {
12068 case 'a':
12069 who |= STANDARD_BITS;
12070 break;
12071 case 'u':
12072 who |= S_ISUID|S_IRWXU;
12073 break;
12074 case 'g':
12075 who |= S_ISGID|S_IRWXG;
12076 break;
12077 case 'o':
12078 who |= S_IRWXO;
12079 break;
12080 default:
12081 goto getop;
12082 }
12083 }
12084
Eric Andersen2870d962001-07-02 17:27:21 +000012085getop: if ((op = *p++) != '+' && op != '-' && op != '=') {
Eric Andersencb57d552001-06-28 07:25:16 +000012086 free(saveset);
12087 return (NULL);
12088 }
12089 if (op == '=')
12090 equalopdone = 0;
12091
12092 who &= ~S_ISTXT;
12093 for (perm = 0, permXbits = 0;; ++p) {
12094 switch (*p) {
12095 case 'r':
12096 perm |= S_IRUSR|S_IRGRP|S_IROTH;
12097 break;
12098 case 's':
12099 /*
Eric Andersen2870d962001-07-02 17:27:21 +000012100 * If specific bits where requested and
12101 * only "other" bits ignore set-id.
Eric Andersencb57d552001-06-28 07:25:16 +000012102 */
12103 if (who == 0 || (who & ~S_IRWXO))
12104 perm |= S_ISUID|S_ISGID;
12105 break;
12106 case 't':
12107 /*
Eric Andersen2870d962001-07-02 17:27:21 +000012108 * If specific bits where requested and
12109 * only "other" bits ignore set-id.
Eric Andersencb57d552001-06-28 07:25:16 +000012110 */
12111 if (who == 0 || (who & ~S_IRWXO)) {
12112 who |= S_ISTXT;
12113 perm |= S_ISTXT;
12114 }
12115 break;
12116 case 'w':
12117 perm |= S_IWUSR|S_IWGRP|S_IWOTH;
12118 break;
12119 case 'X':
12120 permXbits = S_IXUSR|S_IXGRP|S_IXOTH;
12121 break;
12122 case 'x':
12123 perm |= S_IXUSR|S_IXGRP|S_IXOTH;
12124 break;
12125 case 'u':
12126 case 'g':
12127 case 'o':
12128 /*
12129 * When ever we hit 'u', 'g', or 'o', we have
12130 * to flush out any partial mode that we have,
12131 * and then do the copying of the mode bits.
12132 */
12133 if (perm) {
12134 ADDCMD(op, who, perm, mask);
12135 perm = 0;
12136 }
12137 if (op == '=')
12138 equalopdone = 1;
12139 if (op == '+' && permXbits) {
12140 ADDCMD('X', who, permXbits, mask);
12141 permXbits = 0;
12142 }
12143 ADDCMD(*p, who, op, mask);
12144 break;
12145
12146 default:
12147 /*
12148 * Add any permissions that we haven't already
12149 * done.
12150 */
12151 if (perm || (op == '=' && !equalopdone)) {
12152 if (op == '=')
12153 equalopdone = 1;
12154 ADDCMD(op, who, perm, mask);
12155 perm = 0;
12156 }
12157 if (permXbits) {
12158 ADDCMD('X', who, permXbits, mask);
12159 permXbits = 0;
12160 }
12161 goto apply;
12162 }
12163 }
12164
Eric Andersen2870d962001-07-02 17:27:21 +000012165apply: if (!*p)
Eric Andersencb57d552001-06-28 07:25:16 +000012166 break;
12167 if (*p != ',')
12168 goto getop;
12169 ++p;
12170 }
12171 set->cmd = 0;
12172#ifdef SETMODE_DEBUG
12173 (void)printf("Before compress_mode()\n");
12174 dumpmode(saveset);
12175#endif
12176 compress_mode(saveset);
12177#ifdef SETMODE_DEBUG
12178 (void)printf("After compress_mode()\n");
12179 dumpmode(saveset);
12180#endif
12181 return (saveset);
12182}
12183
12184static BITCMD *
12185addcmd(set, op, who, oparg, mask)
12186 BITCMD *set;
12187 int oparg, who;
12188 int op;
12189 u_int mask;
12190{
12191
12192 _DIAGASSERT(set != NULL);
12193
12194 switch (op) {
12195 case '=':
12196 set->cmd = '-';
12197 set->bits = who ? who : STANDARD_BITS;
12198 set++;
12199
12200 op = '+';
12201 /* FALLTHROUGH */
12202 case '+':
12203 case '-':
12204 case 'X':
12205 set->cmd = op;
12206 set->bits = (who ? who : mask) & oparg;
12207 break;
12208
12209 case 'u':
12210 case 'g':
12211 case 'o':
12212 set->cmd = op;
12213 if (who) {
12214 set->cmd2 = ((who & S_IRUSR) ? CMD2_UBITS : 0) |
12215 ((who & S_IRGRP) ? CMD2_GBITS : 0) |
12216 ((who & S_IROTH) ? CMD2_OBITS : 0);
12217 set->bits = (mode_t)~0;
12218 } else {
12219 set->cmd2 = CMD2_UBITS | CMD2_GBITS | CMD2_OBITS;
12220 set->bits = mask;
12221 }
Eric Andersen2870d962001-07-02 17:27:21 +000012222
Eric Andersencb57d552001-06-28 07:25:16 +000012223 if (oparg == '+')
12224 set->cmd2 |= CMD2_SET;
12225 else if (oparg == '-')
12226 set->cmd2 |= CMD2_CLR;
12227 else if (oparg == '=')
12228 set->cmd2 |= CMD2_SET|CMD2_CLR;
12229 break;
12230 }
12231 return (set + 1);
12232}
12233
12234#ifdef SETMODE_DEBUG
12235static void
12236dumpmode(set)
12237 BITCMD *set;
12238{
12239
12240 _DIAGASSERT(set != NULL);
12241
12242 for (; set->cmd; ++set)
12243 (void)printf("cmd: '%c' bits %04o%s%s%s%s%s%s\n",
12244 set->cmd, set->bits, set->cmd2 ? " cmd2:" : "",
12245 set->cmd2 & CMD2_CLR ? " CLR" : "",
12246 set->cmd2 & CMD2_SET ? " SET" : "",
12247 set->cmd2 & CMD2_UBITS ? " UBITS" : "",
12248 set->cmd2 & CMD2_GBITS ? " GBITS" : "",
12249 set->cmd2 & CMD2_OBITS ? " OBITS" : "");
12250}
12251#endif
12252
12253/*
12254 * Given an array of bitcmd structures, compress by compacting consecutive
12255 * '+', '-' and 'X' commands into at most 3 commands, one of each. The 'u',
Eric Andersen2870d962001-07-02 17:27:21 +000012256 * 'g' and 'o' commands continue to be separate. They could probably be
Eric Andersencb57d552001-06-28 07:25:16 +000012257 * compacted, but it's not worth the effort.
12258 */
12259static void
12260compress_mode(set)
12261 BITCMD *set;
12262{
12263 BITCMD *nset;
12264 int setbits, clrbits, Xbits, op;
12265
12266 _DIAGASSERT(set != NULL);
12267
12268 for (nset = set;;) {
12269 /* Copy over any 'u', 'g' and 'o' commands. */
12270 while ((op = nset->cmd) != '+' && op != '-' && op != 'X') {
12271 *set++ = *nset++;
12272 if (!op)
12273 return;
12274 }
12275
12276 for (setbits = clrbits = Xbits = 0;; nset++) {
12277 if ((op = nset->cmd) == '-') {
12278 clrbits |= nset->bits;
12279 setbits &= ~nset->bits;
12280 Xbits &= ~nset->bits;
12281 } else if (op == '+') {
12282 setbits |= nset->bits;
12283 clrbits &= ~nset->bits;
12284 Xbits &= ~nset->bits;
12285 } else if (op == 'X')
12286 Xbits |= nset->bits & ~setbits;
12287 else
12288 break;
12289 }
12290 if (clrbits) {
12291 set->cmd = '-';
12292 set->cmd2 = 0;
12293 set->bits = clrbits;
12294 set++;
12295 }
12296 if (setbits) {
12297 set->cmd = '+';
12298 set->cmd2 = 0;
12299 set->bits = setbits;
12300 set++;
12301 }
12302 if (Xbits) {
12303 set->cmd = 'X';
12304 set->cmd2 = 0;
12305 set->bits = Xbits;
12306 set++;
12307 }
12308 }
12309}
Eric Andersencb57d552001-06-28 07:25:16 +000012310#ifdef DEBUG
Eric Andersen2870d962001-07-02 17:27:21 +000012311static void shtree (union node *, int, char *, FILE*);
12312static void shcmd (union node *, FILE *);
12313static void sharg (union node *, FILE *);
12314static void indent (int, char *, FILE *);
12315static void trstring (char *);
Eric Andersencb57d552001-06-28 07:25:16 +000012316
12317
12318static void
12319showtree(n)
12320 union node *n;
12321{
12322 trputs("showtree called\n");
12323 shtree(n, 1, NULL, stdout);
12324}
12325
12326
12327static void
12328shtree(n, ind, pfx, fp)
12329 union node *n;
12330 int ind;
12331 char *pfx;
12332 FILE *fp;
12333{
12334 struct nodelist *lp;
12335 const char *s;
12336
12337 if (n == NULL)
12338 return;
12339
12340 indent(ind, pfx, fp);
12341 switch(n->type) {
12342 case NSEMI:
12343 s = "; ";
12344 goto binop;
12345 case NAND:
12346 s = " && ";
12347 goto binop;
12348 case NOR:
12349 s = " || ";
12350binop:
12351 shtree(n->nbinary.ch1, ind, NULL, fp);
12352 /* if (ind < 0) */
12353 fputs(s, fp);
12354 shtree(n->nbinary.ch2, ind, NULL, fp);
12355 break;
12356 case NCMD:
12357 shcmd(n, fp);
12358 if (ind >= 0)
12359 putc('\n', fp);
12360 break;
12361 case NPIPE:
12362 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
12363 shcmd(lp->n, fp);
12364 if (lp->next)
12365 fputs(" | ", fp);
12366 }
12367 if (n->npipe.backgnd)
12368 fputs(" &", fp);
12369 if (ind >= 0)
12370 putc('\n', fp);
12371 break;
12372 default:
12373 fprintf(fp, "<node type %d>", n->type);
12374 if (ind >= 0)
12375 putc('\n', fp);
12376 break;
12377 }
12378}
12379
12380
12381
12382static void
12383shcmd(cmd, fp)
12384 union node *cmd;
12385 FILE *fp;
12386{
12387 union node *np;
12388 int first;
12389 const char *s;
12390 int dftfd;
12391
12392 first = 1;
12393 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
12394 if (! first)
12395 putchar(' ');
12396 sharg(np, fp);
12397 first = 0;
12398 }
12399 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
12400 if (! first)
12401 putchar(' ');
12402 switch (np->nfile.type) {
Eric Andersen2870d962001-07-02 17:27:21 +000012403 case NTO: s = ">"; dftfd = 1; break;
12404 case NAPPEND: s = ">>"; dftfd = 1; break;
12405 case NTOFD: s = ">&"; dftfd = 1; break;
12406 case NTOOV: s = ">|"; dftfd = 1; break;
12407 case NFROM: s = "<"; dftfd = 0; break;
12408 case NFROMFD: s = "<&"; dftfd = 0; break;
12409 case NFROMTO: s = "<>"; dftfd = 0; break;
12410 default: s = "*error*"; dftfd = 0; break;
Eric Andersencb57d552001-06-28 07:25:16 +000012411 }
12412 if (np->nfile.fd != dftfd)
12413 fprintf(fp, "%d", np->nfile.fd);
12414 fputs(s, fp);
12415 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
12416 fprintf(fp, "%d", np->ndup.dupfd);
12417 } else {
12418 sharg(np->nfile.fname, fp);
12419 }
12420 first = 0;
12421 }
12422}
12423
12424
12425
12426static void
12427sharg(arg, fp)
12428 union node *arg;
12429 FILE *fp;
12430 {
12431 char *p;
12432 struct nodelist *bqlist;
12433 int subtype;
12434
12435 if (arg->type != NARG) {
12436 printf("<node type %d>\n", arg->type);
12437 fflush(stdout);
12438 abort();
12439 }
12440 bqlist = arg->narg.backquote;
12441 for (p = arg->narg.text ; *p ; p++) {
12442 switch (*p) {
12443 case CTLESC:
12444 putc(*++p, fp);
12445 break;
12446 case CTLVAR:
12447 putc('$', fp);
12448 putc('{', fp);
12449 subtype = *++p;
12450 if (subtype == VSLENGTH)
12451 putc('#', fp);
12452
12453 while (*p != '=')
12454 putc(*p++, fp);
12455
12456 if (subtype & VSNUL)
12457 putc(':', fp);
12458
12459 switch (subtype & VSTYPE) {
12460 case VSNORMAL:
12461 putc('}', fp);
12462 break;
12463 case VSMINUS:
12464 putc('-', fp);
12465 break;
12466 case VSPLUS:
12467 putc('+', fp);
12468 break;
12469 case VSQUESTION:
12470 putc('?', fp);
12471 break;
12472 case VSASSIGN:
12473 putc('=', fp);
12474 break;
12475 case VSTRIMLEFT:
12476 putc('#', fp);
12477 break;
12478 case VSTRIMLEFTMAX:
12479 putc('#', fp);
12480 putc('#', fp);
12481 break;
12482 case VSTRIMRIGHT:
12483 putc('%', fp);
12484 break;
12485 case VSTRIMRIGHTMAX:
12486 putc('%', fp);
12487 putc('%', fp);
12488 break;
12489 case VSLENGTH:
12490 break;
12491 default:
12492 printf("<subtype %d>", subtype);
12493 }
12494 break;
12495 case CTLENDVAR:
12496 putc('}', fp);
12497 break;
12498 case CTLBACKQ:
12499 case CTLBACKQ|CTLQUOTE:
12500 putc('$', fp);
12501 putc('(', fp);
12502 shtree(bqlist->n, -1, NULL, fp);
12503 putc(')', fp);
12504 break;
12505 default:
12506 putc(*p, fp);
12507 break;
12508 }
12509 }
12510}
12511
12512
12513static void
12514indent(amount, pfx, fp)
12515 int amount;
12516 char *pfx;
12517 FILE *fp;
12518{
12519 int i;
12520
12521 for (i = 0 ; i < amount ; i++) {
12522 if (pfx && i == amount - 1)
12523 fputs(pfx, fp);
12524 putc('\t', fp);
12525 }
12526}
12527#endif
12528
12529
12530
12531/*
12532 * Debugging stuff.
12533 */
12534
12535
12536#ifdef DEBUG
12537FILE *tracefile;
12538
12539#if DEBUG == 2
12540static int debug = 1;
12541#else
12542static int debug = 0;
12543#endif
12544
12545
12546static void
12547trputc(c)
12548 int c;
12549{
12550 if (tracefile == NULL)
12551 return;
12552 putc(c, tracefile);
12553 if (c == '\n')
12554 fflush(tracefile);
12555}
12556
12557static void
12558trace(const char *fmt, ...)
12559{
12560 va_list va;
12561#ifdef __STDC__
12562 va_start(va, fmt);
12563#else
12564 char *fmt;
12565 va_start(va);
12566 fmt = va_arg(va, char *);
12567#endif
12568 if (tracefile != NULL) {
12569 (void) vfprintf(tracefile, fmt, va);
12570 if (strchr(fmt, '\n'))
12571 (void) fflush(tracefile);
12572 }
12573 va_end(va);
12574}
12575
12576
12577static void
12578trputs(s)
12579 const char *s;
12580{
12581 if (tracefile == NULL)
12582 return;
12583 fputs(s, tracefile);
12584 if (strchr(s, '\n'))
12585 fflush(tracefile);
12586}
12587
12588
12589static void
12590trstring(s)
12591 char *s;
12592{
12593 char *p;
12594 char c;
12595
12596 if (tracefile == NULL)
12597 return;
12598 putc('"', tracefile);
12599 for (p = s ; *p ; p++) {
12600 switch (*p) {
12601 case '\n': c = 'n'; goto backslash;
12602 case '\t': c = 't'; goto backslash;
12603 case '\r': c = 'r'; goto backslash;
12604 case '"': c = '"'; goto backslash;
12605 case '\\': c = '\\'; goto backslash;
12606 case CTLESC: c = 'e'; goto backslash;
12607 case CTLVAR: c = 'v'; goto backslash;
12608 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
12609 case CTLBACKQ: c = 'q'; goto backslash;
12610 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
Eric Andersen2870d962001-07-02 17:27:21 +000012611backslash: putc('\\', tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000012612 putc(c, tracefile);
12613 break;
12614 default:
12615 if (*p >= ' ' && *p <= '~')
12616 putc(*p, tracefile);
12617 else {
12618 putc('\\', tracefile);
12619 putc(*p >> 6 & 03, tracefile);
12620 putc(*p >> 3 & 07, tracefile);
12621 putc(*p & 07, tracefile);
12622 }
12623 break;
12624 }
12625 }
12626 putc('"', tracefile);
12627}
12628
12629
12630static void
12631trargs(ap)
12632 char **ap;
12633{
12634 if (tracefile == NULL)
12635 return;
12636 while (*ap) {
12637 trstring(*ap++);
12638 if (*ap)
12639 putc(' ', tracefile);
12640 else
12641 putc('\n', tracefile);
12642 }
12643 fflush(tracefile);
12644}
12645
12646
12647static void
12648opentrace() {
12649 char s[100];
12650#ifdef O_APPEND
12651 int flags;
12652#endif
12653
12654 if (!debug)
12655 return;
12656#ifdef not_this_way
12657 {
12658 char *p;
12659 if ((p = getenv("HOME")) == NULL) {
12660 if (geteuid() == 0)
12661 p = "/";
12662 else
12663 p = "/tmp";
12664 }
Eric Andersen2870d962001-07-02 17:27:21 +000012665 strcpy(s, p);
Eric Andersencb57d552001-06-28 07:25:16 +000012666 strcat(s, "/trace");
12667 }
12668#else
Eric Andersen2870d962001-07-02 17:27:21 +000012669 strcpy(s, "./trace");
Eric Andersencb57d552001-06-28 07:25:16 +000012670#endif /* not_this_way */
12671 if ((tracefile = fopen(s, "a")) == NULL) {
12672 fprintf(stderr, "Can't open %s\n", s);
12673 return;
12674 }
12675#ifdef O_APPEND
12676 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
12677 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
12678#endif
12679 fputs("\nTracing started.\n", tracefile);
12680 fflush(tracefile);
12681}
12682#endif /* DEBUG */
12683
12684
12685/*
Eric Andersencb57d552001-06-28 07:25:16 +000012686 * The trap builtin.
12687 */
12688
12689static int
12690trapcmd(argc, argv)
12691 int argc;
12692 char **argv;
12693{
12694 char *action;
12695 char **ap;
12696 int signo;
12697
12698 if (argc <= 1) {
12699 for (signo = 0 ; signo < NSIG ; signo++) {
12700 if (trap[signo] != NULL) {
12701 char *p;
12702
12703 p = single_quote(trap[signo]);
12704 out1fmt("trap -- %s %s\n", p,
12705 signal_names[signo] + (signo ? 3 : 0)
12706 );
12707 stunalloc(p);
12708 }
12709 }
12710 return 0;
12711 }
12712 ap = argv + 1;
12713 if (argc == 2)
12714 action = NULL;
12715 else
12716 action = *ap++;
12717 while (*ap) {
12718 if ((signo = decode_signal(*ap, 0)) < 0)
12719 error("%s: bad trap", *ap);
12720 INTOFF;
12721 if (action) {
12722 if (action[0] == '-' && action[1] == '\0')
12723 action = NULL;
12724 else
12725 action = savestr(action);
12726 }
12727 if (trap[signo])
12728 ckfree(trap[signo]);
12729 trap[signo] = action;
12730 if (signo != 0)
12731 setsignal(signo);
12732 INTON;
12733 ap++;
12734 }
12735 return 0;
12736}
12737
12738
12739
Eric Andersencb57d552001-06-28 07:25:16 +000012740
12741
12742
12743/*
12744 * Set the signal handler for the specified signal. The routine figures
12745 * out what it should be set to.
12746 */
12747
12748static void
Eric Andersen2870d962001-07-02 17:27:21 +000012749setsignal(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000012750{
12751 int action;
12752 char *t;
12753 struct sigaction act;
12754
12755 if ((t = trap[signo]) == NULL)
12756 action = S_DFL;
12757 else if (*t != '\0')
12758 action = S_CATCH;
12759 else
12760 action = S_IGN;
12761 if (rootshell && action == S_DFL) {
12762 switch (signo) {
12763 case SIGINT:
12764 if (iflag || minusc || sflag == 0)
12765 action = S_CATCH;
12766 break;
12767 case SIGQUIT:
12768#ifdef DEBUG
12769 {
Eric Andersencb57d552001-06-28 07:25:16 +000012770
12771 if (debug)
12772 break;
12773 }
12774#endif
12775 /* FALLTHROUGH */
12776 case SIGTERM:
12777 if (iflag)
12778 action = S_IGN;
12779 break;
Eric Andersen2870d962001-07-02 17:27:21 +000012780#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000012781 case SIGTSTP:
12782 case SIGTTOU:
12783 if (mflag)
12784 action = S_IGN;
12785 break;
12786#endif
12787 }
12788 }
12789
12790 t = &sigmode[signo - 1];
12791 if (*t == 0) {
12792 /*
12793 * current setting unknown
12794 */
12795 if (sigaction(signo, 0, &act) == -1) {
12796 /*
12797 * Pretend it worked; maybe we should give a warning
12798 * here, but other shells don't. We don't alter
12799 * sigmode, so that we retry every time.
12800 */
12801 return;
12802 }
12803 if (act.sa_handler == SIG_IGN) {
12804 if (mflag && (signo == SIGTSTP ||
12805 signo == SIGTTIN || signo == SIGTTOU)) {
Eric Andersen2870d962001-07-02 17:27:21 +000012806 *t = S_IGN; /* don't hard ignore these */
Eric Andersencb57d552001-06-28 07:25:16 +000012807 } else
12808 *t = S_HARD_IGN;
12809 } else {
Eric Andersen2870d962001-07-02 17:27:21 +000012810 *t = S_RESET; /* force to be set */
Eric Andersencb57d552001-06-28 07:25:16 +000012811 }
12812 }
12813 if (*t == S_HARD_IGN || *t == action)
12814 return;
12815 switch (action) {
12816 case S_CATCH:
12817 act.sa_handler = onsig;
12818 break;
12819 case S_IGN:
12820 act.sa_handler = SIG_IGN;
12821 break;
12822 default:
12823 act.sa_handler = SIG_DFL;
12824 }
12825 *t = action;
12826 act.sa_flags = 0;
12827 sigemptyset(&act.sa_mask);
12828 sigaction(signo, &act, 0);
12829}
12830
12831/*
12832 * Ignore a signal.
12833 */
12834
12835static void
12836ignoresig(signo)
12837 int signo;
12838{
12839 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
12840 signal(signo, SIG_IGN);
12841 }
12842 sigmode[signo - 1] = S_HARD_IGN;
12843}
12844
12845
Eric Andersencb57d552001-06-28 07:25:16 +000012846/*
12847 * Signal handler.
12848 */
12849
12850static void
Eric Andersen2870d962001-07-02 17:27:21 +000012851onsig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000012852{
12853 if (signo == SIGINT && trap[SIGINT] == NULL) {
12854 onint();
12855 return;
12856 }
12857 gotsig[signo - 1] = 1;
12858 pendingsigs++;
12859}
12860
12861
Eric Andersencb57d552001-06-28 07:25:16 +000012862/*
12863 * Called to execute a trap. Perhaps we should avoid entering new trap
12864 * handlers while we are executing a trap handler.
12865 */
12866
12867static void
Eric Andersen2870d962001-07-02 17:27:21 +000012868dotrap(void)
12869{
Eric Andersencb57d552001-06-28 07:25:16 +000012870 int i;
12871 int savestatus;
12872
12873 for (;;) {
12874 for (i = 1 ; ; i++) {
12875 if (gotsig[i - 1])
12876 break;
12877 if (i >= NSIG - 1)
12878 goto done;
12879 }
12880 gotsig[i - 1] = 0;
12881 savestatus=exitstatus;
12882 evalstring(trap[i], 0);
12883 exitstatus=savestatus;
12884 }
12885done:
12886 pendingsigs = 0;
12887}
12888
Eric Andersencb57d552001-06-28 07:25:16 +000012889/*
12890 * Called to exit the shell.
12891 */
12892
12893static void
Eric Andersen2870d962001-07-02 17:27:21 +000012894exitshell(int status)
Eric Andersencb57d552001-06-28 07:25:16 +000012895{
12896 struct jmploc loc1, loc2;
12897 char *p;
12898
12899 TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
12900 if (setjmp(loc1.loc)) {
12901 goto l1;
12902 }
12903 if (setjmp(loc2.loc)) {
12904 goto l2;
12905 }
12906 handler = &loc1;
12907 if ((p = trap[0]) != NULL && *p != '\0') {
12908 trap[0] = NULL;
12909 evalstring(p, 0);
12910 }
Eric Andersen2870d962001-07-02 17:27:21 +000012911l1: handler = &loc2; /* probably unnecessary */
Eric Andersencb57d552001-06-28 07:25:16 +000012912 flushall();
Eric Andersen2870d962001-07-02 17:27:21 +000012913#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000012914 setjobctl(0);
12915#endif
12916l2: _exit(status);
12917 /* NOTREACHED */
12918}
12919
12920static int decode_signal(const char *string, int minsig)
12921{
12922 int signo;
12923
Eric Andersen2870d962001-07-02 17:27:21 +000012924 if (is_number(string, &signo)) {
Eric Andersencb57d552001-06-28 07:25:16 +000012925 if (signo >= NSIG) {
12926 return -1;
12927 }
12928 return signo;
12929 }
12930
12931 signo = minsig;
12932 if (!signo) {
12933 goto zero;
12934 }
12935 for (; signo < NSIG; signo++) {
12936 if (!strcasecmp(string, &(signal_names[signo])[3])) {
12937 return signo;
12938 }
12939zero:
12940 if (!strcasecmp(string, signal_names[signo])) {
12941 return signo;
12942 }
12943 }
12944
12945 return -1;
12946}
Eric Andersen2870d962001-07-02 17:27:21 +000012947static struct var **hashvar (const char *);
12948static void showvars (const char *, int, int);
12949static struct var **findvar (struct var **, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +000012950
12951/*
12952 * Initialize the varable symbol tables and import the environment
12953 */
12954
Eric Andersencb57d552001-06-28 07:25:16 +000012955/*
12956 * This routine initializes the builtin variables. It is called when the
12957 * shell is initialized and again when a shell procedure is spawned.
12958 */
12959
12960static void
12961initvar() {
12962 const struct varinit *ip;
12963 struct var *vp;
12964 struct var **vpp;
12965
12966 for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
12967 if ((vp->flags & VEXPORT) == 0) {
12968 vpp = hashvar(ip->text);
12969 vp->next = *vpp;
12970 *vpp = vp;
12971 vp->text = strdup(ip->text);
12972 vp->flags = ip->flags;
12973 vp->func = ip->func;
12974 }
12975 }
12976 /*
12977 * PS1 depends on uid
12978 */
12979 if ((vps1.flags & VEXPORT) == 0) {
12980 vpp = hashvar("PS1=");
12981 vps1.next = *vpp;
12982 *vpp = &vps1;
12983 vps1.text = strdup(geteuid() ? "PS1=$ " : "PS1=# ");
12984 vps1.flags = VSTRFIXED|VTEXTFIXED;
12985 }
12986}
12987
12988/*
12989 * Set the value of a variable. The flags argument is ored with the
12990 * flags of the variable. If val is NULL, the variable is unset.
12991 */
12992
12993static void
12994setvar(name, val, flags)
12995 const char *name, *val;
12996 int flags;
12997{
12998 const char *p;
12999 int len;
13000 int namelen;
13001 char *nameeq;
13002 int isbad;
13003 int vallen = 0;
13004
13005 isbad = 0;
13006 p = name;
13007 if (! is_name(*p))
13008 isbad = 1;
13009 p++;
13010 for (;;) {
13011 if (! is_in_name(*p)) {
13012 if (*p == '\0' || *p == '=')
13013 break;
13014 isbad = 1;
13015 }
13016 p++;
13017 }
13018 namelen = p - name;
13019 if (isbad)
13020 error("%.*s: bad variable name", namelen, name);
Eric Andersen2870d962001-07-02 17:27:21 +000013021 len = namelen + 2; /* 2 is space for '=' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +000013022 if (val == NULL) {
13023 flags |= VUNSET;
13024 } else {
13025 len += vallen = strlen(val);
13026 }
13027 INTOFF;
13028 nameeq = ckmalloc(len);
13029 memcpy(nameeq, name, namelen);
13030 nameeq[namelen] = '=';
13031 if (val) {
13032 memcpy(nameeq + namelen + 1, val, vallen + 1);
13033 } else {
13034 nameeq[namelen + 1] = '\0';
13035 }
13036 setvareq(nameeq, flags);
13037 INTON;
13038}
13039
13040
13041
13042/*
13043 * Same as setvar except that the variable and value are passed in
13044 * the first argument as name=value. Since the first argument will
13045 * be actually stored in the table, it should not be a string that
13046 * will go away.
13047 */
13048
13049static void
13050setvareq(s, flags)
13051 char *s;
13052 int flags;
13053{
13054 struct var *vp, **vpp;
13055
13056 vpp = hashvar(s);
13057 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
13058 if ((vp = *findvar(vpp, s))) {
13059 if (vp->flags & VREADONLY) {
13060 size_t len = strchr(s, '=') - s;
13061 error("%.*s: is read only", len, s);
13062 }
13063 INTOFF;
13064
13065 if (vp->func && (flags & VNOFUNC) == 0)
13066 (*vp->func)(strchr(s, '=') + 1);
13067
13068 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
13069 ckfree(vp->text);
13070
13071 vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
13072 vp->flags |= flags;
13073 vp->text = s;
13074
13075 /*
13076 * We could roll this to a function, to handle it as
13077 * a regular variable function callback, but why bother?
13078 */
13079 if (iflag && (vp == &vmpath || (vp == &vmail && !mpathset())))
13080 chkmail(1);
13081 INTON;
13082 return;
13083 }
13084 /* not found */
13085 vp = ckmalloc(sizeof (*vp));
13086 vp->flags = flags;
13087 vp->text = s;
13088 vp->next = *vpp;
13089 vp->func = NULL;
13090 *vpp = vp;
13091}
13092
13093
13094
13095/*
13096 * Process a linked list of variable assignments.
13097 */
13098
13099static void
13100listsetvar(mylist)
13101 struct strlist *mylist;
13102 {
13103 struct strlist *lp;
13104
13105 INTOFF;
13106 for (lp = mylist ; lp ; lp = lp->next) {
13107 setvareq(savestr(lp->text), 0);
13108 }
13109 INTON;
13110}
13111
13112
13113
13114/*
13115 * Find the value of a variable. Returns NULL if not set.
13116 */
13117
13118static char *
13119lookupvar(name)
13120 const char *name;
13121 {
13122 struct var *v;
13123
13124 if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
13125 return strchr(v->text, '=') + 1;
13126 }
13127 return NULL;
13128}
13129
13130
13131
13132/*
13133 * Search the environment of a builtin command.
13134 */
13135
13136static char *
13137bltinlookup(name)
13138 const char *name;
13139{
13140 struct strlist *sp;
13141
13142 for (sp = cmdenviron ; sp ; sp = sp->next) {
13143 if (varequal(sp->text, name))
13144 return strchr(sp->text, '=') + 1;
13145 }
13146 return lookupvar(name);
13147}
13148
13149
13150
13151/*
13152 * Generate a list of exported variables. This routine is used to construct
13153 * the third argument to execve when executing a program.
13154 */
13155
13156static char **
13157environment() {
13158 int nenv;
13159 struct var **vpp;
13160 struct var *vp;
13161 char **env;
13162 char **ep;
13163
13164 nenv = 0;
13165 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
13166 for (vp = *vpp ; vp ; vp = vp->next)
13167 if (vp->flags & VEXPORT)
13168 nenv++;
13169 }
13170 ep = env = stalloc((nenv + 1) * sizeof *env);
13171 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
13172 for (vp = *vpp ; vp ; vp = vp->next)
13173 if (vp->flags & VEXPORT)
13174 *ep++ = vp->text;
13175 }
13176 *ep = NULL;
13177 return env;
13178}
13179
13180
13181/*
13182 * Called when a shell procedure is invoked to clear out nonexported
13183 * variables. It is also necessary to reallocate variables of with
13184 * VSTACK set since these are currently allocated on the stack.
13185 */
13186
Eric Andersencb57d552001-06-28 07:25:16 +000013187static void
Eric Andersen2870d962001-07-02 17:27:21 +000013188shprocvar(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000013189 struct var **vpp;
13190 struct var *vp, **prev;
13191
13192 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
13193 for (prev = vpp ; (vp = *prev) != NULL ; ) {
13194 if ((vp->flags & VEXPORT) == 0) {
13195 *prev = vp->next;
13196 if ((vp->flags & VTEXTFIXED) == 0)
13197 ckfree(vp->text);
13198 if ((vp->flags & VSTRFIXED) == 0)
13199 ckfree(vp);
13200 } else {
13201 if (vp->flags & VSTACK) {
13202 vp->text = savestr(vp->text);
13203 vp->flags &=~ VSTACK;
13204 }
13205 prev = &vp->next;
13206 }
13207 }
13208 }
13209 initvar();
13210}
13211
13212
13213
13214/*
13215 * Command to list all variables which are set. Currently this command
13216 * is invoked from the set command when the set command is called without
13217 * any variables.
13218 */
13219
13220static int
13221showvarscmd(argc, argv)
13222 int argc;
13223 char **argv;
13224{
13225 showvars(nullstr, VUNSET, VUNSET);
13226 return 0;
13227}
13228
13229
13230
13231/*
13232 * The export and readonly commands.
13233 */
13234
13235static int
13236exportcmd(argc, argv)
13237 int argc;
13238 char **argv;
13239{
13240 struct var *vp;
13241 char *name;
13242 const char *p;
13243 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
13244 int pflag;
13245
13246 listsetvar(cmdenviron);
13247 pflag = (nextopt("p") == 'p');
13248 if (argc > 1 && !pflag) {
13249 while ((name = *argptr++) != NULL) {
13250 if ((p = strchr(name, '=')) != NULL) {
13251 p++;
13252 } else {
13253 if ((vp = *findvar(hashvar(name), name))) {
13254 vp->flags |= flag;
13255 goto found;
13256 }
13257 }
13258 setvar(name, p, flag);
13259found:;
13260 }
13261 } else {
13262 showvars(argv[0], flag, 0);
13263 }
13264 return 0;
13265}
13266
13267
13268/*
13269 * The "local" command.
13270 */
13271
Eric Andersen2870d962001-07-02 17:27:21 +000013272/* funcnest nonzero if we are currently evaluating a function */
13273
Eric Andersencb57d552001-06-28 07:25:16 +000013274static int
13275localcmd(argc, argv)
13276 int argc;
13277 char **argv;
13278{
13279 char *name;
13280
Eric Andersen2870d962001-07-02 17:27:21 +000013281 if (! funcnest)
Eric Andersencb57d552001-06-28 07:25:16 +000013282 error("Not in a function");
13283 while ((name = *argptr++) != NULL) {
13284 mklocal(name);
13285 }
13286 return 0;
13287}
13288
13289
13290/*
13291 * Make a variable a local variable. When a variable is made local, it's
13292 * value and flags are saved in a localvar structure. The saved values
13293 * will be restored when the shell function returns. We handle the name
13294 * "-" as a special case.
13295 */
13296
13297static void
13298mklocal(name)
13299 char *name;
13300 {
13301 struct localvar *lvp;
13302 struct var **vpp;
13303 struct var *vp;
13304
13305 INTOFF;
13306 lvp = ckmalloc(sizeof (struct localvar));
13307 if (name[0] == '-' && name[1] == '\0') {
13308 char *p;
Eric Andersen2870d962001-07-02 17:27:21 +000013309 p = ckmalloc(sizeof optet_vals);
13310 lvp->text = memcpy(p, optet_vals, sizeof optet_vals);
Eric Andersencb57d552001-06-28 07:25:16 +000013311 vp = NULL;
13312 } else {
13313 vpp = hashvar(name);
13314 vp = *findvar(vpp, name);
13315 if (vp == NULL) {
13316 if (strchr(name, '='))
13317 setvareq(savestr(name), VSTRFIXED);
13318 else
13319 setvar(name, NULL, VSTRFIXED);
Eric Andersen2870d962001-07-02 17:27:21 +000013320 vp = *vpp; /* the new variable */
Eric Andersencb57d552001-06-28 07:25:16 +000013321 lvp->text = NULL;
13322 lvp->flags = VUNSET;
13323 } else {
13324 lvp->text = vp->text;
13325 lvp->flags = vp->flags;
13326 vp->flags |= VSTRFIXED|VTEXTFIXED;
13327 if (strchr(name, '='))
13328 setvareq(savestr(name), 0);
13329 }
13330 }
13331 lvp->vp = vp;
13332 lvp->next = localvars;
13333 localvars = lvp;
13334 INTON;
13335}
13336
13337
13338/*
13339 * Called after a function returns.
13340 */
13341
13342static void
13343poplocalvars() {
13344 struct localvar *lvp;
13345 struct var *vp;
13346
13347 while ((lvp = localvars) != NULL) {
13348 localvars = lvp->next;
13349 vp = lvp->vp;
Eric Andersen2870d962001-07-02 17:27:21 +000013350 if (vp == NULL) { /* $- saved */
13351 memcpy(optet_vals, lvp->text, sizeof optet_vals);
Eric Andersencb57d552001-06-28 07:25:16 +000013352 ckfree(lvp->text);
13353 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
13354 (void)unsetvar(vp->text);
13355 } else {
13356 if ((vp->flags & VTEXTFIXED) == 0)
13357 ckfree(vp->text);
13358 vp->flags = lvp->flags;
13359 vp->text = lvp->text;
13360 }
13361 ckfree(lvp);
13362 }
13363}
13364
13365
13366static int
13367setvarcmd(argc, argv)
13368 int argc;
13369 char **argv;
13370{
13371 if (argc <= 2)
13372 return unsetcmd(argc, argv);
13373 else if (argc == 3)
13374 setvar(argv[1], argv[2], 0);
13375 else
13376 error("List assignment not implemented");
13377 return 0;
13378}
13379
13380
13381/*
13382 * The unset builtin command. We unset the function before we unset the
13383 * variable to allow a function to be unset when there is a readonly variable
13384 * with the same name.
13385 */
13386
13387static int
13388unsetcmd(argc, argv)
13389 int argc;
13390 char **argv;
13391{
13392 char **ap;
13393 int i;
13394 int flg_func = 0;
13395 int flg_var = 0;
13396 int ret = 0;
13397
13398 while ((i = nextopt("vf")) != '\0') {
13399 if (i == 'f')
13400 flg_func = 1;
13401 else
13402 flg_var = 1;
13403 }
13404 if (flg_func == 0 && flg_var == 0)
13405 flg_var = 1;
13406
13407 for (ap = argptr; *ap ; ap++) {
13408 if (flg_func)
13409 unsetfunc(*ap);
13410 if (flg_var)
13411 ret |= unsetvar(*ap);
13412 }
13413 return ret;
13414}
13415
13416
13417/*
13418 * Unset the specified variable.
13419 */
13420
13421static int
13422unsetvar(s)
13423 const char *s;
13424 {
13425 struct var **vpp;
13426 struct var *vp;
13427
13428 vpp = findvar(hashvar(s), s);
13429 vp = *vpp;
13430 if (vp) {
13431 if (vp->flags & VREADONLY)
13432 return (1);
13433 INTOFF;
13434 if (*(strchr(vp->text, '=') + 1) != '\0')
13435 setvar(s, nullstr, 0);
13436 vp->flags &= ~VEXPORT;
13437 vp->flags |= VUNSET;
13438 if ((vp->flags & VSTRFIXED) == 0) {
13439 if ((vp->flags & VTEXTFIXED) == 0)
13440 ckfree(vp->text);
13441 *vpp = vp->next;
13442 ckfree(vp);
13443 }
13444 INTON;
13445 return (0);
13446 }
13447
13448 return (0);
13449}
13450
13451
13452
13453/*
13454 * Find the appropriate entry in the hash table from the name.
13455 */
13456
13457static struct var **
13458hashvar(p)
13459 const char *p;
13460 {
13461 unsigned int hashval;
13462
13463 hashval = ((unsigned char) *p) << 4;
13464 while (*p && *p != '=')
13465 hashval += (unsigned char) *p++;
13466 return &vartab[hashval % VTABSIZE];
13467}
13468
13469
13470
13471/*
13472 * Returns true if the two strings specify the same varable. The first
13473 * variable name is terminated by '='; the second may be terminated by
13474 * either '=' or '\0'.
13475 */
13476
13477static int
13478varequal(p, q)
13479 const char *p, *q;
13480 {
13481 while (*p == *q++) {
13482 if (*p++ == '=')
13483 return 1;
13484 }
13485 if (*p == '=' && *(q - 1) == '\0')
13486 return 1;
13487 return 0;
13488}
13489
13490static void
13491showvars(const char *myprefix, int mask, int xor)
13492{
13493 struct var **vpp;
13494 struct var *vp;
13495 const char *sep = myprefix == nullstr ? myprefix : spcstr;
13496
13497 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
13498 for (vp = *vpp ; vp ; vp = vp->next) {
13499 if ((vp->flags & mask) ^ xor) {
13500 char *p;
13501 int len;
13502
13503 p = strchr(vp->text, '=') + 1;
13504 len = p - vp->text;
13505 p = single_quote(p);
13506
13507 out1fmt(
13508 "%s%s%.*s%s\n", myprefix, sep, len,
13509 vp->text, p
13510 );
13511 stunalloc(p);
13512 }
13513 }
13514 }
13515}
13516
13517static struct var **
13518findvar(struct var **vpp, const char *name)
13519{
13520 for (; *vpp; vpp = &(*vpp)->next) {
13521 if (varequal((*vpp)->text, name)) {
13522 break;
13523 }
13524 }
13525 return vpp;
13526}
13527
13528/*
13529 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
13530 * This file contains code for the times builtin.
Eric Andersen8df319b2001-07-05 05:24:12 +000013531 * $Id: ash.c,v 1.5 2001/07/05 05:24:12 andersen Exp $
Eric Andersencb57d552001-06-28 07:25:16 +000013532 */
13533static int timescmd (int argc, char **argv)
13534{
13535 struct tms buf;
13536 long int clk_tck = sysconf(_SC_CLK_TCK);
13537
13538 times(&buf);
13539 printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
13540 (int) (buf.tms_utime / clk_tck / 60),
13541 ((double) buf.tms_utime) / clk_tck,
13542 (int) (buf.tms_stime / clk_tck / 60),
13543 ((double) buf.tms_stime) / clk_tck,
13544 (int) (buf.tms_cutime / clk_tck / 60),
13545 ((double) buf.tms_cutime) / clk_tck,
13546 (int) (buf.tms_cstime / clk_tck / 60),
13547 ((double) buf.tms_cstime) / clk_tck);
13548 return 0;
13549}
13550
Eric Andersendf82f612001-06-28 07:46:40 +000013551
13552/*-
13553 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013554 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013555 *
13556 * This code is derived from software contributed to Berkeley by
13557 * Kenneth Almquist.
13558 *
13559 * Redistribution and use in source and binary forms, with or without
13560 * modification, are permitted provided that the following conditions
13561 * are met:
13562 * 1. Redistributions of source code must retain the above copyright
13563 * notice, this list of conditions and the following disclaimer.
13564 * 2. Redistributions in binary form must reproduce the above copyright
13565 * notice, this list of conditions and the following disclaimer in the
13566 * documentation and/or other materials provided with the distribution.
13567 *
Eric Andersen2870d962001-07-02 17:27:21 +000013568 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
13569 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
Eric Andersendf82f612001-06-28 07:46:40 +000013570 *
13571 * 4. Neither the name of the University nor the names of its contributors
13572 * may be used to endorse or promote products derived from this software
13573 * without specific prior written permission.
13574 *
13575 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13576 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13577 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13578 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13579 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13580 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13581 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13582 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13583 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13584 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13585 * SUCH DAMAGE.
13586 */