blob: 66b10f346d4d0ac49012bcc59711efd023b138ea [file] [log] [blame]
Eric Andersenff9eee42001-06-29 04:57:14 +00001/* vi: set sw=4 ts=4: */
2/*
3 * Minix shell port for busybox
4 *
5 * This version of the Minix shell was adapted for use in busybox
Eric Andersencb81e642003-07-14 21:21:08 +00006 * by Erik Andersen <andersen@codepoet.org>
Eric Andersenff9eee42001-06-29 04:57:14 +00007 *
Eric Andersen737f5fb2003-03-14 16:05:59 +00008 * - backtick expansion did not work properly
9 * Jonas Holmberg <jonas.holmberg@axis.com>
10 * Robert Schwebel <r.schwebel@pengutronix.de>
Eric Andersencb81e642003-07-14 21:21:08 +000011 * Erik Andersen <andersen@codepoet.org>
Eric Andersen737f5fb2003-03-14 16:05:59 +000012 *
Rob Landleyc9c1a412006-07-12 19:17:55 +000013 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
Eric Andersenff9eee42001-06-29 04:57:14 +000014 */
15
Denis Vlasenko55f30b02007-03-24 22:42:29 +000016# include <sys/times.h>
17# include <setjmp.h>
18
Mike Frysinger67a32ad2007-03-09 08:25:24 +000019#ifdef STANDALONE
20# ifndef _GNU_SOURCE
21# define _GNU_SOURCE
22# endif
Mike Frysinger67a32ad2007-03-09 08:25:24 +000023# include <sys/types.h>
24# include <sys/stat.h>
25# include <sys/wait.h>
26# include <signal.h>
27# include <stdio.h>
28# include <stdlib.h>
29# include <unistd.h>
30# include <string.h>
31# include <errno.h>
32# include <dirent.h>
33# include <fcntl.h>
34# include <ctype.h>
35# include <assert.h>
36# define bb_dev_null "/dev/null"
37# define DEFAULT_SHELL "/proc/self/exe"
38# define CONFIG_BUSYBOX_EXEC_PATH "/proc/self/exe"
39# define BB_BANNER "busybox standalone"
40# define ENABLE_FEATURE_SH_STANDALONE_SHELL 0
41# define bb_msg_memory_exhausted "memory exhausted"
42# define xmalloc(size) malloc(size)
43# define msh_main(argc,argv) main(argc,argv)
44# define safe_read(fd,buf,count) read(fd,buf,count)
45# define NOT_LONE_DASH(s) ((s)[0] != '-' || (s)[1])
46# define LONE_CHAR(s,c) ((s)[0] == (c) && !(s)[1])
47# define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__))
48static char *find_applet_by_name(const char *applet)
49{
50 return NULL;
51}
52static void utoa_to_buf(unsigned n, char *buf, unsigned buflen)
53{
Denis Vlasenkoc86e0522007-03-20 11:30:28 +000054 unsigned i, out, res;
55 assert(sizeof(unsigned) == 4);
56 if (buflen) {
57 out = 0;
58 for (i = 1000000000; i; i /= 10) {
59 res = n / i;
60 if (res || out || i == 1) {
61 if (!--buflen) break;
62 out++;
63 n -= res*i;
64 *buf++ = '0' + res;
65 }
66 }
67 *buf = '\0';
68 }
Mike Frysinger67a32ad2007-03-09 08:25:24 +000069}
70static void itoa_to_buf(int n, char *buf, unsigned buflen)
71{
Denis Vlasenkoc86e0522007-03-20 11:30:28 +000072 if (buflen && n < 0) {
73 n = -n;
74 *buf++ = '-';
75 buflen--;
76 }
77 utoa_to_buf((unsigned)n, buf, buflen);
Mike Frysinger67a32ad2007-03-09 08:25:24 +000078}
79static char local_buf[12];
80static char *itoa(int n)
81{
Denis Vlasenkoc86e0522007-03-20 11:30:28 +000082 itoa_to_buf(n, local_buf, sizeof(local_buf));
83 return local_buf;
Mike Frysinger67a32ad2007-03-09 08:25:24 +000084}
85#else
Mike Frysinger67a32ad2007-03-09 08:25:24 +000086# include "busybox.h"
Denis Vlasenko489f93e2007-02-01 01:43:16 +000087extern char **environ;
Mike Frysinger67a32ad2007-03-09 08:25:24 +000088#endif
Eric Andersenff9eee42001-06-29 04:57:14 +000089
Mike Frysinger17811882006-05-05 20:33:07 +000090/*#define MSHDEBUG 1*/
Eric Andersen12de6cf2004-08-04 19:19:10 +000091
92#ifdef MSHDEBUG
Mike Frysinger14ff19b2006-06-20 20:37:01 +000093int mshdbg = MSHDEBUG;
Eric Andersen12de6cf2004-08-04 19:19:10 +000094
95#define DBGPRINTF(x) if(mshdbg>0)printf x
96#define DBGPRINTF0(x) if(mshdbg>0)printf x
97#define DBGPRINTF1(x) if(mshdbg>1)printf x
98#define DBGPRINTF2(x) if(mshdbg>2)printf x
99#define DBGPRINTF3(x) if(mshdbg>3)printf x
100#define DBGPRINTF4(x) if(mshdbg>4)printf x
101#define DBGPRINTF5(x) if(mshdbg>5)printf x
102#define DBGPRINTF6(x) if(mshdbg>6)printf x
103#define DBGPRINTF7(x) if(mshdbg>7)printf x
104#define DBGPRINTF8(x) if(mshdbg>8)printf x
105#define DBGPRINTF9(x) if(mshdbg>9)printf x
106
107int mshdbg_rc = 0;
108
109#define RCPRINTF(x) if(mshdbg_rc)printf x
110
111#else
112
113#define DBGPRINTF(x)
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000114#define DBGPRINTF0(x) ((void)0)
115#define DBGPRINTF1(x) ((void)0)
116#define DBGPRINTF2(x) ((void)0)
117#define DBGPRINTF3(x) ((void)0)
118#define DBGPRINTF4(x) ((void)0)
119#define DBGPRINTF5(x) ((void)0)
120#define DBGPRINTF6(x) ((void)0)
121#define DBGPRINTF7(x) ((void)0)
122#define DBGPRINTF8(x) ((void)0)
123#define DBGPRINTF9(x) ((void)0)
Eric Andersen12de6cf2004-08-04 19:19:10 +0000124
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000125#define RCPRINTF(x) ((void)0)
Eric Andersen12de6cf2004-08-04 19:19:10 +0000126
127#endif /* MSHDEBUG */
128
129
Denis Vlasenko38f63192007-01-22 09:03:07 +0000130#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
Mike Frysinger2a131752006-06-06 06:26:12 +0000131# define DEFAULT_ROOT_PROMPT "\\u:\\w> "
132# define DEFAULT_USER_PROMPT "\\u:\\w$ "
133#else
134# define DEFAULT_ROOT_PROMPT "# "
135# define DEFAULT_USER_PROMPT "$ "
136#endif
137
138
Eric Andersenff9eee42001-06-29 04:57:14 +0000139/* -------- sh.h -------- */
140/*
141 * shell
142 */
143
Eric Andersen12de6cf2004-08-04 19:19:10 +0000144#define LINELIM 2100
145#define NPUSH 8 /* limit to input nesting */
Eric Andersenff9eee42001-06-29 04:57:14 +0000146
Eric Andersen392947c2002-12-11 07:42:46 +0000147#undef NOFILE
Eric Andersen12de6cf2004-08-04 19:19:10 +0000148#define NOFILE 20 /* Number of open files */
149#define NUFILE 10 /* Number of user-accessible files */
150#define FDBASE 10 /* First file usable by Shell */
Eric Andersenff9eee42001-06-29 04:57:14 +0000151
152/*
153 * values returned by wait
154 */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000155#define WAITSIG(s) ((s)&0177)
156#define WAITVAL(s) (((s)>>8)&0377)
Eric Andersenff9eee42001-06-29 04:57:14 +0000157#define WAITCORE(s) (((s)&0200)!=0)
158
159/*
Eric Andersenaff114c2004-04-14 17:51:38 +0000160 * library and system definitions
Eric Andersenff9eee42001-06-29 04:57:14 +0000161 */
Eric Andersen8401eea2004-08-04 19:16:54 +0000162typedef void xint; /* base type of jmp_buf, for not broken compilers */
Eric Andersenff9eee42001-06-29 04:57:14 +0000163
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000164
Eric Andersenff9eee42001-06-29 04:57:14 +0000165/*
166 * shell components
167 */
Eric Andersenff9eee42001-06-29 04:57:14 +0000168#define NOBLOCK ((struct op *)NULL)
169#define NOWORD ((char *)NULL)
170#define NOWORDS ((char **)NULL)
171#define NOPIPE ((int *)NULL)
172
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000173
174/*
175 * redirection
176 */
177struct ioword {
178 short io_unit; /* unit affected */
179 short io_flag; /* action (below) */
180 char *io_name; /* file name */
181};
182
183#define IOREAD 1 /* < */
184#define IOHERE 2 /* << (here file) */
185#define IOWRITE 4 /* > */
186#define IOCAT 8 /* >> */
187#define IOXHERE 16 /* ${}, ` in << */
188#define IODUP 32 /* >&digit */
189#define IOCLOSE 64 /* >&- */
190
191#define IODEFAULT (-1) /* token for default IO unit */
192
193
Eric Andersenff9eee42001-06-29 04:57:14 +0000194/*
195 * Description of a command or an operation on commands.
196 * Might eventually use a union.
197 */
198struct op {
Eric Andersen8401eea2004-08-04 19:16:54 +0000199 int type; /* operation type, see below */
200 char **words; /* arguments to a command */
201 struct ioword **ioact; /* IO actions (eg, < > >>) */
Eric Andersenff9eee42001-06-29 04:57:14 +0000202 struct op *left;
203 struct op *right;
Eric Andersen8401eea2004-08-04 19:16:54 +0000204 char *str; /* identifier for case and for */
Eric Andersenff9eee42001-06-29 04:57:14 +0000205};
206
Eric Andersen8401eea2004-08-04 19:16:54 +0000207#define TCOM 1 /* command */
208#define TPAREN 2 /* (c-list) */
209#define TPIPE 3 /* a | b */
210#define TLIST 4 /* a [&;] b */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000211#define TOR 5 /* || */
Eric Andersen8401eea2004-08-04 19:16:54 +0000212#define TAND 6 /* && */
Eric Andersenff9eee42001-06-29 04:57:14 +0000213#define TFOR 7
Eric Andersen12de6cf2004-08-04 19:19:10 +0000214#define TDO 8
Eric Andersenff9eee42001-06-29 04:57:14 +0000215#define TCASE 9
Eric Andersen12de6cf2004-08-04 19:19:10 +0000216#define TIF 10
Eric Andersenff9eee42001-06-29 04:57:14 +0000217#define TWHILE 11
218#define TUNTIL 12
219#define TELIF 13
Eric Andersen8401eea2004-08-04 19:16:54 +0000220#define TPAT 14 /* pattern in case */
221#define TBRACE 15 /* {c-list} */
222#define TASYNC 16 /* c & */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000223/* Added to support "." file expansion */
224#define TDOT 17
225
226/* Strings for names to make debug easier */
"Vladimir N. Oleynik"ac973172005-09-22 14:38:17 +0000227#ifdef MSHDEBUG
Denis Vlasenkoe27f1562007-01-01 06:00:38 +0000228static const char *const T_CMD_NAMES[] = {
Eric Andersen12de6cf2004-08-04 19:19:10 +0000229 "PLACEHOLDER",
230 "TCOM",
231 "TPAREN",
232 "TPIPE",
233 "TLIST",
234 "TOR",
235 "TAND",
236 "TFOR",
237 "TDO",
238 "TCASE",
239 "TIF",
240 "TWHILE",
241 "TUNTIL",
242 "TELIF",
243 "TPAT",
244 "TBRACE",
245 "TASYNC",
246 "TDOT",
247};
"Vladimir N. Oleynik"ac973172005-09-22 14:38:17 +0000248#endif
Eric Andersenff9eee42001-06-29 04:57:14 +0000249
250/*
251 * actions determining the environment of a process
252 */
253#define BIT(i) (1<<(i))
Eric Andersen8401eea2004-08-04 19:16:54 +0000254#define FEXEC BIT(0) /* execute without forking */
Eric Andersenff9eee42001-06-29 04:57:14 +0000255
Eric Andersen12de6cf2004-08-04 19:19:10 +0000256#define AREASIZE (90000)
Eric Andersen12de6cf2004-08-04 19:19:10 +0000257
Eric Andersenff9eee42001-06-29 04:57:14 +0000258/*
259 * flags to control evaluation of words
260 */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000261#define DOSUB 1 /* interpret $, `, and quotes */
262#define DOBLANK 2 /* perform blank interpretation */
263#define DOGLOB 4 /* interpret [?* */
264#define DOKEY 8 /* move words with `=' to 2nd arg. list */
265#define DOTRIM 16 /* trim resulting string */
Eric Andersenff9eee42001-06-29 04:57:14 +0000266
267#define DOALL (DOSUB|DOBLANK|DOGLOB|DOKEY|DOTRIM)
268
Eric Andersenff9eee42001-06-29 04:57:14 +0000269
Eric Andersen12de6cf2004-08-04 19:19:10 +0000270/* PROTOTYPES */
Eric Andersenff9eee42001-06-29 04:57:14 +0000271static int newfile(char *s);
Eric Andersenff9eee42001-06-29 04:57:14 +0000272
273
Eric Andersen8401eea2004-08-04 19:16:54 +0000274struct brkcon {
275 jmp_buf brkpt;
276 struct brkcon *nextlev;
277};
Eric Andersenff9eee42001-06-29 04:57:14 +0000278
Eric Andersen12de6cf2004-08-04 19:19:10 +0000279
Eric Andersenff9eee42001-06-29 04:57:14 +0000280/*
Eric Andersenff9eee42001-06-29 04:57:14 +0000281 * flags:
282 * -e: quit on error
283 * -k: look for name=value everywhere on command line
284 * -n: no execution
285 * -t: exit after reading and executing one command
286 * -v: echo as read
287 * -x: trace
288 * -u: unset variables net diagnostic
289 */
Mike Frysinger3672fe92006-11-15 21:52:10 +0000290static char flags['z' - 'a' + 1];
291/* this looks weird, but is OK ... we index flag with 'a'...'z' */
292static char *flag = flags - 'a';
Eric Andersenff9eee42001-06-29 04:57:14 +0000293
Eric Andersen8401eea2004-08-04 19:16:54 +0000294static char *null; /* null value for variable */
295static int intr; /* interrupt pending */
Eric Andersenff9eee42001-06-29 04:57:14 +0000296
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000297/* moved to G: static char *trap[_NSIG + 1]; */
298/* moved to G: static char ourtrap[_NSIG + 1]; */
Eric Andersen8401eea2004-08-04 19:16:54 +0000299static int trapset; /* trap pending */
Eric Andersenff9eee42001-06-29 04:57:14 +0000300
Eric Andersen8401eea2004-08-04 19:16:54 +0000301static int heedint; /* heed interrupt signals */
Eric Andersenff9eee42001-06-29 04:57:14 +0000302
Eric Andersen8401eea2004-08-04 19:16:54 +0000303static int yynerrs; /* yacc */
Eric Andersenff9eee42001-06-29 04:57:14 +0000304
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000305/* moved to G: static char line[LINELIM]; */
Eric Andersenff9eee42001-06-29 04:57:14 +0000306
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000307#if ENABLE_FEATURE_EDITING
308static char *current_prompt;
309static line_input_t *line_input_state;
310#endif
311
Eric Andersen12de6cf2004-08-04 19:19:10 +0000312
Eric Andersenff9eee42001-06-29 04:57:14 +0000313/*
314 * other functions
315 */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000316static const char *rexecve(char *c, char **v, char **envp);
Eric Andersen8401eea2004-08-04 19:16:54 +0000317static char *evalstr(char *cp, int f);
318static char *putn(int n);
Eric Andersen8401eea2004-08-04 19:16:54 +0000319static char *unquote(char *as);
Eric Andersen8401eea2004-08-04 19:16:54 +0000320static int rlookup(char *n);
321static struct wdblock *glob(char *cp, struct wdblock *wb);
322static int my_getc(int ec);
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +0000323static int subgetc(char ec, int quoted);
Eric Andersenfd7a4c82004-09-02 23:13:10 +0000324static char **makenv(int all, struct wdblock *wb);
Eric Andersen8401eea2004-08-04 19:16:54 +0000325static char **eval(char **ap, int f);
326static int setstatus(int s);
327static int waitfor(int lastpid, int canintr);
Eric Andersenff9eee42001-06-29 04:57:14 +0000328
Eric Andersen8401eea2004-08-04 19:16:54 +0000329static void onintr(int s); /* SIGINT handler */
Eric Andersenff9eee42001-06-29 04:57:14 +0000330
Eric Andersen8401eea2004-08-04 19:16:54 +0000331static int newenv(int f);
332static void quitenv(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000333static void next(int f);
334static void setdash(void);
335static void onecommand(void);
336static void runtrap(int i);
Eric Andersenff9eee42001-06-29 04:57:14 +0000337
Eric Andersen12de6cf2004-08-04 19:19:10 +0000338
Eric Andersenff9eee42001-06-29 04:57:14 +0000339/* -------- area stuff -------- */
340
Eric Andersen12de6cf2004-08-04 19:19:10 +0000341#define REGSIZE sizeof(struct region)
342#define GROWBY (256)
343/* #define SHRINKBY (64) */
Eric Andersenff9eee42001-06-29 04:57:14 +0000344#undef SHRINKBY
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000345#define FREE (32767)
346#define BUSY (0)
347#define ALIGN (sizeof(int)-1)
Eric Andersenff9eee42001-06-29 04:57:14 +0000348
349
350struct region {
Eric Andersen8401eea2004-08-04 19:16:54 +0000351 struct region *next;
352 int area;
Eric Andersenff9eee42001-06-29 04:57:14 +0000353};
354
355
Eric Andersenff9eee42001-06-29 04:57:14 +0000356/* -------- grammar stuff -------- */
357typedef union {
Eric Andersen8401eea2004-08-04 19:16:54 +0000358 char *cp;
359 char **wp;
360 int i;
361 struct op *o;
Eric Andersenff9eee42001-06-29 04:57:14 +0000362} YYSTYPE;
Eric Andersen8401eea2004-08-04 19:16:54 +0000363
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000364#define WORD 256
365#define LOGAND 257
366#define LOGOR 258
367#define BREAK 259
368#define IF 260
369#define THEN 261
370#define ELSE 262
371#define ELIF 263
372#define FI 264
373#define CASE 265
374#define ESAC 266
375#define FOR 267
376#define WHILE 268
377#define UNTIL 269
378#define DO 270
379#define DONE 271
380#define IN 272
Eric Andersen12de6cf2004-08-04 19:19:10 +0000381/* Added for "." file expansion */
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000382#define DOT 273
Eric Andersen12de6cf2004-08-04 19:19:10 +0000383
Eric Andersenff9eee42001-06-29 04:57:14 +0000384#define YYERRCODE 300
385
386/* flags to yylex */
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000387#define CONTIN 01 /* skip new lines to complete command */
Eric Andersenff9eee42001-06-29 04:57:14 +0000388
Eric Andersen8401eea2004-08-04 19:16:54 +0000389static struct op *pipeline(int cf);
Eric Andersenff9eee42001-06-29 04:57:14 +0000390static struct op *andor(void);
391static struct op *c_list(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000392static int synio(int cf);
393static void musthave(int c, int cf);
Eric Andersenff9eee42001-06-29 04:57:14 +0000394static struct op *simple(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000395static struct op *nested(int type, int mark);
396static struct op *command(int cf);
397static struct op *dogroup(int onlydone);
Eric Andersenff9eee42001-06-29 04:57:14 +0000398static struct op *thenpart(void);
399static struct op *elsepart(void);
400static struct op *caselist(void);
401static struct op *casepart(void);
402static char **pattern(void);
403static char **wordlist(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000404static struct op *list(struct op *t1, struct op *t2);
405static struct op *block(int type, struct op *t1, struct op *t2, char **wp);
Eric Andersenff9eee42001-06-29 04:57:14 +0000406static struct op *newtp(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000407static struct op *namelist(struct op *t);
Eric Andersenff9eee42001-06-29 04:57:14 +0000408static char **copyw(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000409static void word(char *cp);
Eric Andersenff9eee42001-06-29 04:57:14 +0000410static struct ioword **copyio(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000411static struct ioword *io(int u, int f, char *cp);
Eric Andersen8401eea2004-08-04 19:16:54 +0000412static int yylex(int cf);
413static int collect(int c, int c1);
414static int dual(int c);
415static void diag(int ec);
416static char *tree(unsigned size);
Eric Andersenff9eee42001-06-29 04:57:14 +0000417
418/* -------- var.h -------- */
419
Eric Andersen8401eea2004-08-04 19:16:54 +0000420struct var {
421 char *value;
422 char *name;
423 struct var *next;
424 char status;
Eric Andersenff9eee42001-06-29 04:57:14 +0000425};
Eric Andersenff9eee42001-06-29 04:57:14 +0000426
Eric Andersen8401eea2004-08-04 19:16:54 +0000427#define COPYV 1 /* flag to setval, suggesting copy */
428#define RONLY 01 /* variable is read-only */
429#define EXPORT 02 /* variable is to be exported */
430#define GETCELL 04 /* name & value space was got with getcell */
Eric Andersenff9eee42001-06-29 04:57:14 +0000431
Eric Andersen8401eea2004-08-04 19:16:54 +0000432static int yyparse(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000433
434static int execute(struct op *t, int *pin, int *pout, int act);
Eric Andersenff9eee42001-06-29 04:57:14 +0000435
Eric Andersen12de6cf2004-08-04 19:19:10 +0000436
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000437#define AFID_NOBUF (~0)
438#define AFID_ID 0
439
440
Eric Andersenff9eee42001-06-29 04:57:14 +0000441/* -------- io.h -------- */
442/* io buffer */
443struct iobuf {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000444 unsigned id; /* buffer id */
445 char buf[512]; /* buffer */
446 char *bufp; /* pointer into buffer */
447 char *ebufp; /* pointer to end of buffer */
Eric Andersenff9eee42001-06-29 04:57:14 +0000448};
449
450/* possible arguments to an IO function */
451struct ioarg {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000452 const char *aword;
Eric Andersen8401eea2004-08-04 19:16:54 +0000453 char **awordlist;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000454 int afile; /* file descriptor */
455 unsigned afid; /* buffer id */
456 long afpos; /* file position */
457 struct iobuf *afbuf; /* buffer for this file */
Eric Andersenff9eee42001-06-29 04:57:14 +0000458};
Eric Andersen8401eea2004-08-04 19:16:54 +0000459
Eric Andersenff9eee42001-06-29 04:57:14 +0000460/* an input generator's state */
Eric Andersen8401eea2004-08-04 19:16:54 +0000461struct io {
462 int (*iofn) (struct ioarg *, struct io *);
463 struct ioarg *argp;
464 int peekc;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000465 char prev; /* previous character read by readc() */
466 char nlcount; /* for `'s */
467 char xchar; /* for `'s */
468 char task; /* reason for pushed IO */
Eric Andersenff9eee42001-06-29 04:57:14 +0000469};
Eric Andersen8401eea2004-08-04 19:16:54 +0000470
Eric Andersen8401eea2004-08-04 19:16:54 +0000471#define XOTHER 0 /* none of the below */
472#define XDOLL 1 /* expanding ${} */
473#define XGRAVE 2 /* expanding `'s */
Denis Vlasenkoe27f1562007-01-01 06:00:38 +0000474#define XIO 3 /* file IO */
Eric Andersenff9eee42001-06-29 04:57:14 +0000475
476/* in substitution */
477#define INSUB() (e.iop->task == XGRAVE || e.iop->task == XDOLL)
478
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000479static struct ioarg temparg = { 0, 0, 0, AFID_NOBUF, 0 }; /* temporary for PUSHIO */
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000480/* moved to G: static struct ioarg ioargstack[NPUSH]; */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000481static struct io iostack[NPUSH];
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000482/* moved to G: static struct iobuf sharedbuf = { AFID_NOBUF }; */
483/* moved to G: static struct iobuf mainbuf = { AFID_NOBUF }; */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000484static unsigned bufid = AFID_ID; /* buffer id counter */
485
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000486#define RUN(what,arg,gen) ((temparg.what = (arg)), run(&temparg,(gen)))
487
488
489/*
Eric Andersenff9eee42001-06-29 04:57:14 +0000490 * input generators for IO structure
491 */
Eric Andersen8401eea2004-08-04 19:16:54 +0000492static int nlchar(struct ioarg *ap);
493static int strchar(struct ioarg *ap);
494static int qstrchar(struct ioarg *ap);
495static int filechar(struct ioarg *ap);
496static int herechar(struct ioarg *ap);
497static int linechar(struct ioarg *ap);
498static int gravechar(struct ioarg *ap, struct io *iop);
499static int qgravechar(struct ioarg *ap, struct io *iop);
500static int dolchar(struct ioarg *ap);
501static int wdchar(struct ioarg *ap);
502static void scraphere(void);
503static void freehere(int area);
504static void gethere(void);
505static void markhere(char *s, struct ioword *iop);
506static int herein(char *hname, int xdoll);
507static int run(struct ioarg *argp, int (*f) (struct ioarg *));
Eric Andersenff9eee42001-06-29 04:57:14 +0000508
Eric Andersen12de6cf2004-08-04 19:19:10 +0000509
Eric Andersen8401eea2004-08-04 19:16:54 +0000510static int eofc(void);
511static int readc(void);
512static void unget(int c);
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +0000513static void ioecho(char c);
Eric Andersenff9eee42001-06-29 04:57:14 +0000514
Eric Andersen12de6cf2004-08-04 19:19:10 +0000515
Eric Andersenff9eee42001-06-29 04:57:14 +0000516/*
517 * IO control
518 */
Eric Andersen8401eea2004-08-04 19:16:54 +0000519static void pushio(struct ioarg *argp, int (*f) (struct ioarg *));
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000520#define PUSHIO(what,arg,gen) ((temparg.what = (arg)), pushio(&temparg,(gen)))
Eric Andersen8401eea2004-08-04 19:16:54 +0000521static int remap(int fd);
522static int openpipe(int *pv);
523static void closepipe(int *pv);
524static struct io *setbase(struct io *ip);
Eric Andersenff9eee42001-06-29 04:57:14 +0000525
Eric Andersenff9eee42001-06-29 04:57:14 +0000526/* -------- word.h -------- */
527
Eric Andersen8401eea2004-08-04 19:16:54 +0000528#define NSTART 16 /* default number of words to allow for initially */
Eric Andersenff9eee42001-06-29 04:57:14 +0000529
Eric Andersen8401eea2004-08-04 19:16:54 +0000530struct wdblock {
531 short w_bsize;
532 short w_nword;
Eric Andersenff9eee42001-06-29 04:57:14 +0000533 /* bounds are arbitrary */
Eric Andersen8401eea2004-08-04 19:16:54 +0000534 char *w_words[1];
Eric Andersenff9eee42001-06-29 04:57:14 +0000535};
536
Eric Andersen8401eea2004-08-04 19:16:54 +0000537static struct wdblock *addword(char *wd, struct wdblock *wb);
538static struct wdblock *newword(int nw);
539static char **getwords(struct wdblock *wb);
Eric Andersenff9eee42001-06-29 04:57:14 +0000540
Eric Andersenff9eee42001-06-29 04:57:14 +0000541/* -------- misc stuff -------- */
542
Eric Andersen12de6cf2004-08-04 19:19:10 +0000543static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp);
Eric Andersen8401eea2004-08-04 19:16:54 +0000544static int iosetup(struct ioword *iop, int pipein, int pipeout);
Eric Andersen8401eea2004-08-04 19:16:54 +0000545static void brkset(struct brkcon *bc);
546static int dolabel(struct op *t);
547static int dohelp(struct op *t);
548static int dochdir(struct op *t);
549static int doshift(struct op *t);
550static int dologin(struct op *t);
551static int doumask(struct op *t);
552static int doexec(struct op *t);
553static int dodot(struct op *t);
554static int dowait(struct op *t);
555static int doread(struct op *t);
556static int doeval(struct op *t);
557static int dotrap(struct op *t);
558static int getsig(char *s);
559static void setsig(int n, sighandler_t f);
560static int getn(char *as);
561static int dobreak(struct op *t);
562static int docontinue(struct op *t);
563static int brkcontin(char *cp, int val);
564static int doexit(struct op *t);
565static int doexport(struct op *t);
566static int doreadonly(struct op *t);
567static void rdexp(char **wp, void (*f) (struct var *), int key);
568static void badid(char *s);
569static int doset(struct op *t);
570static void varput(char *s, int out);
571static int dotimes(struct op *t);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000572static int expand(const char *cp, struct wdblock **wbp, int f);
Eric Andersen8401eea2004-08-04 19:16:54 +0000573static char *blank(int f);
574static int dollar(int quoted);
575static int grave(int quoted);
576static void globname(char *we, char *pp);
577static char *generate(char *start1, char *end1, char *middle, char *end);
578static int anyspcl(struct wdblock *wb);
579static int xstrcmp(char *p1, char *p2);
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000580static void glob0(char *a0, unsigned a1, int a2,
Eric Andersen8401eea2004-08-04 19:16:54 +0000581 int (*a3) (char *, char *));
Eric Andersen8401eea2004-08-04 19:16:54 +0000582static void readhere(char **name, char *s, int ec);
Eric Andersen8401eea2004-08-04 19:16:54 +0000583static int xxchar(struct ioarg *ap);
Eric Andersenff9eee42001-06-29 04:57:14 +0000584
Eric Andersen8401eea2004-08-04 19:16:54 +0000585struct here {
586 char *h_tag;
587 int h_dosub;
588 struct ioword *h_iop;
589 struct here *h_next;
Eric Andersenff9eee42001-06-29 04:57:14 +0000590};
591
"Vladimir N. Oleynik"485d7cb2005-10-17 09:48:57 +0000592static const char * const signame[] = {
Eric Andersenff9eee42001-06-29 04:57:14 +0000593 "Signal 0",
594 "Hangup",
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000595 NULL, /* interrupt */
Eric Andersenff9eee42001-06-29 04:57:14 +0000596 "Quit",
597 "Illegal instruction",
598 "Trace/BPT trap",
599 "Abort",
600 "Bus error",
601 "Floating Point Exception",
602 "Killed",
603 "SIGUSR1",
604 "SIGSEGV",
605 "SIGUSR2",
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000606 NULL, /* broken pipe */
Eric Andersenff9eee42001-06-29 04:57:14 +0000607 "Alarm clock",
608 "Terminated",
609};
Eric Andersen8401eea2004-08-04 19:16:54 +0000610
Eric Andersenff9eee42001-06-29 04:57:14 +0000611#define NSIGNAL (sizeof(signame)/sizeof(signame[0]))
612
613struct res {
"Vladimir N. Oleynik"485d7cb2005-10-17 09:48:57 +0000614 const char *r_name;
Eric Andersen8401eea2004-08-04 19:16:54 +0000615 int r_val;
Eric Andersenff9eee42001-06-29 04:57:14 +0000616};
"Vladimir N. Oleynik"485d7cb2005-10-17 09:48:57 +0000617static const struct res restab[] = {
Eric Andersen8401eea2004-08-04 19:16:54 +0000618 {"for", FOR},
619 {"case", CASE},
620 {"esac", ESAC},
621 {"while", WHILE},
622 {"do", DO},
623 {"done", DONE},
624 {"if", IF},
625 {"in", IN},
626 {"then", THEN},
627 {"else", ELSE},
628 {"elif", ELIF},
629 {"until", UNTIL},
630 {"fi", FI},
Eric Andersen8401eea2004-08-04 19:16:54 +0000631 {";;", BREAK},
632 {"||", LOGOR},
633 {"&&", LOGAND},
634 {"{", '{'},
635 {"}", '}'},
Eric Andersen12de6cf2004-08-04 19:19:10 +0000636 {".", DOT},
Eric Andersen8401eea2004-08-04 19:16:54 +0000637 {0, 0},
Eric Andersenff9eee42001-06-29 04:57:14 +0000638};
639
640
Eric Andersen1c039232001-07-07 00:05:55 +0000641struct builtincmd {
642 const char *name;
Eric Andersen8401eea2004-08-04 19:16:54 +0000643 int (*builtinfunc) (struct op * t);
Eric Andersenff9eee42001-06-29 04:57:14 +0000644};
Eric Andersen8401eea2004-08-04 19:16:54 +0000645static const struct builtincmd builtincmds[] = {
646 {".", dodot},
647 {":", dolabel},
648 {"break", dobreak},
649 {"cd", dochdir},
650 {"continue", docontinue},
651 {"eval", doeval},
652 {"exec", doexec},
653 {"exit", doexit},
654 {"export", doexport},
655 {"help", dohelp},
656 {"login", dologin},
657 {"newgrp", dologin},
658 {"read", doread},
659 {"readonly", doreadonly},
660 {"set", doset},
661 {"shift", doshift},
662 {"times", dotimes},
663 {"trap", dotrap},
664 {"umask", doumask},
665 {"wait", dowait},
666 {0, 0}
Eric Andersenff9eee42001-06-29 04:57:14 +0000667};
668
"Vladimir N. Oleynik"ac973172005-09-22 14:38:17 +0000669static struct op *scantree(struct op *);
Eric Andersen12de6cf2004-08-04 19:19:10 +0000670static struct op *dowholefile(int, int);
671
Eric Andersen12de6cf2004-08-04 19:19:10 +0000672
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000673/* Globals */
Eric Andersen8401eea2004-08-04 19:16:54 +0000674static char **dolv;
675static int dolc;
676static int exstat;
677static char gflg;
"Vladimir N. Oleynik"485d7cb2005-10-17 09:48:57 +0000678static int interactive; /* Is this an interactive shell */
Eric Andersen8401eea2004-08-04 19:16:54 +0000679static int execflg;
680static int multiline; /* \n changed to ; */
681static struct op *outtree; /* result from parser */
682static xint *failpt;
683static xint *errpt;
684static struct brkcon *brklist;
685static int isbreak;
686static struct wdblock *wdlist;
687static struct wdblock *iolist;
Eric Andersen12de6cf2004-08-04 19:19:10 +0000688
689#ifdef MSHDEBUG
690static struct var *mshdbg_var;
691#endif
Eric Andersen8401eea2004-08-04 19:16:54 +0000692static struct var *vlist; /* dictionary */
693static struct var *homedir; /* home directory */
694static struct var *prompt; /* main prompt */
695static struct var *cprompt; /* continuation prompt */
696static struct var *path; /* search path for commands */
697static struct var *shell; /* shell to interpret command files */
698static struct var *ifs; /* field separators */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000699
Eric Andersen8401eea2004-08-04 19:16:54 +0000700static int areanum; /* current allocation area */
701static int intr;
702static int inparse;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000703static char *null = (char*)"";
Eric Andersen8401eea2004-08-04 19:16:54 +0000704static int heedint = 1;
Eric Andersen8401eea2004-08-04 19:16:54 +0000705static void (*qflag) (int) = SIG_IGN;
706static int startl;
707static int peeksym;
708static int nlseen;
709static int iounit = IODEFAULT;
710static YYSTYPE yylval;
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000711static char *elinep; /* done in main(): = line + sizeof(line) - 5 */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000712
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000713static struct here *inhere; /* list of hear docs while parsing */
714static struct here *acthere; /* list of active here documents */
715static struct region *areabot; /* bottom of area */
716static struct region *areatop; /* top of area */
717static struct region *areanxt; /* starting point of scan */
Eric Andersen8401eea2004-08-04 19:16:54 +0000718static void *brktop;
719static void *brkaddr;
Eric Andersenff9eee42001-06-29 04:57:14 +0000720
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000721/*
722 * parsing & execution environment
723 */
724struct env {
725 char *linep;
726 struct io *iobase;
727 struct io *iop;
728 xint *errpt; /* void * */
729 int iofd;
730 struct env *oenv;
731};
732
Eric Andersen12de6cf2004-08-04 19:19:10 +0000733static struct env e = {
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000734 NULL /* set to line in main() */, /* linep: char ptr */
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000735 iostack, /* iobase: struct io ptr */
736 iostack - 1, /* iop: struct io ptr */
737 (xint *) NULL, /* errpt: void ptr for errors? */
738 FDBASE, /* iofd: file desc */
739 (struct env *) NULL /* oenv: struct env ptr */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000740};
741
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000742
743struct globals {
744 char ourtrap[_NSIG + 1];
745 char *trap[_NSIG + 1];
746 struct iobuf sharedbuf; /* in main(): set to { AFID_NOBUF } */
747 struct iobuf mainbuf; /* in main(): set to { AFID_NOBUF } */
748 struct ioarg ioargstack[NPUSH];
749 char filechar_cmdbuf[BUFSIZ];
750 char line[LINELIM];
751 char child_cmd[LINELIM];
752};
753
754#define G (*ptr_to_globals)
755#define ourtrap (G.ourtrap )
756#define trap (G.trap )
757#define sharedbuf (G.sharedbuf )
758#define mainbuf (G.mainbuf )
759#define ioargstack (G.ioargstack )
760#define filechar_cmdbuf (G.filechar_cmdbuf)
761#define line (G.line )
762#define child_cmd (G.child_cmd )
763
764
Eric Andersen12de6cf2004-08-04 19:19:10 +0000765#ifdef MSHDEBUG
766void print_t(struct op *t)
767{
Mike Frysinger02d8fa42006-05-05 20:32:31 +0000768 DBGPRINTF(("T: t=%p, type %s, words=%p, IOword=%p\n", t,
769 T_CMD_NAMES[t->type], t->words, t->ioact));
Eric Andersen12de6cf2004-08-04 19:19:10 +0000770
771 if (t->words) {
772 DBGPRINTF(("T: W1: %s", t->words[0]));
773 }
Eric Andersen12de6cf2004-08-04 19:19:10 +0000774}
775
776void print_tree(struct op *head)
777{
778 if (head == NULL) {
779 DBGPRINTF(("PRINT_TREE: no tree\n"));
780 return;
781 }
782
Mike Frysinger02d8fa42006-05-05 20:32:31 +0000783 DBGPRINTF(("NODE: %p, left %p, right %p\n", head, head->left,
Eric Andersen12de6cf2004-08-04 19:19:10 +0000784 head->right));
785
786 if (head->left)
787 print_tree(head->left);
788
789 if (head->right)
790 print_tree(head->right);
Eric Andersen12de6cf2004-08-04 19:19:10 +0000791}
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000792#endif /* MSHDEBUG */
793
794
795/*
796 * IO functions
797 */
798static void prs(const char *s)
799{
800 if (*s)
801 write(2, s, strlen(s));
802}
803
804static void prn(unsigned u)
805{
806 prs(itoa(u));
807}
808
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000809static void echo(char **wp)
810{
811 int i;
812
813 prs("+");
814 for (i = 0; wp[i]; i++) {
815 if (i)
816 prs(" ");
817 prs(wp[i]);
818 }
819 prs("\n");
820}
821
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000822static void closef(int i)
823{
824 if (i > 2)
825 close(i);
826}
827
828static void closeall(void)
829{
830 int u;
831
832 for (u = NUFILE; u < NOFILE;)
833 close(u++);
834}
Eric Andersen12de6cf2004-08-04 19:19:10 +0000835
Eric Andersenff9eee42001-06-29 04:57:14 +0000836
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000837/* fail but return to process next command */
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000838static void fail(void) ATTRIBUTE_NORETURN;
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000839static void fail(void)
840{
841 longjmp(failpt, 1);
842 /* NOTREACHED */
843}
Eric Andersenff9eee42001-06-29 04:57:14 +0000844
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000845/* abort shell (or fail in subshell) */
846static void leave(void) ATTRIBUTE_NORETURN;
847static void leave(void)
848{
849 DBGPRINTF(("LEAVE: leave called!\n"));
850
851 if (execflg)
852 fail();
853 scraphere();
854 freehere(1);
855 runtrap(0);
856 _exit(exstat);
857 /* NOTREACHED */
858}
859
860static void warn(const char *s)
861{
862 if (*s) {
863 prs(s);
864 exstat = -1;
865 }
866 prs("\n");
867 if (flag['e'])
868 leave();
869}
870
871static void err(const char *s)
872{
873 warn(s);
874 if (flag['n'])
875 return;
876 if (!interactive)
877 leave();
878 if (e.errpt)
879 longjmp(e.errpt, 1);
880 closeall();
881 e.iop = e.iobase = iostack;
882}
883
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000884
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000885/* -------- area.c -------- */
886
Eric Andersenff9eee42001-06-29 04:57:14 +0000887/*
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000888 * All memory between (char *)areabot and (char *)(areatop+1) is
889 * exclusively administered by the area management routines.
890 * It is assumed that sbrk() and brk() manipulate the high end.
Eric Andersenff9eee42001-06-29 04:57:14 +0000891 */
892
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000893#define sbrk(X) ({ \
894 void * __q = (void *)-1; \
895 if (brkaddr + (int)(X) < brktop) { \
896 __q = brkaddr; \
897 brkaddr += (int)(X); \
898 } \
899 __q; \
900})
Eric Andersenff9eee42001-06-29 04:57:14 +0000901
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000902static void initarea(void)
Eric Andersenff9eee42001-06-29 04:57:14 +0000903{
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000904 brkaddr = xmalloc(AREASIZE);
905 brktop = brkaddr + AREASIZE;
Eric Andersenff9eee42001-06-29 04:57:14 +0000906
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000907 while ((long) sbrk(0) & ALIGN)
908 sbrk(1);
909 areabot = (struct region *) sbrk(REGSIZE);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +0000910
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000911 areabot->next = areabot;
912 areabot->area = BUSY;
913 areatop = areabot;
914 areanxt = areabot;
Eric Andersenff9eee42001-06-29 04:57:14 +0000915}
916
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000917static char *getcell(unsigned nbytes)
918{
919 int nregio;
920 struct region *p, *q;
921 int i;
922
923 if (nbytes == 0) {
924 puts("getcell(0)");
925 abort();
926 }
927 /* silly and defeats the algorithm */
928 /*
929 * round upwards and add administration area
930 */
931 nregio = (nbytes + (REGSIZE - 1)) / REGSIZE + 1;
932 p = areanxt;
933 for (;;) {
934 if (p->area > areanum) {
935 /*
936 * merge free cells
937 */
938 while ((q = p->next)->area > areanum && q != areanxt)
939 p->next = q->next;
940 /*
941 * exit loop if cell big enough
942 */
943 if (q >= p + nregio)
944 goto found;
945 }
946 p = p->next;
947 if (p == areanxt)
948 break;
949 }
950 i = nregio >= GROWBY ? nregio : GROWBY;
951 p = (struct region *) sbrk(i * REGSIZE);
952 if (p == (struct region *) -1)
953 return NULL;
954 p--;
955 if (p != areatop) {
956 puts("not contig");
957 abort(); /* allocated areas are contiguous */
958 }
959 q = p + i;
960 p->next = q;
961 p->area = FREE;
962 q->next = areabot;
963 q->area = BUSY;
964 areatop = q;
965 found:
966 /*
967 * we found a FREE area big enough, pointed to by 'p', and up to 'q'
968 */
969 areanxt = p + nregio;
970 if (areanxt < q) {
971 /*
972 * split into requested area and rest
973 */
974 if (areanxt + 1 > q) {
975 puts("OOM");
976 abort(); /* insufficient space left for admin */
977 }
978 areanxt->next = q;
979 areanxt->area = FREE;
980 p->next = areanxt;
981 }
982 p->area = areanum;
983 return (char *) (p + 1);
984}
985
986static void freecell(char *cp)
987{
988 struct region *p;
989
990 p = (struct region *) cp;
991 if (p != NULL) {
992 p--;
993 if (p < areanxt)
994 areanxt = p;
995 p->area = FREE;
996 }
997}
998#define DELETE(obj) freecell((char *)obj)
999
1000static void freearea(int a)
1001{
1002 struct region *p, *top;
1003
1004 top = areatop;
1005 for (p = areabot; p != top; p = p->next)
1006 if (p->area >= a)
1007 p->area = FREE;
1008}
1009
1010static void setarea(char *cp, int a)
1011{
1012 struct region *p;
1013
1014 p = (struct region *) cp;
1015 if (p != NULL)
1016 (p - 1)->area = a;
1017}
1018
1019static int getarea(char *cp)
1020{
1021 return ((struct region *) cp - 1)->area;
1022}
1023
1024static void garbage(void)
1025{
1026 struct region *p, *q, *top;
1027
1028 top = areatop;
1029 for (p = areabot; p != top; p = p->next) {
1030 if (p->area > areanum) {
1031 while ((q = p->next)->area > areanum)
1032 p->next = q->next;
1033 areanxt = p;
1034 }
1035 }
1036#ifdef SHRINKBY
1037 if (areatop >= q + SHRINKBY && q->area > areanum) {
1038 brk((char *) (q + 1));
1039 q->next = areabot;
1040 q->area = BUSY;
1041 areatop = q;
1042 }
1043#endif
1044}
1045
1046static char *space(int n)
1047{
1048 char *cp;
1049
1050 cp = getcell(n);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001051 if (cp == NULL)
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001052 err("out of string space");
1053 return cp;
1054}
1055
1056static char *strsave(const char *s, int a)
1057{
1058 char *cp;
1059
1060 cp = space(strlen(s) + 1);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001061 if (cp == NULL) {
1062// FIXME: I highly doubt this is good.
1063 return (char*)"";
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001064 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001065 setarea(cp, a);
1066 strcpy(cp, s);
1067 return cp;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001068}
1069
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001070
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001071/* -------- var.c -------- */
1072
1073static int eqname(const char *n1, const char *n2)
1074{
1075 for (; *n1 != '=' && *n1 != '\0'; n1++)
1076 if (*n2++ != *n1)
1077 return 0;
1078 return *n2 == '\0' || *n2 == '=';
1079}
1080
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001081static const char *findeq(const char *cp)
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001082{
1083 while (*cp != '\0' && *cp != '=')
1084 cp++;
1085 return cp;
1086}
1087
1088/*
1089 * Find the given name in the dictionary
1090 * and return its value. If the name was
1091 * not previously there, enter it now and
1092 * return a null value.
1093 */
1094static struct var *lookup(const char *n)
1095{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001096// FIXME: dirty hack
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001097 static struct var dummy;
1098
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001099 struct var *vp;
1100 const char *cp;
1101 char *xp;
1102 int c;
1103
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001104 if (isdigit(*n)) {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001105 dummy.name = (char*)n;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001106 for (c = 0; isdigit(*n) && c < 1000; n++)
1107 c = c * 10 + *n - '0';
1108 dummy.status = RONLY;
1109 dummy.value = (c <= dolc ? dolv[c] : null);
1110 return &dummy;
1111 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001112
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001113 for (vp = vlist; vp; vp = vp->next)
1114 if (eqname(vp->name, n))
1115 return vp;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001116
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001117 cp = findeq(n);
1118 vp = (struct var *) space(sizeof(*vp));
1119 if (vp == 0 || (vp->name = space((int) (cp - n) + 2)) == 0) {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001120 dummy.name = dummy.value = (char*)"";
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001121 return &dummy;
1122 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001123
1124 xp = vp->name;
1125 while ((*xp = *n++) != '\0' && *xp != '=')
1126 xp++;
1127 *xp++ = '=';
1128 *xp = '\0';
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001129 setarea((char *) vp, 0);
1130 setarea((char *) vp->name, 0);
1131 vp->value = null;
1132 vp->next = vlist;
1133 vp->status = GETCELL;
1134 vlist = vp;
1135 return vp;
1136}
1137
1138/*
1139 * if name is not NULL, it must be
1140 * a prefix of the space `val',
1141 * and end with `='.
1142 * this is all so that exporting
1143 * values is reasonably painless.
1144 */
1145static void nameval(struct var *vp, const char *val, const char *name)
1146{
1147 const char *cp;
1148 char *xp;
1149 int fl;
1150
1151 if (vp->status & RONLY) {
1152 xp = vp->name;
1153 while (*xp && *xp != '=')
1154 putc(*xp++, stderr);
1155 err(" is read-only");
1156 return;
1157 }
1158 fl = 0;
1159 if (name == NULL) {
1160 xp = space(strlen(vp->name) + strlen(val) + 2);
1161 if (xp == NULL)
1162 return;
1163 /* make string: name=value */
1164 setarea(xp, 0);
1165 name = xp;
1166 cp = vp->name;
1167 while ((*xp = *cp++) != '\0' && *xp != '=')
1168 xp++;
1169 *xp++ = '=';
1170 strcpy(xp, val);
1171 val = xp;
1172 fl = GETCELL;
1173 }
1174 if (vp->status & GETCELL)
1175 freecell(vp->name); /* form new string `name=value' */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001176 vp->name = (char*)name;
1177 vp->value = (char*)val;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001178 vp->status |= fl;
1179}
1180
1181/*
1182 * give variable at `vp' the value `val'.
1183 */
1184static void setval(struct var *vp, const char *val)
1185{
1186 nameval(vp, val, NULL);
1187}
1188
1189static void export(struct var *vp)
1190{
1191 vp->status |= EXPORT;
1192}
1193
1194static void ronly(struct var *vp)
1195{
1196 if (isalpha(vp->name[0]) || vp->name[0] == '_') /* not an internal symbol */
1197 vp->status |= RONLY;
1198}
1199
1200static int isassign(const char *s)
1201{
1202 unsigned char c;
1203 DBGPRINTF7(("ISASSIGN: enter, s=%s\n", s));
1204
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001205 c = *s;
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001206 /* no isalpha() - we shouldn't use locale */
1207 /* c | 0x20 - lowercase (Latin) letters */
1208 if (c != '_' && (unsigned)((c|0x20) - 'a') > 25)
1209 /* not letter */
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001210 return 0;
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001211
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001212 while (1) {
1213 c = *++s;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001214 if (c == '=')
1215 return 1;
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001216 if (c == '\0')
1217 return 0;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001218 if (c != '_'
1219 && (unsigned)(c - '0') > 9 /* not number */
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001220 && (unsigned)((c|0x20) - 'a') > 25 /* not letter */
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001221 ) {
1222 return 0;
1223 }
1224 }
1225}
1226
1227static int assign(const char *s, int cf)
1228{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001229 const char *cp;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001230 struct var *vp;
1231
1232 DBGPRINTF7(("ASSIGN: enter, s=%s, cf=%d\n", s, cf));
1233
1234 if (!isalpha(*s) && *s != '_')
1235 return 0;
1236 for (cp = s; *cp != '='; cp++)
1237 if (*cp == '\0' || (!isalnum(*cp) && *cp != '_'))
1238 return 0;
1239 vp = lookup(s);
1240 nameval(vp, ++cp, cf == COPYV ? NULL : s);
1241 if (cf != COPYV)
1242 vp->status &= ~GETCELL;
1243 return 1;
1244}
1245
1246static int checkname(char *cp)
1247{
1248 DBGPRINTF7(("CHECKNAME: enter, cp=%s\n", cp));
1249
1250 if (!isalpha(*cp++) && *(cp - 1) != '_')
1251 return 0;
1252 while (*cp)
1253 if (!isalnum(*cp++) && *(cp - 1) != '_')
1254 return 0;
1255 return 1;
1256}
1257
1258static void putvlist(int f, int out)
1259{
1260 struct var *vp;
1261
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001262 for (vp = vlist; vp; vp = vp->next) {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001263 if (vp->status & f && (isalpha(*vp->name) || *vp->name == '_')) {
1264 if (vp->status & EXPORT)
1265 write(out, "export ", 7);
1266 if (vp->status & RONLY)
1267 write(out, "readonly ", 9);
1268 write(out, vp->name, (int) (findeq(vp->name) - vp->name));
1269 write(out, "\n", 1);
1270 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001271 }
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001272}
1273
1274
1275/*
1276 * trap handling
1277 */
1278static void sig(int i)
1279{
1280 trapset = i;
1281 signal(i, sig);
1282}
1283
1284static void runtrap(int i)
1285{
1286 char *trapstr;
1287
1288 trapstr = trap[i];
1289 if (trapstr == NULL)
1290 return;
1291
1292 if (i == 0)
1293 trap[i] = NULL;
1294
1295 RUN(aword, trapstr, nlchar);
1296}
1297
1298
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001299static void setdash(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001300{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001301 char *cp;
1302 int c;
Eric Andersen8401eea2004-08-04 19:16:54 +00001303 char m['z' - 'a' + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00001304
1305 cp = m;
Eric Andersen8401eea2004-08-04 19:16:54 +00001306 for (c = 'a'; c <= 'z'; c++)
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001307 if (flag[c])
Eric Andersenff9eee42001-06-29 04:57:14 +00001308 *cp++ = c;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001309 *cp = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00001310 setval(lookup("-"), m);
1311}
1312
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001313static int newfile(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00001314{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001315 int f;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001316
1317 DBGPRINTF7(("NEWFILE: opening %s\n", s));
Eric Andersenff9eee42001-06-29 04:57:14 +00001318
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001319 f = 0;
Denis Vlasenko9f739442006-12-16 23:49:13 +00001320 if (NOT_LONE_DASH(s)) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001321 DBGPRINTF(("NEWFILE: s is %s\n", s));
Eric Andersenff9eee42001-06-29 04:57:14 +00001322 f = open(s, 0);
1323 if (f < 0) {
1324 prs(s);
1325 err(": cannot open");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001326 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001327 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001328 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001329
Eric Andersenff9eee42001-06-29 04:57:14 +00001330 next(remap(f));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001331 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001332}
1333
Eric Andersen12de6cf2004-08-04 19:19:10 +00001334
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001335struct op *scantree(struct op *head)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001336{
1337 struct op *dotnode;
1338
1339 if (head == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001340 return NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001341
1342 if (head->left != NULL) {
1343 dotnode = scantree(head->left);
1344 if (dotnode)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001345 return dotnode;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001346 }
1347
1348 if (head->right != NULL) {
1349 dotnode = scantree(head->right);
1350 if (dotnode)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001351 return dotnode;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001352 }
1353
1354 if (head->words == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001355 return NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001356
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001357 DBGPRINTF5(("SCANTREE: checking node %p\n", head));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001358
Denis Vlasenkocf787cf2007-02-04 17:11:25 +00001359 if ((head->type != TDOT) && LONE_CHAR(head->words[0], '.')) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001360 DBGPRINTF5(("SCANTREE: dot found in node %p\n", head));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001361 return head;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001362 }
1363
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001364 return NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001365}
1366
1367
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001368static void onecommand(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001369{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001370 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00001371 jmp_buf m1;
1372
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001373 DBGPRINTF(("ONECOMMAND: enter, outtree=%p\n", outtree));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001374
Eric Andersenff9eee42001-06-29 04:57:14 +00001375 while (e.oenv)
1376 quitenv();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001377
Eric Andersenff9eee42001-06-29 04:57:14 +00001378 areanum = 1;
1379 freehere(areanum);
1380 freearea(areanum);
1381 garbage();
1382 wdlist = 0;
1383 iolist = 0;
1384 e.errpt = 0;
1385 e.linep = line;
1386 yynerrs = 0;
1387 multiline = 0;
1388 inparse = 1;
1389 intr = 0;
1390 execflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001391
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001392 failpt = m1;
1393 setjmp(failpt); /* Bruce Evans' fix */
1394 failpt = m1;
1395 if (setjmp(failpt) || yyparse() || intr) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001396 DBGPRINTF(("ONECOMMAND: this is not good.\n"));
1397
Eric Andersenff9eee42001-06-29 04:57:14 +00001398 while (e.oenv)
1399 quitenv();
1400 scraphere();
1401 if (!interactive && intr)
1402 leave();
1403 inparse = 0;
1404 intr = 0;
1405 return;
1406 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001407
Eric Andersenff9eee42001-06-29 04:57:14 +00001408 inparse = 0;
1409 brklist = 0;
1410 intr = 0;
1411 execflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001412
1413 if (!flag['n']) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001414 DBGPRINTF(("ONECOMMAND: calling execute, t=outtree=%p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00001415 outtree));
Eric Andersenff9eee42001-06-29 04:57:14 +00001416 execute(outtree, NOPIPE, NOPIPE, 0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001417 }
1418
Eric Andersenff9eee42001-06-29 04:57:14 +00001419 if (!interactive && intr) {
1420 execflg = 0;
1421 leave();
1422 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001423
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001424 i = trapset;
1425 if (i != 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001426 trapset = 0;
1427 runtrap(i);
1428 }
1429}
1430
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001431static int newenv(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00001432{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001433 struct env *ep;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001434
1435 DBGPRINTF(("NEWENV: f=%d (indicates quitenv and return)\n", f));
Eric Andersenff9eee42001-06-29 04:57:14 +00001436
1437 if (f) {
1438 quitenv();
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001439 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001440 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001441
Eric Andersenff9eee42001-06-29 04:57:14 +00001442 ep = (struct env *) space(sizeof(*ep));
1443 if (ep == NULL) {
1444 while (e.oenv)
1445 quitenv();
1446 fail();
1447 }
1448 *ep = e;
1449 e.oenv = ep;
1450 e.errpt = errpt;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001451
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001452 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001453}
1454
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001455static void quitenv(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001456{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001457 struct env *ep;
1458 int fd;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001459
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001460 DBGPRINTF(("QUITENV: e.oenv=%p\n", e.oenv));
Eric Andersenff9eee42001-06-29 04:57:14 +00001461
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001462 ep = e.oenv;
1463 if (ep != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001464 fd = e.iofd;
1465 e = *ep;
1466 /* should close `'d files */
1467 DELETE(ep);
1468 while (--fd >= e.iofd)
1469 close(fd);
1470 }
1471}
1472
1473/*
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001474 * Is character c in s?
Eric Andersenff9eee42001-06-29 04:57:14 +00001475 */
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001476static int any(int c, const char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00001477{
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001478 while (*s)
1479 if (*s++ == c)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001480 return 1;
1481 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001482}
1483
1484/*
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001485 * Is any character from s1 in s2?
Eric Andersenff9eee42001-06-29 04:57:14 +00001486 */
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001487static int anys(const char *s1, const char *s2)
Eric Andersenff9eee42001-06-29 04:57:14 +00001488{
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001489 while (*s1)
1490 if (any(*s1++, s2))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001491 return 1;
1492 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001493}
1494
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001495static char *putn(int n)
Eric Andersenff9eee42001-06-29 04:57:14 +00001496{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001497 return itoa(n);
Eric Andersenff9eee42001-06-29 04:57:14 +00001498}
1499
Eric Andersen8401eea2004-08-04 19:16:54 +00001500static void next(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00001501{
1502 PUSHIO(afile, f, filechar);
1503}
1504
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001505static void onintr(int s) /* ANSI C requires a parameter */
Eric Andersenff9eee42001-06-29 04:57:14 +00001506{
1507 signal(SIGINT, onintr);
1508 intr = 1;
1509 if (interactive) {
1510 if (inparse) {
1511 prs("\n");
1512 fail();
1513 }
Eric Andersen8401eea2004-08-04 19:16:54 +00001514 } else if (heedint) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001515 execflg = 0;
1516 leave();
1517 }
1518}
1519
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001520
Eric Andersenff9eee42001-06-29 04:57:14 +00001521/* -------- gmatch.c -------- */
1522/*
1523 * int gmatch(string, pattern)
1524 * char *string, *pattern;
1525 *
1526 * Match a pattern as in sh(1).
1527 */
1528
1529#define CMASK 0377
1530#define QUOTE 0200
Denis Vlasenko55f30b02007-03-24 22:42:29 +00001531#define QMASK (CMASK & ~QUOTE)
Eric Andersen8401eea2004-08-04 19:16:54 +00001532#define NOT '!' /* might use ^ */
Eric Andersenff9eee42001-06-29 04:57:14 +00001533
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001534static const char *cclass(const char *p, int sub)
1535{
1536 int c, d, not, found;
1537
1538 not = (*p == NOT);
1539 if (not != 0)
1540 p++;
1541 found = not;
1542 do {
1543 if (*p == '\0')
1544 return NULL;
1545 c = *p & CMASK;
1546 if (p[1] == '-' && p[2] != ']') {
1547 d = p[2] & CMASK;
1548 p++;
1549 } else
1550 d = c;
1551 if (c == sub || (c <= sub && sub <= d))
1552 found = !not;
1553 } while (*++p != ']');
1554 return found ? p + 1 : NULL;
1555}
1556
1557static int gmatch(const char *s, const char *p)
Eric Andersenff9eee42001-06-29 04:57:14 +00001558{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001559 int sc, pc;
Eric Andersenff9eee42001-06-29 04:57:14 +00001560
1561 if (s == NULL || p == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001562 return 0;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001563
Eric Andersenff9eee42001-06-29 04:57:14 +00001564 while ((pc = *p++ & CMASK) != '\0') {
1565 sc = *s++ & QMASK;
1566 switch (pc) {
1567 case '[':
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001568 p = cclass(p, sc);
1569 if (p == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001570 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001571 break;
1572
1573 case '?':
1574 if (sc == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001575 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001576 break;
1577
1578 case '*':
1579 s--;
1580 do {
1581 if (*p == '\0' || gmatch(s, p))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001582 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001583 } while (*s++ != '\0');
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001584 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001585
1586 default:
Eric Andersen8401eea2004-08-04 19:16:54 +00001587 if (sc != (pc & ~QUOTE))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001588 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001589 }
1590 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001591 return *s == '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00001592}
1593
Eric Andersenff9eee42001-06-29 04:57:14 +00001594
Eric Andersenff9eee42001-06-29 04:57:14 +00001595/* -------- csyn.c -------- */
1596/*
1597 * shell: syntax (C version)
1598 */
1599
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001600static void yyerror(const char *s) ATTRIBUTE_NORETURN;
1601static void yyerror(const char *s)
1602{
1603 yynerrs++;
1604 if (interactive && e.iop <= iostack) {
1605 multiline = 0;
1606 while (eofc() == 0 && yylex(0) != '\n');
1607 }
1608 err(s);
1609 fail();
1610}
1611
1612static void zzerr(void) ATTRIBUTE_NORETURN;
1613static void zzerr(void)
1614{
1615 yyerror("syntax error");
1616}
1617
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001618int yyparse(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001619{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001620 DBGPRINTF7(("YYPARSE: enter...\n"));
1621
Eric Andersen8401eea2004-08-04 19:16:54 +00001622 startl = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001623 peeksym = 0;
1624 yynerrs = 0;
1625 outtree = c_list();
1626 musthave('\n', 0);
Eric Andersen8401eea2004-08-04 19:16:54 +00001627 return (yynerrs != 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001628}
1629
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001630static struct op *pipeline(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001631{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001632 struct op *t, *p;
1633 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001634
1635 DBGPRINTF7(("PIPELINE: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001636
1637 t = command(cf);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001638
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001639 DBGPRINTF9(("PIPELINE: t=%p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001640
Eric Andersenff9eee42001-06-29 04:57:14 +00001641 if (t != NULL) {
1642 while ((c = yylex(0)) == '|') {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001643 p = command(CONTIN);
1644 if (p == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001645 DBGPRINTF8(("PIPELINE: error!\n"));
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001646 zzerr();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001647 }
1648
Eric Andersenff9eee42001-06-29 04:57:14 +00001649 if (t->type != TPAREN && t->type != TCOM) {
1650 /* shell statement */
1651 t = block(TPAREN, t, NOBLOCK, NOWORDS);
1652 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001653
Eric Andersenff9eee42001-06-29 04:57:14 +00001654 t = block(TPIPE, t, p, NOWORDS);
1655 }
1656 peeksym = c;
1657 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001658
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001659 DBGPRINTF7(("PIPELINE: returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001660 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001661}
1662
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001663static struct op *andor(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001664{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001665 struct op *t, *p;
1666 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001667
1668 DBGPRINTF7(("ANDOR: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001669
1670 t = pipeline(0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001671
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001672 DBGPRINTF9(("ANDOR: t=%p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001673
Eric Andersenff9eee42001-06-29 04:57:14 +00001674 if (t != NULL) {
1675 while ((c = yylex(0)) == LOGAND || c == LOGOR) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001676 p = pipeline(CONTIN);
1677 if (p == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001678 DBGPRINTF8(("ANDOR: error!\n"));
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001679 zzerr();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001680 }
1681
Eric Andersen8401eea2004-08-04 19:16:54 +00001682 t = block(c == LOGAND ? TAND : TOR, t, p, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001683 } /* WHILE */
1684
Eric Andersenff9eee42001-06-29 04:57:14 +00001685 peeksym = c;
1686 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001687
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001688 DBGPRINTF7(("ANDOR: returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001689 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001690}
1691
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001692static struct op *c_list(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001693{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001694 struct op *t, *p;
1695 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001696
1697 DBGPRINTF7(("C_LIST: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001698
1699 t = andor();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001700
Eric Andersenff9eee42001-06-29 04:57:14 +00001701 if (t != NULL) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001702 peeksym = yylex(0);
1703 if (peeksym == '&')
Eric Andersenff9eee42001-06-29 04:57:14 +00001704 t = block(TASYNC, t, NOBLOCK, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001705
Eric Andersen8401eea2004-08-04 19:16:54 +00001706 while ((c = yylex(0)) == ';' || c == '&'
1707 || (multiline && c == '\n')) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001708
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001709 p = andor();
1710 if (p== NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001711 return t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001712
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001713 peeksym = yylex(0);
1714 if (peeksym == '&')
Eric Andersenff9eee42001-06-29 04:57:14 +00001715 p = block(TASYNC, p, NOBLOCK, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001716
Eric Andersenff9eee42001-06-29 04:57:14 +00001717 t = list(t, p);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001718 } /* WHILE */
1719
Eric Andersenff9eee42001-06-29 04:57:14 +00001720 peeksym = c;
1721 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001722 /* IF */
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001723 DBGPRINTF7(("C_LIST: returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001724 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001725}
1726
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001727static int synio(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001728{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001729 struct ioword *iop;
1730 int i;
1731 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001732
1733 DBGPRINTF7(("SYNIO: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001734
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001735 c = yylex(cf);
1736 if (c != '<' && c != '>') {
Eric Andersenff9eee42001-06-29 04:57:14 +00001737 peeksym = c;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001738 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001739 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001740
Eric Andersenff9eee42001-06-29 04:57:14 +00001741 i = yylval.i;
1742 musthave(WORD, 0);
1743 iop = io(iounit, i, yylval.cp);
1744 iounit = IODEFAULT;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001745
Eric Andersenff9eee42001-06-29 04:57:14 +00001746 if (i & IOHERE)
1747 markhere(yylval.cp, iop);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001748
1749 DBGPRINTF7(("SYNIO: returning 1\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001750 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001751}
1752
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001753static void musthave(int c, int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001754{
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001755 peeksym = yylex(cf);
1756 if (peeksym != c) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001757 DBGPRINTF7(("MUSTHAVE: error!\n"));
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001758 zzerr();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001759 }
1760
Eric Andersenff9eee42001-06-29 04:57:14 +00001761 peeksym = 0;
1762}
1763
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001764static struct op *simple(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001765{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001766 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001767
1768 t = NULL;
1769 for (;;) {
1770 switch (peeksym = yylex(0)) {
1771 case '<':
1772 case '>':
1773 (void) synio(0);
1774 break;
1775
1776 case WORD:
1777 if (t == NULL) {
1778 t = newtp();
1779 t->type = TCOM;
1780 }
1781 peeksym = 0;
1782 word(yylval.cp);
1783 break;
1784
1785 default:
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001786 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001787 }
1788 }
1789}
1790
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001791static struct op *nested(int type, int mark)
Eric Andersenff9eee42001-06-29 04:57:14 +00001792{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001793 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001794
1795 DBGPRINTF3(("NESTED: enter, type=%d, mark=%d\n", type, mark));
Eric Andersenff9eee42001-06-29 04:57:14 +00001796
1797 multiline++;
1798 t = c_list();
1799 musthave(mark, 0);
1800 multiline--;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001801 return block(type, t, NOBLOCK, NOWORDS);
Eric Andersenff9eee42001-06-29 04:57:14 +00001802}
1803
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001804static struct op *command(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001805{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001806 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001807 struct wdblock *iosave;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001808 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001809
1810 DBGPRINTF(("COMMAND: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001811
1812 iosave = iolist;
1813 iolist = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001814
Eric Andersenff9eee42001-06-29 04:57:14 +00001815 if (multiline)
1816 cf |= CONTIN;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001817
Eric Andersenff9eee42001-06-29 04:57:14 +00001818 while (synio(cf))
1819 cf = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001820
1821 c = yylex(cf);
1822
1823 switch (c) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001824 default:
1825 peeksym = c;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001826 t = simple();
1827 if (t == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001828 if (iolist == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001829 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001830 t = newtp();
1831 t->type = TCOM;
1832 }
1833 break;
1834
1835 case '(':
1836 t = nested(TPAREN, ')');
1837 break;
1838
1839 case '{':
1840 t = nested(TBRACE, '}');
1841 break;
1842
1843 case FOR:
1844 t = newtp();
1845 t->type = TFOR;
1846 musthave(WORD, 0);
1847 startl = 1;
1848 t->str = yylval.cp;
1849 multiline++;
1850 t->words = wordlist();
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001851 c = yylex(0);
1852 if (c != '\n' && c != ';')
Eric Andersenff9eee42001-06-29 04:57:14 +00001853 peeksym = c;
1854 t->left = dogroup(0);
1855 multiline--;
1856 break;
1857
1858 case WHILE:
1859 case UNTIL:
1860 multiline++;
1861 t = newtp();
Eric Andersen8401eea2004-08-04 19:16:54 +00001862 t->type = c == WHILE ? TWHILE : TUNTIL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001863 t->left = c_list();
1864 t->right = dogroup(1);
1865 t->words = NULL;
1866 multiline--;
1867 break;
1868
1869 case CASE:
1870 t = newtp();
1871 t->type = TCASE;
1872 musthave(WORD, 0);
1873 t->str = yylval.cp;
1874 startl++;
1875 multiline++;
1876 musthave(IN, CONTIN);
1877 startl++;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001878
Eric Andersenff9eee42001-06-29 04:57:14 +00001879 t->left = caselist();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001880
Eric Andersenff9eee42001-06-29 04:57:14 +00001881 musthave(ESAC, 0);
1882 multiline--;
1883 break;
1884
1885 case IF:
1886 multiline++;
1887 t = newtp();
1888 t->type = TIF;
1889 t->left = c_list();
1890 t->right = thenpart();
1891 musthave(FI, 0);
1892 multiline--;
1893 break;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001894
1895 case DOT:
1896 t = newtp();
1897 t->type = TDOT;
1898
1899 musthave(WORD, 0); /* gets name of file */
1900 DBGPRINTF7(("COMMAND: DOT clause, yylval.cp is %s\n", yylval.cp));
1901
1902 word(yylval.cp); /* add word to wdlist */
1903 word(NOWORD); /* terminate wdlist */
1904 t->words = copyw(); /* dup wdlist */
1905 break;
1906
Eric Andersenff9eee42001-06-29 04:57:14 +00001907 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001908
Eric Andersen8401eea2004-08-04 19:16:54 +00001909 while (synio(0));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001910
Eric Andersenff9eee42001-06-29 04:57:14 +00001911 t = namelist(t);
1912 iolist = iosave;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001913
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001914 DBGPRINTF(("COMMAND: returning %p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001915
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001916 return t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001917}
1918
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001919static struct op *dowholefile(int type, int mark)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001920{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001921 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001922
1923 DBGPRINTF(("DOWHOLEFILE: enter, type=%d, mark=%d\n", type, mark));
1924
1925 multiline++;
1926 t = c_list();
1927 multiline--;
1928 t = block(type, t, NOBLOCK, NOWORDS);
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001929 DBGPRINTF(("DOWHOLEFILE: return t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001930 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001931}
1932
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001933static struct op *dogroup(int onlydone)
Eric Andersenff9eee42001-06-29 04:57:14 +00001934{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001935 int c;
1936 struct op *mylist;
Eric Andersenff9eee42001-06-29 04:57:14 +00001937
1938 c = yylex(CONTIN);
1939 if (c == DONE && onlydone)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001940 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001941 if (c != DO)
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001942 zzerr();
Eric Andersenff9eee42001-06-29 04:57:14 +00001943 mylist = c_list();
1944 musthave(DONE, 0);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001945 return mylist;
Eric Andersenff9eee42001-06-29 04:57:14 +00001946}
1947
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001948static struct op *thenpart(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001949{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001950 int c;
1951 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001952
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001953 c = yylex(0);
1954 if (c != THEN) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001955 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001956 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001957 }
1958 t = newtp();
1959 t->type = 0;
1960 t->left = c_list();
1961 if (t->left == NULL)
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001962 zzerr();
Eric Andersenff9eee42001-06-29 04:57:14 +00001963 t->right = elsepart();
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001964 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001965}
1966
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001967static struct op *elsepart(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001968{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001969 int c;
1970 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001971
1972 switch (c = yylex(0)) {
1973 case ELSE:
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001974 t = c_list();
1975 if (t == NULL)
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001976 zzerr();
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001977 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001978
1979 case ELIF:
1980 t = newtp();
1981 t->type = TELIF;
1982 t->left = c_list();
1983 t->right = thenpart();
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001984 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001985
1986 default:
1987 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001988 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001989 }
1990}
1991
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001992static struct op *caselist(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001993{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001994 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001995
1996 t = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001997 while ((peeksym = yylex(CONTIN)) != ESAC) {
1998 DBGPRINTF(("CASELIST, doing yylex, peeksym=%d\n", peeksym));
Eric Andersenff9eee42001-06-29 04:57:14 +00001999 t = list(t, casepart());
Eric Andersen12de6cf2004-08-04 19:19:10 +00002000 }
2001
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002002 DBGPRINTF(("CASELIST, returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002003 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002004}
2005
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002006static struct op *casepart(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002007{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002008 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002009
2010 DBGPRINTF7(("CASEPART: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00002011
2012 t = newtp();
2013 t->type = TPAT;
2014 t->words = pattern();
2015 musthave(')', 0);
2016 t->left = c_list();
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002017 peeksym = yylex(CONTIN);
2018 if (peeksym != ESAC)
Eric Andersenff9eee42001-06-29 04:57:14 +00002019 musthave(BREAK, CONTIN);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002020
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002021 DBGPRINTF7(("CASEPART: made newtp(TPAT, t=%p)\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002022
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002023 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002024}
2025
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002026static char **pattern(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002027{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002028 int c, cf;
Eric Andersenff9eee42001-06-29 04:57:14 +00002029
2030 cf = CONTIN;
2031 do {
2032 musthave(WORD, cf);
2033 word(yylval.cp);
2034 cf = 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002035 c = yylex(0);
2036 } while (c == '|');
Eric Andersenff9eee42001-06-29 04:57:14 +00002037 peeksym = c;
2038 word(NOWORD);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002039
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002040 return copyw();
Eric Andersenff9eee42001-06-29 04:57:14 +00002041}
2042
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002043static char **wordlist(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002044{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002045 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002046
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002047 c = yylex(0);
2048 if (c != IN) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002049 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002050 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00002051 }
2052 startl = 0;
2053 while ((c = yylex(0)) == WORD)
2054 word(yylval.cp);
2055 word(NOWORD);
2056 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002057 return copyw();
Eric Andersenff9eee42001-06-29 04:57:14 +00002058}
2059
2060/*
2061 * supporting functions
2062 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002063static struct op *list(struct op *t1, struct op *t2)
Eric Andersenff9eee42001-06-29 04:57:14 +00002064{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002065 DBGPRINTF7(("LIST: enter, t1=%p, t2=%p\n", t1, t2));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002066
Eric Andersenff9eee42001-06-29 04:57:14 +00002067 if (t1 == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002068 return t2;
Eric Andersenff9eee42001-06-29 04:57:14 +00002069 if (t2 == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002070 return t1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002071
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002072 return block(TLIST, t1, t2, NOWORDS);
Eric Andersenff9eee42001-06-29 04:57:14 +00002073}
2074
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002075static struct op *block(int type, struct op *t1, struct op *t2, char **wp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002076{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002077 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002078
2079 DBGPRINTF7(("BLOCK: enter, type=%d (%s)\n", type, T_CMD_NAMES[type]));
Eric Andersenff9eee42001-06-29 04:57:14 +00002080
2081 t = newtp();
2082 t->type = type;
2083 t->left = t1;
2084 t->right = t2;
2085 t->words = wp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002086
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002087 DBGPRINTF7(("BLOCK: inserted %p between %p and %p\n", t, t1,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002088 t2));
2089
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002090 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002091}
2092
Eric Andersen12de6cf2004-08-04 19:19:10 +00002093/* See if given string is a shell multiline (FOR, IF, etc) */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002094static int rlookup(char *n)
Eric Andersenff9eee42001-06-29 04:57:14 +00002095{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002096 const struct res *rp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002097
2098 DBGPRINTF7(("RLOOKUP: enter, n is %s\n", n));
Eric Andersenff9eee42001-06-29 04:57:14 +00002099
2100 for (rp = restab; rp->r_name; rp++)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002101 if (strcmp(rp->r_name, n) == 0) {
2102 DBGPRINTF7(("RLOOKUP: match, returning %d\n", rp->r_val));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002103 return rp->r_val; /* Return numeric code for shell multiline */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002104 }
2105
2106 DBGPRINTF7(("RLOOKUP: NO match, returning 0\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002107 return 0; /* Not a shell multiline */
Eric Andersenff9eee42001-06-29 04:57:14 +00002108}
2109
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002110static struct op *newtp(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002111{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002112 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002113
Eric Andersen8401eea2004-08-04 19:16:54 +00002114 t = (struct op *) tree(sizeof(*t));
Eric Andersenff9eee42001-06-29 04:57:14 +00002115 t->type = 0;
2116 t->words = NULL;
2117 t->ioact = NULL;
2118 t->left = NULL;
2119 t->right = NULL;
2120 t->str = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002121
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002122 DBGPRINTF3(("NEWTP: allocated %p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002123
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002124 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002125}
2126
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002127static struct op *namelist(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00002128{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002129
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002130 DBGPRINTF7(("NAMELIST: enter, t=%p, type %s, iolist=%p\n", t,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002131 T_CMD_NAMES[t->type], iolist));
2132
Eric Andersenff9eee42001-06-29 04:57:14 +00002133 if (iolist) {
Eric Andersen8401eea2004-08-04 19:16:54 +00002134 iolist = addword((char *) NULL, iolist);
Eric Andersenff9eee42001-06-29 04:57:14 +00002135 t->ioact = copyio();
2136 } else
2137 t->ioact = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002138
Eric Andersenff9eee42001-06-29 04:57:14 +00002139 if (t->type != TCOM) {
2140 if (t->type != TPAREN && t->ioact != NULL) {
2141 t = block(TPAREN, t, NOBLOCK, NOWORDS);
2142 t->ioact = t->left->ioact;
2143 t->left->ioact = NULL;
2144 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002145 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002146 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002147
Eric Andersenff9eee42001-06-29 04:57:14 +00002148 word(NOWORD);
2149 t->words = copyw();
Eric Andersen12de6cf2004-08-04 19:19:10 +00002150
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002151 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002152}
2153
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002154static char **copyw(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002155{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002156 char **wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00002157
2158 wd = getwords(wdlist);
2159 wdlist = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002160 return wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00002161}
2162
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002163static void word(char *cp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002164{
2165 wdlist = addword(cp, wdlist);
2166}
2167
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002168static struct ioword **copyio(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002169{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002170 struct ioword **iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002171
2172 iop = (struct ioword **) getwords(iolist);
2173 iolist = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002174 return iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002175}
2176
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002177static struct ioword *io(int u, int f, char *cp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002178{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002179 struct ioword *iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002180
2181 iop = (struct ioword *) tree(sizeof(*iop));
2182 iop->io_unit = u;
2183 iop->io_flag = f;
2184 iop->io_name = cp;
Eric Andersen8401eea2004-08-04 19:16:54 +00002185 iolist = addword((char *) iop, iolist);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002186 return iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002187}
2188
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002189static int yylex(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00002190{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002191 int c, c1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002192 int atstart;
2193
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002194 c = peeksym;
2195 if (c > 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002196 peeksym = 0;
2197 if (c == '\n')
2198 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002199 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002200 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002201
Eric Andersenff9eee42001-06-29 04:57:14 +00002202 nlseen = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002203 atstart = startl;
2204 startl = 0;
2205 yylval.i = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002206 e.linep = line;
2207
2208/* MALAMO */
2209 line[LINELIM - 1] = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00002210
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002211 loop:
Eric Andersen12de6cf2004-08-04 19:19:10 +00002212 while ((c = my_getc(0)) == ' ' || c == '\t') /* Skip whitespace */
2213 ;
2214
Eric Andersenff9eee42001-06-29 04:57:14 +00002215 switch (c) {
2216 default:
2217 if (any(c, "0123456789")) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002218 c1 = my_getc(0);
2219 unget(c1);
Eric Andersenff9eee42001-06-29 04:57:14 +00002220 if (c1 == '<' || c1 == '>') {
2221 iounit = c - '0';
2222 goto loop;
2223 }
2224 *e.linep++ = c;
2225 c = c1;
2226 }
2227 break;
2228
Eric Andersen12de6cf2004-08-04 19:19:10 +00002229 case '#': /* Comment, skip to next newline or End-of-string */
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002230 while ((c = my_getc(0)) != '\0' && c != '\n');
Eric Andersenff9eee42001-06-29 04:57:14 +00002231 unget(c);
2232 goto loop;
2233
2234 case 0:
Eric Andersen12de6cf2004-08-04 19:19:10 +00002235 DBGPRINTF5(("YYLEX: return 0, c=%d\n", c));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002236 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002237
2238 case '$':
Eric Andersen12de6cf2004-08-04 19:19:10 +00002239 DBGPRINTF9(("YYLEX: found $\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00002240 *e.linep++ = c;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002241 c = my_getc(0);
2242 if (c == '{') {
2243 c = collect(c, '}');
2244 if (c != '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002245 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002246 goto pack;
2247 }
2248 break;
2249
2250 case '`':
2251 case '\'':
2252 case '"':
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002253 c = collect(c, c);
2254 if (c != '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002255 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002256 goto pack;
2257
2258 case '|':
2259 case '&':
2260 case ';':
Eric Andersenff9eee42001-06-29 04:57:14 +00002261 startl = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002262 /* If more chars process them, else return NULL char */
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002263 c1 = dual(c);
2264 if (c1 != '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002265 return c1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002266 return c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002267
Eric Andersenff9eee42001-06-29 04:57:14 +00002268 case '^':
2269 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002270 return '|';
Eric Andersenff9eee42001-06-29 04:57:14 +00002271 case '>':
2272 case '<':
2273 diag(c);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002274 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002275
2276 case '\n':
2277 nlseen++;
2278 gethere();
2279 startl = 1;
2280 if (multiline || cf & CONTIN) {
2281 if (interactive && e.iop <= iostack) {
Denis Vlasenko38f63192007-01-22 09:03:07 +00002282#if ENABLE_FEATURE_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00002283 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00002284#else
Eric Andersen8401eea2004-08-04 19:16:54 +00002285 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00002286#endif
2287 }
2288 if (cf & CONTIN)
2289 goto loop;
2290 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002291 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002292
2293 case '(':
2294 case ')':
2295 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002296 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002297 }
2298
2299 unget(c);
2300
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002301 pack:
2302 while ((c = my_getc(0)) != '\0' && !any(c, "`$ '\"\t;&<>()|^\n")) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002303 if (e.linep >= elinep)
2304 err("word too long");
2305 else
2306 *e.linep++ = c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002307 };
2308
Eric Andersenff9eee42001-06-29 04:57:14 +00002309 unget(c);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002310
Eric Andersen8401eea2004-08-04 19:16:54 +00002311 if (any(c, "\"'`$"))
Eric Andersenff9eee42001-06-29 04:57:14 +00002312 goto loop;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002313
Eric Andersenff9eee42001-06-29 04:57:14 +00002314 *e.linep++ = '\0';
Eric Andersen12de6cf2004-08-04 19:19:10 +00002315
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002316 if (atstart) {
2317 c = rlookup(line);
2318 if (c != 0) {
2319 startl = 1;
2320 return c;
2321 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002322 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002323
Eric Andersenff9eee42001-06-29 04:57:14 +00002324 yylval.cp = strsave(line, areanum);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002325 return WORD;
Eric Andersenff9eee42001-06-29 04:57:14 +00002326}
2327
Eric Andersen12de6cf2004-08-04 19:19:10 +00002328
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002329static int collect(int c, int c1)
Eric Andersenff9eee42001-06-29 04:57:14 +00002330{
2331 char s[2];
2332
Eric Andersen12de6cf2004-08-04 19:19:10 +00002333 DBGPRINTF8(("COLLECT: enter, c=%d, c1=%d\n", c, c1));
2334
Eric Andersenff9eee42001-06-29 04:57:14 +00002335 *e.linep++ = c;
2336 while ((c = my_getc(c1)) != c1) {
2337 if (c == 0) {
2338 unget(c);
2339 s[0] = c1;
2340 s[1] = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00002341 prs("no closing ");
2342 yyerror(s);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002343 return YYERRCODE;
Eric Andersenff9eee42001-06-29 04:57:14 +00002344 }
2345 if (interactive && c == '\n' && e.iop <= iostack) {
Denis Vlasenko38f63192007-01-22 09:03:07 +00002346#if ENABLE_FEATURE_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00002347 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00002348#else
Eric Andersen8401eea2004-08-04 19:16:54 +00002349 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00002350#endif
2351 }
2352 *e.linep++ = c;
2353 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002354
Eric Andersenff9eee42001-06-29 04:57:14 +00002355 *e.linep++ = c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002356
2357 DBGPRINTF8(("COLLECT: return 0, line is %s\n", line));
2358
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002359 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002360}
2361
Eric Andersen12de6cf2004-08-04 19:19:10 +00002362/* "multiline commands" helper func */
2363/* see if next 2 chars form a shell multiline */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002364static int dual(int c)
Eric Andersenff9eee42001-06-29 04:57:14 +00002365{
2366 char s[3];
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002367 char *cp = s;
Eric Andersenff9eee42001-06-29 04:57:14 +00002368
Eric Andersen12de6cf2004-08-04 19:19:10 +00002369 DBGPRINTF8(("DUAL: enter, c=%d\n", c));
2370
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002371 *cp++ = c; /* c is the given "peek" char */
2372 *cp++ = my_getc(0); /* get next char of input */
2373 *cp = '\0'; /* add EOS marker */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002374
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002375 c = rlookup(s); /* see if 2 chars form a shell multiline */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002376 if (c == 0)
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002377 unget(*--cp); /* String is not a shell multiline, put peek char back */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002378
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002379 return c; /* String is multiline, return numeric multiline (restab) code */
Eric Andersenff9eee42001-06-29 04:57:14 +00002380}
2381
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002382static void diag(int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00002383{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002384 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002385
2386 DBGPRINTF8(("DIAG: enter, ec=%d\n", ec));
Eric Andersenff9eee42001-06-29 04:57:14 +00002387
2388 c = my_getc(0);
2389 if (c == '>' || c == '<') {
2390 if (c != ec)
2391 zzerr();
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002392 yylval.i = (ec == '>' ? IOWRITE | IOCAT : IOHERE);
Eric Andersenff9eee42001-06-29 04:57:14 +00002393 c = my_getc(0);
2394 } else
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002395 yylval.i = (ec == '>' ? IOWRITE : IOREAD);
Eric Andersenff9eee42001-06-29 04:57:14 +00002396 if (c != '&' || yylval.i == IOHERE)
2397 unget(c);
2398 else
2399 yylval.i |= IODUP;
2400}
2401
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002402static char *tree(unsigned size)
Eric Andersenff9eee42001-06-29 04:57:14 +00002403{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002404 char *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002405
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002406 t = getcell(size);
2407 if (t == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002408 DBGPRINTF2(("TREE: getcell(%d) failed!\n", size));
Eric Andersenff9eee42001-06-29 04:57:14 +00002409 prs("command line too complicated\n");
2410 fail();
2411 /* NOTREACHED */
2412 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002413 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002414}
2415
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002416
Eric Andersenff9eee42001-06-29 04:57:14 +00002417/* VARARGS1 */
2418/* ARGSUSED */
2419
2420/* -------- exec.c -------- */
2421
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002422static struct op **find1case(struct op *t, const char *w)
2423{
2424 struct op *t1;
2425 struct op **tp;
2426 char **wp;
2427 char *cp;
2428
2429 if (t == NULL) {
2430 DBGPRINTF3(("FIND1CASE: enter, t==NULL, returning.\n"));
2431 return NULL;
2432 }
2433
2434 DBGPRINTF3(("FIND1CASE: enter, t->type=%d (%s)\n", t->type,
2435 T_CMD_NAMES[t->type]));
2436
2437 if (t->type == TLIST) {
2438 tp = find1case(t->left, w);
2439 if (tp != NULL) {
2440 DBGPRINTF3(("FIND1CASE: found one to the left, returning tp=%p\n", tp));
2441 return tp;
2442 }
2443 t1 = t->right; /* TPAT */
2444 } else
2445 t1 = t;
2446
2447 for (wp = t1->words; *wp;) {
2448 cp = evalstr(*wp++, DOSUB);
2449 if (cp && gmatch(w, cp)) {
2450 DBGPRINTF3(("FIND1CASE: returning &t1->left= %p.\n",
2451 &t1->left));
2452 return &t1->left;
2453 }
2454 }
2455
2456 DBGPRINTF(("FIND1CASE: returning NULL\n"));
2457 return NULL;
2458}
2459
2460static struct op *findcase(struct op *t, const char *w)
2461{
2462 struct op **tp;
2463
2464 tp = find1case(t, w);
2465 return tp != NULL ? *tp : NULL;
2466}
2467
Eric Andersenff9eee42001-06-29 04:57:14 +00002468/*
2469 * execute tree
2470 */
2471
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002472static int execute(struct op *t, int *pin, int *pout, int act)
Eric Andersenff9eee42001-06-29 04:57:14 +00002473{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002474 struct op *t1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002475 volatile int i, rv, a;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002476 const char *cp;
2477 char **wp, **wp2;
Eric Andersenff9eee42001-06-29 04:57:14 +00002478 struct var *vp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002479 struct op *outtree_save;
Eric Andersenff9eee42001-06-29 04:57:14 +00002480 struct brkcon bc;
2481
2482#if __GNUC__
2483 /* Avoid longjmp clobbering */
2484 (void) &wp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002485#endif
Eric Andersenff9eee42001-06-29 04:57:14 +00002486
Eric Andersen12de6cf2004-08-04 19:19:10 +00002487 if (t == NULL) {
2488 DBGPRINTF4(("EXECUTE: enter, t==null, returning.\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002489 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002490 }
2491
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002492 DBGPRINTF(("EXECUTE: t=%p, t->type=%d (%s), t->words is %s\n", t,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002493 t->type, T_CMD_NAMES[t->type],
2494 ((t->words == NULL) ? "NULL" : t->words[0])));
2495
Eric Andersenff9eee42001-06-29 04:57:14 +00002496 rv = 0;
2497 a = areanum++;
2498 wp = (wp2 = t->words) != NULL
Eric Andersen8401eea2004-08-04 19:16:54 +00002499 ? eval(wp2, t->type == TCOM ? DOALL : DOALL & ~DOKEY)
2500 : NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00002501
Eric Andersen8401eea2004-08-04 19:16:54 +00002502 switch (t->type) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002503 case TDOT:
2504 DBGPRINTF3(("EXECUTE: TDOT\n"));
2505
2506 outtree_save = outtree;
2507
2508 newfile(evalstr(t->words[0], DOALL));
2509
2510 t->left = dowholefile(TLIST, 0);
2511 t->right = NULL;
2512
2513 outtree = outtree_save;
2514
2515 if (t->left)
2516 rv = execute(t->left, pin, pout, 0);
2517 if (t->right)
2518 rv = execute(t->right, pin, pout, 0);
2519 break;
2520
Eric Andersenff9eee42001-06-29 04:57:14 +00002521 case TPAREN:
Eric Andersen737f5fb2003-03-14 16:05:59 +00002522 rv = execute(t->left, pin, pout, 0);
2523 break;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002524
Eric Andersenff9eee42001-06-29 04:57:14 +00002525 case TCOM:
Denis Vlasenko489f93e2007-02-01 01:43:16 +00002526 rv = forkexec(t, pin, pout, act, wp);
Eric Andersenff9eee42001-06-29 04:57:14 +00002527 break;
2528
2529 case TPIPE:
2530 {
Eric Andersen8401eea2004-08-04 19:16:54 +00002531 int pv[2];
2532
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002533 rv = openpipe(pv);
2534 if (rv < 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00002535 break;
2536 pv[0] = remap(pv[0]);
2537 pv[1] = remap(pv[1]);
2538 (void) execute(t->left, pin, pv, 0);
2539 rv = execute(t->right, pv, pout, 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002540 }
2541 break;
2542
2543 case TLIST:
2544 (void) execute(t->left, pin, pout, 0);
2545 rv = execute(t->right, pin, pout, 0);
2546 break;
2547
2548 case TASYNC:
Eric Andersen8401eea2004-08-04 19:16:54 +00002549 {
2550 int hinteractive = interactive;
Eric Andersenff9eee42001-06-29 04:57:14 +00002551
Eric Andersen12de6cf2004-08-04 19:19:10 +00002552 DBGPRINTF7(("EXECUTE: TASYNC clause, calling vfork()...\n"));
2553
Eric Andersen8401eea2004-08-04 19:16:54 +00002554 i = vfork();
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002555 if (i == 0) { /* child */
Eric Andersen8401eea2004-08-04 19:16:54 +00002556 signal(SIGINT, SIG_IGN);
2557 signal(SIGQUIT, SIG_IGN);
2558 if (interactive)
2559 signal(SIGTERM, SIG_DFL);
2560 interactive = 0;
2561 if (pin == NULL) {
2562 close(0);
"Vladimir N. Oleynik"6c35c7c2005-10-12 15:34:25 +00002563 open(bb_dev_null, 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002564 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002565 _exit(execute(t->left, pin, pout, FEXEC));
Eric Andersenff9eee42001-06-29 04:57:14 +00002566 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002567 interactive = hinteractive;
2568 if (i != -1) {
2569 setval(lookup("!"), putn(i));
2570 if (pin != NULL)
2571 closepipe(pin);
2572 if (interactive) {
2573 prs(putn(i));
2574 prs("\n");
2575 }
2576 } else
2577 rv = -1;
2578 setstatus(rv);
Eric Andersenff9eee42001-06-29 04:57:14 +00002579 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002580 break;
2581
2582 case TOR:
2583 case TAND:
2584 rv = execute(t->left, pin, pout, 0);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002585 t1 = t->right;
2586 if (t1 != NULL && (rv == 0) == (t->type == TAND))
Eric Andersenff9eee42001-06-29 04:57:14 +00002587 rv = execute(t1, pin, pout, 0);
2588 break;
2589
2590 case TFOR:
2591 if (wp == NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00002592 wp = dolv + 1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002593 i = dolc;
2594 if (i < 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00002595 i = 0;
2596 } else {
2597 i = -1;
Eric Andersen8401eea2004-08-04 19:16:54 +00002598 while (*wp++ != NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00002599 }
2600 vp = lookup(t->str);
2601 while (setjmp(bc.brkpt))
2602 if (isbreak)
2603 goto broken;
2604 brkset(&bc);
2605 for (t1 = t->left; i-- && *wp != NULL;) {
2606 setval(vp, *wp++);
2607 rv = execute(t1, pin, pout, 0);
2608 }
2609 brklist = brklist->nextlev;
2610 break;
2611
2612 case TWHILE:
2613 case TUNTIL:
2614 while (setjmp(bc.brkpt))
2615 if (isbreak)
2616 goto broken;
2617 brkset(&bc);
2618 t1 = t->left;
2619 while ((execute(t1, pin, pout, 0) == 0) == (t->type == TWHILE))
2620 rv = execute(t->right, pin, pout, 0);
2621 brklist = brklist->nextlev;
2622 break;
2623
2624 case TIF:
2625 case TELIF:
Eric Andersen8401eea2004-08-04 19:16:54 +00002626 if (t->right != NULL) {
2627 rv = !execute(t->left, pin, pout, 0) ?
2628 execute(t->right->left, pin, pout, 0) :
2629 execute(t->right->right, pin, pout, 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002630 }
2631 break;
2632
2633 case TCASE:
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002634 cp = evalstr(t->str, DOSUB | DOTRIM);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002635 if (cp == NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00002636 cp = "";
Eric Andersen12de6cf2004-08-04 19:19:10 +00002637
2638 DBGPRINTF7(("EXECUTE: TCASE, t->str is %s, cp is %s\n",
2639 ((t->str == NULL) ? "NULL" : t->str),
2640 ((cp == NULL) ? "NULL" : cp)));
2641
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002642 t1 = findcase(t->left, cp);
2643 if (t1 != NULL) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002644 DBGPRINTF7(("EXECUTE: TCASE, calling execute(t=%p, t1=%p)...\n", t, t1));
Eric Andersenff9eee42001-06-29 04:57:14 +00002645 rv = execute(t1, pin, pout, 0);
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002646 DBGPRINTF7(("EXECUTE: TCASE, back from execute(t=%p, t1=%p)...\n", t, t1));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002647 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002648 break;
2649
2650 case TBRACE:
2651/*
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002652 iopp = t->ioact;
2653 if (i)
Eric Andersenff9eee42001-06-29 04:57:14 +00002654 while (*iopp)
2655 if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) {
2656 rv = -1;
2657 break;
2658 }
2659*/
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002660 if (rv >= 0) {
2661 t1 = t->left;
2662 if (t1) {
2663 rv = execute(t1, pin, pout, 0);
2664 }
2665 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002666 break;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002667
2668 };
Eric Andersenff9eee42001-06-29 04:57:14 +00002669
Eric Andersen8401eea2004-08-04 19:16:54 +00002670 broken:
Eric Andersenff9eee42001-06-29 04:57:14 +00002671 t->words = wp2;
2672 isbreak = 0;
2673 freehere(areanum);
2674 freearea(areanum);
2675 areanum = a;
2676 if (interactive && intr) {
2677 closeall();
2678 fail();
2679 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002680
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002681 i = trapset;
2682 if (i != 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002683 trapset = 0;
2684 runtrap(i);
2685 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002686
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002687 DBGPRINTF(("EXECUTE: returning from t=%p, rv=%d\n", t, rv));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002688 return rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00002689}
2690
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002691typedef int (*builtin_func_ptr)(struct op *);
2692
2693static builtin_func_ptr inbuilt(const char *s) {
2694 const struct builtincmd *bp;
2695
2696 for (bp = builtincmds; bp->name != NULL; bp++)
2697 if (strcmp(bp->name, s) == 0)
2698 return bp->builtinfunc;
2699
2700 return NULL;
2701}
2702
2703static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002704{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002705 pid_t newpid;
Eric Andersenff9eee42001-06-29 04:57:14 +00002706 int i, rv;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002707 builtin_func_ptr shcom = NULL;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002708 int f;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002709 const char *cp = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00002710 struct ioword **iopp;
2711 int resetsig;
2712 char **owp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002713 int forked = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002714
2715 int *hpin = pin;
2716 int *hpout = pout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002717 char *hwp;
2718 int hinteractive;
2719 int hintr;
Eric Andersen8401eea2004-08-04 19:16:54 +00002720 struct brkcon *hbrklist;
Eric Andersenff9eee42001-06-29 04:57:14 +00002721 int hexecflg;
2722
2723#if __GNUC__
2724 /* Avoid longjmp clobbering */
2725 (void) &pin;
2726 (void) &pout;
2727 (void) &wp;
2728 (void) &shcom;
2729 (void) &cp;
2730 (void) &resetsig;
2731 (void) &owp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002732#endif
Eric Andersenff9eee42001-06-29 04:57:14 +00002733
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002734 DBGPRINTF(("FORKEXEC: t=%p, pin %p, pout %p, act %d\n", t, pin,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002735 pout, act));
2736 DBGPRINTF7(("FORKEXEC: t->words is %s\n",
2737 ((t->words == NULL) ? "NULL" : t->words[0])));
2738
Eric Andersenff9eee42001-06-29 04:57:14 +00002739 owp = wp;
2740 resetsig = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00002741 rv = -1; /* system-detected error */
Eric Andersenff9eee42001-06-29 04:57:14 +00002742 if (t->type == TCOM) {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002743 while (*wp++ != NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00002744 cp = *wp;
2745
2746 /* strip all initial assignments */
2747 /* not correct wrt PATH=yyy command etc */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002748 if (flag['x']) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002749 DBGPRINTF9(("FORKEXEC: echo'ing, cp=%p, wp=%p, owp=%p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00002750 cp, wp, owp));
Eric Andersen8401eea2004-08-04 19:16:54 +00002751 echo(cp ? wp : owp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002752 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002753
Eric Andersenff9eee42001-06-29 04:57:14 +00002754 if (cp == NULL && t->ioact == NULL) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002755 while ((cp = *owp++) != NULL && assign(cp, COPYV))
2756 /**/;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002757 DBGPRINTF(("FORKEXEC: returning setstatus()\n"));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002758 return setstatus(0);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002759 }
2760 if (cp != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002761 shcom = inbuilt(cp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002762 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002763 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002764
Eric Andersenff9eee42001-06-29 04:57:14 +00002765 t->words = wp;
2766 f = act;
Eric Andersenff9eee42001-06-29 04:57:14 +00002767
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002768 DBGPRINTF(("FORKEXEC: shcom %p, f&FEXEC 0x%x, owp %p\n", shcom,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002769 f & FEXEC, owp));
2770
2771 if (shcom == NULL && (f & FEXEC) == 0) {
2772 /* Save values in case the child process alters them */
Eric Andersenff9eee42001-06-29 04:57:14 +00002773 hpin = pin;
2774 hpout = pout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002775 hwp = *wp;
2776 hinteractive = interactive;
2777 hintr = intr;
2778 hbrklist = brklist;
2779 hexecflg = execflg;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002780
Eric Andersen12de6cf2004-08-04 19:19:10 +00002781 DBGPRINTF3(("FORKEXEC: calling vfork()...\n"));
2782
2783 newpid = vfork();
2784
2785 if (newpid == -1) {
Denis Vlasenko89f0b342006-11-18 22:04:09 +00002786 DBGPRINTF(("FORKEXEC: ERROR, cannot vfork()!\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002787 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002788 }
2789
Denis Vlasenko489f93e2007-02-01 01:43:16 +00002790 if (newpid > 0) { /* Parent */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002791 /* Restore values */
Eric Andersenff9eee42001-06-29 04:57:14 +00002792 pin = hpin;
2793 pout = hpout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002794 *wp = hwp;
2795 interactive = hinteractive;
2796 intr = hintr;
2797 brklist = hbrklist;
2798 execflg = hexecflg;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002799/* moved up
Eric Andersenff9eee42001-06-29 04:57:14 +00002800 if (i == -1)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002801 return rv;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002802*/
Eric Andersenff9eee42001-06-29 04:57:14 +00002803 if (pin != NULL)
2804 closepipe(pin);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002805
2806 return (pout == NULL ? setstatus(waitfor(newpid, 0)) : 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002807 }
2808
Eric Andersen12de6cf2004-08-04 19:19:10 +00002809 /* Must be the child process, pid should be 0 */
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002810 DBGPRINTF(("FORKEXEC: child process, shcom=%p\n", shcom));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002811
Eric Andersenff9eee42001-06-29 04:57:14 +00002812 if (interactive) {
2813 signal(SIGINT, SIG_IGN);
2814 signal(SIGQUIT, SIG_IGN);
2815 resetsig = 1;
2816 }
2817 interactive = 0;
2818 intr = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002819 forked = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002820 brklist = 0;
2821 execflg = 0;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002822 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002823
Eric Andersenff9eee42001-06-29 04:57:14 +00002824 if (owp != NULL)
2825 while ((cp = *owp++) != NULL && assign(cp, COPYV))
2826 if (shcom == NULL)
2827 export(lookup(cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002828
Eric Andersenff9eee42001-06-29 04:57:14 +00002829#ifdef COMPIPE
2830 if ((pin != NULL || pout != NULL) && shcom != NULL && shcom != doexec) {
2831 err("piping to/from shell builtins not yet done");
Eric Andersen12de6cf2004-08-04 19:19:10 +00002832 if (forked)
2833 _exit(-1);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002834 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002835 }
2836#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00002837
Eric Andersenff9eee42001-06-29 04:57:14 +00002838 if (pin != NULL) {
2839 dup2(pin[0], 0);
2840 closepipe(pin);
2841 }
2842 if (pout != NULL) {
2843 dup2(pout[1], 1);
2844 closepipe(pout);
2845 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002846
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002847 iopp = t->ioact;
2848 if (iopp != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002849 if (shcom != NULL && shcom != doexec) {
2850 prs(cp);
2851 err(": cannot redirect shell command");
Eric Andersen12de6cf2004-08-04 19:19:10 +00002852 if (forked)
2853 _exit(-1);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002854 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002855 }
2856 while (*iopp)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002857 if (iosetup(*iopp++, pin != NULL, pout != NULL)) {
2858 if (forked)
2859 _exit(rv);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002860 return rv;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002861 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002862 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002863
2864 if (shcom) {
2865 i = setstatus((*shcom) (t));
2866 if (forked)
2867 _exit(i);
2868 DBGPRINTF(("FORKEXEC: returning i=%d\n", i));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002869 return i;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002870 }
2871
Eric Andersenff9eee42001-06-29 04:57:14 +00002872 /* should use FIOCEXCL */
Eric Andersen8401eea2004-08-04 19:16:54 +00002873 for (i = FDBASE; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00002874 close(i);
2875 if (resetsig) {
2876 signal(SIGINT, SIG_DFL);
2877 signal(SIGQUIT, SIG_DFL);
2878 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002879
Eric Andersen12de6cf2004-08-04 19:19:10 +00002880 if (t->type == TPAREN)
2881 _exit(execute(t->left, NOPIPE, NOPIPE, FEXEC));
2882 if (wp[0] == NULL)
2883 _exit(0);
2884
Eric Andersenfd7a4c82004-09-02 23:13:10 +00002885 cp = rexecve(wp[0], wp, makenv(0, NULL));
Eric Andersen8401eea2004-08-04 19:16:54 +00002886 prs(wp[0]);
2887 prs(": ");
Eric Andersen12de6cf2004-08-04 19:19:10 +00002888 err(cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00002889 if (!execflg)
2890 trap[0] = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002891
2892 DBGPRINTF(("FORKEXEC: calling leave(), pid=%d\n", newpid));
2893
Eric Andersenff9eee42001-06-29 04:57:14 +00002894 leave();
2895 /* NOTREACHED */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002896 _exit(1);
Eric Andersenff9eee42001-06-29 04:57:14 +00002897}
2898
2899/*
2900 * 0< 1> are ignored as required
2901 * within pipelines.
2902 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002903static int iosetup(struct ioword *iop, int pipein, int pipeout)
Eric Andersenff9eee42001-06-29 04:57:14 +00002904{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002905 int u = -1;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002906 char *cp = NULL;
2907 const char *msg;
Eric Andersenff9eee42001-06-29 04:57:14 +00002908
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002909 DBGPRINTF(("IOSETUP: iop %p, pipein %i, pipeout %i\n", iop,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002910 pipein, pipeout));
2911
Eric Andersenff9eee42001-06-29 04:57:14 +00002912 if (iop->io_unit == IODEFAULT) /* take default */
Eric Andersen8401eea2004-08-04 19:16:54 +00002913 iop->io_unit = iop->io_flag & (IOREAD | IOHERE) ? 0 : 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002914
Eric Andersenff9eee42001-06-29 04:57:14 +00002915 if (pipein && iop->io_unit == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002916 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002917
Eric Andersenff9eee42001-06-29 04:57:14 +00002918 if (pipeout && iop->io_unit == 1)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002919 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002920
Eric Andersen8401eea2004-08-04 19:16:54 +00002921 msg = iop->io_flag & (IOREAD | IOHERE) ? "open" : "create";
Eric Andersenff9eee42001-06-29 04:57:14 +00002922 if ((iop->io_flag & IOHERE) == 0) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002923 cp = iop->io_name; /* huh?? */
2924 cp = evalstr(cp, DOSUB | DOTRIM);
2925 if (cp == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002926 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002927 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002928
Eric Andersenff9eee42001-06-29 04:57:14 +00002929 if (iop->io_flag & IODUP) {
2930 if (cp[1] || (!isdigit(*cp) && *cp != '-')) {
2931 prs(cp);
2932 err(": illegal >& argument");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002933 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002934 }
2935 if (*cp == '-')
2936 iop->io_flag = IOCLOSE;
Eric Andersen8401eea2004-08-04 19:16:54 +00002937 iop->io_flag &= ~(IOREAD | IOWRITE);
Eric Andersenff9eee42001-06-29 04:57:14 +00002938 }
2939 switch (iop->io_flag) {
2940 case IOREAD:
2941 u = open(cp, 0);
2942 break;
2943
2944 case IOHERE:
Eric Andersen8401eea2004-08-04 19:16:54 +00002945 case IOHERE | IOXHERE:
2946 u = herein(iop->io_name, iop->io_flag & IOXHERE);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002947 cp = (char*)"here file";
Eric Andersenff9eee42001-06-29 04:57:14 +00002948 break;
2949
Eric Andersen8401eea2004-08-04 19:16:54 +00002950 case IOWRITE | IOCAT:
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002951 u = open(cp, 1);
2952 if (u >= 0) {
Denis Vlasenkoea620772006-10-14 02:23:43 +00002953 lseek(u, (long) 0, SEEK_END);
Eric Andersenff9eee42001-06-29 04:57:14 +00002954 break;
2955 }
2956 case IOWRITE:
2957 u = creat(cp, 0666);
2958 break;
2959
2960 case IODUP:
Eric Andersen8401eea2004-08-04 19:16:54 +00002961 u = dup2(*cp - '0', iop->io_unit);
Eric Andersenff9eee42001-06-29 04:57:14 +00002962 break;
2963
2964 case IOCLOSE:
2965 close(iop->io_unit);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002966 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002967 }
2968 if (u < 0) {
2969 prs(cp);
2970 prs(": cannot ");
2971 warn(msg);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002972 return 1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002973 }
2974 if (u != iop->io_unit) {
2975 dup2(u, iop->io_unit);
2976 close(u);
Eric Andersenff9eee42001-06-29 04:57:14 +00002977 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002978 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002979}
2980
Eric Andersenff9eee42001-06-29 04:57:14 +00002981/*
2982 * Enter a new loop level (marked for break/continue).
2983 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002984static void brkset(struct brkcon *bc)
Eric Andersenff9eee42001-06-29 04:57:14 +00002985{
2986 bc->nextlev = brklist;
2987 brklist = bc;
2988}
2989
2990/*
2991 * Wait for the last process created.
2992 * Print a message for each process found
2993 * that was killed by a signal.
2994 * Ignore interrupt signals while waiting
2995 * unless `canintr' is true.
2996 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002997static int waitfor(int lastpid, int canintr)
Eric Andersenff9eee42001-06-29 04:57:14 +00002998{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002999 int pid, rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003000 int s;
3001 int oheedint = heedint;
3002
3003 heedint = 0;
3004 rv = 0;
3005 do {
3006 pid = wait(&s);
3007 if (pid == -1) {
3008 if (errno != EINTR || canintr)
3009 break;
3010 } else {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003011 rv = WAITSIG(s);
3012 if (rv != 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003013 if (rv < NSIGNAL) {
3014 if (signame[rv] != NULL) {
3015 if (pid != lastpid) {
3016 prn(pid);
3017 prs(": ");
3018 }
3019 prs(signame[rv]);
3020 }
3021 } else {
3022 if (pid != lastpid) {
3023 prn(pid);
3024 prs(": ");
3025 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003026 prs("Signal ");
3027 prn(rv);
3028 prs(" ");
Eric Andersenff9eee42001-06-29 04:57:14 +00003029 }
3030 if (WAITCORE(s))
3031 prs(" - core dumped");
3032 if (rv >= NSIGNAL || signame[rv])
3033 prs("\n");
3034 rv = -1;
3035 } else
3036 rv = WAITVAL(s);
3037 }
3038 } while (pid != lastpid);
3039 heedint = oheedint;
3040 if (intr) {
3041 if (interactive) {
3042 if (canintr)
3043 intr = 0;
3044 } else {
Eric Andersen8401eea2004-08-04 19:16:54 +00003045 if (exstat == 0)
3046 exstat = rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003047 onintr(0);
3048 }
3049 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003050 return rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003051}
3052
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003053static int setstatus(int s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003054{
3055 exstat = s;
3056 setval(lookup("?"), putn(s));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003057 return s;
Eric Andersenff9eee42001-06-29 04:57:14 +00003058}
3059
3060/*
3061 * PATH-searching interface to execve.
3062 * If getenv("PATH") were kept up-to-date,
3063 * execvp might be used.
3064 */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003065static const char *rexecve(char *c, char **v, char **envp)
Eric Andersenff9eee42001-06-29 04:57:14 +00003066{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003067 int i;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003068 const char *sp;
3069 char *tp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003070 int eacces = 0, asis = 0;
Eric Andersen1c039232001-07-07 00:05:55 +00003071 char *name = c;
Eric Andersen8401eea2004-08-04 19:16:54 +00003072
Rob Landleya299efb2006-08-10 21:46:43 +00003073 if (ENABLE_FEATURE_SH_STANDALONE_SHELL) {
3074 optind = 1;
3075 if (find_applet_by_name(name)) {
3076 /* We have to exec here since we vforked. Running
3077 * run_applet_by_name() won't work and bad things
3078 * will happen. */
3079 execve(CONFIG_BUSYBOX_EXEC_PATH, v, envp);
3080 }
Eric Andersen1c039232001-07-07 00:05:55 +00003081 }
Eric Andersen1c039232001-07-07 00:05:55 +00003082
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003083 DBGPRINTF(("REXECVE: c=%p, v=%p, envp=%p\n", c, v, envp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003084
Eric Andersen8401eea2004-08-04 19:16:54 +00003085 sp = any('/', c) ? "" : path->value;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003086 asis = (*sp == '\0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003087 while (asis || *sp != '\0') {
3088 asis = 0;
3089 tp = e.linep;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003090 for (; *sp != '\0'; tp++) {
3091 *tp = *sp++;
3092 if (*tp == ':') {
3093 asis = (*sp == '\0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003094 break;
3095 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003096 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003097 if (tp != e.linep)
3098 *tp++ = '/';
Eric Andersen8401eea2004-08-04 19:16:54 +00003099 for (i = 0; (*tp++ = c[i++]) != '\0';);
Eric Andersen1c039232001-07-07 00:05:55 +00003100
Eric Andersen12de6cf2004-08-04 19:19:10 +00003101 DBGPRINTF3(("REXECVE: e.linep is %s\n", e.linep));
3102
Eric Andersenff9eee42001-06-29 04:57:14 +00003103 execve(e.linep, v, envp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003104
Eric Andersenff9eee42001-06-29 04:57:14 +00003105 switch (errno) {
3106 case ENOEXEC:
3107 *v = e.linep;
3108 tp = *--v;
3109 *v = e.linep;
Glenn L McGrathdc4e75e2003-09-02 02:36:18 +00003110 execve(DEFAULT_SHELL, v, envp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003111 *v = tp;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003112 return "no Shell";
Eric Andersenff9eee42001-06-29 04:57:14 +00003113
3114 case ENOMEM:
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003115 return (char *) bb_msg_memory_exhausted;
Eric Andersenff9eee42001-06-29 04:57:14 +00003116
3117 case E2BIG:
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003118 return "argument list too long";
Eric Andersenff9eee42001-06-29 04:57:14 +00003119
3120 case EACCES:
3121 eacces++;
3122 break;
3123 }
3124 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003125 return errno == ENOENT ? "not found" : "cannot execute";
Eric Andersenff9eee42001-06-29 04:57:14 +00003126}
3127
3128/*
3129 * Run the command produced by generator `f'
3130 * applied to stream `arg'.
3131 */
Eric Andersen8401eea2004-08-04 19:16:54 +00003132static int run(struct ioarg *argp, int (*f) (struct ioarg *))
Eric Andersenff9eee42001-06-29 04:57:14 +00003133{
3134 struct op *otree;
3135 struct wdblock *swdlist;
3136 struct wdblock *siolist;
3137 jmp_buf ev, rt;
3138 xint *ofail;
3139 int rv;
3140
3141#if __GNUC__
3142 /* Avoid longjmp clobbering */
3143 (void) &rv;
3144#endif
3145
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003146 DBGPRINTF(("RUN: enter, areanum %d, outtree %p, failpt %p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00003147 areanum, outtree, failpt));
3148
Eric Andersenff9eee42001-06-29 04:57:14 +00003149 areanum++;
3150 swdlist = wdlist;
3151 siolist = iolist;
3152 otree = outtree;
3153 ofail = failpt;
3154 rv = -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003155
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003156 errpt = ev;
3157 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003158 wdlist = 0;
3159 iolist = 0;
3160 pushio(argp, f);
3161 e.iobase = e.iop;
3162 yynerrs = 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003163 failpt = rt;
3164 if (setjmp(failpt) == 0 && yyparse() == 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00003165 rv = execute(outtree, NOPIPE, NOPIPE, 0);
3166 quitenv();
Eric Andersen12de6cf2004-08-04 19:19:10 +00003167 } else {
3168 DBGPRINTF(("RUN: error from newenv()!\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00003169 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00003170
Eric Andersenff9eee42001-06-29 04:57:14 +00003171 wdlist = swdlist;
3172 iolist = siolist;
3173 failpt = ofail;
3174 outtree = otree;
3175 freearea(areanum--);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003176
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003177 return rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003178}
3179
3180/* -------- do.c -------- */
3181
3182/*
3183 * built-in commands: doX
3184 */
3185
Eric Andersen8401eea2004-08-04 19:16:54 +00003186static int dohelp(struct op *t)
Eric Andersen1c039232001-07-07 00:05:55 +00003187{
3188 int col;
3189 const struct builtincmd *x;
3190
Denis Vlasenko0ee39992006-12-24 15:23:28 +00003191 puts("\nBuilt-in commands:\n"
3192 "-------------------");
Eric Andersen1c039232001-07-07 00:05:55 +00003193
Eric Andersen8401eea2004-08-04 19:16:54 +00003194 for (col = 0, x = builtincmds; x->builtinfunc != NULL; x++) {
Eric Andersen1c039232001-07-07 00:05:55 +00003195 if (!x->name)
3196 continue;
3197 col += printf("%s%s", ((col == 0) ? "\t" : " "), x->name);
3198 if (col > 60) {
Denis Vlasenkoc6f188d2006-10-26 00:37:00 +00003199 puts("");
Eric Andersen1c039232001-07-07 00:05:55 +00003200 col = 0;
3201 }
3202 }
Denis Vlasenko38f63192007-01-22 09:03:07 +00003203#if ENABLE_FEATURE_SH_STANDALONE_SHELL
Eric Andersen1c039232001-07-07 00:05:55 +00003204 {
3205 int i;
3206 const struct BB_applet *applet;
Eric Andersen1c039232001-07-07 00:05:55 +00003207
Eric Andersen8401eea2004-08-04 19:16:54 +00003208 for (i = 0, applet = applets; i < NUM_APPLETS; applet++, i++) {
Eric Andersen1c039232001-07-07 00:05:55 +00003209 if (!applet->name)
3210 continue;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00003211
Eric Andersen8401eea2004-08-04 19:16:54 +00003212 col += printf("%s%s", ((col == 0) ? "\t" : " "), applet->name);
Eric Andersen1c039232001-07-07 00:05:55 +00003213 if (col > 60) {
Denis Vlasenkoc6f188d2006-10-26 00:37:00 +00003214 puts("");
Eric Andersen1c039232001-07-07 00:05:55 +00003215 col = 0;
3216 }
3217 }
3218 }
3219#endif
Denis Vlasenko0ee39992006-12-24 15:23:28 +00003220 puts("\n");
Eric Andersen1c039232001-07-07 00:05:55 +00003221 return EXIT_SUCCESS;
3222}
3223
3224
3225
Eric Andersen8401eea2004-08-04 19:16:54 +00003226static int dolabel(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003227{
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003228 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003229}
3230
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003231static int dochdir(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003232{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003233 const char *cp, *er;
Eric Andersenff9eee42001-06-29 04:57:14 +00003234
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003235 cp = t->words[1];
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003236 if (cp == NULL) {
3237 cp = homedir->value;
Denis Vlasenkod244c5e2007-02-09 17:30:14 +00003238 if (cp != NULL)
3239 goto do_cd;
3240 er = ": no home directory";
3241 } else {
3242 do_cd:
3243 if (chdir(cp) >= 0)
3244 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003245 er = ": bad directory";
Denis Vlasenkod244c5e2007-02-09 17:30:14 +00003246 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003247 prs(cp != NULL ? cp : "cd");
Eric Andersenff9eee42001-06-29 04:57:14 +00003248 err(er);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003249 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003250}
3251
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003252static int doshift(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003253{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003254 int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003255
Eric Andersen8401eea2004-08-04 19:16:54 +00003256 n = t->words[1] ? getn(t->words[1]) : 1;
3257 if (dolc < n) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003258 err("nothing to shift");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003259 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003260 }
3261 dolv[n] = dolv[0];
3262 dolv += n;
3263 dolc -= n;
3264 setval(lookup("#"), putn(dolc));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003265 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003266}
3267
3268/*
3269 * execute login and newgrp directly
3270 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003271static int dologin(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003272{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003273 const char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003274
3275 if (interactive) {
3276 signal(SIGINT, SIG_DFL);
3277 signal(SIGQUIT, SIG_DFL);
3278 }
Eric Andersenfd7a4c82004-09-02 23:13:10 +00003279 cp = rexecve(t->words[0], t->words, makenv(0, NULL));
Eric Andersen8401eea2004-08-04 19:16:54 +00003280 prs(t->words[0]);
3281 prs(": ");
3282 err(cp);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003283 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003284}
3285
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003286static int doumask(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003287{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003288 int i, n;
3289 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003290
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003291 cp = t->words[1];
3292 if (cp == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003293 i = umask(0);
3294 umask(i);
Eric Andersen8401eea2004-08-04 19:16:54 +00003295 for (n = 3 * 4; (n -= 3) >= 0;)
3296 putc('0' + ((i >> n) & 07), stderr);
Eric Andersenff9eee42001-06-29 04:57:14 +00003297 putc('\n', stderr);
3298 } else {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003299/* huh??? '8','9' are not allowed! */
Eric Andersen8401eea2004-08-04 19:16:54 +00003300 for (n = 0; *cp >= '0' && *cp <= '9'; cp++)
3301 n = n * 8 + (*cp - '0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003302 umask(n);
3303 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003304 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003305}
3306
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003307static int doexec(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003308{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003309 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00003310 jmp_buf ex;
3311 xint *ofail;
3312
3313 t->ioact = NULL;
Eric Andersen8401eea2004-08-04 19:16:54 +00003314 for (i = 0; (t->words[i] = t->words[i + 1]) != NULL; i++);
Eric Andersenff9eee42001-06-29 04:57:14 +00003315 if (i == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003316 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003317 execflg = 1;
3318 ofail = failpt;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003319 failpt = ex;
3320 if (setjmp(failpt) == 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00003321 execute(t, NOPIPE, NOPIPE, FEXEC);
3322 failpt = ofail;
3323 execflg = 0;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003324 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003325}
3326
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003327static int dodot(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003328{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003329 int i;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003330 const char *sp;
3331 char *tp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003332 char *cp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003333 int maltmp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003334
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003335 DBGPRINTF(("DODOT: enter, t=%p, tleft %p, tright %p, e.linep is %s\n", t, t->left, t->right, ((e.linep == NULL) ? "NULL" : e.linep)));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003336
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003337 cp = t->words[1];
3338 if (cp == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00003339 DBGPRINTF(("DODOT: bad args, ret 0\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003340 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003341 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003342 DBGPRINTF(("DODOT: cp is %s\n", cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003343
Eric Andersen8401eea2004-08-04 19:16:54 +00003344 sp = any('/', cp) ? ":" : path->value;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003345
3346 DBGPRINTF(("DODOT: sp is %s, e.linep is %s\n",
3347 ((sp == NULL) ? "NULL" : sp),
3348 ((e.linep == NULL) ? "NULL" : e.linep)));
3349
Eric Andersenff9eee42001-06-29 04:57:14 +00003350 while (*sp) {
3351 tp = e.linep;
3352 while (*sp && (*tp = *sp++) != ':')
3353 tp++;
3354 if (tp != e.linep)
3355 *tp++ = '/';
Eric Andersen12de6cf2004-08-04 19:19:10 +00003356
Eric Andersen8401eea2004-08-04 19:16:54 +00003357 for (i = 0; (*tp++ = cp[i++]) != '\0';);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003358
3359 /* Original code */
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003360 i = open(e.linep, 0);
3361 if (i >= 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003362 exstat = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003363 maltmp = remap(i);
3364 DBGPRINTF(("DODOT: remap=%d, exstat=%d, e.iofd %d, i %d, e.linep is %s\n", maltmp, exstat, e.iofd, i, e.linep));
3365
3366 next(maltmp); /* Basically a PUSHIO */
3367
3368 DBGPRINTF(("DODOT: returning exstat=%d\n", exstat));
3369
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003370 return exstat;
Eric Andersenff9eee42001-06-29 04:57:14 +00003371 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003372 } /* while */
Eric Andersen12de6cf2004-08-04 19:19:10 +00003373
Eric Andersenff9eee42001-06-29 04:57:14 +00003374 prs(cp);
3375 err(": not found");
Eric Andersen12de6cf2004-08-04 19:19:10 +00003376
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003377 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003378}
3379
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003380static int dowait(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003381{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003382 int i;
3383 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003384
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003385 cp = t->words[1];
3386 if (cp != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003387 i = getn(cp);
3388 if (i == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003389 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003390 } else
3391 i = -1;
3392 setstatus(waitfor(i, 1));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003393 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003394}
3395
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003396static int doread(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003397{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003398 char *cp, **wp;
3399 int nb = 0;
3400 int nl = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003401
3402 if (t->words[1] == NULL) {
3403 err("Usage: read name ...");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003404 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003405 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003406 for (wp = t->words + 1; *wp; wp++) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003407 for (cp = e.linep; !nl && cp < elinep - 1; cp++) {
3408 nb = read(0, cp, sizeof(*cp));
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003409 if (nb != sizeof(*cp))
Eric Andersenff9eee42001-06-29 04:57:14 +00003410 break;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003411 nl = (*cp == '\n');
3412 if (nl || (wp[1] && any(*cp, ifs->value)))
3413 break;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003414 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003415 *cp = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00003416 if (nb <= 0)
3417 break;
3418 setval(lookup(*wp), e.linep);
3419 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003420 return nb <= 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003421}
3422
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003423static int doeval(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003424{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003425 return RUN(awordlist, t->words + 1, wdchar);
Eric Andersenff9eee42001-06-29 04:57:14 +00003426}
3427
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003428static int dotrap(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003429{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003430 int n, i;
3431 int resetsig;
Eric Andersenff9eee42001-06-29 04:57:14 +00003432
3433 if (t->words[1] == NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00003434 for (i = 0; i <= _NSIG; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00003435 if (trap[i]) {
3436 prn(i);
3437 prs(": ");
3438 prs(trap[i]);
3439 prs("\n");
3440 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003441 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003442 }
3443 resetsig = isdigit(*t->words[1]);
3444 for (i = resetsig ? 1 : 2; t->words[i] != NULL; ++i) {
3445 n = getsig(t->words[i]);
3446 freecell(trap[n]);
3447 trap[n] = 0;
3448 if (!resetsig) {
3449 if (*t->words[1] != '\0') {
3450 trap[n] = strsave(t->words[1], 0);
3451 setsig(n, sig);
3452 } else
3453 setsig(n, SIG_IGN);
3454 } else {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00003455 if (interactive) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003456 if (n == SIGINT)
3457 setsig(n, onintr);
3458 else
Eric Andersen8401eea2004-08-04 19:16:54 +00003459 setsig(n, n == SIGQUIT ? SIG_IGN : SIG_DFL);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00003460 } else
Eric Andersenff9eee42001-06-29 04:57:14 +00003461 setsig(n, SIG_DFL);
3462 }
3463 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003464 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003465}
3466
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003467static int getsig(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003468{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003469 int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003470
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003471 n = getn(s);
3472 if (n < 0 || n > _NSIG) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003473 err("trap: bad signal number");
3474 n = 0;
3475 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003476 return n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003477}
3478
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003479static void setsig(int n, sighandler_t f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003480{
3481 if (n == 0)
3482 return;
3483 if (signal(n, SIG_IGN) != SIG_IGN || ourtrap[n]) {
3484 ourtrap[n] = 1;
3485 signal(n, f);
3486 }
3487}
3488
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003489static int getn(char *as)
Eric Andersenff9eee42001-06-29 04:57:14 +00003490{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003491 char *s;
3492 int n, m;
Eric Andersenff9eee42001-06-29 04:57:14 +00003493
3494 s = as;
3495 m = 1;
3496 if (*s == '-') {
3497 m = -1;
3498 s++;
3499 }
3500 for (n = 0; isdigit(*s); s++)
Eric Andersen8401eea2004-08-04 19:16:54 +00003501 n = (n * 10) + (*s - '0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003502 if (*s) {
3503 prs(as);
3504 err(": bad number");
3505 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003506 return n * m;
Eric Andersenff9eee42001-06-29 04:57:14 +00003507}
3508
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003509static int dobreak(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003510{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003511 return brkcontin(t->words[1], 1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003512}
3513
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003514static int docontinue(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003515{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003516 return brkcontin(t->words[1], 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003517}
3518
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003519static int brkcontin(char *cp, int val)
Eric Andersenff9eee42001-06-29 04:57:14 +00003520{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003521 struct brkcon *bc;
3522 int nl;
Eric Andersenff9eee42001-06-29 04:57:14 +00003523
Eric Andersen8401eea2004-08-04 19:16:54 +00003524 nl = cp == NULL ? 1 : getn(cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003525 if (nl <= 0)
3526 nl = 999;
3527 do {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003528 bc = brklist;
3529 if (bc == NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00003530 break;
3531 brklist = bc->nextlev;
3532 } while (--nl);
3533 if (nl) {
3534 err("bad break/continue level");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003535 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003536 }
3537 isbreak = val;
3538 longjmp(bc->brkpt, 1);
3539 /* NOTREACHED */
3540}
3541
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003542static int doexit(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003543{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003544 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003545
3546 execflg = 0;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003547 cp = t->words[1];
3548 if (cp != NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00003549 setstatus(getn(cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003550
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003551 DBGPRINTF(("DOEXIT: calling leave(), t=%p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003552
Eric Andersenff9eee42001-06-29 04:57:14 +00003553 leave();
3554 /* NOTREACHED */
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003555 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003556}
3557
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003558static int doexport(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003559{
Eric Andersen8401eea2004-08-04 19:16:54 +00003560 rdexp(t->words + 1, export, EXPORT);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003561 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003562}
3563
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003564static int doreadonly(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003565{
Eric Andersen8401eea2004-08-04 19:16:54 +00003566 rdexp(t->words + 1, ronly, RONLY);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003567 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003568}
3569
Eric Andersen8401eea2004-08-04 19:16:54 +00003570static void rdexp(char **wp, void (*f) (struct var *), int key)
Eric Andersenff9eee42001-06-29 04:57:14 +00003571{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003572 DBGPRINTF6(("RDEXP: enter, wp=%p, func=%p, key=%d\n", wp, f, key));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003573 DBGPRINTF6(("RDEXP: *wp=%s\n", *wp));
3574
Eric Andersenff9eee42001-06-29 04:57:14 +00003575 if (*wp != NULL) {
Matt Kraaif69bfc72001-07-12 19:39:59 +00003576 for (; *wp != NULL; wp++) {
3577 if (isassign(*wp)) {
3578 char *cp;
Eric Andersen8401eea2004-08-04 19:16:54 +00003579
Matt Kraaif69bfc72001-07-12 19:39:59 +00003580 assign(*wp, COPYV);
Eric Andersen8401eea2004-08-04 19:16:54 +00003581 for (cp = *wp; *cp != '='; cp++);
Matt Kraaif69bfc72001-07-12 19:39:59 +00003582 *cp = '\0';
3583 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003584 if (checkname(*wp))
Eric Andersen8401eea2004-08-04 19:16:54 +00003585 (*f) (lookup(*wp));
Eric Andersenff9eee42001-06-29 04:57:14 +00003586 else
3587 badid(*wp);
Matt Kraaif69bfc72001-07-12 19:39:59 +00003588 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003589 } else
3590 putvlist(key, 1);
3591}
3592
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003593static void badid(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003594{
3595 prs(s);
3596 err(": bad identifier");
3597}
3598
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003599static int doset(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003600{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003601 struct var *vp;
3602 char *cp;
3603 int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003604
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003605 cp = t->words[1];
3606 if (cp == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003607 for (vp = vlist; vp; vp = vp->next)
3608 varput(vp->name, 1);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003609 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003610 }
3611 if (*cp == '-') {
3612 /* bad: t->words++; */
Eric Andersen8401eea2004-08-04 19:16:54 +00003613 for (n = 0; (t->words[n] = t->words[n + 1]) != NULL; n++);
Eric Andersenff9eee42001-06-29 04:57:14 +00003614 if (*++cp == 0)
3615 flag['x'] = flag['v'] = 0;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003616 else {
3617 for (; *cp; cp++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003618 switch (*cp) {
3619 case 'e':
3620 if (!interactive)
3621 flag['e']++;
3622 break;
3623
3624 default:
Eric Andersen8401eea2004-08-04 19:16:54 +00003625 if (*cp >= 'a' && *cp <= 'z')
3626 flag[(int) *cp]++;
Eric Andersenff9eee42001-06-29 04:57:14 +00003627 break;
3628 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003629 }
3630 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003631 setdash();
3632 }
3633 if (t->words[1]) {
3634 t->words[0] = dolv[0];
Eric Andersen8401eea2004-08-04 19:16:54 +00003635 for (n = 1; t->words[n]; n++)
3636 setarea((char *) t->words[n], 0);
3637 dolc = n - 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003638 dolv = t->words;
3639 setval(lookup("#"), putn(dolc));
Eric Andersen8401eea2004-08-04 19:16:54 +00003640 setarea((char *) (dolv - 1), 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003641 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003642 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003643}
3644
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003645static void varput(char *s, int out)
Eric Andersenff9eee42001-06-29 04:57:14 +00003646{
Matt Kraai69edfec2001-08-06 14:14:18 +00003647 if (isalnum(*s) || *s == '_') {
Eric Andersenff9eee42001-06-29 04:57:14 +00003648 write(out, s, strlen(s));
3649 write(out, "\n", 1);
3650 }
3651}
3652
3653
3654/*
3655 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
3656 * This file contains code for the times builtin.
Eric Andersenff9eee42001-06-29 04:57:14 +00003657 */
Eric Andersen8401eea2004-08-04 19:16:54 +00003658static int dotimes(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003659{
3660 struct tms buf;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003661 long clk_tck = sysconf(_SC_CLK_TCK);
Eric Andersenff9eee42001-06-29 04:57:14 +00003662
3663 times(&buf);
3664 printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
Eric Andersen8401eea2004-08-04 19:16:54 +00003665 (int) (buf.tms_utime / clk_tck / 60),
3666 ((double) buf.tms_utime) / clk_tck,
3667 (int) (buf.tms_stime / clk_tck / 60),
3668 ((double) buf.tms_stime) / clk_tck,
3669 (int) (buf.tms_cutime / clk_tck / 60),
3670 ((double) buf.tms_cutime) / clk_tck,
3671 (int) (buf.tms_cstime / clk_tck / 60),
3672 ((double) buf.tms_cstime) / clk_tck);
Eric Andersenff9eee42001-06-29 04:57:14 +00003673 return 0;
3674}
3675
3676
Eric Andersenff9eee42001-06-29 04:57:14 +00003677/* -------- eval.c -------- */
3678
3679/*
3680 * ${}
3681 * `command`
3682 * blank interpretation
3683 * quoting
3684 * glob
3685 */
3686
Eric Andersen8401eea2004-08-04 19:16:54 +00003687static char **eval(char **ap, int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003688{
3689 struct wdblock *wb;
3690 char **wp;
3691 char **wf;
3692 jmp_buf ev;
3693
3694#if __GNUC__
3695 /* Avoid longjmp clobbering */
3696 (void) &wp;
3697 (void) &ap;
3698#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00003699
3700 DBGPRINTF4(("EVAL: enter, f=%d\n", f));
3701
Eric Andersenff9eee42001-06-29 04:57:14 +00003702 wp = NULL;
3703 wb = NULL;
3704 wf = NULL;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003705 errpt = ev;
3706 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003707 while (*ap && isassign(*ap))
3708 expand(*ap++, &wb, f & ~DOGLOB);
3709 if (flag['k']) {
3710 for (wf = ap; *wf; wf++) {
3711 if (isassign(*wf))
3712 expand(*wf, &wb, f & ~DOGLOB);
3713 }
3714 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003715 for (wb = addword((char *) 0, wb); *ap; ap++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003716 if (!flag['k'] || !isassign(*ap))
3717 expand(*ap, &wb, f & ~DOKEY);
3718 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003719 wb = addword((char *) 0, wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00003720 wp = getwords(wb);
3721 quitenv();
3722 } else
3723 gflg = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003724
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003725 return gflg ? (char **) NULL : wp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003726}
3727
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003728
Eric Andersenff9eee42001-06-29 04:57:14 +00003729/*
3730 * Make the exported environment from the exported
3731 * names in the dictionary. Keyword assignments
3732 * will already have been done.
3733 */
Eric Andersenfd7a4c82004-09-02 23:13:10 +00003734static char **makenv(int all, struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00003735{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003736 struct var *vp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003737
3738 DBGPRINTF5(("MAKENV: enter, all=%d\n", all));
Eric Andersenff9eee42001-06-29 04:57:14 +00003739
Eric Andersenff9eee42001-06-29 04:57:14 +00003740 for (vp = vlist; vp; vp = vp->next)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003741 if (all || vp->status & EXPORT)
Eric Andersenff9eee42001-06-29 04:57:14 +00003742 wb = addword(vp->name, wb);
Eric Andersen8401eea2004-08-04 19:16:54 +00003743 wb = addword((char *) 0, wb);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003744 return getwords(wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00003745}
3746
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003747static int expand(const char *cp, struct wdblock **wbp, int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003748{
3749 jmp_buf ev;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003750 char *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003751
3752#if __GNUC__
3753 /* Avoid longjmp clobbering */
3754 (void) &cp;
3755#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00003756
3757 DBGPRINTF3(("EXPAND: enter, f=%d\n", f));
3758
Eric Andersenff9eee42001-06-29 04:57:14 +00003759 gflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003760
Eric Andersenff9eee42001-06-29 04:57:14 +00003761 if (cp == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003762 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003763
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003764 if (!anys("$`'\"", cp) && !anys(ifs->value, cp)
3765 && ((f & DOGLOB) == 0 || !anys("[*?", cp))
3766 ) {
3767 xp = strsave(cp, areanum);
Eric Andersenff9eee42001-06-29 04:57:14 +00003768 if (f & DOTRIM)
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003769 unquote(xp);
3770 *wbp = addword(xp, *wbp);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003771 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003772 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003773 errpt = ev;
3774 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003775 PUSHIO(aword, cp, strchar);
3776 e.iobase = e.iop;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003777 while ((xp = blank(f)) && gflg == 0) {
3778 e.linep = xp;
3779 xp = strsave(xp, areanum);
Eric Andersen8401eea2004-08-04 19:16:54 +00003780 if ((f & DOGLOB) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003781 if (f & DOTRIM)
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003782 unquote(xp);
3783 *wbp = addword(xp, *wbp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003784 } else
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003785 *wbp = glob(xp, *wbp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003786 }
3787 quitenv();
3788 } else
3789 gflg = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003790 return gflg == 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003791}
3792
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003793static char *evalstr(char *cp, int f)
3794{
3795 struct wdblock *wb;
3796
3797 DBGPRINTF6(("EVALSTR: enter, cp=%p, f=%d\n", cp, f));
3798
3799 wb = NULL;
3800 if (expand(cp, &wb, f)) {
3801 if (wb == NULL || wb->w_nword == 0
3802 || (cp = wb->w_words[0]) == NULL
3803 ) {
Denis Vlasenko8e858e22007-03-07 09:35:43 +00003804// TODO: I suspect that
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003805// char *evalstr(char *cp, int f) is actually
3806// const char *evalstr(const char *cp, int f)!
3807 cp = (char*)"";
3808 }
3809 DELETE(wb);
3810 } else
3811 cp = NULL;
3812 return cp;
3813}
3814
3815
Eric Andersenff9eee42001-06-29 04:57:14 +00003816/*
3817 * Blank interpretation and quoting
3818 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003819static char *blank(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003820{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003821 int c, c1;
3822 char *sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003823 int scanequals, foundequals;
3824
Eric Andersen12de6cf2004-08-04 19:19:10 +00003825 DBGPRINTF3(("BLANK: enter, f=%d\n", f));
3826
Eric Andersenff9eee42001-06-29 04:57:14 +00003827 sp = e.linep;
3828 scanequals = f & DOKEY;
3829 foundequals = 0;
3830
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003831 loop:
3832 c = subgetc('"', foundequals);
3833 switch (c) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003834 case 0:
3835 if (sp == e.linep)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003836 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003837 *e.linep++ = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003838 return sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003839
3840 default:
3841 if (f & DOBLANK && any(c, ifs->value))
3842 goto loop;
3843 break;
3844
3845 case '"':
3846 case '\'':
3847 scanequals = 0;
3848 if (INSUB())
3849 break;
3850 for (c1 = c; (c = subgetc(c1, 1)) != c1;) {
3851 if (c == 0)
3852 break;
3853 if (c == '\'' || !any(c, "$`\""))
3854 c |= QUOTE;
3855 *e.linep++ = c;
3856 }
3857 c = 0;
3858 }
3859 unget(c);
Matt Kraai69edfec2001-08-06 14:14:18 +00003860 if (!isalpha(c) && c != '_')
Eric Andersenff9eee42001-06-29 04:57:14 +00003861 scanequals = 0;
3862 for (;;) {
3863 c = subgetc('"', foundequals);
3864 if (c == 0 ||
Eric Andersen8401eea2004-08-04 19:16:54 +00003865 f & (DOBLANK && any(c, ifs->value)) ||
3866 (!INSUB() && any(c, "\"'"))) {
3867 scanequals = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003868 unget(c);
3869 if (any(c, "\"'"))
3870 goto loop;
3871 break;
3872 }
3873 if (scanequals) {
3874 if (c == '=') {
3875 foundequals = 1;
Eric Andersen8401eea2004-08-04 19:16:54 +00003876 scanequals = 0;
3877 } else if (!isalnum(c) && c != '_')
Eric Andersenff9eee42001-06-29 04:57:14 +00003878 scanequals = 0;
3879 }
3880 *e.linep++ = c;
3881 }
3882 *e.linep++ = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003883 return sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003884}
3885
3886/*
3887 * Get characters, substituting for ` and $
3888 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003889static int subgetc(char ec, int quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00003890{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003891 char c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003892
3893 DBGPRINTF3(("SUBGETC: enter, quoted=%d\n", quoted));
Eric Andersenff9eee42001-06-29 04:57:14 +00003894
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003895 again:
Eric Andersenff9eee42001-06-29 04:57:14 +00003896 c = my_getc(ec);
3897 if (!INSUB() && ec != '\'') {
3898 if (c == '`') {
3899 if (grave(quoted) == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003900 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003901 e.iop->task = XGRAVE;
3902 goto again;
3903 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003904 if (c == '$') {
3905 c = dollar(quoted);
3906 if (c == 0) {
3907 e.iop->task = XDOLL;
3908 goto again;
3909 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003910 }
3911 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003912 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003913}
3914
3915/*
3916 * Prepare to generate the string returned by ${} substitution.
3917 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003918static int dollar(int quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00003919{
3920 int otask;
3921 struct io *oiop;
3922 char *dolp;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003923 char *s, c, *cp = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00003924 struct var *vp;
3925
Eric Andersen12de6cf2004-08-04 19:19:10 +00003926 DBGPRINTF3(("DOLLAR: enter, quoted=%d\n", quoted));
3927
Eric Andersenff9eee42001-06-29 04:57:14 +00003928 c = readc();
3929 s = e.linep;
3930 if (c != '{') {
3931 *e.linep++ = c;
Matt Kraai69edfec2001-08-06 14:14:18 +00003932 if (isalpha(c) || c == '_') {
Eric Andersen8401eea2004-08-04 19:16:54 +00003933 while ((c = readc()) != 0 && (isalnum(c) || c == '_'))
Eric Andersenff9eee42001-06-29 04:57:14 +00003934 if (e.linep < elinep)
3935 *e.linep++ = c;
3936 unget(c);
3937 }
3938 c = 0;
3939 } else {
3940 oiop = e.iop;
3941 otask = e.iop->task;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003942
Eric Andersenff9eee42001-06-29 04:57:14 +00003943 e.iop->task = XOTHER;
Eric Andersen8401eea2004-08-04 19:16:54 +00003944 while ((c = subgetc('"', 0)) != 0 && c != '}' && c != '\n')
Eric Andersenff9eee42001-06-29 04:57:14 +00003945 if (e.linep < elinep)
3946 *e.linep++ = c;
3947 if (oiop == e.iop)
3948 e.iop->task = otask;
3949 if (c != '}') {
3950 err("unclosed ${");
3951 gflg++;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003952 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003953 }
3954 }
3955 if (e.linep >= elinep) {
3956 err("string in ${} too long");
3957 gflg++;
3958 e.linep -= 10;
3959 }
3960 *e.linep = 0;
3961 if (*s)
Eric Andersen8401eea2004-08-04 19:16:54 +00003962 for (cp = s + 1; *cp; cp++)
Eric Andersenff9eee42001-06-29 04:57:14 +00003963 if (any(*cp, "=-+?")) {
3964 c = *cp;
3965 *cp++ = 0;
3966 break;
3967 }
3968 if (s[1] == 0 && (*s == '*' || *s == '@')) {
3969 if (dolc > 1) {
3970 /* currently this does not distinguish $* and $@ */
3971 /* should check dollar */
3972 e.linep = s;
Eric Andersen8401eea2004-08-04 19:16:54 +00003973 PUSHIO(awordlist, dolv + 1, dolchar);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003974 return 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00003975 } else { /* trap the nasty ${=} */
Eric Andersenff9eee42001-06-29 04:57:14 +00003976 s[0] = '1';
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003977 s[1] = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00003978 }
3979 }
3980 vp = lookup(s);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003981 dolp = vp->value;
3982 if (dolp == null) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003983 switch (c) {
3984 case '=':
3985 if (isdigit(*s)) {
3986 err("cannot use ${...=...} with $n");
3987 gflg++;
3988 break;
3989 }
3990 setval(vp, cp);
3991 dolp = vp->value;
3992 break;
3993
3994 case '-':
3995 dolp = strsave(cp, areanum);
3996 break;
3997
3998 case '?':
3999 if (*cp == 0) {
4000 prs("missing value for ");
4001 err(s);
4002 } else
4003 err(cp);
4004 gflg++;
4005 break;
4006 }
4007 } else if (c == '+')
4008 dolp = strsave(cp, areanum);
4009 if (flag['u'] && dolp == null) {
4010 prs("unset variable: ");
4011 err(s);
4012 gflg++;
4013 }
4014 e.linep = s;
4015 PUSHIO(aword, dolp, quoted ? qstrchar : strchar);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004016 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004017}
4018
4019/*
4020 * Run the command in `...` and read its output.
4021 */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004022
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004023static int grave(int quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00004024{
Denis Vlasenko55f30b02007-03-24 22:42:29 +00004025 /* moved to G: static char child_cmd[LINELIM]; */
4026
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004027 const char *cp;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004028 int i;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004029 int j;
Eric Andersenff9eee42001-06-29 04:57:14 +00004030 int pf[2];
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004031 const char *src;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004032 char *dest;
4033 int count;
4034 int ignore;
4035 int ignore_once;
4036 char *argument_list[4];
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004037 struct wdblock *wb = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004038
4039#if __GNUC__
4040 /* Avoid longjmp clobbering */
4041 (void) &cp;
4042#endif
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004043
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004044 for (cp = e.iop->argp->aword; *cp != '`'; cp++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004045 if (*cp == 0) {
4046 err("no closing `");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004047 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004048 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004049 }
Eric Andersen737f5fb2003-03-14 16:05:59 +00004050
4051 /* string copy with dollar expansion */
4052 src = e.iop->argp->aword;
4053 dest = child_cmd;
4054 count = 0;
4055 ignore = 0;
4056 ignore_once = 0;
4057 while ((*src != '`') && (count < LINELIM)) {
4058 if (*src == '\'')
4059 ignore = !ignore;
4060 if (*src == '\\')
4061 ignore_once = 1;
4062 if (*src == '$' && !ignore && !ignore_once) {
4063 struct var *vp;
4064 char var_name[LINELIM];
4065 char alt_value[LINELIM];
4066 int var_index = 0;
4067 int alt_index = 0;
4068 char operator = 0;
4069 int braces = 0;
4070 char *value;
4071
4072 src++;
4073 if (*src == '{') {
4074 braces = 1;
4075 src++;
4076 }
4077
4078 var_name[var_index++] = *src++;
Paul Fox54690dc2005-07-20 18:33:12 +00004079 while (isalnum(*src) || *src=='_')
Eric Andersen737f5fb2003-03-14 16:05:59 +00004080 var_name[var_index++] = *src++;
4081 var_name[var_index] = 0;
4082
4083 if (braces) {
4084 switch (*src) {
4085 case '}':
4086 break;
4087 case '-':
4088 case '=':
4089 case '+':
4090 case '?':
Eric Andersen8401eea2004-08-04 19:16:54 +00004091 operator = * src;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004092 break;
4093 default:
4094 err("unclosed ${\n");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004095 return 0;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004096 }
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004097 if (operator) {
Eric Andersen737f5fb2003-03-14 16:05:59 +00004098 src++;
4099 while (*src && (*src != '}')) {
4100 alt_value[alt_index++] = *src++;
4101 }
4102 alt_value[alt_index] = 0;
4103 if (*src != '}') {
4104 err("unclosed ${\n");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004105 return 0;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004106 }
4107 }
4108 src++;
4109 }
4110
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004111 if (isalpha(*var_name)) {
4112 /* let subshell handle it instead */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004113
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004114 char *namep = var_name;
4115
4116 *dest++ = '$';
4117 if (braces)
4118 *dest++ = '{';
4119 while (*namep)
4120 *dest++ = *namep++;
4121 if (operator) {
4122 char *altp = alt_value;
4123 *dest++ = operator;
4124 while (*altp)
4125 *dest++ = *altp++;
4126 }
4127 if (braces)
4128 *dest++ = '}';
4129
4130 wb = addword(lookup(var_name)->name, wb);
4131 } else {
4132 /* expand */
4133
4134 vp = lookup(var_name);
4135 if (vp->value != null)
4136 value = (operator == '+') ?
4137 alt_value : vp->value;
4138 else if (operator == '?') {
4139 err(alt_value);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004140 return 0;
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004141 } else if (alt_index && (operator != '+')) {
4142 value = alt_value;
4143 if (operator == '=')
4144 setval(vp, value);
4145 } else
4146 continue;
4147
4148 while (*value && (count < LINELIM)) {
4149 *dest++ = *value++;
4150 count++;
4151 }
Eric Andersen737f5fb2003-03-14 16:05:59 +00004152 }
4153 } else {
4154 *dest++ = *src++;
4155 count++;
4156 ignore_once = 0;
4157 }
4158 }
4159 *dest = '\0';
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004160
Eric Andersenff9eee42001-06-29 04:57:14 +00004161 if (openpipe(pf) < 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004162 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004163
Eric Andersen8401eea2004-08-04 19:16:54 +00004164 while ((i = vfork()) == -1 && errno == EAGAIN);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004165
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004166 DBGPRINTF3(("GRAVE: i is %p\n", io));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004167
Eric Andersen737f5fb2003-03-14 16:05:59 +00004168 if (i < 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004169 closepipe(pf);
Eric Andersen8401eea2004-08-04 19:16:54 +00004170 err((char *) bb_msg_memory_exhausted);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004171 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004172 }
4173 if (i != 0) {
Eric Andersen737f5fb2003-03-14 16:05:59 +00004174 waitpid(i, NULL, 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004175 e.iop->argp->aword = ++cp;
4176 close(pf[1]);
Eric Andersen8401eea2004-08-04 19:16:54 +00004177 PUSHIO(afile, remap(pf[0]),
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004178 (int (*)(struct ioarg *)) ((quoted) ? qgravechar : gravechar));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004179 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004180 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004181 /* allow trapped signals */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004182 /* XXX - Maybe this signal stuff should go as well? */
Eric Andersen8401eea2004-08-04 19:16:54 +00004183 for (j = 0; j <= _NSIG; j++)
Eric Andersen737f5fb2003-03-14 16:05:59 +00004184 if (ourtrap[j] && signal(j, SIG_IGN) != SIG_IGN)
4185 signal(j, SIG_DFL);
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004186
Eric Andersenff9eee42001-06-29 04:57:14 +00004187 dup2(pf[1], 1);
4188 closepipe(pf);
Eric Andersen737f5fb2003-03-14 16:05:59 +00004189
Eric Andersen8401eea2004-08-04 19:16:54 +00004190 argument_list[0] = (char *) DEFAULT_SHELL;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004191 argument_list[1] = (char *) "-c";
Eric Andersen737f5fb2003-03-14 16:05:59 +00004192 argument_list[2] = child_cmd;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004193 argument_list[3] = NULL;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004194
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004195 cp = rexecve(argument_list[0], argument_list, makenv(1, wb));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004196 prs(argument_list[0]);
4197 prs(": ");
4198 err(cp);
Eric Andersen737f5fb2003-03-14 16:05:59 +00004199 _exit(1);
Eric Andersenff9eee42001-06-29 04:57:14 +00004200}
4201
Eric Andersen737f5fb2003-03-14 16:05:59 +00004202
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004203static char *unquote(char *as)
Eric Andersenff9eee42001-06-29 04:57:14 +00004204{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004205 char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00004206
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004207 s = as;
4208 if (s != NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00004209 while (*s)
4210 *s++ &= ~QUOTE;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004211 return as;
Eric Andersenff9eee42001-06-29 04:57:14 +00004212}
4213
4214/* -------- glob.c -------- */
4215
4216/*
4217 * glob
4218 */
4219
4220#define scopy(x) strsave((x), areanum)
4221#define BLKSIZ 512
4222#define NDENT ((BLKSIZ+sizeof(struct dirent)-1)/sizeof(struct dirent))
4223
Eric Andersen8401eea2004-08-04 19:16:54 +00004224static struct wdblock *cl, *nl;
4225static char spcl[] = "[?*";
Eric Andersenff9eee42001-06-29 04:57:14 +00004226
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004227static struct wdblock *glob(char *cp, struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004228{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004229 int i;
4230 char *pp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004231
4232 if (cp == 0)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004233 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004234 i = 0;
4235 for (pp = cp; *pp; pp++)
4236 if (any(*pp, spcl))
4237 i++;
4238 else if (!any(*pp & ~QUOTE, spcl))
4239 *pp &= ~QUOTE;
4240 if (i != 0) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004241 for (cl = addword(scopy(cp), NULL); anyspcl(cl); cl = nl) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004242 nl = newword(cl->w_nword * 2);
4243 for (i = 0; i < cl->w_nword; i++) { /* for each argument */
Eric Andersenff9eee42001-06-29 04:57:14 +00004244 for (pp = cl->w_words[i]; *pp; pp++)
4245 if (any(*pp, spcl)) {
4246 globname(cl->w_words[i], pp);
4247 break;
4248 }
4249 if (*pp == '\0')
4250 nl = addword(scopy(cl->w_words[i]), nl);
4251 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004252 for (i = 0; i < cl->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004253 DELETE(cl->w_words[i]);
4254 DELETE(cl);
4255 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004256 for (i = 0; i < cl->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004257 unquote(cl->w_words[i]);
Eric Andersen8401eea2004-08-04 19:16:54 +00004258 glob0((char *) cl->w_words, cl->w_nword, sizeof(char *), xstrcmp);
Eric Andersenff9eee42001-06-29 04:57:14 +00004259 if (cl->w_nword) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004260 for (i = 0; i < cl->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004261 wb = addword(cl->w_words[i], wb);
4262 DELETE(cl);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004263 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004264 }
4265 }
4266 wb = addword(unquote(cp), wb);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004267 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004268}
4269
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004270static void globname(char *we, char *pp)
Eric Andersenff9eee42001-06-29 04:57:14 +00004271{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004272 char *np, *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004273 char *name, *gp, *dp;
4274 int k;
4275 DIR *dirp;
4276 struct dirent *de;
Eric Andersen8401eea2004-08-04 19:16:54 +00004277 char dname[NAME_MAX + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00004278 struct stat dbuf;
4279
4280 for (np = we; np != pp; pp--)
4281 if (pp[-1] == '/')
4282 break;
Eric Andersen8401eea2004-08-04 19:16:54 +00004283 for (dp = cp = space((int) (pp - np) + 3); np < pp;)
Eric Andersenff9eee42001-06-29 04:57:14 +00004284 *cp++ = *np++;
4285 *cp++ = '.';
4286 *cp = '\0';
Eric Andersen8401eea2004-08-04 19:16:54 +00004287 for (gp = cp = space(strlen(pp) + 1); *np && *np != '/';)
Eric Andersenff9eee42001-06-29 04:57:14 +00004288 *cp++ = *np++;
4289 *cp = '\0';
4290 dirp = opendir(dp);
4291 if (dirp == 0) {
4292 DELETE(dp);
4293 DELETE(gp);
4294 return;
4295 }
4296 dname[NAME_MAX] = '\0';
Eric Andersen8401eea2004-08-04 19:16:54 +00004297 while ((de = readdir(dirp)) != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004298 /* XXX Hmmm... What this could be? (abial) */
4299 /*
Eric Andersen8401eea2004-08-04 19:16:54 +00004300 if (ent[j].d_ino == 0)
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004301 continue;
Eric Andersen8401eea2004-08-04 19:16:54 +00004302 */
Eric Andersenff9eee42001-06-29 04:57:14 +00004303 strncpy(dname, de->d_name, NAME_MAX);
Eric Andersen8401eea2004-08-04 19:16:54 +00004304 if (dname[0] == '.')
4305 if (*gp != '.')
4306 continue;
4307 for (k = 0; k < NAME_MAX; k++)
4308 if (any(dname[k], spcl))
4309 dname[k] |= QUOTE;
4310 if (gmatch(dname, gp)) {
4311 name = generate(we, pp, dname, np);
4312 if (*np && !anys(np, spcl)) {
4313 if (stat(name, &dbuf)) {
4314 DELETE(name);
Eric Andersenff9eee42001-06-29 04:57:14 +00004315 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00004316 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004317 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004318 nl = addword(name, nl);
4319 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004320 }
4321 closedir(dirp);
4322 DELETE(dp);
4323 DELETE(gp);
4324}
4325
4326/*
4327 * generate a pathname as below.
4328 * start..end1 / middle end
4329 * the slashes come for free
4330 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004331static char *generate(char *start1, char *end1, char *middle, char *end)
Eric Andersenff9eee42001-06-29 04:57:14 +00004332{
4333 char *p;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004334 char *op, *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004335
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004336 p = op = space((int)(end1 - start1) + strlen(middle) + strlen(end) + 2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004337 for (xp = start1; xp != end1;)
4338 *op++ = *xp++;
Eric Andersen8401eea2004-08-04 19:16:54 +00004339 for (xp = middle; (*op++ = *xp++) != '\0';);
Eric Andersenff9eee42001-06-29 04:57:14 +00004340 op--;
Eric Andersen8401eea2004-08-04 19:16:54 +00004341 for (xp = end; (*op++ = *xp++) != '\0';);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004342 return p;
Eric Andersenff9eee42001-06-29 04:57:14 +00004343}
4344
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004345static int anyspcl(struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004346{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004347 int i;
4348 char **wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004349
4350 wd = wb->w_words;
Eric Andersen8401eea2004-08-04 19:16:54 +00004351 for (i = 0; i < wb->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004352 if (anys(spcl, *wd++))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004353 return 1;
4354 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004355}
4356
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004357static int xstrcmp(char *p1, char *p2)
Eric Andersenff9eee42001-06-29 04:57:14 +00004358{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004359 return strcmp(*(char **) p1, *(char **) p2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004360}
4361
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004362
Eric Andersenff9eee42001-06-29 04:57:14 +00004363/* -------- word.c -------- */
4364
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004365static struct wdblock *newword(int nw)
Eric Andersenff9eee42001-06-29 04:57:14 +00004366{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004367 struct wdblock *wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004368
Eric Andersen8401eea2004-08-04 19:16:54 +00004369 wb = (struct wdblock *) space(sizeof(*wb) + nw * sizeof(char *));
Eric Andersenff9eee42001-06-29 04:57:14 +00004370 wb->w_bsize = nw;
4371 wb->w_nword = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004372 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004373}
4374
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004375static struct wdblock *addword(char *wd, struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004376{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004377 struct wdblock *wb2;
4378 int nw;
Eric Andersenff9eee42001-06-29 04:57:14 +00004379
4380 if (wb == NULL)
4381 wb = newword(NSTART);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004382 nw = wb->w_nword;
4383 if (nw >= wb->w_bsize) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004384 wb2 = newword(nw * 2);
Eric Andersen8401eea2004-08-04 19:16:54 +00004385 memcpy((char *) wb2->w_words, (char *) wb->w_words,
4386 nw * sizeof(char *));
Eric Andersenff9eee42001-06-29 04:57:14 +00004387 wb2->w_nword = nw;
4388 DELETE(wb);
4389 wb = wb2;
4390 }
4391 wb->w_words[wb->w_nword++] = wd;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004392 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004393}
Eric Andersen8401eea2004-08-04 19:16:54 +00004394
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004395static
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004396char **getwords(struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004397{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004398 char **wd;
4399 int nb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004400
4401 if (wb == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004402 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004403 if (wb->w_nword == 0) {
4404 DELETE(wb);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004405 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004406 }
4407 wd = (char **) space(nb = sizeof(*wd) * wb->w_nword);
Eric Andersen8401eea2004-08-04 19:16:54 +00004408 memcpy((char *) wd, (char *) wb->w_words, nb);
4409 DELETE(wb); /* perhaps should done by caller */
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004410 return wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004411}
4412
"Vladimir N. Oleynik"ac973172005-09-22 14:38:17 +00004413static int (*func) (char *, char *);
4414static int globv;
Eric Andersenff9eee42001-06-29 04:57:14 +00004415
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004416static void glob3(char *i, char *j, char *k)
Eric Andersenff9eee42001-06-29 04:57:14 +00004417{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004418 char *index1, *index2, *index3;
4419 int c;
4420 int m;
4421
4422 m = globv;
4423 index1 = i;
4424 index2 = j;
4425 index3 = k;
4426 do {
4427 c = *index1;
4428 *index1++ = *index3;
4429 *index3++ = *index2;
4430 *index2++ = c;
4431 } while (--m);
4432}
4433
4434static void glob2(char *i, char *j)
4435{
4436 char *index1, *index2, c;
4437 int m;
4438
4439 m = globv;
4440 index1 = i;
4441 index2 = j;
4442 do {
4443 c = *index1;
4444 *index1++ = *index2;
4445 *index2++ = c;
4446 } while (--m);
Eric Andersenff9eee42001-06-29 04:57:14 +00004447}
4448
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004449static void glob1(char *base, char *lim)
Eric Andersenff9eee42001-06-29 04:57:14 +00004450{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004451 char *i, *j;
Eric Andersenff9eee42001-06-29 04:57:14 +00004452 int v2;
4453 char *lptr, *hptr;
4454 int c;
4455 unsigned n;
4456
Eric Andersenff9eee42001-06-29 04:57:14 +00004457 v2 = globv;
4458
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004459 top:
4460 n = (int) (lim - base);
4461 if (n <= v2)
Eric Andersenff9eee42001-06-29 04:57:14 +00004462 return;
Eric Andersen8401eea2004-08-04 19:16:54 +00004463 n = v2 * (n / (2 * v2));
4464 hptr = lptr = base + n;
Eric Andersenff9eee42001-06-29 04:57:14 +00004465 i = base;
Eric Andersen8401eea2004-08-04 19:16:54 +00004466 j = lim - v2;
4467 for (;;) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004468 if (i < lptr) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004469 c = (*func) (i, lptr);
4470 if (c == 0) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004471 lptr -= v2;
4472 glob2(i, lptr);
Eric Andersenff9eee42001-06-29 04:57:14 +00004473 continue;
4474 }
4475 if (c < 0) {
4476 i += v2;
4477 continue;
4478 }
4479 }
4480
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004481 begin:
Eric Andersenff9eee42001-06-29 04:57:14 +00004482 if (j > hptr) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004483 c = (*func) (hptr, j);
4484 if (c == 0) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004485 hptr += v2;
4486 glob2(hptr, j);
Eric Andersenff9eee42001-06-29 04:57:14 +00004487 goto begin;
4488 }
4489 if (c > 0) {
4490 if (i == lptr) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004491 hptr += v2;
4492 glob3(i, hptr, j);
4493 i = (lptr += v2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004494 goto begin;
4495 }
4496 glob2(i, j);
4497 j -= v2;
4498 i += v2;
4499 continue;
4500 }
4501 j -= v2;
4502 goto begin;
4503 }
4504
4505
4506 if (i == lptr) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004507 if (lptr - base >= lim - hptr) {
4508 glob1(hptr + v2, lim);
Eric Andersenff9eee42001-06-29 04:57:14 +00004509 lim = lptr;
4510 } else {
4511 glob1(base, lptr);
Eric Andersen8401eea2004-08-04 19:16:54 +00004512 base = hptr + v2;
Eric Andersenff9eee42001-06-29 04:57:14 +00004513 }
4514 goto top;
4515 }
4516
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004517 lptr -= v2;
4518 glob3(j, lptr, i);
4519 j = (hptr -= v2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004520 }
4521}
4522
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004523static void glob0(char *a0, unsigned a1, int a2, int (*a3) (char *, char *))
Eric Andersenff9eee42001-06-29 04:57:14 +00004524{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004525 func = a3;
4526 globv = a2;
4527 glob1(a0, a0 + a1 * a2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004528}
4529
Eric Andersenff9eee42001-06-29 04:57:14 +00004530
4531/* -------- io.c -------- */
4532
4533/*
4534 * shell IO
4535 */
4536
Eric Andersen8401eea2004-08-04 19:16:54 +00004537static int my_getc(int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00004538{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004539 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004540
Eric Andersen8401eea2004-08-04 19:16:54 +00004541 if (e.linep > elinep) {
4542 while ((c = readc()) != '\n' && c);
Eric Andersenff9eee42001-06-29 04:57:14 +00004543 err("input line too long");
4544 gflg++;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004545 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004546 }
4547 c = readc();
Eric Andersen737f5fb2003-03-14 16:05:59 +00004548 if ((ec != '\'') && (ec != '`') && (e.iop->task != XGRAVE)) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004549 if (c == '\\') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004550 c = readc();
4551 if (c == '\n' && ec != '\"')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004552 return my_getc(ec);
Eric Andersenff9eee42001-06-29 04:57:14 +00004553 c |= QUOTE;
4554 }
4555 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004556 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004557}
4558
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004559static void unget(int c)
Eric Andersenff9eee42001-06-29 04:57:14 +00004560{
4561 if (e.iop >= e.iobase)
4562 e.iop->peekc = c;
4563}
4564
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004565static int eofc(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00004566{
Eric Andersen8401eea2004-08-04 19:16:54 +00004567 return e.iop < e.iobase || (e.iop->peekc == 0 && e.iop->prev == 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004568}
4569
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004570static int readc(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00004571{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004572 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004573
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004574 RCPRINTF(("READC: e.iop %p, e.iobase %p\n", e.iop, e.iobase));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004575
4576 for (; e.iop >= e.iobase; e.iop--) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004577 RCPRINTF(("READC: e.iop %p, peekc 0x%x\n", e.iop, e.iop->peekc));
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004578 c = e.iop->peekc;
4579 if (c != '\0') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004580 e.iop->peekc = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004581 return c;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004582 }
4583 if (e.iop->prev != 0) {
4584 c = (*e.iop->iofn)(e.iop->argp, e.iop);
4585 if (c != '\0') {
4586 if (c == -1) {
4587 e.iop++;
4588 continue;
Eric Andersen8401eea2004-08-04 19:16:54 +00004589 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004590 if (e.iop == iostack)
4591 ioecho(c);
4592 e.iop->prev = c;
4593 return e.iop->prev;
Eric Andersenff9eee42001-06-29 04:57:14 +00004594 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004595 if (e.iop->task == XIO && e.iop->prev != '\n') {
4596 e.iop->prev = 0;
4597 if (e.iop == iostack)
4598 ioecho('\n');
4599 return '\n';
Eric Andersen8401eea2004-08-04 19:16:54 +00004600 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004601 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004602 if (e.iop->task == XIO) {
4603 if (multiline) {
4604 e.iop->prev = 0;
4605 return e.iop->prev;
4606 }
4607 if (interactive && e.iop == iostack + 1) {
4608#if ENABLE_FEATURE_EDITING
4609 current_prompt = prompt->value;
4610#else
4611 prs(prompt->value);
4612#endif
4613 }
4614 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004615 } /* FOR */
4616
4617 if (e.iop >= iostack) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004618 RCPRINTF(("READC: return 0, e.iop %p\n", e.iop));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004619 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004620 }
4621
4622 DBGPRINTF(("READC: leave()...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00004623 leave();
Eric Andersen12de6cf2004-08-04 19:19:10 +00004624
Eric Andersenff9eee42001-06-29 04:57:14 +00004625 /* NOTREACHED */
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004626 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004627}
4628
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004629static void ioecho(char c)
Eric Andersenff9eee42001-06-29 04:57:14 +00004630{
4631 if (flag['v'])
4632 write(2, &c, sizeof c);
4633}
4634
Eric Andersen12de6cf2004-08-04 19:19:10 +00004635
Eric Andersen8401eea2004-08-04 19:16:54 +00004636static void pushio(struct ioarg *argp, int (*fn) (struct ioarg *))
Eric Andersenff9eee42001-06-29 04:57:14 +00004637{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004638 DBGPRINTF(("PUSHIO: argp %p, argp->afid 0x%x, e.iop %p\n", argp,
Eric Andersen12de6cf2004-08-04 19:19:10 +00004639 argp->afid, e.iop));
4640
4641 /* Set env ptr for io source to next array spot and check for array overflow */
Eric Andersenff9eee42001-06-29 04:57:14 +00004642 if (++e.iop >= &iostack[NPUSH]) {
4643 e.iop--;
4644 err("Shell input nested too deeply");
4645 gflg++;
4646 return;
4647 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004648
4649 /* We did not overflow the NPUSH array spots so setup data structs */
4650
4651 e.iop->iofn = (int (*)(struct ioarg *, struct io *)) fn; /* Store data source func ptr */
Eric Andersenff9eee42001-06-29 04:57:14 +00004652
4653 if (argp->afid != AFID_NOBUF)
Eric Andersen8401eea2004-08-04 19:16:54 +00004654 e.iop->argp = argp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004655 else {
Eric Andersen12de6cf2004-08-04 19:19:10 +00004656
4657 e.iop->argp = ioargstack + (e.iop - iostack); /* MAL - index into stack */
4658 *e.iop->argp = *argp; /* copy data from temp area into stack spot */
4659
4660 /* MAL - mainbuf is for 1st data source (command line?) and all nested use a single shared buffer? */
4661
4662 if (e.iop == &iostack[0])
4663 e.iop->argp->afbuf = &mainbuf;
4664 else
4665 e.iop->argp->afbuf = &sharedbuf;
4666
4667 /* MAL - if not a termimal AND (commandline OR readable file) then give it a buffer id? */
4668 /* This line appears to be active when running scripts from command line */
4669 if ((isatty(e.iop->argp->afile) == 0)
4670 && (e.iop == &iostack[0]
Denis Vlasenkoea620772006-10-14 02:23:43 +00004671 || lseek(e.iop->argp->afile, 0L, SEEK_CUR) != -1)) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00004672 if (++bufid == AFID_NOBUF) /* counter rollover check, AFID_NOBUF = 11111111 */
4673 bufid = AFID_ID; /* AFID_ID = 0 */
4674
4675 e.iop->argp->afid = bufid; /* assign buffer id */
Eric Andersen8401eea2004-08-04 19:16:54 +00004676 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004677
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004678 DBGPRINTF(("PUSHIO: iostack %p, e.iop %p, afbuf %p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00004679 iostack, e.iop, e.iop->argp->afbuf));
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004680 DBGPRINTF(("PUSHIO: mbuf %p, sbuf %p, bid %d, e.iop %p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00004681 &mainbuf, &sharedbuf, bufid, e.iop));
4682
Eric Andersenff9eee42001-06-29 04:57:14 +00004683 }
4684
Eric Andersen8401eea2004-08-04 19:16:54 +00004685 e.iop->prev = ~'\n';
Eric Andersenff9eee42001-06-29 04:57:14 +00004686 e.iop->peekc = 0;
4687 e.iop->xchar = 0;
4688 e.iop->nlcount = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004689
Eric Andersenff9eee42001-06-29 04:57:14 +00004690 if (fn == filechar || fn == linechar)
4691 e.iop->task = XIO;
Eric Andersen8401eea2004-08-04 19:16:54 +00004692 else if (fn == (int (*)(struct ioarg *)) gravechar
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004693 || fn == (int (*)(struct ioarg *)) qgravechar)
Eric Andersenff9eee42001-06-29 04:57:14 +00004694 e.iop->task = XGRAVE;
4695 else
4696 e.iop->task = XOTHER;
4697}
4698
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004699static struct io *setbase(struct io *ip)
Eric Andersenff9eee42001-06-29 04:57:14 +00004700{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004701 struct io *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004702
4703 xp = e.iobase;
4704 e.iobase = ip;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004705 return xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004706}
4707
4708/*
4709 * Input generating functions
4710 */
4711
4712/*
4713 * Produce the characters of a string, then a newline, then EOF.
4714 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004715static int nlchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004716{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004717 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004718
4719 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004720 return 0;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004721 c = *ap->aword++;
4722 if (c == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004723 ap->aword = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004724 return '\n';
Eric Andersenff9eee42001-06-29 04:57:14 +00004725 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004726 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004727}
4728
4729/*
4730 * Given a list of words, produce the characters
4731 * in them, with a space after each word.
4732 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004733static int wdchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004734{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004735 char c;
4736 char **wl;
Eric Andersenff9eee42001-06-29 04:57:14 +00004737
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004738 wl = ap->awordlist;
4739 if (wl == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004740 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004741 if (*wl != NULL) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004742 c = *(*wl)++;
4743 if (c != 0)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004744 return c & 0177;
Eric Andersenff9eee42001-06-29 04:57:14 +00004745 ap->awordlist++;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004746 return ' ';
Eric Andersenff9eee42001-06-29 04:57:14 +00004747 }
4748 ap->awordlist = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004749 return '\n';
Eric Andersenff9eee42001-06-29 04:57:14 +00004750}
4751
4752/*
4753 * Return the characters of a list of words,
4754 * producing a space between them.
4755 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004756static int dolchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004757{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004758 char *wp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004759
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004760 wp = *ap->awordlist++;
4761 if (wp != NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004762 PUSHIO(aword, wp, *ap->awordlist == NULL ? strchar : xxchar);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004763 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004764 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004765 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004766}
4767
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004768static int xxchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004769{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004770 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004771
4772 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004773 return 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004774 c = *ap->aword++;
4775 if (c == '\0') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004776 ap->aword = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004777 return ' ';
Eric Andersenff9eee42001-06-29 04:57:14 +00004778 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004779 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004780}
4781
4782/*
4783 * Produce the characters from a single word (string).
4784 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004785static int strchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004786{
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004787 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004788 return 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004789 return *ap->aword++;
Eric Andersenff9eee42001-06-29 04:57:14 +00004790}
4791
4792/*
4793 * Produce quoted characters from a single word (string).
4794 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004795static int qstrchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004796{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004797 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004798
Denis Vlasenkob2abef32007-01-01 18:18:04 +00004799 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004800 return 0;
Denis Vlasenkob2abef32007-01-01 18:18:04 +00004801 c = *ap->aword++;
4802 if (c)
4803 c |= QUOTE;
4804 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004805}
4806
4807/*
4808 * Return the characters from a file.
4809 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004810static int filechar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004811{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004812 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004813 char c;
4814 struct iobuf *bp = ap->afbuf;
4815
4816 if (ap->afid != AFID_NOBUF) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004817 i = (ap->afid != bp->id);
4818 if (i || bp->bufp == bp->ebufp) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004819 if (i)
Denis Vlasenkoea620772006-10-14 02:23:43 +00004820 lseek(ap->afile, ap->afpos, SEEK_SET);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004821
Eric Andersen8401eea2004-08-04 19:16:54 +00004822 i = safe_read(ap->afile, bp->buf, sizeof(bp->buf));
4823 if (i <= 0) {
4824 closef(ap->afile);
4825 return 0;
4826 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004827
Eric Andersen8401eea2004-08-04 19:16:54 +00004828 bp->id = ap->afid;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004829 bp->bufp = bp->buf;
4830 bp->ebufp = bp->bufp + i;
Eric Andersen8401eea2004-08-04 19:16:54 +00004831 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004832
Eric Andersen8401eea2004-08-04 19:16:54 +00004833 ap->afpos++;
4834 return *bp->bufp++ & 0177;
Eric Andersenff9eee42001-06-29 04:57:14 +00004835 }
Denis Vlasenko38f63192007-01-22 09:03:07 +00004836#if ENABLE_FEATURE_EDITING
Eric Andersen737f5fb2003-03-14 16:05:59 +00004837 if (interactive && isatty(ap->afile)) {
Denis Vlasenko55f30b02007-03-24 22:42:29 +00004838 /* moved to G: static char filechar_cmdbuf[BUFSIZ]; */
Eric Andersen8401eea2004-08-04 19:16:54 +00004839 static int position = 0, size = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004840
Eric Andersen8401eea2004-08-04 19:16:54 +00004841 while (size == 0 || position >= size) {
Denis Vlasenko55f30b02007-03-24 22:42:29 +00004842 read_line_input(current_prompt, filechar_cmdbuf, BUFSIZ, line_input_state);
4843 size = strlen(filechar_cmdbuf);
Eric Andersen8401eea2004-08-04 19:16:54 +00004844 position = 0;
4845 }
Denis Vlasenko55f30b02007-03-24 22:42:29 +00004846 c = filechar_cmdbuf[position];
Eric Andersen8401eea2004-08-04 19:16:54 +00004847 position++;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004848 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004849 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004850#endif
4851 i = safe_read(ap->afile, &c, sizeof(c));
4852 return i == sizeof(c) ? (c & 0x7f) : (closef(ap->afile), 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004853}
4854
4855/*
4856 * Return the characters from a here temp file.
4857 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004858static int herechar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004859{
4860 char c;
4861
Eric Andersenff9eee42001-06-29 04:57:14 +00004862 if (read(ap->afile, &c, sizeof(c)) != sizeof(c)) {
4863 close(ap->afile);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004864 c = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00004865 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004866 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004867}
4868
4869/*
4870 * Return the characters produced by a process (`...`).
4871 * Quote them if required, and remove any trailing newline characters.
4872 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004873static int gravechar(struct ioarg *ap, struct io *iop)
Eric Andersenff9eee42001-06-29 04:57:14 +00004874{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004875 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004876
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004877 c = qgravechar(ap, iop) & ~QUOTE;
4878 if (c == '\n')
Eric Andersenff9eee42001-06-29 04:57:14 +00004879 c = ' ';
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004880 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004881}
4882
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004883static int qgravechar(struct ioarg *ap, struct io *iop)
Eric Andersenff9eee42001-06-29 04:57:14 +00004884{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004885 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004886
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004887 DBGPRINTF3(("QGRAVECHAR: enter, ap=%p, iop=%p\n", ap, iop));
Eric Andersenff9eee42001-06-29 04:57:14 +00004888
4889 if (iop->xchar) {
4890 if (iop->nlcount) {
4891 iop->nlcount--;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004892 return '\n' | QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00004893 }
4894 c = iop->xchar;
4895 iop->xchar = 0;
4896 } else if ((c = filechar(ap)) == '\n') {
4897 iop->nlcount = 1;
4898 while ((c = filechar(ap)) == '\n')
4899 iop->nlcount++;
4900 iop->xchar = c;
4901 if (c == 0)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004902 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004903 iop->nlcount--;
4904 c = '\n';
4905 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004906 return c != 0 ? c | QUOTE : 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004907}
4908
4909/*
4910 * Return a single command (usually the first line) from a file.
4911 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004912static int linechar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004913{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004914 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004915
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004916 c = filechar(ap);
4917 if (c == '\n') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004918 if (!multiline) {
4919 closef(ap->afile);
Eric Andersen8401eea2004-08-04 19:16:54 +00004920 ap->afile = -1; /* illegal value */
Eric Andersenff9eee42001-06-29 04:57:14 +00004921 }
4922 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004923 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004924}
4925
Eric Andersenff9eee42001-06-29 04:57:14 +00004926/*
4927 * remap fd into Shell's fd space
4928 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004929static int remap(int fd)
Eric Andersenff9eee42001-06-29 04:57:14 +00004930{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004931 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004932 int map[NOFILE];
Eric Andersen12de6cf2004-08-04 19:19:10 +00004933 int newfd;
4934
Eric Andersen12de6cf2004-08-04 19:19:10 +00004935 DBGPRINTF(("REMAP: fd=%d, e.iofd=%d\n", fd, e.iofd));
Eric Andersenff9eee42001-06-29 04:57:14 +00004936
4937 if (fd < e.iofd) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004938 for (i = 0; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004939 map[i] = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004940
Eric Andersenff9eee42001-06-29 04:57:14 +00004941 do {
4942 map[fd] = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004943 newfd = dup(fd);
4944 fd = newfd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004945 } while (fd >= 0 && fd < e.iofd);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004946
Eric Andersen8401eea2004-08-04 19:16:54 +00004947 for (i = 0; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004948 if (map[i])
4949 close(i);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004950
Eric Andersenff9eee42001-06-29 04:57:14 +00004951 if (fd < 0)
4952 err("too many files open in shell");
4953 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004954
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004955 return fd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004956}
4957
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004958static int openpipe(int *pv)
Eric Andersenff9eee42001-06-29 04:57:14 +00004959{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004960 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004961
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004962 i = pipe(pv);
4963 if (i < 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00004964 err("can't create pipe - try again");
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004965 return i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004966}
4967
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004968static void closepipe(int *pv)
Eric Andersenff9eee42001-06-29 04:57:14 +00004969{
4970 if (pv != NULL) {
4971 close(*pv++);
4972 close(*pv);
4973 }
4974}
4975
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004976
Eric Andersenff9eee42001-06-29 04:57:14 +00004977/* -------- here.c -------- */
4978
4979/*
4980 * here documents
4981 */
4982
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004983static void markhere(char *s, struct ioword *iop)
Eric Andersenff9eee42001-06-29 04:57:14 +00004984{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004985 struct here *h, *lh;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004986
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004987 DBGPRINTF7(("MARKHERE: enter, s=%p\n", s));
Eric Andersenff9eee42001-06-29 04:57:14 +00004988
4989 h = (struct here *) space(sizeof(struct here));
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004990 if (h == NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00004991 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004992
Eric Andersenff9eee42001-06-29 04:57:14 +00004993 h->h_tag = evalstr(s, DOSUB);
4994 if (h->h_tag == 0)
4995 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004996
Eric Andersenff9eee42001-06-29 04:57:14 +00004997 h->h_iop = iop;
4998 iop->io_name = 0;
4999 h->h_next = NULL;
5000 if (inhere == 0)
5001 inhere = h;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00005002 else {
5003 for (lh = inhere; lh != NULL; lh = lh->h_next) {
Eric Andersenff9eee42001-06-29 04:57:14 +00005004 if (lh->h_next == 0) {
5005 lh->h_next = h;
5006 break;
5007 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00005008 }
5009 }
Eric Andersen8401eea2004-08-04 19:16:54 +00005010 iop->io_flag |= IOHERE | IOXHERE;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00005011 for (s = h->h_tag; *s; s++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00005012 if (*s & QUOTE) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005013 iop->io_flag &= ~IOXHERE;
5014 *s &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00005015 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00005016 }
Eric Andersenff9eee42001-06-29 04:57:14 +00005017 h->h_dosub = iop->io_flag & IOXHERE;
5018}
5019
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005020static void gethere(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00005021{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005022 struct here *h, *hp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005023
5024 DBGPRINTF7(("GETHERE: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00005025
5026 /* Scan here files first leaving inhere list in place */
5027 for (hp = h = inhere; h != NULL; hp = h, h = h->h_next)
Eric Andersen8401eea2004-08-04 19:16:54 +00005028 readhere(&h->h_iop->io_name, h->h_tag, h->h_dosub ? 0 : '\'');
Eric Andersenff9eee42001-06-29 04:57:14 +00005029
5030 /* Make inhere list active - keep list intact for scraphere */
5031 if (hp != NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005032 hp->h_next = acthere;
5033 acthere = inhere;
5034 inhere = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00005035 }
5036}
5037
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005038static void readhere(char **name, char *s, int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00005039{
5040 int tf;
5041 char tname[30] = ".msh_XXXXXX";
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005042 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00005043 jmp_buf ev;
Eric Andersen8401eea2004-08-04 19:16:54 +00005044 char myline[LINELIM + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00005045 char *thenext;
5046
Mike Frysinger02d8fa42006-05-05 20:32:31 +00005047 DBGPRINTF7(("READHERE: enter, name=%p, s=%p\n", name, s));
Eric Andersen12de6cf2004-08-04 19:19:10 +00005048
Eric Andersenff9eee42001-06-29 04:57:14 +00005049 tf = mkstemp(tname);
5050 if (tf < 0)
5051 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005052
Eric Andersenff9eee42001-06-29 04:57:14 +00005053 *name = strsave(tname, areanum);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00005054 errpt = ev;
5055 if (newenv(setjmp(errpt)) != 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00005056 unlink(tname);
5057 else {
Eric Andersen8401eea2004-08-04 19:16:54 +00005058 pushio(e.iop->argp, (int (*)(struct ioarg *)) e.iop->iofn);
Eric Andersenff9eee42001-06-29 04:57:14 +00005059 e.iobase = e.iop;
5060 for (;;) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005061 if (interactive && e.iop <= iostack) {
Denis Vlasenko38f63192007-01-22 09:03:07 +00005062#if ENABLE_FEATURE_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00005063 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00005064#else
Eric Andersen8401eea2004-08-04 19:16:54 +00005065 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00005066#endif
5067 }
5068 thenext = myline;
5069 while ((c = my_getc(ec)) != '\n' && c) {
5070 if (ec == '\'')
Eric Andersen8401eea2004-08-04 19:16:54 +00005071 c &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00005072 if (thenext >= &myline[LINELIM]) {
5073 c = 0;
5074 break;
5075 }
5076 *thenext++ = c;
5077 }
5078 *thenext = 0;
5079 if (strcmp(s, myline) == 0 || c == 0)
5080 break;
5081 *thenext++ = '\n';
Eric Andersen8401eea2004-08-04 19:16:54 +00005082 write(tf, myline, (int) (thenext - myline));
Eric Andersenff9eee42001-06-29 04:57:14 +00005083 }
5084 if (c == 0) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005085 prs("here document `");
5086 prs(s);
5087 err("' unclosed");
Eric Andersenff9eee42001-06-29 04:57:14 +00005088 }
5089 quitenv();
5090 }
5091 close(tf);
5092}
5093
5094/*
5095 * open here temp file.
5096 * if unquoted here, expand here temp file into second temp file.
5097 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005098static int herein(char *hname, int xdoll)
Eric Andersenff9eee42001-06-29 04:57:14 +00005099{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005100 int hf;
Eric Andersenff9eee42001-06-29 04:57:14 +00005101 int tf;
5102
5103#if __GNUC__
5104 /* Avoid longjmp clobbering */
5105 (void) &tf;
5106#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00005107 if (hname == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00005108 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005109
5110 DBGPRINTF7(("HEREIN: hname is %s, xdoll=%d\n", hname, xdoll));
5111
Eric Andersenff9eee42001-06-29 04:57:14 +00005112 hf = open(hname, 0);
5113 if (hf < 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00005114 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005115
Eric Andersenff9eee42001-06-29 04:57:14 +00005116 if (xdoll) {
5117 char c;
5118 char tname[30] = ".msh_XXXXXX";
5119 jmp_buf ev;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005120
Eric Andersenff9eee42001-06-29 04:57:14 +00005121 tf = mkstemp(tname);
5122 if (tf < 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00005123 return -1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00005124 errpt = ev;
5125 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00005126 PUSHIO(afile, hf, herechar);
5127 setbase(e.iop);
5128 while ((c = subgetc(0, 0)) != 0) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005129 c &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00005130 write(tf, &c, sizeof c);
5131 }
5132 quitenv();
5133 } else
5134 unlink(tname);
5135 close(tf);
5136 tf = open(tname, 0);
5137 unlink(tname);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00005138 return tf;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00005139 }
5140 return hf;
Eric Andersenff9eee42001-06-29 04:57:14 +00005141}
5142
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005143static void scraphere(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00005144{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005145 struct here *h;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005146
5147 DBGPRINTF7(("SCRAPHERE: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00005148
5149 for (h = inhere; h != NULL; h = h->h_next) {
5150 if (h->h_iop && h->h_iop->io_name)
Eric Andersen8401eea2004-08-04 19:16:54 +00005151 unlink(h->h_iop->io_name);
Eric Andersenff9eee42001-06-29 04:57:14 +00005152 }
5153 inhere = NULL;
5154}
5155
5156/* unlink here temp files before a freearea(area) */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005157static void freehere(int area)
Eric Andersenff9eee42001-06-29 04:57:14 +00005158{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005159 struct here *h, *hl;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005160
5161 DBGPRINTF6(("FREEHERE: enter, area=%d\n", area));
Eric Andersenff9eee42001-06-29 04:57:14 +00005162
5163 hl = NULL;
5164 for (h = acthere; h != NULL; h = h->h_next)
5165 if (getarea((char *) h) >= area) {
5166 if (h->h_iop->io_name != NULL)
5167 unlink(h->h_iop->io_name);
5168 if (hl == NULL)
5169 acthere = h->h_next;
5170 else
5171 hl->h_next = h->h_next;
5172 } else
5173 hl = h;
5174}
5175
5176
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005177/* -------- sh.c -------- */
5178/*
5179 * shell
5180 */
5181
Denis Vlasenko06af2162007-02-03 17:28:39 +00005182int msh_main(int argc, char **argv);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005183int msh_main(int argc, char **argv)
5184{
5185 int f;
5186 char *s;
5187 int cflag;
5188 char *name, **ap;
5189 int (*iof) (struct ioarg *);
5190
Denis Vlasenko55f30b02007-03-24 22:42:29 +00005191 PTR_TO_GLOBALS = xzalloc(sizeof(G));
5192 sharedbuf.id = AFID_NOBUF;
5193 mainbuf.id = AFID_NOBUF;
5194 e.linep = line;
5195 elinep = line + sizeof(line) - 5;
5196
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005197#if ENABLE_FEATURE_EDITING
5198 line_input_state = new_line_input_t(FOR_SHELL);
5199#endif
5200
5201 DBGPRINTF(("MSH_MAIN: argc %d, environ %p\n", argc, environ));
5202
5203 initarea();
5204 ap = environ;
5205 if (ap != NULL) {
5206 while (*ap)
5207 assign(*ap++, !COPYV);
5208 for (ap = environ; *ap;)
5209 export(lookup(*ap++));
5210 }
5211 closeall();
5212 areanum = 1;
5213
5214 shell = lookup("SHELL");
5215 if (shell->value == null)
5216 setval(shell, (char *)DEFAULT_SHELL);
5217 export(shell);
5218
5219 homedir = lookup("HOME");
5220 if (homedir->value == null)
5221 setval(homedir, "/");
5222 export(homedir);
5223
5224 setval(lookup("$"), putn(getpid()));
5225
5226 path = lookup("PATH");
5227 if (path->value == null) {
5228 if (geteuid() == 0)
5229 setval(path, "/sbin:/bin:/usr/sbin:/usr/bin");
5230 else
5231 setval(path, "/bin:/usr/bin");
5232 }
5233 export(path);
5234
5235 ifs = lookup("IFS");
5236 if (ifs->value == null)
5237 setval(ifs, " \t\n");
5238
5239#ifdef MSHDEBUG
5240 mshdbg_var = lookup("MSHDEBUG");
5241 if (mshdbg_var->value == null)
5242 setval(mshdbg_var, "0");
5243#endif
5244
5245 prompt = lookup("PS1");
5246#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
5247 if (prompt->value == null)
5248#endif
5249 setval(prompt, DEFAULT_USER_PROMPT);
5250 if (geteuid() == 0) {
5251 setval(prompt, DEFAULT_ROOT_PROMPT);
5252 prompt->status &= ~EXPORT;
5253 }
5254 cprompt = lookup("PS2");
5255#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
5256 if (cprompt->value == null)
5257#endif
5258 setval(cprompt, "> ");
5259
5260 iof = filechar;
5261 cflag = 0;
5262 name = *argv++;
5263 if (--argc >= 1) {
5264 if (argv[0][0] == '-' && argv[0][1] != '\0') {
5265 for (s = argv[0] + 1; *s; s++)
5266 switch (*s) {
5267 case 'c':
5268 prompt->status &= ~EXPORT;
5269 cprompt->status &= ~EXPORT;
5270 setval(prompt, "");
5271 setval(cprompt, "");
5272 cflag = 1;
5273 if (--argc > 0)
5274 PUSHIO(aword, *++argv, iof = nlchar);
5275 break;
5276
5277 case 'q':
5278 qflag = SIG_DFL;
5279 break;
5280
5281 case 's':
5282 /* standard input */
5283 break;
5284
5285 case 't':
5286 prompt->status &= ~EXPORT;
5287 setval(prompt, "");
5288 iof = linechar;
5289 break;
5290
5291 case 'i':
5292 interactive++;
5293 default:
5294 if (*s >= 'a' && *s <= 'z')
5295 flag[(int) *s]++;
5296 }
5297 } else {
5298 argv--;
5299 argc++;
5300 }
5301
5302 if (iof == filechar && --argc > 0) {
5303 setval(prompt, "");
5304 setval(cprompt, "");
5305 prompt->status &= ~EXPORT;
5306 cprompt->status &= ~EXPORT;
5307
5308/* Shell is non-interactive, activate printf-based debug */
5309#ifdef MSHDEBUG
5310 mshdbg = (int) (((char) (mshdbg_var->value[0])) - '0');
5311 if (mshdbg < 0)
5312 mshdbg = 0;
5313#endif
5314 DBGPRINTF(("MSH_MAIN: calling newfile()\n"));
5315
5316 name = *++argv;
5317 if (newfile(name))
5318 exit(1); /* Exit on error */
5319 }
5320 }
5321
5322 setdash();
5323
5324 /* This won't be true if PUSHIO has been called, say from newfile() above */
5325 if (e.iop < iostack) {
5326 PUSHIO(afile, 0, iof);
5327 if (isatty(0) && isatty(1) && !cflag) {
5328 interactive++;
5329#if !ENABLE_FEATURE_SH_EXTRA_QUIET
5330#ifdef MSHDEBUG
5331 printf("\n\n%s Built-in shell (msh with debug)\n", BB_BANNER);
5332#else
5333 printf("\n\n%s Built-in shell (msh)\n", BB_BANNER);
5334#endif
5335 printf("Enter 'help' for a list of built-in commands.\n\n");
5336#endif
5337 }
5338 }
5339
5340 signal(SIGQUIT, qflag);
5341 if (name && name[0] == '-') {
5342 interactive++;
5343 f = open(".profile", 0);
5344 if (f >= 0)
5345 next(remap(f));
5346 f = open("/etc/profile", 0);
5347 if (f >= 0)
5348 next(remap(f));
5349 }
5350 if (interactive)
5351 signal(SIGTERM, sig);
5352
5353 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
5354 signal(SIGINT, onintr);
5355 dolv = argv;
5356 dolc = argc;
5357 dolv[0] = name;
5358 if (dolc > 1) {
5359 for (ap = ++argv; --argc > 0;) {
5360 *ap = *argv++;
5361 if (assign(*ap, !COPYV)) {
5362 dolc--; /* keyword */
5363 } else {
5364 ap++;
5365 }
5366 }
5367 }
5368 setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc));
5369
5370 DBGPRINTF(("MSH_MAIN: begin FOR loop, interactive %d, e.iop %p, iostack %p\n", interactive, e.iop, iostack));
5371
5372 for (;;) {
5373 if (interactive && e.iop <= iostack) {
5374#if ENABLE_FEATURE_EDITING
5375 current_prompt = prompt->value;
5376#else
5377 prs(prompt->value);
5378#endif
5379 }
5380 onecommand();
5381 /* Ensure that getenv("PATH") stays current */
5382 setenv("PATH", path->value, 1);
5383 }
5384
5385 DBGPRINTF(("MSH_MAIN: returning.\n"));
5386}
5387
5388
Eric Andersenff9eee42001-06-29 04:57:14 +00005389/*
5390 * Copyright (c) 1987,1997, Prentice Hall
5391 * All rights reserved.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005392 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005393 * Redistribution and use of the MINIX operating system in source and
5394 * binary forms, with or without modification, are permitted provided
5395 * that the following conditions are met:
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005396 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005397 * Redistributions of source code must retain the above copyright
5398 * notice, this list of conditions and the following disclaimer.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005399 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005400 * Redistributions in binary form must reproduce the above
5401 * copyright notice, this list of conditions and the following
5402 * disclaimer in the documentation and/or other materials provided
5403 * with the distribution.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005404 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005405 * Neither the name of Prentice Hall nor the names of the software
5406 * authors or contributors may be used to endorse or promote
5407 * products derived from this software without specific prior
5408 * written permission.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005409 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005410 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND
5411 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
5412 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
5413 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
5414 * IN NO EVENT SHALL PRENTICE HALL OR ANY AUTHORS OR CONTRIBUTORS BE
5415 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
5416 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
5417 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
5418 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
5419 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
5420 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
5421 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5422 *
5423 */