blob: 489ccaa95088734a0c267d2807acb8c953a3b975 [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
1641#ifdef ASH_BBAPPS_AS_BUILTINS
1642static int bltincmd (int, char **);
1643#endif
1644static int cdcmd (int, char **);
1645static int breakcmd (int, char **);
1646#ifdef ASH_CMDCMD
1647static int commandcmd (int, char **);
1648#endif
1649static int dotcmd (int, char **);
1650static int evalcmd (int, char **);
1651static int execcmd (int, char **);
1652static int exitcmd (int, char **);
1653static int exportcmd (int, char **);
1654static int histcmd (int, char **);
1655static int hashcmd (int, char **);
1656static int jobscmd (int, char **);
1657static int localcmd (int, char **);
1658#ifdef ASH_PWD
1659static int pwdcmd (int, char **);
1660#endif
1661static int readcmd (int, char **);
1662static int returncmd (int, char **);
1663static int setcmd (int, char **);
1664static int setvarcmd (int, char **);
1665static int shiftcmd (int, char **);
1666static int trapcmd (int, char **);
1667static int umaskcmd (int, char **);
1668#ifdef ASH_ALIAS
1669static int aliascmd (int, char **);
1670static int unaliascmd (int, char **);
1671#endif
1672static int unsetcmd (int, char **);
1673static int waitcmd (int, char **);
1674static int ulimitcmd (int, char **);
1675static int timescmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001676#ifdef ASH_MATH_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00001677static int expcmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001678#endif
1679#ifdef ASH_TYPE
Eric Andersen2870d962001-07-02 17:27:21 +00001680static int typecmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001681#endif
1682#ifdef ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00001683static int getoptscmd (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00001684#endif
1685
Eric Andersen2870d962001-07-02 17:27:21 +00001686#ifndef BB_TRUE_FALSE
1687# ifdef ASH_BBAPPS_AS_BUILTINS
1688static int true_main (int, char **);
1689static int false_main (int, char **);
1690# endif
1691#endif
1692
1693static void setpwd (const char *, int);
1694
1695
1696#define BUILTIN_NOSPEC "0"
1697#define BUILTIN_SPECIAL "1"
1698#define BUILTIN_REGULAR "2"
1699#define BUILTIN_ASSIGN "4"
1700#define BUILTIN_SPEC_ASSG "5"
1701#define BUILTIN_REG_ASSG "6"
1702
1703#define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)
1704#define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)
1705#define IS_BUILTIN_ASSIGN(builtincmd) ((builtincmd)->name[0] & 4)
1706
1707struct builtincmd {
1708 const char *name;
1709 int (*const builtinfunc) (int, char **);
1710 //unsigned flags;
1711};
1712
Eric Andersencb57d552001-06-28 07:25:16 +00001713
1714/* It is CRUCIAL that this listing be kept in ascii order, otherwise
1715 * the binary search in find_builtin() will stop working. If you value
1716 * your kneecaps, you'll be sure to *make sure* that any changes made
1717 * to this array result in the listing remaining in ascii order. You
1718 * have been warned.
1719 */
1720static const struct builtincmd builtincmds[] = {
Eric Andersen2870d962001-07-02 17:27:21 +00001721 { BUILTIN_SPECIAL ".", dotcmd },
1722 { BUILTIN_SPECIAL ":", true_main },
1723#ifdef ASH_ALIAS
1724 { BUILTIN_REG_ASSG "alias", aliascmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001725#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001726#ifdef JOBS
1727 { BUILTIN_REGULAR "bg", bgcmd },
1728#endif
1729 { BUILTIN_SPECIAL "break", breakcmd },
1730#ifdef ASH_BBAPPS_AS_BUILTINS
1731 { BUILTIN_SPECIAL "builtin", bltincmd },
1732#endif
1733 { BUILTIN_REGULAR "cd", cdcmd },
1734#ifdef ASH_BBAPPS_AS_BUILTINS
1735 { BUILTIN_NOSPEC "chdir", cdcmd },
1736#endif
1737#ifdef ASH_CMDCMD
1738 { BUILTIN_REGULAR "command", commandcmd },
1739#endif
1740 { BUILTIN_SPECIAL "continue", breakcmd },
1741 { BUILTIN_SPECIAL "eval", evalcmd },
1742 { BUILTIN_SPECIAL "exec", execcmd },
1743 { BUILTIN_SPECIAL "exit", exitcmd },
1744#ifdef ASH_MATH_SUPPORT
1745 { BUILTIN_NOSPEC "exp", expcmd },
1746#endif
1747 { BUILTIN_SPEC_ASSG "export", exportcmd },
1748#ifdef ASH_BBAPPS_AS_BUILTINS
1749 { BUILTIN_REGULAR "false", false_main },
1750#endif
1751 { BUILTIN_REGULAR "fc", histcmd },
1752#ifdef JOBS
1753 { BUILTIN_REGULAR "fg", fgcmd },
1754#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001755#ifdef ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00001756 { BUILTIN_REGULAR "getopts", getoptscmd },
1757#endif
1758 { BUILTIN_NOSPEC "hash", hashcmd },
1759 { BUILTIN_REGULAR "jobs", jobscmd },
1760#ifdef JOBS
1761 { BUILTIN_REGULAR "kill", killcmd },
1762#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001763#ifdef ASH_MATH_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +00001764 { BUILTIN_NOSPEC "let", expcmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001765#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001766 { BUILTIN_ASSIGN "local", localcmd },
1767#ifdef ASH_PWD
1768 { BUILTIN_NOSPEC "pwd", pwdcmd },
1769#endif
1770 { BUILTIN_REGULAR "read", readcmd },
1771 { BUILTIN_SPEC_ASSG "readonly", exportcmd },
1772 { BUILTIN_SPECIAL "return", returncmd },
1773 { BUILTIN_SPECIAL "set", setcmd },
1774 { BUILTIN_NOSPEC "setvar", setvarcmd },
1775 { BUILTIN_SPECIAL "shift", shiftcmd },
1776 { BUILTIN_SPECIAL "times", timescmd },
1777 { BUILTIN_SPECIAL "trap", trapcmd },
1778#ifdef ASH_BBAPPS_AS_BUILTINS
1779 { BUILTIN_REGULAR "true", true_main },
1780#endif
Eric Andersencb57d552001-06-28 07:25:16 +00001781#ifdef ASH_TYPE
Eric Andersen2870d962001-07-02 17:27:21 +00001782 { BUILTIN_NOSPEC "type", typecmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001783#endif
Eric Andersen2870d962001-07-02 17:27:21 +00001784 { BUILTIN_NOSPEC "ulimit", ulimitcmd },
1785 { BUILTIN_REGULAR "umask", umaskcmd },
1786#ifdef ASH_ALIAS
1787 { BUILTIN_REGULAR "unalias", unaliascmd },
1788#endif
1789 { BUILTIN_SPECIAL "unset", unsetcmd },
1790 { BUILTIN_REGULAR "wait", waitcmd },
Eric Andersencb57d552001-06-28 07:25:16 +00001791};
1792#define NUMBUILTINS (sizeof (builtincmds) / sizeof (struct builtincmd) )
1793
Eric Andersen2870d962001-07-02 17:27:21 +00001794static const struct builtincmd *DOTCMD = &builtincmds[0];
1795static struct builtincmd *BLTINCMD;
1796static struct builtincmd *EXECCMD;
1797static struct builtincmd *EVALCMD;
Eric Andersencb57d552001-06-28 07:25:16 +00001798
Eric Andersen2870d962001-07-02 17:27:21 +00001799/* states */
1800#define JOBSTOPPED 1 /* all procs are stopped */
1801#define JOBDONE 2 /* all procs are completed */
Eric Andersencb57d552001-06-28 07:25:16 +00001802
Eric Andersen2870d962001-07-02 17:27:21 +00001803/*
1804 * A job structure contains information about a job. A job is either a
1805 * single process or a set of processes contained in a pipeline. In the
1806 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
1807 * array of pids.
1808 */
Eric Andersencb57d552001-06-28 07:25:16 +00001809
Eric Andersen2870d962001-07-02 17:27:21 +00001810struct procstat {
1811 pid_t pid; /* process id */
1812 int status; /* status flags (defined above) */
1813 char *cmd; /* text of command being run */
1814};
Eric Andersencb57d552001-06-28 07:25:16 +00001815
Eric Andersen2870d962001-07-02 17:27:21 +00001816
1817static int job_warning; /* user was warned about stopped jobs */
1818
1819#ifdef JOBS
1820static void setjobctl(int enable);
1821#else
1822#define setjobctl(on) /* do nothing */
Eric Andersencb57d552001-06-28 07:25:16 +00001823#endif
1824
Eric Andersen2870d962001-07-02 17:27:21 +00001825
1826struct job {
1827 struct procstat ps0; /* status of process */
1828 struct procstat *ps; /* status or processes when more than one */
1829 short nprocs; /* number of processes */
1830 short pgrp; /* process group of this job */
1831 char state; /* true if job is finished */
1832 char used; /* true if this entry is in used */
1833 char changed; /* true if status has changed */
1834#ifdef JOBS
1835 char jobctl; /* job running under job control */
1836#endif
1837};
1838
1839static struct job *jobtab; /* array of jobs */
1840static int njobs; /* size of array */
1841static int backgndpid = -1; /* pid of last background process */
1842#ifdef JOBS
1843static int initialpgrp; /* pgrp of shell on invocation */
1844static int curjob; /* current job */
1845static int jobctl;
1846#endif
1847static int intreceived;
1848
1849static struct job *makejob (union node *, int);
1850static int forkshell (struct job *, union node *, int);
1851static int waitforjob (struct job *);
1852
1853static int docd (char *, int);
1854static char *getcomponent (void);
1855static void updatepwd (const char *);
1856static void getpwd (void);
1857
1858static char *padvance (const char **, const char *);
1859
1860static char nullstr[1]; /* zero length string */
1861static char *curdir = nullstr; /* current working directory */
1862static char *cdcomppath;
1863
Eric Andersencb57d552001-06-28 07:25:16 +00001864static int
1865cdcmd(argc, argv)
1866 int argc;
1867 char **argv;
1868{
1869 const char *dest;
1870 const char *path;
1871 char *p;
1872 struct stat statb;
1873 int print = 0;
1874
1875 nextopt(nullstr);
1876 if ((dest = *argptr) == NULL && (dest = bltinlookup("HOME")) == NULL)
1877 error("HOME not set");
1878 if (*dest == '\0')
Eric Andersen2870d962001-07-02 17:27:21 +00001879 dest = ".";
Eric Andersencb57d552001-06-28 07:25:16 +00001880 if (dest[0] == '-' && dest[1] == '\0') {
1881 dest = bltinlookup("OLDPWD");
1882 if (!dest || !*dest) {
1883 dest = curdir;
1884 }
1885 print = 1;
1886 if (dest)
Eric Andersen2870d962001-07-02 17:27:21 +00001887 print = 1;
Eric Andersencb57d552001-06-28 07:25:16 +00001888 else
Eric Andersen2870d962001-07-02 17:27:21 +00001889 dest = ".";
Eric Andersencb57d552001-06-28 07:25:16 +00001890 }
1891 if (*dest == '/' || (path = bltinlookup("CDPATH")) == NULL)
1892 path = nullstr;
1893 while ((p = padvance(&path, dest)) != NULL) {
1894 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
1895 if (!print) {
1896 /*
1897 * XXX - rethink
1898 */
1899 if (p[0] == '.' && p[1] == '/' && p[2] != '\0')
1900 p += 2;
1901 print = strcmp(p, dest);
1902 }
1903 if (docd(p, print) >= 0)
1904 return 0;
1905
1906 }
1907 }
1908 error("can't cd to %s", dest);
1909 /* NOTREACHED */
1910}
1911
1912
1913/*
1914 * Actually do the chdir. In an interactive shell, print the
1915 * directory name if "print" is nonzero.
1916 */
1917
1918static int
1919docd(dest, print)
1920 char *dest;
1921 int print;
1922{
1923 char *p;
1924 char *q;
1925 char *component;
1926 struct stat statb;
1927 int first;
1928 int badstat;
1929
1930 TRACE(("docd(\"%s\", %d) called\n", dest, print));
1931
1932 /*
1933 * Check each component of the path. If we find a symlink or
1934 * something we can't stat, clear curdir to force a getcwd()
1935 * next time we get the value of the current directory.
1936 */
1937 badstat = 0;
1938 cdcomppath = sstrdup(dest);
1939 STARTSTACKSTR(p);
1940 if (*dest == '/') {
1941 STPUTC('/', p);
1942 cdcomppath++;
1943 }
1944 first = 1;
1945 while ((q = getcomponent()) != NULL) {
1946 if (q[0] == '\0' || (q[0] == '.' && q[1] == '\0'))
1947 continue;
1948 if (! first)
1949 STPUTC('/', p);
1950 first = 0;
1951 component = q;
1952 while (*q)
1953 STPUTC(*q++, p);
1954 if (equal(component, ".."))
1955 continue;
1956 STACKSTRNUL(p);
1957 if ((lstat(stackblock(), &statb) < 0)
1958 || (S_ISLNK(statb.st_mode))) {
1959 /* print = 1; */
1960 badstat = 1;
1961 break;
1962 }
1963 }
1964
1965 INTOFF;
1966 if (chdir(dest) < 0) {
1967 INTON;
1968 return -1;
1969 }
1970 updatepwd(badstat ? NULL : dest);
1971 INTON;
1972 if (print && iflag)
1973 out1fmt(snlfmt, curdir);
1974 return 0;
1975}
1976
1977
1978/*
1979 * Get the next component of the path name pointed to by cdcomppath.
1980 * This routine overwrites the string pointed to by cdcomppath.
1981 */
1982
1983static char *
1984getcomponent() {
1985 char *p;
1986 char *start;
1987
1988 if ((p = cdcomppath) == NULL)
1989 return NULL;
1990 start = cdcomppath;
1991 while (*p != '/' && *p != '\0')
1992 p++;
1993 if (*p == '\0') {
1994 cdcomppath = NULL;
1995 } else {
1996 *p++ = '\0';
1997 cdcomppath = p;
1998 }
1999 return start;
2000}
2001
2002
2003
2004/*
2005 * Update curdir (the name of the current directory) in response to a
2006 * cd command. We also call hashcd to let the routines in exec.c know
2007 * that the current directory has changed.
2008 */
2009
Eric Andersen2870d962001-07-02 17:27:21 +00002010static void hashcd (void);
2011
Eric Andersencb57d552001-06-28 07:25:16 +00002012static void
Eric Andersen2870d962001-07-02 17:27:21 +00002013updatepwd(const char *dir)
2014{
Eric Andersencb57d552001-06-28 07:25:16 +00002015 char *new;
2016 char *p;
2017 size_t len;
2018
Eric Andersen2870d962001-07-02 17:27:21 +00002019 hashcd(); /* update command hash table */
Eric Andersencb57d552001-06-28 07:25:16 +00002020
2021 /*
2022 * If our argument is NULL, we don't know the current directory
2023 * any more because we traversed a symbolic link or something
2024 * we couldn't stat().
2025 */
2026 if (dir == NULL || curdir == nullstr) {
2027 setpwd(0, 1);
2028 return;
2029 }
2030 len = strlen(dir);
2031 cdcomppath = sstrdup(dir);
2032 STARTSTACKSTR(new);
2033 if (*dir != '/') {
2034 p = curdir;
2035 while (*p)
2036 STPUTC(*p++, new);
2037 if (p[-1] == '/')
2038 STUNPUTC(new);
2039 }
2040 while ((p = getcomponent()) != NULL) {
2041 if (equal(p, "..")) {
2042 while (new > stackblock() && (STUNPUTC(new), *new) != '/');
2043 } else if (*p != '\0' && ! equal(p, ".")) {
2044 STPUTC('/', new);
2045 while (*p)
2046 STPUTC(*p++, new);
2047 }
2048 }
2049 if (new == stackblock())
2050 STPUTC('/', new);
2051 STACKSTRNUL(new);
2052 setpwd(stackblock(), 1);
2053}
2054
2055
Eric Andersen2870d962001-07-02 17:27:21 +00002056#ifdef ASH_PWD
Eric Andersencb57d552001-06-28 07:25:16 +00002057static int
2058pwdcmd(argc, argv)
2059 int argc;
2060 char **argv;
2061{
2062 out1fmt(snlfmt, curdir);
2063 return 0;
2064}
Eric Andersen2870d962001-07-02 17:27:21 +00002065#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002066
2067/*
2068 * Find out what the current directory is. If we already know the current
2069 * directory, this routine returns immediately.
2070 */
2071static void
Eric Andersen2870d962001-07-02 17:27:21 +00002072getpwd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00002073{
Eric Andersen2870d962001-07-02 17:27:21 +00002074 curdir = xgetcwd(0);
2075 if(curdir==0)
2076 curdir = nullstr;
Eric Andersencb57d552001-06-28 07:25:16 +00002077}
2078
2079static void
2080setpwd(const char *val, int setold)
2081{
2082 if (setold) {
2083 setvar("OLDPWD", curdir, VEXPORT);
2084 }
2085 INTOFF;
2086 if (curdir != nullstr) {
2087 free(curdir);
2088 curdir = nullstr;
2089 }
2090 if (!val) {
2091 getpwd();
2092 } else {
2093 curdir = savestr(val);
2094 }
2095 INTON;
2096 setvar("PWD", curdir, VEXPORT);
2097}
2098
Eric Andersencb57d552001-06-28 07:25:16 +00002099/*
2100 * Errors and exceptions.
2101 */
2102
2103/*
2104 * Code to handle exceptions in C.
2105 */
2106
Eric Andersen2870d962001-07-02 17:27:21 +00002107/*
2108 * We enclose jmp_buf in a structure so that we can declare pointers to
2109 * jump locations. The global variable handler contains the location to
2110 * jump to when an exception occurs, and the global variable exception
2111 * contains a code identifying the exeception. To implement nested
2112 * exception handlers, the user should save the value of handler on entry
2113 * to an inner scope, set handler to point to a jmploc structure for the
2114 * inner scope, and restore handler on exit from the scope.
2115 */
2116
2117struct jmploc {
2118 jmp_buf loc;
2119};
2120
2121/* exceptions */
2122#define EXINT 0 /* SIGINT received */
2123#define EXERROR 1 /* a generic error */
2124#define EXSHELLPROC 2 /* execute a shell procedure */
2125#define EXEXEC 3 /* command execution failed */
2126
2127static struct jmploc *handler;
Eric Andersencb57d552001-06-28 07:25:16 +00002128static int exception;
Eric Andersencb57d552001-06-28 07:25:16 +00002129
Eric Andersen2870d962001-07-02 17:27:21 +00002130static void exverror (int, const char *, va_list)
Eric Andersencb57d552001-06-28 07:25:16 +00002131 __attribute__((__noreturn__));
2132
2133/*
2134 * Called to raise an exception. Since C doesn't include exceptions, we
2135 * just do a longjmp to the exception handler. The type of exception is
2136 * stored in the global variable "exception".
2137 */
2138
Eric Andersen2870d962001-07-02 17:27:21 +00002139static void exraise (int) __attribute__((__noreturn__));
2140
Eric Andersencb57d552001-06-28 07:25:16 +00002141static void
Eric Andersen2870d962001-07-02 17:27:21 +00002142exraise(int e)
Eric Andersencb57d552001-06-28 07:25:16 +00002143{
2144#ifdef DEBUG
2145 if (handler == NULL)
2146 abort();
2147#endif
2148 exception = e;
2149 longjmp(handler->loc, 1);
2150}
2151
2152
2153/*
2154 * Called from trap.c when a SIGINT is received. (If the user specifies
2155 * that SIGINT is to be trapped or ignored using the trap builtin, then
2156 * this routine is not called.) Suppressint is nonzero when interrupts
2157 * are held using the INTOFF macro. The call to _exit is necessary because
2158 * there is a short period after a fork before the signal handlers are
2159 * set to the appropriate value for the child. (The test for iflag is
2160 * just defensive programming.)
2161 */
2162
2163static void
Eric Andersen2870d962001-07-02 17:27:21 +00002164onint(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00002165 sigset_t mysigset;
2166
2167 if (suppressint) {
2168 intpending++;
2169 return;
2170 }
2171 intpending = 0;
2172 sigemptyset(&mysigset);
2173 sigprocmask(SIG_SETMASK, &mysigset, NULL);
2174 if (rootshell && iflag)
2175 exraise(EXINT);
2176 else {
2177 signal(SIGINT, SIG_DFL);
2178 raise(SIGINT);
2179 }
2180 /* NOTREACHED */
2181}
2182
2183
Eric Andersen2870d962001-07-02 17:27:21 +00002184static char *commandname; /* currently executing command */
2185
Eric Andersencb57d552001-06-28 07:25:16 +00002186/*
2187 * Exverror is called to raise the error exception. If the first argument
2188 * is not NULL then error prints an error message using printf style
2189 * formatting. It then raises the error exception.
2190 */
2191static void
Eric Andersen2870d962001-07-02 17:27:21 +00002192exverror(int cond, const char *msg, va_list ap)
Eric Andersencb57d552001-06-28 07:25:16 +00002193{
2194 CLEAR_PENDING_INT;
2195 INTOFF;
2196
2197#ifdef DEBUG
2198 if (msg)
2199 TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid()));
2200 else
2201 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
2202#endif
2203 if (msg) {
2204 if (commandname)
2205 outfmt(&errout, "%s: ", commandname);
2206 doformat(&errout, msg, ap);
2207#if FLUSHERR
2208 outc('\n', &errout);
2209#else
2210 outcslow('\n', &errout);
2211#endif
2212 }
2213 flushall();
2214 exraise(cond);
2215 /* NOTREACHED */
2216}
2217
2218
2219#ifdef __STDC__
2220static void
2221error(const char *msg, ...)
2222#else
2223static void
2224error(va_alist)
2225 va_dcl
2226#endif
2227{
2228#ifndef __STDC__
2229 const char *msg;
2230#endif
2231 va_list ap;
2232#ifdef __STDC__
2233 va_start(ap, msg);
2234#else
2235 va_start(ap);
2236 msg = va_arg(ap, const char *);
2237#endif
2238 exverror(EXERROR, msg, ap);
2239 /* NOTREACHED */
2240 va_end(ap);
2241}
2242
2243
2244#ifdef __STDC__
2245static void
2246exerror(int cond, const char *msg, ...)
2247#else
2248static void
2249exerror(va_alist)
2250 va_dcl
2251#endif
2252{
2253#ifndef __STDC__
2254 int cond;
2255 const char *msg;
2256#endif
2257 va_list ap;
2258#ifdef __STDC__
2259 va_start(ap, msg);
2260#else
2261 va_start(ap);
2262 cond = va_arg(ap, int);
2263 msg = va_arg(ap, const char *);
2264#endif
2265 exverror(cond, msg, ap);
2266 /* NOTREACHED */
2267 va_end(ap);
2268}
2269
2270
2271
2272/*
2273 * Table of error messages.
2274 */
2275
2276struct errname {
Eric Andersen2870d962001-07-02 17:27:21 +00002277 short errcode; /* error number */
2278 short action; /* operation which encountered the error */
Eric Andersencb57d552001-06-28 07:25:16 +00002279};
2280
Eric Andersen2870d962001-07-02 17:27:21 +00002281/*
2282 * Types of operations (passed to the errmsg routine).
2283 */
2284
2285#define E_OPEN 01 /* opening a file */
2286#define E_CREAT 02 /* creating a file */
2287#define E_EXEC 04 /* executing a program */
Eric Andersencb57d552001-06-28 07:25:16 +00002288
2289#define ALL (E_OPEN|E_CREAT|E_EXEC)
2290
2291static const struct errname errormsg[] = {
Eric Andersen2870d962001-07-02 17:27:21 +00002292 { EINTR, ALL },
2293 { EACCES, ALL },
2294 { EIO, ALL },
2295 { ENOENT, E_OPEN },
2296 { ENOENT, E_CREAT },
2297 { ENOENT, E_EXEC },
2298 { ENOTDIR, E_OPEN },
2299 { ENOTDIR, E_CREAT },
2300 { ENOTDIR, E_EXEC },
2301 { EISDIR, ALL },
2302 { EEXIST, E_CREAT },
2303#ifdef EMFILE
2304 { EMFILE, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002305#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002306 { ENFILE, ALL },
2307 { ENOSPC, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002308#ifdef EDQUOT
Eric Andersen2870d962001-07-02 17:27:21 +00002309 { EDQUOT, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002310#endif
2311#ifdef ENOSR
Eric Andersen2870d962001-07-02 17:27:21 +00002312 { ENOSR, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002313#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002314 { ENXIO, ALL },
2315 { EROFS, ALL },
2316 { ETXTBSY, ALL },
2317#ifdef EAGAIN
2318 { EAGAIN, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002319#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002320 { ENOMEM, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002321#ifdef ENOLINK
Eric Andersen2870d962001-07-02 17:27:21 +00002322 { ENOLINK, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002323#endif
2324#ifdef EMULTIHOP
Eric Andersen2870d962001-07-02 17:27:21 +00002325 { EMULTIHOP, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002326#endif
2327#ifdef ECOMM
Eric Andersen2870d962001-07-02 17:27:21 +00002328 { ECOMM, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002329#endif
2330#ifdef ESTALE
Eric Andersen2870d962001-07-02 17:27:21 +00002331 { ESTALE, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002332#endif
2333#ifdef ETIMEDOUT
Eric Andersen2870d962001-07-02 17:27:21 +00002334 { ETIMEDOUT, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002335#endif
2336#ifdef ELOOP
Eric Andersen2870d962001-07-02 17:27:21 +00002337 { ELOOP, ALL },
Eric Andersencb57d552001-06-28 07:25:16 +00002338#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002339 { E2BIG, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002340#ifdef ELIBACC
Eric Andersen2870d962001-07-02 17:27:21 +00002341 { ELIBACC, E_EXEC },
Eric Andersencb57d552001-06-28 07:25:16 +00002342#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002343};
2344
Eric Andersen2870d962001-07-02 17:27:21 +00002345#define ERRNAME_SIZE (sizeof(errormsg)/sizeof(struct errname))
Eric Andersencb57d552001-06-28 07:25:16 +00002346
2347/*
2348 * Return a string describing an error. The returned string may be a
2349 * pointer to a static buffer that will be overwritten on the next call.
2350 * Action describes the operation that got the error.
2351 */
2352
2353static const char *
Eric Andersen2870d962001-07-02 17:27:21 +00002354errmsg(int e, int action)
Eric Andersencb57d552001-06-28 07:25:16 +00002355{
2356 struct errname const *ep;
2357 static char buf[12];
2358
Eric Andersen2870d962001-07-02 17:27:21 +00002359 for (ep = errormsg ; ep < errormsg+ERRNAME_SIZE; ep++) {
Eric Andersencb57d552001-06-28 07:25:16 +00002360 if (ep->errcode == e && (ep->action & action) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00002361 return strerror(e);
Eric Andersencb57d552001-06-28 07:25:16 +00002362 }
Eric Andersen2870d962001-07-02 17:27:21 +00002363
Eric Andersencb57d552001-06-28 07:25:16 +00002364 fmtstr(buf, sizeof buf, "error %d", e);
2365 return buf;
2366}
2367
2368
Eric Andersen2870d962001-07-02 17:27:21 +00002369#ifndef ASH_BBAPPS_AS_BUILTINS
Eric Andersencb57d552001-06-28 07:25:16 +00002370static void
2371__inton() {
2372 if (--suppressint == 0 && intpending) {
2373 onint();
2374 }
2375}
2376#endif
Eric Andersencb57d552001-06-28 07:25:16 +00002377
2378/* flags in argument to evaltree */
Eric Andersen2870d962001-07-02 17:27:21 +00002379#define EV_EXIT 01 /* exit after evaluating tree */
2380#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
2381#define EV_BACKCMD 04 /* command executing within back quotes */
Eric Andersencb57d552001-06-28 07:25:16 +00002382
Eric Andersen2870d962001-07-02 17:27:21 +00002383static int evalskip; /* set if we are skipping commands */
2384static int skipcount; /* number of levels to skip */
2385static int loopnest; /* current loop nesting level */
2386static int funcnest; /* depth of function calls */
Eric Andersencb57d552001-06-28 07:25:16 +00002387
2388
Eric Andersen2870d962001-07-02 17:27:21 +00002389
2390static struct strlist *cmdenviron; /* environment for builtin command */
2391static int exitstatus; /* exit status of last command */
2392static int oexitstatus; /* saved exit status */
Eric Andersencb57d552001-06-28 07:25:16 +00002393
2394
Eric Andersen2870d962001-07-02 17:27:21 +00002395static void evalloop (union node *, int);
2396static void evalfor (union node *, int);
2397static void evalcase (union node *, int);
2398static void evalsubshell (union node *, int);
2399static void expredir (union node *);
2400static void evalpipe (union node *);
Eric Andersencb57d552001-06-28 07:25:16 +00002401#ifdef notyet
Eric Andersen2870d962001-07-02 17:27:21 +00002402static void evalcommand (union node *, int, struct backcmd *);
Eric Andersencb57d552001-06-28 07:25:16 +00002403#else
Eric Andersen2870d962001-07-02 17:27:21 +00002404static void evalcommand (union node *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00002405#endif
Eric Andersen2870d962001-07-02 17:27:21 +00002406static void prehash (union node *);
2407static void eprintlist (struct strlist *);
Eric Andersencb57d552001-06-28 07:25:16 +00002408
Eric Andersen2870d962001-07-02 17:27:21 +00002409static union node *parsecmd(int);
Eric Andersencb57d552001-06-28 07:25:16 +00002410/*
2411 * Called to reset things after an exception.
2412 */
2413
Eric Andersencb57d552001-06-28 07:25:16 +00002414/*
2415 * The eval commmand.
2416 */
Eric Andersen2870d962001-07-02 17:27:21 +00002417static void evalstring (char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00002418
2419static int
2420evalcmd(argc, argv)
2421 int argc;
2422 char **argv;
2423{
Eric Andersen2870d962001-07-02 17:27:21 +00002424 char *p;
2425 char *concat;
2426 char **ap;
Eric Andersencb57d552001-06-28 07:25:16 +00002427
Eric Andersen2870d962001-07-02 17:27:21 +00002428 if (argc > 1) {
2429 p = argv[1];
2430 if (argc > 2) {
2431 STARTSTACKSTR(concat);
2432 ap = argv + 2;
2433 for (;;) {
2434 while (*p)
2435 STPUTC(*p++, concat);
2436 if ((p = *ap++) == NULL)
2437 break;
2438 STPUTC(' ', concat);
2439 }
2440 STPUTC('\0', concat);
2441 p = grabstackstr(concat);
2442 }
2443 evalstring(p, EV_TESTED);
2444 }
2445 return exitstatus;
Eric Andersencb57d552001-06-28 07:25:16 +00002446}
2447
Eric Andersencb57d552001-06-28 07:25:16 +00002448/*
2449 * Execute a command or commands contained in a string.
2450 */
2451
Eric Andersen2870d962001-07-02 17:27:21 +00002452static void evaltree (union node *, int);
2453static void setinputstring (char *);
2454static void popfile (void);
2455static void setstackmark(struct stackmark *mark);
2456static void popstackmark(struct stackmark *mark);
2457
2458
Eric Andersencb57d552001-06-28 07:25:16 +00002459static void
Eric Andersen2870d962001-07-02 17:27:21 +00002460evalstring(char *s, int flag)
2461{
Eric Andersencb57d552001-06-28 07:25:16 +00002462 union node *n;
2463 struct stackmark smark;
2464
2465 setstackmark(&smark);
2466 setinputstring(s);
2467 while ((n = parsecmd(0)) != NEOF) {
2468 evaltree(n, flag);
2469 popstackmark(&smark);
2470 }
2471 popfile();
2472 popstackmark(&smark);
2473}
2474
Eric Andersencb57d552001-06-28 07:25:16 +00002475/*
2476 * Evaluate a parse tree. The value is left in the global variable
2477 * exitstatus.
2478 */
Eric Andersen2870d962001-07-02 17:27:21 +00002479static struct builtincmd *find_builtin (const char *);
2480static void defun (char *, union node *);
Eric Andersencb57d552001-06-28 07:25:16 +00002481
2482static void
2483evaltree(n, flags)
2484 union node *n;
2485 int flags;
2486{
2487 int checkexit = 0;
2488 if (n == NULL) {
2489 TRACE(("evaltree(NULL) called\n"));
2490 goto out;
2491 }
2492 TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type));
2493 switch (n->type) {
2494 case NSEMI:
2495 evaltree(n->nbinary.ch1, flags & EV_TESTED);
2496 if (evalskip)
2497 goto out;
2498 evaltree(n->nbinary.ch2, flags);
2499 break;
2500 case NAND:
2501 evaltree(n->nbinary.ch1, EV_TESTED);
2502 if (evalskip || exitstatus != 0)
2503 goto out;
2504 evaltree(n->nbinary.ch2, flags);
2505 break;
2506 case NOR:
2507 evaltree(n->nbinary.ch1, EV_TESTED);
2508 if (evalskip || exitstatus == 0)
2509 goto out;
2510 evaltree(n->nbinary.ch2, flags);
2511 break;
2512 case NREDIR:
2513 expredir(n->nredir.redirect);
2514 redirect(n->nredir.redirect, REDIR_PUSH);
2515 evaltree(n->nredir.n, flags);
2516 popredir();
2517 break;
2518 case NSUBSHELL:
2519 evalsubshell(n, flags);
2520 break;
2521 case NBACKGND:
2522 evalsubshell(n, flags);
2523 break;
2524 case NIF: {
2525 evaltree(n->nif.test, EV_TESTED);
2526 if (evalskip)
2527 goto out;
2528 if (exitstatus == 0)
2529 evaltree(n->nif.ifpart, flags);
2530 else if (n->nif.elsepart)
2531 evaltree(n->nif.elsepart, flags);
2532 else
2533 exitstatus = 0;
2534 break;
2535 }
2536 case NWHILE:
2537 case NUNTIL:
2538 evalloop(n, flags);
2539 break;
2540 case NFOR:
2541 evalfor(n, flags);
2542 break;
2543 case NCASE:
2544 evalcase(n, flags);
2545 break;
2546 case NDEFUN: {
2547 struct builtincmd *bcmd;
2548 if (
2549 (bcmd = find_builtin(n->narg.text)) &&
Eric Andersen2870d962001-07-02 17:27:21 +00002550 IS_BUILTIN_SPECIAL(bcmd)
Eric Andersencb57d552001-06-28 07:25:16 +00002551 ) {
2552 outfmt(out2, "%s is a special built-in\n", n->narg.text);
2553 exitstatus = 1;
2554 break;
2555 }
2556 defun(n->narg.text, n->narg.next);
2557 exitstatus = 0;
2558 break;
2559 }
2560 case NNOT:
2561 evaltree(n->nnot.com, EV_TESTED);
2562 exitstatus = !exitstatus;
2563 break;
2564
2565 case NPIPE:
2566 evalpipe(n);
2567 checkexit = 1;
2568 break;
2569 case NCMD:
2570#ifdef notyet
2571 evalcommand(n, flags, (struct backcmd *)NULL);
2572#else
2573 evalcommand(n, flags);
2574#endif
2575 checkexit = 1;
2576 break;
2577#ifdef DEBUG
2578 default:
2579 out1fmt("Node type = %d\n", n->type);
2580#ifndef USE_GLIBC_STDIO
2581 flushout(out1);
2582#endif
2583 break;
2584#endif
2585 }
2586out:
2587 if (pendingsigs)
2588 dotrap();
2589 if (
2590 flags & EV_EXIT ||
2591 (checkexit && eflag && exitstatus && !(flags & EV_TESTED))
2592 )
2593 exitshell(exitstatus);
2594}
2595
2596
2597static void
2598evalloop(n, flags)
2599 union node *n;
2600 int flags;
2601{
2602 int status;
2603
2604 loopnest++;
2605 status = 0;
2606 for (;;) {
2607 evaltree(n->nbinary.ch1, EV_TESTED);
2608 if (evalskip) {
Eric Andersen2870d962001-07-02 17:27:21 +00002609skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00002610 evalskip = 0;
2611 continue;
2612 }
2613 if (evalskip == SKIPBREAK && --skipcount <= 0)
2614 evalskip = 0;
2615 break;
2616 }
2617 if (n->type == NWHILE) {
2618 if (exitstatus != 0)
2619 break;
2620 } else {
2621 if (exitstatus == 0)
2622 break;
2623 }
2624 evaltree(n->nbinary.ch2, flags & EV_TESTED);
2625 status = exitstatus;
2626 if (evalskip)
2627 goto skipping;
2628 }
2629 loopnest--;
2630 exitstatus = status;
2631}
2632
Eric Andersen2870d962001-07-02 17:27:21 +00002633static void expandarg (union node *, struct arglist *, int);
2634static void fixredir(union node *n, const char *text, int err);
Eric Andersencb57d552001-06-28 07:25:16 +00002635
2636static void
2637evalfor(n, flags)
2638 union node *n;
2639 int flags;
2640{
2641 struct arglist arglist;
2642 union node *argp;
2643 struct strlist *sp;
2644 struct stackmark smark;
2645
2646 setstackmark(&smark);
2647 arglist.lastp = &arglist.list;
2648 for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
2649 oexitstatus = exitstatus;
2650 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
2651 if (evalskip)
2652 goto out;
2653 }
2654 *arglist.lastp = NULL;
2655
2656 exitstatus = 0;
2657 loopnest++;
2658 for (sp = arglist.list ; sp ; sp = sp->next) {
2659 setvar(n->nfor.var, sp->text, 0);
2660 evaltree(n->nfor.body, flags & EV_TESTED);
2661 if (evalskip) {
2662 if (evalskip == SKIPCONT && --skipcount <= 0) {
2663 evalskip = 0;
2664 continue;
2665 }
2666 if (evalskip == SKIPBREAK && --skipcount <= 0)
2667 evalskip = 0;
2668 break;
2669 }
2670 }
2671 loopnest--;
2672out:
2673 popstackmark(&smark);
2674}
2675
2676
Eric Andersencb57d552001-06-28 07:25:16 +00002677static void
2678evalcase(n, flags)
2679 union node *n;
2680 int flags;
2681{
2682 union node *cp;
2683 union node *patp;
2684 struct arglist arglist;
2685 struct stackmark smark;
2686
2687 setstackmark(&smark);
2688 arglist.lastp = &arglist.list;
2689 oexitstatus = exitstatus;
2690 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
2691 for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) {
2692 for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
2693 if (casematch(patp, arglist.list->text)) {
2694 if (evalskip == 0) {
2695 evaltree(cp->nclist.body, flags);
2696 }
2697 goto out;
2698 }
2699 }
2700 }
2701out:
2702 popstackmark(&smark);
2703}
2704
Eric Andersencb57d552001-06-28 07:25:16 +00002705/*
2706 * Kick off a subshell to evaluate a tree.
2707 */
2708
2709static void
2710evalsubshell(n, flags)
2711 union node *n;
2712 int flags;
2713{
2714 struct job *jp;
2715 int backgnd = (n->type == NBACKGND);
2716
2717 expredir(n->nredir.redirect);
2718 jp = makejob(n, 1);
2719 if (forkshell(jp, n, backgnd) == 0) {
2720 if (backgnd)
2721 flags &=~ EV_TESTED;
2722 redirect(n->nredir.redirect, 0);
Eric Andersen2870d962001-07-02 17:27:21 +00002723 evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00002724 }
2725 if (! backgnd) {
2726 INTOFF;
2727 exitstatus = waitforjob(jp);
2728 INTON;
2729 }
2730}
2731
2732
2733
2734/*
2735 * Compute the names of the files in a redirection list.
2736 */
2737
2738static void
2739expredir(n)
2740 union node *n;
2741{
2742 union node *redir;
2743
2744 for (redir = n ; redir ; redir = redir->nfile.next) {
2745 struct arglist fn;
2746 fn.lastp = &fn.list;
2747 oexitstatus = exitstatus;
2748 switch (redir->type) {
2749 case NFROMTO:
2750 case NFROM:
2751 case NTO:
2752 case NAPPEND:
2753 case NTOOV:
2754 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
2755 redir->nfile.expfname = fn.list->text;
2756 break;
2757 case NFROMFD:
2758 case NTOFD:
2759 if (redir->ndup.vname) {
2760 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
2761 fixredir(redir, fn.list->text, 1);
2762 }
2763 break;
2764 }
2765 }
2766}
2767
Eric Andersencb57d552001-06-28 07:25:16 +00002768/*
2769 * Evaluate a pipeline. All the processes in the pipeline are children
2770 * of the process creating the pipeline. (This differs from some versions
2771 * of the shell, which make the last process in a pipeline the parent
2772 * of all the rest.)
2773 */
2774
2775static void
2776evalpipe(n)
2777 union node *n;
2778{
2779 struct job *jp;
2780 struct nodelist *lp;
2781 int pipelen;
2782 int prevfd;
2783 int pip[2];
2784
2785 TRACE(("evalpipe(0x%lx) called\n", (long)n));
2786 pipelen = 0;
2787 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
2788 pipelen++;
2789 INTOFF;
2790 jp = makejob(n, pipelen);
2791 prevfd = -1;
2792 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
2793 prehash(lp->n);
2794 pip[1] = -1;
2795 if (lp->next) {
2796 if (pipe(pip) < 0) {
2797 close(prevfd);
2798 error("Pipe call failed");
2799 }
2800 }
2801 if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
2802 INTON;
2803 if (prevfd > 0) {
2804 close(0);
2805 dup_as_newfd(prevfd, 0);
2806 close(prevfd);
2807 if (pip[0] == 0) {
2808 pip[0] = -1;
2809 }
2810 }
2811 if (pip[1] >= 0) {
2812 if (pip[0] >= 0) {
2813 close(pip[0]);
2814 }
2815 if (pip[1] != 1) {
2816 close(1);
2817 dup_as_newfd(pip[1], 1);
2818 close(pip[1]);
2819 }
2820 }
2821 evaltree(lp->n, EV_EXIT);
2822 }
2823 if (prevfd >= 0)
2824 close(prevfd);
2825 prevfd = pip[0];
2826 close(pip[1]);
2827 }
2828 INTON;
2829 if (n->npipe.backgnd == 0) {
2830 INTOFF;
2831 exitstatus = waitforjob(jp);
2832 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
2833 INTON;
2834 }
2835}
2836
2837
2838
2839/*
2840 * Execute a command inside back quotes. If it's a builtin command, we
2841 * want to save its output in a block obtained from malloc. Otherwise
2842 * we fork off a subprocess and get the output of the command via a pipe.
2843 * Should be called with interrupts off.
2844 */
2845
2846static void
Eric Andersen2870d962001-07-02 17:27:21 +00002847evalbackcmd(union node *n, struct backcmd *result)
Eric Andersencb57d552001-06-28 07:25:16 +00002848{
2849 int pip[2];
2850 struct job *jp;
Eric Andersen2870d962001-07-02 17:27:21 +00002851 struct stackmark smark; /* unnecessary */
Eric Andersencb57d552001-06-28 07:25:16 +00002852
2853 setstackmark(&smark);
2854 result->fd = -1;
2855 result->buf = NULL;
2856 result->nleft = 0;
2857 result->jp = NULL;
2858 if (n == NULL) {
2859 exitstatus = 0;
2860 goto out;
2861 }
2862#ifdef notyet
2863 /*
2864 * For now we disable executing builtins in the same
2865 * context as the shell, because we are not keeping
2866 * enough state to recover from changes that are
2867 * supposed only to affect subshells. eg. echo "`cd /`"
2868 */
2869 if (n->type == NCMD) {
2870 exitstatus = oexitstatus;
2871 evalcommand(n, EV_BACKCMD, result);
2872 } else
2873#endif
2874 {
2875 exitstatus = 0;
2876 if (pipe(pip) < 0)
2877 error("Pipe call failed");
2878 jp = makejob(n, 1);
2879 if (forkshell(jp, n, FORK_NOJOB) == 0) {
2880 FORCEINTON;
2881 close(pip[0]);
2882 if (pip[1] != 1) {
2883 close(1);
2884 dup_as_newfd(pip[1], 1);
2885 close(pip[1]);
2886 }
2887 eflag = 0;
2888 evaltree(n, EV_EXIT);
2889 }
2890 close(pip[1]);
2891 result->fd = pip[0];
2892 result->jp = jp;
2893 }
2894out:
2895 popstackmark(&smark);
2896 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
2897 result->fd, result->buf, result->nleft, result->jp));
2898}
2899
2900
2901
2902/*
2903 * Execute a simple command.
2904 */
2905
Eric Andersen2870d962001-07-02 17:27:21 +00002906static void find_command (const char *, struct cmdentry *, int, const char *);
2907
2908static int
2909isassignment(const char *word) {
2910 if (!is_name(*word)) {
2911 return 0;
2912 }
2913 do {
2914 word++;
2915 } while (is_in_name(*word));
2916 return *word == '=';
2917}
2918
Eric Andersencb57d552001-06-28 07:25:16 +00002919static void
2920#ifdef notyet
2921evalcommand(cmd, flags, backcmd)
2922 union node *cmd;
2923 int flags;
2924 struct backcmd *backcmd;
2925#else
2926evalcommand(cmd, flags)
2927 union node *cmd;
2928 int flags;
2929#endif
2930{
2931 struct stackmark smark;
2932 union node *argp;
2933 struct arglist arglist;
2934 struct arglist varlist;
2935 char **argv;
2936 int argc;
2937 char **envp;
2938 struct strlist *sp;
2939 int mode;
2940#ifdef notyet
2941 int pip[2];
2942#endif
2943 struct cmdentry cmdentry;
2944 struct job *jp;
2945 char *volatile savecmdname;
2946 volatile struct shparam saveparam;
2947 struct localvar *volatile savelocalvars;
2948 volatile int e;
2949 char *lastarg;
2950 const char *path;
2951 const struct builtincmd *firstbltin;
2952 struct jmploc *volatile savehandler;
2953 struct jmploc jmploc;
2954#if __GNUC__
2955 /* Avoid longjmp clobbering */
2956 (void) &argv;
2957 (void) &argc;
2958 (void) &lastarg;
2959 (void) &flags;
2960#endif
2961
2962 /* First expand the arguments. */
2963 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
2964 setstackmark(&smark);
2965 arglist.lastp = &arglist.list;
2966 varlist.lastp = &varlist.list;
2967 arglist.list = 0;
2968 oexitstatus = exitstatus;
2969 exitstatus = 0;
2970 path = pathval();
2971 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
2972 expandarg(argp, &varlist, EXP_VARTILDE);
2973 }
2974 for (
2975 argp = cmd->ncmd.args; argp && !arglist.list;
2976 argp = argp->narg.next
2977 ) {
2978 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
2979 }
2980 if (argp) {
2981 struct builtincmd *bcmd;
2982 bool pseudovarflag;
2983 bcmd = find_builtin(arglist.list->text);
Eric Andersen2870d962001-07-02 17:27:21 +00002984 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
Eric Andersencb57d552001-06-28 07:25:16 +00002985 for (; argp; argp = argp->narg.next) {
2986 if (pseudovarflag && isassignment(argp->narg.text)) {
2987 expandarg(argp, &arglist, EXP_VARTILDE);
2988 continue;
2989 }
2990 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
2991 }
2992 }
2993 *arglist.lastp = NULL;
2994 *varlist.lastp = NULL;
2995 expredir(cmd->ncmd.redirect);
2996 argc = 0;
2997 for (sp = arglist.list ; sp ; sp = sp->next)
2998 argc++;
2999 argv = stalloc(sizeof (char *) * (argc + 1));
3000
3001 for (sp = arglist.list ; sp ; sp = sp->next) {
3002 TRACE(("evalcommand arg: %s\n", sp->text));
3003 *argv++ = sp->text;
3004 }
3005 *argv = NULL;
3006 lastarg = NULL;
3007 if (iflag && funcnest == 0 && argc > 0)
3008 lastarg = argv[-1];
3009 argv -= argc;
3010
3011 /* Print the command if xflag is set. */
3012 if (xflag) {
3013#ifdef FLUSHERR
3014 outc('+', &errout);
3015#else
3016 outcslow('+', &errout);
3017#endif
3018 eprintlist(varlist.list);
3019 eprintlist(arglist.list);
3020#ifdef FLUSHERR
3021 outc('\n', &errout);
3022 flushout(&errout);
3023#else
3024 outcslow('\n', &errout);
3025#endif
3026 }
3027
3028 /* Now locate the command. */
3029 if (argc == 0) {
3030 cmdentry.cmdtype = CMDBUILTIN;
3031 firstbltin = cmdentry.u.cmd = BLTINCMD;
3032 } else {
3033 const char *oldpath;
3034 int findflag = DO_ERR;
3035 int oldfindflag;
3036
3037 /*
3038 * Modify the command lookup path, if a PATH= assignment
3039 * is present
3040 */
3041 for (sp = varlist.list ; sp ; sp = sp->next)
3042 if (varequal(sp->text, defpathvar)) {
3043 path = sp->text + 5;
3044 findflag |= DO_BRUTE;
3045 }
3046 oldpath = path;
3047 oldfindflag = findflag;
3048 firstbltin = 0;
3049 for(;;) {
3050 find_command(argv[0], &cmdentry, findflag, path);
Eric Andersen2870d962001-07-02 17:27:21 +00003051 if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */
Eric Andersencb57d552001-06-28 07:25:16 +00003052 exitstatus = 127;
3053#ifdef FLUSHERR
3054 flushout(&errout);
3055#endif
3056 goto out;
3057 }
3058 /* implement bltin and command here */
3059 if (cmdentry.cmdtype != CMDBUILTIN) {
3060 break;
3061 }
3062 if (!firstbltin) {
3063 firstbltin = cmdentry.u.cmd;
3064 }
3065 if (cmdentry.u.cmd == BLTINCMD) {
3066 for(;;) {
3067 struct builtincmd *bcmd;
3068
3069 argv++;
3070 if (--argc == 0)
3071 goto found;
3072 if (!(bcmd = find_builtin(*argv))) {
3073 outfmt(&errout, "%s: not found\n", *argv);
3074 exitstatus = 127;
3075#ifdef FLUSHERR
3076 flushout(&errout);
3077#endif
3078 goto out;
3079 }
3080 cmdentry.u.cmd = bcmd;
3081 if (bcmd != BLTINCMD)
3082 break;
3083 }
3084 }
Eric Andersen2870d962001-07-02 17:27:21 +00003085 if (cmdentry.u.cmd == find_builtin("command")) {
Eric Andersencb57d552001-06-28 07:25:16 +00003086 argv++;
3087 if (--argc == 0) {
3088 goto found;
3089 }
3090 if (*argv[0] == '-') {
3091 if (!equal(argv[0], "-p")) {
3092 argv--;
3093 argc++;
3094 break;
3095 }
3096 argv++;
3097 if (--argc == 0) {
3098 goto found;
3099 }
3100 path = defpath;
3101 findflag |= DO_BRUTE;
3102 } else {
3103 path = oldpath;
3104 findflag = oldfindflag;
3105 }
3106 findflag |= DO_NOFUN;
3107 continue;
3108 }
3109found:
3110 break;
3111 }
3112 }
3113
3114 /* Fork off a child process if necessary. */
3115 if (cmd->ncmd.backgnd
3116 || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0)
3117#ifdef notyet
3118 || ((flags & EV_BACKCMD) != 0
3119 && (cmdentry.cmdtype != CMDBUILTIN
3120 || cmdentry.u.bcmd == DOTCMD
3121 || cmdentry.u.bcmd == EVALCMD))
3122#endif
3123 ) {
3124 jp = makejob(cmd, 1);
3125 mode = cmd->ncmd.backgnd;
3126#ifdef notyet
3127 if (flags & EV_BACKCMD) {
3128 mode = FORK_NOJOB;
3129 if (pipe(pip) < 0)
3130 error("Pipe call failed");
3131 }
3132#endif
3133 if (forkshell(jp, cmd, mode) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00003134 goto parent; /* at end of routine */
Eric Andersencb57d552001-06-28 07:25:16 +00003135#ifdef notyet
3136 if (flags & EV_BACKCMD) {
3137 FORCEINTON;
3138 close(pip[0]);
3139 if (pip[1] != 1) {
3140 close(1);
3141 dup_as_newfd(pip[1], 1);
3142 close(pip[1]);
3143 }
3144 }
3145#endif
3146 flags |= EV_EXIT;
3147 }
3148
3149 /* This is the child process if a fork occurred. */
3150 /* Execute the command. */
3151 if (cmdentry.cmdtype == CMDFUNCTION) {
3152#ifdef DEBUG
3153 trputs("Shell function: "); trargs(argv);
3154#endif
3155 exitstatus = oexitstatus;
3156 redirect(cmd->ncmd.redirect, REDIR_PUSH);
3157 saveparam = shellparam;
3158 shellparam.malloc = 0;
3159 shellparam.nparam = argc - 1;
3160 shellparam.p = argv + 1;
3161 INTOFF;
3162 savelocalvars = localvars;
3163 localvars = NULL;
3164 INTON;
3165 if (setjmp(jmploc.loc)) {
3166 if (exception == EXSHELLPROC) {
3167 freeparam((volatile struct shparam *)
3168 &saveparam);
3169 } else {
3170 saveparam.optind = shellparam.optind;
3171 saveparam.optoff = shellparam.optoff;
3172 freeparam(&shellparam);
3173 shellparam = saveparam;
3174 }
3175 poplocalvars();
3176 localvars = savelocalvars;
3177 handler = savehandler;
3178 longjmp(handler->loc, 1);
3179 }
3180 savehandler = handler;
3181 handler = &jmploc;
3182 for (sp = varlist.list ; sp ; sp = sp->next)
3183 mklocal(sp->text);
3184 funcnest++;
3185 evaltree(cmdentry.u.func, flags & EV_TESTED);
3186 funcnest--;
3187 INTOFF;
3188 poplocalvars();
3189 localvars = savelocalvars;
3190 saveparam.optind = shellparam.optind;
3191 saveparam.optoff = shellparam.optoff;
3192 freeparam(&shellparam);
3193 shellparam = saveparam;
3194 handler = savehandler;
3195 popredir();
3196 INTON;
3197 if (evalskip == SKIPFUNC) {
3198 evalskip = 0;
3199 skipcount = 0;
3200 }
3201 if (flags & EV_EXIT)
3202 exitshell(exitstatus);
3203 } else if (cmdentry.cmdtype == CMDBUILTIN) {
3204#ifdef DEBUG
3205 trputs("builtin command: "); trargs(argv);
3206#endif
3207 mode = (cmdentry.u.cmd == EXECCMD)? 0 : REDIR_PUSH;
3208#ifdef notyet
3209 if (flags == EV_BACKCMD) {
3210#ifdef USE_GLIBC_STDIO
3211 openmemout();
3212#else
3213 memout.nleft = 0;
3214 memout.nextc = memout.buf;
3215 memout.bufsize = 64;
3216#endif
3217 mode |= REDIR_BACKQ;
3218 }
3219#endif
3220 redirect(cmd->ncmd.redirect, mode);
3221 savecmdname = commandname;
Eric Andersen2870d962001-07-02 17:27:21 +00003222 if (IS_BUILTIN_SPECIAL(firstbltin)) {
Eric Andersencb57d552001-06-28 07:25:16 +00003223 listsetvar(varlist.list);
3224 } else {
3225 cmdenviron = varlist.list;
3226 }
3227 e = -1;
3228 if (setjmp(jmploc.loc)) {
3229 e = exception;
3230 exitstatus = (e == EXINT)? SIGINT+128 : 2;
3231 goto cmddone;
3232 }
3233 savehandler = handler;
3234 handler = &jmploc;
3235 commandname = argv[0];
3236 argptr = argv + 1;
Eric Andersen2870d962001-07-02 17:27:21 +00003237 optptr = NULL; /* initialize nextopt */
Eric Andersencb57d552001-06-28 07:25:16 +00003238 exitstatus = (*cmdentry.u.cmd->builtinfunc)(argc, argv);
3239 flushall();
3240cmddone:
3241 exitstatus |= outerr(out1);
3242 out1 = &output;
3243 out2 = &errout;
3244 freestdout();
3245 cmdenviron = NULL;
3246 if (e != EXSHELLPROC) {
3247 commandname = savecmdname;
3248 if (flags & EV_EXIT)
3249 exitshell(exitstatus);
3250 }
3251 handler = savehandler;
3252 if (e != -1) {
3253 if ((e != EXERROR && e != EXEXEC)
3254 || cmdentry.u.cmd == BLTINCMD
3255 || cmdentry.u.cmd == DOTCMD
3256 || cmdentry.u.cmd == EVALCMD
3257 || cmdentry.u.cmd == EXECCMD)
3258 exraise(e);
3259 FORCEINTON;
3260 }
3261 if (cmdentry.u.cmd != EXECCMD)
3262 popredir();
3263#ifdef notyet
3264 if (flags == EV_BACKCMD) {
3265 INTOFF;
3266#ifdef USE_GLIBC_STDIO
Eric Andersen2870d962001-07-02 17:27:21 +00003267 if (__closememout())
3268 error("__closememout() failed: %m");
Eric Andersencb57d552001-06-28 07:25:16 +00003269#endif
3270 backcmd->buf = memout.buf;
3271#ifdef USE_GLIBC_STDIO
3272 backcmd->nleft = memout.bufsize;
3273#else
3274 backcmd->nleft = memout.nextc - memout.buf;
3275#endif
3276 memout.buf = NULL;
3277 INTON;
3278 }
3279#endif
3280 } else {
3281#ifdef DEBUG
3282 trputs("normal command: "); trargs(argv);
3283#endif
3284 redirect(cmd->ncmd.redirect, 0);
3285 clearredir();
3286 for (sp = varlist.list ; sp ; sp = sp->next)
3287 setvareq(sp->text, VEXPORT|VSTACK);
3288 envp = environment();
3289 shellexec(argv, envp, path, cmdentry.u.index);
3290 }
3291 goto out;
3292
Eric Andersen2870d962001-07-02 17:27:21 +00003293parent: /* parent process gets here (if we forked) */
3294 if (mode == 0) { /* argument to fork */
Eric Andersencb57d552001-06-28 07:25:16 +00003295 INTOFF;
3296 exitstatus = waitforjob(jp);
3297 INTON;
3298#ifdef notyet
3299 } else if (mode == 2) {
3300 backcmd->fd = pip[0];
3301 close(pip[1]);
3302 backcmd->jp = jp;
3303#endif
3304 }
3305
3306out:
3307 if (lastarg)
3308 setvar("_", lastarg, 0);
3309 popstackmark(&smark);
3310}
3311
3312
3313
3314/*
3315 * Search for a command. This is called before we fork so that the
3316 * location of the command will be available in the parent as well as
3317 * the child. The check for "goodname" is an overly conservative
3318 * check that the name will not be subject to expansion.
3319 */
3320
3321static void
3322prehash(n)
3323 union node *n;
3324{
3325 struct cmdentry entry;
3326
3327 if (n->type == NCMD && n->ncmd.args)
3328 if (goodname(n->ncmd.args->narg.text))
3329 find_command(n->ncmd.args->narg.text, &entry, 0,
3330 pathval());
3331}
3332
3333
3334
3335/*
3336 * Builtin commands. Builtin commands whose functions are closely
3337 * tied to evaluation are implemented here.
3338 */
3339
3340/*
3341 * No command given, or a bltin command with no arguments. Set the
3342 * specified variables.
3343 */
3344
3345int
3346bltincmd(argc, argv)
3347 int argc;
3348 char **argv;
3349{
3350 /*
3351 * Preserve exitstatus of a previous possible redirection
3352 * as POSIX mandates
3353 */
3354 return exitstatus;
3355}
3356
3357
3358/*
3359 * Handle break and continue commands. Break, continue, and return are
3360 * all handled by setting the evalskip flag. The evaluation routines
3361 * above all check this flag, and if it is set they start skipping
3362 * commands rather than executing them. The variable skipcount is
3363 * the number of loops to break/continue, or the number of function
3364 * levels to return. (The latter is always 1.) It should probably
3365 * be an error to break out of more loops than exist, but it isn't
3366 * in the standard shell so we don't make it one here.
3367 */
3368
3369static int
3370breakcmd(argc, argv)
3371 int argc;
3372 char **argv;
3373{
3374 int n = argc > 1 ? number(argv[1]) : 1;
3375
3376 if (n > loopnest)
3377 n = loopnest;
3378 if (n > 0) {
3379 evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
3380 skipcount = n;
3381 }
3382 return 0;
3383}
3384
3385
3386/*
3387 * The return command.
3388 */
3389
3390static int
3391returncmd(argc, argv)
3392 int argc;
3393 char **argv;
3394{
3395 int ret = argc > 1 ? number(argv[1]) : oexitstatus;
3396
3397 if (funcnest) {
3398 evalskip = SKIPFUNC;
3399 skipcount = 1;
3400 return ret;
3401 }
3402 else {
3403 /* Do what ksh does; skip the rest of the file */
3404 evalskip = SKIPFILE;
3405 skipcount = 1;
3406 return ret;
3407 }
3408}
3409
3410
3411#ifndef BB_TRUE_FALSE
Eric Andersen2870d962001-07-02 17:27:21 +00003412#ifdef ASH_BBAPPS_AS_BUILTINS
Eric Andersencb57d552001-06-28 07:25:16 +00003413static int
3414false_main(argc, argv)
3415 int argc;
3416 char **argv;
3417{
3418 return 1;
3419}
3420
3421
3422static int
3423true_main(argc, argv)
3424 int argc;
3425 char **argv;
3426{
3427 return 0;
3428}
3429#endif
Eric Andersen2870d962001-07-02 17:27:21 +00003430#endif
3431
3432/*
3433 * Controls whether the shell is interactive or not.
3434 */
3435
3436static void setsignal(int signo);
3437static void chkmail(int silent);
3438
3439
3440static void
3441setinteractive(int on)
3442{
3443 static int is_interactive;
3444
3445 if (on == is_interactive)
3446 return;
3447 setsignal(SIGINT);
3448 setsignal(SIGQUIT);
3449 setsignal(SIGTERM);
3450 chkmail(1);
3451 is_interactive = on;
3452}
3453
3454static void
3455optschanged(void)
3456{
3457 setinteractive(iflag);
3458 setjobctl(mflag);
3459}
3460
Eric Andersencb57d552001-06-28 07:25:16 +00003461
3462static int
3463execcmd(argc, argv)
3464 int argc;
3465 char **argv;
3466{
3467 if (argc > 1) {
3468 struct strlist *sp;
3469
Eric Andersen2870d962001-07-02 17:27:21 +00003470 iflag = 0; /* exit on error */
Eric Andersencb57d552001-06-28 07:25:16 +00003471 mflag = 0;
3472 optschanged();
3473 for (sp = cmdenviron; sp ; sp = sp->next)
3474 setvareq(sp->text, VEXPORT|VSTACK);
3475 shellexec(argv + 1, environment(), pathval(), 0);
3476 }
3477 return 0;
3478}
3479
3480static void
3481eprintlist(struct strlist *sp)
3482{
3483 for (; sp; sp = sp->next) {
3484 outfmt(&errout, " %s",sp->text);
3485 }
3486}
Eric Andersencb57d552001-06-28 07:25:16 +00003487/*
3488 * When commands are first encountered, they are entered in a hash table.
3489 * This ensures that a full path search will not have to be done for them
3490 * on each invocation.
3491 *
3492 * We should investigate converting to a linear search, even though that
3493 * would make the command name "hash" a misnomer.
3494 */
Eric Andersen2870d962001-07-02 17:27:21 +00003495#define CMDTABLESIZE 31 /* should be prime */
3496#define ARB 1 /* actual size determined at run time */
Eric Andersencb57d552001-06-28 07:25:16 +00003497
3498
3499
3500struct tblentry {
Eric Andersen2870d962001-07-02 17:27:21 +00003501 struct tblentry *next; /* next entry in hash chain */
3502 union param param; /* definition of builtin function */
3503 short cmdtype; /* index identifying command */
3504 char rehash; /* if set, cd done since entry created */
3505 char cmdname[ARB]; /* name of command */
Eric Andersencb57d552001-06-28 07:25:16 +00003506};
3507
3508
3509static struct tblentry *cmdtable[CMDTABLESIZE];
Eric Andersen2870d962001-07-02 17:27:21 +00003510static int builtinloc = -1; /* index in path of %builtin, or -1 */
3511static int exerrno = 0; /* Last exec error */
Eric Andersencb57d552001-06-28 07:25:16 +00003512
3513
Eric Andersen2870d962001-07-02 17:27:21 +00003514static void tryexec (char *, char **, char **);
3515static void printentry (struct tblentry *, int);
3516static void clearcmdentry (int);
3517static struct tblentry *cmdlookup (const char *, int);
3518static void delete_cmd_entry (void);
Eric Andersencb57d552001-06-28 07:25:16 +00003519#ifdef ASH_TYPE
Eric Andersen2870d962001-07-02 17:27:21 +00003520static int describe_command (char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00003521#endif
Eric Andersen2870d962001-07-02 17:27:21 +00003522static int path_change (const char *, int *);
Eric Andersencb57d552001-06-28 07:25:16 +00003523
3524
3525/*
3526 * Exec a program. Never returns. If you change this routine, you may
3527 * have to change the find_command routine as well.
3528 */
3529
Eric Andersen2870d962001-07-02 17:27:21 +00003530static const char *pathopt; /* set by padvance */
3531
Eric Andersencb57d552001-06-28 07:25:16 +00003532static void
3533shellexec(argv, envp, path, idx)
3534 char **argv, **envp;
3535 const char *path;
3536 int idx;
3537{
3538 char *cmdname;
3539 int e;
3540
3541 if (strchr(argv[0], '/') != NULL) {
3542 tryexec(argv[0], argv, envp);
3543 e = errno;
3544 } else {
3545 e = ENOENT;
3546 while ((cmdname = padvance(&path, argv[0])) != NULL) {
3547 if (--idx < 0 && pathopt == NULL) {
3548 tryexec(cmdname, argv, envp);
3549 if (errno != ENOENT && errno != ENOTDIR)
3550 e = errno;
3551 }
3552 stunalloc(cmdname);
3553 }
3554 }
3555
3556 /* Map to POSIX errors */
3557 switch (e) {
3558 case EACCES:
3559 exerrno = 126;
3560 break;
3561 case ENOENT:
3562 exerrno = 127;
3563 break;
3564 default:
3565 exerrno = 2;
3566 break;
3567 }
3568 exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
3569 /* NOTREACHED */
3570}
3571
Eric Andersen2870d962001-07-02 17:27:21 +00003572/*
3573 * Clear traps on a fork.
3574 */
3575static void
3576clear_traps(void) {
3577 char **tp;
3578
3579 for (tp = trap ; tp < &trap[NSIG] ; tp++) {
3580 if (*tp && **tp) { /* trap not NULL or SIG_IGN */
3581 INTOFF;
3582 ckfree(*tp);
3583 *tp = NULL;
3584 if (tp != &trap[0])
3585 setsignal(tp - trap);
3586 INTON;
3587 }
3588 }
3589}
3590
3591
3592static void
3593initshellproc(void) {
3594
3595#ifdef ASH_ALIAS
3596 /* from alias.c: */
3597 {
3598 rmaliases();
3599 }
3600#endif
3601 /* from eval.c: */
3602 {
3603 exitstatus = 0;
3604 }
3605
3606 /* from exec.c: */
3607 {
3608 deletefuncs();
3609 }
3610
3611 /* from jobs.c: */
3612 {
3613 backgndpid = -1;
3614#ifdef JOBS
3615 jobctl = 0;
3616#endif
3617 }
3618
3619 /* from options.c: */
3620 {
3621 int i;
3622
3623 for (i = 0; i < NOPTS; i++)
3624 optent_val(i) = 0;
3625 optschanged();
3626
3627 }
3628
3629 /* from redir.c: */
3630 {
3631 clearredir();
3632 }
3633
3634 /* from trap.c: */
3635 {
3636 char *sm;
3637
3638 clear_traps();
3639 for (sm = sigmode ; sm < sigmode + NSIG - 1; sm++) {
3640 if (*sm == S_IGN)
3641 *sm = S_HARD_IGN;
3642 }
3643 }
3644
3645 /* from var.c: */
3646 {
3647 shprocvar();
3648 }
3649}
3650
3651static int preadbuffer(void);
3652static void pushfile (void);
3653static int preadfd (void);
3654
3655/*
3656 * Read a character from the script, returning PEOF on end of file.
3657 * Nul characters in the input are silently discarded.
3658 */
3659
3660#ifdef ASH_BBAPPS_AS_BUILTINS
3661#define pgetc_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
3662static int
3663pgetc(void)
3664{
3665 return pgetc_macro();
3666}
3667#else
3668static int
3669pgetc_macro(void)
3670{
3671 return --parsenleft >= 0? *parsenextc++ : preadbuffer();
3672}
3673
3674static inline int
3675pgetc(void)
3676{
3677 return pgetc_macro();
3678}
3679#endif
3680
3681
3682/*
3683 * Undo the last call to pgetc. Only one character may be pushed back.
3684 * PEOF may be pushed back.
3685 */
3686
3687static void
3688pungetc() {
3689 parsenleft++;
3690 parsenextc--;
3691}
3692
3693
3694static void
3695popfile(void) {
3696 struct parsefile *pf = parsefile;
3697
3698 INTOFF;
3699 if (pf->fd >= 0)
3700 close(pf->fd);
3701 if (pf->buf)
3702 ckfree(pf->buf);
3703 while (pf->strpush)
3704 popstring();
3705 parsefile = pf->prev;
3706 ckfree(pf);
3707 parsenleft = parsefile->nleft;
3708 parselleft = parsefile->lleft;
3709 parsenextc = parsefile->nextc;
3710 plinno = parsefile->linno;
3711 INTON;
3712}
3713
3714
3715/*
3716 * Return to top level.
3717 */
3718
3719static void
3720popallfiles(void) {
3721 while (parsefile != &basepf)
3722 popfile();
3723}
3724
3725/*
3726 * Close the file(s) that the shell is reading commands from. Called
3727 * after a fork is done.
3728 */
3729
3730static void
3731closescript() {
3732 popallfiles();
3733 if (parsefile->fd > 0) {
3734 close(parsefile->fd);
3735 parsefile->fd = 0;
3736 }
3737}
3738
3739
3740/*
3741 * Like setinputfile, but takes an open file descriptor. Call this with
3742 * interrupts off.
3743 */
3744
3745static void
3746setinputfd(fd, push)
3747 int fd, push;
3748{
3749 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
3750 if (push) {
3751 pushfile();
3752 parsefile->buf = 0;
3753 } else {
3754 closescript();
3755 while (parsefile->strpush)
3756 popstring();
3757 }
3758 parsefile->fd = fd;
3759 if (parsefile->buf == NULL)
3760 parsefile->buf = ckmalloc(BUFSIZ);
3761 parselleft = parsenleft = 0;
3762 plinno = 1;
3763}
3764
3765
3766/*
3767 * Set the input to take input from a file. If push is set, push the
3768 * old input onto the stack first.
3769 */
3770
3771static void
3772setinputfile(const char *fname, int push)
3773{
3774 int fd;
3775 int myfileno2;
3776
3777 INTOFF;
3778 if ((fd = open(fname, O_RDONLY)) < 0)
3779 error("Can't open %s", fname);
3780 if (fd < 10) {
3781 myfileno2 = dup_as_newfd(fd, 10);
3782 close(fd);
3783 if (myfileno2 < 0)
3784 error("Out of file descriptors");
3785 fd = myfileno2;
3786 }
3787 setinputfd(fd, push);
3788 INTON;
3789}
3790
Eric Andersencb57d552001-06-28 07:25:16 +00003791
3792static void
3793tryexec(cmd, argv, envp)
3794 char *cmd;
3795 char **argv;
3796 char **envp;
3797 {
3798 int e;
Eric Andersencb57d552001-06-28 07:25:16 +00003799
Eric Andersencb57d552001-06-28 07:25:16 +00003800 execve(cmd, argv, envp);
Eric Andersencb57d552001-06-28 07:25:16 +00003801 e = errno;
3802 if (e == ENOEXEC) {
3803 INTOFF;
3804 initshellproc();
3805 setinputfile(cmd, 0);
3806 commandname = arg0 = savestr(argv[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00003807 setparam(argv + 1);
3808 exraise(EXSHELLPROC);
3809 }
3810 errno = e;
3811}
3812
Eric Andersen2870d962001-07-02 17:27:21 +00003813static char *commandtext (const union node *);
Eric Andersencb57d552001-06-28 07:25:16 +00003814
3815/*
3816 * Do a path search. The variable path (passed by reference) should be
3817 * set to the start of the path before the first call; padvance will update
3818 * this value as it proceeds. Successive calls to padvance will return
3819 * the possible path expansions in sequence. If an option (indicated by
3820 * a percent sign) appears in the path entry then the global variable
3821 * pathopt will be set to point to it; otherwise pathopt will be set to
3822 * NULL.
3823 */
3824
3825static const char *pathopt;
3826
Eric Andersen2870d962001-07-02 17:27:21 +00003827static void growstackblock(void);
3828
3829
Eric Andersencb57d552001-06-28 07:25:16 +00003830static char *
Eric Andersen2870d962001-07-02 17:27:21 +00003831padvance(const char **path, const char *name)
3832{
Eric Andersencb57d552001-06-28 07:25:16 +00003833 const char *p;
3834 char *q;
3835 const char *start;
3836 int len;
3837
3838 if (*path == NULL)
3839 return NULL;
3840 start = *path;
3841 for (p = start ; *p && *p != ':' && *p != '%' ; p++);
Eric Andersen2870d962001-07-02 17:27:21 +00003842 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +00003843 while (stackblocksize() < len)
3844 growstackblock();
3845 q = stackblock();
3846 if (p != start) {
3847 memcpy(q, start, p - start);
3848 q += p - start;
3849 *q++ = '/';
3850 }
3851 strcpy(q, name);
3852 pathopt = NULL;
3853 if (*p == '%') {
3854 pathopt = ++p;
3855 while (*p && *p != ':') p++;
3856 }
3857 if (*p == ':')
3858 *path = p + 1;
3859 else
3860 *path = NULL;
3861 return stalloc(len);
3862}
3863
3864
3865
3866/*** Command hashing code ***/
3867
3868
3869static int
3870hashcmd(argc, argv)
3871 int argc;
3872 char **argv;
3873{
3874 struct tblentry **pp;
3875 struct tblentry *cmdp;
3876 int c;
3877 int verbose;
3878 struct cmdentry entry;
3879 char *name;
3880
3881 verbose = 0;
3882 while ((c = nextopt("rv")) != '\0') {
3883 if (c == 'r') {
3884 clearcmdentry(0);
3885 return 0;
3886 } else if (c == 'v') {
3887 verbose++;
3888 }
3889 }
3890 if (*argptr == NULL) {
3891 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
3892 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
3893 if (cmdp->cmdtype != CMDBUILTIN) {
3894 printentry(cmdp, verbose);
3895 }
3896 }
3897 }
3898 return 0;
3899 }
3900 c = 0;
3901 while ((name = *argptr) != NULL) {
3902 if ((cmdp = cmdlookup(name, 0)) != NULL
3903 && (cmdp->cmdtype == CMDNORMAL
3904 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
3905 delete_cmd_entry();
3906 find_command(name, &entry, DO_ERR, pathval());
3907 if (entry.cmdtype == CMDUNKNOWN) c = 1;
3908 else if (verbose) {
3909 cmdp = cmdlookup(name, 0);
3910 if (cmdp) printentry(cmdp, verbose);
3911 flushall();
3912 }
3913 argptr++;
3914 }
3915 return c;
3916}
3917
3918
3919static void
3920printentry(cmdp, verbose)
3921 struct tblentry *cmdp;
3922 int verbose;
3923 {
3924 int idx;
3925 const char *path;
3926 char *name;
3927
3928 if (cmdp->cmdtype == CMDNORMAL) {
3929 idx = cmdp->param.index;
3930 path = pathval();
3931 do {
3932 name = padvance(&path, cmdp->cmdname);
3933 stunalloc(name);
3934 } while (--idx >= 0);
3935 out1str(name);
3936 } else if (cmdp->cmdtype == CMDBUILTIN) {
3937 out1fmt("builtin %s", cmdp->cmdname);
3938 } else if (cmdp->cmdtype == CMDFUNCTION) {
3939 out1fmt("function %s", cmdp->cmdname);
3940 if (verbose) {
3941 INTOFF;
3942 name = commandtext(cmdp->param.func);
3943 out1fmt(" %s", name);
3944 ckfree(name);
3945 INTON;
3946 }
3947#ifdef DEBUG
3948 } else {
3949 error("internal error: cmdtype %d", cmdp->cmdtype);
3950#endif
3951 }
3952 out1fmt(snlfmt, cmdp->rehash ? "*" : nullstr);
3953}
3954
3955
3956
3957/*
3958 * Resolve a command name. If you change this routine, you may have to
3959 * change the shellexec routine as well.
3960 */
3961
Eric Andersen2870d962001-07-02 17:27:21 +00003962static int prefix (const char *, const char *);
3963
Eric Andersencb57d552001-06-28 07:25:16 +00003964static void
Eric Andersen2870d962001-07-02 17:27:21 +00003965find_command(const char *name, struct cmdentry *entry, int act, const char *path)
Eric Andersencb57d552001-06-28 07:25:16 +00003966{
3967 struct tblentry *cmdp;
3968 int idx;
3969 int prev;
3970 char *fullname;
3971 struct stat statb;
3972 int e;
3973 int bltin;
3974 int firstchange;
3975 int updatetbl;
3976 bool regular;
3977 struct builtincmd *bcmd;
3978
3979 /* If name contains a slash, don't use the hash table */
3980 if (strchr(name, '/') != NULL) {
3981 if (act & DO_ABS) {
3982 while (stat(name, &statb) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00003983 if (errno != ENOENT && errno != ENOTDIR)
3984 e = errno;
3985 entry->cmdtype = CMDUNKNOWN;
3986 entry->u.index = -1;
3987 return;
3988 }
3989 entry->cmdtype = CMDNORMAL;
3990 entry->u.index = -1;
3991 return;
3992 }
3993 entry->cmdtype = CMDNORMAL;
3994 entry->u.index = 0;
3995 return;
3996 }
3997
3998 updatetbl = 1;
3999 if (act & DO_BRUTE) {
4000 firstchange = path_change(path, &bltin);
4001 } else {
4002 bltin = builtinloc;
4003 firstchange = 9999;
4004 }
4005
4006 /* If name is in the table, and not invalidated by cd, we're done */
4007 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0) {
4008 if (cmdp->cmdtype == CMDFUNCTION) {
4009 if (act & DO_NOFUN) {
4010 updatetbl = 0;
4011 } else {
4012 goto success;
4013 }
4014 } else if (act & DO_BRUTE) {
4015 if ((cmdp->cmdtype == CMDNORMAL &&
4016 cmdp->param.index >= firstchange) ||
4017 (cmdp->cmdtype == CMDBUILTIN &&
4018 ((builtinloc < 0 && bltin >= 0) ?
4019 bltin : builtinloc) >= firstchange)) {
4020 /* need to recompute the entry */
4021 } else {
4022 goto success;
4023 }
4024 } else {
4025 goto success;
4026 }
4027 }
4028
4029 bcmd = find_builtin(name);
Eric Andersen2870d962001-07-02 17:27:21 +00004030 regular = bcmd && IS_BUILTIN_REGULAR(bcmd);
Eric Andersencb57d552001-06-28 07:25:16 +00004031
4032 if (regular) {
4033 if (cmdp && (cmdp->cmdtype == CMDBUILTIN)) {
Eric Andersen2870d962001-07-02 17:27:21 +00004034 goto success;
Eric Andersencb57d552001-06-28 07:25:16 +00004035 }
4036 } else if (act & DO_BRUTE) {
4037 if (firstchange == 0) {
4038 updatetbl = 0;
4039 }
4040 }
4041
4042 /* If %builtin not in path, check for builtin next */
4043 if (regular || (bltin < 0 && bcmd)) {
4044builtin:
4045 if (!updatetbl) {
4046 entry->cmdtype = CMDBUILTIN;
4047 entry->u.cmd = bcmd;
4048 return;
4049 }
4050 INTOFF;
4051 cmdp = cmdlookup(name, 1);
4052 cmdp->cmdtype = CMDBUILTIN;
4053 cmdp->param.cmd = bcmd;
4054 INTON;
4055 goto success;
4056 }
4057
4058 /* We have to search path. */
Eric Andersen2870d962001-07-02 17:27:21 +00004059 prev = -1; /* where to start */
4060 if (cmdp && cmdp->rehash) { /* doing a rehash */
Eric Andersencb57d552001-06-28 07:25:16 +00004061 if (cmdp->cmdtype == CMDBUILTIN)
4062 prev = builtinloc;
4063 else
4064 prev = cmdp->param.index;
4065 }
4066
4067 e = ENOENT;
4068 idx = -1;
4069loop:
4070 while ((fullname = padvance(&path, name)) != NULL) {
4071 stunalloc(fullname);
4072 idx++;
4073 if (idx >= firstchange) {
4074 updatetbl = 0;
4075 }
4076 if (pathopt) {
4077 if (prefix("builtin", pathopt)) {
4078 if ((bcmd = find_builtin(name))) {
4079 goto builtin;
4080 }
4081 continue;
4082 } else if (!(act & DO_NOFUN) &&
4083 prefix("func", pathopt)) {
4084 /* handled below */
4085 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00004086 continue; /* ignore unimplemented options */
Eric Andersencb57d552001-06-28 07:25:16 +00004087 }
4088 }
4089 /* if rehash, don't redo absolute path names */
4090 if (fullname[0] == '/' && idx <= prev &&
4091 idx < firstchange) {
4092 if (idx < prev)
4093 continue;
4094 TRACE(("searchexec \"%s\": no change\n", name));
4095 goto success;
4096 }
4097 while (stat(fullname, &statb) < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00004098 if (errno != ENOENT && errno != ENOTDIR)
4099 e = errno;
4100 goto loop;
4101 }
Eric Andersen2870d962001-07-02 17:27:21 +00004102 e = EACCES; /* if we fail, this will be the error */
Eric Andersencb57d552001-06-28 07:25:16 +00004103 if (!S_ISREG(statb.st_mode))
4104 continue;
Eric Andersen2870d962001-07-02 17:27:21 +00004105 if (pathopt) { /* this is a %func directory */
Eric Andersencb57d552001-06-28 07:25:16 +00004106 stalloc(strlen(fullname) + 1);
4107 readcmdfile(fullname);
4108 if ((cmdp = cmdlookup(name, 0)) == NULL || cmdp->cmdtype != CMDFUNCTION)
4109 error("%s not defined in %s", name, fullname);
4110 stunalloc(fullname);
4111 goto success;
4112 }
Eric Andersencb57d552001-06-28 07:25:16 +00004113 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
4114 /* If we aren't called with DO_BRUTE and cmdp is set, it must
4115 be a function and we're being called with DO_NOFUN */
4116 if (!updatetbl) {
4117 entry->cmdtype = CMDNORMAL;
4118 entry->u.index = idx;
4119 return;
4120 }
4121 INTOFF;
4122 cmdp = cmdlookup(name, 1);
4123 cmdp->cmdtype = CMDNORMAL;
4124 cmdp->param.index = idx;
4125 INTON;
4126 goto success;
4127 }
4128
4129 /* We failed. If there was an entry for this command, delete it */
4130 if (cmdp && updatetbl)
4131 delete_cmd_entry();
4132 if (act & DO_ERR)
4133 outfmt(out2, "%s: %s\n", name, errmsg(e, E_EXEC));
4134 entry->cmdtype = CMDUNKNOWN;
4135 return;
4136
4137success:
4138 cmdp->rehash = 0;
4139 entry->cmdtype = cmdp->cmdtype;
4140 entry->u = cmdp->param;
4141}
4142
4143
4144
4145/*
4146 * Search the table of builtin commands.
4147 */
4148
Eric Andersen2870d962001-07-02 17:27:21 +00004149static int
4150bstrcmp(const void *name, const void *b)
4151{
4152 return strcmp((const char *)name, (*(const char *const *) b)+1);
4153}
4154
4155static struct builtincmd *
4156find_builtin(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00004157{
4158 struct builtincmd *bp;
4159
Eric Andersen2870d962001-07-02 17:27:21 +00004160 bp = bsearch(name, builtincmds, NUMBUILTINS, sizeof(struct builtincmd),
4161 bstrcmp
Eric Andersencb57d552001-06-28 07:25:16 +00004162 );
4163 return bp;
4164}
4165
4166
4167/*
4168 * Called when a cd is done. Marks all commands so the next time they
4169 * are executed they will be rehashed.
4170 */
4171
4172static void
Eric Andersen2870d962001-07-02 17:27:21 +00004173hashcd(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00004174 struct tblentry **pp;
4175 struct tblentry *cmdp;
4176
4177 for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
4178 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4179 if (cmdp->cmdtype == CMDNORMAL
4180 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
4181 cmdp->rehash = 1;
4182 }
4183 }
4184}
4185
4186
4187
4188/*
4189 * Called before PATH is changed. The argument is the new value of PATH;
4190 * pathval() still returns the old value at this point. Called with
4191 * interrupts off.
4192 */
4193
4194static void
Eric Andersen2870d962001-07-02 17:27:21 +00004195changepath(const char *newval)
Eric Andersencb57d552001-06-28 07:25:16 +00004196{
4197 int firstchange;
4198 int bltin;
4199
4200 firstchange = path_change(newval, &bltin);
4201 if (builtinloc < 0 && bltin >= 0)
Eric Andersen2870d962001-07-02 17:27:21 +00004202 builtinloc = bltin; /* zap builtins */
Eric Andersencb57d552001-06-28 07:25:16 +00004203 clearcmdentry(firstchange);
4204 builtinloc = bltin;
4205}
4206
4207
4208/*
4209 * Clear out command entries. The argument specifies the first entry in
4210 * PATH which has changed.
4211 */
4212
4213static void
4214clearcmdentry(firstchange)
4215 int firstchange;
4216{
4217 struct tblentry **tblp;
4218 struct tblentry **pp;
4219 struct tblentry *cmdp;
4220
4221 INTOFF;
4222 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4223 pp = tblp;
4224 while ((cmdp = *pp) != NULL) {
4225 if ((cmdp->cmdtype == CMDNORMAL &&
4226 cmdp->param.index >= firstchange)
4227 || (cmdp->cmdtype == CMDBUILTIN &&
4228 builtinloc >= firstchange)) {
4229 *pp = cmdp->next;
4230 ckfree(cmdp);
4231 } else {
4232 pp = &cmdp->next;
4233 }
4234 }
4235 }
4236 INTON;
4237}
4238
Eric Andersen2870d962001-07-02 17:27:21 +00004239/*
4240 * Free a parse tree.
4241 */
4242
4243static void
4244freefunc(union node *n)
4245{
4246 if (n)
4247 ckfree(n);
4248}
4249
Eric Andersencb57d552001-06-28 07:25:16 +00004250
4251/*
4252 * Delete all functions.
4253 */
4254
Eric Andersencb57d552001-06-28 07:25:16 +00004255static void
Eric Andersen2870d962001-07-02 17:27:21 +00004256deletefuncs(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00004257 struct tblentry **tblp;
4258 struct tblentry **pp;
4259 struct tblentry *cmdp;
4260
4261 INTOFF;
4262 for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
4263 pp = tblp;
4264 while ((cmdp = *pp) != NULL) {
4265 if (cmdp->cmdtype == CMDFUNCTION) {
4266 *pp = cmdp->next;
4267 freefunc(cmdp->param.func);
4268 ckfree(cmdp);
4269 } else {
4270 pp = &cmdp->next;
4271 }
4272 }
4273 }
4274 INTON;
4275}
4276
4277
4278
4279/*
4280 * Locate a command in the command hash table. If "add" is nonzero,
4281 * add the command to the table if it is not already present. The
4282 * variable "lastcmdentry" is set to point to the address of the link
4283 * pointing to the entry, so that delete_cmd_entry can delete the
4284 * entry.
4285 */
4286
Eric Andersen2870d962001-07-02 17:27:21 +00004287static struct tblentry **lastcmdentry;
Eric Andersencb57d552001-06-28 07:25:16 +00004288
4289static struct tblentry *
Eric Andersen2870d962001-07-02 17:27:21 +00004290cmdlookup(const char *name, int add)
Eric Andersencb57d552001-06-28 07:25:16 +00004291{
4292 int hashval;
Eric Andersen2870d962001-07-02 17:27:21 +00004293 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +00004294 struct tblentry *cmdp;
4295 struct tblentry **pp;
4296
4297 p = name;
4298 hashval = *p << 4;
4299 while (*p)
4300 hashval += *p++;
4301 hashval &= 0x7FFF;
4302 pp = &cmdtable[hashval % CMDTABLESIZE];
4303 for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
4304 if (equal(cmdp->cmdname, name))
4305 break;
4306 pp = &cmdp->next;
4307 }
4308 if (add && cmdp == NULL) {
4309 INTOFF;
4310 cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB
4311 + strlen(name) + 1);
4312 cmdp->next = NULL;
4313 cmdp->cmdtype = CMDUNKNOWN;
4314 cmdp->rehash = 0;
4315 strcpy(cmdp->cmdname, name);
4316 INTON;
4317 }
4318 lastcmdentry = pp;
4319 return cmdp;
4320}
4321
4322/*
4323 * Delete the command entry returned on the last lookup.
4324 */
4325
4326static void
4327delete_cmd_entry() {
4328 struct tblentry *cmdp;
4329
4330 INTOFF;
4331 cmdp = *lastcmdentry;
4332 *lastcmdentry = cmdp->next;
4333 ckfree(cmdp);
4334 INTON;
4335}
4336
4337
4338
Eric Andersencb57d552001-06-28 07:25:16 +00004339/*
4340 * Add a new command entry, replacing any existing command entry for
4341 * the same name.
4342 */
4343
4344static void
Eric Andersen2870d962001-07-02 17:27:21 +00004345addcmdentry(char *name, struct cmdentry *entry)
4346{
Eric Andersencb57d552001-06-28 07:25:16 +00004347 struct tblentry *cmdp;
4348
4349 INTOFF;
4350 cmdp = cmdlookup(name, 1);
4351 if (cmdp->cmdtype == CMDFUNCTION) {
4352 freefunc(cmdp->param.func);
4353 }
4354 cmdp->cmdtype = entry->cmdtype;
4355 cmdp->param = entry->u;
4356 INTON;
4357}
4358
4359
4360/*
4361 * Define a shell function.
4362 */
4363
Eric Andersen2870d962001-07-02 17:27:21 +00004364static union node *copyfunc(union node *);
4365
Eric Andersencb57d552001-06-28 07:25:16 +00004366static void
Eric Andersen2870d962001-07-02 17:27:21 +00004367defun(char *name, union node *func)
4368{
Eric Andersencb57d552001-06-28 07:25:16 +00004369 struct cmdentry entry;
4370
4371 entry.cmdtype = CMDFUNCTION;
4372 entry.u.func = copyfunc(func);
4373 addcmdentry(name, &entry);
4374}
4375
4376
4377/*
4378 * Delete a function if it exists.
4379 */
4380
4381static void
Eric Andersen2870d962001-07-02 17:27:21 +00004382unsetfunc(char *name)
4383{
Eric Andersencb57d552001-06-28 07:25:16 +00004384 struct tblentry *cmdp;
4385
4386 if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) {
4387 freefunc(cmdp->param.func);
4388 delete_cmd_entry();
4389 }
4390}
4391
Eric Andersen2870d962001-07-02 17:27:21 +00004392/*
4393 * Wrapper around strcmp for qsort/bsearch/...
4394 */
4395static int
4396pstrcmp(const void *a, const void *b)
4397{
4398 return strcmp((const char *) a, *(const char *const *) b);
4399}
4400
4401/*
4402 * Find a keyword is in a sorted array.
4403 */
4404
4405static const char *const *
4406findkwd(const char *s)
4407{
4408 return bsearch(s, parsekwd, sizeof(parsekwd) / sizeof(const char *),
4409 sizeof(const char *), pstrcmp);
4410}
4411
Eric Andersencb57d552001-06-28 07:25:16 +00004412#ifdef ASH_TYPE
4413/*
4414 * Locate and print what a word is...
4415 */
4416
4417static int
4418typecmd(argc, argv)
4419 int argc;
4420 char **argv;
4421{
4422 int i;
4423 int err = 0;
4424
4425 for (i = 1; i < argc; i++) {
4426 err |= describe_command(argv[i], 1);
4427 }
4428 return err;
4429}
4430
4431static int
Eric Andersen2870d962001-07-02 17:27:21 +00004432describe_command(char *command, int verbose)
Eric Andersencb57d552001-06-28 07:25:16 +00004433{
4434 struct cmdentry entry;
4435 struct tblentry *cmdp;
Eric Andersen2870d962001-07-02 17:27:21 +00004436#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00004437 const struct alias *ap;
Eric Andersen2870d962001-07-02 17:27:21 +00004438#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004439 const char *path = pathval();
4440
4441 if (verbose) {
4442 out1str(command);
4443 }
4444
4445 /* First look at the keywords */
4446 if (findkwd(command)) {
4447 out1str(verbose ? " is a shell keyword" : command);
4448 goto out;
4449 }
4450
Eric Andersen2870d962001-07-02 17:27:21 +00004451#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00004452 /* Then look at the aliases */
4453 if ((ap = lookupalias(command, 0)) != NULL) {
4454 if (verbose) {
4455 out1fmt(" is an alias for %s", ap->val);
4456 } else {
4457 printalias(ap);
4458 }
4459 goto out;
4460 }
Eric Andersen2870d962001-07-02 17:27:21 +00004461#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004462 /* Then check if it is a tracked alias */
4463 if ((cmdp = cmdlookup(command, 0)) != NULL) {
4464 entry.cmdtype = cmdp->cmdtype;
4465 entry.u = cmdp->param;
4466 } else {
4467 /* Finally use brute force */
4468 find_command(command, &entry, DO_ABS, path);
4469 }
4470
4471 switch (entry.cmdtype) {
4472 case CMDNORMAL: {
4473 int j = entry.u.index;
4474 char *p;
4475 if (j == -1) {
4476 p = command;
4477 } else {
4478 do {
4479 p = padvance(&path, command);
4480 stunalloc(p);
4481 } while (--j >= 0);
4482 }
4483 if (verbose) {
4484 out1fmt(
4485 " is%s %s",
4486 cmdp ? " a tracked alias for" : nullstr, p
4487 );
4488 } else {
4489 out1str(p);
4490 }
4491 break;
4492 }
4493
4494 case CMDFUNCTION:
4495 if (verbose) {
4496 out1str(" is a shell function");
4497 } else {
4498 out1str(command);
4499 }
4500 break;
4501
4502 case CMDBUILTIN:
4503 if (verbose) {
4504 out1fmt(
4505 " is a %sshell builtin",
Eric Andersen2870d962001-07-02 17:27:21 +00004506 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
Eric Andersencb57d552001-06-28 07:25:16 +00004507 "special " : nullstr
4508 );
4509 } else {
4510 out1str(command);
4511 }
4512 break;
4513
4514 default:
4515 if (verbose) {
4516 out1str(": not found\n");
4517 }
4518 return 127;
4519 }
4520
4521out:
4522 out1c('\n');
4523 return 0;
4524}
Eric Andersen2870d962001-07-02 17:27:21 +00004525#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004526
Eric Andersen2870d962001-07-02 17:27:21 +00004527#ifdef ASH_CMDCMD
Eric Andersencb57d552001-06-28 07:25:16 +00004528static int
4529commandcmd(argc, argv)
4530 int argc;
4531 char **argv;
4532{
4533 int c;
4534 int default_path = 0;
4535 int verify_only = 0;
4536 int verbose_verify_only = 0;
4537
4538 while ((c = nextopt("pvV")) != '\0')
4539 switch (c) {
4540 case 'p':
4541 default_path = 1;
4542 break;
4543 case 'v':
4544 verify_only = 1;
4545 break;
4546 case 'V':
4547 verbose_verify_only = 1;
4548 break;
4549 default:
4550 outfmt(out2,
4551"command: nextopt returned character code 0%o\n", c);
4552 return EX_SOFTWARE;
4553 }
4554
4555 if (default_path + verify_only + verbose_verify_only > 1 ||
4556 !*argptr) {
4557 outfmt(out2,
4558"command [-p] command [arg ...]\n");
4559 outfmt(out2,
4560"command {-v|-V} command\n");
4561 return EX_USAGE;
4562 }
4563
4564#ifdef ASH_TYPE
4565 if (verify_only || verbose_verify_only) {
4566 return describe_command(*argptr, verbose_verify_only);
4567 }
Eric Andersen2870d962001-07-02 17:27:21 +00004568#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004569
4570 return 0;
4571}
Eric Andersen2870d962001-07-02 17:27:21 +00004572#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004573
4574static int
4575path_change(newval, bltin)
4576 const char *newval;
4577 int *bltin;
4578{
4579 const char *old, *new;
4580 int idx;
4581 int firstchange;
4582
4583 old = pathval();
4584 new = newval;
Eric Andersen2870d962001-07-02 17:27:21 +00004585 firstchange = 9999; /* assume no change */
Eric Andersencb57d552001-06-28 07:25:16 +00004586 idx = 0;
4587 *bltin = -1;
4588 for (;;) {
4589 if (*old != *new) {
4590 firstchange = idx;
4591 if ((*old == '\0' && *new == ':')
4592 || (*old == ':' && *new == '\0'))
4593 firstchange++;
Eric Andersen2870d962001-07-02 17:27:21 +00004594 old = new; /* ignore subsequent differences */
Eric Andersencb57d552001-06-28 07:25:16 +00004595 }
4596 if (*new == '\0')
4597 break;
4598 if (*new == '%' && *bltin < 0 && prefix("builtin", new + 1))
4599 *bltin = idx;
4600 if (*new == ':') {
4601 idx++;
4602 }
4603 new++, old++;
4604 }
4605 if (builtinloc >= 0 && *bltin < 0)
4606 firstchange = 0;
4607 return firstchange;
4608}
Eric Andersencb57d552001-06-28 07:25:16 +00004609/*
4610 * Routines to expand arguments to commands. We have to deal with
4611 * backquotes, shell variables, and file metacharacters.
4612 */
4613/*
4614 * _rmescape() flags
4615 */
Eric Andersen2870d962001-07-02 17:27:21 +00004616#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
4617#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Eric Andersencb57d552001-06-28 07:25:16 +00004618
4619/*
4620 * Structure specifying which parts of the string should be searched
4621 * for IFS characters.
4622 */
4623
4624struct ifsregion {
Eric Andersen2870d962001-07-02 17:27:21 +00004625 struct ifsregion *next; /* next region in list */
4626 int begoff; /* offset of start of region */
4627 int endoff; /* offset of end of region */
4628 int nulonly; /* search for nul bytes only */
Eric Andersencb57d552001-06-28 07:25:16 +00004629};
4630
4631
Eric Andersen2870d962001-07-02 17:27:21 +00004632static char *expdest; /* output of current string */
4633static struct nodelist *argbackq; /* list of back quote expressions */
4634static struct ifsregion ifsfirst; /* first struct in list of ifs regions */
4635static struct ifsregion *ifslastp; /* last struct in list */
4636static struct arglist exparg; /* holds expanded arg list */
Eric Andersencb57d552001-06-28 07:25:16 +00004637
Eric Andersen2870d962001-07-02 17:27:21 +00004638static void argstr (char *, int);
4639static char *exptilde (char *, int);
4640static void expbackq (union node *, int, int);
4641static int subevalvar (char *, char *, int, int, int, int, int);
4642static char *evalvar (char *, int);
4643static int varisset (char *, int);
4644static void strtodest (const char *, const char *, int);
4645static void varvalue (char *, int, int);
4646static void recordregion (int, int, int);
4647static void removerecordregions (int);
4648static void ifsbreakup (char *, struct arglist *);
4649static void ifsfree (void);
4650static void expandmeta (struct strlist *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004651#if defined(__GLIBC__) && !defined(FNMATCH_BROKEN)
4652#define preglob(p) _rmescapes((p), RMESCAPE_ALLOC | RMESCAPE_GLOB)
4653#if !defined(GLOB_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00004654static void addglob (const glob_t *);
Eric Andersencb57d552001-06-28 07:25:16 +00004655#endif
4656#endif
4657#if !(defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersen2870d962001-07-02 17:27:21 +00004658static void expmeta (char *, char *);
Eric Andersencb57d552001-06-28 07:25:16 +00004659#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004660#if !(defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
Eric Andersen2870d962001-07-02 17:27:21 +00004661static struct strlist *expsort (struct strlist *);
4662static struct strlist *msort (struct strlist *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004663#endif
4664#if defined(__GLIBC__) && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00004665static int patmatch (char *, char *, int);
4666static int patmatch2 (char *, char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004667#else
Eric Andersen2870d962001-07-02 17:27:21 +00004668static int pmatch (char *, char *, int);
Eric Andersencb57d552001-06-28 07:25:16 +00004669#define patmatch2 patmatch
4670#endif
Eric Andersen2870d962001-07-02 17:27:21 +00004671static char *cvtnum (int, char *);
Eric Andersencb57d552001-06-28 07:25:16 +00004672
4673/*
4674 * Expand shell variables and backquotes inside a here document.
4675 */
4676
Eric Andersen2870d962001-07-02 17:27:21 +00004677/* arg: the document, fd: where to write the expanded version */
Eric Andersencb57d552001-06-28 07:25:16 +00004678static void
Eric Andersen2870d962001-07-02 17:27:21 +00004679expandhere(union node *arg, int fd)
4680{
Eric Andersencb57d552001-06-28 07:25:16 +00004681 herefd = fd;
4682 expandarg(arg, (struct arglist *)NULL, 0);
4683 xwrite(fd, stackblock(), expdest - stackblock());
4684}
4685
4686
4687/*
4688 * Perform variable substitution and command substitution on an argument,
4689 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
4690 * perform splitting and file name expansion. When arglist is NULL, perform
4691 * here document expansion.
4692 */
4693
4694static void
4695expandarg(arg, arglist, flag)
4696 union node *arg;
4697 struct arglist *arglist;
4698 int flag;
4699{
4700 struct strlist *sp;
4701 char *p;
4702
4703 argbackq = arg->narg.backquote;
4704 STARTSTACKSTR(expdest);
4705 ifsfirst.next = NULL;
4706 ifslastp = NULL;
4707 argstr(arg->narg.text, flag);
4708 if (arglist == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00004709 return; /* here document expanded */
Eric Andersencb57d552001-06-28 07:25:16 +00004710 }
4711 STPUTC('\0', expdest);
4712 p = grabstackstr(expdest);
4713 exparg.lastp = &exparg.list;
4714 /*
4715 * TODO - EXP_REDIR
4716 */
4717 if (flag & EXP_FULL) {
4718 ifsbreakup(p, &exparg);
4719 *exparg.lastp = NULL;
4720 exparg.lastp = &exparg.list;
4721 expandmeta(exparg.list, flag);
4722 } else {
4723 if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */
4724 rmescapes(p);
4725 sp = (struct strlist *)stalloc(sizeof (struct strlist));
4726 sp->text = p;
4727 *exparg.lastp = sp;
4728 exparg.lastp = &sp->next;
4729 }
4730 ifsfree();
4731 *exparg.lastp = NULL;
4732 if (exparg.list) {
4733 *arglist->lastp = exparg.list;
4734 arglist->lastp = exparg.lastp;
4735 }
4736}
4737
4738
4739
4740/*
4741 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
4742 * characters to allow for further processing. Otherwise treat
4743 * $@ like $* since no splitting will be performed.
4744 */
4745
4746static void
4747argstr(p, flag)
4748 char *p;
4749 int flag;
4750{
4751 char c;
Eric Andersen2870d962001-07-02 17:27:21 +00004752 int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */
Eric Andersencb57d552001-06-28 07:25:16 +00004753 int firsteq = 1;
4754
4755 if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
4756 p = exptilde(p, flag);
4757 for (;;) {
4758 switch (c = *p++) {
4759 case '\0':
4760 case CTLENDVAR: /* ??? */
4761 goto breakloop;
4762 case CTLQUOTEMARK:
4763 /* "$@" syntax adherence hack */
4764 if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=')
4765 break;
4766 if ((flag & EXP_FULL) != 0)
4767 STPUTC(c, expdest);
4768 break;
4769 case CTLESC:
4770 if (quotes)
4771 STPUTC(c, expdest);
4772 c = *p++;
4773 STPUTC(c, expdest);
4774 break;
4775 case CTLVAR:
4776 p = evalvar(p, flag);
4777 break;
4778 case CTLBACKQ:
4779 case CTLBACKQ|CTLQUOTE:
4780 expbackq(argbackq->n, c & CTLQUOTE, flag);
4781 argbackq = argbackq->next;
4782 break;
4783#ifdef ASH_MATH_SUPPORT
4784 case CTLENDARI:
4785 expari(flag);
4786 break;
Eric Andersen2870d962001-07-02 17:27:21 +00004787#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004788 case ':':
4789 case '=':
4790 /*
4791 * sort of a hack - expand tildes in variable
4792 * assignments (after the first '=' and after ':'s).
4793 */
4794 STPUTC(c, expdest);
4795 if (flag & EXP_VARTILDE && *p == '~') {
4796 if (c == '=') {
4797 if (firsteq)
4798 firsteq = 0;
4799 else
4800 break;
4801 }
4802 p = exptilde(p, flag);
4803 }
4804 break;
4805 default:
4806 STPUTC(c, expdest);
4807 }
4808 }
4809breakloop:;
4810 return;
4811}
4812
4813static char *
4814exptilde(p, flag)
4815 char *p;
4816 int flag;
4817{
4818 char c, *startp = p;
4819 struct passwd *pw;
4820 const char *home;
4821 int quotes = flag & (EXP_FULL | EXP_CASE);
4822
4823 while ((c = *p) != '\0') {
4824 switch(c) {
4825 case CTLESC:
4826 return (startp);
4827 case CTLQUOTEMARK:
4828 return (startp);
4829 case ':':
4830 if (flag & EXP_VARTILDE)
4831 goto done;
4832 break;
4833 case '/':
4834 goto done;
4835 }
4836 p++;
4837 }
4838done:
4839 *p = '\0';
4840 if (*(startp+1) == '\0') {
4841 if ((home = lookupvar("HOME")) == NULL)
4842 goto lose;
4843 } else {
4844 if ((pw = getpwnam(startp+1)) == NULL)
4845 goto lose;
4846 home = pw->pw_dir;
4847 }
4848 if (*home == '\0')
4849 goto lose;
4850 *p = c;
4851 strtodest(home, SQSYNTAX, quotes);
4852 return (p);
4853lose:
4854 *p = c;
4855 return (startp);
4856}
4857
4858
Eric Andersen2870d962001-07-02 17:27:21 +00004859static void
4860removerecordregions(int endoff)
Eric Andersencb57d552001-06-28 07:25:16 +00004861{
4862 if (ifslastp == NULL)
4863 return;
4864
4865 if (ifsfirst.endoff > endoff) {
4866 while (ifsfirst.next != NULL) {
4867 struct ifsregion *ifsp;
4868 INTOFF;
4869 ifsp = ifsfirst.next->next;
4870 ckfree(ifsfirst.next);
4871 ifsfirst.next = ifsp;
4872 INTON;
4873 }
4874 if (ifsfirst.begoff > endoff)
4875 ifslastp = NULL;
4876 else {
4877 ifslastp = &ifsfirst;
4878 ifsfirst.endoff = endoff;
4879 }
4880 return;
4881 }
Eric Andersen2870d962001-07-02 17:27:21 +00004882
Eric Andersencb57d552001-06-28 07:25:16 +00004883 ifslastp = &ifsfirst;
4884 while (ifslastp->next && ifslastp->next->begoff < endoff)
4885 ifslastp=ifslastp->next;
4886 while (ifslastp->next != NULL) {
4887 struct ifsregion *ifsp;
4888 INTOFF;
4889 ifsp = ifslastp->next->next;
4890 ckfree(ifslastp->next);
4891 ifslastp->next = ifsp;
4892 INTON;
4893 }
4894 if (ifslastp->endoff > endoff)
4895 ifslastp->endoff = endoff;
4896}
4897
4898
4899#ifdef ASH_MATH_SUPPORT
4900/*
4901 * Expand arithmetic expression. Backup to start of expression,
4902 * evaluate, place result in (backed up) result, adjust string position.
4903 */
4904static void
Eric Andersen2870d962001-07-02 17:27:21 +00004905expari(int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00004906{
4907 char *p, *start;
4908 int result;
4909 int begoff;
4910 int quotes = flag & (EXP_FULL | EXP_CASE);
4911 int quoted;
4912
Eric Andersen2870d962001-07-02 17:27:21 +00004913 /* ifsfree(); */
Eric Andersencb57d552001-06-28 07:25:16 +00004914
4915 /*
4916 * This routine is slightly over-complicated for
4917 * efficiency. First we make sure there is
4918 * enough space for the result, which may be bigger
4919 * than the expression if we add exponentation. Next we
4920 * scan backwards looking for the start of arithmetic. If the
4921 * next previous character is a CTLESC character, then we
4922 * have to rescan starting from the beginning since CTLESC
4923 * characters have to be processed left to right.
4924 */
4925 CHECKSTRSPACE(10, expdest);
4926 USTPUTC('\0', expdest);
4927 start = stackblock();
4928 p = expdest - 1;
4929 while (*p != CTLARI && p >= start)
4930 --p;
4931 if (*p != CTLARI)
4932 error("missing CTLARI (shouldn't happen)");
4933 if (p > start && *(p-1) == CTLESC)
4934 for (p = start; *p != CTLARI; p++)
4935 if (*p == CTLESC)
4936 p++;
4937
4938 if (p[1] == '"')
4939 quoted=1;
4940 else
4941 quoted=0;
4942 begoff = p - start;
4943 removerecordregions(begoff);
4944 if (quotes)
4945 rmescapes(p+2);
4946 result = arith(p+2);
4947 fmtstr(p, 12, "%d", result);
4948
4949 while (*p++)
4950 ;
4951
4952 if (quoted == 0)
4953 recordregion(begoff, p - 1 - start, 0);
4954 result = expdest - p + 1;
4955 STADJUST(-result, expdest);
4956}
Eric Andersen2870d962001-07-02 17:27:21 +00004957#endif
Eric Andersencb57d552001-06-28 07:25:16 +00004958
4959/*
4960 * Expand stuff in backwards quotes.
4961 */
4962
4963static void
4964expbackq(cmd, quoted, flag)
4965 union node *cmd;
4966 int quoted;
4967 int flag;
4968{
4969 volatile struct backcmd in;
4970 int i;
4971 char buf[128];
4972 char *p;
4973 char *dest = expdest;
4974 volatile struct ifsregion saveifs;
4975 struct ifsregion *volatile savelastp;
4976 struct nodelist *volatile saveargbackq;
4977 char lastc;
4978 int startloc = dest - stackblock();
4979 char const *syntax = quoted? DQSYNTAX : BASESYNTAX;
4980 volatile int saveherefd;
4981 int quotes = flag & (EXP_FULL | EXP_CASE);
4982 struct jmploc jmploc;
4983 struct jmploc *volatile savehandler;
4984 int ex;
4985
4986#if __GNUC__
4987 /* Avoid longjmp clobbering */
4988 (void) &dest;
4989 (void) &syntax;
4990#endif
4991
4992 in.fd = -1;
4993 in.buf = 0;
4994 in.jp = 0;
4995
4996 INTOFF;
4997 saveifs = ifsfirst;
4998 savelastp = ifslastp;
4999 saveargbackq = argbackq;
5000 saveherefd = herefd;
5001 herefd = -1;
5002 if ((ex = setjmp(jmploc.loc))) {
5003 goto err1;
5004 }
5005 savehandler = handler;
5006 handler = &jmploc;
5007 INTON;
5008 p = grabstackstr(dest);
5009 evalbackcmd(cmd, (struct backcmd *) &in);
5010 ungrabstackstr(p, dest);
5011err1:
5012 INTOFF;
5013 ifsfirst = saveifs;
5014 ifslastp = savelastp;
5015 argbackq = saveargbackq;
5016 herefd = saveherefd;
5017 if (ex) {
5018 goto err2;
5019 }
5020
5021 p = in.buf;
5022 lastc = '\0';
5023 for (;;) {
5024 if (--in.nleft < 0) {
5025 if (in.fd < 0)
5026 break;
5027 while ((i = read(in.fd, buf, sizeof buf)) < 0 && errno == EINTR);
5028 TRACE(("expbackq: read returns %d\n", i));
5029 if (i <= 0)
5030 break;
5031 p = buf;
5032 in.nleft = i - 1;
5033 }
5034 lastc = *p++;
5035 if (lastc != '\0') {
5036 if (quotes && syntax[(int)lastc] == CCTL)
5037 STPUTC(CTLESC, dest);
5038 STPUTC(lastc, dest);
5039 }
5040 }
5041
5042 /* Eat all trailing newlines */
5043 for (; dest > stackblock() && dest[-1] == '\n';)
5044 STUNPUTC(dest);
5045
5046err2:
5047 if (in.fd >= 0)
5048 close(in.fd);
5049 if (in.buf)
5050 ckfree(in.buf);
5051 if (in.jp)
5052 exitstatus = waitforjob(in.jp);
5053 handler = savehandler;
5054 if (ex) {
5055 longjmp(handler->loc, 1);
5056 }
5057 if (quoted == 0)
5058 recordregion(startloc, dest - stackblock(), 0);
5059 TRACE(("evalbackq: size=%d: \"%.*s\"\n",
5060 (dest - stackblock()) - startloc,
5061 (dest - stackblock()) - startloc,
5062 stackblock() + startloc));
5063 expdest = dest;
5064 INTON;
5065}
5066
Eric Andersencb57d552001-06-28 07:25:16 +00005067static int
5068subevalvar(p, str, strloc, subtype, startloc, varflags, quotes)
5069 char *p;
5070 char *str;
5071 int strloc;
5072 int subtype;
5073 int startloc;
5074 int varflags;
5075 int quotes;
5076{
5077 char *startp;
5078 char *loc = NULL;
5079 char *q;
5080 int c = 0;
5081 int saveherefd = herefd;
5082 struct nodelist *saveargbackq = argbackq;
5083 int amount;
5084
5085 herefd = -1;
5086 argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0);
5087 STACKSTRNUL(expdest);
5088 herefd = saveherefd;
5089 argbackq = saveargbackq;
5090 startp = stackblock() + startloc;
5091 if (str == NULL)
5092 str = stackblock() + strloc;
5093
5094 switch (subtype) {
5095 case VSASSIGN:
5096 setvar(str, startp, 0);
5097 amount = startp - expdest;
5098 STADJUST(amount, expdest);
5099 varflags &= ~VSNUL;
5100 if (c != 0)
5101 *loc = c;
5102 return 1;
5103
5104 case VSQUESTION:
5105 if (*p != CTLENDVAR) {
5106 outfmt(&errout, snlfmt, startp);
5107 error((char *)NULL);
5108 }
5109 error("%.*s: parameter %snot set", p - str - 1,
5110 str, (varflags & VSNUL) ? "null or "
5111 : nullstr);
5112 /* NOTREACHED */
5113
5114 case VSTRIMLEFT:
5115 for (loc = startp; loc < str; loc++) {
5116 c = *loc;
5117 *loc = '\0';
5118 if (patmatch2(str, startp, quotes))
5119 goto recordleft;
5120 *loc = c;
5121 if (quotes && *loc == CTLESC)
Eric Andersen2870d962001-07-02 17:27:21 +00005122 loc++;
Eric Andersencb57d552001-06-28 07:25:16 +00005123 }
5124 return 0;
5125
5126 case VSTRIMLEFTMAX:
5127 for (loc = str - 1; loc >= startp;) {
5128 c = *loc;
5129 *loc = '\0';
5130 if (patmatch2(str, startp, quotes))
5131 goto recordleft;
5132 *loc = c;
5133 loc--;
5134 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
5135 for (q = startp; q < loc; q++)
5136 if (*q == CTLESC)
5137 q++;
5138 if (q > loc)
5139 loc--;
5140 }
5141 }
5142 return 0;
5143
5144 case VSTRIMRIGHT:
Eric Andersen2870d962001-07-02 17:27:21 +00005145 for (loc = str - 1; loc >= startp;) {
Eric Andersencb57d552001-06-28 07:25:16 +00005146 if (patmatch2(str, loc, quotes))
5147 goto recordright;
5148 loc--;
Eric Andersen2870d962001-07-02 17:27:21 +00005149 if (quotes && loc > startp && *(loc - 1) == CTLESC) {
Eric Andersencb57d552001-06-28 07:25:16 +00005150 for (q = startp; q < loc; q++)
5151 if (*q == CTLESC)
5152 q++;
5153 if (q > loc)
5154 loc--;
5155 }
5156 }
5157 return 0;
5158
5159 case VSTRIMRIGHTMAX:
5160 for (loc = startp; loc < str - 1; loc++) {
5161 if (patmatch2(str, loc, quotes))
5162 goto recordright;
5163 if (quotes && *loc == CTLESC)
Eric Andersen2870d962001-07-02 17:27:21 +00005164 loc++;
Eric Andersencb57d552001-06-28 07:25:16 +00005165 }
5166 return 0;
5167
5168#ifdef DEBUG
5169 default:
5170 abort();
5171#endif
5172 }
5173
5174recordleft:
5175 *loc = c;
5176 amount = ((str - 1) - (loc - startp)) - expdest;
5177 STADJUST(amount, expdest);
5178 while (loc != str - 1)
5179 *startp++ = *loc++;
5180 return 1;
5181
5182recordright:
5183 amount = loc - expdest;
5184 STADJUST(amount, expdest);
5185 STPUTC('\0', expdest);
5186 STADJUST(-1, expdest);
5187 return 1;
5188}
5189
5190
5191/*
5192 * Expand a variable, and return a pointer to the next character in the
5193 * input string.
5194 */
5195
5196static char *
5197evalvar(p, flag)
5198 char *p;
5199 int flag;
5200{
5201 int subtype;
5202 int varflags;
5203 char *var;
5204 char *val;
5205 int patloc;
5206 int c;
5207 int set;
5208 int special;
5209 int startloc;
5210 int varlen;
5211 int easy;
5212 int quotes = flag & (EXP_FULL | EXP_CASE);
5213
5214 varflags = *p++;
5215 subtype = varflags & VSTYPE;
5216 var = p;
5217 special = 0;
5218 if (! is_name(*p))
5219 special = 1;
5220 p = strchr(p, '=') + 1;
5221again: /* jump here after setting a variable with ${var=text} */
5222 if (special) {
5223 set = varisset(var, varflags & VSNUL);
5224 val = NULL;
5225 } else {
5226 val = lookupvar(var);
5227 if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
5228 val = NULL;
5229 set = 0;
5230 } else
5231 set = 1;
5232 }
5233 varlen = 0;
5234 startloc = expdest - stackblock();
5235 if (set && subtype != VSPLUS) {
5236 /* insert the value of the variable */
5237 if (special) {
5238 varvalue(var, varflags & VSQUOTE, flag);
5239 if (subtype == VSLENGTH) {
5240 varlen = expdest - stackblock() - startloc;
5241 STADJUST(-varlen, expdest);
5242 }
5243 } else {
5244 if (subtype == VSLENGTH) {
5245 varlen = strlen(val);
5246 } else {
5247 strtodest(
5248 val,
5249 varflags & VSQUOTE ?
5250 DQSYNTAX : BASESYNTAX,
5251 quotes
5252 );
5253 }
5254 }
5255 }
5256
5257 if (subtype == VSPLUS)
5258 set = ! set;
5259
5260 easy = ((varflags & VSQUOTE) == 0 ||
5261 (*var == '@' && shellparam.nparam != 1));
5262
5263
5264 switch (subtype) {
5265 case VSLENGTH:
5266 expdest = cvtnum(varlen, expdest);
5267 goto record;
5268
5269 case VSNORMAL:
5270 if (!easy)
5271 break;
5272record:
5273 recordregion(startloc, expdest - stackblock(),
5274 varflags & VSQUOTE);
5275 break;
5276
5277 case VSPLUS:
5278 case VSMINUS:
5279 if (!set) {
Eric Andersen2870d962001-07-02 17:27:21 +00005280 argstr(p, flag);
Eric Andersencb57d552001-06-28 07:25:16 +00005281 break;
5282 }
5283 if (easy)
5284 goto record;
5285 break;
5286
5287 case VSTRIMLEFT:
5288 case VSTRIMLEFTMAX:
5289 case VSTRIMRIGHT:
5290 case VSTRIMRIGHTMAX:
5291 if (!set)
5292 break;
5293 /*
5294 * Terminate the string and start recording the pattern
5295 * right after it
5296 */
5297 STPUTC('\0', expdest);
5298 patloc = expdest - stackblock();
5299 if (subevalvar(p, NULL, patloc, subtype,
5300 startloc, varflags, quotes) == 0) {
5301 int amount = (expdest - stackblock() - patloc) + 1;
5302 STADJUST(-amount, expdest);
5303 }
5304 /* Remove any recorded regions beyond start of variable */
5305 removerecordregions(startloc);
5306 goto record;
5307
5308 case VSASSIGN:
5309 case VSQUESTION:
5310 if (!set) {
5311 if (subevalvar(p, var, 0, subtype, startloc,
5312 varflags, quotes)) {
5313 varflags &= ~VSNUL;
Eric Andersen2870d962001-07-02 17:27:21 +00005314 /*
5315 * Remove any recorded regions beyond
5316 * start of variable
Eric Andersencb57d552001-06-28 07:25:16 +00005317 */
5318 removerecordregions(startloc);
5319 goto again;
5320 }
5321 break;
5322 }
5323 if (easy)
5324 goto record;
5325 break;
5326
5327#ifdef DEBUG
5328 default:
5329 abort();
5330#endif
5331 }
5332
Eric Andersen2870d962001-07-02 17:27:21 +00005333 if (subtype != VSNORMAL) { /* skip to end of alternative */
Eric Andersencb57d552001-06-28 07:25:16 +00005334 int nesting = 1;
5335 for (;;) {
5336 if ((c = *p++) == CTLESC)
5337 p++;
5338 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
5339 if (set)
5340 argbackq = argbackq->next;
5341 } else if (c == CTLVAR) {
5342 if ((*p++ & VSTYPE) != VSNORMAL)
5343 nesting++;
5344 } else if (c == CTLENDVAR) {
5345 if (--nesting == 0)
5346 break;
5347 }
5348 }
5349 }
5350 return p;
5351}
5352
Eric Andersencb57d552001-06-28 07:25:16 +00005353/*
5354 * Test whether a specialized variable is set.
5355 */
5356
5357static int
5358varisset(name, nulok)
5359 char *name;
5360 int nulok;
5361{
5362 if (*name == '!')
5363 return backgndpid != -1;
5364 else if (*name == '@' || *name == '*') {
5365 if (*shellparam.p == NULL)
5366 return 0;
5367
5368 if (nulok) {
5369 char **av;
5370
5371 for (av = shellparam.p; *av; av++)
5372 if (**av != '\0')
5373 return 1;
5374 return 0;
5375 }
5376 } else if (is_digit(*name)) {
5377 char *ap;
5378 int num = atoi(name);
5379
5380 if (num > shellparam.nparam)
5381 return 0;
5382
5383 if (num == 0)
5384 ap = arg0;
5385 else
5386 ap = shellparam.p[num - 1];
5387
5388 if (nulok && (ap == NULL || *ap == '\0'))
5389 return 0;
5390 }
5391 return 1;
5392}
5393
Eric Andersencb57d552001-06-28 07:25:16 +00005394/*
5395 * Put a string on the stack.
5396 */
5397
5398static void
5399strtodest(p, syntax, quotes)
5400 const char *p;
5401 const char *syntax;
5402 int quotes;
5403{
5404 while (*p) {
5405 if (quotes && syntax[(int) *p] == CCTL)
5406 STPUTC(CTLESC, expdest);
5407 STPUTC(*p++, expdest);
5408 }
5409}
5410
Eric Andersencb57d552001-06-28 07:25:16 +00005411/*
5412 * Add the value of a specialized variable to the stack string.
5413 */
5414
5415static void
5416varvalue(name, quoted, flags)
5417 char *name;
5418 int quoted;
5419 int flags;
5420{
5421 int num;
5422 char *p;
5423 int i;
5424 int sep;
5425 int sepq = 0;
5426 char **ap;
5427 char const *syntax;
5428 int allow_split = flags & EXP_FULL;
5429 int quotes = flags & (EXP_FULL | EXP_CASE);
5430
5431 syntax = quoted ? DQSYNTAX : BASESYNTAX;
5432 switch (*name) {
5433 case '$':
5434 num = rootpid;
5435 goto numvar;
5436 case '?':
5437 num = oexitstatus;
5438 goto numvar;
5439 case '#':
5440 num = shellparam.nparam;
5441 goto numvar;
5442 case '!':
5443 num = backgndpid;
5444numvar:
5445 expdest = cvtnum(num, expdest);
5446 break;
5447 case '-':
5448 for (i = 0 ; i < NOPTS ; i++) {
Eric Andersen2870d962001-07-02 17:27:21 +00005449 if (optent_val(i))
5450 STPUTC(optent_letter(optlist[i]), expdest);
Eric Andersencb57d552001-06-28 07:25:16 +00005451 }
5452 break;
5453 case '@':
5454 if (allow_split && quoted) {
5455 sep = 1 << CHAR_BIT;
5456 goto param;
5457 }
5458 /* fall through */
5459 case '*':
5460 sep = ifsset() ? ifsval()[0] : ' ';
5461 if (quotes) {
5462 sepq = syntax[(int) sep] == CCTL;
5463 }
5464param:
5465 for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
5466 strtodest(p, syntax, quotes);
5467 if (*ap && sep) {
5468 if (sepq)
5469 STPUTC(CTLESC, expdest);
5470 STPUTC(sep, expdest);
5471 }
5472 }
5473 break;
5474 case '0':
5475 strtodest(arg0, syntax, quotes);
5476 break;
5477 default:
5478 num = atoi(name);
5479 if (num > 0 && num <= shellparam.nparam) {
5480 strtodest(shellparam.p[num - 1], syntax, quotes);
5481 }
5482 break;
5483 }
5484}
5485
5486
Eric Andersencb57d552001-06-28 07:25:16 +00005487/*
5488 * Record the fact that we have to scan this region of the
5489 * string for IFS characters.
5490 */
5491
5492static void
5493recordregion(start, end, nulonly)
5494 int start;
5495 int end;
5496 int nulonly;
5497{
5498 struct ifsregion *ifsp;
5499
5500 if (ifslastp == NULL) {
5501 ifsp = &ifsfirst;
5502 } else {
5503 INTOFF;
5504 ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion));
5505 ifsp->next = NULL;
5506 ifslastp->next = ifsp;
5507 INTON;
5508 }
5509 ifslastp = ifsp;
5510 ifslastp->begoff = start;
5511 ifslastp->endoff = end;
5512 ifslastp->nulonly = nulonly;
5513}
5514
5515
5516
5517/*
5518 * Break the argument string into pieces based upon IFS and add the
5519 * strings to the argument list. The regions of the string to be
5520 * searched for IFS characters have been stored by recordregion.
5521 */
5522static void
5523ifsbreakup(string, arglist)
5524 char *string;
5525 struct arglist *arglist;
5526 {
5527 struct ifsregion *ifsp;
5528 struct strlist *sp;
5529 char *start;
5530 char *p;
5531 char *q;
5532 const char *ifs, *realifs;
5533 int ifsspc;
5534 int nulonly;
5535
5536
5537 start = string;
5538 ifsspc = 0;
5539 nulonly = 0;
5540 realifs = ifsset() ? ifsval() : defifs;
5541 if (ifslastp != NULL) {
5542 ifsp = &ifsfirst;
5543 do {
5544 p = string + ifsp->begoff;
5545 nulonly = ifsp->nulonly;
5546 ifs = nulonly ? nullstr : realifs;
5547 ifsspc = 0;
5548 while (p < string + ifsp->endoff) {
5549 q = p;
5550 if (*p == CTLESC)
5551 p++;
5552 if (strchr(ifs, *p)) {
5553 if (!nulonly)
5554 ifsspc = (strchr(defifs, *p) != NULL);
5555 /* Ignore IFS whitespace at start */
5556 if (q == start && ifsspc) {
5557 p++;
5558 start = p;
5559 continue;
5560 }
5561 *q = '\0';
5562 sp = (struct strlist *)stalloc(sizeof *sp);
5563 sp->text = start;
5564 *arglist->lastp = sp;
5565 arglist->lastp = &sp->next;
5566 p++;
5567 if (!nulonly) {
5568 for (;;) {
5569 if (p >= string + ifsp->endoff) {
5570 break;
5571 }
5572 q = p;
5573 if (*p == CTLESC)
5574 p++;
5575 if (strchr(ifs, *p) == NULL ) {
5576 p = q;
5577 break;
5578 } else if (strchr(defifs, *p) == NULL) {
5579 if (ifsspc) {
5580 p++;
5581 ifsspc = 0;
5582 } else {
5583 p = q;
5584 break;
5585 }
5586 } else
5587 p++;
5588 }
5589 }
5590 start = p;
5591 } else
5592 p++;
5593 }
5594 } while ((ifsp = ifsp->next) != NULL);
5595 if (!(*start || (!ifsspc && start > string && nulonly))) {
5596 return;
5597 }
5598 }
5599
5600 sp = (struct strlist *)stalloc(sizeof *sp);
5601 sp->text = start;
5602 *arglist->lastp = sp;
5603 arglist->lastp = &sp->next;
5604}
5605
5606static void
5607ifsfree()
5608{
5609 while (ifsfirst.next != NULL) {
5610 struct ifsregion *ifsp;
5611 INTOFF;
5612 ifsp = ifsfirst.next->next;
5613 ckfree(ifsfirst.next);
5614 ifsfirst.next = ifsp;
5615 INTON;
5616 }
5617 ifslastp = NULL;
5618 ifsfirst.next = NULL;
5619}
5620
Eric Andersen2870d962001-07-02 17:27:21 +00005621/*
5622 * Add a file name to the list.
5623 */
Eric Andersencb57d552001-06-28 07:25:16 +00005624
Eric Andersen2870d962001-07-02 17:27:21 +00005625static void
5626addfname(const char *name)
5627{
5628 char *p;
5629 struct strlist *sp;
5630
5631 p = sstrdup(name);
5632 sp = (struct strlist *)stalloc(sizeof *sp);
5633 sp->text = p;
5634 *exparg.lastp = sp;
5635 exparg.lastp = &sp->next;
5636}
Eric Andersencb57d552001-06-28 07:25:16 +00005637
5638/*
5639 * Expand shell metacharacters. At this point, the only control characters
5640 * should be escapes. The results are stored in the list exparg.
5641 */
5642
5643#if defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)
5644static void
5645expandmeta(str, flag)
5646 struct strlist *str;
5647 int flag;
5648{
5649 const char *p;
5650 glob_t pglob;
5651 /* TODO - EXP_REDIR */
5652
5653 while (str) {
5654 if (fflag)
5655 goto nometa;
5656 p = preglob(str->text);
5657 INTOFF;
5658 switch (glob(p, GLOB_NOMAGIC, 0, &pglob)) {
5659 case 0:
5660 if (!(pglob.gl_flags & GLOB_MAGCHAR))
5661 goto nometa2;
5662 addglob(&pglob);
5663 globfree(&pglob);
5664 INTON;
5665 break;
5666 case GLOB_NOMATCH:
5667nometa2:
5668 globfree(&pglob);
5669 INTON;
5670nometa:
5671 *exparg.lastp = str;
5672 rmescapes(str->text);
5673 exparg.lastp = &str->next;
5674 break;
Eric Andersen2870d962001-07-02 17:27:21 +00005675 default: /* GLOB_NOSPACE */
Eric Andersencb57d552001-06-28 07:25:16 +00005676 error("Out of space");
5677 }
5678 str = str->next;
5679 }
5680}
5681
5682
5683/*
5684 * Add the result of glob(3) to the list.
5685 */
5686
5687static void
5688addglob(pglob)
5689 const glob_t *pglob;
5690{
5691 char **p = pglob->gl_pathv;
5692
5693 do {
5694 addfname(*p);
5695 } while (*++p);
5696}
5697
5698
Eric Andersen2870d962001-07-02 17:27:21 +00005699#else /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
Eric Andersencb57d552001-06-28 07:25:16 +00005700static char *expdir;
5701
5702
5703static void
5704expandmeta(str, flag)
5705 struct strlist *str;
5706 int flag;
5707{
5708 char *p;
5709 struct strlist **savelastp;
5710 struct strlist *sp;
5711 char c;
5712 /* TODO - EXP_REDIR */
5713
5714 while (str) {
5715 if (fflag)
5716 goto nometa;
5717 p = str->text;
Eric Andersen2870d962001-07-02 17:27:21 +00005718 for (;;) { /* fast check for meta chars */
Eric Andersencb57d552001-06-28 07:25:16 +00005719 if ((c = *p++) == '\0')
5720 goto nometa;
5721 if (c == '*' || c == '?' || c == '[' || c == '!')
5722 break;
5723 }
5724 savelastp = exparg.lastp;
5725 INTOFF;
5726 if (expdir == NULL) {
5727 int i = strlen(str->text);
5728 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
5729 }
5730
5731 expmeta(expdir, str->text);
5732 ckfree(expdir);
5733 expdir = NULL;
5734 INTON;
5735 if (exparg.lastp == savelastp) {
5736 /*
5737 * no matches
5738 */
5739nometa:
5740 *exparg.lastp = str;
5741 rmescapes(str->text);
5742 exparg.lastp = &str->next;
5743 } else {
5744 *exparg.lastp = NULL;
5745 *savelastp = sp = expsort(*savelastp);
5746 while (sp->next != NULL)
5747 sp = sp->next;
5748 exparg.lastp = &sp->next;
5749 }
5750 str = str->next;
5751 }
5752}
5753
5754
5755/*
5756 * Do metacharacter (i.e. *, ?, [...]) expansion.
5757 */
5758
5759static void
5760expmeta(enddir, name)
5761 char *enddir;
5762 char *name;
5763 {
5764 char *p;
5765 const char *cp;
5766 char *q;
5767 char *start;
5768 char *endname;
5769 int metaflag;
5770 struct stat statb;
5771 DIR *dirp;
5772 struct dirent *dp;
5773 int atend;
5774 int matchdot;
5775
5776 metaflag = 0;
5777 start = name;
5778 for (p = name ; ; p++) {
5779 if (*p == '*' || *p == '?')
5780 metaflag = 1;
5781 else if (*p == '[') {
5782 q = p + 1;
5783 if (*q == '!')
5784 q++;
5785 for (;;) {
5786 while (*q == CTLQUOTEMARK)
5787 q++;
5788 if (*q == CTLESC)
5789 q++;
5790 if (*q == '/' || *q == '\0')
5791 break;
5792 if (*++q == ']') {
5793 metaflag = 1;
5794 break;
5795 }
5796 }
Eric Andersen2870d962001-07-02 17:27:21 +00005797 } else if (*p == '!' && p[1] == '!' && (p == name || p[-1] == '/')) {
Eric Andersencb57d552001-06-28 07:25:16 +00005798 metaflag = 1;
5799 } else if (*p == '\0')
5800 break;
5801 else if (*p == CTLQUOTEMARK)
5802 continue;
5803 else if (*p == CTLESC)
5804 p++;
5805 if (*p == '/') {
5806 if (metaflag)
5807 break;
5808 start = p + 1;
5809 }
5810 }
Eric Andersen2870d962001-07-02 17:27:21 +00005811 if (metaflag == 0) { /* we've reached the end of the file name */
Eric Andersencb57d552001-06-28 07:25:16 +00005812 if (enddir != expdir)
5813 metaflag++;
5814 for (p = name ; ; p++) {
5815 if (*p == CTLQUOTEMARK)
5816 continue;
5817 if (*p == CTLESC)
5818 p++;
5819 *enddir++ = *p;
5820 if (*p == '\0')
5821 break;
5822 }
5823 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
5824 addfname(expdir);
5825 return;
5826 }
5827 endname = p;
5828 if (start != name) {
5829 p = name;
5830 while (p < start) {
5831 while (*p == CTLQUOTEMARK)
5832 p++;
5833 if (*p == CTLESC)
5834 p++;
5835 *enddir++ = *p++;
5836 }
5837 }
5838 if (enddir == expdir) {
5839 cp = ".";
5840 } else if (enddir == expdir + 1 && *expdir == '/') {
5841 cp = "/";
5842 } else {
5843 cp = expdir;
5844 enddir[-1] = '\0';
5845 }
5846 if ((dirp = opendir(cp)) == NULL)
5847 return;
5848 if (enddir != expdir)
5849 enddir[-1] = '/';
5850 if (*endname == 0) {
5851 atend = 1;
5852 } else {
5853 atend = 0;
5854 *endname++ = '\0';
5855 }
5856 matchdot = 0;
5857 p = start;
5858 while (*p == CTLQUOTEMARK)
5859 p++;
5860 if (*p == CTLESC)
5861 p++;
5862 if (*p == '.')
5863 matchdot++;
5864 while (! int_pending() && (dp = readdir(dirp)) != NULL) {
5865 if (dp->d_name[0] == '.' && ! matchdot)
5866 continue;
5867 if (patmatch(start, dp->d_name, 0)) {
5868 if (atend) {
Eric Andersen2870d962001-07-02 17:27:21 +00005869 strcpy(enddir, dp->d_name);
Eric Andersencb57d552001-06-28 07:25:16 +00005870 addfname(expdir);
5871 } else {
5872 for (p = enddir, cp = dp->d_name;
5873 (*p++ = *cp++) != '\0';)
5874 continue;
5875 p[-1] = '/';
5876 expmeta(p, endname);
5877 }
5878 }
5879 }
5880 closedir(dirp);
5881 if (! atend)
5882 endname[-1] = '/';
5883}
Eric Andersen2870d962001-07-02 17:27:21 +00005884#endif /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */
Eric Andersencb57d552001-06-28 07:25:16 +00005885
5886
Eric Andersencb57d552001-06-28 07:25:16 +00005887
5888#if !(defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN))
5889/*
5890 * Sort the results of file name expansion. It calculates the number of
5891 * strings to sort and then calls msort (short for merge sort) to do the
5892 * work.
5893 */
5894
5895static struct strlist *
5896expsort(str)
5897 struct strlist *str;
5898 {
5899 int len;
5900 struct strlist *sp;
5901
5902 len = 0;
5903 for (sp = str ; sp ; sp = sp->next)
5904 len++;
5905 return msort(str, len);
5906}
5907
5908
5909static struct strlist *
5910msort(list, len)
5911 struct strlist *list;
5912 int len;
5913{
5914 struct strlist *p, *q = NULL;
5915 struct strlist **lpp;
5916 int half;
5917 int n;
5918
5919 if (len <= 1)
5920 return list;
5921 half = len >> 1;
5922 p = list;
5923 for (n = half ; --n >= 0 ; ) {
5924 q = p;
5925 p = p->next;
5926 }
Eric Andersen2870d962001-07-02 17:27:21 +00005927 q->next = NULL; /* terminate first half of list */
5928 q = msort(list, half); /* sort first half of list */
5929 p = msort(p, len - half); /* sort second half */
Eric Andersencb57d552001-06-28 07:25:16 +00005930 lpp = &list;
5931 for (;;) {
5932 if (strcmp(p->text, q->text) < 0) {
5933 *lpp = p;
5934 lpp = &p->next;
5935 if ((p = *lpp) == NULL) {
5936 *lpp = q;
5937 break;
5938 }
5939 } else {
5940 *lpp = q;
5941 lpp = &q->next;
5942 if ((q = *lpp) == NULL) {
5943 *lpp = p;
5944 break;
5945 }
5946 }
5947 }
5948 return list;
5949}
5950#endif
5951
5952
5953
5954/*
5955 * Returns true if the pattern matches the string.
5956 */
5957
5958#if defined(__GLIBC__) && !defined(FNMATCH_BROKEN)
Eric Andersen2870d962001-07-02 17:27:21 +00005959/* squoted: string might have quote chars */
Eric Andersencb57d552001-06-28 07:25:16 +00005960static int
Eric Andersen2870d962001-07-02 17:27:21 +00005961patmatch(char *pattern, char *string, int squoted)
5962{
Eric Andersencb57d552001-06-28 07:25:16 +00005963 const char *p;
5964 char *q;
5965
5966 p = preglob(pattern);
5967 q = squoted ? _rmescapes(string, RMESCAPE_ALLOC) : string;
5968
5969 return !fnmatch(p, q, 0);
5970}
5971
5972
5973static int
Eric Andersen2870d962001-07-02 17:27:21 +00005974patmatch2(char *pattern, char *string, int squoted)
5975{
Eric Andersencb57d552001-06-28 07:25:16 +00005976 char *p;
5977 int res;
5978
5979 sstrnleft--;
5980 p = grabstackstr(expdest);
5981 res = patmatch(pattern, string, squoted);
5982 ungrabstackstr(p, expdest);
5983 return res;
5984}
5985#else
5986static int
Eric Andersen2870d962001-07-02 17:27:21 +00005987patmatch(char *pattern, char *string, int squoted) {
5988 return pmatch(pattern, string, squoted);
Eric Andersencb57d552001-06-28 07:25:16 +00005989}
5990
5991
5992static int
Eric Andersen2870d962001-07-02 17:27:21 +00005993pmatch(char *pattern, char *string, int squoted)
5994{
Eric Andersencb57d552001-06-28 07:25:16 +00005995 char *p, *q;
5996 char c;
5997
5998 p = pattern;
5999 q = string;
6000 for (;;) {
6001 switch (c = *p++) {
6002 case '\0':
6003 goto breakloop;
6004 case CTLESC:
6005 if (squoted && *q == CTLESC)
6006 q++;
6007 if (*q++ != *p++)
6008 return 0;
6009 break;
6010 case CTLQUOTEMARK:
6011 continue;
6012 case '?':
6013 if (squoted && *q == CTLESC)
6014 q++;
6015 if (*q++ == '\0')
6016 return 0;
6017 break;
6018 case '*':
6019 c = *p;
6020 while (c == CTLQUOTEMARK || c == '*')
6021 c = *++p;
6022 if (c != CTLESC && c != CTLQUOTEMARK &&
6023 c != '?' && c != '*' && c != '[') {
6024 while (*q != c) {
6025 if (squoted && *q == CTLESC &&
6026 q[1] == c)
6027 break;
6028 if (*q == '\0')
6029 return 0;
6030 if (squoted && *q == CTLESC)
6031 q++;
6032 q++;
6033 }
6034 }
6035 do {
6036 if (pmatch(p, q, squoted))
6037 return 1;
6038 if (squoted && *q == CTLESC)
6039 q++;
6040 } while (*q++ != '\0');
6041 return 0;
6042 case '[': {
6043 char *endp;
6044 int invert, found;
6045 char chr;
6046
6047 endp = p;
6048 if (*endp == '!')
6049 endp++;
6050 for (;;) {
6051 while (*endp == CTLQUOTEMARK)
6052 endp++;
6053 if (*endp == '\0')
Eric Andersen2870d962001-07-02 17:27:21 +00006054 goto dft; /* no matching ] */
Eric Andersencb57d552001-06-28 07:25:16 +00006055 if (*endp == CTLESC)
6056 endp++;
6057 if (*++endp == ']')
6058 break;
6059 }
6060 invert = 0;
6061 if (*p == '!') {
6062 invert++;
6063 p++;
6064 }
6065 found = 0;
6066 chr = *q++;
6067 if (squoted && chr == CTLESC)
6068 chr = *q++;
6069 if (chr == '\0')
6070 return 0;
6071 c = *p++;
6072 do {
6073 if (c == CTLQUOTEMARK)
6074 continue;
6075 if (c == CTLESC)
6076 c = *p++;
6077 if (*p == '-' && p[1] != ']') {
6078 p++;
6079 while (*p == CTLQUOTEMARK)
6080 p++;
6081 if (*p == CTLESC)
6082 p++;
6083 if (chr >= c && chr <= *p)
6084 found = 1;
6085 p++;
6086 } else {
6087 if (chr == c)
6088 found = 1;
6089 }
6090 } while ((c = *p++) != ']');
6091 if (found == invert)
6092 return 0;
6093 break;
6094 }
Eric Andersen2870d962001-07-02 17:27:21 +00006095dft: default:
Eric Andersencb57d552001-06-28 07:25:16 +00006096 if (squoted && *q == CTLESC)
6097 q++;
6098 if (*q++ != c)
6099 return 0;
6100 break;
6101 }
6102 }
6103breakloop:
6104 if (*q != '\0')
6105 return 0;
6106 return 1;
6107}
6108#endif
6109
6110
6111
6112/*
6113 * Remove any CTLESC characters from a string.
6114 */
6115
6116#if defined(__GLIBC__) && !defined(FNMATCH_BROKEN)
6117static char *
Eric Andersen2870d962001-07-02 17:27:21 +00006118_rmescapes(char *str, int flag)
Eric Andersencb57d552001-06-28 07:25:16 +00006119{
6120 char *p, *q, *r;
6121 static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
6122
6123 p = strpbrk(str, qchars);
6124 if (!p) {
6125 return str;
6126 }
6127 q = p;
6128 r = str;
6129 if (flag & RMESCAPE_ALLOC) {
6130 size_t len = p - str;
6131 q = r = stalloc(strlen(p) + len + 1);
6132 if (len > 0) {
6133#ifdef _GNU_SOURCE
6134 q = mempcpy(q, str, len);
6135#else
6136 memcpy(q, str, len);
6137 q += len;
6138#endif
6139 }
6140 }
6141 while (*p) {
6142 if (*p == CTLQUOTEMARK) {
6143 p++;
6144 continue;
6145 }
6146 if (*p == CTLESC) {
6147 p++;
6148 if (flag & RMESCAPE_GLOB && *p != '/') {
6149 *q++ = '\\';
6150 }
6151 }
6152 *q++ = *p++;
6153 }
6154 *q = '\0';
6155 return r;
6156}
6157#else
6158static void
6159rmescapes(str)
6160 char *str;
6161{
6162 char *p, *q;
6163
6164 p = str;
6165 while (*p != CTLESC && *p != CTLQUOTEMARK) {
6166 if (*p++ == '\0')
6167 return;
6168 }
6169 q = p;
6170 while (*p) {
6171 if (*p == CTLQUOTEMARK) {
6172 p++;
6173 continue;
6174 }
6175 if (*p == CTLESC)
6176 p++;
6177 *q++ = *p++;
6178 }
6179 *q = '\0';
6180}
6181#endif
6182
6183
6184
6185/*
6186 * See if a pattern matches in a case statement.
6187 */
6188
6189static int
Eric Andersen2870d962001-07-02 17:27:21 +00006190casematch(union node *pattern, const char *val)
6191{
Eric Andersencb57d552001-06-28 07:25:16 +00006192 struct stackmark smark;
6193 int result;
6194 char *p;
6195
6196 setstackmark(&smark);
6197 argbackq = pattern->narg.backquote;
6198 STARTSTACKSTR(expdest);
6199 ifslastp = NULL;
6200 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE);
6201 STPUTC('\0', expdest);
6202 p = grabstackstr(expdest);
Eric Andersen2870d962001-07-02 17:27:21 +00006203 result = patmatch(p, (char *)val, 0);
Eric Andersencb57d552001-06-28 07:25:16 +00006204 popstackmark(&smark);
6205 return result;
6206}
6207
6208/*
6209 * Our own itoa().
6210 */
6211
6212static char *
6213cvtnum(num, buf)
6214 int num;
6215 char *buf;
6216 {
6217 int len;
6218
6219 CHECKSTRSPACE(32, buf);
6220 len = sprintf(buf, "%d", num);
6221 STADJUST(len, buf);
6222 return buf;
6223}
Eric Andersencb57d552001-06-28 07:25:16 +00006224/*
6225 * Editline and history functions (and glue).
6226 */
6227static int histcmd(argc, argv)
6228 int argc;
6229 char **argv;
6230{
6231 error("not compiled with history support");
6232 /* NOTREACHED */
6233}
6234
6235
Eric Andersen2870d962001-07-02 17:27:21 +00006236static int whichprompt; /* 1 == PS1, 2 == PS2 */
Eric Andersencb57d552001-06-28 07:25:16 +00006237
Eric Andersencb57d552001-06-28 07:25:16 +00006238
6239struct redirtab {
6240 struct redirtab *next;
6241 short renamed[10];
6242};
6243
Eric Andersen2870d962001-07-02 17:27:21 +00006244static struct redirtab *redirlist;
Eric Andersencb57d552001-06-28 07:25:16 +00006245
6246extern char **environ;
6247
6248
6249
6250/*
6251 * Initialization code.
6252 */
6253
6254static void
Eric Andersen2870d962001-07-02 17:27:21 +00006255init(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00006256
6257 /* from cd.c: */
6258 {
6259 setpwd(0, 0);
6260 }
6261
6262 /* from input.c: */
6263 {
6264 basepf.nextc = basepf.buf = basebuf;
6265 }
6266
6267 /* from output.c: */
6268 {
6269#ifdef USE_GLIBC_STDIO
6270 initstreams();
6271#endif
6272 }
6273
6274 /* from var.c: */
6275 {
6276 char **envp;
6277 char ppid[32];
6278
6279 initvar();
6280 for (envp = environ ; *envp ; envp++) {
6281 if (strchr(*envp, '=')) {
6282 setvareq(*envp, VEXPORT|VTEXTFIXED);
6283 }
6284 }
6285
6286 fmtstr(ppid, sizeof(ppid), "%d", (int) getppid());
6287 setvar("PPID", ppid, 0);
6288 }
6289}
6290
6291
6292
6293/*
6294 * This routine is called when an error or an interrupt occurs in an
6295 * interactive shell and control is returned to the main command loop.
6296 */
6297
Eric Andersen2870d962001-07-02 17:27:21 +00006298#ifdef ASH_ALIAS
6299/* 1 == check for aliases, 2 == also check for assignments */
6300static int checkalias;
6301#endif
6302
Eric Andersencb57d552001-06-28 07:25:16 +00006303static void
Eric Andersen2870d962001-07-02 17:27:21 +00006304reset(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00006305
6306 /* from eval.c: */
6307 {
6308 evalskip = 0;
6309 loopnest = 0;
6310 funcnest = 0;
6311 }
6312
6313 /* from input.c: */
6314 {
6315 if (exception != EXSHELLPROC)
Eric Andersen2870d962001-07-02 17:27:21 +00006316 parselleft = parsenleft = 0; /* clear input buffer */
Eric Andersencb57d552001-06-28 07:25:16 +00006317 popallfiles();
6318 }
6319
6320 /* from parser.c: */
6321 {
6322 tokpushback = 0;
6323 checkkwd = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00006324#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00006325 checkalias = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00006326#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006327 }
6328
6329 /* from redir.c: */
6330 {
6331 while (redirlist)
6332 popredir();
6333 }
6334
6335 /* from output.c: */
6336 {
6337 out1 = &output;
6338 out2 = &errout;
6339#ifdef USE_GLIBC_STDIO
6340 if (memout.stream != NULL)
6341 __closememout();
6342#endif
6343 if (memout.buf != NULL) {
6344 ckfree(memout.buf);
6345 memout.buf = NULL;
6346 }
6347 }
6348}
6349
6350
6351
6352/*
Eric Andersencb57d552001-06-28 07:25:16 +00006353 * This file implements the input routines used by the parser.
6354 */
6355
6356#ifdef BB_FEATURE_COMMAND_EDITING
6357unsigned int shell_context;
6358static const char * cmdedit_prompt;
6359static inline void putprompt(const char *s) {
6360 cmdedit_prompt = s;
6361}
6362#else
6363static inline void putprompt(const char *s) {
6364 out2str(s);
6365}
6366#endif
6367
Eric Andersen2870d962001-07-02 17:27:21 +00006368#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
Eric Andersencb57d552001-06-28 07:25:16 +00006369
Eric Andersencb57d552001-06-28 07:25:16 +00006370
Eric Andersencb57d552001-06-28 07:25:16 +00006371
Eric Andersen2870d962001-07-02 17:27:21 +00006372/*
6373 * Same as pgetc(), but ignores PEOA.
6374 */
Eric Andersencb57d552001-06-28 07:25:16 +00006375
Eric Andersen2870d962001-07-02 17:27:21 +00006376#ifdef ASH_ALIAS
6377static int
6378pgetc2()
6379{
6380 int c;
6381 do {
6382 c = pgetc_macro();
6383 } while (c == PEOA);
6384 return c;
Eric Andersencb57d552001-06-28 07:25:16 +00006385}
Eric Andersen2870d962001-07-02 17:27:21 +00006386#else
6387static inline int pgetc2() { return pgetc_macro(); }
Eric Andersencb57d552001-06-28 07:25:16 +00006388#endif
6389
Eric Andersencb57d552001-06-28 07:25:16 +00006390/*
6391 * Read a line from the script.
6392 */
6393
6394static char *
Eric Andersen2870d962001-07-02 17:27:21 +00006395pfgets(char *line, int len)
Eric Andersencb57d552001-06-28 07:25:16 +00006396{
6397 char *p = line;
6398 int nleft = len;
6399 int c;
6400
6401 while (--nleft > 0) {
6402 c = pgetc2();
6403 if (c == PEOF) {
6404 if (p == line)
6405 return NULL;
6406 break;
6407 }
6408 *p++ = c;
6409 if (c == '\n')
6410 break;
6411 }
6412 *p = '\0';
6413 return line;
6414}
6415
Eric Andersencb57d552001-06-28 07:25:16 +00006416static int
Eric Andersen2870d962001-07-02 17:27:21 +00006417preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006418{
6419 int nr;
6420 char *buf = parsefile->buf;
6421 parsenextc = buf;
6422
6423retry:
6424#ifdef BB_FEATURE_COMMAND_EDITING
6425 {
6426 if (parsefile->fd)
6427 nr = read(parsefile->fd, buf, BUFSIZ - 1);
Eric Andersen2870d962001-07-02 17:27:21 +00006428 else {
Eric Andersencb57d552001-06-28 07:25:16 +00006429 do {
6430 cmdedit_read_input((char*)cmdedit_prompt, buf);
6431 nr = strlen(buf);
6432 } while (nr <=0 || shell_context);
6433 cmdedit_terminate();
6434 }
6435 }
6436#else
6437 nr = read(parsefile->fd, buf, BUFSIZ - 1);
6438#endif
6439
6440 if (nr < 0) {
6441 if (errno == EINTR)
6442 goto retry;
6443 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
6444 int flags = fcntl(0, F_GETFL, 0);
6445 if (flags >= 0 && flags & O_NONBLOCK) {
6446 flags &=~ O_NONBLOCK;
6447 if (fcntl(0, F_SETFL, flags) >= 0) {
6448 out2str("sh: turning off NDELAY mode\n");
6449 goto retry;
6450 }
6451 }
6452 }
6453 }
6454 return nr;
6455}
6456
Eric Andersen2870d962001-07-02 17:27:21 +00006457static void
6458popstring(void)
6459{
6460 struct strpush *sp = parsefile->strpush;
6461
6462 INTOFF;
6463#ifdef ASH_ALIAS
6464 if (sp->ap) {
6465 if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
6466 if (!checkalias) {
6467 checkalias = 1;
6468 }
6469 }
6470 if (sp->string != sp->ap->val) {
6471 ckfree(sp->string);
6472 }
6473
6474 sp->ap->flag &= ~ALIASINUSE;
6475 if (sp->ap->flag & ALIASDEAD) {
6476 unalias(sp->ap->name);
6477 }
6478 }
6479#endif
6480 parsenextc = sp->prevstring;
6481 parsenleft = sp->prevnleft;
6482/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
6483 parsefile->strpush = sp->prev;
6484 if (sp != &(parsefile->basestrpush))
6485 ckfree(sp);
6486 INTON;
6487}
6488
6489
Eric Andersencb57d552001-06-28 07:25:16 +00006490/*
6491 * Refill the input buffer and return the next input character:
6492 *
6493 * 1) If a string was pushed back on the input, pop it;
6494 * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
6495 * from a string so we can't refill the buffer, return EOF.
6496 * 3) If the is more stuff in this buffer, use it else call read to fill it.
6497 * 4) Process input up to the next newline, deleting nul characters.
6498 */
6499
6500static int
Eric Andersen2870d962001-07-02 17:27:21 +00006501preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00006502{
6503 char *p, *q;
6504 int more;
6505 char savec;
6506
6507 while (parsefile->strpush) {
Eric Andersen2870d962001-07-02 17:27:21 +00006508#ifdef ASH_ALIAS
6509 if (parsenleft == -1 && parsefile->strpush->ap &&
6510 parsenextc[-1] != ' ' && parsenextc[-1] != '\t') {
Eric Andersencb57d552001-06-28 07:25:16 +00006511 return PEOA;
6512 }
Eric Andersen2870d962001-07-02 17:27:21 +00006513#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006514 popstring();
6515 if (--parsenleft >= 0)
6516 return (*parsenextc++);
6517 }
6518 if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
6519 return PEOF;
6520 flushout(&output);
6521#ifdef FLUSHERR
6522 flushout(&errout);
6523#endif
6524
6525again:
6526 if (parselleft <= 0) {
6527 if ((parselleft = preadfd()) <= 0) {
6528 parselleft = parsenleft = EOF_NLEFT;
6529 return PEOF;
6530 }
6531 }
6532
6533 q = p = parsenextc;
6534
6535 /* delete nul characters */
6536 for (more = 1; more;) {
6537 switch (*p) {
6538 case '\0':
Eric Andersen2870d962001-07-02 17:27:21 +00006539 p++; /* Skip nul */
Eric Andersencb57d552001-06-28 07:25:16 +00006540 goto check;
6541
6542
6543 case '\n':
6544 parsenleft = q - parsenextc;
6545 more = 0; /* Stop processing here */
6546 break;
6547 }
6548
6549 *q++ = *p++;
6550check:
6551 if (--parselleft <= 0 && more) {
6552 parsenleft = q - parsenextc - 1;
6553 if (parsenleft < 0)
6554 goto again;
6555 more = 0;
6556 }
6557 }
6558
6559 savec = *q;
6560 *q = '\0';
6561
6562 if (vflag) {
6563 out2str(parsenextc);
6564#ifdef FLUSHERR
6565 flushout(out2);
6566#endif
6567 }
6568
6569 *q = savec;
6570
6571 return *parsenextc++;
6572}
6573
Eric Andersencb57d552001-06-28 07:25:16 +00006574
6575/*
6576 * Push a string back onto the input at this current parsefile level.
6577 * We handle aliases this way.
6578 */
6579static void
Eric Andersen2870d962001-07-02 17:27:21 +00006580pushstring(char *s, int len, void *ap)
6581{
Eric Andersencb57d552001-06-28 07:25:16 +00006582 struct strpush *sp;
6583
6584 INTOFF;
6585/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/
6586 if (parsefile->strpush) {
6587 sp = ckmalloc(sizeof (struct strpush));
6588 sp->prev = parsefile->strpush;
6589 parsefile->strpush = sp;
6590 } else
6591 sp = parsefile->strpush = &(parsefile->basestrpush);
6592 sp->prevstring = parsenextc;
6593 sp->prevnleft = parsenleft;
Eric Andersen2870d962001-07-02 17:27:21 +00006594#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +00006595 sp->ap = (struct alias *)ap;
6596 if (ap) {
6597 ((struct alias *)ap)->flag |= ALIASINUSE;
6598 sp->string = s;
6599 }
Eric Andersen2870d962001-07-02 17:27:21 +00006600#endif
Eric Andersencb57d552001-06-28 07:25:16 +00006601 parsenextc = s;
6602 parsenleft = len;
6603 INTON;
6604}
6605
Eric Andersencb57d552001-06-28 07:25:16 +00006606
Eric Andersencb57d552001-06-28 07:25:16 +00006607
6608
6609/*
6610 * Like setinputfile, but takes input from a string.
6611 */
6612
6613static void
6614setinputstring(string)
6615 char *string;
6616 {
6617 INTOFF;
6618 pushfile();
6619 parsenextc = string;
6620 parsenleft = strlen(string);
6621 parsefile->buf = NULL;
6622 plinno = 1;
6623 INTON;
6624}
6625
6626
6627
6628/*
6629 * To handle the "." command, a stack of input files is used. Pushfile
6630 * adds a new entry to the stack and popfile restores the previous level.
6631 */
6632
6633static void
Eric Andersen2870d962001-07-02 17:27:21 +00006634pushfile(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00006635 struct parsefile *pf;
6636
6637 parsefile->nleft = parsenleft;
6638 parsefile->lleft = parselleft;
6639 parsefile->nextc = parsenextc;
6640 parsefile->linno = plinno;
6641 pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
6642 pf->prev = parsefile;
6643 pf->fd = -1;
6644 pf->strpush = NULL;
6645 pf->basestrpush.prev = NULL;
6646 parsefile = pf;
6647}
6648
Eric Andersen2870d962001-07-02 17:27:21 +00006649#ifdef JOBS
6650static void restartjob (struct job *);
Eric Andersencb57d552001-06-28 07:25:16 +00006651#endif
Eric Andersen2870d962001-07-02 17:27:21 +00006652static void freejob (struct job *);
6653static struct job *getjob (const char *);
6654static int dowait (int, struct job *);
6655static int waitproc (int, int *);
Eric Andersencb57d552001-06-28 07:25:16 +00006656static void waitonint(int);
6657
6658
Eric Andersen2870d962001-07-02 17:27:21 +00006659/*
6660 * We keep track of whether or not fd0 has been redirected. This is for
6661 * background commands, where we want to redirect fd0 to /dev/null only
6662 * if it hasn't already been redirected.
6663*/
6664static int fd0_redirected = 0;
6665
6666/* Return true if fd 0 has already been redirected at least once. */
6667static inline int
6668fd0_redirected_p () {
6669 return fd0_redirected != 0;
6670}
6671
6672/*
6673 * We also keep track of where fileno2 goes.
6674 */
6675static int fileno2 = 2;
6676
6677static int openredirect (union node *);
6678static void dupredirect (union node *, int, char[10 ]);
6679static int openhere (union node *);
6680static int noclobberopen (const char *);
6681
6682
6683
6684#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006685/*
6686 * Turn job control on and off.
6687 *
6688 * Note: This code assumes that the third arg to ioctl is a character
6689 * pointer, which is true on Berkeley systems but not System V. Since
6690 * System V doesn't have job control yet, this isn't a problem now.
6691 */
6692
Eric Andersen2870d962001-07-02 17:27:21 +00006693
Eric Andersencb57d552001-06-28 07:25:16 +00006694
6695static void setjobctl(int enable)
6696{
6697#ifdef OLD_TTY_DRIVER
6698 int ldisc;
6699#endif
6700
6701 if (enable == jobctl || rootshell == 0)
6702 return;
6703 if (enable) {
6704 do { /* while we are in the background */
6705#ifdef OLD_TTY_DRIVER
6706 if (ioctl(fileno2, TIOCGPGRP, (char *)&initialpgrp) < 0) {
6707#else
6708 initialpgrp = tcgetpgrp(fileno2);
6709 if (initialpgrp < 0) {
6710#endif
6711 out2str("sh: can't access tty; job cenabletrol turned off\n");
6712 mflag = 0;
6713 return;
6714 }
6715 if (initialpgrp == -1)
6716 initialpgrp = getpgrp();
6717 else if (initialpgrp != getpgrp()) {
6718 killpg(initialpgrp, SIGTTIN);
6719 continue;
6720 }
6721 } while (0);
6722#ifdef OLD_TTY_DRIVER
6723 if (ioctl(fileno2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) {
6724 out2str("sh: need new tty driver to run job cenabletrol; job cenabletrol turned off\n");
6725 mflag = 0;
6726 return;
6727 }
6728#endif
6729 setsignal(SIGTSTP);
6730 setsignal(SIGTTOU);
6731 setsignal(SIGTTIN);
6732 setpgid(0, rootpid);
6733#ifdef OLD_TTY_DRIVER
6734 ioctl(fileno2, TIOCSPGRP, (char *)&rootpid);
6735#else
6736 tcsetpgrp(fileno2, rootpid);
6737#endif
6738 } else { /* turning job cenabletrol off */
6739 setpgid(0, initialpgrp);
6740#ifdef OLD_TTY_DRIVER
6741 ioctl(fileno2, TIOCSPGRP, (char *)&initialpgrp);
6742#else
6743 tcsetpgrp(fileno2, initialpgrp);
6744#endif
6745 setsignal(SIGTSTP);
6746 setsignal(SIGTTOU);
6747 setsignal(SIGTTIN);
6748 }
6749 jobctl = enable;
6750}
6751#endif
6752
6753
Eric Andersencb57d552001-06-28 07:25:16 +00006754/* A translation list so we can be polite to our users. */
6755static char *signal_names[NSIG + 2] = {
6756 "EXIT",
6757 "SIGHUP",
6758 "SIGINT",
6759 "SIGQUIT",
6760 "SIGILL",
6761 "SIGTRAP",
6762 "SIGABRT",
6763 "SIGBUS",
6764 "SIGFPE",
6765 "SIGKILL",
6766 "SIGUSR1",
6767 "SIGSEGV",
6768 "SIGUSR2",
6769 "SIGPIPE",
6770 "SIGALRM",
6771 "SIGTERM",
6772 "SIGJUNK(16)",
6773 "SIGCHLD",
6774 "SIGCONT",
6775 "SIGSTOP",
6776 "SIGTSTP",
6777 "SIGTTIN",
6778 "SIGTTOU",
6779 "SIGURG",
6780 "SIGXCPU",
6781 "SIGXFSZ",
6782 "SIGVTALRM",
6783 "SIGPROF",
6784 "SIGWINCH",
6785 "SIGIO",
6786 "SIGPWR",
6787 "SIGSYS",
6788 "SIGRTMIN",
6789 "SIGRTMIN+1",
6790 "SIGRTMIN+2",
6791 "SIGRTMIN+3",
6792 "SIGRTMIN+4",
6793 "SIGRTMIN+5",
6794 "SIGRTMIN+6",
6795 "SIGRTMIN+7",
6796 "SIGRTMIN+8",
6797 "SIGRTMIN+9",
6798 "SIGRTMIN+10",
6799 "SIGRTMIN+11",
6800 "SIGRTMIN+12",
6801 "SIGRTMIN+13",
6802 "SIGRTMIN+14",
6803 "SIGRTMIN+15",
6804 "SIGRTMAX-15",
6805 "SIGRTMAX-14",
6806 "SIGRTMAX-13",
6807 "SIGRTMAX-12",
6808 "SIGRTMAX-11",
6809 "SIGRTMAX-10",
6810 "SIGRTMAX-9",
6811 "SIGRTMAX-8",
6812 "SIGRTMAX-7",
6813 "SIGRTMAX-6",
6814 "SIGRTMAX-5",
6815 "SIGRTMAX-4",
6816 "SIGRTMAX-3",
6817 "SIGRTMAX-2",
6818 "SIGRTMAX-1",
6819 "SIGRTMAX",
6820 "DEBUG",
6821 (char *)0x0,
6822};
6823
6824
6825
Eric Andersen2870d962001-07-02 17:27:21 +00006826#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00006827static int
6828killcmd(argc, argv)
6829 int argc;
6830 char **argv;
6831{
6832 int signo = -1;
6833 int list = 0;
6834 int i;
6835 pid_t pid;
6836 struct job *jp;
6837
6838 if (argc <= 1) {
6839usage:
6840 error(
6841"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n"
6842"kill -l [exitstatus]"
6843 );
6844 }
6845
6846 if (*argv[1] == '-') {
6847 signo = decode_signal(argv[1] + 1, 1);
6848 if (signo < 0) {
6849 int c;
6850
6851 while ((c = nextopt("ls:")) != '\0')
6852 switch (c) {
6853 case 'l':
6854 list = 1;
6855 break;
6856 case 's':
6857 signo = decode_signal(optionarg, 1);
6858 if (signo < 0) {
6859 error(
6860 "invalid signal number or name: %s",
6861 optionarg
6862 );
6863 }
Eric Andersen2870d962001-07-02 17:27:21 +00006864 break;
Eric Andersencb57d552001-06-28 07:25:16 +00006865#ifdef DEBUG
6866 default:
6867 error(
6868 "nextopt returned character code 0%o", c);
6869#endif
6870 }
6871 } else
6872 argptr++;
6873 }
6874
6875 if (!list && signo < 0)
6876 signo = SIGTERM;
6877
6878 if ((signo < 0 || !*argptr) ^ list) {
6879 goto usage;
6880 }
6881
6882 if (list) {
6883 if (!*argptr) {
6884 out1str("0\n");
6885 for (i = 1; i < NSIG; i++) {
6886 out1fmt(snlfmt, signal_names[i] + 3);
6887 }
6888 return 0;
6889 }
6890 signo = atoi(*argptr);
6891 if (signo > 128)
6892 signo -= 128;
6893 if (0 < signo && signo < NSIG)
6894 out1fmt(snlfmt, signal_names[signo] + 3);
6895 else
6896 error("invalid signal number or exit status: %s",
6897 *argptr);
6898 return 0;
6899 }
6900
6901 do {
6902 if (**argptr == '%') {
6903 jp = getjob(*argptr);
6904 if (jp->jobctl == 0)
6905 error("job %s not created under job control",
6906 *argptr);
6907 pid = -jp->ps[0].pid;
6908 } else
6909 pid = atoi(*argptr);
6910 if (kill(pid, signo) != 0)
Eric Andersen2870d962001-07-02 17:27:21 +00006911 error("%s: %m", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00006912 } while (*++argptr);
6913
6914 return 0;
6915}
6916
6917static int
6918fgcmd(argc, argv)
6919 int argc;
6920 char **argv;
6921{
6922 struct job *jp;
6923 int pgrp;
6924 int status;
6925
6926 jp = getjob(argv[1]);
6927 if (jp->jobctl == 0)
6928 error("job not created under job control");
6929 pgrp = jp->ps[0].pid;
6930#ifdef OLD_TTY_DRIVER
6931 ioctl(fileno2, TIOCSPGRP, (char *)&pgrp);
6932#else
6933 tcsetpgrp(fileno2, pgrp);
6934#endif
6935 restartjob(jp);
6936 INTOFF;
6937 status = waitforjob(jp);
6938 INTON;
6939 return status;
6940}
6941
6942
6943static int
6944bgcmd(argc, argv)
6945 int argc;
6946 char **argv;
6947{
6948 struct job *jp;
6949
6950 do {
6951 jp = getjob(*++argv);
6952 if (jp->jobctl == 0)
6953 error("job not created under job control");
6954 restartjob(jp);
6955 } while (--argc > 1);
6956 return 0;
6957}
6958
6959
6960static void
6961restartjob(jp)
6962 struct job *jp;
6963{
6964 struct procstat *ps;
6965 int i;
6966
6967 if (jp->state == JOBDONE)
6968 return;
6969 INTOFF;
6970 killpg(jp->ps[0].pid, SIGCONT);
6971 for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
6972 if (WIFSTOPPED(ps->status)) {
6973 ps->status = -1;
6974 jp->state = 0;
6975 }
6976 }
6977 INTON;
6978}
6979#endif
6980
Eric Andersen2870d962001-07-02 17:27:21 +00006981static void showjobs(int change);
6982
Eric Andersencb57d552001-06-28 07:25:16 +00006983
6984static int
6985jobscmd(argc, argv)
6986 int argc;
6987 char **argv;
6988{
6989 showjobs(0);
6990 return 0;
6991}
6992
6993
6994/*
6995 * Print a list of jobs. If "change" is nonzero, only print jobs whose
6996 * statuses have changed since the last call to showjobs.
6997 *
6998 * If the shell is interrupted in the process of creating a job, the
6999 * result may be a job structure containing zero processes. Such structures
7000 * will be freed here.
7001 */
7002
7003static void
7004showjobs(change)
7005 int change;
7006{
7007 int jobno;
7008 int procno;
7009 int i;
7010 struct job *jp;
7011 struct procstat *ps;
7012 int col;
7013 char s[64];
7014
7015 TRACE(("showjobs(%d) called\n", change));
7016 while (dowait(0, (struct job *)NULL) > 0);
7017 for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
7018 if (! jp->used)
7019 continue;
7020 if (jp->nprocs == 0) {
7021 freejob(jp);
7022 continue;
7023 }
7024 if (change && ! jp->changed)
7025 continue;
7026 procno = jp->nprocs;
Eric Andersen2870d962001-07-02 17:27:21 +00007027 for (ps = jp->ps ; ; ps++) { /* for each process */
Eric Andersencb57d552001-06-28 07:25:16 +00007028 if (ps == jp->ps)
Eric Andersen2870d962001-07-02 17:27:21 +00007029 fmtstr(s, 64, "[%d] %ld ", jobno,
Eric Andersencb57d552001-06-28 07:25:16 +00007030 (long)ps->pid);
7031 else
Eric Andersen2870d962001-07-02 17:27:21 +00007032 fmtstr(s, 64, " %ld ",
Eric Andersencb57d552001-06-28 07:25:16 +00007033 (long)ps->pid);
7034 out1str(s);
7035 col = strlen(s);
7036 s[0] = '\0';
7037 if (ps->status == -1) {
7038 /* don't print anything */
7039 } else if (WIFEXITED(ps->status)) {
Eric Andersen2870d962001-07-02 17:27:21 +00007040 fmtstr(s, 64, "Exit %d",
Eric Andersencb57d552001-06-28 07:25:16 +00007041 WEXITSTATUS(ps->status));
7042 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00007043#ifdef JOBS
7044 if (WIFSTOPPED(ps->status))
Eric Andersencb57d552001-06-28 07:25:16 +00007045 i = WSTOPSIG(ps->status);
7046 else /* WIFSIGNALED(ps->status) */
7047#endif
7048 i = WTERMSIG(ps->status);
7049 if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F])
Eric Andersen2870d962001-07-02 17:27:21 +00007050 strcpy(s, sys_siglist[i & 0x7F]);
Eric Andersencb57d552001-06-28 07:25:16 +00007051 else
7052 fmtstr(s, 64, "Signal %d", i & 0x7F);
7053 if (WCOREDUMP(ps->status))
7054 strcat(s, " (core dumped)");
7055 }
7056 out1str(s);
7057 col += strlen(s);
7058 out1fmt(
7059 "%*c%s\n", 30 - col >= 0 ? 30 - col : 0, ' ',
7060 ps->cmd
7061 );
7062 if (--procno <= 0)
7063 break;
7064 }
7065 jp->changed = 0;
7066 if (jp->state == JOBDONE) {
7067 freejob(jp);
7068 }
7069 }
7070}
7071
7072
7073/*
7074 * Mark a job structure as unused.
7075 */
7076
7077static void
7078freejob(jp)
7079 struct job *jp;
7080 {
7081 struct procstat *ps;
7082 int i;
7083
7084 INTOFF;
7085 for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
7086 if (ps->cmd != nullstr)
7087 ckfree(ps->cmd);
7088 }
7089 if (jp->ps != &jp->ps0)
7090 ckfree(jp->ps);
7091 jp->used = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00007092#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007093 if (curjob == jp - jobtab + 1)
7094 curjob = 0;
7095#endif
7096 INTON;
7097}
7098
7099
7100
7101static int
7102waitcmd(argc, argv)
7103 int argc;
7104 char **argv;
7105{
7106 struct job *job;
7107 int status, retval;
7108 struct job *jp;
7109
7110 if (--argc > 0) {
7111start:
7112 job = getjob(*++argv);
7113 } else {
7114 job = NULL;
7115 }
Eric Andersen2870d962001-07-02 17:27:21 +00007116 for (;;) { /* loop until process terminated or stopped */
Eric Andersencb57d552001-06-28 07:25:16 +00007117 if (job != NULL) {
7118 if (job->state) {
7119 status = job->ps[job->nprocs - 1].status;
7120 if (! iflag)
7121 freejob(job);
7122 if (--argc) {
7123 goto start;
7124 }
7125 if (WIFEXITED(status))
7126 retval = WEXITSTATUS(status);
Eric Andersen2870d962001-07-02 17:27:21 +00007127#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007128 else if (WIFSTOPPED(status))
7129 retval = WSTOPSIG(status) + 128;
7130#endif
7131 else {
7132 /* XXX: limits number of signals */
7133 retval = WTERMSIG(status) + 128;
7134 }
7135 return retval;
7136 }
7137 } else {
7138 for (jp = jobtab ; ; jp++) {
Eric Andersen2870d962001-07-02 17:27:21 +00007139 if (jp >= jobtab + njobs) { /* no running procs */
Eric Andersencb57d552001-06-28 07:25:16 +00007140 return 0;
7141 }
7142 if (jp->used && jp->state == 0)
7143 break;
7144 }
7145 }
7146 if (dowait(2, 0) < 0 && errno == EINTR) {
7147 return 129;
7148 }
7149 }
7150}
7151
7152
7153
7154/*
7155 * Convert a job name to a job structure.
7156 */
7157
7158static struct job *
Eric Andersen2870d962001-07-02 17:27:21 +00007159getjob(const char *name)
7160{
Eric Andersencb57d552001-06-28 07:25:16 +00007161 int jobno;
7162 struct job *jp;
7163 int pid;
7164 int i;
7165
7166 if (name == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00007167#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007168currentjob:
7169 if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0)
7170 error("No current job");
7171 return &jobtab[jobno - 1];
7172#else
7173 error("No current job");
7174#endif
7175 } else if (name[0] == '%') {
7176 if (is_digit(name[1])) {
7177 jobno = number(name + 1);
7178 if (jobno > 0 && jobno <= njobs
7179 && jobtab[jobno - 1].used != 0)
7180 return &jobtab[jobno - 1];
Eric Andersen2870d962001-07-02 17:27:21 +00007181#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007182 } else if (name[1] == '%' && name[2] == '\0') {
7183 goto currentjob;
7184#endif
7185 } else {
7186 struct job *found = NULL;
7187 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
7188 if (jp->used && jp->nprocs > 0
7189 && prefix(name + 1, jp->ps[0].cmd)) {
7190 if (found)
7191 error("%s: ambiguous", name);
7192 found = jp;
7193 }
7194 }
7195 if (found)
7196 return found;
7197 }
Eric Andersen2870d962001-07-02 17:27:21 +00007198 } else if (is_number(name, &pid)) {
Eric Andersencb57d552001-06-28 07:25:16 +00007199 for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
7200 if (jp->used && jp->nprocs > 0
7201 && jp->ps[jp->nprocs - 1].pid == pid)
7202 return jp;
7203 }
7204 }
7205 error("No such job: %s", name);
7206 /* NOTREACHED */
7207}
7208
7209
7210
7211/*
7212 * Return a new job structure,
7213 */
7214
Eric Andersen2870d962001-07-02 17:27:21 +00007215static struct job *
Eric Andersencb57d552001-06-28 07:25:16 +00007216makejob(node, nprocs)
7217 union node *node;
7218 int nprocs;
7219{
7220 int i;
7221 struct job *jp;
7222
7223 for (i = njobs, jp = jobtab ; ; jp++) {
7224 if (--i < 0) {
7225 INTOFF;
7226 if (njobs == 0) {
7227 jobtab = ckmalloc(4 * sizeof jobtab[0]);
7228 } else {
7229 jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
7230 memcpy(jp, jobtab, njobs * sizeof jp[0]);
7231 /* Relocate `ps' pointers */
7232 for (i = 0; i < njobs; i++)
7233 if (jp[i].ps == &jobtab[i].ps0)
7234 jp[i].ps = &jp[i].ps0;
7235 ckfree(jobtab);
7236 jobtab = jp;
7237 }
7238 jp = jobtab + njobs;
7239 for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0);
7240 INTON;
7241 break;
7242 }
7243 if (jp->used == 0)
7244 break;
7245 }
7246 INTOFF;
7247 jp->state = 0;
7248 jp->used = 1;
7249 jp->changed = 0;
7250 jp->nprocs = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00007251#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007252 jp->jobctl = jobctl;
7253#endif
7254 if (nprocs > 1) {
7255 jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
7256 } else {
7257 jp->ps = &jp->ps0;
7258 }
7259 INTON;
7260 TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs,
7261 jp - jobtab + 1));
7262 return jp;
7263}
7264
7265
7266/*
7267 * Fork of a subshell. If we are doing job control, give the subshell its
7268 * own process group. Jp is a job structure that the job is to be added to.
7269 * N is the command that will be evaluated by the child. Both jp and n may
7270 * be NULL. The mode parameter can be one of the following:
Eric Andersen2870d962001-07-02 17:27:21 +00007271 * FORK_FG - Fork off a foreground process.
7272 * FORK_BG - Fork off a background process.
7273 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
7274 * process group even if job control is on.
Eric Andersencb57d552001-06-28 07:25:16 +00007275 *
7276 * When job control is turned off, background processes have their standard
7277 * input redirected to /dev/null (except for the second and later processes
7278 * in a pipeline).
7279 */
7280
Eric Andersen2870d962001-07-02 17:27:21 +00007281
7282
Eric Andersencb57d552001-06-28 07:25:16 +00007283static int
Eric Andersen2870d962001-07-02 17:27:21 +00007284forkshell(struct job *jp, union node *n, int mode)
Eric Andersencb57d552001-06-28 07:25:16 +00007285{
7286 int pid;
7287 int pgrp;
7288 const char *devnull = _PATH_DEVNULL;
7289 const char *nullerr = "Can't open %s";
7290
7291 TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long)n,
7292 mode));
7293 INTOFF;
7294 pid = fork();
7295 if (pid == -1) {
7296 TRACE(("Fork failed, errno=%d\n", errno));
7297 INTON;
7298 error("Cannot fork");
7299 }
7300 if (pid == 0) {
7301 struct job *p;
7302 int wasroot;
7303 int i;
7304
7305 TRACE(("Child shell %d\n", getpid()));
7306 wasroot = rootshell;
7307 rootshell = 0;
7308 closescript();
7309 INTON;
7310 clear_traps();
Eric Andersen2870d962001-07-02 17:27:21 +00007311#ifdef JOBS
7312 jobctl = 0; /* do job control only in root shell */
Eric Andersencb57d552001-06-28 07:25:16 +00007313 if (wasroot && mode != FORK_NOJOB && mflag) {
7314 if (jp == NULL || jp->nprocs == 0)
7315 pgrp = getpid();
7316 else
7317 pgrp = jp->ps[0].pid;
7318 setpgid(0, pgrp);
7319 if (mode == FORK_FG) {
7320 /*** this causes superfluous TIOCSPGRPS ***/
7321#ifdef OLD_TTY_DRIVER
7322 if (ioctl(fileno2, TIOCSPGRP, (char *)&pgrp) < 0)
7323 error("TIOCSPGRP failed, errno=%d", errno);
7324#else
7325 if (tcsetpgrp(fileno2, pgrp) < 0)
7326 error("tcsetpgrp failed, errno=%d", errno);
7327#endif
7328 }
7329 setsignal(SIGTSTP);
7330 setsignal(SIGTTOU);
7331 } else if (mode == FORK_BG) {
7332 ignoresig(SIGINT);
7333 ignoresig(SIGQUIT);
7334 if ((jp == NULL || jp->nprocs == 0) &&
7335 ! fd0_redirected_p ()) {
7336 close(0);
7337 if (open(devnull, O_RDONLY) != 0)
7338 error(nullerr, devnull);
7339 }
7340 }
7341#else
7342 if (mode == FORK_BG) {
7343 ignoresig(SIGINT);
7344 ignoresig(SIGQUIT);
7345 if ((jp == NULL || jp->nprocs == 0) &&
7346 ! fd0_redirected_p ()) {
7347 close(0);
7348 if (open(devnull, O_RDONLY) != 0)
7349 error(nullerr, devnull);
7350 }
7351 }
7352#endif
7353 for (i = njobs, p = jobtab ; --i >= 0 ; p++)
7354 if (p->used)
7355 freejob(p);
7356 if (wasroot && iflag) {
7357 setsignal(SIGINT);
7358 setsignal(SIGQUIT);
7359 setsignal(SIGTERM);
7360 }
7361 return pid;
7362 }
7363 if (rootshell && mode != FORK_NOJOB && mflag) {
7364 if (jp == NULL || jp->nprocs == 0)
7365 pgrp = pid;
7366 else
7367 pgrp = jp->ps[0].pid;
7368 setpgid(pid, pgrp);
7369 }
7370 if (mode == FORK_BG)
Eric Andersen2870d962001-07-02 17:27:21 +00007371 backgndpid = pid; /* set $! */
Eric Andersencb57d552001-06-28 07:25:16 +00007372 if (jp) {
7373 struct procstat *ps = &jp->ps[jp->nprocs++];
7374 ps->pid = pid;
7375 ps->status = -1;
7376 ps->cmd = nullstr;
7377 if (iflag && rootshell && n)
7378 ps->cmd = commandtext(n);
7379 }
7380 INTON;
7381 TRACE(("In parent shell: child = %d\n", pid));
7382 return pid;
7383}
7384
7385
7386
7387/*
7388 * Wait for job to finish.
7389 *
7390 * Under job control we have the problem that while a child process is
7391 * running interrupts generated by the user are sent to the child but not
7392 * to the shell. This means that an infinite loop started by an inter-
7393 * active user may be hard to kill. With job control turned off, an
7394 * interactive user may place an interactive program inside a loop. If
7395 * the interactive program catches interrupts, the user doesn't want
7396 * these interrupts to also abort the loop. The approach we take here
7397 * is to have the shell ignore interrupt signals while waiting for a
7398 * forground process to terminate, and then send itself an interrupt
7399 * signal if the child process was terminated by an interrupt signal.
7400 * Unfortunately, some programs want to do a bit of cleanup and then
7401 * exit on interrupt; unless these processes terminate themselves by
7402 * sending a signal to themselves (instead of calling exit) they will
7403 * confuse this approach.
7404 */
7405
7406static int
7407waitforjob(jp)
7408 struct job *jp;
7409 {
Eric Andersen2870d962001-07-02 17:27:21 +00007410#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007411 int mypgrp = getpgrp();
7412#endif
7413 int status;
7414 int st;
7415 struct sigaction act, oact;
7416
7417 INTOFF;
7418 intreceived = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00007419#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007420 if (!jobctl) {
7421#else
7422 if (!iflag) {
7423#endif
7424 sigaction(SIGINT, 0, &act);
7425 act.sa_handler = waitonint;
7426 sigaction(SIGINT, &act, &oact);
7427 }
7428 TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1));
7429 while (jp->state == 0) {
7430 dowait(1, jp);
7431 }
Eric Andersen2870d962001-07-02 17:27:21 +00007432#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007433 if (!jobctl) {
7434#else
7435 if (!iflag) {
7436#endif
7437 sigaction(SIGINT, &oact, 0);
7438 if (intreceived && trap[SIGINT]) kill(getpid(), SIGINT);
7439 }
Eric Andersen2870d962001-07-02 17:27:21 +00007440#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007441 if (jp->jobctl) {
7442#ifdef OLD_TTY_DRIVER
7443 if (ioctl(fileno2, TIOCSPGRP, (char *)&mypgrp) < 0)
7444 error("TIOCSPGRP failed, errno=%d\n", errno);
7445#else
7446 if (tcsetpgrp(fileno2, mypgrp) < 0)
7447 error("tcsetpgrp failed, errno=%d\n", errno);
7448#endif
7449 }
7450 if (jp->state == JOBSTOPPED)
7451 curjob = jp - jobtab + 1;
7452#endif
7453 status = jp->ps[jp->nprocs - 1].status;
7454 /* convert to 8 bits */
7455 if (WIFEXITED(status))
7456 st = WEXITSTATUS(status);
Eric Andersen2870d962001-07-02 17:27:21 +00007457#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007458 else if (WIFSTOPPED(status))
7459 st = WSTOPSIG(status) + 128;
7460#endif
7461 else
7462 st = WTERMSIG(status) + 128;
Eric Andersen2870d962001-07-02 17:27:21 +00007463#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007464 if (jp->jobctl) {
7465 /*
7466 * This is truly gross.
7467 * If we're doing job control, then we did a TIOCSPGRP which
7468 * caused us (the shell) to no longer be in the controlling
7469 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
7470 * intuit from the subprocess exit status whether a SIGINT
7471 * occured, and if so interrupt ourselves. Yuck. - mycroft
7472 */
7473 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
7474 raise(SIGINT);
7475 }
Eric Andersen2870d962001-07-02 17:27:21 +00007476 if (jp->state == JOBDONE)
7477
Eric Andersencb57d552001-06-28 07:25:16 +00007478#endif
Eric Andersencb57d552001-06-28 07:25:16 +00007479 freejob(jp);
7480 INTON;
7481 return st;
7482}
7483
7484
7485
7486/*
7487 * Wait for a process to terminate.
7488 */
7489
7490static int
7491dowait(block, job)
7492 int block;
7493 struct job *job;
7494{
7495 int pid;
7496 int status;
7497 struct procstat *sp;
7498 struct job *jp;
7499 struct job *thisjob;
7500 int done;
7501 int stopped;
7502 int core;
7503 int sig;
7504
7505 TRACE(("dowait(%d) called\n", block));
7506 do {
7507 pid = waitproc(block, &status);
7508 TRACE(("wait returns %d, status=%d\n", pid, status));
7509 } while (!(block & 2) && pid == -1 && errno == EINTR);
7510 if (pid <= 0)
7511 return pid;
7512 INTOFF;
7513 thisjob = NULL;
7514 for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
7515 if (jp->used) {
7516 done = 1;
7517 stopped = 1;
7518 for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
7519 if (sp->pid == -1)
7520 continue;
7521 if (sp->pid == pid) {
7522 TRACE(("Changing status of proc %d from 0x%x to 0x%x\n", pid, sp->status, status));
7523 sp->status = status;
7524 thisjob = jp;
7525 }
7526 if (sp->status == -1)
7527 stopped = 0;
7528 else if (WIFSTOPPED(sp->status))
7529 done = 0;
7530 }
Eric Andersen2870d962001-07-02 17:27:21 +00007531 if (stopped) { /* stopped or done */
Eric Andersencb57d552001-06-28 07:25:16 +00007532 int state = done? JOBDONE : JOBSTOPPED;
7533 if (jp->state != state) {
7534 TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
7535 jp->state = state;
Eric Andersen2870d962001-07-02 17:27:21 +00007536#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007537 if (done && curjob == jp - jobtab + 1)
Eric Andersen2870d962001-07-02 17:27:21 +00007538 curjob = 0; /* no current job */
Eric Andersencb57d552001-06-28 07:25:16 +00007539#endif
7540 }
7541 }
7542 }
7543 }
7544 INTON;
7545 if (! rootshell || ! iflag || (job && thisjob == job)) {
7546 core = WCOREDUMP(status);
Eric Andersen2870d962001-07-02 17:27:21 +00007547#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007548 if (WIFSTOPPED(status)) sig = WSTOPSIG(status);
7549 else
7550#endif
7551 if (WIFEXITED(status)) sig = 0;
7552 else sig = WTERMSIG(status);
7553
7554 if (sig != 0 && sig != SIGINT && sig != SIGPIPE) {
7555 if (thisjob != job)
7556 outfmt(out2, "%d: ", pid);
Eric Andersen2870d962001-07-02 17:27:21 +00007557#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007558 if (sig == SIGTSTP && rootshell && iflag)
7559 outfmt(out2, "%%%ld ",
7560 (long)(job - jobtab + 1));
7561#endif
7562 if (sig < NSIG && sys_siglist[sig])
7563 out2str(sys_siglist[sig]);
7564 else
7565 outfmt(out2, "Signal %d", sig);
7566 if (core)
7567 out2str(" - core dumped");
7568 out2c('\n');
7569#ifdef FLUSHERR
7570 flushout(&errout);
7571#endif
7572 } else {
Eric Andersen2870d962001-07-02 17:27:21 +00007573 TRACE(("Not printing status: status=%d, sig=%d\n",
Eric Andersencb57d552001-06-28 07:25:16 +00007574 status, sig));
7575 }
7576 } else {
7577 TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job));
7578 if (thisjob)
7579 thisjob->changed = 1;
7580 }
7581 return pid;
7582}
7583
7584
7585
7586/*
7587 * Do a wait system call. If job control is compiled in, we accept
7588 * stopped processes. If block is zero, we return a value of zero
7589 * rather than blocking.
7590 *
7591 * System V doesn't have a non-blocking wait system call. It does
7592 * have a SIGCLD signal that is sent to a process when one of it's
7593 * children dies. The obvious way to use SIGCLD would be to install
7594 * a handler for SIGCLD which simply bumped a counter when a SIGCLD
7595 * was received, and have waitproc bump another counter when it got
7596 * the status of a process. Waitproc would then know that a wait
7597 * system call would not block if the two counters were different.
7598 * This approach doesn't work because if a process has children that
7599 * have not been waited for, System V will send it a SIGCLD when it
7600 * installs a signal handler for SIGCLD. What this means is that when
7601 * a child exits, the shell will be sent SIGCLD signals continuously
7602 * until is runs out of stack space, unless it does a wait call before
7603 * restoring the signal handler. The code below takes advantage of
7604 * this (mis)feature by installing a signal handler for SIGCLD and
7605 * then checking to see whether it was called. If there are any
7606 * children to be waited for, it will be.
7607 *
Eric Andersencb57d552001-06-28 07:25:16 +00007608 */
7609
Eric Andersencb57d552001-06-28 07:25:16 +00007610static int
7611waitproc(block, status)
7612 int block;
7613 int *status;
7614{
Eric Andersencb57d552001-06-28 07:25:16 +00007615 int flags;
7616
7617 flags = 0;
Eric Andersen2870d962001-07-02 17:27:21 +00007618#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +00007619 if (jobctl)
7620 flags |= WUNTRACED;
7621#endif
7622 if (block == 0)
7623 flags |= WNOHANG;
7624 return wait3(status, flags, (struct rusage *)NULL);
Eric Andersencb57d552001-06-28 07:25:16 +00007625}
7626
7627/*
7628 * return 1 if there are stopped jobs, otherwise 0
7629 */
Eric Andersencb57d552001-06-28 07:25:16 +00007630static int
Eric Andersen2870d962001-07-02 17:27:21 +00007631stoppedjobs(void)
Eric Andersencb57d552001-06-28 07:25:16 +00007632{
7633 int jobno;
7634 struct job *jp;
7635
7636 if (job_warning)
7637 return (0);
7638 for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
7639 if (jp->used == 0)
7640 continue;
7641 if (jp->state == JOBSTOPPED) {
7642 out2str("You have stopped jobs.\n");
7643 job_warning = 2;
7644 return (1);
7645 }
7646 }
7647
7648 return (0);
7649}
7650
7651/*
7652 * Return a string identifying a command (to be printed by the
7653 * jobs command.
7654 */
7655
7656static char *cmdnextc;
7657static int cmdnleft;
Eric Andersen2870d962001-07-02 17:27:21 +00007658#define MAXCMDTEXT 200
Eric Andersencb57d552001-06-28 07:25:16 +00007659
Eric Andersen2870d962001-07-02 17:27:21 +00007660static void
7661cmdputs(const char *s)
7662{
7663 const char *p;
7664 char *q;
7665 char c;
7666 int subtype = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00007667
Eric Andersen2870d962001-07-02 17:27:21 +00007668 if (cmdnleft <= 0)
7669 return;
7670 p = s;
7671 q = cmdnextc;
7672 while ((c = *p++) != '\0') {
7673 if (c == CTLESC)
7674 *q++ = *p++;
7675 else if (c == CTLVAR) {
7676 *q++ = '$';
7677 if (--cmdnleft > 0)
7678 *q++ = '{';
7679 subtype = *p++;
7680 } else if (c == '=' && subtype != 0) {
7681 *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL];
7682 subtype = 0;
7683 } else if (c == CTLENDVAR) {
7684 *q++ = '}';
7685 } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE)
7686 cmdnleft++; /* ignore it */
7687 else
7688 *q++ = c;
7689 if (--cmdnleft <= 0) {
7690 *q++ = '.';
7691 *q++ = '.';
7692 *q++ = '.';
7693 break;
7694 }
7695 }
7696 cmdnextc = q;
Eric Andersencb57d552001-06-28 07:25:16 +00007697}
7698
7699
7700static void
Eric Andersen2870d962001-07-02 17:27:21 +00007701cmdtxt(const union node *n)
7702{
Eric Andersencb57d552001-06-28 07:25:16 +00007703 union node *np;
7704 struct nodelist *lp;
7705 const char *p;
7706 int i;
7707 char s[2];
7708
7709 if (n == NULL)
7710 return;
7711 switch (n->type) {
7712 case NSEMI:
7713 cmdtxt(n->nbinary.ch1);
7714 cmdputs("; ");
7715 cmdtxt(n->nbinary.ch2);
7716 break;
7717 case NAND:
7718 cmdtxt(n->nbinary.ch1);
7719 cmdputs(" && ");
7720 cmdtxt(n->nbinary.ch2);
7721 break;
7722 case NOR:
7723 cmdtxt(n->nbinary.ch1);
7724 cmdputs(" || ");
7725 cmdtxt(n->nbinary.ch2);
7726 break;
7727 case NPIPE:
7728 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
7729 cmdtxt(lp->n);
7730 if (lp->next)
7731 cmdputs(" | ");
7732 }
7733 break;
7734 case NSUBSHELL:
7735 cmdputs("(");
7736 cmdtxt(n->nredir.n);
7737 cmdputs(")");
7738 break;
7739 case NREDIR:
7740 case NBACKGND:
7741 cmdtxt(n->nredir.n);
7742 break;
7743 case NIF:
7744 cmdputs("if ");
7745 cmdtxt(n->nif.test);
7746 cmdputs("; then ");
7747 cmdtxt(n->nif.ifpart);
7748 cmdputs("...");
7749 break;
7750 case NWHILE:
7751 cmdputs("while ");
7752 goto until;
7753 case NUNTIL:
7754 cmdputs("until ");
7755until:
7756 cmdtxt(n->nbinary.ch1);
7757 cmdputs("; do ");
7758 cmdtxt(n->nbinary.ch2);
7759 cmdputs("; done");
7760 break;
7761 case NFOR:
7762 cmdputs("for ");
7763 cmdputs(n->nfor.var);
7764 cmdputs(" in ...");
7765 break;
7766 case NCASE:
7767 cmdputs("case ");
7768 cmdputs(n->ncase.expr->narg.text);
7769 cmdputs(" in ...");
7770 break;
7771 case NDEFUN:
7772 cmdputs(n->narg.text);
7773 cmdputs("() ...");
7774 break;
7775 case NCMD:
7776 for (np = n->ncmd.args ; np ; np = np->narg.next) {
7777 cmdtxt(np);
7778 if (np->narg.next)
7779 cmdputs(spcstr);
7780 }
7781 for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
7782 cmdputs(spcstr);
7783 cmdtxt(np);
7784 }
7785 break;
7786 case NARG:
7787 cmdputs(n->narg.text);
7788 break;
7789 case NTO:
7790 p = ">"; i = 1; goto redir;
7791 case NAPPEND:
7792 p = ">>"; i = 1; goto redir;
7793 case NTOFD:
7794 p = ">&"; i = 1; goto redir;
7795 case NTOOV:
7796 p = ">|"; i = 1; goto redir;
7797 case NFROM:
7798 p = "<"; i = 0; goto redir;
7799 case NFROMFD:
7800 p = "<&"; i = 0; goto redir;
7801 case NFROMTO:
7802 p = "<>"; i = 0; goto redir;
7803redir:
7804 if (n->nfile.fd != i) {
7805 s[0] = n->nfile.fd + '0';
7806 s[1] = '\0';
7807 cmdputs(s);
7808 }
7809 cmdputs(p);
7810 if (n->type == NTOFD || n->type == NFROMFD) {
7811 s[0] = n->ndup.dupfd + '0';
7812 s[1] = '\0';
7813 cmdputs(s);
7814 } else {
7815 cmdtxt(n->nfile.fname);
7816 }
7817 break;
7818 case NHERE:
7819 case NXHERE:
7820 cmdputs("<<...");
7821 break;
7822 default:
7823 cmdputs("???");
7824 break;
7825 }
7826}
7827
7828
Eric Andersen2870d962001-07-02 17:27:21 +00007829static char *
7830commandtext(const union node *n)
7831{
7832 char *name;
Eric Andersencb57d552001-06-28 07:25:16 +00007833
Eric Andersen2870d962001-07-02 17:27:21 +00007834 cmdnextc = name = ckmalloc(MAXCMDTEXT);
7835 cmdnleft = MAXCMDTEXT - 4;
7836 cmdtxt(n);
7837 *cmdnextc = '\0';
7838 return name;
Eric Andersencb57d552001-06-28 07:25:16 +00007839}
7840
Eric Andersen2870d962001-07-02 17:27:21 +00007841
Eric Andersencb57d552001-06-28 07:25:16 +00007842static void waitonint(int sig) {
7843 intreceived = 1;
7844 return;
7845}
Eric Andersencb57d552001-06-28 07:25:16 +00007846/*
7847 * Routines to check for mail. (Perhaps make part of main.c?)
7848 */
7849
7850
7851#define MAXMBOXES 10
7852
7853
Eric Andersen2870d962001-07-02 17:27:21 +00007854static int nmboxes; /* number of mailboxes */
7855static time_t mailtime[MAXMBOXES]; /* times of mailboxes */
Eric Andersencb57d552001-06-28 07:25:16 +00007856
7857
7858
7859/*
7860 * Print appropriate message(s) if mail has arrived. If the argument is
7861 * nozero, then the value of MAIL has changed, so we just update the
7862 * values.
7863 */
7864
7865static void
Eric Andersen2870d962001-07-02 17:27:21 +00007866chkmail(int silent)
Eric Andersencb57d552001-06-28 07:25:16 +00007867{
7868 int i;
7869 const char *mpath;
7870 char *p;
7871 char *q;
7872 struct stackmark smark;
7873 struct stat statb;
7874
7875 if (silent)
7876 nmboxes = 10;
7877 if (nmboxes == 0)
7878 return;
7879 setstackmark(&smark);
7880 mpath = mpathset()? mpathval() : mailval();
7881 for (i = 0 ; i < nmboxes ; i++) {
7882 p = padvance(&mpath, nullstr);
7883 if (p == NULL)
7884 break;
7885 if (*p == '\0')
7886 continue;
7887 for (q = p ; *q ; q++);
7888#ifdef DEBUG
7889 if (q[-1] != '/')
7890 abort();
7891#endif
Eric Andersen2870d962001-07-02 17:27:21 +00007892 q[-1] = '\0'; /* delete trailing '/' */
Eric Andersencb57d552001-06-28 07:25:16 +00007893 if (stat(p, &statb) < 0)
7894 statb.st_size = 0;
7895 if (statb.st_size > mailtime[i] && ! silent) {
7896 outfmt(
7897 &errout, snlfmt,
7898 pathopt? pathopt : "you have mail"
7899 );
7900 }
7901 mailtime[i] = statb.st_size;
Eric Andersencb57d552001-06-28 07:25:16 +00007902 }
7903 nmboxes = i;
7904 popstackmark(&smark);
7905}
Eric Andersencb57d552001-06-28 07:25:16 +00007906
7907#define PROFILE 0
7908
Eric Andersencb57d552001-06-28 07:25:16 +00007909#if PROFILE
Eric Andersen2870d962001-07-02 17:27:21 +00007910static short profile_buf[16384];
Eric Andersencb57d552001-06-28 07:25:16 +00007911extern int etext();
7912#endif
7913
Eric Andersen2870d962001-07-02 17:27:21 +00007914static void read_profile (const char *);
7915static char *find_dot_file (char *);
7916static void cmdloop (int);
7917static void options (int);
7918static void minus_o (char *, int);
7919static void setoption (int, int);
7920static void procargs (int, char **);
Eric Andersencb57d552001-06-28 07:25:16 +00007921
Eric Andersen2870d962001-07-02 17:27:21 +00007922
Eric Andersencb57d552001-06-28 07:25:16 +00007923/*
7924 * Main routine. We initialize things, parse the arguments, execute
7925 * profiles if we're a login shell, and then call cmdloop to execute
7926 * commands. The setjmp call sets up the location to jump to when an
7927 * exception occurs. When an exception occurs the variable "state"
7928 * is used to figure out how far we had gotten.
7929 */
7930
7931int
7932shell_main(argc, argv)
7933 int argc;
7934 char **argv;
7935{
7936 struct jmploc jmploc;
7937 struct stackmark smark;
7938 volatile int state;
7939 char *shinit;
7940
7941 DOTCMD = find_builtin(".");
7942 BLTINCMD = find_builtin("builtin");
Eric Andersencb57d552001-06-28 07:25:16 +00007943 EXECCMD = find_builtin("exec");
7944 EVALCMD = find_builtin("eval");
7945
7946#if PROFILE
7947 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
7948#endif
7949#if defined(linux) || defined(__GNU__)
7950 signal(SIGCHLD, SIG_DFL);
7951#endif
7952 state = 0;
7953 if (setjmp(jmploc.loc)) {
7954 INTOFF;
7955 /*
7956 * When a shell procedure is executed, we raise the
7957 * exception EXSHELLPROC to clean up before executing
7958 * the shell procedure.
7959 */
7960 switch (exception) {
7961 case EXSHELLPROC:
7962 rootpid = getpid();
7963 rootshell = 1;
7964 minusc = NULL;
7965 state = 3;
7966 break;
7967
7968 case EXEXEC:
7969 exitstatus = exerrno;
7970 break;
7971
7972 case EXERROR:
7973 exitstatus = 2;
7974 break;
7975
7976 default:
7977 break;
7978 }
7979
7980 if (exception != EXSHELLPROC) {
7981 if (state == 0 || iflag == 0 || ! rootshell)
7982 exitshell(exitstatus);
7983 }
7984 reset();
Eric Andersen2870d962001-07-02 17:27:21 +00007985 if (exception == EXINT) {
Eric Andersencb57d552001-06-28 07:25:16 +00007986 out2c('\n');
7987#ifdef FLUSHERR
7988 flushout(out2);
7989#endif
7990 }
7991 popstackmark(&smark);
Eric Andersen2870d962001-07-02 17:27:21 +00007992 FORCEINTON; /* enable interrupts */
Eric Andersencb57d552001-06-28 07:25:16 +00007993 if (state == 1)
7994 goto state1;
7995 else if (state == 2)
7996 goto state2;
7997 else if (state == 3)
7998 goto state3;
7999 else
8000 goto state4;
8001 }
8002 handler = &jmploc;
8003#ifdef DEBUG
8004 opentrace();
8005 trputs("Shell args: "); trargs(argv);
8006#endif
8007 rootpid = getpid();
8008 rootshell = 1;
8009 init();
8010 setstackmark(&smark);
8011 procargs(argc, argv);
8012 if (argv[0] && argv[0][0] == '-') {
8013 state = 1;
8014 read_profile("/etc/profile");
8015state1:
8016 state = 2;
8017 read_profile(".profile");
8018 }
8019state2:
8020 state = 3;
8021#ifndef linux
8022 if (getuid() == geteuid() && getgid() == getegid()) {
8023#endif
8024 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
8025 state = 3;
8026 read_profile(shinit);
8027 }
8028#ifndef linux
8029 }
8030#endif
8031state3:
8032 state = 4;
8033 if (sflag == 0 || minusc) {
8034 static int sigs[] = {
Eric Andersen2870d962001-07-02 17:27:21 +00008035 SIGINT, SIGQUIT, SIGHUP,
Eric Andersencb57d552001-06-28 07:25:16 +00008036#ifdef SIGTSTP
8037 SIGTSTP,
8038#endif
8039 SIGPIPE
8040 };
8041#define SIGSSIZE (sizeof(sigs)/sizeof(sigs[0]))
8042 int i;
8043
8044 for (i = 0; i < SIGSSIZE; i++)
8045 setsignal(sigs[i]);
8046 }
8047
8048 if (minusc)
8049 evalstring(minusc, 0);
8050
8051 if (sflag || minusc == NULL) {
Eric Andersen2870d962001-07-02 17:27:21 +00008052state4: /* XXX ??? - why isn't this before the "if" statement */
Eric Andersencb57d552001-06-28 07:25:16 +00008053 cmdloop(1);
8054 }
8055#if PROFILE
8056 monitor(0);
8057#endif
8058 exitshell(exitstatus);
8059 /* NOTREACHED */
8060}
8061
8062
8063/*
8064 * Read and execute commands. "Top" is nonzero for the top level command
8065 * loop; it turns on prompting if the shell is interactive.
8066 */
8067
8068static void
Eric Andersen2870d962001-07-02 17:27:21 +00008069cmdloop(int top)
Eric Andersencb57d552001-06-28 07:25:16 +00008070{
8071 union node *n;
8072 struct stackmark smark;
8073 int inter;
8074 int numeof = 0;
8075
8076 TRACE(("cmdloop(%d) called\n", top));
8077 setstackmark(&smark);
8078 for (;;) {
8079 if (pendingsigs)
8080 dotrap();
8081 inter = 0;
8082 if (iflag && top) {
8083 inter++;
8084 showjobs(1);
8085 chkmail(0);
8086 flushout(&output);
8087 }
8088 n = parsecmd(inter);
8089 /* showtree(n); DEBUG */
8090 if (n == NEOF) {
8091 if (!top || numeof >= 50)
8092 break;
8093 if (!stoppedjobs()) {
8094 if (!Iflag)
8095 break;
8096 out2str("\nUse \"exit\" to leave shell.\n");
8097 }
8098 numeof++;
8099 } else if (n != NULL && nflag == 0) {
8100 job_warning = (job_warning == 2) ? 1 : 0;
8101 numeof = 0;
8102 evaltree(n, 0);
8103 }
8104 popstackmark(&smark);
8105 setstackmark(&smark);
8106 if (evalskip == SKIPFILE) {
8107 evalskip = 0;
8108 break;
8109 }
8110 }
8111 popstackmark(&smark);
8112}
8113
8114
8115
8116/*
8117 * Read /etc/profile or .profile. Return on error.
8118 */
8119
8120static void
8121read_profile(name)
8122 const char *name;
8123{
8124 int fd;
8125 int xflag_set = 0;
8126 int vflag_set = 0;
8127
8128 INTOFF;
8129 if ((fd = open(name, O_RDONLY)) >= 0)
8130 setinputfd(fd, 1);
8131 INTON;
8132 if (fd < 0)
8133 return;
8134 /* -q turns off -x and -v just when executing init files */
8135 if (qflag) {
8136 if (xflag)
8137 xflag = 0, xflag_set = 1;
8138 if (vflag)
8139 vflag = 0, vflag_set = 1;
8140 }
8141 cmdloop(0);
8142 if (qflag) {
8143 if (xflag_set)
8144 xflag = 1;
8145 if (vflag_set)
8146 vflag = 1;
8147 }
8148 popfile();
8149}
8150
8151
8152
8153/*
8154 * Read a file containing shell functions.
8155 */
8156
8157static void
Eric Andersen2870d962001-07-02 17:27:21 +00008158readcmdfile(const char *name)
Eric Andersencb57d552001-06-28 07:25:16 +00008159{
8160 int fd;
8161
8162 INTOFF;
8163 if ((fd = open(name, O_RDONLY)) >= 0)
8164 setinputfd(fd, 1);
8165 else
8166 error("Can't open %s", name);
8167 INTON;
8168 cmdloop(0);
8169 popfile();
8170}
8171
8172
8173
8174/*
8175 * Take commands from a file. To be compatable we should do a path
8176 * search for the file, which is necessary to find sub-commands.
8177 */
8178
8179
8180static char *
8181find_dot_file(mybasename)
8182 char *mybasename;
8183{
8184 char *fullname;
8185 const char *path = pathval();
8186 struct stat statb;
8187
8188 /* don't try this for absolute or relative paths */
8189 if (strchr(mybasename, '/'))
8190 return mybasename;
8191
8192 while ((fullname = padvance(&path, mybasename)) != NULL) {
8193 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
8194 /*
8195 * Don't bother freeing here, since it will
8196 * be freed by the caller.
8197 */
8198 return fullname;
8199 }
8200 stunalloc(fullname);
8201 }
8202
8203 /* not found in the PATH */
8204 error("%s: not found", mybasename);
8205 /* NOTREACHED */
8206}
8207
8208static int
8209dotcmd(argc, argv)
8210 int argc;
8211 char **argv;
8212{
8213 struct strlist *sp;
8214 exitstatus = 0;
8215
8216 for (sp = cmdenviron; sp ; sp = sp->next)
8217 setvareq(savestr(sp->text), VSTRFIXED|VTEXTFIXED);
8218
Eric Andersen2870d962001-07-02 17:27:21 +00008219 if (argc >= 2) { /* That's what SVR2 does */
Eric Andersencb57d552001-06-28 07:25:16 +00008220 char *fullname;
8221 struct stackmark smark;
8222
8223 setstackmark(&smark);
8224 fullname = find_dot_file(argv[1]);
8225 setinputfile(fullname, 1);
8226 commandname = fullname;
8227 cmdloop(0);
8228 popfile();
8229 popstackmark(&smark);
8230 }
8231 return exitstatus;
8232}
8233
8234
8235static int
8236exitcmd(argc, argv)
8237 int argc;
8238 char **argv;
8239{
8240 if (stoppedjobs())
8241 return 0;
8242 if (argc > 1)
8243 exitstatus = number(argv[1]);
8244 else
8245 exitstatus = oexitstatus;
8246 exitshell(exitstatus);
8247 /* NOTREACHED */
8248}
Eric Andersen2870d962001-07-02 17:27:21 +00008249static pointer
8250stalloc(int nbytes)
Eric Andersencb57d552001-06-28 07:25:16 +00008251{
8252 char *p;
8253
8254 nbytes = ALIGN(nbytes);
8255 if (nbytes > stacknleft) {
8256 int blocksize;
8257 struct stack_block *sp;
8258
8259 blocksize = nbytes;
8260 if (blocksize < MINSIZE)
8261 blocksize = MINSIZE;
8262 INTOFF;
8263 sp = ckmalloc(sizeof(struct stack_block) - MINSIZE + blocksize);
8264 sp->prev = stackp;
8265 stacknxt = sp->space;
8266 stacknleft = blocksize;
8267 stackp = sp;
8268 INTON;
8269 }
8270 p = stacknxt;
8271 stacknxt += nbytes;
8272 stacknleft -= nbytes;
8273 return p;
8274}
8275
8276
8277static void
Eric Andersen2870d962001-07-02 17:27:21 +00008278stunalloc(pointer p)
8279{
Eric Andersencb57d552001-06-28 07:25:16 +00008280#ifdef DEBUG
Eric Andersen2870d962001-07-02 17:27:21 +00008281 if (p == NULL) { /*DEBUG */
Eric Andersencb57d552001-06-28 07:25:16 +00008282 write(2, "stunalloc\n", 10);
8283 abort();
8284 }
8285#endif
8286 if (!(stacknxt >= (char *)p && (char *)p >= stackp->space)) {
8287 p = stackp->space;
8288 }
8289 stacknleft += stacknxt - (char *)p;
8290 stacknxt = p;
8291}
8292
8293
Eric Andersencb57d552001-06-28 07:25:16 +00008294static void
Eric Andersen2870d962001-07-02 17:27:21 +00008295setstackmark(struct stackmark *mark)
8296{
Eric Andersencb57d552001-06-28 07:25:16 +00008297 mark->stackp = stackp;
8298 mark->stacknxt = stacknxt;
8299 mark->stacknleft = stacknleft;
8300 mark->marknext = markp;
8301 markp = mark;
8302}
8303
8304
8305static void
Eric Andersen2870d962001-07-02 17:27:21 +00008306popstackmark(struct stackmark *mark)
8307{
Eric Andersencb57d552001-06-28 07:25:16 +00008308 struct stack_block *sp;
8309
8310 INTOFF;
8311 markp = mark->marknext;
8312 while (stackp != mark->stackp) {
8313 sp = stackp;
8314 stackp = sp->prev;
8315 ckfree(sp);
8316 }
8317 stacknxt = mark->stacknxt;
8318 stacknleft = mark->stacknleft;
8319 INTON;
8320}
8321
8322
8323/*
8324 * When the parser reads in a string, it wants to stick the string on the
8325 * stack and only adjust the stack pointer when it knows how big the
8326 * string is. Stackblock (defined in stack.h) returns a pointer to a block
8327 * of space on top of the stack and stackblocklen returns the length of
8328 * this block. Growstackblock will grow this space by at least one byte,
8329 * possibly moving it (like realloc). Grabstackblock actually allocates the
8330 * part of the block that has been used.
8331 */
8332
8333static void
Eric Andersen2870d962001-07-02 17:27:21 +00008334growstackblock(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00008335 char *p;
8336 int newlen = ALIGN(stacknleft * 2 + 100);
8337 char *oldspace = stacknxt;
8338 int oldlen = stacknleft;
8339 struct stack_block *sp;
8340 struct stack_block *oldstackp;
8341
8342 if (stacknxt == stackp->space && stackp != &stackbase) {
8343 INTOFF;
8344 oldstackp = stackp;
8345 sp = stackp;
8346 stackp = sp->prev;
8347 sp = ckrealloc((pointer)sp, sizeof(struct stack_block) - MINSIZE + newlen);
8348 sp->prev = stackp;
8349 stackp = sp;
8350 stacknxt = sp->space;
8351 stacknleft = newlen;
8352 {
8353 /* Stack marks pointing to the start of the old block
Eric Andersen2870d962001-07-02 17:27:21 +00008354 * must be relocated to point to the new block
Eric Andersencb57d552001-06-28 07:25:16 +00008355 */
8356 struct stackmark *xmark;
8357 xmark = markp;
8358 while (xmark != NULL && xmark->stackp == oldstackp) {
8359 xmark->stackp = stackp;
8360 xmark->stacknxt = stacknxt;
8361 xmark->stacknleft = stacknleft;
8362 xmark = xmark->marknext;
8363 }
8364 }
8365 INTON;
8366 } else {
8367 p = stalloc(newlen);
8368 memcpy(p, oldspace, oldlen);
Eric Andersen2870d962001-07-02 17:27:21 +00008369 stacknxt = p; /* free the space */
8370 stacknleft += newlen; /* we just allocated */
Eric Andersencb57d552001-06-28 07:25:16 +00008371 }
8372}
8373
8374
8375
Eric Andersen2870d962001-07-02 17:27:21 +00008376static inline void
8377grabstackblock(int len)
Eric Andersencb57d552001-06-28 07:25:16 +00008378{
8379 len = ALIGN(len);
8380 stacknxt += len;
8381 stacknleft -= len;
8382}
8383
8384
8385
8386/*
8387 * The following routines are somewhat easier to use that the above.
8388 * The user declares a variable of type STACKSTR, which may be declared
8389 * to be a register. The macro STARTSTACKSTR initializes things. Then
8390 * the user uses the macro STPUTC to add characters to the string. In
8391 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
8392 * grown as necessary. When the user is done, she can just leave the
8393 * string there and refer to it using stackblock(). Or she can allocate
8394 * the space for it using grabstackstr(). If it is necessary to allow
8395 * someone else to use the stack temporarily and then continue to grow
8396 * the string, the user should use grabstack to allocate the space, and
8397 * then call ungrabstr(p) to return to the previous mode of operation.
8398 *
8399 * USTPUTC is like STPUTC except that it doesn't check for overflow.
8400 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
8401 * is space for at least one character.
8402 */
8403
8404
8405static char *
Eric Andersen2870d962001-07-02 17:27:21 +00008406growstackstr(void) {
Eric Andersencb57d552001-06-28 07:25:16 +00008407 int len = stackblocksize();
8408 if (herefd >= 0 && len >= 1024) {
8409 xwrite(herefd, stackblock(), len);
8410 sstrnleft = len - 1;
8411 return stackblock();
8412 }
8413 growstackblock();
8414 sstrnleft = stackblocksize() - len - 1;
8415 return stackblock() + len;
8416}
8417
8418
8419/*
8420 * Called from CHECKSTRSPACE.
8421 */
8422
8423static char *
8424makestrspace(size_t newlen) {
8425 int len = stackblocksize() - sstrnleft;
8426 do {
8427 growstackblock();
8428 sstrnleft = stackblocksize() - len;
8429 } while (sstrnleft < newlen);
8430 return stackblock() + len;
8431}
8432
8433
8434
8435static void
Eric Andersen2870d962001-07-02 17:27:21 +00008436ungrabstackstr(char *s, char *p)
8437{
Eric Andersencb57d552001-06-28 07:25:16 +00008438 stacknleft += stacknxt - s;
8439 stacknxt = s;
8440 sstrnleft = stacknleft - (p - s);
8441}
Eric Andersencb57d552001-06-28 07:25:16 +00008442/*
8443 * Miscelaneous builtins.
8444 */
8445
8446
8447#undef rflag
8448
8449#ifdef __GLIBC__
Eric Andersen2870d962001-07-02 17:27:21 +00008450static mode_t getmode(const void *, mode_t);
Eric Andersencb57d552001-06-28 07:25:16 +00008451static void *setmode(const char *);
8452
8453#if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1
8454typedef enum __rlimit_resource rlim_t;
8455#endif
8456#endif
8457
8458
8459
8460/*
8461 * The read builtin. The -e option causes backslashes to escape the
8462 * following character.
8463 *
8464 * This uses unbuffered input, which may be avoidable in some cases.
8465 */
8466
8467static int
8468readcmd(argc, argv)
8469 int argc;
8470 char **argv;
8471{
8472 char **ap;
8473 int backslash;
8474 char c;
8475 int rflag;
8476 char *prompt;
8477 const char *ifs;
8478 char *p;
8479 int startword;
8480 int status;
8481 int i;
8482
8483 rflag = 0;
8484 prompt = NULL;
8485 while ((i = nextopt("p:r")) != '\0') {
8486 if (i == 'p')
8487 prompt = optionarg;
8488 else
8489 rflag = 1;
8490 }
8491 if (prompt && isatty(0)) {
8492 putprompt(prompt);
8493 flushall();
8494 }
8495 if (*(ap = argptr) == NULL)
8496 error("arg count");
8497 if ((ifs = bltinlookup("IFS")) == NULL)
8498 ifs = defifs;
8499 status = 0;
8500 startword = 1;
8501 backslash = 0;
8502 STARTSTACKSTR(p);
8503 for (;;) {
8504 if (read(0, &c, 1) != 1) {
8505 status = 1;
8506 break;
8507 }
8508 if (c == '\0')
8509 continue;
8510 if (backslash) {
8511 backslash = 0;
8512 if (c != '\n')
8513 STPUTC(c, p);
8514 continue;
8515 }
8516 if (!rflag && c == '\\') {
8517 backslash++;
8518 continue;
8519 }
8520 if (c == '\n')
8521 break;
8522 if (startword && *ifs == ' ' && strchr(ifs, c)) {
8523 continue;
8524 }
8525 startword = 0;
8526 if (backslash && c == '\\') {
8527 if (read(0, &c, 1) != 1) {
8528 status = 1;
8529 break;
8530 }
8531 STPUTC(c, p);
8532 } else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
8533 STACKSTRNUL(p);
8534 setvar(*ap, stackblock(), 0);
8535 ap++;
8536 startword = 1;
8537 STARTSTACKSTR(p);
8538 } else {
8539 STPUTC(c, p);
8540 }
8541 }
8542 STACKSTRNUL(p);
8543 /* Remove trailing blanks */
8544 while (stackblock() <= --p && strchr(ifs, *p) != NULL)
8545 *p = '\0';
8546 setvar(*ap, stackblock(), 0);
8547 while (*++ap != NULL)
8548 setvar(*ap, nullstr, 0);
8549 return status;
8550}
8551
8552
8553
8554static int
8555umaskcmd(argc, argv)
8556 int argc;
8557 char **argv;
8558{
8559 char *ap;
8560 int mask;
8561 int i;
8562 int symbolic_mode = 0;
8563
8564 while ((i = nextopt("S")) != '\0') {
8565 symbolic_mode = 1;
8566 }
8567
8568 INTOFF;
8569 mask = umask(0);
8570 umask(mask);
8571 INTON;
8572
8573 if ((ap = *argptr) == NULL) {
8574 if (symbolic_mode) {
8575 char u[4], g[4], o[4];
8576
8577 i = 0;
8578 if ((mask & S_IRUSR) == 0)
8579 u[i++] = 'r';
8580 if ((mask & S_IWUSR) == 0)
8581 u[i++] = 'w';
8582 if ((mask & S_IXUSR) == 0)
8583 u[i++] = 'x';
8584 u[i] = '\0';
8585
8586 i = 0;
8587 if ((mask & S_IRGRP) == 0)
8588 g[i++] = 'r';
8589 if ((mask & S_IWGRP) == 0)
8590 g[i++] = 'w';
8591 if ((mask & S_IXGRP) == 0)
8592 g[i++] = 'x';
8593 g[i] = '\0';
8594
8595 i = 0;
8596 if ((mask & S_IROTH) == 0)
8597 o[i++] = 'r';
8598 if ((mask & S_IWOTH) == 0)
8599 o[i++] = 'w';
8600 if ((mask & S_IXOTH) == 0)
8601 o[i++] = 'x';
8602 o[i] = '\0';
8603
8604 out1fmt("u=%s,g=%s,o=%s\n", u, g, o);
8605 } else {
8606 out1fmt("%.4o\n", mask);
8607 }
8608 } else {
8609 if (isdigit((unsigned char)*ap)) {
8610 mask = 0;
8611 do {
8612 if (*ap >= '8' || *ap < '0')
8613 error("Illegal number: %s", argv[1]);
8614 mask = (mask << 3) + (*ap - '0');
8615 } while (*++ap != '\0');
8616 umask(mask);
8617 } else {
8618 void *set;
8619
8620 INTOFF;
8621 if ((set = setmode(ap)) != 0) {
8622 mask = getmode(set, ~mask & 0777);
8623 ckfree(set);
8624 }
8625 INTON;
8626 if (!set)
8627 error("Illegal mode: %s", ap);
8628
8629 umask(~mask & 0777);
8630 }
8631 }
8632 return 0;
8633}
8634
8635/*
8636 * ulimit builtin
8637 *
8638 * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
8639 * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
8640 * ash by J.T. Conklin.
8641 *
8642 * Public domain.
8643 */
8644
8645struct limits {
8646 const char *name;
Eric Andersen2870d962001-07-02 17:27:21 +00008647 int cmd;
8648 int factor; /* multiply by to get rlim_{cur,max} values */
8649 char option;
Eric Andersencb57d552001-06-28 07:25:16 +00008650};
8651
8652static const struct limits limits[] = {
8653#ifdef RLIMIT_CPU
Eric Andersen2870d962001-07-02 17:27:21 +00008654 { "time(seconds)", RLIMIT_CPU, 1, 't' },
Eric Andersencb57d552001-06-28 07:25:16 +00008655#endif
8656#ifdef RLIMIT_FSIZE
Eric Andersen2870d962001-07-02 17:27:21 +00008657 { "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
Eric Andersencb57d552001-06-28 07:25:16 +00008658#endif
8659#ifdef RLIMIT_DATA
Eric Andersen2870d962001-07-02 17:27:21 +00008660 { "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
Eric Andersencb57d552001-06-28 07:25:16 +00008661#endif
8662#ifdef RLIMIT_STACK
Eric Andersen2870d962001-07-02 17:27:21 +00008663 { "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
Eric Andersencb57d552001-06-28 07:25:16 +00008664#endif
8665#ifdef RLIMIT_CORE
Eric Andersen2870d962001-07-02 17:27:21 +00008666 { "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
Eric Andersencb57d552001-06-28 07:25:16 +00008667#endif
8668#ifdef RLIMIT_RSS
Eric Andersen2870d962001-07-02 17:27:21 +00008669 { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
Eric Andersencb57d552001-06-28 07:25:16 +00008670#endif
8671#ifdef RLIMIT_MEMLOCK
Eric Andersen2870d962001-07-02 17:27:21 +00008672 { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
Eric Andersencb57d552001-06-28 07:25:16 +00008673#endif
8674#ifdef RLIMIT_NPROC
Eric Andersen2870d962001-07-02 17:27:21 +00008675 { "process(processes)", RLIMIT_NPROC, 1, 'p' },
Eric Andersencb57d552001-06-28 07:25:16 +00008676#endif
8677#ifdef RLIMIT_NOFILE
Eric Andersen2870d962001-07-02 17:27:21 +00008678 { "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' },
Eric Andersencb57d552001-06-28 07:25:16 +00008679#endif
8680#ifdef RLIMIT_VMEM
Eric Andersen2870d962001-07-02 17:27:21 +00008681 { "vmemory(kbytes)", RLIMIT_VMEM, 1024, 'v' },
Eric Andersencb57d552001-06-28 07:25:16 +00008682#endif
8683#ifdef RLIMIT_SWAP
Eric Andersen2870d962001-07-02 17:27:21 +00008684 { "swap(kbytes)", RLIMIT_SWAP, 1024, 'w' },
Eric Andersencb57d552001-06-28 07:25:16 +00008685#endif
Eric Andersen2870d962001-07-02 17:27:21 +00008686 { (char *) 0, 0, 0, '\0' }
Eric Andersencb57d552001-06-28 07:25:16 +00008687};
8688
8689static int
8690ulimitcmd(argc, argv)
8691 int argc;
8692 char **argv;
8693{
Eric Andersen2870d962001-07-02 17:27:21 +00008694 int c;
Eric Andersencb57d552001-06-28 07:25:16 +00008695 rlim_t val = 0;
8696 enum { SOFT = 0x1, HARD = 0x2 }
8697 how = SOFT | HARD;
Eric Andersen2870d962001-07-02 17:27:21 +00008698 const struct limits *l;
8699 int set, all = 0;
8700 int optc, what;
8701 struct rlimit limit;
Eric Andersencb57d552001-06-28 07:25:16 +00008702
8703 what = 'f';
8704 while ((optc = nextopt("HSatfdsmcnpl")) != '\0')
8705 switch (optc) {
8706 case 'H':
8707 how = HARD;
8708 break;
8709 case 'S':
8710 how = SOFT;
8711 break;
8712 case 'a':
8713 all = 1;
8714 break;
8715 default:
8716 what = optc;
8717 }
8718
8719 for (l = limits; l->name && l->option != what; l++)
8720 ;
8721 if (!l->name)
8722 error("internal error (%c)", what);
8723
8724 set = *argptr ? 1 : 0;
8725 if (set) {
8726 char *p = *argptr;
8727
8728 if (all || argptr[1])
8729 error("too many arguments");
8730 if (strcmp(p, "unlimited") == 0)
8731 val = RLIM_INFINITY;
8732 else {
8733 val = (rlim_t) 0;
8734
8735 while ((c = *p++) >= '0' && c <= '9')
8736 {
8737 val = (val * 10) + (long)(c - '0');
8738 if (val < (rlim_t) 0)
8739 break;
8740 }
8741 if (c)
8742 error("bad number");
8743 val *= l->factor;
8744 }
8745 }
8746 if (all) {
8747 for (l = limits; l->name; l++) {
8748 getrlimit(l->cmd, &limit);
8749 if (how & SOFT)
8750 val = limit.rlim_cur;
8751 else if (how & HARD)
8752 val = limit.rlim_max;
8753
8754 out1fmt("%-20s ", l->name);
8755 if (val == RLIM_INFINITY)
8756 out1fmt("unlimited\n");
8757 else
8758 {
8759 val /= l->factor;
Eric Andersencb57d552001-06-28 07:25:16 +00008760 out1fmt("%lld\n", (long long) val);
Eric Andersencb57d552001-06-28 07:25:16 +00008761 }
8762 }
8763 return 0;
8764 }
8765
8766 getrlimit(l->cmd, &limit);
8767 if (set) {
8768 if (how & HARD)
8769 limit.rlim_max = val;
8770 if (how & SOFT)
8771 limit.rlim_cur = val;
8772 if (setrlimit(l->cmd, &limit) < 0)
Eric Andersen2870d962001-07-02 17:27:21 +00008773 error("error setting limit (%m)");
Eric Andersencb57d552001-06-28 07:25:16 +00008774 } else {
8775 if (how & SOFT)
8776 val = limit.rlim_cur;
8777 else if (how & HARD)
8778 val = limit.rlim_max;
8779
8780 if (val == RLIM_INFINITY)
8781 out1fmt("unlimited\n");
8782 else
8783 {
8784 val /= l->factor;
Eric Andersencb57d552001-06-28 07:25:16 +00008785 out1fmt("%lld\n", (long long) val);
Eric Andersencb57d552001-06-28 07:25:16 +00008786 }
8787 }
8788 return 0;
8789}
Eric Andersencb57d552001-06-28 07:25:16 +00008790/*
8791 * prefix -- see if pfx is a prefix of string.
8792 */
8793
8794static int
8795prefix(pfx, string)
8796 char const *pfx;
8797 char const *string;
8798 {
8799 while (*pfx) {
8800 if (*pfx++ != *string++)
8801 return 0;
8802 }
8803 return 1;
8804}
8805
Eric Andersen2870d962001-07-02 17:27:21 +00008806/*
8807 * Return true if s is a string of digits, and save munber in intptr
8808 * nagative is bad
8809 */
8810
8811static int
8812is_number(const char *p, int *intptr)
8813{
8814 int ret = 0;
8815
8816 do {
8817 if (! is_digit(*p))
8818 return 0;
8819 ret *= 10;
8820 ret += digit_val(*p);
8821 p++;
8822 } while (*p != '\0');
8823
8824 *intptr = ret;
8825 return 1;
8826}
Eric Andersencb57d552001-06-28 07:25:16 +00008827
8828/*
8829 * Convert a string of digits to an integer, printing an error message on
8830 * failure.
8831 */
8832
8833static int
Eric Andersen2870d962001-07-02 17:27:21 +00008834number(const char *s)
8835{
8836 int i;
8837 if (! is_number(s, &i))
Eric Andersencb57d552001-06-28 07:25:16 +00008838 error("Illegal number: %s", s);
Eric Andersen2870d962001-07-02 17:27:21 +00008839 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00008840}
8841
Eric Andersencb57d552001-06-28 07:25:16 +00008842/*
8843 * Produce a possibly single quoted string suitable as input to the shell.
8844 * The return string is allocated on the stack.
8845 */
8846
8847static char *
8848single_quote(const char *s) {
8849 char *p;
8850
8851 STARTSTACKSTR(p);
8852
8853 do {
8854 char *q = p;
8855 size_t len1, len1p, len2, len2p;
8856
8857 len1 = strcspn(s, "'");
8858 len2 = strspn(s + len1, "'");
8859
8860 len1p = len1 ? len1 + 2 : len1;
8861 switch (len2) {
8862 case 0:
8863 len2p = 0;
8864 break;
8865 case 1:
8866 len2p = 2;
8867 break;
8868 default:
8869 len2p = len2 + 2;
8870 }
8871
8872 CHECKSTRSPACE(len1p + len2p + 1, p);
8873
8874 if (len1) {
8875 *p = '\'';
8876#ifdef _GNU_SOURCE
8877 q = mempcpy(p + 1, s, len1);
8878#else
8879 q = p + 1 + len1;
8880 memcpy(p + 1, s, len1);
8881#endif
8882 *q++ = '\'';
8883 s += len1;
8884 }
8885
8886 switch (len2) {
8887 case 0:
8888 break;
8889 case 1:
8890 *q++ = '\\';
8891 *q = '\'';
8892 s++;
8893 break;
8894 default:
8895 *q = '"';
8896#ifdef _GNU_SOURCE
8897 *(char *) mempcpy(q + 1, s, len2) = '"';
8898#else
8899 q += 1 + len2;
8900 memcpy(q + 1, s, len2);
8901 *q = '"';
8902#endif
8903 s += len2;
8904 }
8905
8906 STADJUST(len1p + len2p, p);
8907 } while (*s);
8908
8909 USTPUTC(0, p);
8910
8911 return grabstackstr(p);
8912}
8913
8914/*
8915 * Like strdup but works with the ash stack.
8916 */
8917
8918static char *
8919sstrdup(const char *p)
8920{
8921 size_t len = strlen(p) + 1;
8922 return memcpy(stalloc(len), p, len);
8923}
8924
Eric Andersencb57d552001-06-28 07:25:16 +00008925
8926/*
Eric Andersencb57d552001-06-28 07:25:16 +00008927 * This file was generated by the mknodes program.
8928 */
8929
Eric Andersencb57d552001-06-28 07:25:16 +00008930/*
8931 * Routine for dealing with parsed shell commands.
8932 */
8933
8934
Eric Andersen2870d962001-07-02 17:27:21 +00008935static int funcblocksize; /* size of structures in function */
8936static int funcstringsize; /* size of strings in node */
8937static pointer funcblock; /* block to allocate function from */
8938static char *funcstring; /* block to allocate strings from */
Eric Andersencb57d552001-06-28 07:25:16 +00008939
8940static const short nodesize[26] = {
8941 ALIGN(sizeof (struct nbinary)),
8942 ALIGN(sizeof (struct ncmd)),
8943 ALIGN(sizeof (struct npipe)),
8944 ALIGN(sizeof (struct nredir)),
8945 ALIGN(sizeof (struct nredir)),
8946 ALIGN(sizeof (struct nredir)),
8947 ALIGN(sizeof (struct nbinary)),
8948 ALIGN(sizeof (struct nbinary)),
8949 ALIGN(sizeof (struct nif)),
8950 ALIGN(sizeof (struct nbinary)),
8951 ALIGN(sizeof (struct nbinary)),
8952 ALIGN(sizeof (struct nfor)),
8953 ALIGN(sizeof (struct ncase)),
8954 ALIGN(sizeof (struct nclist)),
8955 ALIGN(sizeof (struct narg)),
8956 ALIGN(sizeof (struct narg)),
8957 ALIGN(sizeof (struct nfile)),
8958 ALIGN(sizeof (struct nfile)),
8959 ALIGN(sizeof (struct nfile)),
8960 ALIGN(sizeof (struct nfile)),
8961 ALIGN(sizeof (struct nfile)),
8962 ALIGN(sizeof (struct ndup)),
8963 ALIGN(sizeof (struct ndup)),
8964 ALIGN(sizeof (struct nhere)),
8965 ALIGN(sizeof (struct nhere)),
8966 ALIGN(sizeof (struct nnot)),
8967};
8968
8969
Eric Andersen2870d962001-07-02 17:27:21 +00008970static void calcsize (union node *);
8971static void sizenodelist (struct nodelist *);
8972static union node *copynode (union node *);
8973static struct nodelist *copynodelist (struct nodelist *);
8974static char *nodesavestr (char *);
Eric Andersencb57d552001-06-28 07:25:16 +00008975
8976
8977
8978/*
8979 * Make a copy of a parse tree.
8980 */
8981
Eric Andersen2870d962001-07-02 17:27:21 +00008982static union node *
8983copyfunc(union node *n)
Eric Andersencb57d552001-06-28 07:25:16 +00008984{
8985 if (n == NULL)
8986 return NULL;
8987 funcblocksize = 0;
8988 funcstringsize = 0;
8989 calcsize(n);
8990 funcblock = ckmalloc(funcblocksize + funcstringsize);
8991 funcstring = (char *) funcblock + funcblocksize;
8992 return copynode(n);
8993}
8994
8995
8996
8997static void
8998calcsize(n)
8999 union node *n;
9000{
9001 if (n == NULL)
9002 return;
9003 funcblocksize += nodesize[n->type];
9004 switch (n->type) {
9005 case NSEMI:
9006 case NAND:
9007 case NOR:
9008 case NWHILE:
9009 case NUNTIL:
9010 calcsize(n->nbinary.ch2);
9011 calcsize(n->nbinary.ch1);
9012 break;
9013 case NCMD:
9014 calcsize(n->ncmd.redirect);
9015 calcsize(n->ncmd.args);
9016 calcsize(n->ncmd.assign);
9017 break;
9018 case NPIPE:
9019 sizenodelist(n->npipe.cmdlist);
9020 break;
9021 case NREDIR:
9022 case NBACKGND:
9023 case NSUBSHELL:
9024 calcsize(n->nredir.redirect);
9025 calcsize(n->nredir.n);
9026 break;
9027 case NIF:
9028 calcsize(n->nif.elsepart);
9029 calcsize(n->nif.ifpart);
9030 calcsize(n->nif.test);
9031 break;
9032 case NFOR:
9033 funcstringsize += strlen(n->nfor.var) + 1;
9034 calcsize(n->nfor.body);
9035 calcsize(n->nfor.args);
9036 break;
9037 case NCASE:
9038 calcsize(n->ncase.cases);
9039 calcsize(n->ncase.expr);
9040 break;
9041 case NCLIST:
9042 calcsize(n->nclist.body);
9043 calcsize(n->nclist.pattern);
9044 calcsize(n->nclist.next);
9045 break;
9046 case NDEFUN:
9047 case NARG:
9048 sizenodelist(n->narg.backquote);
9049 funcstringsize += strlen(n->narg.text) + 1;
9050 calcsize(n->narg.next);
9051 break;
9052 case NTO:
9053 case NFROM:
9054 case NFROMTO:
9055 case NAPPEND:
9056 case NTOOV:
9057 calcsize(n->nfile.fname);
9058 calcsize(n->nfile.next);
9059 break;
9060 case NTOFD:
9061 case NFROMFD:
9062 calcsize(n->ndup.vname);
9063 calcsize(n->ndup.next);
9064 break;
9065 case NHERE:
9066 case NXHERE:
9067 calcsize(n->nhere.doc);
9068 calcsize(n->nhere.next);
9069 break;
9070 case NNOT:
9071 calcsize(n->nnot.com);
9072 break;
9073 };
9074}
9075
9076
9077
9078static void
9079sizenodelist(lp)
9080 struct nodelist *lp;
9081{
9082 while (lp) {
9083 funcblocksize += ALIGN(sizeof(struct nodelist));
9084 calcsize(lp->n);
9085 lp = lp->next;
9086 }
9087}
9088
9089
9090
9091static union node *
9092copynode(n)
9093 union node *n;
9094{
9095 union node *new;
9096
9097 if (n == NULL)
9098 return NULL;
9099 new = funcblock;
9100 funcblock = (char *) funcblock + nodesize[n->type];
9101 switch (n->type) {
9102 case NSEMI:
9103 case NAND:
9104 case NOR:
9105 case NWHILE:
9106 case NUNTIL:
9107 new->nbinary.ch2 = copynode(n->nbinary.ch2);
9108 new->nbinary.ch1 = copynode(n->nbinary.ch1);
9109 break;
9110 case NCMD:
9111 new->ncmd.redirect = copynode(n->ncmd.redirect);
9112 new->ncmd.args = copynode(n->ncmd.args);
9113 new->ncmd.assign = copynode(n->ncmd.assign);
9114 new->ncmd.backgnd = n->ncmd.backgnd;
9115 break;
9116 case NPIPE:
9117 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
9118 new->npipe.backgnd = n->npipe.backgnd;
9119 break;
9120 case NREDIR:
9121 case NBACKGND:
9122 case NSUBSHELL:
9123 new->nredir.redirect = copynode(n->nredir.redirect);
9124 new->nredir.n = copynode(n->nredir.n);
9125 break;
9126 case NIF:
9127 new->nif.elsepart = copynode(n->nif.elsepart);
9128 new->nif.ifpart = copynode(n->nif.ifpart);
9129 new->nif.test = copynode(n->nif.test);
9130 break;
9131 case NFOR:
9132 new->nfor.var = nodesavestr(n->nfor.var);
9133 new->nfor.body = copynode(n->nfor.body);
9134 new->nfor.args = copynode(n->nfor.args);
9135 break;
9136 case NCASE:
9137 new->ncase.cases = copynode(n->ncase.cases);
9138 new->ncase.expr = copynode(n->ncase.expr);
9139 break;
9140 case NCLIST:
9141 new->nclist.body = copynode(n->nclist.body);
9142 new->nclist.pattern = copynode(n->nclist.pattern);
9143 new->nclist.next = copynode(n->nclist.next);
9144 break;
9145 case NDEFUN:
9146 case NARG:
9147 new->narg.backquote = copynodelist(n->narg.backquote);
9148 new->narg.text = nodesavestr(n->narg.text);
9149 new->narg.next = copynode(n->narg.next);
9150 break;
9151 case NTO:
9152 case NFROM:
9153 case NFROMTO:
9154 case NAPPEND:
9155 case NTOOV:
9156 new->nfile.fname = copynode(n->nfile.fname);
9157 new->nfile.fd = n->nfile.fd;
9158 new->nfile.next = copynode(n->nfile.next);
9159 break;
9160 case NTOFD:
9161 case NFROMFD:
9162 new->ndup.vname = copynode(n->ndup.vname);
9163 new->ndup.dupfd = n->ndup.dupfd;
9164 new->ndup.fd = n->ndup.fd;
9165 new->ndup.next = copynode(n->ndup.next);
9166 break;
9167 case NHERE:
9168 case NXHERE:
9169 new->nhere.doc = copynode(n->nhere.doc);
9170 new->nhere.fd = n->nhere.fd;
9171 new->nhere.next = copynode(n->nhere.next);
9172 break;
9173 case NNOT:
9174 new->nnot.com = copynode(n->nnot.com);
9175 break;
9176 };
9177 new->type = n->type;
9178 return new;
9179}
9180
9181
9182static struct nodelist *
9183copynodelist(lp)
9184 struct nodelist *lp;
9185{
9186 struct nodelist *start;
9187 struct nodelist **lpp;
9188
9189 lpp = &start;
9190 while (lp) {
9191 *lpp = funcblock;
9192 funcblock = (char *) funcblock + ALIGN(sizeof(struct nodelist));
9193 (*lpp)->n = copynode(lp->n);
9194 lp = lp->next;
9195 lpp = &(*lpp)->next;
9196 }
9197 *lpp = NULL;
9198 return start;
9199}
9200
9201
9202
9203static char *
9204nodesavestr(s)
9205 char *s;
9206{
9207#ifdef _GNU_SOURCE
9208 char *rtn = funcstring;
9209
9210 funcstring = stpcpy(funcstring, s) + 1;
9211 return rtn;
9212#else
9213 register char *p = s;
9214 register char *q = funcstring;
9215 char *rtn = funcstring;
9216
9217 while ((*q++ = *p++) != '\0')
9218 continue;
9219 funcstring = q;
9220 return rtn;
9221#endif
9222}
9223
Eric Andersencb57d552001-06-28 07:25:16 +00009224#ifdef ASH_GETOPTS
Eric Andersen2870d962001-07-02 17:27:21 +00009225static int getopts (char *, char *, char **, int *, int *);
Eric Andersencb57d552001-06-28 07:25:16 +00009226#endif
9227
9228
9229/*
9230 * Process the shell command line arguments.
9231 */
9232
9233static void
9234procargs(argc, argv)
9235 int argc;
9236 char **argv;
9237{
9238 int i;
9239
9240 argptr = argv;
9241 if (argc > 0)
9242 argptr++;
9243 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00009244 optent_val(i) = 2;
Eric Andersencb57d552001-06-28 07:25:16 +00009245 options(1);
9246 if (*argptr == NULL && minusc == NULL)
9247 sflag = 1;
9248 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
9249 iflag = 1;
9250 if (mflag == 2)
9251 mflag = iflag;
9252 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00009253 if (optent_val(i) == 2)
9254 optent_val(i) = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009255 arg0 = argv[0];
9256 if (sflag == 0 && minusc == NULL) {
9257 commandname = argv[0];
9258 arg0 = *argptr++;
9259 setinputfile(arg0, 0);
9260 commandname = arg0;
9261 }
9262 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
9263 if (argptr && minusc && *argptr)
Eric Andersen2870d962001-07-02 17:27:21 +00009264 arg0 = *argptr++;
Eric Andersencb57d552001-06-28 07:25:16 +00009265
9266 shellparam.p = argptr;
9267 shellparam.optind = 1;
9268 shellparam.optoff = -1;
9269 /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
9270 while (*argptr) {
9271 shellparam.nparam++;
9272 argptr++;
9273 }
9274 optschanged();
9275}
9276
9277
Eric Andersencb57d552001-06-28 07:25:16 +00009278
9279/*
9280 * Process shell options. The global variable argptr contains a pointer
9281 * to the argument list; we advance it past the options.
9282 */
9283
9284static void
9285options(cmdline)
9286 int cmdline;
9287{
9288 char *p;
9289 int val;
9290 int c;
9291
9292 if (cmdline)
9293 minusc = NULL;
9294 while ((p = *argptr) != NULL) {
9295 argptr++;
9296 if ((c = *p++) == '-') {
9297 val = 1;
Eric Andersen2870d962001-07-02 17:27:21 +00009298 if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) {
9299 if (!cmdline) {
9300 /* "-" means turn off -x and -v */
9301 if (p[0] == '\0')
9302 xflag = vflag = 0;
9303 /* "--" means reset params */
9304 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +00009305 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +00009306 }
9307 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +00009308 }
9309 } else if (c == '+') {
9310 val = 0;
9311 } else {
9312 argptr--;
9313 break;
9314 }
9315 while ((c = *p++) != '\0') {
9316 if (c == 'c' && cmdline) {
9317 char *q;
Eric Andersen2870d962001-07-02 17:27:21 +00009318#ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */
Eric Andersencb57d552001-06-28 07:25:16 +00009319 if (*p == '\0')
9320#endif
9321 q = *argptr++;
9322 if (q == NULL || minusc != NULL)
9323 error("Bad -c option");
9324 minusc = q;
9325#ifdef NOHACK
9326 break;
9327#endif
9328 } else if (c == 'o') {
9329 minus_o(*argptr, val);
9330 if (*argptr)
9331 argptr++;
9332 } else {
9333 setoption(c, val);
9334 }
9335 }
9336 }
9337}
9338
9339static void
9340minus_o(name, val)
9341 char *name;
9342 int val;
9343{
9344 int i;
9345
9346 if (name == NULL) {
9347 out1str("Current option settings\n");
9348 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00009349 out1fmt("%-16s%s\n", optent_name(optlist[i]),
9350 optent_val(i) ? "on" : "off");
Eric Andersencb57d552001-06-28 07:25:16 +00009351 } else {
9352 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00009353 if (equal(name, optent_name(optlist[i]))) {
9354 setoption(optent_letter(optlist[i]), val);
Eric Andersencb57d552001-06-28 07:25:16 +00009355 return;
9356 }
9357 error("Illegal option -o %s", name);
9358 }
9359}
9360
9361
9362static void
Eric Andersen2870d962001-07-02 17:27:21 +00009363setoption(int flag, int val)
9364{
Eric Andersencb57d552001-06-28 07:25:16 +00009365 int i;
9366
9367 for (i = 0; i < NOPTS; i++)
Eric Andersen2870d962001-07-02 17:27:21 +00009368 if (optent_letter(optlist[i]) == flag) {
9369 optent_val(i) = val;
Eric Andersencb57d552001-06-28 07:25:16 +00009370 if (val) {
9371 /* #%$ hack for ksh semantics */
9372 if (flag == 'V')
9373 Eflag = 0;
9374 else if (flag == 'E')
9375 Vflag = 0;
9376 }
9377 return;
9378 }
9379 error("Illegal option -%c", flag);
9380 /* NOTREACHED */
9381}
9382
9383
9384
Eric Andersencb57d552001-06-28 07:25:16 +00009385/*
9386 * Set the shell parameters.
9387 */
9388
9389static void
Eric Andersen2870d962001-07-02 17:27:21 +00009390setparam(char **argv)
9391{
Eric Andersencb57d552001-06-28 07:25:16 +00009392 char **newparam;
9393 char **ap;
9394 int nparam;
9395
9396 for (nparam = 0 ; argv[nparam] ; nparam++);
9397 ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
9398 while (*argv) {
9399 *ap++ = savestr(*argv++);
9400 }
9401 *ap = NULL;
9402 freeparam(&shellparam);
9403 shellparam.malloc = 1;
9404 shellparam.nparam = nparam;
9405 shellparam.p = newparam;
9406 shellparam.optind = 1;
9407 shellparam.optoff = -1;
9408}
9409
9410
9411/*
9412 * Free the list of positional parameters.
9413 */
9414
9415static void
Eric Andersen2870d962001-07-02 17:27:21 +00009416freeparam(volatile struct shparam *param)
9417{
Eric Andersencb57d552001-06-28 07:25:16 +00009418 char **ap;
9419
9420 if (param->malloc) {
9421 for (ap = param->p ; *ap ; ap++)
9422 ckfree(*ap);
9423 ckfree(param->p);
9424 }
9425}
9426
9427
9428
9429/*
9430 * The shift builtin command.
9431 */
9432
9433static int
9434shiftcmd(argc, argv)
9435 int argc;
9436 char **argv;
9437{
9438 int n;
9439 char **ap1, **ap2;
9440
9441 n = 1;
9442 if (argc > 1)
9443 n = number(argv[1]);
9444 if (n > shellparam.nparam)
9445 error("can't shift that many");
9446 INTOFF;
9447 shellparam.nparam -= n;
9448 for (ap1 = shellparam.p ; --n >= 0 ; ap1++) {
9449 if (shellparam.malloc)
9450 ckfree(*ap1);
9451 }
9452 ap2 = shellparam.p;
9453 while ((*ap2++ = *ap1++) != NULL);
9454 shellparam.optind = 1;
9455 shellparam.optoff = -1;
9456 INTON;
9457 return 0;
9458}
9459
9460
9461
9462/*
9463 * The set command builtin.
9464 */
9465
9466static int
9467setcmd(argc, argv)
9468 int argc;
9469 char **argv;
9470{
9471 if (argc == 1)
9472 return showvarscmd(argc, argv);
9473 INTOFF;
9474 options(0);
9475 optschanged();
9476 if (*argptr != NULL) {
9477 setparam(argptr);
9478 }
9479 INTON;
9480 return 0;
9481}
9482
9483
9484static void
Eric Andersen2870d962001-07-02 17:27:21 +00009485getoptsreset(const char *value)
Eric Andersencb57d552001-06-28 07:25:16 +00009486{
9487 shellparam.optind = number(value);
9488 shellparam.optoff = -1;
9489}
9490
Eric Andersen2870d962001-07-02 17:27:21 +00009491#ifdef BB_LOCALE_SUPPORT
9492static void change_lc_all(const char *value)
9493{
9494 if(value != 0 && *value != 0)
9495 setlocale(LC_ALL, value);
9496}
9497
9498static void change_lc_ctype(const char *value)
9499{
9500 if(value != 0 && *value != 0)
9501 setlocale(LC_CTYPE, value);
9502}
9503
9504#endif
9505
Eric Andersencb57d552001-06-28 07:25:16 +00009506#ifdef ASH_GETOPTS
9507/*
9508 * The getopts builtin. Shellparam.optnext points to the next argument
9509 * to be processed. Shellparam.optptr points to the next character to
9510 * be processed in the current argument. If shellparam.optnext is NULL,
9511 * then it's the first time getopts has been called.
9512 */
9513
9514static int
9515getoptscmd(argc, argv)
9516 int argc;
9517 char **argv;
9518{
9519 char **optbase;
9520
9521 if (argc < 3)
9522 error("Usage: getopts optstring var [arg]");
9523 else if (argc == 3) {
9524 optbase = shellparam.p;
9525 if (shellparam.optind > shellparam.nparam + 1) {
9526 shellparam.optind = 1;
9527 shellparam.optoff = -1;
9528 }
9529 }
9530 else {
9531 optbase = &argv[3];
9532 if (shellparam.optind > argc - 2) {
9533 shellparam.optind = 1;
9534 shellparam.optoff = -1;
9535 }
9536 }
9537
9538 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
9539 &shellparam.optoff);
9540}
9541
9542/*
9543 * Safe version of setvar, returns 1 on success 0 on failure.
9544 */
9545
9546static int
9547setvarsafe(name, val, flags)
9548 const char *name, *val;
9549 int flags;
9550{
9551 struct jmploc jmploc;
9552 struct jmploc *volatile savehandler = handler;
9553 int err = 0;
9554#ifdef __GNUC__
9555 (void) &err;
9556#endif
9557
9558 if (setjmp(jmploc.loc))
9559 err = 1;
9560 else {
9561 handler = &jmploc;
9562 setvar(name, val, flags);
9563 }
9564 handler = savehandler;
9565 return err;
9566}
9567
9568static int
9569getopts(optstr, optvar, optfirst, myoptind, optoff)
9570 char *optstr;
9571 char *optvar;
9572 char **optfirst;
9573 int *myoptind;
9574 int *optoff;
9575{
9576 char *p, *q;
9577 char c = '?';
9578 int done = 0;
9579 int err = 0;
9580 char s[10];
9581 char **optnext = optfirst + *myoptind - 1;
9582
9583 if (*myoptind <= 1 || *optoff < 0 || !(*(optnext - 1)) ||
9584 strlen(*(optnext - 1)) < *optoff)
9585 p = NULL;
9586 else
9587 p = *(optnext - 1) + *optoff;
9588 if (p == NULL || *p == '\0') {
9589 /* Current word is done, advance */
9590 if (optnext == NULL)
9591 return 1;
9592 p = *optnext;
9593 if (p == NULL || *p != '-' || *++p == '\0') {
9594atend:
9595 *myoptind = optnext - optfirst + 1;
9596 p = NULL;
9597 done = 1;
9598 goto out;
9599 }
9600 optnext++;
Eric Andersen2870d962001-07-02 17:27:21 +00009601 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009602 goto atend;
9603 }
9604
9605 c = *p++;
9606 for (q = optstr; *q != c; ) {
9607 if (*q == '\0') {
9608 if (optstr[0] == ':') {
9609 s[0] = c;
9610 s[1] = '\0';
9611 err |= setvarsafe("OPTARG", s, 0);
9612 }
9613 else {
9614 outfmt(&errout, "Illegal option -%c\n", c);
9615 (void) unsetvar("OPTARG");
9616 }
9617 c = '?';
9618 goto bad;
9619 }
9620 if (*++q == ':')
9621 q++;
9622 }
9623
9624 if (*++q == ':') {
9625 if (*p == '\0' && (p = *optnext) == NULL) {
9626 if (optstr[0] == ':') {
9627 s[0] = c;
9628 s[1] = '\0';
9629 err |= setvarsafe("OPTARG", s, 0);
9630 c = ':';
9631 }
9632 else {
9633 outfmt(&errout, "No arg for -%c option\n", c);
9634 (void) unsetvar("OPTARG");
9635 c = '?';
9636 }
9637 goto bad;
9638 }
9639
9640 if (p == *optnext)
9641 optnext++;
9642 setvarsafe("OPTARG", p, 0);
9643 p = NULL;
9644 }
9645 else
9646 setvarsafe("OPTARG", "", 0);
9647 *myoptind = optnext - optfirst + 1;
9648 goto out;
9649
9650bad:
9651 *myoptind = 1;
9652 p = NULL;
9653out:
9654 *optoff = p ? p - *(optnext - 1) : -1;
9655 fmtstr(s, sizeof(s), "%d", *myoptind);
9656 err |= setvarsafe("OPTIND", s, VNOFUNC);
9657 s[0] = c;
9658 s[1] = '\0';
9659 err |= setvarsafe(optvar, s, 0);
9660 if (err) {
9661 *myoptind = 1;
9662 *optoff = -1;
9663 flushall();
9664 exraise(EXERROR);
9665 }
9666 return done;
9667}
Eric Andersen2870d962001-07-02 17:27:21 +00009668#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009669
9670/*
9671 * XXX - should get rid of. have all builtins use getopt(3). the
9672 * library getopt must have the BSD extension static variable "optreset"
9673 * otherwise it can't be used within the shell safely.
9674 *
9675 * Standard option processing (a la getopt) for builtin routines. The
9676 * only argument that is passed to nextopt is the option string; the
9677 * other arguments are unnecessary. It return the character, or '\0' on
9678 * end of input.
9679 */
9680
9681static int
9682nextopt(optstring)
9683 const char *optstring;
9684 {
9685 char *p;
9686 const char *q;
9687 char c;
9688
9689 if ((p = optptr) == NULL || *p == '\0') {
9690 p = *argptr;
9691 if (p == NULL || *p != '-' || *++p == '\0')
9692 return '\0';
9693 argptr++;
Eric Andersen2870d962001-07-02 17:27:21 +00009694 if (p[0] == '-' && p[1] == '\0') /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +00009695 return '\0';
9696 }
9697 c = *p++;
9698 for (q = optstring ; *q != c ; ) {
9699 if (*q == '\0')
9700 error("Illegal option -%c", c);
9701 if (*++q == ':')
9702 q++;
9703 }
9704 if (*++q == ':') {
9705 if (*p == '\0' && (p = *argptr++) == NULL)
9706 error("No arg for -%c option", c);
9707 optionarg = p;
9708 p = NULL;
9709 }
9710 optptr = p;
9711 return c;
9712}
9713
9714
Eric Andersencb57d552001-06-28 07:25:16 +00009715/*
9716 * Shell output routines. We use our own output routines because:
Eric Andersen2870d962001-07-02 17:27:21 +00009717 * When a builtin command is interrupted we have to discard
9718 * any pending output.
9719 * When a builtin command appears in back quotes, we want to
9720 * save the output of the command in a region obtained
9721 * via malloc, rather than doing a fork and reading the
9722 * output of the command via a pipe.
9723 * Our output routines may be smaller than the stdio routines.
Eric Andersencb57d552001-06-28 07:25:16 +00009724 */
9725
9726
Eric Andersencb57d552001-06-28 07:25:16 +00009727
9728#ifndef USE_GLIBC_STDIO
Eric Andersen2870d962001-07-02 17:27:21 +00009729static void __outstr (const char *, size_t, struct output*);
Eric Andersencb57d552001-06-28 07:25:16 +00009730#endif
9731
9732
9733#ifndef USE_GLIBC_STDIO
9734static void
9735__outstr(const char *p, size_t len, struct output *dest) {
9736 if (!dest->bufsize) {
9737 dest->nleft = 0;
9738 } else if (dest->buf == NULL) {
9739 if (len > dest->bufsize && dest->fd == MEM_OUT) {
9740 dest->bufsize = len;
9741 }
9742 INTOFF;
9743 dest->buf = ckmalloc(dest->bufsize);
9744 dest->nextc = dest->buf;
9745 dest->nleft = dest->bufsize;
9746 INTON;
9747 } else if (dest->fd == MEM_OUT) {
9748 int offset;
9749
9750 offset = dest->bufsize;
9751 INTOFF;
9752 if (dest->bufsize >= len) {
9753 dest->bufsize <<= 1;
9754 } else {
9755 dest->bufsize += len;
9756 }
9757 dest->buf = ckrealloc(dest->buf, dest->bufsize);
9758 dest->nleft = dest->bufsize - offset;
9759 dest->nextc = dest->buf + offset;
9760 INTON;
9761 } else {
9762 flushout(dest);
9763 }
9764
9765 if (len < dest->nleft) {
9766 dest->nleft -= len;
9767 memcpy(dest->nextc, p, len);
9768 dest->nextc += len;
9769 return;
9770 }
9771
9772 if (xwrite(dest->fd, p, len) < len)
9773 dest->flags |= OUTPUT_ERR;
9774}
9775#endif
9776
9777
9778static void
Eric Andersen2870d962001-07-02 17:27:21 +00009779outstr(const char *p, struct output *file)
9780{
Eric Andersencb57d552001-06-28 07:25:16 +00009781#ifdef USE_GLIBC_STDIO
9782 INTOFF;
9783 fputs(p, file->stream);
9784 INTON;
9785#else
9786 size_t len;
9787
9788 if (!*p) {
9789 return;
9790 }
9791 len = strlen(p);
9792 if ((file->nleft -= len) > 0) {
9793 memcpy(file->nextc, p, len);
9794 file->nextc += len;
9795 return;
9796 }
9797 __outstr(p, len, file);
9798#endif
9799}
9800
9801
9802#ifndef USE_GLIBC_STDIO
9803
9804
9805static void
9806outcslow(c, dest)
9807 char c;
9808 struct output *dest;
9809 {
9810 __outstr(&c, 1, dest);
9811}
9812#endif
9813
9814
9815static void
9816flushall() {
9817 flushout(&output);
9818#ifdef FLUSHERR
9819 flushout(&errout);
9820#endif
9821}
9822
9823
9824static void
9825flushout(dest)
9826 struct output *dest;
9827 {
9828#ifdef USE_GLIBC_STDIO
9829 INTOFF;
9830 fflush(dest->stream);
9831 INTON;
9832#else
9833 size_t len;
9834
9835 len = dest->nextc - dest->buf;
9836 if (dest->buf == NULL || !len || dest->fd < 0)
9837 return;
9838 dest->nextc = dest->buf;
9839 dest->nleft = dest->bufsize;
9840 if (xwrite(dest->fd, dest->buf, len) < len)
9841 dest->flags |= OUTPUT_ERR;
9842#endif
9843}
9844
9845
9846static void
9847freestdout() {
9848 if (output.buf) {
9849 INTOFF;
9850 ckfree(output.buf);
9851 output.buf = NULL;
9852 output.nleft = 0;
9853 INTON;
9854 }
9855 output.flags = 0;
9856}
9857
9858
9859static void
9860#ifdef __STDC__
9861outfmt(struct output *file, const char *fmt, ...)
9862#else
9863static void
9864outfmt(va_alist)
9865 va_dcl
9866#endif
9867{
9868 va_list ap;
9869#ifndef __STDC__
9870 struct output *file;
9871 const char *fmt;
9872
9873 va_start(ap);
9874 file = va_arg(ap, struct output *);
9875 fmt = va_arg(ap, const char *);
9876#else
9877 va_start(ap, fmt);
9878#endif
9879 doformat(file, fmt, ap);
9880 va_end(ap);
9881}
9882
9883
9884static void
9885#ifdef __STDC__
9886out1fmt(const char *fmt, ...)
9887#else
9888out1fmt(va_alist)
9889 va_dcl
9890#endif
9891{
9892 va_list ap;
9893#ifndef __STDC__
9894 const char *fmt;
9895
9896 va_start(ap);
9897 fmt = va_arg(ap, const char *);
9898#else
9899 va_start(ap, fmt);
9900#endif
9901 doformat(out1, fmt, ap);
9902 va_end(ap);
9903}
9904
9905static void
9906#ifdef __STDC__
9907fmtstr(char *outbuf, size_t length, const char *fmt, ...)
9908#else
9909fmtstr(va_alist)
9910 va_dcl
9911#endif
9912{
9913 va_list ap;
9914#ifndef __STDC__
9915 char *outbuf;
9916 size_t length;
9917 const char *fmt;
9918
9919 va_start(ap);
9920 outbuf = va_arg(ap, char *);
9921 length = va_arg(ap, size_t);
9922 fmt = va_arg(ap, const char *);
9923#else
9924 va_start(ap, fmt);
9925#endif
9926 INTOFF;
9927 vsnprintf(outbuf, length, fmt, ap);
9928 INTON;
9929}
9930
9931#ifndef USE_GLIBC_STDIO
Eric Andersencb57d552001-06-28 07:25:16 +00009932
9933static void
Eric Andersen2870d962001-07-02 17:27:21 +00009934doformat(struct output *dest, const char *f, va_list ap)
Eric Andersencb57d552001-06-28 07:25:16 +00009935{
Eric Andersen2870d962001-07-02 17:27:21 +00009936 char *pm;
9937 int size = BUFSIZ;
Eric Andersencb57d552001-06-28 07:25:16 +00009938
Eric Andersen2870d962001-07-02 17:27:21 +00009939 while(size) {
9940 int nchars;
Eric Andersencb57d552001-06-28 07:25:16 +00009941
Eric Andersen2870d962001-07-02 17:27:21 +00009942 pm = xmalloc(size);
9943 nchars = vsnprintf(pm, size, f, ap);
9944 if(nchars > -1) {
9945 outstr(pm, dest);
9946 size = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00009947 }
Eric Andersen2870d962001-07-02 17:27:21 +00009948 else
9949 size *= 2;
9950 free(pm);
Eric Andersencb57d552001-06-28 07:25:16 +00009951 }
Eric Andersencb57d552001-06-28 07:25:16 +00009952}
9953#endif
9954
9955
9956
9957/*
9958 * Version of write which resumes after a signal is caught.
9959 */
9960
9961static int
Eric Andersen2870d962001-07-02 17:27:21 +00009962xwrite(int fd, const char *buf, int nbytes)
9963{
Eric Andersencb57d552001-06-28 07:25:16 +00009964 int ntry;
9965 int i;
9966 int n;
9967
9968 n = nbytes;
9969 ntry = 0;
9970 for (;;) {
9971 i = write(fd, buf, n);
9972 if (i > 0) {
9973 if ((n -= i) <= 0)
9974 return nbytes;
9975 buf += i;
9976 ntry = 0;
9977 } else if (i == 0) {
9978 if (++ntry > 10)
9979 return nbytes - n;
9980 } else if (errno != EINTR) {
9981 return -1;
9982 }
9983 }
9984}
9985
9986
Eric Andersencb57d552001-06-28 07:25:16 +00009987#ifdef USE_GLIBC_STDIO
9988static void initstreams() {
9989 output.stream = stdout;
9990 errout.stream = stderr;
9991}
9992
9993
9994static void
9995openmemout() {
9996 INTOFF;
9997 memout.stream = open_memstream(&memout.buf, &memout.bufsize);
9998 INTON;
9999}
10000
10001
10002static int
10003__closememout() {
10004 int error;
10005 error = fclose(memout.stream);
10006 memout.stream = NULL;
10007 return error;
10008}
10009#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010010/*
10011 * Shell command parser.
10012 */
10013
10014#define EOFMARKLEN 79
10015
10016
10017
10018struct heredoc {
Eric Andersen2870d962001-07-02 17:27:21 +000010019 struct heredoc *next; /* next here document in list */
10020 union node *here; /* redirection node */
10021 char *eofmark; /* string indicating end of input */
10022 int striptabs; /* if set, strip leading tabs */
Eric Andersencb57d552001-06-28 07:25:16 +000010023};
10024
Eric Andersen2870d962001-07-02 17:27:21 +000010025static struct heredoc *heredoclist; /* list of here documents to read */
10026static int parsebackquote; /* nonzero if we are inside backquotes */
10027static int doprompt; /* if set, prompt the user */
10028static int needprompt; /* true if interactive and at start of line */
10029static int lasttoken; /* last token read */
Eric Andersencb57d552001-06-28 07:25:16 +000010030
Eric Andersen2870d962001-07-02 17:27:21 +000010031static char *wordtext; /* text of last word returned by readtoken */
Eric Andersencb57d552001-06-28 07:25:16 +000010032
Eric Andersen2870d962001-07-02 17:27:21 +000010033static struct nodelist *backquotelist;
10034static union node *redirnode;
Eric Andersencb57d552001-06-28 07:25:16 +000010035struct heredoc *heredoc;
Eric Andersen2870d962001-07-02 17:27:21 +000010036static int quoteflag; /* set if (part of) last token was quoted */
10037static int startlinno; /* line # where last token started */
Eric Andersencb57d552001-06-28 07:25:16 +000010038
10039
Eric Andersen2870d962001-07-02 17:27:21 +000010040static union node *list (int);
10041static union node *andor (void);
10042static union node *pipeline (void);
10043static union node *command (void);
10044static union node *simplecmd (void);
10045static void parsefname (void);
10046static void parseheredoc (void);
10047static int peektoken (void);
10048static int readtoken (void);
10049static int xxreadtoken (void);
10050static int readtoken1 (int, char const *, char *, int);
10051static int noexpand (char *);
10052static void synexpect (int) __attribute__((noreturn));
10053static void synerror (const char *) __attribute__((noreturn));
10054static void setprompt (int);
Eric Andersencb57d552001-06-28 07:25:16 +000010055
10056
10057/*
10058 * Read and parse a command. Returns NEOF on end of file. (NULL is a
10059 * valid parse tree indicating a blank line.)
10060 */
10061
Eric Andersen2870d962001-07-02 17:27:21 +000010062static union node *
Eric Andersencb57d552001-06-28 07:25:16 +000010063parsecmd(int interact)
10064{
10065 int t;
10066
10067 tokpushback = 0;
10068 doprompt = interact;
10069 if (doprompt)
10070 setprompt(1);
10071 else
10072 setprompt(0);
10073 needprompt = 0;
10074 t = readtoken();
10075 if (t == TEOF)
10076 return NEOF;
10077 if (t == TNL)
10078 return NULL;
10079 tokpushback++;
10080 return list(1);
10081}
10082
10083
10084static union node *
10085list(nlflag)
10086 int nlflag;
10087{
10088 union node *n1, *n2, *n3;
10089 int tok;
10090
10091 checkkwd = 2;
10092 if (nlflag == 0 && tokendlist[peektoken()])
10093 return NULL;
10094 n1 = NULL;
10095 for (;;) {
10096 n2 = andor();
10097 tok = readtoken();
10098 if (tok == TBACKGND) {
10099 if (n2->type == NCMD || n2->type == NPIPE) {
10100 n2->ncmd.backgnd = 1;
10101 } else if (n2->type == NREDIR) {
10102 n2->type = NBACKGND;
10103 } else {
10104 n3 = (union node *)stalloc(sizeof (struct nredir));
10105 n3->type = NBACKGND;
10106 n3->nredir.n = n2;
10107 n3->nredir.redirect = NULL;
10108 n2 = n3;
10109 }
10110 }
10111 if (n1 == NULL) {
10112 n1 = n2;
10113 }
10114 else {
10115 n3 = (union node *)stalloc(sizeof (struct nbinary));
10116 n3->type = NSEMI;
10117 n3->nbinary.ch1 = n1;
10118 n3->nbinary.ch2 = n2;
10119 n1 = n3;
10120 }
10121 switch (tok) {
10122 case TBACKGND:
10123 case TSEMI:
10124 tok = readtoken();
10125 /* fall through */
10126 case TNL:
10127 if (tok == TNL) {
10128 parseheredoc();
10129 if (nlflag)
10130 return n1;
10131 } else {
10132 tokpushback++;
10133 }
10134 checkkwd = 2;
10135 if (tokendlist[peektoken()])
10136 return n1;
10137 break;
10138 case TEOF:
10139 if (heredoclist)
10140 parseheredoc();
10141 else
Eric Andersen2870d962001-07-02 17:27:21 +000010142 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +000010143 return n1;
10144 default:
10145 if (nlflag)
10146 synexpect(-1);
10147 tokpushback++;
10148 return n1;
10149 }
10150 }
10151}
10152
10153
10154
10155static union node *
10156andor() {
10157 union node *n1, *n2, *n3;
10158 int t;
10159
10160 checkkwd = 1;
10161 n1 = pipeline();
10162 for (;;) {
10163 if ((t = readtoken()) == TAND) {
10164 t = NAND;
10165 } else if (t == TOR) {
10166 t = NOR;
10167 } else {
10168 tokpushback++;
10169 return n1;
10170 }
10171 checkkwd = 2;
10172 n2 = pipeline();
10173 n3 = (union node *)stalloc(sizeof (struct nbinary));
10174 n3->type = t;
10175 n3->nbinary.ch1 = n1;
10176 n3->nbinary.ch2 = n2;
10177 n1 = n3;
10178 }
10179}
10180
10181
10182
10183static union node *
10184pipeline() {
10185 union node *n1, *n2, *pipenode;
10186 struct nodelist *lp, *prev;
10187 int negate;
10188
10189 negate = 0;
10190 TRACE(("pipeline: entered\n"));
10191 if (readtoken() == TNOT) {
10192 negate = !negate;
10193 checkkwd = 1;
10194 } else
10195 tokpushback++;
10196 n1 = command();
10197 if (readtoken() == TPIPE) {
10198 pipenode = (union node *)stalloc(sizeof (struct npipe));
10199 pipenode->type = NPIPE;
10200 pipenode->npipe.backgnd = 0;
10201 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10202 pipenode->npipe.cmdlist = lp;
10203 lp->n = n1;
10204 do {
10205 prev = lp;
10206 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
10207 checkkwd = 2;
10208 lp->n = command();
10209 prev->next = lp;
10210 } while (readtoken() == TPIPE);
10211 lp->next = NULL;
10212 n1 = pipenode;
10213 }
10214 tokpushback++;
10215 if (negate) {
10216 n2 = (union node *)stalloc(sizeof (struct nnot));
10217 n2->type = NNOT;
10218 n2->nnot.com = n1;
10219 return n2;
10220 } else
10221 return n1;
10222}
10223
10224
10225
10226static union node *
10227command() {
10228 union node *n1, *n2;
10229 union node *ap, **app;
10230 union node *cp, **cpp;
10231 union node *redir, **rpp;
10232 int t;
10233
10234 redir = NULL;
10235 n1 = NULL;
10236 rpp = &redir;
10237
10238 switch (readtoken()) {
10239 case TIF:
10240 n1 = (union node *)stalloc(sizeof (struct nif));
10241 n1->type = NIF;
10242 n1->nif.test = list(0);
10243 if (readtoken() != TTHEN)
10244 synexpect(TTHEN);
10245 n1->nif.ifpart = list(0);
10246 n2 = n1;
10247 while (readtoken() == TELIF) {
10248 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
10249 n2 = n2->nif.elsepart;
10250 n2->type = NIF;
10251 n2->nif.test = list(0);
10252 if (readtoken() != TTHEN)
10253 synexpect(TTHEN);
10254 n2->nif.ifpart = list(0);
10255 }
10256 if (lasttoken == TELSE)
10257 n2->nif.elsepart = list(0);
10258 else {
10259 n2->nif.elsepart = NULL;
10260 tokpushback++;
10261 }
10262 if (readtoken() != TFI)
10263 synexpect(TFI);
10264 checkkwd = 1;
10265 break;
10266 case TWHILE:
10267 case TUNTIL: {
10268 int got;
10269 n1 = (union node *)stalloc(sizeof (struct nbinary));
10270 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
10271 n1->nbinary.ch1 = list(0);
10272 if ((got=readtoken()) != TDO) {
10273TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
10274 synexpect(TDO);
10275 }
10276 n1->nbinary.ch2 = list(0);
10277 if (readtoken() != TDONE)
10278 synexpect(TDONE);
10279 checkkwd = 1;
10280 break;
10281 }
10282 case TFOR:
10283 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
10284 synerror("Bad for loop variable");
10285 n1 = (union node *)stalloc(sizeof (struct nfor));
10286 n1->type = NFOR;
10287 n1->nfor.var = wordtext;
10288 checkkwd = 1;
10289 if (readtoken() == TIN) {
10290 app = &ap;
10291 while (readtoken() == TWORD) {
10292 n2 = (union node *)stalloc(sizeof (struct narg));
10293 n2->type = NARG;
10294 n2->narg.text = wordtext;
10295 n2->narg.backquote = backquotelist;
10296 *app = n2;
10297 app = &n2->narg.next;
10298 }
10299 *app = NULL;
10300 n1->nfor.args = ap;
10301 if (lasttoken != TNL && lasttoken != TSEMI)
10302 synexpect(-1);
10303 } else {
10304 static char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
10305 '@', '=', '\0'};
10306 n2 = (union node *)stalloc(sizeof (struct narg));
10307 n2->type = NARG;
10308 n2->narg.text = argvars;
10309 n2->narg.backquote = NULL;
10310 n2->narg.next = NULL;
10311 n1->nfor.args = n2;
10312 /*
10313 * Newline or semicolon here is optional (but note
10314 * that the original Bourne shell only allowed NL).
10315 */
10316 if (lasttoken != TNL && lasttoken != TSEMI)
10317 tokpushback++;
10318 }
10319 checkkwd = 2;
10320 if (readtoken() != TDO)
10321 synexpect(TDO);
10322 n1->nfor.body = list(0);
10323 if (readtoken() != TDONE)
10324 synexpect(TDONE);
10325 checkkwd = 1;
10326 break;
10327 case TCASE:
10328 n1 = (union node *)stalloc(sizeof (struct ncase));
10329 n1->type = NCASE;
10330 if (readtoken() != TWORD)
10331 synexpect(TWORD);
10332 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
10333 n2->type = NARG;
10334 n2->narg.text = wordtext;
10335 n2->narg.backquote = backquotelist;
10336 n2->narg.next = NULL;
10337 do {
10338 checkkwd = 1;
10339 } while (readtoken() == TNL);
10340 if (lasttoken != TIN)
10341 synerror("expecting \"in\"");
10342 cpp = &n1->ncase.cases;
10343 checkkwd = 2, readtoken();
10344 do {
10345 if (lasttoken == TLP)
10346 readtoken();
10347 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
10348 cp->type = NCLIST;
10349 app = &cp->nclist.pattern;
10350 for (;;) {
10351 *app = ap = (union node *)stalloc(sizeof (struct narg));
10352 ap->type = NARG;
10353 ap->narg.text = wordtext;
10354 ap->narg.backquote = backquotelist;
10355 if (checkkwd = 2, readtoken() != TPIPE)
10356 break;
10357 app = &ap->narg.next;
10358 readtoken();
10359 }
10360 ap->narg.next = NULL;
10361 if (lasttoken != TRP)
10362 synexpect(TRP);
10363 cp->nclist.body = list(0);
10364
10365 checkkwd = 2;
10366 if ((t = readtoken()) != TESAC) {
10367 if (t != TENDCASE)
10368 synexpect(TENDCASE);
10369 else
10370 checkkwd = 2, readtoken();
10371 }
10372 cpp = &cp->nclist.next;
10373 } while(lasttoken != TESAC);
10374 *cpp = NULL;
10375 checkkwd = 1;
10376 break;
10377 case TLP:
10378 n1 = (union node *)stalloc(sizeof (struct nredir));
10379 n1->type = NSUBSHELL;
10380 n1->nredir.n = list(0);
10381 n1->nredir.redirect = NULL;
10382 if (readtoken() != TRP)
10383 synexpect(TRP);
10384 checkkwd = 1;
10385 break;
10386 case TBEGIN:
10387 n1 = list(0);
10388 if (readtoken() != TEND)
10389 synexpect(TEND);
10390 checkkwd = 1;
10391 break;
10392 /* Handle an empty command like other simple commands. */
10393 case TSEMI:
10394 case TAND:
10395 case TOR:
10396 case TNL:
10397 case TEOF:
10398 case TRP:
10399 case TBACKGND:
10400 /*
10401 * An empty command before a ; doesn't make much sense, and
10402 * should certainly be disallowed in the case of `if ;'.
10403 */
10404 if (!redir)
10405 synexpect(-1);
10406 case TWORD:
10407 case TREDIR:
10408 tokpushback++;
10409 n1 = simplecmd();
10410 return n1;
10411 default:
10412 synexpect(-1);
10413 /* NOTREACHED */
10414 }
10415
10416 /* Now check for redirection which may follow command */
10417 while (readtoken() == TREDIR) {
10418 *rpp = n2 = redirnode;
10419 rpp = &n2->nfile.next;
10420 parsefname();
10421 }
10422 tokpushback++;
10423 *rpp = NULL;
10424 if (redir) {
10425 if (n1->type != NSUBSHELL) {
10426 n2 = (union node *)stalloc(sizeof (struct nredir));
10427 n2->type = NREDIR;
10428 n2->nredir.n = n1;
10429 n1 = n2;
10430 }
10431 n1->nredir.redirect = redir;
10432 }
10433
10434 return n1;
10435}
10436
10437
10438static union node *
10439simplecmd() {
10440 union node *args, **app;
10441 union node *n = NULL;
10442 union node *vars, **vpp;
10443 union node **rpp, *redir;
10444
10445 args = NULL;
10446 app = &args;
10447 vars = NULL;
10448 vpp = &vars;
10449 redir = NULL;
10450 rpp = &redir;
10451
Eric Andersen2870d962001-07-02 17:27:21 +000010452#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010453 checkalias = 2;
Eric Andersen2870d962001-07-02 17:27:21 +000010454#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010455 for (;;) {
10456 switch (readtoken()) {
10457 case TWORD:
10458 case TASSIGN:
10459 n = (union node *)stalloc(sizeof (struct narg));
10460 n->type = NARG;
10461 n->narg.text = wordtext;
10462 n->narg.backquote = backquotelist;
10463 if (lasttoken == TWORD) {
10464 *app = n;
10465 app = &n->narg.next;
10466 } else {
10467 *vpp = n;
10468 vpp = &n->narg.next;
10469 }
10470 break;
10471 case TREDIR:
10472 *rpp = n = redirnode;
10473 rpp = &n->nfile.next;
Eric Andersen2870d962001-07-02 17:27:21 +000010474 parsefname(); /* read name of redirection file */
Eric Andersencb57d552001-06-28 07:25:16 +000010475 break;
10476 case TLP:
10477 if (
10478 args && app == &args->narg.next &&
10479 !vars && !redir
10480 ) {
10481 /* We have a function */
10482 if (readtoken() != TRP)
10483 synexpect(TRP);
Eric Andersencb57d552001-06-28 07:25:16 +000010484 n->type = NDEFUN;
10485 checkkwd = 2;
10486 n->narg.next = command();
10487 return n;
10488 }
10489 /* fall through */
10490 default:
10491 tokpushback++;
10492 goto out;
10493 }
10494 }
10495out:
10496 *app = NULL;
10497 *vpp = NULL;
10498 *rpp = NULL;
10499 n = (union node *)stalloc(sizeof (struct ncmd));
10500 n->type = NCMD;
10501 n->ncmd.backgnd = 0;
10502 n->ncmd.args = args;
10503 n->ncmd.assign = vars;
10504 n->ncmd.redirect = redir;
10505 return n;
10506}
10507
10508static union node *
Eric Andersen2870d962001-07-02 17:27:21 +000010509makename(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000010510 union node *n;
10511
10512 n = (union node *)stalloc(sizeof (struct narg));
10513 n->type = NARG;
10514 n->narg.next = NULL;
10515 n->narg.text = wordtext;
10516 n->narg.backquote = backquotelist;
10517 return n;
10518}
10519
10520static void fixredir(union node *n, const char *text, int err)
Eric Andersen2870d962001-07-02 17:27:21 +000010521{
Eric Andersencb57d552001-06-28 07:25:16 +000010522 TRACE(("Fix redir %s %d\n", text, err));
10523 if (!err)
10524 n->ndup.vname = NULL;
10525
10526 if (is_digit(text[0]) && text[1] == '\0')
10527 n->ndup.dupfd = digit_val(text[0]);
10528 else if (text[0] == '-' && text[1] == '\0')
10529 n->ndup.dupfd = -1;
10530 else {
10531
10532 if (err)
10533 synerror("Bad fd number");
10534 else
10535 n->ndup.vname = makename();
10536 }
10537}
10538
10539
10540static void
Eric Andersen2870d962001-07-02 17:27:21 +000010541parsefname(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000010542 union node *n = redirnode;
10543
10544 if (readtoken() != TWORD)
10545 synexpect(-1);
10546 if (n->type == NHERE) {
10547 struct heredoc *here = heredoc;
10548 struct heredoc *p;
10549 int i;
10550
10551 if (quoteflag == 0)
10552 n->type = NXHERE;
10553 TRACE(("Here document %d\n", n->type));
10554 if (here->striptabs) {
10555 while (*wordtext == '\t')
10556 wordtext++;
10557 }
10558 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
10559 synerror("Illegal eof marker for << redirection");
10560 rmescapes(wordtext);
10561 here->eofmark = wordtext;
10562 here->next = NULL;
10563 if (heredoclist == NULL)
10564 heredoclist = here;
10565 else {
10566 for (p = heredoclist ; p->next ; p = p->next);
10567 p->next = here;
10568 }
10569 } else if (n->type == NTOFD || n->type == NFROMFD) {
10570 fixredir(n, wordtext, 0);
10571 } else {
10572 n->nfile.fname = makename();
10573 }
10574}
10575
10576
10577/*
10578 * Input any here documents.
10579 */
10580
10581static void
10582parseheredoc() {
10583 struct heredoc *here;
10584 union node *n;
10585
10586 while (heredoclist) {
10587 here = heredoclist;
10588 heredoclist = here->next;
10589 if (needprompt) {
10590 setprompt(2);
10591 needprompt = 0;
10592 }
10593 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
10594 here->eofmark, here->striptabs);
10595 n = (union node *)stalloc(sizeof (struct narg));
10596 n->narg.type = NARG;
10597 n->narg.next = NULL;
10598 n->narg.text = wordtext;
10599 n->narg.backquote = backquotelist;
10600 here->here->nhere.doc = n;
10601 }
10602}
10603
10604static int
10605peektoken() {
10606 int t;
10607
10608 t = readtoken();
10609 tokpushback++;
10610 return (t);
10611}
10612
10613static int
10614readtoken() {
10615 int t;
Eric Andersen2870d962001-07-02 17:27:21 +000010616#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010617 int savecheckkwd = checkkwd;
10618 int savecheckalias = checkalias;
10619 struct alias *ap;
Eric Andersen2870d962001-07-02 17:27:21 +000010620#endif
10621
Eric Andersencb57d552001-06-28 07:25:16 +000010622#ifdef DEBUG
10623 int alreadyseen = tokpushback;
10624#endif
10625
Eric Andersen2870d962001-07-02 17:27:21 +000010626#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010627top:
Eric Andersen2870d962001-07-02 17:27:21 +000010628#endif
10629
Eric Andersencb57d552001-06-28 07:25:16 +000010630 t = xxreadtoken();
Eric Andersen2870d962001-07-02 17:27:21 +000010631
10632#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010633 checkalias = savecheckalias;
Eric Andersen2870d962001-07-02 17:27:21 +000010634#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010635
10636 if (checkkwd) {
10637 /*
10638 * eat newlines
10639 */
10640 if (checkkwd == 2) {
10641 checkkwd = 0;
10642 while (t == TNL) {
10643 parseheredoc();
10644 t = xxreadtoken();
10645 }
10646 }
10647 checkkwd = 0;
10648 /*
10649 * check for keywords
10650 */
10651 if (t == TWORD && !quoteflag)
10652 {
10653 const char *const *pp;
10654
10655 if ((pp = findkwd(wordtext))) {
10656 lasttoken = t = pp - parsekwd + KWDOFFSET;
10657 TRACE(("keyword %s recognized\n", tokname[t]));
10658 goto out;
10659 }
10660 }
10661 }
10662
Eric Andersen2870d962001-07-02 17:27:21 +000010663#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000010664 if (t != TWORD) {
10665 if (t != TREDIR) {
10666 checkalias = 0;
10667 }
10668 } else if (checkalias == 2 && isassignment(wordtext)) {
10669 lasttoken = t = TASSIGN;
10670 } else if (checkalias) {
10671 if (!quoteflag && (ap = lookupalias(wordtext, 1)) != NULL) {
10672 if (*ap->val) {
10673 pushstring(ap->val, strlen(ap->val), ap);
10674 }
10675 checkkwd = savecheckkwd;
10676 goto top;
10677 }
10678 checkalias = 0;
10679 }
Eric Andersen2870d962001-07-02 17:27:21 +000010680#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010681out:
10682#ifdef DEBUG
10683 if (!alreadyseen)
10684 TRACE(("token %s %s\n", tokname[t], t == TWORD || t == TASSIGN ? wordtext : ""));
10685 else
10686 TRACE(("reread token %s %s\n", tokname[t], t == TWORD || t == TASSIGN ? wordtext : ""));
10687#endif
10688 return (t);
10689}
10690
10691
10692/*
10693 * Read the next input token.
10694 * If the token is a word, we set backquotelist to the list of cmds in
Eric Andersen2870d962001-07-02 17:27:21 +000010695 * backquotes. We set quoteflag to true if any part of the word was
10696 * quoted.
Eric Andersencb57d552001-06-28 07:25:16 +000010697 * If the token is TREDIR, then we set redirnode to a structure containing
Eric Andersen2870d962001-07-02 17:27:21 +000010698 * the redirection.
Eric Andersencb57d552001-06-28 07:25:16 +000010699 * In all cases, the variable startlinno is set to the number of the line
Eric Andersen2870d962001-07-02 17:27:21 +000010700 * on which the token starts.
Eric Andersencb57d552001-06-28 07:25:16 +000010701 *
10702 * [Change comment: here documents and internal procedures]
10703 * [Readtoken shouldn't have any arguments. Perhaps we should make the
10704 * word parsing code into a separate routine. In this case, readtoken
10705 * doesn't need to have any internal procedures, but parseword does.
10706 * We could also make parseoperator in essence the main routine, and
10707 * have parseword (readtoken1?) handle both words and redirection.]
10708 */
10709
Eric Andersen2870d962001-07-02 17:27:21 +000010710#define RETURN(token) return lasttoken = token
Eric Andersencb57d552001-06-28 07:25:16 +000010711
10712static int
10713xxreadtoken() {
10714 int c;
10715
10716 if (tokpushback) {
10717 tokpushback = 0;
10718 return lasttoken;
10719 }
10720 if (needprompt) {
10721 setprompt(2);
10722 needprompt = 0;
10723 }
10724 startlinno = plinno;
Eric Andersen2870d962001-07-02 17:27:21 +000010725 for (;;) { /* until token or start of word found */
Eric Andersencb57d552001-06-28 07:25:16 +000010726 c = pgetc_macro();
10727 switch (c) {
10728 case ' ': case '\t':
10729 case PEOA:
10730 continue;
10731 case '#':
10732 while ((c = pgetc()) != '\n' && c != PEOF);
10733 pungetc();
10734 continue;
10735 case '\\':
10736 if (pgetc() == '\n') {
10737 startlinno = ++plinno;
10738 if (doprompt)
10739 setprompt(2);
10740 else
10741 setprompt(0);
10742 continue;
10743 }
10744 pungetc();
10745 goto breakloop;
10746 case '\n':
10747 plinno++;
10748 needprompt = doprompt;
10749 RETURN(TNL);
10750 case PEOF:
10751 RETURN(TEOF);
10752 case '&':
10753 if (pgetc() == '&')
10754 RETURN(TAND);
10755 pungetc();
10756 RETURN(TBACKGND);
10757 case '|':
10758 if (pgetc() == '|')
10759 RETURN(TOR);
10760 pungetc();
10761 RETURN(TPIPE);
10762 case ';':
10763 if (pgetc() == ';')
10764 RETURN(TENDCASE);
10765 pungetc();
10766 RETURN(TSEMI);
10767 case '(':
10768 RETURN(TLP);
10769 case ')':
10770 RETURN(TRP);
10771 default:
10772 goto breakloop;
10773 }
10774 }
10775breakloop:
10776 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
10777#undef RETURN
10778}
10779
10780
10781
10782/*
10783 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
10784 * is not NULL, read a here document. In the latter case, eofmark is the
10785 * word which marks the end of the document and striptabs is true if
10786 * leading tabs should be stripped from the document. The argument firstc
10787 * is the first character of the input token or document.
10788 *
10789 * Because C does not have internal subroutines, I have simulated them
10790 * using goto's to implement the subroutine linkage. The following macros
10791 * will run code that appears at the end of readtoken1.
10792 */
10793
Eric Andersen2870d962001-07-02 17:27:21 +000010794#define CHECKEND() {goto checkend; checkend_return:;}
10795#define PARSEREDIR() {goto parseredir; parseredir_return:;}
10796#define PARSESUB() {goto parsesub; parsesub_return:;}
10797#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
10798#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
10799#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000010800
10801static int
10802readtoken1(firstc, syntax, eofmark, striptabs)
10803 int firstc;
10804 char const *syntax;
10805 char *eofmark;
10806 int striptabs;
10807 {
10808 int c = firstc;
10809 char *out;
10810 int len;
10811 char line[EOFMARKLEN + 1];
10812 struct nodelist *bqlist;
10813 int quotef;
10814 int dblquote;
Eric Andersen2870d962001-07-02 17:27:21 +000010815 int varnest; /* levels of variables expansion */
10816 int arinest; /* levels of arithmetic expansion */
10817 int parenlevel; /* levels of parens in arithmetic */
10818 int dqvarnest; /* levels of variables expansion within double quotes */
Eric Andersencb57d552001-06-28 07:25:16 +000010819 int oldstyle;
Eric Andersen2870d962001-07-02 17:27:21 +000010820 char const *prevsyntax; /* syntax before arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010821#if __GNUC__
10822 /* Avoid longjmp clobbering */
10823 (void) &out;
10824 (void) &quotef;
10825 (void) &dblquote;
10826 (void) &varnest;
10827 (void) &arinest;
10828 (void) &parenlevel;
10829 (void) &dqvarnest;
10830 (void) &oldstyle;
10831 (void) &prevsyntax;
10832 (void) &syntax;
10833#endif
10834
10835 startlinno = plinno;
10836 dblquote = 0;
10837 if (syntax == DQSYNTAX)
10838 dblquote = 1;
10839 quotef = 0;
10840 bqlist = NULL;
10841 varnest = 0;
10842 arinest = 0;
10843 parenlevel = 0;
10844 dqvarnest = 0;
10845
10846 STARTSTACKSTR(out);
Eric Andersen2870d962001-07-02 17:27:21 +000010847 loop: { /* for each line, until end of word */
10848 CHECKEND(); /* set c to PEOF if at end of here document */
10849 for (;;) { /* until end of line or end of word */
10850 CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */
Eric Andersencb57d552001-06-28 07:25:16 +000010851 switch(syntax[c]) {
Eric Andersen2870d962001-07-02 17:27:21 +000010852 case CNL: /* '\n' */
Eric Andersencb57d552001-06-28 07:25:16 +000010853 if (syntax == BASESYNTAX)
Eric Andersen2870d962001-07-02 17:27:21 +000010854 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010855 USTPUTC(c, out);
10856 plinno++;
10857 if (doprompt)
10858 setprompt(2);
10859 else
10860 setprompt(0);
10861 c = pgetc();
Eric Andersen2870d962001-07-02 17:27:21 +000010862 goto loop; /* continue outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010863 case CWORD:
10864 USTPUTC(c, out);
10865 break;
10866 case CCTL:
10867 if ((eofmark == NULL || dblquote) &&
10868 dqvarnest == 0)
10869 USTPUTC(CTLESC, out);
10870 USTPUTC(c, out);
10871 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010872 case CBACK: /* backslash */
Eric Andersencb57d552001-06-28 07:25:16 +000010873 c = pgetc2();
10874 if (c == PEOF) {
10875 USTPUTC('\\', out);
10876 pungetc();
10877 } else if (c == '\n') {
10878 if (doprompt)
10879 setprompt(2);
10880 else
10881 setprompt(0);
10882 } else {
10883 if (dblquote && c != '\\' && c != '`' && c != '$'
10884 && (c != '"' || eofmark != NULL))
10885 USTPUTC('\\', out);
10886 if (SQSYNTAX[c] == CCTL)
10887 USTPUTC(CTLESC, out);
10888 else if (eofmark == NULL)
10889 USTPUTC(CTLQUOTEMARK, out);
10890 USTPUTC(c, out);
10891 quotef++;
10892 }
10893 break;
10894 case CSQUOTE:
10895 if (eofmark == NULL)
10896 USTPUTC(CTLQUOTEMARK, out);
10897 syntax = SQSYNTAX;
10898 break;
10899 case CDQUOTE:
10900 if (eofmark == NULL)
10901 USTPUTC(CTLQUOTEMARK, out);
10902 syntax = DQSYNTAX;
10903 dblquote = 1;
10904 break;
10905 case CENDQUOTE:
10906 if (eofmark != NULL && arinest == 0 &&
10907 varnest == 0) {
10908 USTPUTC(c, out);
10909 } else {
10910 if (arinest) {
10911 syntax = ARISYNTAX;
10912 dblquote = 0;
10913 } else if (eofmark == NULL &&
10914 dqvarnest == 0) {
10915 syntax = BASESYNTAX;
10916 dblquote = 0;
10917 }
10918 quotef++;
10919 }
10920 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010921 case CVAR: /* '$' */
10922 PARSESUB(); /* parse substitution */
Eric Andersencb57d552001-06-28 07:25:16 +000010923 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010924 case CENDVAR: /* '}' */
Eric Andersencb57d552001-06-28 07:25:16 +000010925 if (varnest > 0) {
10926 varnest--;
10927 if (dqvarnest > 0) {
10928 dqvarnest--;
10929 }
10930 USTPUTC(CTLENDVAR, out);
10931 } else {
10932 USTPUTC(c, out);
10933 }
10934 break;
10935#ifdef ASH_MATH_SUPPORT
Eric Andersen2870d962001-07-02 17:27:21 +000010936 case CLP: /* '(' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010937 parenlevel++;
10938 USTPUTC(c, out);
10939 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010940 case CRP: /* ')' in arithmetic */
Eric Andersencb57d552001-06-28 07:25:16 +000010941 if (parenlevel > 0) {
10942 USTPUTC(c, out);
10943 --parenlevel;
10944 } else {
10945 if (pgetc() == ')') {
10946 if (--arinest == 0) {
10947 USTPUTC(CTLENDARI, out);
10948 syntax = prevsyntax;
10949 if (syntax == DQSYNTAX)
10950 dblquote = 1;
10951 else
10952 dblquote = 0;
10953 } else
10954 USTPUTC(')', out);
10955 } else {
10956 /*
10957 * unbalanced parens
10958 * (don't 2nd guess - no error)
10959 */
10960 pungetc();
10961 USTPUTC(')', out);
10962 }
10963 }
10964 break;
10965#endif
Eric Andersen2870d962001-07-02 17:27:21 +000010966 case CBQUOTE: /* '`' */
Eric Andersencb57d552001-06-28 07:25:16 +000010967 PARSEBACKQOLD();
10968 break;
Eric Andersen2870d962001-07-02 17:27:21 +000010969 case CENDFILE:
10970 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010971 case CIGN:
10972 break;
10973 default:
10974 if (varnest == 0)
Eric Andersen2870d962001-07-02 17:27:21 +000010975 goto endword; /* exit outer loop */
Eric Andersencb57d552001-06-28 07:25:16 +000010976 if (c != PEOA) {
10977 USTPUTC(c, out);
10978 }
10979 }
10980 c = pgetc_macro();
10981 }
10982 }
10983endword:
10984 if (syntax == ARISYNTAX)
10985 synerror("Missing '))'");
10986 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
10987 synerror("Unterminated quoted string");
10988 if (varnest != 0) {
10989 startlinno = plinno;
10990 synerror("Missing '}'");
10991 }
10992 USTPUTC('\0', out);
10993 len = out - stackblock();
10994 out = stackblock();
10995 if (eofmark == NULL) {
10996 if ((c == '>' || c == '<')
10997 && quotef == 0
10998 && len <= 2
10999 && (*out == '\0' || is_digit(*out))) {
11000 PARSEREDIR();
11001 return lasttoken = TREDIR;
11002 } else {
11003 pungetc();
11004 }
11005 }
11006 quoteflag = quotef;
11007 backquotelist = bqlist;
11008 grabstackblock(len);
11009 wordtext = out;
11010 return lasttoken = TWORD;
11011/* end of readtoken routine */
11012
11013
11014
11015/*
11016 * Check to see whether we are at the end of the here document. When this
11017 * is called, c is set to the first character of the next input line. If
11018 * we are at the end of the here document, this routine sets the c to PEOF.
11019 */
11020
11021checkend: {
11022 if (eofmark) {
Eric Andersen2870d962001-07-02 17:27:21 +000011023#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000011024 if (c == PEOA) {
11025 c = pgetc2();
11026 }
Eric Andersen2870d962001-07-02 17:27:21 +000011027#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011028 if (striptabs) {
11029 while (c == '\t') {
11030 c = pgetc2();
11031 }
11032 }
11033 if (c == *eofmark) {
11034 if (pfgets(line, sizeof line) != NULL) {
11035 char *p, *q;
11036
11037 p = line;
11038 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
11039 if (*p == '\n' && *q == '\0') {
11040 c = PEOF;
11041 plinno++;
11042 needprompt = doprompt;
11043 } else {
11044 pushstring(line, strlen(line), NULL);
11045 }
11046 }
11047 }
11048 }
11049 goto checkend_return;
11050}
11051
11052
11053/*
11054 * Parse a redirection operator. The variable "out" points to a string
11055 * specifying the fd to be redirected. The variable "c" contains the
11056 * first character of the redirection operator.
11057 */
11058
11059parseredir: {
11060 char fd = *out;
11061 union node *np;
11062
11063 np = (union node *)stalloc(sizeof (struct nfile));
11064 if (c == '>') {
11065 np->nfile.fd = 1;
11066 c = pgetc();
11067 if (c == '>')
11068 np->type = NAPPEND;
11069 else if (c == '&')
11070 np->type = NTOFD;
11071 else if (c == '|')
11072 np->type = NTOOV;
11073 else {
11074 np->type = NTO;
11075 pungetc();
11076 }
Eric Andersen2870d962001-07-02 17:27:21 +000011077 } else { /* c == '<' */
Eric Andersencb57d552001-06-28 07:25:16 +000011078 np->nfile.fd = 0;
11079 switch (c = pgetc()) {
11080 case '<':
11081 if (sizeof (struct nfile) != sizeof (struct nhere)) {
11082 np = (union node *)stalloc(sizeof (struct nhere));
11083 np->nfile.fd = 0;
11084 }
11085 np->type = NHERE;
11086 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
11087 heredoc->here = np;
11088 if ((c = pgetc()) == '-') {
11089 heredoc->striptabs = 1;
11090 } else {
11091 heredoc->striptabs = 0;
11092 pungetc();
11093 }
11094 break;
11095
11096 case '&':
11097 np->type = NFROMFD;
11098 break;
11099
11100 case '>':
11101 np->type = NFROMTO;
11102 break;
11103
11104 default:
11105 np->type = NFROM;
11106 pungetc();
11107 break;
11108 }
11109 }
11110 if (fd != '\0')
11111 np->nfile.fd = digit_val(fd);
11112 redirnode = np;
11113 goto parseredir_return;
11114}
11115
11116
11117/*
11118 * Parse a substitution. At this point, we have read the dollar sign
11119 * and nothing else.
11120 */
11121
11122parsesub: {
11123 int subtype;
11124 int typeloc;
11125 int flags;
11126 char *p;
11127 static const char types[] = "}-+?=";
11128
11129 c = pgetc();
11130 if (
11131 c <= PEOA ||
11132 (c != '(' && c != '{' && !is_name(c) && !is_special(c))
11133 ) {
11134 USTPUTC('$', out);
11135 pungetc();
Eric Andersen2870d962001-07-02 17:27:21 +000011136 } else if (c == '(') { /* $(command) or $((arith)) */
Eric Andersencb57d552001-06-28 07:25:16 +000011137 if (pgetc() == '(') {
11138 PARSEARITH();
11139 } else {
11140 pungetc();
11141 PARSEBACKQNEW();
11142 }
11143 } else {
11144 USTPUTC(CTLVAR, out);
11145 typeloc = out - stackblock();
11146 USTPUTC(VSNORMAL, out);
11147 subtype = VSNORMAL;
11148 if (c == '{') {
11149 c = pgetc();
11150 if (c == '#') {
11151 if ((c = pgetc()) == '}')
11152 c = '#';
11153 else
11154 subtype = VSLENGTH;
11155 }
11156 else
11157 subtype = 0;
11158 }
11159 if (c > PEOA && is_name(c)) {
11160 do {
11161 STPUTC(c, out);
11162 c = pgetc();
11163 } while (c > PEOA && is_in_name(c));
11164 } else if (is_digit(c)) {
11165 do {
11166 USTPUTC(c, out);
11167 c = pgetc();
11168 } while (is_digit(c));
11169 }
11170 else if (is_special(c)) {
11171 USTPUTC(c, out);
11172 c = pgetc();
11173 }
11174 else
Eric Andersen2870d962001-07-02 17:27:21 +000011175badsub: synerror("Bad substitution");
Eric Andersencb57d552001-06-28 07:25:16 +000011176
11177 STPUTC('=', out);
11178 flags = 0;
11179 if (subtype == 0) {
11180 switch (c) {
11181 case ':':
11182 flags = VSNUL;
11183 c = pgetc();
11184 /*FALLTHROUGH*/
11185 default:
11186 p = strchr(types, c);
11187 if (p == NULL)
11188 goto badsub;
11189 subtype = p - types + VSNORMAL;
11190 break;
11191 case '%':
11192 case '#':
11193 {
11194 int cc = c;
11195 subtype = c == '#' ? VSTRIMLEFT :
11196 VSTRIMRIGHT;
11197 c = pgetc();
11198 if (c == cc)
11199 subtype++;
11200 else
11201 pungetc();
11202 break;
11203 }
11204 }
11205 } else {
11206 pungetc();
11207 }
11208 if (dblquote || arinest)
11209 flags |= VSQUOTE;
11210 *(stackblock() + typeloc) = subtype | flags;
11211 if (subtype != VSNORMAL) {
11212 varnest++;
11213 if (dblquote) {
11214 dqvarnest++;
11215 }
11216 }
11217 }
11218 goto parsesub_return;
11219}
11220
11221
11222/*
11223 * Called to parse command substitutions. Newstyle is set if the command
11224 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
11225 * list of commands (passed by reference), and savelen is the number of
11226 * characters on the top of the stack which must be preserved.
11227 */
11228
11229parsebackq: {
11230 struct nodelist **nlpp;
11231 int savepbq;
11232 union node *n;
11233 char *volatile str;
11234 struct jmploc jmploc;
11235 struct jmploc *volatile savehandler;
11236 int savelen;
11237 int saveprompt;
11238#ifdef __GNUC__
11239 (void) &saveprompt;
11240#endif
11241
11242 savepbq = parsebackquote;
11243 if (setjmp(jmploc.loc)) {
11244 if (str)
11245 ckfree(str);
11246 parsebackquote = 0;
11247 handler = savehandler;
11248 longjmp(handler->loc, 1);
11249 }
11250 INTOFF;
11251 str = NULL;
11252 savelen = out - stackblock();
11253 if (savelen > 0) {
11254 str = ckmalloc(savelen);
11255 memcpy(str, stackblock(), savelen);
11256 }
11257 savehandler = handler;
11258 handler = &jmploc;
11259 INTON;
Eric Andersen2870d962001-07-02 17:27:21 +000011260 if (oldstyle) {
11261 /* We must read until the closing backquote, giving special
11262 treatment to some slashes, and then push the string and
11263 reread it as input, interpreting it normally. */
11264 char *pout;
11265 int pc;
11266 int psavelen;
11267 char *pstr;
Eric Andersencb57d552001-06-28 07:25:16 +000011268
11269
Eric Andersen2870d962001-07-02 17:27:21 +000011270 STARTSTACKSTR(pout);
Eric Andersencb57d552001-06-28 07:25:16 +000011271 for (;;) {
11272 if (needprompt) {
11273 setprompt(2);
11274 needprompt = 0;
11275 }
11276 switch (pc = pgetc()) {
11277 case '`':
11278 goto done;
11279
11280 case '\\':
Eric Andersen2870d962001-07-02 17:27:21 +000011281 if ((pc = pgetc()) == '\n') {
Eric Andersencb57d552001-06-28 07:25:16 +000011282 plinno++;
11283 if (doprompt)
11284 setprompt(2);
11285 else
11286 setprompt(0);
11287 /*
11288 * If eating a newline, avoid putting
11289 * the newline into the new character
11290 * stream (via the STPUTC after the
11291 * switch).
11292 */
11293 continue;
11294 }
Eric Andersen2870d962001-07-02 17:27:21 +000011295 if (pc != '\\' && pc != '`' && pc != '$'
11296 && (!dblquote || pc != '"'))
11297 STPUTC('\\', pout);
Eric Andersencb57d552001-06-28 07:25:16 +000011298 if (pc > PEOA) {
11299 break;
11300 }
11301 /* fall through */
11302
11303 case PEOF:
Eric Andersen2870d962001-07-02 17:27:21 +000011304#ifdef ASH_ALIAS
Eric Andersencb57d552001-06-28 07:25:16 +000011305 case PEOA:
Eric Andersen2870d962001-07-02 17:27:21 +000011306#endif
11307 startlinno = plinno;
Eric Andersencb57d552001-06-28 07:25:16 +000011308 synerror("EOF in backquote substitution");
11309
11310 case '\n':
11311 plinno++;
11312 needprompt = doprompt;
11313 break;
11314
11315 default:
11316 break;
11317 }
11318 STPUTC(pc, pout);
Eric Andersen2870d962001-07-02 17:27:21 +000011319 }
Eric Andersencb57d552001-06-28 07:25:16 +000011320done:
Eric Andersen2870d962001-07-02 17:27:21 +000011321 STPUTC('\0', pout);
11322 psavelen = pout - stackblock();
11323 if (psavelen > 0) {
Eric Andersencb57d552001-06-28 07:25:16 +000011324 pstr = grabstackstr(pout);
11325 setinputstring(pstr);
Eric Andersen2870d962001-07-02 17:27:21 +000011326 }
11327 }
Eric Andersencb57d552001-06-28 07:25:16 +000011328 nlpp = &bqlist;
11329 while (*nlpp)
11330 nlpp = &(*nlpp)->next;
11331 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
11332 (*nlpp)->next = NULL;
11333 parsebackquote = oldstyle;
11334
11335 if (oldstyle) {
11336 saveprompt = doprompt;
11337 doprompt = 0;
11338 }
11339
11340 n = list(0);
11341
11342 if (oldstyle)
11343 doprompt = saveprompt;
11344 else {
11345 if (readtoken() != TRP)
11346 synexpect(TRP);
11347 }
11348
11349 (*nlpp)->n = n;
Eric Andersen2870d962001-07-02 17:27:21 +000011350 if (oldstyle) {
Eric Andersencb57d552001-06-28 07:25:16 +000011351 /*
11352 * Start reading from old file again, ignoring any pushed back
11353 * tokens left from the backquote parsing
11354 */
Eric Andersen2870d962001-07-02 17:27:21 +000011355 popfile();
Eric Andersencb57d552001-06-28 07:25:16 +000011356 tokpushback = 0;
11357 }
11358 while (stackblocksize() <= savelen)
11359 growstackblock();
11360 STARTSTACKSTR(out);
11361 if (str) {
11362 memcpy(out, str, savelen);
11363 STADJUST(savelen, out);
11364 INTOFF;
11365 ckfree(str);
11366 str = NULL;
11367 INTON;
11368 }
11369 parsebackquote = savepbq;
11370 handler = savehandler;
11371 if (arinest || dblquote)
11372 USTPUTC(CTLBACKQ | CTLQUOTE, out);
11373 else
11374 USTPUTC(CTLBACKQ, out);
11375 if (oldstyle)
11376 goto parsebackq_oldreturn;
11377 else
11378 goto parsebackq_newreturn;
11379}
11380
11381/*
11382 * Parse an arithmetic expansion (indicate start of one and set state)
11383 */
11384parsearith: {
11385
11386 if (++arinest == 1) {
11387 prevsyntax = syntax;
11388 syntax = ARISYNTAX;
11389 USTPUTC(CTLARI, out);
11390 if (dblquote)
11391 USTPUTC('"',out);
11392 else
11393 USTPUTC(' ',out);
11394 } else {
11395 /*
11396 * we collapse embedded arithmetic expansion to
11397 * parenthesis, which should be equivalent
11398 */
11399 USTPUTC('(', out);
11400 }
11401 goto parsearith_return;
11402}
11403
11404} /* end of readtoken */
11405
11406
Eric Andersencb57d552001-06-28 07:25:16 +000011407/*
11408 * Returns true if the text contains nothing to expand (no dollar signs
11409 * or backquotes).
11410 */
11411
11412static int
11413noexpand(text)
11414 char *text;
11415 {
11416 char *p;
11417 char c;
11418
11419 p = text;
11420 while ((c = *p++) != '\0') {
11421 if (c == CTLQUOTEMARK)
11422 continue;
11423 if (c == CTLESC)
11424 p++;
11425 else if (BASESYNTAX[(int)c] == CCTL)
11426 return 0;
11427 }
11428 return 1;
11429}
11430
11431
11432/*
11433 * Return true if the argument is a legal variable name (a letter or
11434 * underscore followed by zero or more letters, underscores, and digits).
11435 */
11436
11437static int
Eric Andersen2870d962001-07-02 17:27:21 +000011438goodname(const char *name)
11439{
11440 const char *p;
Eric Andersencb57d552001-06-28 07:25:16 +000011441
11442 p = name;
11443 if (! is_name(*p))
11444 return 0;
11445 while (*++p) {
11446 if (! is_in_name(*p))
11447 return 0;
11448 }
11449 return 1;
11450}
11451
11452
11453/*
11454 * Called when an unexpected token is read during the parse. The argument
11455 * is the token that is expected, or -1 if more than one type of token can
11456 * occur at this point.
11457 */
11458
11459static void
11460synexpect(token)
11461 int token;
11462{
11463 char msg[64];
11464
11465 if (token >= 0) {
11466 fmtstr(msg, 64, "%s unexpected (expecting %s)",
11467 tokname[lasttoken], tokname[token]);
11468 } else {
11469 fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]);
11470 }
11471 synerror(msg);
11472 /* NOTREACHED */
11473}
11474
11475
11476static void
Eric Andersen2870d962001-07-02 17:27:21 +000011477synerror(const char *msg)
11478{
Eric Andersencb57d552001-06-28 07:25:16 +000011479 if (commandname)
11480 outfmt(&errout, "%s: %d: ", commandname, startlinno);
11481 outfmt(&errout, "Syntax error: %s\n", msg);
11482 error((char *)NULL);
11483 /* NOTREACHED */
11484}
11485
Eric Andersencb57d552001-06-28 07:25:16 +000011486
11487/*
11488 * called by editline -- any expansions to the prompt
11489 * should be added here.
11490 */
11491static const char *
11492getprompt(void *unused)
Eric Andersen2870d962001-07-02 17:27:21 +000011493{
Eric Andersencb57d552001-06-28 07:25:16 +000011494 switch (whichprompt) {
11495 case 0:
11496 return "";
11497 case 1:
11498 return ps1val();
11499 case 2:
11500 return ps2val();
11501 default:
11502 return "<internal prompt error>";
11503 }
11504}
11505
Eric Andersen2870d962001-07-02 17:27:21 +000011506static void
11507setprompt(int which)
11508{
11509 whichprompt = which;
11510 putprompt(getprompt(NULL));
Eric Andersencb57d552001-06-28 07:25:16 +000011511}
11512
Eric Andersencb57d552001-06-28 07:25:16 +000011513
Eric Andersencb57d552001-06-28 07:25:16 +000011514/*
11515 * Code for dealing with input/output redirection.
11516 */
11517
Eric Andersen2870d962001-07-02 17:27:21 +000011518#define EMPTY -2 /* marks an unused slot in redirtab */
Eric Andersencb57d552001-06-28 07:25:16 +000011519#ifndef PIPE_BUF
Eric Andersen2870d962001-07-02 17:27:21 +000011520# define PIPESIZE 4096 /* amount of buffering in a pipe */
Eric Andersencb57d552001-06-28 07:25:16 +000011521#else
11522# define PIPESIZE PIPE_BUF
11523#endif
11524
11525
Eric Andersencb57d552001-06-28 07:25:16 +000011526
11527/*
11528 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
11529 * old file descriptors are stashed away so that the redirection can be
11530 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
11531 * standard output, and the standard error if it becomes a duplicate of
11532 * stdout, is saved in memory.
11533 */
11534
11535static void
11536redirect(redir, flags)
11537 union node *redir;
11538 int flags;
11539 {
11540 union node *n;
11541 struct redirtab *sv = NULL;
11542 int i;
11543 int fd;
11544 int newfd;
11545 int try;
Eric Andersen2870d962001-07-02 17:27:21 +000011546 char memory[10]; /* file descriptors to write to memory */
Eric Andersencb57d552001-06-28 07:25:16 +000011547
11548 for (i = 10 ; --i >= 0 ; )
11549 memory[i] = 0;
11550 memory[1] = flags & REDIR_BACKQ;
11551 if (flags & REDIR_PUSH) {
11552 sv = ckmalloc(sizeof (struct redirtab));
11553 for (i = 0 ; i < 10 ; i++)
11554 sv->renamed[i] = EMPTY;
11555 sv->next = redirlist;
11556 redirlist = sv;
11557 }
11558 for (n = redir ; n ; n = n->nfile.next) {
11559 fd = n->nfile.fd;
11560 try = 0;
11561 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
11562 n->ndup.dupfd == fd)
11563 continue; /* redirect from/to same file descriptor */
11564
11565 INTOFF;
11566 newfd = openredirect(n);
11567 if (((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) ||
11568 (fd == fileno2)) {
11569 if (newfd == fd) {
11570 try++;
11571 } else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
11572 switch (errno) {
11573 case EBADF:
11574 if (!try) {
11575 dupredirect(n, newfd, memory);
11576 try++;
11577 break;
11578 }
11579 /* FALLTHROUGH*/
11580 default:
11581 if (newfd >= 0) {
11582 close(newfd);
11583 }
11584 INTON;
Eric Andersen2870d962001-07-02 17:27:21 +000011585 error("%d: %m", fd);
Eric Andersencb57d552001-06-28 07:25:16 +000011586 /* NOTREACHED */
11587 }
11588 }
11589 if (!try) {
11590 close(fd);
11591 if (flags & REDIR_PUSH) {
11592 sv->renamed[fd] = i;
11593 }
11594 if (fd == fileno2) {
11595 fileno2 = i;
11596 }
11597 }
11598 } else if (fd != newfd) {
11599 close(fd);
11600 }
Eric Andersen2870d962001-07-02 17:27:21 +000011601 if (fd == 0)
11602 fd0_redirected++;
Eric Andersencb57d552001-06-28 07:25:16 +000011603 if (!try)
11604 dupredirect(n, newfd, memory);
11605 INTON;
11606 }
11607 if (memory[1])
11608 out1 = &memout;
11609 if (memory[2])
11610 out2 = &memout;
11611}
11612
11613
11614static int
11615openredirect(redir)
11616 union node *redir;
11617 {
11618 char *fname;
11619 int f;
11620
11621 switch (redir->nfile.type) {
11622 case NFROM:
11623 fname = redir->nfile.expfname;
11624 if ((f = open(fname, O_RDONLY)) < 0)
11625 goto eopen;
11626 break;
11627 case NFROMTO:
11628 fname = redir->nfile.expfname;
11629 if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
11630 goto ecreate;
11631 break;
11632 case NTO:
11633 /* Take care of noclobber mode. */
11634 if (Cflag) {
11635 fname = redir->nfile.expfname;
11636 if ((f = noclobberopen(fname)) < 0)
11637 goto ecreate;
11638 break;
11639 }
11640 case NTOOV:
11641 fname = redir->nfile.expfname;
11642#ifdef O_CREAT
11643 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
11644 goto ecreate;
11645#else
11646 if ((f = creat(fname, 0666)) < 0)
11647 goto ecreate;
11648#endif
11649 break;
11650 case NAPPEND:
11651 fname = redir->nfile.expfname;
11652#ifdef O_APPEND
11653 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
11654 goto ecreate;
11655#else
11656 if ((f = open(fname, O_WRONLY)) < 0
11657 && (f = creat(fname, 0666)) < 0)
11658 goto ecreate;
11659 lseek(f, (off_t)0, 2);
11660#endif
11661 break;
11662 default:
11663#ifdef DEBUG
11664 abort();
11665#endif
11666 /* Fall through to eliminate warning. */
11667 case NTOFD:
11668 case NFROMFD:
11669 f = -1;
11670 break;
11671 case NHERE:
11672 case NXHERE:
11673 f = openhere(redir);
11674 break;
11675 }
11676
11677 return f;
11678ecreate:
11679 error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
11680eopen:
11681 error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
11682}
11683
11684
11685static void
Eric Andersen2870d962001-07-02 17:27:21 +000011686dupredirect(union node *redir, int f, char memory[10])
11687{
Eric Andersencb57d552001-06-28 07:25:16 +000011688 int fd = redir->nfile.fd;
11689
11690 memory[fd] = 0;
11691 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Eric Andersen2870d962001-07-02 17:27:21 +000011692 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
Eric Andersencb57d552001-06-28 07:25:16 +000011693 if (memory[redir->ndup.dupfd])
11694 memory[fd] = 1;
11695 else
11696 dup_as_newfd(redir->ndup.dupfd, fd);
11697 }
11698 return;
11699 }
11700
11701 if (f != fd) {
11702 dup_as_newfd(f, fd);
11703 close(f);
11704 }
11705 return;
11706}
11707
11708
11709/*
11710 * Handle here documents. Normally we fork off a process to write the
11711 * data to a pipe. If the document is short, we can stuff the data in
11712 * the pipe without forking.
11713 */
11714
11715static int
11716openhere(redir)
11717 union node *redir;
11718 {
11719 int pip[2];
11720 int len = 0;
11721
11722 if (pipe(pip) < 0)
11723 error("Pipe call failed");
11724 if (redir->type == NHERE) {
11725 len = strlen(redir->nhere.doc->narg.text);
11726 if (len <= PIPESIZE) {
11727 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11728 goto out;
11729 }
11730 }
11731 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
11732 close(pip[0]);
11733 signal(SIGINT, SIG_IGN);
11734 signal(SIGQUIT, SIG_IGN);
11735 signal(SIGHUP, SIG_IGN);
11736#ifdef SIGTSTP
11737 signal(SIGTSTP, SIG_IGN);
11738#endif
11739 signal(SIGPIPE, SIG_DFL);
11740 if (redir->type == NHERE)
11741 xwrite(pip[1], redir->nhere.doc->narg.text, len);
11742 else
11743 expandhere(redir->nhere.doc, pip[1]);
11744 _exit(0);
11745 }
11746out:
11747 close(pip[1]);
11748 return pip[0];
11749}
11750
11751
Eric Andersencb57d552001-06-28 07:25:16 +000011752/*
11753 * Undo the effects of the last redirection.
11754 */
11755
11756static void
Eric Andersen2870d962001-07-02 17:27:21 +000011757popredir(void)
11758{
Eric Andersencb57d552001-06-28 07:25:16 +000011759 struct redirtab *rp = redirlist;
11760 int i;
11761
11762 INTOFF;
11763 for (i = 0 ; i < 10 ; i++) {
11764 if (rp->renamed[i] != EMPTY) {
Eric Andersen2870d962001-07-02 17:27:21 +000011765 if (i == 0)
11766 fd0_redirected--;
Eric Andersencb57d552001-06-28 07:25:16 +000011767 close(i);
11768 if (rp->renamed[i] >= 0) {
11769 dup_as_newfd(rp->renamed[i], i);
11770 close(rp->renamed[i]);
11771 }
11772 if (rp->renamed[i] == fileno2) {
11773 fileno2 = i;
11774 }
11775 }
11776 }
11777 redirlist = rp->next;
11778 ckfree(rp);
11779 INTON;
11780}
11781
11782/*
Eric Andersencb57d552001-06-28 07:25:16 +000011783 * Discard all saved file descriptors.
11784 */
11785
11786static void
Eric Andersen2870d962001-07-02 17:27:21 +000011787clearredir(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000011788 struct redirtab *rp;
11789 int i;
11790
11791 for (rp = redirlist ; rp ; rp = rp->next) {
11792 for (i = 0 ; i < 10 ; i++) {
11793 if (rp->renamed[i] >= 0) {
11794 close(rp->renamed[i]);
11795 if (rp->renamed[i] == fileno2) {
11796 fileno2 = -1;
11797 }
11798 }
11799 rp->renamed[i] = EMPTY;
11800 }
11801 }
11802 if (fileno2 != 2 && fileno2 >= 0) {
11803 close(fileno2);
11804 fileno2 = -1;
11805 }
11806}
11807
11808
Eric Andersencb57d552001-06-28 07:25:16 +000011809/*
11810 * Copy a file descriptor to be >= to. Returns -1
11811 * if the source file descriptor is closed, EMPTY if there are no unused
11812 * file descriptors left.
11813 */
11814
11815static int
11816dup_as_newfd(from, to)
11817 int from;
11818 int to;
11819{
11820 int newfd;
11821
11822 newfd = fcntl(from, F_DUPFD, to);
11823 if (newfd < 0) {
11824 if (errno == EMFILE)
11825 return EMPTY;
11826 else
Eric Andersen2870d962001-07-02 17:27:21 +000011827 error("%d: %m", from);
Eric Andersencb57d552001-06-28 07:25:16 +000011828 }
11829 return newfd;
11830}
11831
11832/*
11833 * Open a file in noclobber mode.
11834 * The code was copied from bash.
11835 */
11836static int
Eric Andersen2870d962001-07-02 17:27:21 +000011837noclobberopen(const char *fname)
Eric Andersencb57d552001-06-28 07:25:16 +000011838{
11839 int r, fd;
11840 struct stat finfo, finfo2;
11841
11842 /*
11843 * If the file exists and is a regular file, return an error
11844 * immediately.
11845 */
11846 r = stat(fname, &finfo);
11847 if (r == 0 && S_ISREG(finfo.st_mode)) {
11848 errno = EEXIST;
11849 return -1;
11850 }
11851
11852 /*
11853 * If the file was not present (r != 0), make sure we open it
11854 * exclusively so that if it is created before we open it, our open
11855 * will fail. Make sure that we do not truncate an existing file.
11856 * Note that we don't turn on O_EXCL unless the stat failed -- if the
11857 * file was not a regular file, we leave O_EXCL off.
11858 */
11859 if (r != 0)
11860 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
11861 fd = open(fname, O_WRONLY|O_CREAT, 0666);
11862
11863 /* If the open failed, return the file descriptor right away. */
11864 if (fd < 0)
11865 return fd;
11866
11867 /*
11868 * OK, the open succeeded, but the file may have been changed from a
11869 * non-regular file to a regular file between the stat and the open.
11870 * We are assuming that the O_EXCL open handles the case where FILENAME
11871 * did not exist and is symlinked to an existing file between the stat
11872 * and open.
11873 */
11874
11875 /*
11876 * If we can open it and fstat the file descriptor, and neither check
11877 * revealed that it was a regular file, and the file has not been
11878 * replaced, return the file descriptor.
11879 */
11880 if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
11881 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
Eric Andersen2870d962001-07-02 17:27:21 +000011882 return fd;
Eric Andersencb57d552001-06-28 07:25:16 +000011883
11884 /* The file has been replaced. badness. */
11885 close(fd);
11886 errno = EEXIST;
11887 return -1;
11888}
Eric Andersen2870d962001-07-02 17:27:21 +000011889/*#ifdef __weak_alias
Eric Andersencb57d552001-06-28 07:25:16 +000011890__weak_alias(getmode,_getmode)
11891__weak_alias(setmode,_setmode)
Eric Andersen2870d962001-07-02 17:27:21 +000011892#endif*/
Eric Andersencb57d552001-06-28 07:25:16 +000011893
11894#ifdef __GLIBC__
11895#define S_ISTXT __S_ISVTX
11896#endif
11897
Eric Andersen2870d962001-07-02 17:27:21 +000011898#define SET_LEN 6 /* initial # of bitcmd struct to malloc */
11899#define SET_LEN_INCR 4 /* # of bitcmd structs to add as needed */
Eric Andersencb57d552001-06-28 07:25:16 +000011900
11901typedef struct bitcmd {
Eric Andersen2870d962001-07-02 17:27:21 +000011902 char cmd;
11903 char cmd2;
11904 mode_t bits;
Eric Andersencb57d552001-06-28 07:25:16 +000011905} BITCMD;
11906
Eric Andersen2870d962001-07-02 17:27:21 +000011907#define CMD2_CLR 0x01
11908#define CMD2_SET 0x02
11909#define CMD2_GBITS 0x04
11910#define CMD2_OBITS 0x08
11911#define CMD2_UBITS 0x10
Eric Andersencb57d552001-06-28 07:25:16 +000011912
Eric Andersen2870d962001-07-02 17:27:21 +000011913static BITCMD *addcmd (BITCMD *, int, int, int, u_int);
11914static void compress_mode (BITCMD *);
Eric Andersencb57d552001-06-28 07:25:16 +000011915#ifdef SETMODE_DEBUG
Eric Andersen2870d962001-07-02 17:27:21 +000011916static void dumpmode (BITCMD *);
Eric Andersencb57d552001-06-28 07:25:16 +000011917#endif
11918
11919/*
11920 * Given the old mode and an array of bitcmd structures, apply the operations
11921 * described in the bitcmd structures to the old mode, and return the new mode.
11922 * Note that there is no '=' command; a strict assignment is just a '-' (clear
11923 * bits) followed by a '+' (set bits).
11924 */
Eric Andersen2870d962001-07-02 17:27:21 +000011925static mode_t
Eric Andersencb57d552001-06-28 07:25:16 +000011926getmode(bbox, omode)
11927 const void *bbox;
11928 mode_t omode;
11929{
11930 const BITCMD *set;
11931 mode_t clrval, newmode, value;
11932
11933 _DIAGASSERT(bbox != NULL);
11934
11935 set = (const BITCMD *)bbox;
11936 newmode = omode;
11937 for (value = 0;; set++)
11938 switch(set->cmd) {
11939 /*
11940 * When copying the user, group or other bits around, we "know"
11941 * where the bits are in the mode so that we can do shifts to
11942 * copy them around. If we don't use shifts, it gets real
11943 * grundgy with lots of single bit checks and bit sets.
11944 */
11945 case 'u':
11946 value = (newmode & S_IRWXU) >> 6;
11947 goto common;
11948
11949 case 'g':
11950 value = (newmode & S_IRWXG) >> 3;
11951 goto common;
11952
11953 case 'o':
11954 value = newmode & S_IRWXO;
Eric Andersen2870d962001-07-02 17:27:21 +000011955common: if (set->cmd2 & CMD2_CLR) {
Eric Andersencb57d552001-06-28 07:25:16 +000011956 clrval =
11957 (set->cmd2 & CMD2_SET) ? S_IRWXO : value;
11958 if (set->cmd2 & CMD2_UBITS)
11959 newmode &= ~((clrval<<6) & set->bits);
11960 if (set->cmd2 & CMD2_GBITS)
11961 newmode &= ~((clrval<<3) & set->bits);
11962 if (set->cmd2 & CMD2_OBITS)
11963 newmode &= ~(clrval & set->bits);
11964 }
11965 if (set->cmd2 & CMD2_SET) {
11966 if (set->cmd2 & CMD2_UBITS)
11967 newmode |= (value<<6) & set->bits;
11968 if (set->cmd2 & CMD2_GBITS)
11969 newmode |= (value<<3) & set->bits;
11970 if (set->cmd2 & CMD2_OBITS)
11971 newmode |= value & set->bits;
11972 }
11973 break;
11974
11975 case '+':
11976 newmode |= set->bits;
11977 break;
11978
11979 case '-':
11980 newmode &= ~set->bits;
11981 break;
11982
11983 case 'X':
11984 if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH))
11985 newmode |= set->bits;
11986 break;
11987
11988 case '\0':
11989 default:
11990#ifdef SETMODE_DEBUG
11991 (void)printf("getmode:%04o -> %04o\n", omode, newmode);
11992#endif
11993 return (newmode);
11994 }
11995}
11996
Eric Andersen2870d962001-07-02 17:27:21 +000011997#define ADDCMD(a, b, c, d) do { \
11998 if (set >= endset) { \
11999 BITCMD *newset; \
12000 setlen += SET_LEN_INCR; \
12001 newset = realloc(saveset, sizeof(BITCMD) * setlen); \
12002 if (newset == NULL) { \
12003 free(saveset); \
12004 return (NULL); \
12005 } \
12006 set = newset + (set - saveset); \
12007 saveset = newset; \
12008 endset = newset + (setlen - 2); \
12009 } \
12010 set = addcmd(set, (a), (b), (c), (d)); \
Eric Andersencb57d552001-06-28 07:25:16 +000012011} while (/*CONSTCOND*/0)
12012
Eric Andersen2870d962001-07-02 17:27:21 +000012013#define STANDARD_BITS (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
Eric Andersencb57d552001-06-28 07:25:16 +000012014
12015static void *
12016setmode(p)
12017 const char *p;
12018{
12019 int perm, who;
12020 char op, *ep;
12021 BITCMD *set, *saveset, *endset;
12022 sigset_t mysigset, sigoset;
12023 mode_t mask;
Eric Andersen2870d962001-07-02 17:27:21 +000012024 int equalopdone = 0; /* pacify gcc */
Eric Andersencb57d552001-06-28 07:25:16 +000012025 int permXbits, setlen;
12026
12027 if (!*p)
12028 return (NULL);
12029
12030 /*
12031 * Get a copy of the mask for the permissions that are mask relative.
12032 * Flip the bits, we want what's not set. Since it's possible that
12033 * the caller is opening files inside a signal handler, protect them
12034 * as best we can.
12035 */
12036 sigfillset(&mysigset);
12037 (void)sigprocmask(SIG_BLOCK, &mysigset, &sigoset);
12038 (void)umask(mask = umask(0));
12039 mask = ~mask;
12040 (void)sigprocmask(SIG_SETMASK, &sigoset, NULL);
12041
12042 setlen = SET_LEN + 2;
Eric Andersen2870d962001-07-02 17:27:21 +000012043
Eric Andersencb57d552001-06-28 07:25:16 +000012044 if ((set = malloc((u_int)(sizeof(BITCMD) * setlen))) == NULL)
12045 return (NULL);
12046 saveset = set;
12047 endset = set + (setlen - 2);
12048
12049 /*
12050 * If an absolute number, get it and return; disallow non-octal digits
12051 * or illegal bits.
12052 */
12053 if (isdigit((unsigned char)*p)) {
12054 perm = (mode_t)strtol(p, &ep, 8);
12055 if (*ep || perm & ~(STANDARD_BITS|S_ISTXT)) {
12056 free(saveset);
12057 return (NULL);
12058 }
12059 ADDCMD('=', (STANDARD_BITS|S_ISTXT), perm, mask);
12060 set->cmd = 0;
12061 return (saveset);
12062 }
12063
12064 /*
12065 * Build list of structures to set/clear/copy bits as described by
12066 * each clause of the symbolic mode.
12067 */
12068 for (;;) {
12069 /* First, find out which bits might be modified. */
12070 for (who = 0;; ++p) {
12071 switch (*p) {
12072 case 'a':
12073 who |= STANDARD_BITS;
12074 break;
12075 case 'u':
12076 who |= S_ISUID|S_IRWXU;
12077 break;
12078 case 'g':
12079 who |= S_ISGID|S_IRWXG;
12080 break;
12081 case 'o':
12082 who |= S_IRWXO;
12083 break;
12084 default:
12085 goto getop;
12086 }
12087 }
12088
Eric Andersen2870d962001-07-02 17:27:21 +000012089getop: if ((op = *p++) != '+' && op != '-' && op != '=') {
Eric Andersencb57d552001-06-28 07:25:16 +000012090 free(saveset);
12091 return (NULL);
12092 }
12093 if (op == '=')
12094 equalopdone = 0;
12095
12096 who &= ~S_ISTXT;
12097 for (perm = 0, permXbits = 0;; ++p) {
12098 switch (*p) {
12099 case 'r':
12100 perm |= S_IRUSR|S_IRGRP|S_IROTH;
12101 break;
12102 case 's':
12103 /*
Eric Andersen2870d962001-07-02 17:27:21 +000012104 * If specific bits where requested and
12105 * only "other" bits ignore set-id.
Eric Andersencb57d552001-06-28 07:25:16 +000012106 */
12107 if (who == 0 || (who & ~S_IRWXO))
12108 perm |= S_ISUID|S_ISGID;
12109 break;
12110 case 't':
12111 /*
Eric Andersen2870d962001-07-02 17:27:21 +000012112 * If specific bits where requested and
12113 * only "other" bits ignore set-id.
Eric Andersencb57d552001-06-28 07:25:16 +000012114 */
12115 if (who == 0 || (who & ~S_IRWXO)) {
12116 who |= S_ISTXT;
12117 perm |= S_ISTXT;
12118 }
12119 break;
12120 case 'w':
12121 perm |= S_IWUSR|S_IWGRP|S_IWOTH;
12122 break;
12123 case 'X':
12124 permXbits = S_IXUSR|S_IXGRP|S_IXOTH;
12125 break;
12126 case 'x':
12127 perm |= S_IXUSR|S_IXGRP|S_IXOTH;
12128 break;
12129 case 'u':
12130 case 'g':
12131 case 'o':
12132 /*
12133 * When ever we hit 'u', 'g', or 'o', we have
12134 * to flush out any partial mode that we have,
12135 * and then do the copying of the mode bits.
12136 */
12137 if (perm) {
12138 ADDCMD(op, who, perm, mask);
12139 perm = 0;
12140 }
12141 if (op == '=')
12142 equalopdone = 1;
12143 if (op == '+' && permXbits) {
12144 ADDCMD('X', who, permXbits, mask);
12145 permXbits = 0;
12146 }
12147 ADDCMD(*p, who, op, mask);
12148 break;
12149
12150 default:
12151 /*
12152 * Add any permissions that we haven't already
12153 * done.
12154 */
12155 if (perm || (op == '=' && !equalopdone)) {
12156 if (op == '=')
12157 equalopdone = 1;
12158 ADDCMD(op, who, perm, mask);
12159 perm = 0;
12160 }
12161 if (permXbits) {
12162 ADDCMD('X', who, permXbits, mask);
12163 permXbits = 0;
12164 }
12165 goto apply;
12166 }
12167 }
12168
Eric Andersen2870d962001-07-02 17:27:21 +000012169apply: if (!*p)
Eric Andersencb57d552001-06-28 07:25:16 +000012170 break;
12171 if (*p != ',')
12172 goto getop;
12173 ++p;
12174 }
12175 set->cmd = 0;
12176#ifdef SETMODE_DEBUG
12177 (void)printf("Before compress_mode()\n");
12178 dumpmode(saveset);
12179#endif
12180 compress_mode(saveset);
12181#ifdef SETMODE_DEBUG
12182 (void)printf("After compress_mode()\n");
12183 dumpmode(saveset);
12184#endif
12185 return (saveset);
12186}
12187
12188static BITCMD *
12189addcmd(set, op, who, oparg, mask)
12190 BITCMD *set;
12191 int oparg, who;
12192 int op;
12193 u_int mask;
12194{
12195
12196 _DIAGASSERT(set != NULL);
12197
12198 switch (op) {
12199 case '=':
12200 set->cmd = '-';
12201 set->bits = who ? who : STANDARD_BITS;
12202 set++;
12203
12204 op = '+';
12205 /* FALLTHROUGH */
12206 case '+':
12207 case '-':
12208 case 'X':
12209 set->cmd = op;
12210 set->bits = (who ? who : mask) & oparg;
12211 break;
12212
12213 case 'u':
12214 case 'g':
12215 case 'o':
12216 set->cmd = op;
12217 if (who) {
12218 set->cmd2 = ((who & S_IRUSR) ? CMD2_UBITS : 0) |
12219 ((who & S_IRGRP) ? CMD2_GBITS : 0) |
12220 ((who & S_IROTH) ? CMD2_OBITS : 0);
12221 set->bits = (mode_t)~0;
12222 } else {
12223 set->cmd2 = CMD2_UBITS | CMD2_GBITS | CMD2_OBITS;
12224 set->bits = mask;
12225 }
Eric Andersen2870d962001-07-02 17:27:21 +000012226
Eric Andersencb57d552001-06-28 07:25:16 +000012227 if (oparg == '+')
12228 set->cmd2 |= CMD2_SET;
12229 else if (oparg == '-')
12230 set->cmd2 |= CMD2_CLR;
12231 else if (oparg == '=')
12232 set->cmd2 |= CMD2_SET|CMD2_CLR;
12233 break;
12234 }
12235 return (set + 1);
12236}
12237
12238#ifdef SETMODE_DEBUG
12239static void
12240dumpmode(set)
12241 BITCMD *set;
12242{
12243
12244 _DIAGASSERT(set != NULL);
12245
12246 for (; set->cmd; ++set)
12247 (void)printf("cmd: '%c' bits %04o%s%s%s%s%s%s\n",
12248 set->cmd, set->bits, set->cmd2 ? " cmd2:" : "",
12249 set->cmd2 & CMD2_CLR ? " CLR" : "",
12250 set->cmd2 & CMD2_SET ? " SET" : "",
12251 set->cmd2 & CMD2_UBITS ? " UBITS" : "",
12252 set->cmd2 & CMD2_GBITS ? " GBITS" : "",
12253 set->cmd2 & CMD2_OBITS ? " OBITS" : "");
12254}
12255#endif
12256
12257/*
12258 * Given an array of bitcmd structures, compress by compacting consecutive
12259 * '+', '-' and 'X' commands into at most 3 commands, one of each. The 'u',
Eric Andersen2870d962001-07-02 17:27:21 +000012260 * 'g' and 'o' commands continue to be separate. They could probably be
Eric Andersencb57d552001-06-28 07:25:16 +000012261 * compacted, but it's not worth the effort.
12262 */
12263static void
12264compress_mode(set)
12265 BITCMD *set;
12266{
12267 BITCMD *nset;
12268 int setbits, clrbits, Xbits, op;
12269
12270 _DIAGASSERT(set != NULL);
12271
12272 for (nset = set;;) {
12273 /* Copy over any 'u', 'g' and 'o' commands. */
12274 while ((op = nset->cmd) != '+' && op != '-' && op != 'X') {
12275 *set++ = *nset++;
12276 if (!op)
12277 return;
12278 }
12279
12280 for (setbits = clrbits = Xbits = 0;; nset++) {
12281 if ((op = nset->cmd) == '-') {
12282 clrbits |= nset->bits;
12283 setbits &= ~nset->bits;
12284 Xbits &= ~nset->bits;
12285 } else if (op == '+') {
12286 setbits |= nset->bits;
12287 clrbits &= ~nset->bits;
12288 Xbits &= ~nset->bits;
12289 } else if (op == 'X')
12290 Xbits |= nset->bits & ~setbits;
12291 else
12292 break;
12293 }
12294 if (clrbits) {
12295 set->cmd = '-';
12296 set->cmd2 = 0;
12297 set->bits = clrbits;
12298 set++;
12299 }
12300 if (setbits) {
12301 set->cmd = '+';
12302 set->cmd2 = 0;
12303 set->bits = setbits;
12304 set++;
12305 }
12306 if (Xbits) {
12307 set->cmd = 'X';
12308 set->cmd2 = 0;
12309 set->bits = Xbits;
12310 set++;
12311 }
12312 }
12313}
Eric Andersencb57d552001-06-28 07:25:16 +000012314#ifdef DEBUG
Eric Andersen2870d962001-07-02 17:27:21 +000012315static void shtree (union node *, int, char *, FILE*);
12316static void shcmd (union node *, FILE *);
12317static void sharg (union node *, FILE *);
12318static void indent (int, char *, FILE *);
12319static void trstring (char *);
Eric Andersencb57d552001-06-28 07:25:16 +000012320
12321
12322static void
12323showtree(n)
12324 union node *n;
12325{
12326 trputs("showtree called\n");
12327 shtree(n, 1, NULL, stdout);
12328}
12329
12330
12331static void
12332shtree(n, ind, pfx, fp)
12333 union node *n;
12334 int ind;
12335 char *pfx;
12336 FILE *fp;
12337{
12338 struct nodelist *lp;
12339 const char *s;
12340
12341 if (n == NULL)
12342 return;
12343
12344 indent(ind, pfx, fp);
12345 switch(n->type) {
12346 case NSEMI:
12347 s = "; ";
12348 goto binop;
12349 case NAND:
12350 s = " && ";
12351 goto binop;
12352 case NOR:
12353 s = " || ";
12354binop:
12355 shtree(n->nbinary.ch1, ind, NULL, fp);
12356 /* if (ind < 0) */
12357 fputs(s, fp);
12358 shtree(n->nbinary.ch2, ind, NULL, fp);
12359 break;
12360 case NCMD:
12361 shcmd(n, fp);
12362 if (ind >= 0)
12363 putc('\n', fp);
12364 break;
12365 case NPIPE:
12366 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
12367 shcmd(lp->n, fp);
12368 if (lp->next)
12369 fputs(" | ", fp);
12370 }
12371 if (n->npipe.backgnd)
12372 fputs(" &", fp);
12373 if (ind >= 0)
12374 putc('\n', fp);
12375 break;
12376 default:
12377 fprintf(fp, "<node type %d>", n->type);
12378 if (ind >= 0)
12379 putc('\n', fp);
12380 break;
12381 }
12382}
12383
12384
12385
12386static void
12387shcmd(cmd, fp)
12388 union node *cmd;
12389 FILE *fp;
12390{
12391 union node *np;
12392 int first;
12393 const char *s;
12394 int dftfd;
12395
12396 first = 1;
12397 for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
12398 if (! first)
12399 putchar(' ');
12400 sharg(np, fp);
12401 first = 0;
12402 }
12403 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
12404 if (! first)
12405 putchar(' ');
12406 switch (np->nfile.type) {
Eric Andersen2870d962001-07-02 17:27:21 +000012407 case NTO: s = ">"; dftfd = 1; break;
12408 case NAPPEND: s = ">>"; dftfd = 1; break;
12409 case NTOFD: s = ">&"; dftfd = 1; break;
12410 case NTOOV: s = ">|"; dftfd = 1; break;
12411 case NFROM: s = "<"; dftfd = 0; break;
12412 case NFROMFD: s = "<&"; dftfd = 0; break;
12413 case NFROMTO: s = "<>"; dftfd = 0; break;
12414 default: s = "*error*"; dftfd = 0; break;
Eric Andersencb57d552001-06-28 07:25:16 +000012415 }
12416 if (np->nfile.fd != dftfd)
12417 fprintf(fp, "%d", np->nfile.fd);
12418 fputs(s, fp);
12419 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
12420 fprintf(fp, "%d", np->ndup.dupfd);
12421 } else {
12422 sharg(np->nfile.fname, fp);
12423 }
12424 first = 0;
12425 }
12426}
12427
12428
12429
12430static void
12431sharg(arg, fp)
12432 union node *arg;
12433 FILE *fp;
12434 {
12435 char *p;
12436 struct nodelist *bqlist;
12437 int subtype;
12438
12439 if (arg->type != NARG) {
12440 printf("<node type %d>\n", arg->type);
12441 fflush(stdout);
12442 abort();
12443 }
12444 bqlist = arg->narg.backquote;
12445 for (p = arg->narg.text ; *p ; p++) {
12446 switch (*p) {
12447 case CTLESC:
12448 putc(*++p, fp);
12449 break;
12450 case CTLVAR:
12451 putc('$', fp);
12452 putc('{', fp);
12453 subtype = *++p;
12454 if (subtype == VSLENGTH)
12455 putc('#', fp);
12456
12457 while (*p != '=')
12458 putc(*p++, fp);
12459
12460 if (subtype & VSNUL)
12461 putc(':', fp);
12462
12463 switch (subtype & VSTYPE) {
12464 case VSNORMAL:
12465 putc('}', fp);
12466 break;
12467 case VSMINUS:
12468 putc('-', fp);
12469 break;
12470 case VSPLUS:
12471 putc('+', fp);
12472 break;
12473 case VSQUESTION:
12474 putc('?', fp);
12475 break;
12476 case VSASSIGN:
12477 putc('=', fp);
12478 break;
12479 case VSTRIMLEFT:
12480 putc('#', fp);
12481 break;
12482 case VSTRIMLEFTMAX:
12483 putc('#', fp);
12484 putc('#', fp);
12485 break;
12486 case VSTRIMRIGHT:
12487 putc('%', fp);
12488 break;
12489 case VSTRIMRIGHTMAX:
12490 putc('%', fp);
12491 putc('%', fp);
12492 break;
12493 case VSLENGTH:
12494 break;
12495 default:
12496 printf("<subtype %d>", subtype);
12497 }
12498 break;
12499 case CTLENDVAR:
12500 putc('}', fp);
12501 break;
12502 case CTLBACKQ:
12503 case CTLBACKQ|CTLQUOTE:
12504 putc('$', fp);
12505 putc('(', fp);
12506 shtree(bqlist->n, -1, NULL, fp);
12507 putc(')', fp);
12508 break;
12509 default:
12510 putc(*p, fp);
12511 break;
12512 }
12513 }
12514}
12515
12516
12517static void
12518indent(amount, pfx, fp)
12519 int amount;
12520 char *pfx;
12521 FILE *fp;
12522{
12523 int i;
12524
12525 for (i = 0 ; i < amount ; i++) {
12526 if (pfx && i == amount - 1)
12527 fputs(pfx, fp);
12528 putc('\t', fp);
12529 }
12530}
12531#endif
12532
12533
12534
12535/*
12536 * Debugging stuff.
12537 */
12538
12539
12540#ifdef DEBUG
12541FILE *tracefile;
12542
12543#if DEBUG == 2
12544static int debug = 1;
12545#else
12546static int debug = 0;
12547#endif
12548
12549
12550static void
12551trputc(c)
12552 int c;
12553{
12554 if (tracefile == NULL)
12555 return;
12556 putc(c, tracefile);
12557 if (c == '\n')
12558 fflush(tracefile);
12559}
12560
12561static void
12562trace(const char *fmt, ...)
12563{
12564 va_list va;
12565#ifdef __STDC__
12566 va_start(va, fmt);
12567#else
12568 char *fmt;
12569 va_start(va);
12570 fmt = va_arg(va, char *);
12571#endif
12572 if (tracefile != NULL) {
12573 (void) vfprintf(tracefile, fmt, va);
12574 if (strchr(fmt, '\n'))
12575 (void) fflush(tracefile);
12576 }
12577 va_end(va);
12578}
12579
12580
12581static void
12582trputs(s)
12583 const char *s;
12584{
12585 if (tracefile == NULL)
12586 return;
12587 fputs(s, tracefile);
12588 if (strchr(s, '\n'))
12589 fflush(tracefile);
12590}
12591
12592
12593static void
12594trstring(s)
12595 char *s;
12596{
12597 char *p;
12598 char c;
12599
12600 if (tracefile == NULL)
12601 return;
12602 putc('"', tracefile);
12603 for (p = s ; *p ; p++) {
12604 switch (*p) {
12605 case '\n': c = 'n'; goto backslash;
12606 case '\t': c = 't'; goto backslash;
12607 case '\r': c = 'r'; goto backslash;
12608 case '"': c = '"'; goto backslash;
12609 case '\\': c = '\\'; goto backslash;
12610 case CTLESC: c = 'e'; goto backslash;
12611 case CTLVAR: c = 'v'; goto backslash;
12612 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
12613 case CTLBACKQ: c = 'q'; goto backslash;
12614 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
Eric Andersen2870d962001-07-02 17:27:21 +000012615backslash: putc('\\', tracefile);
Eric Andersencb57d552001-06-28 07:25:16 +000012616 putc(c, tracefile);
12617 break;
12618 default:
12619 if (*p >= ' ' && *p <= '~')
12620 putc(*p, tracefile);
12621 else {
12622 putc('\\', tracefile);
12623 putc(*p >> 6 & 03, tracefile);
12624 putc(*p >> 3 & 07, tracefile);
12625 putc(*p & 07, tracefile);
12626 }
12627 break;
12628 }
12629 }
12630 putc('"', tracefile);
12631}
12632
12633
12634static void
12635trargs(ap)
12636 char **ap;
12637{
12638 if (tracefile == NULL)
12639 return;
12640 while (*ap) {
12641 trstring(*ap++);
12642 if (*ap)
12643 putc(' ', tracefile);
12644 else
12645 putc('\n', tracefile);
12646 }
12647 fflush(tracefile);
12648}
12649
12650
12651static void
12652opentrace() {
12653 char s[100];
12654#ifdef O_APPEND
12655 int flags;
12656#endif
12657
12658 if (!debug)
12659 return;
12660#ifdef not_this_way
12661 {
12662 char *p;
12663 if ((p = getenv("HOME")) == NULL) {
12664 if (geteuid() == 0)
12665 p = "/";
12666 else
12667 p = "/tmp";
12668 }
Eric Andersen2870d962001-07-02 17:27:21 +000012669 strcpy(s, p);
Eric Andersencb57d552001-06-28 07:25:16 +000012670 strcat(s, "/trace");
12671 }
12672#else
Eric Andersen2870d962001-07-02 17:27:21 +000012673 strcpy(s, "./trace");
Eric Andersencb57d552001-06-28 07:25:16 +000012674#endif /* not_this_way */
12675 if ((tracefile = fopen(s, "a")) == NULL) {
12676 fprintf(stderr, "Can't open %s\n", s);
12677 return;
12678 }
12679#ifdef O_APPEND
12680 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
12681 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
12682#endif
12683 fputs("\nTracing started.\n", tracefile);
12684 fflush(tracefile);
12685}
12686#endif /* DEBUG */
12687
12688
12689/*
Eric Andersencb57d552001-06-28 07:25:16 +000012690 * The trap builtin.
12691 */
12692
12693static int
12694trapcmd(argc, argv)
12695 int argc;
12696 char **argv;
12697{
12698 char *action;
12699 char **ap;
12700 int signo;
12701
12702 if (argc <= 1) {
12703 for (signo = 0 ; signo < NSIG ; signo++) {
12704 if (trap[signo] != NULL) {
12705 char *p;
12706
12707 p = single_quote(trap[signo]);
12708 out1fmt("trap -- %s %s\n", p,
12709 signal_names[signo] + (signo ? 3 : 0)
12710 );
12711 stunalloc(p);
12712 }
12713 }
12714 return 0;
12715 }
12716 ap = argv + 1;
12717 if (argc == 2)
12718 action = NULL;
12719 else
12720 action = *ap++;
12721 while (*ap) {
12722 if ((signo = decode_signal(*ap, 0)) < 0)
12723 error("%s: bad trap", *ap);
12724 INTOFF;
12725 if (action) {
12726 if (action[0] == '-' && action[1] == '\0')
12727 action = NULL;
12728 else
12729 action = savestr(action);
12730 }
12731 if (trap[signo])
12732 ckfree(trap[signo]);
12733 trap[signo] = action;
12734 if (signo != 0)
12735 setsignal(signo);
12736 INTON;
12737 ap++;
12738 }
12739 return 0;
12740}
12741
12742
12743
Eric Andersencb57d552001-06-28 07:25:16 +000012744
12745
12746
12747/*
12748 * Set the signal handler for the specified signal. The routine figures
12749 * out what it should be set to.
12750 */
12751
12752static void
Eric Andersen2870d962001-07-02 17:27:21 +000012753setsignal(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000012754{
12755 int action;
12756 char *t;
12757 struct sigaction act;
12758
12759 if ((t = trap[signo]) == NULL)
12760 action = S_DFL;
12761 else if (*t != '\0')
12762 action = S_CATCH;
12763 else
12764 action = S_IGN;
12765 if (rootshell && action == S_DFL) {
12766 switch (signo) {
12767 case SIGINT:
12768 if (iflag || minusc || sflag == 0)
12769 action = S_CATCH;
12770 break;
12771 case SIGQUIT:
12772#ifdef DEBUG
12773 {
Eric Andersencb57d552001-06-28 07:25:16 +000012774
12775 if (debug)
12776 break;
12777 }
12778#endif
12779 /* FALLTHROUGH */
12780 case SIGTERM:
12781 if (iflag)
12782 action = S_IGN;
12783 break;
Eric Andersen2870d962001-07-02 17:27:21 +000012784#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000012785 case SIGTSTP:
12786 case SIGTTOU:
12787 if (mflag)
12788 action = S_IGN;
12789 break;
12790#endif
12791 }
12792 }
12793
12794 t = &sigmode[signo - 1];
12795 if (*t == 0) {
12796 /*
12797 * current setting unknown
12798 */
12799 if (sigaction(signo, 0, &act) == -1) {
12800 /*
12801 * Pretend it worked; maybe we should give a warning
12802 * here, but other shells don't. We don't alter
12803 * sigmode, so that we retry every time.
12804 */
12805 return;
12806 }
12807 if (act.sa_handler == SIG_IGN) {
12808 if (mflag && (signo == SIGTSTP ||
12809 signo == SIGTTIN || signo == SIGTTOU)) {
Eric Andersen2870d962001-07-02 17:27:21 +000012810 *t = S_IGN; /* don't hard ignore these */
Eric Andersencb57d552001-06-28 07:25:16 +000012811 } else
12812 *t = S_HARD_IGN;
12813 } else {
Eric Andersen2870d962001-07-02 17:27:21 +000012814 *t = S_RESET; /* force to be set */
Eric Andersencb57d552001-06-28 07:25:16 +000012815 }
12816 }
12817 if (*t == S_HARD_IGN || *t == action)
12818 return;
12819 switch (action) {
12820 case S_CATCH:
12821 act.sa_handler = onsig;
12822 break;
12823 case S_IGN:
12824 act.sa_handler = SIG_IGN;
12825 break;
12826 default:
12827 act.sa_handler = SIG_DFL;
12828 }
12829 *t = action;
12830 act.sa_flags = 0;
12831 sigemptyset(&act.sa_mask);
12832 sigaction(signo, &act, 0);
12833}
12834
12835/*
12836 * Ignore a signal.
12837 */
12838
12839static void
12840ignoresig(signo)
12841 int signo;
12842{
12843 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
12844 signal(signo, SIG_IGN);
12845 }
12846 sigmode[signo - 1] = S_HARD_IGN;
12847}
12848
12849
Eric Andersencb57d552001-06-28 07:25:16 +000012850/*
12851 * Signal handler.
12852 */
12853
12854static void
Eric Andersen2870d962001-07-02 17:27:21 +000012855onsig(int signo)
Eric Andersencb57d552001-06-28 07:25:16 +000012856{
12857 if (signo == SIGINT && trap[SIGINT] == NULL) {
12858 onint();
12859 return;
12860 }
12861 gotsig[signo - 1] = 1;
12862 pendingsigs++;
12863}
12864
12865
Eric Andersencb57d552001-06-28 07:25:16 +000012866/*
12867 * Called to execute a trap. Perhaps we should avoid entering new trap
12868 * handlers while we are executing a trap handler.
12869 */
12870
12871static void
Eric Andersen2870d962001-07-02 17:27:21 +000012872dotrap(void)
12873{
Eric Andersencb57d552001-06-28 07:25:16 +000012874 int i;
12875 int savestatus;
12876
12877 for (;;) {
12878 for (i = 1 ; ; i++) {
12879 if (gotsig[i - 1])
12880 break;
12881 if (i >= NSIG - 1)
12882 goto done;
12883 }
12884 gotsig[i - 1] = 0;
12885 savestatus=exitstatus;
12886 evalstring(trap[i], 0);
12887 exitstatus=savestatus;
12888 }
12889done:
12890 pendingsigs = 0;
12891}
12892
Eric Andersencb57d552001-06-28 07:25:16 +000012893/*
12894 * Called to exit the shell.
12895 */
12896
12897static void
Eric Andersen2870d962001-07-02 17:27:21 +000012898exitshell(int status)
Eric Andersencb57d552001-06-28 07:25:16 +000012899{
12900 struct jmploc loc1, loc2;
12901 char *p;
12902
12903 TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
12904 if (setjmp(loc1.loc)) {
12905 goto l1;
12906 }
12907 if (setjmp(loc2.loc)) {
12908 goto l2;
12909 }
12910 handler = &loc1;
12911 if ((p = trap[0]) != NULL && *p != '\0') {
12912 trap[0] = NULL;
12913 evalstring(p, 0);
12914 }
Eric Andersen2870d962001-07-02 17:27:21 +000012915l1: handler = &loc2; /* probably unnecessary */
Eric Andersencb57d552001-06-28 07:25:16 +000012916 flushall();
Eric Andersen2870d962001-07-02 17:27:21 +000012917#ifdef JOBS
Eric Andersencb57d552001-06-28 07:25:16 +000012918 setjobctl(0);
12919#endif
12920l2: _exit(status);
12921 /* NOTREACHED */
12922}
12923
12924static int decode_signal(const char *string, int minsig)
12925{
12926 int signo;
12927
Eric Andersen2870d962001-07-02 17:27:21 +000012928 if (is_number(string, &signo)) {
Eric Andersencb57d552001-06-28 07:25:16 +000012929 if (signo >= NSIG) {
12930 return -1;
12931 }
12932 return signo;
12933 }
12934
12935 signo = minsig;
12936 if (!signo) {
12937 goto zero;
12938 }
12939 for (; signo < NSIG; signo++) {
12940 if (!strcasecmp(string, &(signal_names[signo])[3])) {
12941 return signo;
12942 }
12943zero:
12944 if (!strcasecmp(string, signal_names[signo])) {
12945 return signo;
12946 }
12947 }
12948
12949 return -1;
12950}
Eric Andersen2870d962001-07-02 17:27:21 +000012951static struct var **hashvar (const char *);
12952static void showvars (const char *, int, int);
12953static struct var **findvar (struct var **, const char *);
Eric Andersencb57d552001-06-28 07:25:16 +000012954
12955/*
12956 * Initialize the varable symbol tables and import the environment
12957 */
12958
Eric Andersencb57d552001-06-28 07:25:16 +000012959/*
12960 * This routine initializes the builtin variables. It is called when the
12961 * shell is initialized and again when a shell procedure is spawned.
12962 */
12963
12964static void
12965initvar() {
12966 const struct varinit *ip;
12967 struct var *vp;
12968 struct var **vpp;
12969
12970 for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
12971 if ((vp->flags & VEXPORT) == 0) {
12972 vpp = hashvar(ip->text);
12973 vp->next = *vpp;
12974 *vpp = vp;
12975 vp->text = strdup(ip->text);
12976 vp->flags = ip->flags;
12977 vp->func = ip->func;
12978 }
12979 }
12980 /*
12981 * PS1 depends on uid
12982 */
12983 if ((vps1.flags & VEXPORT) == 0) {
12984 vpp = hashvar("PS1=");
12985 vps1.next = *vpp;
12986 *vpp = &vps1;
12987 vps1.text = strdup(geteuid() ? "PS1=$ " : "PS1=# ");
12988 vps1.flags = VSTRFIXED|VTEXTFIXED;
12989 }
12990}
12991
12992/*
12993 * Set the value of a variable. The flags argument is ored with the
12994 * flags of the variable. If val is NULL, the variable is unset.
12995 */
12996
12997static void
12998setvar(name, val, flags)
12999 const char *name, *val;
13000 int flags;
13001{
13002 const char *p;
13003 int len;
13004 int namelen;
13005 char *nameeq;
13006 int isbad;
13007 int vallen = 0;
13008
13009 isbad = 0;
13010 p = name;
13011 if (! is_name(*p))
13012 isbad = 1;
13013 p++;
13014 for (;;) {
13015 if (! is_in_name(*p)) {
13016 if (*p == '\0' || *p == '=')
13017 break;
13018 isbad = 1;
13019 }
13020 p++;
13021 }
13022 namelen = p - name;
13023 if (isbad)
13024 error("%.*s: bad variable name", namelen, name);
Eric Andersen2870d962001-07-02 17:27:21 +000013025 len = namelen + 2; /* 2 is space for '=' and '\0' */
Eric Andersencb57d552001-06-28 07:25:16 +000013026 if (val == NULL) {
13027 flags |= VUNSET;
13028 } else {
13029 len += vallen = strlen(val);
13030 }
13031 INTOFF;
13032 nameeq = ckmalloc(len);
13033 memcpy(nameeq, name, namelen);
13034 nameeq[namelen] = '=';
13035 if (val) {
13036 memcpy(nameeq + namelen + 1, val, vallen + 1);
13037 } else {
13038 nameeq[namelen + 1] = '\0';
13039 }
13040 setvareq(nameeq, flags);
13041 INTON;
13042}
13043
13044
13045
13046/*
13047 * Same as setvar except that the variable and value are passed in
13048 * the first argument as name=value. Since the first argument will
13049 * be actually stored in the table, it should not be a string that
13050 * will go away.
13051 */
13052
13053static void
13054setvareq(s, flags)
13055 char *s;
13056 int flags;
13057{
13058 struct var *vp, **vpp;
13059
13060 vpp = hashvar(s);
13061 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
13062 if ((vp = *findvar(vpp, s))) {
13063 if (vp->flags & VREADONLY) {
13064 size_t len = strchr(s, '=') - s;
13065 error("%.*s: is read only", len, s);
13066 }
13067 INTOFF;
13068
13069 if (vp->func && (flags & VNOFUNC) == 0)
13070 (*vp->func)(strchr(s, '=') + 1);
13071
13072 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
13073 ckfree(vp->text);
13074
13075 vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
13076 vp->flags |= flags;
13077 vp->text = s;
13078
13079 /*
13080 * We could roll this to a function, to handle it as
13081 * a regular variable function callback, but why bother?
13082 */
13083 if (iflag && (vp == &vmpath || (vp == &vmail && !mpathset())))
13084 chkmail(1);
13085 INTON;
13086 return;
13087 }
13088 /* not found */
13089 vp = ckmalloc(sizeof (*vp));
13090 vp->flags = flags;
13091 vp->text = s;
13092 vp->next = *vpp;
13093 vp->func = NULL;
13094 *vpp = vp;
13095}
13096
13097
13098
13099/*
13100 * Process a linked list of variable assignments.
13101 */
13102
13103static void
13104listsetvar(mylist)
13105 struct strlist *mylist;
13106 {
13107 struct strlist *lp;
13108
13109 INTOFF;
13110 for (lp = mylist ; lp ; lp = lp->next) {
13111 setvareq(savestr(lp->text), 0);
13112 }
13113 INTON;
13114}
13115
13116
13117
13118/*
13119 * Find the value of a variable. Returns NULL if not set.
13120 */
13121
13122static char *
13123lookupvar(name)
13124 const char *name;
13125 {
13126 struct var *v;
13127
13128 if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
13129 return strchr(v->text, '=') + 1;
13130 }
13131 return NULL;
13132}
13133
13134
13135
13136/*
13137 * Search the environment of a builtin command.
13138 */
13139
13140static char *
13141bltinlookup(name)
13142 const char *name;
13143{
13144 struct strlist *sp;
13145
13146 for (sp = cmdenviron ; sp ; sp = sp->next) {
13147 if (varequal(sp->text, name))
13148 return strchr(sp->text, '=') + 1;
13149 }
13150 return lookupvar(name);
13151}
13152
13153
13154
13155/*
13156 * Generate a list of exported variables. This routine is used to construct
13157 * the third argument to execve when executing a program.
13158 */
13159
13160static char **
13161environment() {
13162 int nenv;
13163 struct var **vpp;
13164 struct var *vp;
13165 char **env;
13166 char **ep;
13167
13168 nenv = 0;
13169 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
13170 for (vp = *vpp ; vp ; vp = vp->next)
13171 if (vp->flags & VEXPORT)
13172 nenv++;
13173 }
13174 ep = env = stalloc((nenv + 1) * sizeof *env);
13175 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
13176 for (vp = *vpp ; vp ; vp = vp->next)
13177 if (vp->flags & VEXPORT)
13178 *ep++ = vp->text;
13179 }
13180 *ep = NULL;
13181 return env;
13182}
13183
13184
13185/*
13186 * Called when a shell procedure is invoked to clear out nonexported
13187 * variables. It is also necessary to reallocate variables of with
13188 * VSTACK set since these are currently allocated on the stack.
13189 */
13190
Eric Andersencb57d552001-06-28 07:25:16 +000013191static void
Eric Andersen2870d962001-07-02 17:27:21 +000013192shprocvar(void) {
Eric Andersencb57d552001-06-28 07:25:16 +000013193 struct var **vpp;
13194 struct var *vp, **prev;
13195
13196 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
13197 for (prev = vpp ; (vp = *prev) != NULL ; ) {
13198 if ((vp->flags & VEXPORT) == 0) {
13199 *prev = vp->next;
13200 if ((vp->flags & VTEXTFIXED) == 0)
13201 ckfree(vp->text);
13202 if ((vp->flags & VSTRFIXED) == 0)
13203 ckfree(vp);
13204 } else {
13205 if (vp->flags & VSTACK) {
13206 vp->text = savestr(vp->text);
13207 vp->flags &=~ VSTACK;
13208 }
13209 prev = &vp->next;
13210 }
13211 }
13212 }
13213 initvar();
13214}
13215
13216
13217
13218/*
13219 * Command to list all variables which are set. Currently this command
13220 * is invoked from the set command when the set command is called without
13221 * any variables.
13222 */
13223
13224static int
13225showvarscmd(argc, argv)
13226 int argc;
13227 char **argv;
13228{
13229 showvars(nullstr, VUNSET, VUNSET);
13230 return 0;
13231}
13232
13233
13234
13235/*
13236 * The export and readonly commands.
13237 */
13238
13239static int
13240exportcmd(argc, argv)
13241 int argc;
13242 char **argv;
13243{
13244 struct var *vp;
13245 char *name;
13246 const char *p;
13247 int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
13248 int pflag;
13249
13250 listsetvar(cmdenviron);
13251 pflag = (nextopt("p") == 'p');
13252 if (argc > 1 && !pflag) {
13253 while ((name = *argptr++) != NULL) {
13254 if ((p = strchr(name, '=')) != NULL) {
13255 p++;
13256 } else {
13257 if ((vp = *findvar(hashvar(name), name))) {
13258 vp->flags |= flag;
13259 goto found;
13260 }
13261 }
13262 setvar(name, p, flag);
13263found:;
13264 }
13265 } else {
13266 showvars(argv[0], flag, 0);
13267 }
13268 return 0;
13269}
13270
13271
13272/*
13273 * The "local" command.
13274 */
13275
Eric Andersen2870d962001-07-02 17:27:21 +000013276/* funcnest nonzero if we are currently evaluating a function */
13277
Eric Andersencb57d552001-06-28 07:25:16 +000013278static int
13279localcmd(argc, argv)
13280 int argc;
13281 char **argv;
13282{
13283 char *name;
13284
Eric Andersen2870d962001-07-02 17:27:21 +000013285 if (! funcnest)
Eric Andersencb57d552001-06-28 07:25:16 +000013286 error("Not in a function");
13287 while ((name = *argptr++) != NULL) {
13288 mklocal(name);
13289 }
13290 return 0;
13291}
13292
13293
13294/*
13295 * Make a variable a local variable. When a variable is made local, it's
13296 * value and flags are saved in a localvar structure. The saved values
13297 * will be restored when the shell function returns. We handle the name
13298 * "-" as a special case.
13299 */
13300
13301static void
13302mklocal(name)
13303 char *name;
13304 {
13305 struct localvar *lvp;
13306 struct var **vpp;
13307 struct var *vp;
13308
13309 INTOFF;
13310 lvp = ckmalloc(sizeof (struct localvar));
13311 if (name[0] == '-' && name[1] == '\0') {
13312 char *p;
Eric Andersen2870d962001-07-02 17:27:21 +000013313 p = ckmalloc(sizeof optet_vals);
13314 lvp->text = memcpy(p, optet_vals, sizeof optet_vals);
Eric Andersencb57d552001-06-28 07:25:16 +000013315 vp = NULL;
13316 } else {
13317 vpp = hashvar(name);
13318 vp = *findvar(vpp, name);
13319 if (vp == NULL) {
13320 if (strchr(name, '='))
13321 setvareq(savestr(name), VSTRFIXED);
13322 else
13323 setvar(name, NULL, VSTRFIXED);
Eric Andersen2870d962001-07-02 17:27:21 +000013324 vp = *vpp; /* the new variable */
Eric Andersencb57d552001-06-28 07:25:16 +000013325 lvp->text = NULL;
13326 lvp->flags = VUNSET;
13327 } else {
13328 lvp->text = vp->text;
13329 lvp->flags = vp->flags;
13330 vp->flags |= VSTRFIXED|VTEXTFIXED;
13331 if (strchr(name, '='))
13332 setvareq(savestr(name), 0);
13333 }
13334 }
13335 lvp->vp = vp;
13336 lvp->next = localvars;
13337 localvars = lvp;
13338 INTON;
13339}
13340
13341
13342/*
13343 * Called after a function returns.
13344 */
13345
13346static void
13347poplocalvars() {
13348 struct localvar *lvp;
13349 struct var *vp;
13350
13351 while ((lvp = localvars) != NULL) {
13352 localvars = lvp->next;
13353 vp = lvp->vp;
Eric Andersen2870d962001-07-02 17:27:21 +000013354 if (vp == NULL) { /* $- saved */
13355 memcpy(optet_vals, lvp->text, sizeof optet_vals);
Eric Andersencb57d552001-06-28 07:25:16 +000013356 ckfree(lvp->text);
13357 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
13358 (void)unsetvar(vp->text);
13359 } else {
13360 if ((vp->flags & VTEXTFIXED) == 0)
13361 ckfree(vp->text);
13362 vp->flags = lvp->flags;
13363 vp->text = lvp->text;
13364 }
13365 ckfree(lvp);
13366 }
13367}
13368
13369
13370static int
13371setvarcmd(argc, argv)
13372 int argc;
13373 char **argv;
13374{
13375 if (argc <= 2)
13376 return unsetcmd(argc, argv);
13377 else if (argc == 3)
13378 setvar(argv[1], argv[2], 0);
13379 else
13380 error("List assignment not implemented");
13381 return 0;
13382}
13383
13384
13385/*
13386 * The unset builtin command. We unset the function before we unset the
13387 * variable to allow a function to be unset when there is a readonly variable
13388 * with the same name.
13389 */
13390
13391static int
13392unsetcmd(argc, argv)
13393 int argc;
13394 char **argv;
13395{
13396 char **ap;
13397 int i;
13398 int flg_func = 0;
13399 int flg_var = 0;
13400 int ret = 0;
13401
13402 while ((i = nextopt("vf")) != '\0') {
13403 if (i == 'f')
13404 flg_func = 1;
13405 else
13406 flg_var = 1;
13407 }
13408 if (flg_func == 0 && flg_var == 0)
13409 flg_var = 1;
13410
13411 for (ap = argptr; *ap ; ap++) {
13412 if (flg_func)
13413 unsetfunc(*ap);
13414 if (flg_var)
13415 ret |= unsetvar(*ap);
13416 }
13417 return ret;
13418}
13419
13420
13421/*
13422 * Unset the specified variable.
13423 */
13424
13425static int
13426unsetvar(s)
13427 const char *s;
13428 {
13429 struct var **vpp;
13430 struct var *vp;
13431
13432 vpp = findvar(hashvar(s), s);
13433 vp = *vpp;
13434 if (vp) {
13435 if (vp->flags & VREADONLY)
13436 return (1);
13437 INTOFF;
13438 if (*(strchr(vp->text, '=') + 1) != '\0')
13439 setvar(s, nullstr, 0);
13440 vp->flags &= ~VEXPORT;
13441 vp->flags |= VUNSET;
13442 if ((vp->flags & VSTRFIXED) == 0) {
13443 if ((vp->flags & VTEXTFIXED) == 0)
13444 ckfree(vp->text);
13445 *vpp = vp->next;
13446 ckfree(vp);
13447 }
13448 INTON;
13449 return (0);
13450 }
13451
13452 return (0);
13453}
13454
13455
13456
13457/*
13458 * Find the appropriate entry in the hash table from the name.
13459 */
13460
13461static struct var **
13462hashvar(p)
13463 const char *p;
13464 {
13465 unsigned int hashval;
13466
13467 hashval = ((unsigned char) *p) << 4;
13468 while (*p && *p != '=')
13469 hashval += (unsigned char) *p++;
13470 return &vartab[hashval % VTABSIZE];
13471}
13472
13473
13474
13475/*
13476 * Returns true if the two strings specify the same varable. The first
13477 * variable name is terminated by '='; the second may be terminated by
13478 * either '=' or '\0'.
13479 */
13480
13481static int
13482varequal(p, q)
13483 const char *p, *q;
13484 {
13485 while (*p == *q++) {
13486 if (*p++ == '=')
13487 return 1;
13488 }
13489 if (*p == '=' && *(q - 1) == '\0')
13490 return 1;
13491 return 0;
13492}
13493
13494static void
13495showvars(const char *myprefix, int mask, int xor)
13496{
13497 struct var **vpp;
13498 struct var *vp;
13499 const char *sep = myprefix == nullstr ? myprefix : spcstr;
13500
13501 for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
13502 for (vp = *vpp ; vp ; vp = vp->next) {
13503 if ((vp->flags & mask) ^ xor) {
13504 char *p;
13505 int len;
13506
13507 p = strchr(vp->text, '=') + 1;
13508 len = p - vp->text;
13509 p = single_quote(p);
13510
13511 out1fmt(
13512 "%s%s%.*s%s\n", myprefix, sep, len,
13513 vp->text, p
13514 );
13515 stunalloc(p);
13516 }
13517 }
13518 }
13519}
13520
13521static struct var **
13522findvar(struct var **vpp, const char *name)
13523{
13524 for (; *vpp; vpp = &(*vpp)->next) {
13525 if (varequal((*vpp)->text, name)) {
13526 break;
13527 }
13528 }
13529 return vpp;
13530}
13531
13532/*
13533 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
13534 * This file contains code for the times builtin.
Eric Andersen2870d962001-07-02 17:27:21 +000013535 * $Id: ash.c,v 1.4 2001/07/02 17:27:21 andersen Exp $
Eric Andersencb57d552001-06-28 07:25:16 +000013536 */
13537static int timescmd (int argc, char **argv)
13538{
13539 struct tms buf;
13540 long int clk_tck = sysconf(_SC_CLK_TCK);
13541
13542 times(&buf);
13543 printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
13544 (int) (buf.tms_utime / clk_tck / 60),
13545 ((double) buf.tms_utime) / clk_tck,
13546 (int) (buf.tms_stime / clk_tck / 60),
13547 ((double) buf.tms_stime) / clk_tck,
13548 (int) (buf.tms_cutime / clk_tck / 60),
13549 ((double) buf.tms_cutime) / clk_tck,
13550 (int) (buf.tms_cstime / clk_tck / 60),
13551 ((double) buf.tms_cstime) / clk_tck);
13552 return 0;
13553}
13554
Eric Andersendf82f612001-06-28 07:46:40 +000013555
13556/*-
13557 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013558 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013559 *
13560 * This code is derived from software contributed to Berkeley by
13561 * Kenneth Almquist.
13562 *
13563 * Redistribution and use in source and binary forms, with or without
13564 * modification, are permitted provided that the following conditions
13565 * are met:
13566 * 1. Redistributions of source code must retain the above copyright
13567 * notice, this list of conditions and the following disclaimer.
13568 * 2. Redistributions in binary form must reproduce the above copyright
13569 * notice, this list of conditions and the following disclaimer in the
13570 * documentation and/or other materials provided with the distribution.
13571 *
Eric Andersen2870d962001-07-02 17:27:21 +000013572 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
13573 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
Eric Andersendf82f612001-06-28 07:46:40 +000013574 *
13575 * 4. Neither the name of the University nor the names of its contributors
13576 * may be used to endorse or promote products derived from this software
13577 * without specific prior written permission.
13578 *
13579 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13580 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13581 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13582 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13583 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13584 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13585 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13586 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13587 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13588 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13589 * SUCH DAMAGE.
13590 */