blob: 63f365962e293ed744a97a57fd2923da46b5c4d0 [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 Vlasenko95cb3262007-04-09 03:06:34 +000016#include <sys/times.h>
17#include <setjmp.h>
Denis Vlasenko55f30b02007-03-24 22:42:29 +000018
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"
Denis Vlasenkoca525b42007-06-13 12:27:17 +000039# define bb_banner "busybox standalone"
Denis Vlasenko80d14be2007-04-10 23:03:30 +000040# define ENABLE_FEATURE_SH_STANDALONE 0
Mike Frysinger67a32ad2007-03-09 08:25:24 +000041# 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)
Denis Vlasenkoe376d452008-02-20 22:23:24 +000045# define nonblock_safe_read(fd,buf,count) read(fd,buf,count)
Mike Frysinger67a32ad2007-03-09 08:25:24 +000046# define NOT_LONE_DASH(s) ((s)[0] != '-' || (s)[1])
47# define LONE_CHAR(s,c) ((s)[0] == (c) && !(s)[1])
48# define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__))
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000049static int find_applet_by_name(const char *applet)
Mike Frysinger67a32ad2007-03-09 08:25:24 +000050{
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000051 return -1;
Mike Frysinger67a32ad2007-03-09 08:25:24 +000052}
Denis Vlasenko10457b92007-03-27 22:01:31 +000053static char *utoa_to_buf(unsigned n, char *buf, unsigned buflen)
Mike Frysinger67a32ad2007-03-09 08:25:24 +000054{
Denis Vlasenkoc86e0522007-03-20 11:30:28 +000055 unsigned i, out, res;
56 assert(sizeof(unsigned) == 4);
57 if (buflen) {
58 out = 0;
59 for (i = 1000000000; i; i /= 10) {
60 res = n / i;
61 if (res || out || i == 1) {
Denis Vlasenko4b924f32007-05-30 00:29:55 +000062 if (!--buflen) break;
63 out++;
64 n -= res*i;
65 *buf++ = '0' + res;
Denis Vlasenkoc86e0522007-03-20 11:30:28 +000066 }
67 }
Denis Vlasenkoc86e0522007-03-20 11:30:28 +000068 }
Denis Vlasenko10457b92007-03-27 22:01:31 +000069 return buf;
Mike Frysinger67a32ad2007-03-09 08:25:24 +000070}
Denis Vlasenko10457b92007-03-27 22:01:31 +000071static char *itoa_to_buf(int n, char *buf, unsigned buflen)
Mike Frysinger67a32ad2007-03-09 08:25:24 +000072{
Denis Vlasenkoc86e0522007-03-20 11:30:28 +000073 if (buflen && n < 0) {
74 n = -n;
75 *buf++ = '-';
76 buflen--;
77 }
Denis Vlasenko10457b92007-03-27 22:01:31 +000078 return utoa_to_buf((unsigned)n, buf, buflen);
Mike Frysinger67a32ad2007-03-09 08:25:24 +000079}
80static char local_buf[12];
81static char *itoa(int n)
82{
Denis Vlasenko10457b92007-03-27 22:01:31 +000083 *(itoa_to_buf(n, local_buf, sizeof(local_buf))) = '\0';
Denis Vlasenkoc86e0522007-03-20 11:30:28 +000084 return local_buf;
Mike Frysinger67a32ad2007-03-09 08:25:24 +000085}
86#else
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000087# include "busybox.h" /* for applet_names */
Mike Frysinger67a32ad2007-03-09 08:25:24 +000088#endif
Eric Andersenff9eee42001-06-29 04:57:14 +000089
Denis Vlasenko7e497522008-02-12 09:51:03 +000090//#define MSHDEBUG 4
Eric Andersen12de6cf2004-08-04 19:19:10 +000091
92#ifdef MSHDEBUG
Denis Vlasenko509697f2008-03-02 12:49:39 +000093static int mshdbg = MSHDEBUG;
Eric Andersen12de6cf2004-08-04 19:19:10 +000094
Denis Vlasenko51742f42007-04-12 00:32:05 +000095#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
Eric Andersen12de6cf2004-08-04 19:19:10 +0000106
Denis Vlasenko509697f2008-03-02 12:49:39 +0000107static int mshdbg_rc = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +0000108
Denis Vlasenko51742f42007-04-12 00:32:05 +0000109#define RCPRINTF(x) if (mshdbg_rc) printf x
Eric Andersen12de6cf2004-08-04 19:19:10 +0000110
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 */
Denis Vlasenko5f9468e2007-04-14 13:22:09 +0000155#define WAITSIG(s) ((s) & 0177)
156#define WAITVAL(s) (((s) >> 8) & 0377)
157#define WAITCORE(s) (((s) & 0200) != 0)
Eric Andersenff9eee42001-06-29 04:57:14 +0000158
159/*
Eric Andersenaff114c2004-04-14 17:51:38 +0000160 * library and system definitions
Eric Andersenff9eee42001-06-29 04:57:14 +0000161 */
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000162typedef void xint; /* base type of jmp_buf, for not broken compilers */
Eric Andersenff9eee42001-06-29 04:57:14 +0000163
164/*
165 * shell components
166 */
Eric Andersenff9eee42001-06-29 04:57:14 +0000167#define NOBLOCK ((struct op *)NULL)
168#define NOWORD ((char *)NULL)
169#define NOWORDS ((char **)NULL)
170#define NOPIPE ((int *)NULL)
171
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000172/*
173 * redirection
174 */
175struct ioword {
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +0000176 smallint io_flag; /* action (below) */
177 int io_fd; /* fd affected */
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000178 char *io_name; /* file name */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000179};
180
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000181#define IOREAD 1 /* < */
182#define IOHERE 2 /* << (here file) */
183#define IOWRITE 4 /* > */
184#define IOCAT 8 /* >> */
185#define IOXHERE 16 /* ${}, ` in << */
186#define IODUP 32 /* >&digit */
187#define IOCLOSE 64 /* >&- */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000188
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +0000189#define IODEFAULT (-1) /* "default" IO fd */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000190
191
Eric Andersenff9eee42001-06-29 04:57:14 +0000192/*
193 * Description of a command or an operation on commands.
194 * Might eventually use a union.
195 */
196struct op {
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +0000197 smallint op_type; /* operation type, see Txxxx below */
Denis Vlasenko509697f2008-03-02 12:49:39 +0000198 char **op_words; /* arguments to a command */
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000199 struct ioword **ioact; /* IO actions (eg, < > >>) */
Eric Andersenff9eee42001-06-29 04:57:14 +0000200 struct op *left;
201 struct op *right;
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000202 char *str; /* identifier for case and for */
Eric Andersenff9eee42001-06-29 04:57:14 +0000203};
204
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000205#define TCOM 1 /* command */
206#define TPAREN 2 /* (c-list) */
207#define TPIPE 3 /* a | b */
208#define TLIST 4 /* a [&;] b */
209#define TOR 5 /* || */
210#define TAND 6 /* && */
211#define TFOR 7
212#define TDO 8
213#define TCASE 9
214#define TIF 10
215#define TWHILE 11
216#define TUNTIL 12
217#define TELIF 13
218#define TPAT 14 /* pattern in case */
219#define TBRACE 15 /* {c-list} */
220#define TASYNC 16 /* c & */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000221/* Added to support "." file expansion */
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000222#define TDOT 17
Eric Andersen12de6cf2004-08-04 19:19:10 +0000223
224/* Strings for names to make debug easier */
"Vladimir N. Oleynik"ac973172005-09-22 14:38:17 +0000225#ifdef MSHDEBUG
Denis Vlasenkoe27f1562007-01-01 06:00:38 +0000226static const char *const T_CMD_NAMES[] = {
Eric Andersen12de6cf2004-08-04 19:19:10 +0000227 "PLACEHOLDER",
228 "TCOM",
229 "TPAREN",
230 "TPIPE",
231 "TLIST",
232 "TOR",
233 "TAND",
234 "TFOR",
235 "TDO",
236 "TCASE",
237 "TIF",
238 "TWHILE",
239 "TUNTIL",
240 "TELIF",
241 "TPAT",
242 "TBRACE",
243 "TASYNC",
244 "TDOT",
245};
"Vladimir N. Oleynik"ac973172005-09-22 14:38:17 +0000246#endif
Eric Andersenff9eee42001-06-29 04:57:14 +0000247
Denis Vlasenko5f9468e2007-04-14 13:22:09 +0000248#define AREASIZE (90000)
Eric Andersen12de6cf2004-08-04 19:19:10 +0000249
Eric Andersenff9eee42001-06-29 04:57:14 +0000250/*
251 * flags to control evaluation of words
252 */
Denis Vlasenko5f9468e2007-04-14 13:22:09 +0000253#define DOSUB 1 /* interpret $, `, and quotes */
254#define DOBLANK 2 /* perform blank interpretation */
255#define DOGLOB 4 /* interpret [?* */
256#define DOKEY 8 /* move words with `=' to 2nd arg. list */
257#define DOTRIM 16 /* trim resulting string */
Eric Andersenff9eee42001-06-29 04:57:14 +0000258
Denis Vlasenko5f9468e2007-04-14 13:22:09 +0000259#define DOALL (DOSUB|DOBLANK|DOGLOB|DOKEY|DOTRIM)
Eric Andersenff9eee42001-06-29 04:57:14 +0000260
Eric Andersenff9eee42001-06-29 04:57:14 +0000261
Eric Andersen8401eea2004-08-04 19:16:54 +0000262struct brkcon {
263 jmp_buf brkpt;
264 struct brkcon *nextlev;
265};
Eric Andersenff9eee42001-06-29 04:57:14 +0000266
Eric Andersen12de6cf2004-08-04 19:19:10 +0000267
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000268static smallint trapset; /* trap pending (signal number) */
Eric Andersenff9eee42001-06-29 04:57:14 +0000269
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000270static smallint yynerrs; /* yacc (flag) */
Eric Andersenff9eee42001-06-29 04:57:14 +0000271
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000272/* moved to G: static char line[LINELIM]; */
Eric Andersenff9eee42001-06-29 04:57:14 +0000273
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000274#if ENABLE_FEATURE_EDITING
275static char *current_prompt;
276static line_input_t *line_input_state;
277#endif
278
Eric Andersen12de6cf2004-08-04 19:19:10 +0000279
Eric Andersenff9eee42001-06-29 04:57:14 +0000280/*
281 * other functions
282 */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000283static const char *rexecve(char *c, char **v, char **envp);
Eric Andersen8401eea2004-08-04 19:16:54 +0000284static char *evalstr(char *cp, int f);
285static char *putn(int n);
Eric Andersen8401eea2004-08-04 19:16:54 +0000286static char *unquote(char *as);
Eric Andersen8401eea2004-08-04 19:16:54 +0000287static int rlookup(char *n);
288static struct wdblock *glob(char *cp, struct wdblock *wb);
289static int my_getc(int ec);
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +0000290static int subgetc(char ec, int quoted);
Eric Andersenfd7a4c82004-09-02 23:13:10 +0000291static char **makenv(int all, struct wdblock *wb);
Eric Andersen8401eea2004-08-04 19:16:54 +0000292static char **eval(char **ap, int f);
293static int setstatus(int s);
294static int waitfor(int lastpid, int canintr);
Eric Andersenff9eee42001-06-29 04:57:14 +0000295
Eric Andersen8401eea2004-08-04 19:16:54 +0000296static void onintr(int s); /* SIGINT handler */
Eric Andersenff9eee42001-06-29 04:57:14 +0000297
Eric Andersen8401eea2004-08-04 19:16:54 +0000298static int newenv(int f);
299static void quitenv(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000300static void next(int f);
301static void setdash(void);
302static void onecommand(void);
303static void runtrap(int i);
Eric Andersenff9eee42001-06-29 04:57:14 +0000304
Eric Andersen12de6cf2004-08-04 19:19:10 +0000305
Eric Andersenff9eee42001-06-29 04:57:14 +0000306/* -------- area stuff -------- */
307
Denis Vlasenko5f9468e2007-04-14 13:22:09 +0000308#define REGSIZE sizeof(struct region)
309#define GROWBY (256)
310/* #define SHRINKBY (64) */
311#undef SHRINKBY
312#define FREE (32767)
313#define BUSY (0)
314#define ALIGN (sizeof(int)-1)
Eric Andersenff9eee42001-06-29 04:57:14 +0000315
316
317struct region {
Eric Andersen8401eea2004-08-04 19:16:54 +0000318 struct region *next;
319 int area;
Eric Andersenff9eee42001-06-29 04:57:14 +0000320};
321
322
Eric Andersenff9eee42001-06-29 04:57:14 +0000323/* -------- grammar stuff -------- */
324typedef union {
Eric Andersen8401eea2004-08-04 19:16:54 +0000325 char *cp;
326 char **wp;
327 int i;
328 struct op *o;
Eric Andersenff9eee42001-06-29 04:57:14 +0000329} YYSTYPE;
Eric Andersen8401eea2004-08-04 19:16:54 +0000330
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000331#define WORD 256
332#define LOGAND 257
333#define LOGOR 258
334#define BREAK 259
335#define IF 260
336#define THEN 261
337#define ELSE 262
338#define ELIF 263
339#define FI 264
340#define CASE 265
341#define ESAC 266
342#define FOR 267
343#define WHILE 268
344#define UNTIL 269
345#define DO 270
346#define DONE 271
347#define IN 272
Eric Andersen12de6cf2004-08-04 19:19:10 +0000348/* Added for "." file expansion */
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000349#define DOT 273
Eric Andersen12de6cf2004-08-04 19:19:10 +0000350
Eric Andersenff9eee42001-06-29 04:57:14 +0000351#define YYERRCODE 300
352
353/* flags to yylex */
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000354#define CONTIN 01 /* skip new lines to complete command */
Eric Andersenff9eee42001-06-29 04:57:14 +0000355
Eric Andersen8401eea2004-08-04 19:16:54 +0000356static struct op *pipeline(int cf);
Eric Andersenff9eee42001-06-29 04:57:14 +0000357static struct op *andor(void);
358static struct op *c_list(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000359static int synio(int cf);
360static void musthave(int c, int cf);
Eric Andersenff9eee42001-06-29 04:57:14 +0000361static struct op *simple(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000362static struct op *nested(int type, int mark);
363static struct op *command(int cf);
364static struct op *dogroup(int onlydone);
Eric Andersenff9eee42001-06-29 04:57:14 +0000365static struct op *thenpart(void);
366static struct op *elsepart(void);
367static struct op *caselist(void);
368static struct op *casepart(void);
369static char **pattern(void);
370static char **wordlist(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000371static struct op *list(struct op *t1, struct op *t2);
372static struct op *block(int type, struct op *t1, struct op *t2, char **wp);
Eric Andersenff9eee42001-06-29 04:57:14 +0000373static struct op *newtp(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000374static struct op *namelist(struct op *t);
Eric Andersenff9eee42001-06-29 04:57:14 +0000375static char **copyw(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000376static void word(char *cp);
Eric Andersenff9eee42001-06-29 04:57:14 +0000377static struct ioword **copyio(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000378static struct ioword *io(int u, int f, char *cp);
Eric Andersen8401eea2004-08-04 19:16:54 +0000379static int yylex(int cf);
380static int collect(int c, int c1);
381static int dual(int c);
382static void diag(int ec);
383static char *tree(unsigned size);
Eric Andersenff9eee42001-06-29 04:57:14 +0000384
385/* -------- var.h -------- */
386
Eric Andersen8401eea2004-08-04 19:16:54 +0000387struct var {
388 char *value;
389 char *name;
390 struct var *next;
391 char status;
Eric Andersenff9eee42001-06-29 04:57:14 +0000392};
Eric Andersenff9eee42001-06-29 04:57:14 +0000393
Eric Andersen8401eea2004-08-04 19:16:54 +0000394#define COPYV 1 /* flag to setval, suggesting copy */
395#define RONLY 01 /* variable is read-only */
396#define EXPORT 02 /* variable is to be exported */
397#define GETCELL 04 /* name & value space was got with getcell */
Eric Andersenff9eee42001-06-29 04:57:14 +0000398
Eric Andersen8401eea2004-08-04 19:16:54 +0000399static int yyparse(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000400
Eric Andersen12de6cf2004-08-04 19:19:10 +0000401
Eric Andersenff9eee42001-06-29 04:57:14 +0000402/* -------- io.h -------- */
403/* io buffer */
404struct iobuf {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000405 unsigned id; /* buffer id */
406 char buf[512]; /* buffer */
407 char *bufp; /* pointer into buffer */
408 char *ebufp; /* pointer to end of buffer */
Eric Andersenff9eee42001-06-29 04:57:14 +0000409};
410
411/* possible arguments to an IO function */
412struct ioarg {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000413 const char *aword;
Eric Andersen8401eea2004-08-04 19:16:54 +0000414 char **awordlist;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000415 int afile; /* file descriptor */
416 unsigned afid; /* buffer id */
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000417 off_t afpos; /* file position */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000418 struct iobuf *afbuf; /* buffer for this file */
Eric Andersenff9eee42001-06-29 04:57:14 +0000419};
Eric Andersen8401eea2004-08-04 19:16:54 +0000420
Eric Andersenff9eee42001-06-29 04:57:14 +0000421/* an input generator's state */
Eric Andersen8401eea2004-08-04 19:16:54 +0000422struct io {
423 int (*iofn) (struct ioarg *, struct io *);
424 struct ioarg *argp;
425 int peekc;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000426 char prev; /* previous character read by readc() */
427 char nlcount; /* for `'s */
428 char xchar; /* for `'s */
429 char task; /* reason for pushed IO */
Eric Andersenff9eee42001-06-29 04:57:14 +0000430};
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000431/* ->task: */
432#define XOTHER 0 /* none of the below */
433#define XDOLL 1 /* expanding ${} */
434#define XGRAVE 2 /* expanding `'s */
435#define XIO 3 /* file IO */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000436
437
438/*
Eric Andersenff9eee42001-06-29 04:57:14 +0000439 * input generators for IO structure
440 */
Eric Andersen8401eea2004-08-04 19:16:54 +0000441static int nlchar(struct ioarg *ap);
442static int strchar(struct ioarg *ap);
443static int qstrchar(struct ioarg *ap);
444static int filechar(struct ioarg *ap);
445static int herechar(struct ioarg *ap);
446static int linechar(struct ioarg *ap);
447static int gravechar(struct ioarg *ap, struct io *iop);
448static int qgravechar(struct ioarg *ap, struct io *iop);
449static int dolchar(struct ioarg *ap);
450static int wdchar(struct ioarg *ap);
451static void scraphere(void);
452static void freehere(int area);
453static void gethere(void);
454static void markhere(char *s, struct ioword *iop);
455static int herein(char *hname, int xdoll);
456static int run(struct ioarg *argp, int (*f) (struct ioarg *));
Eric Andersenff9eee42001-06-29 04:57:14 +0000457
Eric Andersen12de6cf2004-08-04 19:19:10 +0000458
Eric Andersen8401eea2004-08-04 19:16:54 +0000459static int eofc(void);
460static int readc(void);
461static void unget(int c);
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +0000462static void ioecho(char c);
Eric Andersenff9eee42001-06-29 04:57:14 +0000463
Eric Andersen12de6cf2004-08-04 19:19:10 +0000464
Eric Andersenff9eee42001-06-29 04:57:14 +0000465/*
466 * IO control
467 */
Eric Andersen8401eea2004-08-04 19:16:54 +0000468static void pushio(struct ioarg *argp, int (*f) (struct ioarg *));
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000469#define PUSHIO(what,arg,gen) ((temparg.what = (arg)), pushio(&temparg,(gen)))
Eric Andersen8401eea2004-08-04 19:16:54 +0000470static int remap(int fd);
471static int openpipe(int *pv);
472static void closepipe(int *pv);
473static struct io *setbase(struct io *ip);
Eric Andersenff9eee42001-06-29 04:57:14 +0000474
Eric Andersenff9eee42001-06-29 04:57:14 +0000475/* -------- word.h -------- */
476
Eric Andersen8401eea2004-08-04 19:16:54 +0000477#define NSTART 16 /* default number of words to allow for initially */
Eric Andersenff9eee42001-06-29 04:57:14 +0000478
Eric Andersen8401eea2004-08-04 19:16:54 +0000479struct wdblock {
480 short w_bsize;
481 short w_nword;
Eric Andersenff9eee42001-06-29 04:57:14 +0000482 /* bounds are arbitrary */
Eric Andersen8401eea2004-08-04 19:16:54 +0000483 char *w_words[1];
Eric Andersenff9eee42001-06-29 04:57:14 +0000484};
485
Eric Andersen8401eea2004-08-04 19:16:54 +0000486static struct wdblock *addword(char *wd, struct wdblock *wb);
487static struct wdblock *newword(int nw);
488static char **getwords(struct wdblock *wb);
Eric Andersenff9eee42001-06-29 04:57:14 +0000489
Eric Andersenff9eee42001-06-29 04:57:14 +0000490/* -------- misc stuff -------- */
491
Denis Vlasenkofe218832008-03-01 09:35:39 +0000492static int dolabel(struct op *t, char **args);
493static int dohelp(struct op *t, char **args);
494static int dochdir(struct op *t, char **args);
495static int doshift(struct op *t, char **args);
496static int dologin(struct op *t, char **args);
497static int doumask(struct op *t, char **args);
498static int doexec(struct op *t, char **args);
499static int dodot(struct op *t, char **args);
500static int dowait(struct op *t, char **args);
501static int doread(struct op *t, char **args);
502static int doeval(struct op *t, char **args);
503static int dotrap(struct op *t, char **args);
504static int dobreak(struct op *t, char **args);
505static int doexit(struct op *t, char **args);
506static int doexport(struct op *t, char **args);
507static int doreadonly(struct op *t, char **args);
508static int doset(struct op *t, char **args);
509static int dotimes(struct op *t, char **args);
510static int docontinue(struct op *t, char **args);
511
Denis Vlasenko7e497522008-02-12 09:51:03 +0000512static int forkexec(struct op *t, int *pin, int *pout, int no_fork, char **wp);
513static int execute(struct op *t, int *pin, int *pout, int no_fork);
Eric Andersen8401eea2004-08-04 19:16:54 +0000514static int iosetup(struct ioword *iop, int pipein, int pipeout);
Eric Andersen8401eea2004-08-04 19:16:54 +0000515static void brkset(struct brkcon *bc);
Eric Andersen8401eea2004-08-04 19:16:54 +0000516static int getsig(char *s);
517static void setsig(int n, sighandler_t f);
518static int getn(char *as);
Eric Andersen8401eea2004-08-04 19:16:54 +0000519static int brkcontin(char *cp, int val);
Eric Andersen8401eea2004-08-04 19:16:54 +0000520static void rdexp(char **wp, void (*f) (struct var *), int key);
521static void badid(char *s);
Eric Andersen8401eea2004-08-04 19:16:54 +0000522static void varput(char *s, int out);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000523static int expand(const char *cp, struct wdblock **wbp, int f);
Eric Andersen8401eea2004-08-04 19:16:54 +0000524static char *blank(int f);
525static int dollar(int quoted);
526static int grave(int quoted);
527static void globname(char *we, char *pp);
528static char *generate(char *start1, char *end1, char *middle, char *end);
529static int anyspcl(struct wdblock *wb);
Eric Andersen8401eea2004-08-04 19:16:54 +0000530static void readhere(char **name, char *s, int ec);
Eric Andersen8401eea2004-08-04 19:16:54 +0000531static int xxchar(struct ioarg *ap);
Eric Andersenff9eee42001-06-29 04:57:14 +0000532
Eric Andersen8401eea2004-08-04 19:16:54 +0000533struct here {
534 char *h_tag;
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000535 char h_dosub;
Eric Andersen8401eea2004-08-04 19:16:54 +0000536 struct ioword *h_iop;
537 struct here *h_next;
Eric Andersenff9eee42001-06-29 04:57:14 +0000538};
539
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000540static const char *const signame[] = {
Eric Andersenff9eee42001-06-29 04:57:14 +0000541 "Signal 0",
542 "Hangup",
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000543 NULL, /* interrupt */
Eric Andersenff9eee42001-06-29 04:57:14 +0000544 "Quit",
545 "Illegal instruction",
546 "Trace/BPT trap",
547 "Abort",
548 "Bus error",
549 "Floating Point Exception",
550 "Killed",
551 "SIGUSR1",
552 "SIGSEGV",
553 "SIGUSR2",
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000554 NULL, /* broken pipe */
Eric Andersenff9eee42001-06-29 04:57:14 +0000555 "Alarm clock",
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000556 "Terminated"
Eric Andersenff9eee42001-06-29 04:57:14 +0000557};
Eric Andersen8401eea2004-08-04 19:16:54 +0000558
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000559
Denis Vlasenkofe218832008-03-01 09:35:39 +0000560typedef int (*builtin_func_ptr)(struct op *, char **);
Denis Vlasenko7e497522008-02-12 09:51:03 +0000561
Eric Andersen1c039232001-07-07 00:05:55 +0000562struct builtincmd {
563 const char *name;
Denis Vlasenko7e497522008-02-12 09:51:03 +0000564 builtin_func_ptr builtinfunc;
Eric Andersenff9eee42001-06-29 04:57:14 +0000565};
Denis Vlasenko7e497522008-02-12 09:51:03 +0000566
Eric Andersen8401eea2004-08-04 19:16:54 +0000567static const struct builtincmd builtincmds[] = {
Denis Vlasenko95cb3262007-04-09 03:06:34 +0000568 { "." , dodot },
569 { ":" , dolabel },
570 { "break" , dobreak },
571 { "cd" , dochdir },
572 { "continue", docontinue },
573 { "eval" , doeval },
574 { "exec" , doexec },
575 { "exit" , doexit },
576 { "export" , doexport },
577 { "help" , dohelp },
578 { "login" , dologin },
579 { "newgrp" , dologin },
580 { "read" , doread },
581 { "readonly", doreadonly },
582 { "set" , doset },
583 { "shift" , doshift },
584 { "times" , dotimes },
585 { "trap" , dotrap },
586 { "umask" , doumask },
587 { "wait" , dowait },
588 { NULL , NULL },
Eric Andersenff9eee42001-06-29 04:57:14 +0000589};
590
"Vladimir N. Oleynik"ac973172005-09-22 14:38:17 +0000591static struct op *scantree(struct op *);
Denis Vlasenko68404f12008-03-17 09:00:54 +0000592static struct op *dowholefile(int /*, int*/);
Eric Andersen12de6cf2004-08-04 19:19:10 +0000593
Eric Andersen12de6cf2004-08-04 19:19:10 +0000594
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000595/* Globals */
Eric Andersen8401eea2004-08-04 19:16:54 +0000596static char **dolv;
597static int dolc;
598static int exstat;
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000599static smallint gflg; /* (seems to be a parse error indicator) */
600static smallint interactive; /* Is this an interactive shell */
601static smallint execflg;
602static smallint isbreak; /* "break" statement was seen */
603static int multiline; /* '\n' changed to ';' (counter) */
604static struct op *outtree; /* result from parser */
Eric Andersen8401eea2004-08-04 19:16:54 +0000605static xint *failpt;
606static xint *errpt;
607static struct brkcon *brklist;
Eric Andersen8401eea2004-08-04 19:16:54 +0000608static struct wdblock *wdlist;
609static struct wdblock *iolist;
Eric Andersen12de6cf2004-08-04 19:19:10 +0000610
611#ifdef MSHDEBUG
612static struct var *mshdbg_var;
613#endif
Eric Andersen8401eea2004-08-04 19:16:54 +0000614static struct var *vlist; /* dictionary */
615static struct var *homedir; /* home directory */
616static struct var *prompt; /* main prompt */
617static struct var *cprompt; /* continuation prompt */
618static struct var *path; /* search path for commands */
619static struct var *shell; /* shell to interpret command files */
620static struct var *ifs; /* field separators */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000621
Denis Vlasenko95cb3262007-04-09 03:06:34 +0000622static int areanum; /* current allocation area */
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000623static smallint intr; /* interrupt pending (bool) */
624static smallint heedint = 1; /* heed interrupt signals (bool) */
Eric Andersen8401eea2004-08-04 19:16:54 +0000625static int inparse;
Denis Vlasenko95cb3262007-04-09 03:06:34 +0000626static char *null = (char*)""; /* null value for variable */
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +0000627static void (*qflag)(int) = SIG_IGN;
Eric Andersen8401eea2004-08-04 19:16:54 +0000628static int startl;
629static int peeksym;
630static int nlseen;
631static int iounit = IODEFAULT;
632static YYSTYPE yylval;
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000633static char *elinep; /* done in main(): = line + sizeof(line) - 5 */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000634
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000635static struct here *inhere; /* list of hear docs while parsing */
636static struct here *acthere; /* list of active here documents */
637static struct region *areabot; /* bottom of area */
638static struct region *areatop; /* top of area */
639static struct region *areanxt; /* starting point of scan */
Eric Andersen8401eea2004-08-04 19:16:54 +0000640static void *brktop;
641static void *brkaddr;
Eric Andersenff9eee42001-06-29 04:57:14 +0000642
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000643#define AFID_NOBUF (~0)
644#define AFID_ID 0
645
646
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000647/*
648 * parsing & execution environment
649 */
650struct env {
651 char *linep;
652 struct io *iobase;
653 struct io *iop;
654 xint *errpt; /* void * */
655 int iofd;
656 struct env *oenv;
657};
658
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000659
660struct globals {
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000661 struct env global_env;
662 struct ioarg temparg; // = { .afid = AFID_NOBUF }; /* temporary for PUSHIO */
663 unsigned bufid; // = AFID_ID; /* buffer id counter */
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000664 char ourtrap[_NSIG + 1];
665 char *trap[_NSIG + 1];
666 struct iobuf sharedbuf; /* in main(): set to { AFID_NOBUF } */
667 struct iobuf mainbuf; /* in main(): set to { AFID_NOBUF } */
668 struct ioarg ioargstack[NPUSH];
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000669 /*
670 * flags:
671 * -e: quit on error
672 * -k: look for name=value everywhere on command line
673 * -n: no execution
674 * -t: exit after reading and executing one command
675 * -v: echo as read
676 * -x: trace
677 * -u: unset variables net diagnostic
678 */
679 char flags['z' - 'a' + 1];
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000680 char filechar_cmdbuf[BUFSIZ];
681 char line[LINELIM];
682 char child_cmd[LINELIM];
Denis Vlasenkoab801872007-12-02 08:35:37 +0000683
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000684 struct io iostack[NPUSH];
685
Denis Vlasenkoab801872007-12-02 08:35:37 +0000686 char grave__var_name[LINELIM];
687 char grave__alt_value[LINELIM];
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000688};
689
690#define G (*ptr_to_globals)
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000691#define global_env (G.global_env )
692#define temparg (G.temparg )
693#define bufid (G.bufid )
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000694#define ourtrap (G.ourtrap )
695#define trap (G.trap )
696#define sharedbuf (G.sharedbuf )
697#define mainbuf (G.mainbuf )
698#define ioargstack (G.ioargstack )
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000699/* this looks weird, but is OK ... we index FLAG with 'a'...'z' */
700#define FLAG (G.flags - 'a' )
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000701#define filechar_cmdbuf (G.filechar_cmdbuf)
702#define line (G.line )
703#define child_cmd (G.child_cmd )
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000704#define iostack (G.iostack )
Denis Vlasenkoab801872007-12-02 08:35:37 +0000705#define INIT_G() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000706 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000707 global_env.linep = line; \
708 global_env.iobase = iostack; \
709 global_env.iop = iostack - 1; \
710 global_env.iofd = FDBASE; \
711 temparg.afid = AFID_NOBUF; \
712 bufid = AFID_ID; \
Denis Vlasenkoab801872007-12-02 08:35:37 +0000713} while (0)
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000714
715
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000716/* in substitution */
717#define INSUB() (global_env.iop->task == XGRAVE || global_env.iop->task == XDOLL)
718
719#define RUN(what, arg, gen) ((temparg.what = (arg)), run(&temparg, (gen)))
720
Eric Andersen12de6cf2004-08-04 19:19:10 +0000721#ifdef MSHDEBUG
Denis Vlasenko509697f2008-03-02 12:49:39 +0000722static void print_tree(struct op *head)
Eric Andersen12de6cf2004-08-04 19:19:10 +0000723{
724 if (head == NULL) {
725 DBGPRINTF(("PRINT_TREE: no tree\n"));
726 return;
727 }
728
Mike Frysinger02d8fa42006-05-05 20:32:31 +0000729 DBGPRINTF(("NODE: %p, left %p, right %p\n", head, head->left,
Eric Andersen12de6cf2004-08-04 19:19:10 +0000730 head->right));
731
732 if (head->left)
733 print_tree(head->left);
734
735 if (head->right)
736 print_tree(head->right);
Eric Andersen12de6cf2004-08-04 19:19:10 +0000737}
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000738#endif /* MSHDEBUG */
739
740
741/*
742 * IO functions
743 */
744static void prs(const char *s)
745{
746 if (*s)
747 write(2, s, strlen(s));
748}
749
750static void prn(unsigned u)
751{
752 prs(itoa(u));
753}
754
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000755static void echo(char **wp)
756{
757 int i;
758
759 prs("+");
760 for (i = 0; wp[i]; i++) {
761 if (i)
762 prs(" ");
763 prs(wp[i]);
764 }
765 prs("\n");
766}
767
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000768static void closef(int i)
769{
770 if (i > 2)
771 close(i);
772}
773
774static void closeall(void)
775{
776 int u;
777
778 for (u = NUFILE; u < NOFILE;)
779 close(u++);
780}
Eric Andersen12de6cf2004-08-04 19:19:10 +0000781
Eric Andersenff9eee42001-06-29 04:57:14 +0000782
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000783/* fail but return to process next command */
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000784static void fail(void) ATTRIBUTE_NORETURN;
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000785static void fail(void)
786{
787 longjmp(failpt, 1);
788 /* NOTREACHED */
789}
Eric Andersenff9eee42001-06-29 04:57:14 +0000790
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000791/* abort shell (or fail in subshell) */
792static void leave(void) ATTRIBUTE_NORETURN;
793static void leave(void)
794{
795 DBGPRINTF(("LEAVE: leave called!\n"));
796
797 if (execflg)
798 fail();
799 scraphere();
800 freehere(1);
801 runtrap(0);
802 _exit(exstat);
803 /* NOTREACHED */
804}
805
806static void warn(const char *s)
807{
808 if (*s) {
809 prs(s);
810 exstat = -1;
811 }
812 prs("\n");
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +0000813 if (FLAG['e'])
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000814 leave();
815}
816
817static void err(const char *s)
818{
819 warn(s);
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +0000820 if (FLAG['n'])
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000821 return;
822 if (!interactive)
823 leave();
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000824 if (global_env.errpt)
825 longjmp(global_env.errpt, 1);
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000826 closeall();
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000827 global_env.iop = global_env.iobase = iostack;
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000828}
829
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000830
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000831/* -------- area.c -------- */
832
Eric Andersenff9eee42001-06-29 04:57:14 +0000833/*
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000834 * All memory between (char *)areabot and (char *)(areatop+1) is
835 * exclusively administered by the area management routines.
836 * It is assumed that sbrk() and brk() manipulate the high end.
Eric Andersenff9eee42001-06-29 04:57:14 +0000837 */
838
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000839#define sbrk(X) ({ \
840 void * __q = (void *)-1; \
841 if (brkaddr + (int)(X) < brktop) { \
842 __q = brkaddr; \
843 brkaddr += (int)(X); \
844 } \
845 __q; \
846})
Eric Andersenff9eee42001-06-29 04:57:14 +0000847
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000848static void initarea(void)
Eric Andersenff9eee42001-06-29 04:57:14 +0000849{
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000850 brkaddr = xmalloc(AREASIZE);
851 brktop = brkaddr + AREASIZE;
Eric Andersenff9eee42001-06-29 04:57:14 +0000852
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000853 while ((long) sbrk(0) & ALIGN)
854 sbrk(1);
855 areabot = (struct region *) sbrk(REGSIZE);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +0000856
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000857 areabot->next = areabot;
858 areabot->area = BUSY;
859 areatop = areabot;
860 areanxt = areabot;
Eric Andersenff9eee42001-06-29 04:57:14 +0000861}
862
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000863static char *getcell(unsigned nbytes)
864{
865 int nregio;
866 struct region *p, *q;
867 int i;
868
869 if (nbytes == 0) {
870 puts("getcell(0)");
871 abort();
872 }
873 /* silly and defeats the algorithm */
874 /*
875 * round upwards and add administration area
876 */
877 nregio = (nbytes + (REGSIZE - 1)) / REGSIZE + 1;
878 p = areanxt;
879 for (;;) {
880 if (p->area > areanum) {
881 /*
882 * merge free cells
883 */
884 while ((q = p->next)->area > areanum && q != areanxt)
885 p->next = q->next;
886 /*
887 * exit loop if cell big enough
888 */
889 if (q >= p + nregio)
890 goto found;
891 }
892 p = p->next;
893 if (p == areanxt)
894 break;
895 }
896 i = nregio >= GROWBY ? nregio : GROWBY;
897 p = (struct region *) sbrk(i * REGSIZE);
898 if (p == (struct region *) -1)
899 return NULL;
900 p--;
901 if (p != areatop) {
902 puts("not contig");
903 abort(); /* allocated areas are contiguous */
904 }
905 q = p + i;
906 p->next = q;
907 p->area = FREE;
908 q->next = areabot;
909 q->area = BUSY;
910 areatop = q;
911 found:
912 /*
913 * we found a FREE area big enough, pointed to by 'p', and up to 'q'
914 */
915 areanxt = p + nregio;
916 if (areanxt < q) {
917 /*
918 * split into requested area and rest
919 */
920 if (areanxt + 1 > q) {
921 puts("OOM");
922 abort(); /* insufficient space left for admin */
923 }
924 areanxt->next = q;
925 areanxt->area = FREE;
926 p->next = areanxt;
927 }
928 p->area = areanum;
929 return (char *) (p + 1);
930}
931
932static void freecell(char *cp)
933{
934 struct region *p;
935
936 p = (struct region *) cp;
937 if (p != NULL) {
938 p--;
939 if (p < areanxt)
940 areanxt = p;
941 p->area = FREE;
942 }
943}
944#define DELETE(obj) freecell((char *)obj)
945
946static void freearea(int a)
947{
948 struct region *p, *top;
949
950 top = areatop;
951 for (p = areabot; p != top; p = p->next)
952 if (p->area >= a)
953 p->area = FREE;
954}
955
956static void setarea(char *cp, int a)
957{
958 struct region *p;
959
960 p = (struct region *) cp;
961 if (p != NULL)
962 (p - 1)->area = a;
963}
964
965static int getarea(char *cp)
966{
967 return ((struct region *) cp - 1)->area;
968}
969
970static void garbage(void)
971{
972 struct region *p, *q, *top;
973
974 top = areatop;
975 for (p = areabot; p != top; p = p->next) {
976 if (p->area > areanum) {
977 while ((q = p->next)->area > areanum)
978 p->next = q->next;
979 areanxt = p;
980 }
981 }
982#ifdef SHRINKBY
983 if (areatop >= q + SHRINKBY && q->area > areanum) {
984 brk((char *) (q + 1));
985 q->next = areabot;
986 q->area = BUSY;
987 areatop = q;
988 }
989#endif
990}
991
Denis Vlasenko509697f2008-03-02 12:49:39 +0000992static void *get_space(int n)
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000993{
994 char *cp;
995
996 cp = getcell(n);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000997 if (cp == NULL)
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000998 err("out of string space");
999 return cp;
1000}
1001
1002static char *strsave(const char *s, int a)
1003{
1004 char *cp;
1005
Denis Vlasenko509697f2008-03-02 12:49:39 +00001006 cp = get_space(strlen(s) + 1);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001007 if (cp == NULL) {
1008// FIXME: I highly doubt this is good.
1009 return (char*)"";
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001010 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001011 setarea(cp, a);
1012 strcpy(cp, s);
1013 return cp;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001014}
1015
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001016
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001017/* -------- var.c -------- */
1018
1019static int eqname(const char *n1, const char *n2)
1020{
1021 for (; *n1 != '=' && *n1 != '\0'; n1++)
1022 if (*n2++ != *n1)
1023 return 0;
1024 return *n2 == '\0' || *n2 == '=';
1025}
1026
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001027static const char *findeq(const char *cp)
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001028{
1029 while (*cp != '\0' && *cp != '=')
1030 cp++;
1031 return cp;
1032}
1033
1034/*
1035 * Find the given name in the dictionary
1036 * and return its value. If the name was
1037 * not previously there, enter it now and
1038 * return a null value.
1039 */
1040static struct var *lookup(const char *n)
1041{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001042// FIXME: dirty hack
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001043 static struct var dummy;
1044
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001045 struct var *vp;
1046 const char *cp;
1047 char *xp;
1048 int c;
1049
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001050 if (isdigit(*n)) {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001051 dummy.name = (char*)n;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001052 for (c = 0; isdigit(*n) && c < 1000; n++)
1053 c = c * 10 + *n - '0';
1054 dummy.status = RONLY;
1055 dummy.value = (c <= dolc ? dolv[c] : null);
1056 return &dummy;
1057 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001058
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001059 for (vp = vlist; vp; vp = vp->next)
1060 if (eqname(vp->name, n))
1061 return vp;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001062
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001063 cp = findeq(n);
Denis Vlasenko509697f2008-03-02 12:49:39 +00001064 vp = get_space(sizeof(*vp));
1065 if (vp == 0 || (vp->name = get_space((int) (cp - n) + 2)) == NULL) {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001066 dummy.name = dummy.value = (char*)"";
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001067 return &dummy;
1068 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001069
1070 xp = vp->name;
1071 while ((*xp = *n++) != '\0' && *xp != '=')
1072 xp++;
1073 *xp++ = '=';
1074 *xp = '\0';
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001075 setarea((char *) vp, 0);
1076 setarea((char *) vp->name, 0);
1077 vp->value = null;
1078 vp->next = vlist;
1079 vp->status = GETCELL;
1080 vlist = vp;
1081 return vp;
1082}
1083
1084/*
1085 * if name is not NULL, it must be
1086 * a prefix of the space `val',
1087 * and end with `='.
1088 * this is all so that exporting
1089 * values is reasonably painless.
1090 */
1091static void nameval(struct var *vp, const char *val, const char *name)
1092{
1093 const char *cp;
1094 char *xp;
1095 int fl;
1096
1097 if (vp->status & RONLY) {
1098 xp = vp->name;
1099 while (*xp && *xp != '=')
Denis Vlasenko4daad902007-09-27 10:20:47 +00001100 fputc(*xp++, stderr);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001101 err(" is read-only");
1102 return;
1103 }
1104 fl = 0;
1105 if (name == NULL) {
Denis Vlasenko509697f2008-03-02 12:49:39 +00001106 xp = get_space(strlen(vp->name) + strlen(val) + 2);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001107 if (xp == NULL)
1108 return;
1109 /* make string: name=value */
1110 setarea(xp, 0);
1111 name = xp;
1112 cp = vp->name;
1113 while ((*xp = *cp++) != '\0' && *xp != '=')
1114 xp++;
1115 *xp++ = '=';
1116 strcpy(xp, val);
1117 val = xp;
1118 fl = GETCELL;
1119 }
1120 if (vp->status & GETCELL)
1121 freecell(vp->name); /* form new string `name=value' */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001122 vp->name = (char*)name;
1123 vp->value = (char*)val;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001124 vp->status |= fl;
1125}
1126
1127/*
1128 * give variable at `vp' the value `val'.
1129 */
1130static void setval(struct var *vp, const char *val)
1131{
1132 nameval(vp, val, NULL);
1133}
1134
1135static void export(struct var *vp)
1136{
1137 vp->status |= EXPORT;
1138}
1139
1140static void ronly(struct var *vp)
1141{
1142 if (isalpha(vp->name[0]) || vp->name[0] == '_') /* not an internal symbol */
1143 vp->status |= RONLY;
1144}
1145
1146static int isassign(const char *s)
1147{
1148 unsigned char c;
1149 DBGPRINTF7(("ISASSIGN: enter, s=%s\n", s));
1150
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001151 c = *s;
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001152 /* no isalpha() - we shouldn't use locale */
1153 /* c | 0x20 - lowercase (Latin) letters */
1154 if (c != '_' && (unsigned)((c|0x20) - 'a') > 25)
1155 /* not letter */
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001156 return 0;
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001157
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001158 while (1) {
1159 c = *++s;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001160 if (c == '=')
1161 return 1;
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001162 if (c == '\0')
1163 return 0;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001164 if (c != '_'
1165 && (unsigned)(c - '0') > 9 /* not number */
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001166 && (unsigned)((c|0x20) - 'a') > 25 /* not letter */
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001167 ) {
1168 return 0;
1169 }
1170 }
1171}
1172
1173static int assign(const char *s, int cf)
1174{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001175 const char *cp;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001176 struct var *vp;
1177
1178 DBGPRINTF7(("ASSIGN: enter, s=%s, cf=%d\n", s, cf));
1179
1180 if (!isalpha(*s) && *s != '_')
1181 return 0;
1182 for (cp = s; *cp != '='; cp++)
1183 if (*cp == '\0' || (!isalnum(*cp) && *cp != '_'))
1184 return 0;
1185 vp = lookup(s);
1186 nameval(vp, ++cp, cf == COPYV ? NULL : s);
1187 if (cf != COPYV)
1188 vp->status &= ~GETCELL;
1189 return 1;
1190}
1191
1192static int checkname(char *cp)
1193{
1194 DBGPRINTF7(("CHECKNAME: enter, cp=%s\n", cp));
1195
1196 if (!isalpha(*cp++) && *(cp - 1) != '_')
1197 return 0;
1198 while (*cp)
1199 if (!isalnum(*cp++) && *(cp - 1) != '_')
1200 return 0;
1201 return 1;
1202}
1203
1204static void putvlist(int f, int out)
1205{
1206 struct var *vp;
1207
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001208 for (vp = vlist; vp; vp = vp->next) {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001209 if (vp->status & f && (isalpha(*vp->name) || *vp->name == '_')) {
1210 if (vp->status & EXPORT)
1211 write(out, "export ", 7);
1212 if (vp->status & RONLY)
1213 write(out, "readonly ", 9);
1214 write(out, vp->name, (int) (findeq(vp->name) - vp->name));
1215 write(out, "\n", 1);
1216 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001217 }
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001218}
1219
1220
1221/*
1222 * trap handling
1223 */
1224static void sig(int i)
1225{
1226 trapset = i;
1227 signal(i, sig);
1228}
1229
1230static void runtrap(int i)
1231{
1232 char *trapstr;
1233
1234 trapstr = trap[i];
1235 if (trapstr == NULL)
1236 return;
1237
1238 if (i == 0)
1239 trap[i] = NULL;
1240
1241 RUN(aword, trapstr, nlchar);
1242}
1243
1244
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001245static void setdash(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001246{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001247 char *cp;
1248 int c;
Eric Andersen8401eea2004-08-04 19:16:54 +00001249 char m['z' - 'a' + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00001250
1251 cp = m;
Eric Andersen8401eea2004-08-04 19:16:54 +00001252 for (c = 'a'; c <= 'z'; c++)
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00001253 if (FLAG[c])
Eric Andersenff9eee42001-06-29 04:57:14 +00001254 *cp++ = c;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001255 *cp = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00001256 setval(lookup("-"), m);
1257}
1258
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001259static int newfile(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00001260{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001261 int f;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001262
1263 DBGPRINTF7(("NEWFILE: opening %s\n", s));
Eric Andersenff9eee42001-06-29 04:57:14 +00001264
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001265 f = 0;
Denis Vlasenko9f739442006-12-16 23:49:13 +00001266 if (NOT_LONE_DASH(s)) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001267 DBGPRINTF(("NEWFILE: s is %s\n", s));
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00001268 f = open(s, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00001269 if (f < 0) {
1270 prs(s);
1271 err(": cannot open");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001272 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001273 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001274 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001275
Eric Andersenff9eee42001-06-29 04:57:14 +00001276 next(remap(f));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001277 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001278}
1279
Eric Andersen12de6cf2004-08-04 19:19:10 +00001280
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001281struct op *scantree(struct op *head)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001282{
1283 struct op *dotnode;
1284
1285 if (head == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001286 return NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001287
1288 if (head->left != NULL) {
1289 dotnode = scantree(head->left);
1290 if (dotnode)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001291 return dotnode;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001292 }
1293
1294 if (head->right != NULL) {
1295 dotnode = scantree(head->right);
1296 if (dotnode)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001297 return dotnode;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001298 }
1299
Denis Vlasenko509697f2008-03-02 12:49:39 +00001300 if (head->op_words == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001301 return NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001302
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001303 DBGPRINTF5(("SCANTREE: checking node %p\n", head));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001304
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001305 if ((head->op_type != TDOT) && LONE_CHAR(head->op_words[0], '.')) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001306 DBGPRINTF5(("SCANTREE: dot found in node %p\n", head));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001307 return head;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001308 }
1309
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001310 return NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001311}
1312
1313
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001314static void onecommand(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001315{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001316 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00001317 jmp_buf m1;
1318
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001319 DBGPRINTF(("ONECOMMAND: enter, outtree=%p\n", outtree));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001320
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001321 while (global_env.oenv)
Eric Andersenff9eee42001-06-29 04:57:14 +00001322 quitenv();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001323
Eric Andersenff9eee42001-06-29 04:57:14 +00001324 areanum = 1;
1325 freehere(areanum);
1326 freearea(areanum);
1327 garbage();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001328 wdlist = NULL;
1329 iolist = NULL;
1330 global_env.errpt = NULL;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001331 global_env.linep = line;
Eric Andersenff9eee42001-06-29 04:57:14 +00001332 yynerrs = 0;
1333 multiline = 0;
1334 inparse = 1;
1335 intr = 0;
1336 execflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001337
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001338 failpt = m1;
1339 setjmp(failpt); /* Bruce Evans' fix */
1340 failpt = m1;
1341 if (setjmp(failpt) || yyparse() || intr) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001342 DBGPRINTF(("ONECOMMAND: this is not good.\n"));
1343
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001344 while (global_env.oenv)
Eric Andersenff9eee42001-06-29 04:57:14 +00001345 quitenv();
1346 scraphere();
1347 if (!interactive && intr)
1348 leave();
1349 inparse = 0;
1350 intr = 0;
1351 return;
1352 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001353
Eric Andersenff9eee42001-06-29 04:57:14 +00001354 inparse = 0;
1355 brklist = 0;
1356 intr = 0;
1357 execflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001358
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00001359 if (!FLAG['n']) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001360 DBGPRINTF(("ONECOMMAND: calling execute, t=outtree=%p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00001361 outtree));
Denis Vlasenko7e497522008-02-12 09:51:03 +00001362 execute(outtree, NOPIPE, NOPIPE, /* no_fork: */ 0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001363 }
1364
Eric Andersenff9eee42001-06-29 04:57:14 +00001365 if (!interactive && intr) {
1366 execflg = 0;
1367 leave();
1368 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001369
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001370 i = trapset;
1371 if (i != 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001372 trapset = 0;
1373 runtrap(i);
1374 }
1375}
1376
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001377static int newenv(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00001378{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001379 struct env *ep;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001380
1381 DBGPRINTF(("NEWENV: f=%d (indicates quitenv and return)\n", f));
Eric Andersenff9eee42001-06-29 04:57:14 +00001382
1383 if (f) {
1384 quitenv();
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001385 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001386 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001387
Denis Vlasenko509697f2008-03-02 12:49:39 +00001388 ep = get_space(sizeof(*ep));
Eric Andersenff9eee42001-06-29 04:57:14 +00001389 if (ep == NULL) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001390 while (global_env.oenv)
Eric Andersenff9eee42001-06-29 04:57:14 +00001391 quitenv();
1392 fail();
1393 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001394 *ep = global_env;
1395 global_env.oenv = ep;
1396 global_env.errpt = errpt;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001397
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001398 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001399}
1400
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001401static void quitenv(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001402{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001403 struct env *ep;
1404 int fd;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001405
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001406 DBGPRINTF(("QUITENV: global_env.oenv=%p\n", global_env.oenv));
Eric Andersenff9eee42001-06-29 04:57:14 +00001407
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001408 ep = global_env.oenv;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001409 if (ep != NULL) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001410 fd = global_env.iofd;
1411 global_env = *ep;
Eric Andersenff9eee42001-06-29 04:57:14 +00001412 /* should close `'d files */
1413 DELETE(ep);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001414 while (--fd >= global_env.iofd)
Eric Andersenff9eee42001-06-29 04:57:14 +00001415 close(fd);
1416 }
1417}
1418
1419/*
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001420 * Is character c in s?
Eric Andersenff9eee42001-06-29 04:57:14 +00001421 */
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001422static int any(int c, const char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00001423{
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001424 while (*s)
1425 if (*s++ == c)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001426 return 1;
1427 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001428}
1429
1430/*
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001431 * Is any character from s1 in s2?
Eric Andersenff9eee42001-06-29 04:57:14 +00001432 */
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001433static int anys(const char *s1, const char *s2)
Eric Andersenff9eee42001-06-29 04:57:14 +00001434{
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001435 while (*s1)
1436 if (any(*s1++, s2))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001437 return 1;
1438 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001439}
1440
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001441static char *putn(int n)
Eric Andersenff9eee42001-06-29 04:57:14 +00001442{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001443 return itoa(n);
Eric Andersenff9eee42001-06-29 04:57:14 +00001444}
1445
Eric Andersen8401eea2004-08-04 19:16:54 +00001446static void next(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00001447{
1448 PUSHIO(afile, f, filechar);
1449}
1450
Denis Vlasenko68404f12008-03-17 09:00:54 +00001451static void onintr(int s ATTRIBUTE_UNUSED) /* ANSI C requires a parameter */
Eric Andersenff9eee42001-06-29 04:57:14 +00001452{
1453 signal(SIGINT, onintr);
1454 intr = 1;
1455 if (interactive) {
1456 if (inparse) {
1457 prs("\n");
1458 fail();
1459 }
Eric Andersen8401eea2004-08-04 19:16:54 +00001460 } else if (heedint) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001461 execflg = 0;
1462 leave();
1463 }
1464}
1465
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001466
Eric Andersenff9eee42001-06-29 04:57:14 +00001467/* -------- gmatch.c -------- */
1468/*
1469 * int gmatch(string, pattern)
1470 * char *string, *pattern;
1471 *
1472 * Match a pattern as in sh(1).
1473 */
1474
1475#define CMASK 0377
1476#define QUOTE 0200
Denis Vlasenko55f30b02007-03-24 22:42:29 +00001477#define QMASK (CMASK & ~QUOTE)
Eric Andersen8401eea2004-08-04 19:16:54 +00001478#define NOT '!' /* might use ^ */
Eric Andersenff9eee42001-06-29 04:57:14 +00001479
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001480static const char *cclass(const char *p, int sub)
1481{
1482 int c, d, not, found;
1483
1484 not = (*p == NOT);
1485 if (not != 0)
1486 p++;
1487 found = not;
1488 do {
1489 if (*p == '\0')
1490 return NULL;
1491 c = *p & CMASK;
1492 if (p[1] == '-' && p[2] != ']') {
1493 d = p[2] & CMASK;
1494 p++;
1495 } else
1496 d = c;
1497 if (c == sub || (c <= sub && sub <= d))
1498 found = !not;
1499 } while (*++p != ']');
1500 return found ? p + 1 : NULL;
1501}
1502
1503static int gmatch(const char *s, const char *p)
Eric Andersenff9eee42001-06-29 04:57:14 +00001504{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001505 int sc, pc;
Eric Andersenff9eee42001-06-29 04:57:14 +00001506
1507 if (s == NULL || p == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001508 return 0;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001509
Eric Andersenff9eee42001-06-29 04:57:14 +00001510 while ((pc = *p++ & CMASK) != '\0') {
1511 sc = *s++ & QMASK;
1512 switch (pc) {
1513 case '[':
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001514 p = cclass(p, sc);
1515 if (p == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001516 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001517 break;
1518
1519 case '?':
1520 if (sc == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001521 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001522 break;
1523
1524 case '*':
1525 s--;
1526 do {
1527 if (*p == '\0' || gmatch(s, p))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001528 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001529 } while (*s++ != '\0');
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001530 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001531
1532 default:
Eric Andersen8401eea2004-08-04 19:16:54 +00001533 if (sc != (pc & ~QUOTE))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001534 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001535 }
1536 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001537 return *s == '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00001538}
1539
Eric Andersenff9eee42001-06-29 04:57:14 +00001540
Eric Andersenff9eee42001-06-29 04:57:14 +00001541/* -------- csyn.c -------- */
1542/*
1543 * shell: syntax (C version)
1544 */
1545
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001546static void yyerror(const char *s) ATTRIBUTE_NORETURN;
1547static void yyerror(const char *s)
1548{
Denis Vlasenko648b44f2008-02-12 06:04:06 +00001549 yynerrs = 1;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001550 if (interactive && global_env.iop <= iostack) {
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001551 multiline = 0;
Denis Vlasenko648b44f2008-02-12 06:04:06 +00001552 while (eofc() == 0 && yylex(0) != '\n')
1553 continue;
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001554 }
1555 err(s);
1556 fail();
1557}
1558
1559static void zzerr(void) ATTRIBUTE_NORETURN;
1560static void zzerr(void)
1561{
1562 yyerror("syntax error");
1563}
1564
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001565int yyparse(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001566{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001567 DBGPRINTF7(("YYPARSE: enter...\n"));
1568
Eric Andersen8401eea2004-08-04 19:16:54 +00001569 startl = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001570 peeksym = 0;
1571 yynerrs = 0;
1572 outtree = c_list();
1573 musthave('\n', 0);
Denis Vlasenko648b44f2008-02-12 06:04:06 +00001574 return yynerrs; /* 0/1 */
Eric Andersenff9eee42001-06-29 04:57:14 +00001575}
1576
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001577static struct op *pipeline(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001578{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001579 struct op *t, *p;
1580 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001581
1582 DBGPRINTF7(("PIPELINE: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001583
1584 t = command(cf);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001585
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001586 DBGPRINTF9(("PIPELINE: t=%p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001587
Eric Andersenff9eee42001-06-29 04:57:14 +00001588 if (t != NULL) {
1589 while ((c = yylex(0)) == '|') {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001590 p = command(CONTIN);
1591 if (p == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001592 DBGPRINTF8(("PIPELINE: error!\n"));
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001593 zzerr();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001594 }
1595
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001596 if (t->op_type != TPAREN && t->op_type != TCOM) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001597 /* shell statement */
1598 t = block(TPAREN, t, NOBLOCK, NOWORDS);
1599 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001600
Eric Andersenff9eee42001-06-29 04:57:14 +00001601 t = block(TPIPE, t, p, NOWORDS);
1602 }
1603 peeksym = c;
1604 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001605
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001606 DBGPRINTF7(("PIPELINE: returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001607 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001608}
1609
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001610static struct op *andor(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001611{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001612 struct op *t, *p;
1613 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001614
1615 DBGPRINTF7(("ANDOR: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001616
1617 t = pipeline(0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001618
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001619 DBGPRINTF9(("ANDOR: t=%p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001620
Eric Andersenff9eee42001-06-29 04:57:14 +00001621 if (t != NULL) {
1622 while ((c = yylex(0)) == LOGAND || c == LOGOR) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001623 p = pipeline(CONTIN);
1624 if (p == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001625 DBGPRINTF8(("ANDOR: error!\n"));
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001626 zzerr();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001627 }
1628
Eric Andersen8401eea2004-08-04 19:16:54 +00001629 t = block(c == LOGAND ? TAND : TOR, t, p, NOWORDS);
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001630 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001631
Eric Andersenff9eee42001-06-29 04:57:14 +00001632 peeksym = c;
1633 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001634
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001635 DBGPRINTF7(("ANDOR: returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001636 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001637}
1638
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001639static struct op *c_list(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001640{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001641 struct op *t, *p;
1642 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001643
1644 DBGPRINTF7(("C_LIST: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001645
1646 t = andor();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001647
Eric Andersenff9eee42001-06-29 04:57:14 +00001648 if (t != NULL) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001649 peeksym = yylex(0);
1650 if (peeksym == '&')
Eric Andersenff9eee42001-06-29 04:57:14 +00001651 t = block(TASYNC, t, NOBLOCK, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001652
Eric Andersen8401eea2004-08-04 19:16:54 +00001653 while ((c = yylex(0)) == ';' || c == '&'
Denis Vlasenko509697f2008-03-02 12:49:39 +00001654 || (multiline && c == '\n')
1655 ) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001656 p = andor();
1657 if (p== NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001658 return t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001659
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001660 peeksym = yylex(0);
1661 if (peeksym == '&')
Eric Andersenff9eee42001-06-29 04:57:14 +00001662 p = block(TASYNC, p, NOBLOCK, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001663
Eric Andersenff9eee42001-06-29 04:57:14 +00001664 t = list(t, p);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001665 } /* WHILE */
1666
Eric Andersenff9eee42001-06-29 04:57:14 +00001667 peeksym = c;
1668 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001669 /* IF */
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001670 DBGPRINTF7(("C_LIST: returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001671 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001672}
1673
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001674static int synio(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001675{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001676 struct ioword *iop;
1677 int i;
1678 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001679
1680 DBGPRINTF7(("SYNIO: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001681
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001682 c = yylex(cf);
1683 if (c != '<' && c != '>') {
Eric Andersenff9eee42001-06-29 04:57:14 +00001684 peeksym = c;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001685 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001686 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001687
Eric Andersenff9eee42001-06-29 04:57:14 +00001688 i = yylval.i;
1689 musthave(WORD, 0);
1690 iop = io(iounit, i, yylval.cp);
1691 iounit = IODEFAULT;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001692
Eric Andersenff9eee42001-06-29 04:57:14 +00001693 if (i & IOHERE)
1694 markhere(yylval.cp, iop);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001695
1696 DBGPRINTF7(("SYNIO: returning 1\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001697 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001698}
1699
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001700static void musthave(int c, int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001701{
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001702 peeksym = yylex(cf);
1703 if (peeksym != c) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001704 DBGPRINTF7(("MUSTHAVE: error!\n"));
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001705 zzerr();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001706 }
1707
Eric Andersenff9eee42001-06-29 04:57:14 +00001708 peeksym = 0;
1709}
1710
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001711static struct op *simple(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001712{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001713 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001714
1715 t = NULL;
1716 for (;;) {
1717 switch (peeksym = yylex(0)) {
1718 case '<':
1719 case '>':
1720 (void) synio(0);
1721 break;
1722
1723 case WORD:
1724 if (t == NULL) {
1725 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001726 t->op_type = TCOM;
Eric Andersenff9eee42001-06-29 04:57:14 +00001727 }
1728 peeksym = 0;
1729 word(yylval.cp);
1730 break;
1731
1732 default:
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001733 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001734 }
1735 }
1736}
1737
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001738static struct op *nested(int type, int mark)
Eric Andersenff9eee42001-06-29 04:57:14 +00001739{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001740 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001741
1742 DBGPRINTF3(("NESTED: enter, type=%d, mark=%d\n", type, mark));
Eric Andersenff9eee42001-06-29 04:57:14 +00001743
1744 multiline++;
1745 t = c_list();
1746 musthave(mark, 0);
1747 multiline--;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001748 return block(type, t, NOBLOCK, NOWORDS);
Eric Andersenff9eee42001-06-29 04:57:14 +00001749}
1750
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001751static struct op *command(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001752{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001753 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001754 struct wdblock *iosave;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001755 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001756
1757 DBGPRINTF(("COMMAND: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001758
1759 iosave = iolist;
1760 iolist = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001761
Eric Andersenff9eee42001-06-29 04:57:14 +00001762 if (multiline)
1763 cf |= CONTIN;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001764
Eric Andersenff9eee42001-06-29 04:57:14 +00001765 while (synio(cf))
1766 cf = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001767
1768 c = yylex(cf);
1769
1770 switch (c) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001771 default:
1772 peeksym = c;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001773 t = simple();
1774 if (t == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001775 if (iolist == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001776 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001777 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001778 t->op_type = TCOM;
Eric Andersenff9eee42001-06-29 04:57:14 +00001779 }
1780 break;
1781
1782 case '(':
1783 t = nested(TPAREN, ')');
1784 break;
1785
1786 case '{':
1787 t = nested(TBRACE, '}');
1788 break;
1789
1790 case FOR:
1791 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001792 t->op_type = TFOR;
Eric Andersenff9eee42001-06-29 04:57:14 +00001793 musthave(WORD, 0);
1794 startl = 1;
1795 t->str = yylval.cp;
1796 multiline++;
Denis Vlasenko509697f2008-03-02 12:49:39 +00001797 t->op_words = wordlist();
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001798 c = yylex(0);
1799 if (c != '\n' && c != ';')
Eric Andersenff9eee42001-06-29 04:57:14 +00001800 peeksym = c;
1801 t->left = dogroup(0);
1802 multiline--;
1803 break;
1804
1805 case WHILE:
1806 case UNTIL:
1807 multiline++;
1808 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001809 t->op_type = (c == WHILE ? TWHILE : TUNTIL);
Eric Andersenff9eee42001-06-29 04:57:14 +00001810 t->left = c_list();
1811 t->right = dogroup(1);
Denis Vlasenko509697f2008-03-02 12:49:39 +00001812 /* t->op_words = NULL; - newtp() did this */
Eric Andersenff9eee42001-06-29 04:57:14 +00001813 multiline--;
1814 break;
1815
1816 case CASE:
1817 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001818 t->op_type = TCASE;
Eric Andersenff9eee42001-06-29 04:57:14 +00001819 musthave(WORD, 0);
1820 t->str = yylval.cp;
1821 startl++;
1822 multiline++;
1823 musthave(IN, CONTIN);
1824 startl++;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001825
Eric Andersenff9eee42001-06-29 04:57:14 +00001826 t->left = caselist();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001827
Eric Andersenff9eee42001-06-29 04:57:14 +00001828 musthave(ESAC, 0);
1829 multiline--;
1830 break;
1831
1832 case IF:
1833 multiline++;
1834 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001835 t->op_type = TIF;
Eric Andersenff9eee42001-06-29 04:57:14 +00001836 t->left = c_list();
1837 t->right = thenpart();
1838 musthave(FI, 0);
1839 multiline--;
1840 break;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001841
1842 case DOT:
1843 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001844 t->op_type = TDOT;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001845
Denis Vlasenko509697f2008-03-02 12:49:39 +00001846 musthave(WORD, 0); /* gets name of file */
Eric Andersen12de6cf2004-08-04 19:19:10 +00001847 DBGPRINTF7(("COMMAND: DOT clause, yylval.cp is %s\n", yylval.cp));
1848
Denis Vlasenko509697f2008-03-02 12:49:39 +00001849 word(yylval.cp); /* add word to wdlist */
1850 word(NOWORD); /* terminate wdlist */
1851 t->op_words = copyw(); /* dup wdlist */
Eric Andersen12de6cf2004-08-04 19:19:10 +00001852 break;
1853
Eric Andersenff9eee42001-06-29 04:57:14 +00001854 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001855
Denis Vlasenko509697f2008-03-02 12:49:39 +00001856 while (synio(0))
1857 continue;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001858
Eric Andersenff9eee42001-06-29 04:57:14 +00001859 t = namelist(t);
1860 iolist = iosave;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001861
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001862 DBGPRINTF(("COMMAND: returning %p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001863
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001864 return t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001865}
1866
Denis Vlasenko68404f12008-03-17 09:00:54 +00001867static struct op *dowholefile(int type /*, int mark*/)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001868{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001869 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001870
Denis Vlasenko68404f12008-03-17 09:00:54 +00001871 DBGPRINTF(("DOWHOLEFILE: enter, type=%d\n", type /*, mark*/));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001872
1873 multiline++;
1874 t = c_list();
1875 multiline--;
1876 t = block(type, t, NOBLOCK, NOWORDS);
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001877 DBGPRINTF(("DOWHOLEFILE: return t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001878 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001879}
1880
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001881static struct op *dogroup(int onlydone)
Eric Andersenff9eee42001-06-29 04:57:14 +00001882{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001883 int c;
1884 struct op *mylist;
Eric Andersenff9eee42001-06-29 04:57:14 +00001885
1886 c = yylex(CONTIN);
1887 if (c == DONE && onlydone)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001888 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001889 if (c != DO)
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001890 zzerr();
Eric Andersenff9eee42001-06-29 04:57:14 +00001891 mylist = c_list();
1892 musthave(DONE, 0);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001893 return mylist;
Eric Andersenff9eee42001-06-29 04:57:14 +00001894}
1895
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001896static struct op *thenpart(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001897{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001898 int c;
1899 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001900
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001901 c = yylex(0);
1902 if (c != THEN) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001903 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001904 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001905 }
1906 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001907 /*t->op_type = 0; - newtp() did this */
Eric Andersenff9eee42001-06-29 04:57:14 +00001908 t->left = c_list();
1909 if (t->left == NULL)
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001910 zzerr();
Eric Andersenff9eee42001-06-29 04:57:14 +00001911 t->right = elsepart();
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001912 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001913}
1914
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001915static struct op *elsepart(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001916{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001917 int c;
1918 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001919
1920 switch (c = yylex(0)) {
1921 case ELSE:
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001922 t = c_list();
1923 if (t == NULL)
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001924 zzerr();
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001925 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001926
1927 case ELIF:
1928 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001929 t->op_type = TELIF;
Eric Andersenff9eee42001-06-29 04:57:14 +00001930 t->left = c_list();
1931 t->right = thenpart();
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001932 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001933
1934 default:
1935 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001936 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001937 }
1938}
1939
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001940static struct op *caselist(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001941{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001942 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001943
1944 t = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001945 while ((peeksym = yylex(CONTIN)) != ESAC) {
1946 DBGPRINTF(("CASELIST, doing yylex, peeksym=%d\n", peeksym));
Eric Andersenff9eee42001-06-29 04:57:14 +00001947 t = list(t, casepart());
Eric Andersen12de6cf2004-08-04 19:19:10 +00001948 }
1949
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001950 DBGPRINTF(("CASELIST, returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001951 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001952}
1953
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001954static struct op *casepart(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001955{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001956 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001957
1958 DBGPRINTF7(("CASEPART: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001959
1960 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001961 t->op_type = TPAT;
Denis Vlasenko509697f2008-03-02 12:49:39 +00001962 t->op_words = pattern();
Eric Andersenff9eee42001-06-29 04:57:14 +00001963 musthave(')', 0);
1964 t->left = c_list();
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001965 peeksym = yylex(CONTIN);
1966 if (peeksym != ESAC)
Eric Andersenff9eee42001-06-29 04:57:14 +00001967 musthave(BREAK, CONTIN);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001968
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001969 DBGPRINTF7(("CASEPART: made newtp(TPAT, t=%p)\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001970
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001971 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001972}
1973
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001974static char **pattern(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001975{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001976 int c, cf;
Eric Andersenff9eee42001-06-29 04:57:14 +00001977
1978 cf = CONTIN;
1979 do {
1980 musthave(WORD, cf);
1981 word(yylval.cp);
1982 cf = 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001983 c = yylex(0);
1984 } while (c == '|');
Eric Andersenff9eee42001-06-29 04:57:14 +00001985 peeksym = c;
1986 word(NOWORD);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001987
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001988 return copyw();
Eric Andersenff9eee42001-06-29 04:57:14 +00001989}
1990
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001991static char **wordlist(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001992{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001993 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00001994
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001995 c = yylex(0);
1996 if (c != IN) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001997 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001998 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001999 }
2000 startl = 0;
2001 while ((c = yylex(0)) == WORD)
2002 word(yylval.cp);
2003 word(NOWORD);
2004 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002005 return copyw();
Eric Andersenff9eee42001-06-29 04:57:14 +00002006}
2007
2008/*
2009 * supporting functions
2010 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002011static struct op *list(struct op *t1, struct op *t2)
Eric Andersenff9eee42001-06-29 04:57:14 +00002012{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002013 DBGPRINTF7(("LIST: enter, t1=%p, t2=%p\n", t1, t2));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002014
Eric Andersenff9eee42001-06-29 04:57:14 +00002015 if (t1 == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002016 return t2;
Eric Andersenff9eee42001-06-29 04:57:14 +00002017 if (t2 == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002018 return t1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002019
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002020 return block(TLIST, t1, t2, NOWORDS);
Eric Andersenff9eee42001-06-29 04:57:14 +00002021}
2022
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002023static struct op *block(int type, struct op *t1, struct op *t2, char **wp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002024{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002025 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002026
2027 DBGPRINTF7(("BLOCK: enter, type=%d (%s)\n", type, T_CMD_NAMES[type]));
Eric Andersenff9eee42001-06-29 04:57:14 +00002028
2029 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002030 t->op_type = type;
Eric Andersenff9eee42001-06-29 04:57:14 +00002031 t->left = t1;
2032 t->right = t2;
Denis Vlasenko509697f2008-03-02 12:49:39 +00002033 t->op_words = wp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002034
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002035 DBGPRINTF7(("BLOCK: inserted %p between %p and %p\n", t, t1, t2));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002036
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002037 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002038}
2039
Eric Andersen12de6cf2004-08-04 19:19:10 +00002040/* See if given string is a shell multiline (FOR, IF, etc) */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002041static int rlookup(char *n)
Eric Andersenff9eee42001-06-29 04:57:14 +00002042{
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002043 struct res {
2044 char r_name[6];
2045 int16_t r_val;
2046 };
2047 static const struct res restab[] = {
2048 { "for" , FOR },
2049 { "case" , CASE },
2050 { "esac" , ESAC },
2051 { "while", WHILE },
2052 { "do" , DO },
2053 { "done" , DONE },
2054 { "if" , IF },
2055 { "in" , IN },
2056 { "then" , THEN },
2057 { "else" , ELSE },
2058 { "elif" , ELIF },
2059 { "until", UNTIL },
2060 { "fi" , FI },
2061 { ";;" , BREAK },
2062 { "||" , LOGOR },
2063 { "&&" , LOGAND },
2064 { "{" , '{' },
2065 { "}" , '}' },
2066 { "." , DOT },
2067 { },
2068 };
2069
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002070 const struct res *rp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002071
2072 DBGPRINTF7(("RLOOKUP: enter, n is %s\n", n));
Eric Andersenff9eee42001-06-29 04:57:14 +00002073
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002074 for (rp = restab; rp->r_name[0]; rp++)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002075 if (strcmp(rp->r_name, n) == 0) {
2076 DBGPRINTF7(("RLOOKUP: match, returning %d\n", rp->r_val));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002077 return rp->r_val; /* Return numeric code for shell multiline */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002078 }
2079
2080 DBGPRINTF7(("RLOOKUP: NO match, returning 0\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002081 return 0; /* Not a shell multiline */
Eric Andersenff9eee42001-06-29 04:57:14 +00002082}
2083
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002084static struct op *newtp(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002085{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002086 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002087
Eric Andersen8401eea2004-08-04 19:16:54 +00002088 t = (struct op *) tree(sizeof(*t));
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002089 memset(t, 0, sizeof(*t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002090
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002091 DBGPRINTF3(("NEWTP: allocated %p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002092
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002093 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002094}
2095
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002096static struct op *namelist(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00002097{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002098 DBGPRINTF7(("NAMELIST: enter, t=%p, type %s, iolist=%p\n", t,
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002099 T_CMD_NAMES[t->op_type], iolist));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002100
Eric Andersenff9eee42001-06-29 04:57:14 +00002101 if (iolist) {
Eric Andersen8401eea2004-08-04 19:16:54 +00002102 iolist = addword((char *) NULL, iolist);
Eric Andersenff9eee42001-06-29 04:57:14 +00002103 t->ioact = copyio();
2104 } else
2105 t->ioact = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002106
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002107 if (t->op_type != TCOM) {
2108 if (t->op_type != TPAREN && t->ioact != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002109 t = block(TPAREN, t, NOBLOCK, NOWORDS);
2110 t->ioact = t->left->ioact;
2111 t->left->ioact = NULL;
2112 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002113 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002114 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002115
Eric Andersenff9eee42001-06-29 04:57:14 +00002116 word(NOWORD);
Denis Vlasenko509697f2008-03-02 12:49:39 +00002117 t->op_words = copyw();
Eric Andersen12de6cf2004-08-04 19:19:10 +00002118
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002119 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002120}
2121
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002122static char **copyw(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002123{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002124 char **wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00002125
2126 wd = getwords(wdlist);
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002127 wdlist = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002128 return wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00002129}
2130
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002131static void word(char *cp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002132{
2133 wdlist = addword(cp, wdlist);
2134}
2135
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002136static struct ioword **copyio(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002137{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002138 struct ioword **iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002139
2140 iop = (struct ioword **) getwords(iolist);
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002141 iolist = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002142 return iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002143}
2144
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002145static struct ioword *io(int u, int f, char *cp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002146{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002147 struct ioword *iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002148
2149 iop = (struct ioword *) tree(sizeof(*iop));
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002150 iop->io_fd = u;
Eric Andersenff9eee42001-06-29 04:57:14 +00002151 iop->io_flag = f;
2152 iop->io_name = cp;
Eric Andersen8401eea2004-08-04 19:16:54 +00002153 iolist = addword((char *) iop, iolist);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002154 return iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002155}
2156
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002157static int yylex(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00002158{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002159 int c, c1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002160 int atstart;
2161
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002162 c = peeksym;
2163 if (c > 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002164 peeksym = 0;
2165 if (c == '\n')
2166 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002167 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002168 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002169
Eric Andersenff9eee42001-06-29 04:57:14 +00002170 nlseen = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002171 atstart = startl;
2172 startl = 0;
2173 yylval.i = 0;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002174 global_env.linep = line;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002175
2176/* MALAMO */
2177 line[LINELIM - 1] = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00002178
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002179 loop:
Eric Andersen12de6cf2004-08-04 19:19:10 +00002180 while ((c = my_getc(0)) == ' ' || c == '\t') /* Skip whitespace */
Denis Vlasenko509697f2008-03-02 12:49:39 +00002181 continue;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002182
Eric Andersenff9eee42001-06-29 04:57:14 +00002183 switch (c) {
2184 default:
2185 if (any(c, "0123456789")) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002186 c1 = my_getc(0);
2187 unget(c1);
Eric Andersenff9eee42001-06-29 04:57:14 +00002188 if (c1 == '<' || c1 == '>') {
2189 iounit = c - '0';
2190 goto loop;
2191 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002192 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002193 c = c1;
2194 }
2195 break;
2196
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002197 case '#': /* Comment, skip to next newline or End-of-string */
Denis Vlasenko509697f2008-03-02 12:49:39 +00002198 while ((c = my_getc(0)) != '\0' && c != '\n')
2199 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00002200 unget(c);
2201 goto loop;
2202
2203 case 0:
Eric Andersen12de6cf2004-08-04 19:19:10 +00002204 DBGPRINTF5(("YYLEX: return 0, c=%d\n", c));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002205 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002206
2207 case '$':
Eric Andersen12de6cf2004-08-04 19:19:10 +00002208 DBGPRINTF9(("YYLEX: found $\n"));
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002209 *global_env.linep++ = c;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002210 c = my_getc(0);
2211 if (c == '{') {
2212 c = collect(c, '}');
2213 if (c != '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002214 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002215 goto pack;
2216 }
2217 break;
2218
2219 case '`':
2220 case '\'':
2221 case '"':
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002222 c = collect(c, c);
2223 if (c != '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002224 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002225 goto pack;
2226
2227 case '|':
2228 case '&':
2229 case ';':
Eric Andersenff9eee42001-06-29 04:57:14 +00002230 startl = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002231 /* If more chars process them, else return NULL char */
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002232 c1 = dual(c);
2233 if (c1 != '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002234 return c1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002235 return c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002236
Eric Andersenff9eee42001-06-29 04:57:14 +00002237 case '^':
2238 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002239 return '|';
Eric Andersenff9eee42001-06-29 04:57:14 +00002240 case '>':
2241 case '<':
2242 diag(c);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002243 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002244
2245 case '\n':
2246 nlseen++;
2247 gethere();
2248 startl = 1;
2249 if (multiline || cf & CONTIN) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002250 if (interactive && global_env.iop <= iostack) {
Denis Vlasenko38f63192007-01-22 09:03:07 +00002251#if ENABLE_FEATURE_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00002252 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00002253#else
Eric Andersen8401eea2004-08-04 19:16:54 +00002254 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00002255#endif
2256 }
2257 if (cf & CONTIN)
2258 goto loop;
2259 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002260 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002261
2262 case '(':
2263 case ')':
2264 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002265 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002266 }
2267
2268 unget(c);
2269
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002270 pack:
2271 while ((c = my_getc(0)) != '\0' && !any(c, "`$ '\"\t;&<>()|^\n")) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002272 if (global_env.linep >= elinep)
Eric Andersenff9eee42001-06-29 04:57:14 +00002273 err("word too long");
2274 else
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002275 *global_env.linep++ = c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002276 };
2277
Eric Andersenff9eee42001-06-29 04:57:14 +00002278 unget(c);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002279
Eric Andersen8401eea2004-08-04 19:16:54 +00002280 if (any(c, "\"'`$"))
Eric Andersenff9eee42001-06-29 04:57:14 +00002281 goto loop;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002282
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002283 *global_env.linep++ = '\0';
Eric Andersen12de6cf2004-08-04 19:19:10 +00002284
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002285 if (atstart) {
2286 c = rlookup(line);
2287 if (c != 0) {
2288 startl = 1;
2289 return c;
2290 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002291 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002292
Eric Andersenff9eee42001-06-29 04:57:14 +00002293 yylval.cp = strsave(line, areanum);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002294 return WORD;
Eric Andersenff9eee42001-06-29 04:57:14 +00002295}
2296
Eric Andersen12de6cf2004-08-04 19:19:10 +00002297
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002298static int collect(int c, int c1)
Eric Andersenff9eee42001-06-29 04:57:14 +00002299{
2300 char s[2];
2301
Eric Andersen12de6cf2004-08-04 19:19:10 +00002302 DBGPRINTF8(("COLLECT: enter, c=%d, c1=%d\n", c, c1));
2303
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002304 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002305 while ((c = my_getc(c1)) != c1) {
2306 if (c == 0) {
2307 unget(c);
2308 s[0] = c1;
2309 s[1] = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00002310 prs("no closing ");
2311 yyerror(s);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002312 return YYERRCODE;
Eric Andersenff9eee42001-06-29 04:57:14 +00002313 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002314 if (interactive && c == '\n' && global_env.iop <= iostack) {
Denis Vlasenko38f63192007-01-22 09:03:07 +00002315#if ENABLE_FEATURE_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00002316 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00002317#else
Eric Andersen8401eea2004-08-04 19:16:54 +00002318 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00002319#endif
2320 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002321 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002322 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002323
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002324 *global_env.linep++ = c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002325
2326 DBGPRINTF8(("COLLECT: return 0, line is %s\n", line));
2327
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002328 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002329}
2330
Eric Andersen12de6cf2004-08-04 19:19:10 +00002331/* "multiline commands" helper func */
2332/* see if next 2 chars form a shell multiline */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002333static int dual(int c)
Eric Andersenff9eee42001-06-29 04:57:14 +00002334{
2335 char s[3];
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002336 char *cp = s;
Eric Andersenff9eee42001-06-29 04:57:14 +00002337
Eric Andersen12de6cf2004-08-04 19:19:10 +00002338 DBGPRINTF8(("DUAL: enter, c=%d\n", c));
2339
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002340 *cp++ = c; /* c is the given "peek" char */
2341 *cp++ = my_getc(0); /* get next char of input */
2342 *cp = '\0'; /* add EOS marker */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002343
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002344 c = rlookup(s); /* see if 2 chars form a shell multiline */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002345 if (c == 0)
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002346 unget(*--cp); /* String is not a shell multiline, put peek char back */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002347
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002348 return c; /* String is multiline, return numeric multiline (restab) code */
Eric Andersenff9eee42001-06-29 04:57:14 +00002349}
2350
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002351static void diag(int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00002352{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002353 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002354
2355 DBGPRINTF8(("DIAG: enter, ec=%d\n", ec));
Eric Andersenff9eee42001-06-29 04:57:14 +00002356
2357 c = my_getc(0);
2358 if (c == '>' || c == '<') {
2359 if (c != ec)
2360 zzerr();
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002361 yylval.i = (ec == '>' ? IOWRITE | IOCAT : IOHERE);
Eric Andersenff9eee42001-06-29 04:57:14 +00002362 c = my_getc(0);
2363 } else
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002364 yylval.i = (ec == '>' ? IOWRITE : IOREAD);
Eric Andersenff9eee42001-06-29 04:57:14 +00002365 if (c != '&' || yylval.i == IOHERE)
2366 unget(c);
2367 else
2368 yylval.i |= IODUP;
2369}
2370
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002371static char *tree(unsigned size)
Eric Andersenff9eee42001-06-29 04:57:14 +00002372{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002373 char *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002374
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002375 t = getcell(size);
2376 if (t == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002377 DBGPRINTF2(("TREE: getcell(%d) failed!\n", size));
Eric Andersenff9eee42001-06-29 04:57:14 +00002378 prs("command line too complicated\n");
2379 fail();
2380 /* NOTREACHED */
2381 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002382 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002383}
2384
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002385
Eric Andersenff9eee42001-06-29 04:57:14 +00002386/* VARARGS1 */
2387/* ARGSUSED */
2388
2389/* -------- exec.c -------- */
2390
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002391static struct op **find1case(struct op *t, const char *w)
2392{
2393 struct op *t1;
2394 struct op **tp;
2395 char **wp;
2396 char *cp;
2397
2398 if (t == NULL) {
2399 DBGPRINTF3(("FIND1CASE: enter, t==NULL, returning.\n"));
2400 return NULL;
2401 }
2402
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002403 DBGPRINTF3(("FIND1CASE: enter, t->op_type=%d (%s)\n", t->op_type,
2404 T_CMD_NAMES[t->op_type]));
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002405
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002406 if (t->op_type == TLIST) {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002407 tp = find1case(t->left, w);
2408 if (tp != NULL) {
2409 DBGPRINTF3(("FIND1CASE: found one to the left, returning tp=%p\n", tp));
2410 return tp;
2411 }
2412 t1 = t->right; /* TPAT */
2413 } else
2414 t1 = t;
2415
Denis Vlasenko509697f2008-03-02 12:49:39 +00002416 for (wp = t1->op_words; *wp;) {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002417 cp = evalstr(*wp++, DOSUB);
2418 if (cp && gmatch(w, cp)) {
2419 DBGPRINTF3(("FIND1CASE: returning &t1->left= %p.\n",
2420 &t1->left));
2421 return &t1->left;
2422 }
2423 }
2424
2425 DBGPRINTF(("FIND1CASE: returning NULL\n"));
2426 return NULL;
2427}
2428
2429static struct op *findcase(struct op *t, const char *w)
2430{
2431 struct op **tp;
2432
2433 tp = find1case(t, w);
2434 return tp != NULL ? *tp : NULL;
2435}
2436
Eric Andersenff9eee42001-06-29 04:57:14 +00002437/*
2438 * execute tree
2439 */
2440
Denis Vlasenko7e497522008-02-12 09:51:03 +00002441static int execute(struct op *t, int *pin, int *pout, int no_fork)
Eric Andersenff9eee42001-06-29 04:57:14 +00002442{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002443 struct op *t1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002444 volatile int i, rv, a;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002445 const char *cp;
2446 char **wp, **wp2;
Eric Andersenff9eee42001-06-29 04:57:14 +00002447 struct var *vp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002448 struct op *outtree_save;
Eric Andersenff9eee42001-06-29 04:57:14 +00002449 struct brkcon bc;
2450
2451#if __GNUC__
2452 /* Avoid longjmp clobbering */
2453 (void) &wp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002454#endif
Eric Andersenff9eee42001-06-29 04:57:14 +00002455
Eric Andersen12de6cf2004-08-04 19:19:10 +00002456 if (t == NULL) {
2457 DBGPRINTF4(("EXECUTE: enter, t==null, returning.\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002458 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002459 }
2460
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002461 DBGPRINTF(("EXECUTE: t=%p, t->op_type=%d (%s), t->op_words is %s\n", t,
2462 t->op_type, T_CMD_NAMES[t->op_type],
Denis Vlasenko509697f2008-03-02 12:49:39 +00002463 ((t->op_words == NULL) ? "NULL" : t->op_words[0])));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002464
Eric Andersenff9eee42001-06-29 04:57:14 +00002465 rv = 0;
2466 a = areanum++;
Denis Vlasenko509697f2008-03-02 12:49:39 +00002467 wp2 = t->op_words;
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002468 wp = (wp2 != NULL)
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002469 ? eval(wp2, t->op_type == TCOM ? DOALL : DOALL & ~DOKEY)
Eric Andersen8401eea2004-08-04 19:16:54 +00002470 : NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00002471
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002472 switch (t->op_type) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002473 case TDOT:
2474 DBGPRINTF3(("EXECUTE: TDOT\n"));
2475
2476 outtree_save = outtree;
2477
Denis Vlasenko509697f2008-03-02 12:49:39 +00002478 newfile(evalstr(t->op_words[0], DOALL));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002479
Denis Vlasenko68404f12008-03-17 09:00:54 +00002480 t->left = dowholefile(TLIST /*, 0*/);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002481 t->right = NULL;
2482
2483 outtree = outtree_save;
2484
2485 if (t->left)
Denis Vlasenko7e497522008-02-12 09:51:03 +00002486 rv = execute(t->left, pin, pout, /* no_fork: */ 0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002487 if (t->right)
Denis Vlasenko7e497522008-02-12 09:51:03 +00002488 rv = execute(t->right, pin, pout, /* no_fork: */ 0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002489 break;
2490
Eric Andersenff9eee42001-06-29 04:57:14 +00002491 case TPAREN:
Denis Vlasenko7e497522008-02-12 09:51:03 +00002492 rv = execute(t->left, pin, pout, /* no_fork: */ 0);
Eric Andersen737f5fb2003-03-14 16:05:59 +00002493 break;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002494
Eric Andersenff9eee42001-06-29 04:57:14 +00002495 case TCOM:
Denis Vlasenko7e497522008-02-12 09:51:03 +00002496 rv = forkexec(t, pin, pout, no_fork, wp);
Eric Andersenff9eee42001-06-29 04:57:14 +00002497 break;
2498
2499 case TPIPE:
2500 {
Eric Andersen8401eea2004-08-04 19:16:54 +00002501 int pv[2];
2502
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002503 rv = openpipe(pv);
2504 if (rv < 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00002505 break;
2506 pv[0] = remap(pv[0]);
2507 pv[1] = remap(pv[1]);
Denis Vlasenko7e497522008-02-12 09:51:03 +00002508 (void) execute(t->left, pin, pv, /* no_fork: */ 0);
2509 rv = execute(t->right, pv, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002510 }
2511 break;
2512
2513 case TLIST:
Denis Vlasenko7e497522008-02-12 09:51:03 +00002514 (void) execute(t->left, pin, pout, /* no_fork: */ 0);
2515 rv = execute(t->right, pin, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002516 break;
2517
2518 case TASYNC:
Eric Andersen8401eea2004-08-04 19:16:54 +00002519 {
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002520 smallint hinteractive = interactive;
Eric Andersenff9eee42001-06-29 04:57:14 +00002521
Eric Andersen12de6cf2004-08-04 19:19:10 +00002522 DBGPRINTF7(("EXECUTE: TASYNC clause, calling vfork()...\n"));
2523
Eric Andersen8401eea2004-08-04 19:16:54 +00002524 i = vfork();
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002525 if (i == 0) { /* child */
Eric Andersen8401eea2004-08-04 19:16:54 +00002526 signal(SIGINT, SIG_IGN);
2527 signal(SIGQUIT, SIG_IGN);
2528 if (interactive)
2529 signal(SIGTERM, SIG_DFL);
2530 interactive = 0;
2531 if (pin == NULL) {
2532 close(0);
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00002533 xopen(bb_dev_null, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00002534 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002535 _exit(execute(t->left, pin, pout, /* no_fork: */ 1));
Eric Andersenff9eee42001-06-29 04:57:14 +00002536 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002537 interactive = hinteractive;
2538 if (i != -1) {
2539 setval(lookup("!"), putn(i));
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002540 closepipe(pin);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002541 if (interactive) {
2542 prs(putn(i));
2543 prs("\n");
2544 }
2545 } else
2546 rv = -1;
2547 setstatus(rv);
Eric Andersenff9eee42001-06-29 04:57:14 +00002548 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002549 break;
2550
2551 case TOR:
2552 case TAND:
Denis Vlasenko7e497522008-02-12 09:51:03 +00002553 rv = execute(t->left, pin, pout, /* no_fork: */ 0);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002554 t1 = t->right;
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002555 if (t1 != NULL && (rv == 0) == (t->op_type == TAND))
Denis Vlasenko7e497522008-02-12 09:51:03 +00002556 rv = execute(t1, pin, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002557 break;
2558
2559 case TFOR:
2560 if (wp == NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00002561 wp = dolv + 1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002562 i = dolc;
2563 if (i < 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00002564 i = 0;
2565 } else {
2566 i = -1;
Denis Vlasenko509697f2008-03-02 12:49:39 +00002567 while (*wp++ != NULL)
2568 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00002569 }
2570 vp = lookup(t->str);
2571 while (setjmp(bc.brkpt))
2572 if (isbreak)
2573 goto broken;
2574 brkset(&bc);
2575 for (t1 = t->left; i-- && *wp != NULL;) {
2576 setval(vp, *wp++);
Denis Vlasenko7e497522008-02-12 09:51:03 +00002577 rv = execute(t1, pin, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002578 }
2579 brklist = brklist->nextlev;
2580 break;
2581
2582 case TWHILE:
2583 case TUNTIL:
2584 while (setjmp(bc.brkpt))
2585 if (isbreak)
2586 goto broken;
2587 brkset(&bc);
2588 t1 = t->left;
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002589 while ((execute(t1, pin, pout, /* no_fork: */ 0) == 0) == (t->op_type == TWHILE))
Denis Vlasenko7e497522008-02-12 09:51:03 +00002590 rv = execute(t->right, pin, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002591 brklist = brklist->nextlev;
2592 break;
2593
2594 case TIF:
2595 case TELIF:
Eric Andersen8401eea2004-08-04 19:16:54 +00002596 if (t->right != NULL) {
Denis Vlasenko7e497522008-02-12 09:51:03 +00002597 rv = !execute(t->left, pin, pout, /* no_fork: */ 0) ?
2598 execute(t->right->left, pin, pout, /* no_fork: */ 0) :
2599 execute(t->right->right, pin, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002600 }
2601 break;
2602
2603 case TCASE:
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002604 cp = evalstr(t->str, DOSUB | DOTRIM);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002605 if (cp == NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00002606 cp = "";
Eric Andersen12de6cf2004-08-04 19:19:10 +00002607
2608 DBGPRINTF7(("EXECUTE: TCASE, t->str is %s, cp is %s\n",
2609 ((t->str == NULL) ? "NULL" : t->str),
2610 ((cp == NULL) ? "NULL" : cp)));
2611
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002612 t1 = findcase(t->left, cp);
2613 if (t1 != NULL) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002614 DBGPRINTF7(("EXECUTE: TCASE, calling execute(t=%p, t1=%p)...\n", t, t1));
Denis Vlasenko7e497522008-02-12 09:51:03 +00002615 rv = execute(t1, pin, pout, /* no_fork: */ 0);
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002616 DBGPRINTF7(("EXECUTE: TCASE, back from execute(t=%p, t1=%p)...\n", t, t1));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002617 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002618 break;
2619
2620 case TBRACE:
2621/*
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002622 iopp = t->ioact;
2623 if (i)
Eric Andersenff9eee42001-06-29 04:57:14 +00002624 while (*iopp)
2625 if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) {
2626 rv = -1;
2627 break;
2628 }
2629*/
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002630 if (rv >= 0) {
2631 t1 = t->left;
2632 if (t1) {
Denis Vlasenko7e497522008-02-12 09:51:03 +00002633 rv = execute(t1, pin, pout, /* no_fork: */ 0);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002634 }
2635 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002636 break;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002637
2638 };
Eric Andersenff9eee42001-06-29 04:57:14 +00002639
Denis Vlasenkoe4712752007-04-14 15:08:41 +00002640 broken:
Denis Vlasenko509697f2008-03-02 12:49:39 +00002641// Restoring op_words is most likely not needed now: see comment in forkexec()
2642// (also take a look at exec builtin (doexec) - it touches t->op_words)
2643 t->op_words = wp2;
Eric Andersenff9eee42001-06-29 04:57:14 +00002644 isbreak = 0;
2645 freehere(areanum);
2646 freearea(areanum);
2647 areanum = a;
2648 if (interactive && intr) {
2649 closeall();
2650 fail();
2651 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002652
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002653 i = trapset;
2654 if (i != 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002655 trapset = 0;
2656 runtrap(i);
2657 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002658
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002659 DBGPRINTF(("EXECUTE: returning from t=%p, rv=%d\n", t, rv));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002660 return rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00002661}
2662
Denis Vlasenkoe4712752007-04-14 15:08:41 +00002663static builtin_func_ptr inbuilt(const char *s)
2664{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002665 const struct builtincmd *bp;
2666
Denis Vlasenko95cb3262007-04-09 03:06:34 +00002667 for (bp = builtincmds; bp->name; bp++)
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002668 if (strcmp(bp->name, s) == 0)
2669 return bp->builtinfunc;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002670 return NULL;
2671}
2672
Denis Vlasenko7e497522008-02-12 09:51:03 +00002673static int forkexec(struct op *t, int *pin, int *pout, int no_fork, char **wp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002674{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002675 pid_t newpid;
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002676 int i;
2677 builtin_func_ptr bltin = NULL;
Denis Vlasenko7e497522008-02-12 09:51:03 +00002678 const char *bltin_name = NULL;
2679 const char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00002680 struct ioword **iopp;
2681 int resetsig;
2682 char **owp;
Denis Vlasenko7e497522008-02-12 09:51:03 +00002683 int forked;
Eric Andersenff9eee42001-06-29 04:57:14 +00002684
2685 int *hpin = pin;
2686 int *hpout = pout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002687 char *hwp;
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002688 smallint hinteractive;
2689 smallint hintr;
2690 smallint hexecflg;
Eric Andersen8401eea2004-08-04 19:16:54 +00002691 struct brkcon *hbrklist;
Eric Andersenff9eee42001-06-29 04:57:14 +00002692
2693#if __GNUC__
2694 /* Avoid longjmp clobbering */
2695 (void) &pin;
2696 (void) &pout;
2697 (void) &wp;
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002698 (void) &bltin;
Eric Andersenff9eee42001-06-29 04:57:14 +00002699 (void) &cp;
2700 (void) &resetsig;
2701 (void) &owp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002702#endif
Eric Andersenff9eee42001-06-29 04:57:14 +00002703
Denis Vlasenko7e497522008-02-12 09:51:03 +00002704 DBGPRINTF(("FORKEXEC: t=%p, pin %p, pout %p, no_fork %d\n", t, pin,
2705 pout, no_fork));
Denis Vlasenko509697f2008-03-02 12:49:39 +00002706 DBGPRINTF7(("FORKEXEC: t->op_words is %s\n",
2707 ((t->op_words == NULL) ? "NULL" : t->op_words[0])));
Eric Andersenff9eee42001-06-29 04:57:14 +00002708 owp = wp;
2709 resetsig = 0;
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002710 if (t->op_type == TCOM) {
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00002711 while (*wp++ != NULL)
2712 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00002713 cp = *wp;
2714
2715 /* strip all initial assignments */
Denis Vlasenko7e497522008-02-12 09:51:03 +00002716 /* FIXME: not correct wrt PATH=yyy command etc */
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00002717 if (FLAG['x']) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002718 DBGPRINTF9(("FORKEXEC: echo'ing, cp=%p, wp=%p, owp=%p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00002719 cp, wp, owp));
Eric Andersen8401eea2004-08-04 19:16:54 +00002720 echo(cp ? wp : owp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002721 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002722
Denis Vlasenko7e497522008-02-12 09:51:03 +00002723 if (cp == NULL) {
2724 if (t->ioact == NULL) {
2725 while ((cp = *owp++) != NULL && assign(cp, COPYV))
2726 continue;
2727 DBGPRINTF(("FORKEXEC: returning setstatus(0)\n"));
2728 return setstatus(0);
2729 }
2730 } else { /* cp != NULL */
2731 bltin_name = cp;
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002732 bltin = inbuilt(cp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002733 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002734 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002735
Denis Vlasenko7e497522008-02-12 09:51:03 +00002736 forked = 0;
Denis Vlasenko509697f2008-03-02 12:49:39 +00002737 // We were pointing t->op_words to temporary (expanded) arg list:
2738 // t->op_words = wp;
Denis Vlasenkofe218832008-03-01 09:35:39 +00002739 // and restored it later (in execute()), but "break"
Denis Vlasenko509697f2008-03-02 12:49:39 +00002740 // longjmps away (at "Run builtin" below), leaving t->op_words clobbered!
Denis Vlasenkofe218832008-03-01 09:35:39 +00002741 // See http://bugs.busybox.net/view.php?id=846.
Denis Vlasenko509697f2008-03-02 12:49:39 +00002742 // Now we do not touch t->op_words, but separately pass wp as param list
Denis Vlasenkofe218832008-03-01 09:35:39 +00002743 // to builtins
Denis Vlasenko7e497522008-02-12 09:51:03 +00002744 DBGPRINTF(("FORKEXEC: bltin %p, no_fork %d, owp %p\n", bltin,
2745 no_fork, owp));
2746 /* Don't fork if it is a lone builtin (not in pipe)
2747 * OR we are told to _not_ fork */
2748 if ((!bltin || pin || pout) /* not lone bltin AND */
2749 && !no_fork /* not told to avoid fork */
2750 ) {
2751 /* Save values in case child alters them after vfork */
Eric Andersenff9eee42001-06-29 04:57:14 +00002752 hpin = pin;
2753 hpout = pout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002754 hwp = *wp;
2755 hinteractive = interactive;
2756 hintr = intr;
2757 hbrklist = brklist;
2758 hexecflg = execflg;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002759
Eric Andersen12de6cf2004-08-04 19:19:10 +00002760 DBGPRINTF3(("FORKEXEC: calling vfork()...\n"));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002761 newpid = vfork();
Eric Andersen12de6cf2004-08-04 19:19:10 +00002762 if (newpid == -1) {
Denis Vlasenko89f0b342006-11-18 22:04:09 +00002763 DBGPRINTF(("FORKEXEC: ERROR, cannot vfork()!\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002764 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002765 }
2766
Denis Vlasenko489f93e2007-02-01 01:43:16 +00002767 if (newpid > 0) { /* Parent */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002768 /* Restore values */
Eric Andersenff9eee42001-06-29 04:57:14 +00002769 pin = hpin;
2770 pout = hpout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002771 *wp = hwp;
2772 interactive = hinteractive;
2773 intr = hintr;
2774 brklist = hbrklist;
2775 execflg = hexecflg;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002776
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002777 closepipe(pin);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002778 return (pout == NULL ? setstatus(waitfor(newpid, 0)) : 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002779 }
2780
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002781 /* Child */
Denis Vlasenko7e497522008-02-12 09:51:03 +00002782 DBGPRINTF(("FORKEXEC: child process, bltin=%p (%s)\n", bltin, bltin_name));
Eric Andersenff9eee42001-06-29 04:57:14 +00002783 if (interactive) {
2784 signal(SIGINT, SIG_IGN);
2785 signal(SIGQUIT, SIG_IGN);
2786 resetsig = 1;
2787 }
2788 interactive = 0;
2789 intr = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002790 forked = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002791 brklist = 0;
2792 execflg = 0;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002793 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002794
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002795 if (owp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002796 while ((cp = *owp++) != NULL && assign(cp, COPYV))
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002797 if (!bltin)
Eric Andersenff9eee42001-06-29 04:57:14 +00002798 export(lookup(cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002799
Denis Vlasenko284d0fa2008-02-16 13:18:17 +00002800 if (pin) { /* NB: close _first_, then move fds! */
2801 close(pin[1]);
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00002802 xmove_fd(pin[0], 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002803 }
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002804 if (pout) {
Denis Vlasenko284d0fa2008-02-16 13:18:17 +00002805 close(pout[0]);
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00002806 xmove_fd(pout[1], 1);
Eric Andersenff9eee42001-06-29 04:57:14 +00002807 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002808
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002809 iopp = t->ioact;
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002810 if (iopp) {
2811 if (bltin && bltin != doexec) {
Denis Vlasenko7e497522008-02-12 09:51:03 +00002812 prs(bltin_name);
Eric Andersenff9eee42001-06-29 04:57:14 +00002813 err(": cannot redirect shell command");
Eric Andersen12de6cf2004-08-04 19:19:10 +00002814 if (forked)
2815 _exit(-1);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002816 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002817 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002818 while (*iopp) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002819 if (iosetup(*iopp++, pin != NULL, pout != NULL)) {
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002820 /* system-detected error */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002821 if (forked)
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002822 _exit(-1);
2823 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002824 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002825 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002826 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002827
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002828 if (bltin) {
Denis Vlasenko7e497522008-02-12 09:51:03 +00002829 if (forked || pin || pout) {
2830 /* Builtin in pipe: disallowed */
2831 /* TODO: allow "exec"? */
2832 prs(bltin_name);
2833 err(": cannot run builtin as part of pipe");
2834 if (forked)
2835 _exit(-1);
2836 return -1;
2837 }
Denis Vlasenkofe218832008-03-01 09:35:39 +00002838 /* Run builtin */
2839 i = setstatus(bltin(t, wp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002840 if (forked)
2841 _exit(i);
2842 DBGPRINTF(("FORKEXEC: returning i=%d\n", i));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002843 return i;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002844 }
2845
Eric Andersenff9eee42001-06-29 04:57:14 +00002846 /* should use FIOCEXCL */
Eric Andersen8401eea2004-08-04 19:16:54 +00002847 for (i = FDBASE; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00002848 close(i);
2849 if (resetsig) {
2850 signal(SIGINT, SIG_DFL);
2851 signal(SIGQUIT, SIG_DFL);
2852 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002853
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002854 if (t->op_type == TPAREN)
Denis Vlasenko7e497522008-02-12 09:51:03 +00002855 _exit(execute(t->left, NOPIPE, NOPIPE, /* no_fork: */ 1));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002856 if (wp[0] == NULL)
2857 _exit(0);
2858
Eric Andersenfd7a4c82004-09-02 23:13:10 +00002859 cp = rexecve(wp[0], wp, makenv(0, NULL));
Eric Andersen8401eea2004-08-04 19:16:54 +00002860 prs(wp[0]);
2861 prs(": ");
Eric Andersen12de6cf2004-08-04 19:19:10 +00002862 err(cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00002863 if (!execflg)
2864 trap[0] = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002865
Denis Vlasenko7e497522008-02-12 09:51:03 +00002866 DBGPRINTF(("FORKEXEC: calling leave(), pid=%d\n", getpid()));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002867
Eric Andersenff9eee42001-06-29 04:57:14 +00002868 leave();
2869 /* NOTREACHED */
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002870 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002871}
2872
2873/*
2874 * 0< 1> are ignored as required
2875 * within pipelines.
2876 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002877static int iosetup(struct ioword *iop, int pipein, int pipeout)
Eric Andersenff9eee42001-06-29 04:57:14 +00002878{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002879 int u = -1;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002880 char *cp = NULL;
2881 const char *msg;
Eric Andersenff9eee42001-06-29 04:57:14 +00002882
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002883 DBGPRINTF(("IOSETUP: iop %p, pipein %i, pipeout %i\n", iop,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002884 pipein, pipeout));
2885
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002886 if (iop->io_fd == IODEFAULT) /* take default */
2887 iop->io_fd = iop->io_flag & (IOREAD | IOHERE) ? 0 : 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002888
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002889 if (pipein && iop->io_fd == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002890 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002891
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002892 if (pipeout && iop->io_fd == 1)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002893 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002894
Eric Andersen8401eea2004-08-04 19:16:54 +00002895 msg = iop->io_flag & (IOREAD | IOHERE) ? "open" : "create";
Eric Andersenff9eee42001-06-29 04:57:14 +00002896 if ((iop->io_flag & IOHERE) == 0) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002897 cp = iop->io_name; /* huh?? */
2898 cp = evalstr(cp, DOSUB | DOTRIM);
2899 if (cp == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002900 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002901 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002902
Eric Andersenff9eee42001-06-29 04:57:14 +00002903 if (iop->io_flag & IODUP) {
2904 if (cp[1] || (!isdigit(*cp) && *cp != '-')) {
2905 prs(cp);
2906 err(": illegal >& argument");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002907 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002908 }
2909 if (*cp == '-')
2910 iop->io_flag = IOCLOSE;
Eric Andersen8401eea2004-08-04 19:16:54 +00002911 iop->io_flag &= ~(IOREAD | IOWRITE);
Eric Andersenff9eee42001-06-29 04:57:14 +00002912 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002913
Eric Andersenff9eee42001-06-29 04:57:14 +00002914 switch (iop->io_flag) {
2915 case IOREAD:
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00002916 u = open(cp, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00002917 break;
2918
2919 case IOHERE:
Eric Andersen8401eea2004-08-04 19:16:54 +00002920 case IOHERE | IOXHERE:
2921 u = herein(iop->io_name, iop->io_flag & IOXHERE);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002922 cp = (char*)"here file";
Eric Andersenff9eee42001-06-29 04:57:14 +00002923 break;
2924
Eric Andersen8401eea2004-08-04 19:16:54 +00002925 case IOWRITE | IOCAT:
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00002926 u = open(cp, O_WRONLY);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002927 if (u >= 0) {
Denis Vlasenkoea620772006-10-14 02:23:43 +00002928 lseek(u, (long) 0, SEEK_END);
Eric Andersenff9eee42001-06-29 04:57:14 +00002929 break;
2930 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002931 /* fall through to creation if >>file doesn't exist */
2932
Eric Andersenff9eee42001-06-29 04:57:14 +00002933 case IOWRITE:
2934 u = creat(cp, 0666);
2935 break;
2936
2937 case IODUP:
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002938 u = dup2(*cp - '0', iop->io_fd);
Eric Andersenff9eee42001-06-29 04:57:14 +00002939 break;
2940
2941 case IOCLOSE:
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002942 close(iop->io_fd);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002943 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002944 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002945
Eric Andersenff9eee42001-06-29 04:57:14 +00002946 if (u < 0) {
2947 prs(cp);
2948 prs(": cannot ");
2949 warn(msg);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002950 return 1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002951 }
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002952 xmove_fd(u, iop->io_fd);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002953 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002954}
2955
Eric Andersenff9eee42001-06-29 04:57:14 +00002956/*
2957 * Enter a new loop level (marked for break/continue).
2958 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002959static void brkset(struct brkcon *bc)
Eric Andersenff9eee42001-06-29 04:57:14 +00002960{
2961 bc->nextlev = brklist;
2962 brklist = bc;
2963}
2964
2965/*
2966 * Wait for the last process created.
2967 * Print a message for each process found
2968 * that was killed by a signal.
2969 * Ignore interrupt signals while waiting
2970 * unless `canintr' is true.
2971 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002972static int waitfor(int lastpid, int canintr)
Eric Andersenff9eee42001-06-29 04:57:14 +00002973{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002974 int pid, rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00002975 int s;
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002976 smallint oheedint = heedint;
Eric Andersenff9eee42001-06-29 04:57:14 +00002977
2978 heedint = 0;
2979 rv = 0;
2980 do {
2981 pid = wait(&s);
2982 if (pid == -1) {
2983 if (errno != EINTR || canintr)
2984 break;
2985 } else {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002986 rv = WAITSIG(s);
2987 if (rv != 0) {
Denis Vlasenko80b8b392007-06-25 10:55:35 +00002988 if (rv < ARRAY_SIZE(signame)) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002989 if (signame[rv] != NULL) {
2990 if (pid != lastpid) {
2991 prn(pid);
2992 prs(": ");
2993 }
2994 prs(signame[rv]);
2995 }
2996 } else {
2997 if (pid != lastpid) {
2998 prn(pid);
2999 prs(": ");
3000 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003001 prs("Signal ");
3002 prn(rv);
3003 prs(" ");
Eric Andersenff9eee42001-06-29 04:57:14 +00003004 }
3005 if (WAITCORE(s))
3006 prs(" - core dumped");
Denis Vlasenko80b8b392007-06-25 10:55:35 +00003007 if (rv >= ARRAY_SIZE(signame) || signame[rv])
Eric Andersenff9eee42001-06-29 04:57:14 +00003008 prs("\n");
3009 rv = -1;
3010 } else
3011 rv = WAITVAL(s);
3012 }
3013 } while (pid != lastpid);
3014 heedint = oheedint;
3015 if (intr) {
3016 if (interactive) {
3017 if (canintr)
3018 intr = 0;
3019 } else {
Eric Andersen8401eea2004-08-04 19:16:54 +00003020 if (exstat == 0)
3021 exstat = rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003022 onintr(0);
3023 }
3024 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003025 return rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003026}
3027
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003028static int setstatus(int s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003029{
3030 exstat = s;
3031 setval(lookup("?"), putn(s));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003032 return s;
Eric Andersenff9eee42001-06-29 04:57:14 +00003033}
3034
3035/*
3036 * PATH-searching interface to execve.
3037 * If getenv("PATH") were kept up-to-date,
3038 * execvp might be used.
3039 */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003040static const char *rexecve(char *c, char **v, char **envp)
Eric Andersenff9eee42001-06-29 04:57:14 +00003041{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003042 const char *sp;
3043 char *tp;
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00003044 int asis = 0;
Eric Andersen1c039232001-07-07 00:05:55 +00003045 char *name = c;
Eric Andersen8401eea2004-08-04 19:16:54 +00003046
Denis Vlasenko80d14be2007-04-10 23:03:30 +00003047 if (ENABLE_FEATURE_SH_STANDALONE) {
Denis Vlasenko1aa7e472007-11-28 06:49:03 +00003048 if (find_applet_by_name(name) >= 0) {
Rob Landleya299efb2006-08-10 21:46:43 +00003049 /* We have to exec here since we vforked. Running
Denis Vlasenkoe4f2d062007-04-11 17:03:19 +00003050 * run_applet_and_exit() won't work and bad things
Rob Landleya299efb2006-08-10 21:46:43 +00003051 * will happen. */
Denis Vlasenkobdbbb7e2007-06-08 15:02:55 +00003052 execve(bb_busybox_exec_path, v, envp);
Rob Landleya299efb2006-08-10 21:46:43 +00003053 }
Eric Andersen1c039232001-07-07 00:05:55 +00003054 }
Eric Andersen1c039232001-07-07 00:05:55 +00003055
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003056 DBGPRINTF(("REXECVE: c=%p, v=%p, envp=%p\n", c, v, envp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003057
Eric Andersen8401eea2004-08-04 19:16:54 +00003058 sp = any('/', c) ? "" : path->value;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003059 asis = (*sp == '\0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003060 while (asis || *sp != '\0') {
3061 asis = 0;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003062 tp = global_env.linep;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003063 for (; *sp != '\0'; tp++) {
3064 *tp = *sp++;
3065 if (*tp == ':') {
3066 asis = (*sp == '\0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003067 break;
3068 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003069 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003070 if (tp != global_env.linep)
Eric Andersenff9eee42001-06-29 04:57:14 +00003071 *tp++ = '/';
Denis Vlasenko509697f2008-03-02 12:49:39 +00003072 strcpy(tp, c);
3073 //for (i = 0; (*tp++ = c[i++]) != '\0';)
3074 // continue;
Eric Andersen1c039232001-07-07 00:05:55 +00003075
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003076 DBGPRINTF3(("REXECVE: global_env.linep is %s\n", global_env.linep));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003077
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003078 execve(global_env.linep, v, envp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003079
Eric Andersenff9eee42001-06-29 04:57:14 +00003080 switch (errno) {
3081 case ENOEXEC:
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003082 *v = global_env.linep;
Denis Vlasenko509697f2008-03-02 12:49:39 +00003083 v--;
3084 tp = *v;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003085 *v = global_env.linep;
Glenn L McGrathdc4e75e2003-09-02 02:36:18 +00003086 execve(DEFAULT_SHELL, v, envp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003087 *v = tp;
Denis Vlasenko509697f2008-03-02 12:49:39 +00003088 return "no shell";
Eric Andersenff9eee42001-06-29 04:57:14 +00003089
3090 case ENOMEM:
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003091 return (char *) bb_msg_memory_exhausted;
Eric Andersenff9eee42001-06-29 04:57:14 +00003092
3093 case E2BIG:
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003094 return "argument list too long";
Eric Andersenff9eee42001-06-29 04:57:14 +00003095 }
3096 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003097 return errno == ENOENT ? "not found" : "cannot execute";
Eric Andersenff9eee42001-06-29 04:57:14 +00003098}
3099
3100/*
3101 * Run the command produced by generator `f'
3102 * applied to stream `arg'.
3103 */
Eric Andersen8401eea2004-08-04 19:16:54 +00003104static int run(struct ioarg *argp, int (*f) (struct ioarg *))
Eric Andersenff9eee42001-06-29 04:57:14 +00003105{
3106 struct op *otree;
3107 struct wdblock *swdlist;
3108 struct wdblock *siolist;
3109 jmp_buf ev, rt;
3110 xint *ofail;
3111 int rv;
3112
3113#if __GNUC__
3114 /* Avoid longjmp clobbering */
3115 (void) &rv;
3116#endif
3117
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003118 DBGPRINTF(("RUN: enter, areanum %d, outtree %p, failpt %p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00003119 areanum, outtree, failpt));
3120
Eric Andersenff9eee42001-06-29 04:57:14 +00003121 areanum++;
3122 swdlist = wdlist;
3123 siolist = iolist;
3124 otree = outtree;
3125 ofail = failpt;
3126 rv = -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003127
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003128 errpt = ev;
3129 if (newenv(setjmp(errpt)) == 0) {
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00003130 wdlist = NULL;
3131 iolist = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00003132 pushio(argp, f);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003133 global_env.iobase = global_env.iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00003134 yynerrs = 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003135 failpt = rt;
3136 if (setjmp(failpt) == 0 && yyparse() == 0)
Denis Vlasenko7e497522008-02-12 09:51:03 +00003137 rv = execute(outtree, NOPIPE, NOPIPE, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003138 quitenv();
Eric Andersen12de6cf2004-08-04 19:19:10 +00003139 } else {
3140 DBGPRINTF(("RUN: error from newenv()!\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00003141 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00003142
Eric Andersenff9eee42001-06-29 04:57:14 +00003143 wdlist = swdlist;
3144 iolist = siolist;
3145 failpt = ofail;
3146 outtree = otree;
3147 freearea(areanum--);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003148
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003149 return rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003150}
3151
3152/* -------- do.c -------- */
3153
3154/*
3155 * built-in commands: doX
3156 */
3157
Denis Vlasenko68404f12008-03-17 09:00:54 +00003158static int dohelp(struct op *t ATTRIBUTE_UNUSED, char **args ATTRIBUTE_UNUSED)
Eric Andersen1c039232001-07-07 00:05:55 +00003159{
3160 int col;
3161 const struct builtincmd *x;
3162
Denis Vlasenko0ee39992006-12-24 15:23:28 +00003163 puts("\nBuilt-in commands:\n"
3164 "-------------------");
Eric Andersen1c039232001-07-07 00:05:55 +00003165
Denis Vlasenko95cb3262007-04-09 03:06:34 +00003166 col = 0;
3167 x = builtincmds;
3168 while (x->name) {
3169 col += printf("%c%s", ((col == 0) ? '\t' : ' '), x->name);
Eric Andersen1c039232001-07-07 00:05:55 +00003170 if (col > 60) {
Denis Vlasenko4daad902007-09-27 10:20:47 +00003171 bb_putchar('\n');
Eric Andersen1c039232001-07-07 00:05:55 +00003172 col = 0;
3173 }
Denis Vlasenko95cb3262007-04-09 03:06:34 +00003174 x++;
Eric Andersen1c039232001-07-07 00:05:55 +00003175 }
Denis Vlasenko80d14be2007-04-10 23:03:30 +00003176#if ENABLE_FEATURE_SH_STANDALONE
Eric Andersen1c039232001-07-07 00:05:55 +00003177 {
Denis Vlasenko1aa7e472007-11-28 06:49:03 +00003178 const char *applet = applet_names;
Eric Andersen1c039232001-07-07 00:05:55 +00003179
Denis Vlasenko1aa7e472007-11-28 06:49:03 +00003180 while (*applet) {
3181 col += printf("%c%s", ((col == 0) ? '\t' : ' '), applet);
Eric Andersen1c039232001-07-07 00:05:55 +00003182 if (col > 60) {
Denis Vlasenko4daad902007-09-27 10:20:47 +00003183 bb_putchar('\n');
Eric Andersen1c039232001-07-07 00:05:55 +00003184 col = 0;
3185 }
Denis Vlasenko1aa7e472007-11-28 06:49:03 +00003186 applet += strlen(applet) + 1;
Eric Andersen1c039232001-07-07 00:05:55 +00003187 }
3188 }
3189#endif
Denis Vlasenko0ee39992006-12-24 15:23:28 +00003190 puts("\n");
Eric Andersen1c039232001-07-07 00:05:55 +00003191 return EXIT_SUCCESS;
3192}
3193
Denis Vlasenko68404f12008-03-17 09:00:54 +00003194static int dolabel(struct op *t ATTRIBUTE_UNUSED, char **args ATTRIBUTE_UNUSED)
Eric Andersenff9eee42001-06-29 04:57:14 +00003195{
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003196 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003197}
3198
Denis Vlasenko68404f12008-03-17 09:00:54 +00003199static int dochdir(struct op *t ATTRIBUTE_UNUSED, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003200{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003201 const char *cp, *er;
Eric Andersenff9eee42001-06-29 04:57:14 +00003202
Denis Vlasenkofe218832008-03-01 09:35:39 +00003203 cp = args[1];
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003204 if (cp == NULL) {
3205 cp = homedir->value;
Denis Vlasenkod244c5e2007-02-09 17:30:14 +00003206 if (cp != NULL)
3207 goto do_cd;
3208 er = ": no home directory";
3209 } else {
3210 do_cd:
3211 if (chdir(cp) >= 0)
3212 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003213 er = ": bad directory";
Denis Vlasenkod244c5e2007-02-09 17:30:14 +00003214 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003215 prs(cp != NULL ? cp : "cd");
Eric Andersenff9eee42001-06-29 04:57:14 +00003216 err(er);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003217 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003218}
3219
Denis Vlasenko68404f12008-03-17 09:00:54 +00003220static int doshift(struct op *t ATTRIBUTE_UNUSED, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003221{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003222 int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003223
Denis Vlasenkofe218832008-03-01 09:35:39 +00003224 n = args[1] ? getn(args[1]) : 1;
Eric Andersen8401eea2004-08-04 19:16:54 +00003225 if (dolc < n) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003226 err("nothing to shift");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003227 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003228 }
3229 dolv[n] = dolv[0];
3230 dolv += n;
3231 dolc -= n;
3232 setval(lookup("#"), putn(dolc));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003233 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003234}
3235
3236/*
3237 * execute login and newgrp directly
3238 */
Denis Vlasenko68404f12008-03-17 09:00:54 +00003239static int dologin(struct op *t ATTRIBUTE_UNUSED, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003240{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003241 const char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003242
3243 if (interactive) {
3244 signal(SIGINT, SIG_DFL);
3245 signal(SIGQUIT, SIG_DFL);
3246 }
Denis Vlasenkofe218832008-03-01 09:35:39 +00003247 cp = rexecve(args[0], args, makenv(0, NULL));
3248 prs(args[0]);
Eric Andersen8401eea2004-08-04 19:16:54 +00003249 prs(": ");
3250 err(cp);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003251 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003252}
3253
Denis Vlasenko68404f12008-03-17 09:00:54 +00003254static int doumask(struct op *t ATTRIBUTE_UNUSED, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003255{
Denis Vlasenko7e497522008-02-12 09:51:03 +00003256 int i;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003257 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003258
Denis Vlasenkofe218832008-03-01 09:35:39 +00003259 cp = args[1];
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003260 if (cp == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003261 i = umask(0);
3262 umask(i);
Denis Vlasenko7e497522008-02-12 09:51:03 +00003263 printf("%04o\n", i);
Eric Andersenff9eee42001-06-29 04:57:14 +00003264 } else {
Denis Vlasenko7e497522008-02-12 09:51:03 +00003265 i = bb_strtou(cp, NULL, 8);
3266 if (errno) {
3267 err("umask: bad octal number");
3268 return 1;
3269 }
3270 umask(i);
Eric Andersenff9eee42001-06-29 04:57:14 +00003271 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003272 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003273}
3274
Denis Vlasenkofe218832008-03-01 09:35:39 +00003275static int doexec(struct op *t, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003276{
Eric Andersenff9eee42001-06-29 04:57:14 +00003277 jmp_buf ex;
3278 xint *ofail;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003279 char **sv_words;
Eric Andersenff9eee42001-06-29 04:57:14 +00003280
3281 t->ioact = NULL;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003282 if (!args[1])
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003283 return 1;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003284
Eric Andersenff9eee42001-06-29 04:57:14 +00003285 execflg = 1;
3286 ofail = failpt;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003287 failpt = ex;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003288
Denis Vlasenko509697f2008-03-02 12:49:39 +00003289 sv_words = t->op_words;
3290 t->op_words = args + 1;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003291// TODO: test what will happen with "exec break" -
Denis Vlasenko509697f2008-03-02 12:49:39 +00003292// will it leave t->op_words pointing to garbage?
Denis Vlasenkofe218832008-03-01 09:35:39 +00003293// (see http://bugs.busybox.net/view.php?id=846)
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003294 if (setjmp(failpt) == 0)
Denis Vlasenko7e497522008-02-12 09:51:03 +00003295 execute(t, NOPIPE, NOPIPE, /* no_fork: */ 1);
Denis Vlasenko509697f2008-03-02 12:49:39 +00003296 t->op_words = sv_words;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003297
Eric Andersenff9eee42001-06-29 04:57:14 +00003298 failpt = ofail;
3299 execflg = 0;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003300
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003301 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003302}
3303
Denis Vlasenko68404f12008-03-17 09:00:54 +00003304static int dodot(struct op *t ATTRIBUTE_UNUSED, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003305{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003306 int i;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003307 const char *sp;
3308 char *tp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003309 char *cp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003310 int maltmp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003311
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003312 DBGPRINTF(("DODOT: enter, t=%p, tleft %p, tright %p, global_env.linep is %s\n",
3313 t, t->left, t->right, ((global_env.linep == NULL) ? "NULL" : global_env.linep)));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003314
Denis Vlasenkofe218832008-03-01 09:35:39 +00003315 cp = args[1];
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003316 if (cp == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00003317 DBGPRINTF(("DODOT: bad args, ret 0\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003318 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003319 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003320 DBGPRINTF(("DODOT: cp is %s\n", cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003321
Eric Andersen8401eea2004-08-04 19:16:54 +00003322 sp = any('/', cp) ? ":" : path->value;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003323
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003324 DBGPRINTF(("DODOT: sp is %s, global_env.linep is %s\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00003325 ((sp == NULL) ? "NULL" : sp),
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003326 ((global_env.linep == NULL) ? "NULL" : global_env.linep)));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003327
Eric Andersenff9eee42001-06-29 04:57:14 +00003328 while (*sp) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003329 tp = global_env.linep;
Eric Andersenff9eee42001-06-29 04:57:14 +00003330 while (*sp && (*tp = *sp++) != ':')
3331 tp++;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003332 if (tp != global_env.linep)
Eric Andersenff9eee42001-06-29 04:57:14 +00003333 *tp++ = '/';
Denis Vlasenko509697f2008-03-02 12:49:39 +00003334 strcpy(tp, cp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003335
3336 /* Original code */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003337 i = open(global_env.linep, O_RDONLY);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003338 if (i >= 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003339 exstat = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003340 maltmp = remap(i);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003341 DBGPRINTF(("DODOT: remap=%d, exstat=%d, global_env.iofd %d, i %d, global_env.linep is %s\n",
3342 maltmp, exstat, global_env.iofd, i, global_env.linep));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003343
3344 next(maltmp); /* Basically a PUSHIO */
3345
3346 DBGPRINTF(("DODOT: returning exstat=%d\n", exstat));
3347
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003348 return exstat;
Eric Andersenff9eee42001-06-29 04:57:14 +00003349 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003350 } /* while */
Eric Andersen12de6cf2004-08-04 19:19:10 +00003351
Eric Andersenff9eee42001-06-29 04:57:14 +00003352 prs(cp);
3353 err(": not found");
Eric Andersen12de6cf2004-08-04 19:19:10 +00003354
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003355 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003356}
3357
Denis Vlasenko68404f12008-03-17 09:00:54 +00003358static int dowait(struct op *t ATTRIBUTE_UNUSED, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003359{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003360 int i;
3361 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003362
Denis Vlasenkofe218832008-03-01 09:35:39 +00003363 cp = args[1];
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003364 if (cp != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003365 i = getn(cp);
3366 if (i == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003367 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003368 } else
3369 i = -1;
3370 setstatus(waitfor(i, 1));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003371 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003372}
3373
Denis Vlasenko68404f12008-03-17 09:00:54 +00003374static int doread(struct op *t ATTRIBUTE_UNUSED, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003375{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003376 char *cp, **wp;
3377 int nb = 0;
3378 int nl = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003379
Denis Vlasenkofe218832008-03-01 09:35:39 +00003380 if (args[1] == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003381 err("Usage: read name ...");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003382 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003383 }
Denis Vlasenkofe218832008-03-01 09:35:39 +00003384 for (wp = args + 1; *wp; wp++) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003385 for (cp = global_env.linep; !nl && cp < elinep - 1; cp++) {
Denis Vlasenkoe376d452008-02-20 22:23:24 +00003386 nb = nonblock_safe_read(0, cp, sizeof(*cp));
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003387 if (nb != sizeof(*cp))
Eric Andersenff9eee42001-06-29 04:57:14 +00003388 break;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003389 nl = (*cp == '\n');
3390 if (nl || (wp[1] && any(*cp, ifs->value)))
3391 break;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003392 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003393 *cp = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00003394 if (nb <= 0)
3395 break;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003396 setval(lookup(*wp), global_env.linep);
Eric Andersenff9eee42001-06-29 04:57:14 +00003397 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003398 return nb <= 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003399}
3400
Denis Vlasenko68404f12008-03-17 09:00:54 +00003401static int doeval(struct op *t ATTRIBUTE_UNUSED, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003402{
Denis Vlasenkofe218832008-03-01 09:35:39 +00003403 return RUN(awordlist, args + 1, wdchar);
Eric Andersenff9eee42001-06-29 04:57:14 +00003404}
3405
Denis Vlasenko68404f12008-03-17 09:00:54 +00003406static int dotrap(struct op *t ATTRIBUTE_UNUSED, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003407{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003408 int n, i;
3409 int resetsig;
Eric Andersenff9eee42001-06-29 04:57:14 +00003410
Denis Vlasenkofe218832008-03-01 09:35:39 +00003411 if (args[1] == NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00003412 for (i = 0; i <= _NSIG; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00003413 if (trap[i]) {
3414 prn(i);
3415 prs(": ");
3416 prs(trap[i]);
3417 prs("\n");
3418 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003419 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003420 }
Denis Vlasenkofe218832008-03-01 09:35:39 +00003421 resetsig = isdigit(args[1][0]);
3422 for (i = resetsig ? 1 : 2; args[i] != NULL; ++i) {
3423 n = getsig(args[i]);
Eric Andersenff9eee42001-06-29 04:57:14 +00003424 freecell(trap[n]);
3425 trap[n] = 0;
3426 if (!resetsig) {
Denis Vlasenkofe218832008-03-01 09:35:39 +00003427 if (args[1][0] != '\0') {
3428 trap[n] = strsave(args[1], 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003429 setsig(n, sig);
3430 } else
3431 setsig(n, SIG_IGN);
3432 } else {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00003433 if (interactive) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003434 if (n == SIGINT)
3435 setsig(n, onintr);
3436 else
Eric Andersen8401eea2004-08-04 19:16:54 +00003437 setsig(n, n == SIGQUIT ? SIG_IGN : SIG_DFL);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00003438 } else
Eric Andersenff9eee42001-06-29 04:57:14 +00003439 setsig(n, SIG_DFL);
3440 }
3441 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003442 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003443}
3444
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003445static int getsig(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003446{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003447 int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003448
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003449 n = getn(s);
3450 if (n < 0 || n > _NSIG) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003451 err("trap: bad signal number");
3452 n = 0;
3453 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003454 return n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003455}
3456
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003457static void setsig(int n, sighandler_t f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003458{
3459 if (n == 0)
3460 return;
3461 if (signal(n, SIG_IGN) != SIG_IGN || ourtrap[n]) {
3462 ourtrap[n] = 1;
3463 signal(n, f);
3464 }
3465}
3466
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003467static int getn(char *as)
Eric Andersenff9eee42001-06-29 04:57:14 +00003468{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003469 char *s;
3470 int n, m;
Eric Andersenff9eee42001-06-29 04:57:14 +00003471
3472 s = as;
3473 m = 1;
3474 if (*s == '-') {
3475 m = -1;
3476 s++;
3477 }
3478 for (n = 0; isdigit(*s); s++)
Eric Andersen8401eea2004-08-04 19:16:54 +00003479 n = (n * 10) + (*s - '0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003480 if (*s) {
3481 prs(as);
3482 err(": bad number");
3483 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003484 return n * m;
Eric Andersenff9eee42001-06-29 04:57:14 +00003485}
3486
Denis Vlasenko68404f12008-03-17 09:00:54 +00003487static int dobreak(struct op *t ATTRIBUTE_UNUSED, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003488{
Denis Vlasenkofe218832008-03-01 09:35:39 +00003489 return brkcontin(args[1], 1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003490}
3491
Denis Vlasenko68404f12008-03-17 09:00:54 +00003492static int docontinue(struct op *t ATTRIBUTE_UNUSED, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003493{
Denis Vlasenkofe218832008-03-01 09:35:39 +00003494 return brkcontin(args[1], 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003495}
3496
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003497static int brkcontin(char *cp, int val)
Eric Andersenff9eee42001-06-29 04:57:14 +00003498{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003499 struct brkcon *bc;
3500 int nl;
Eric Andersenff9eee42001-06-29 04:57:14 +00003501
Eric Andersen8401eea2004-08-04 19:16:54 +00003502 nl = cp == NULL ? 1 : getn(cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003503 if (nl <= 0)
3504 nl = 999;
3505 do {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003506 bc = brklist;
3507 if (bc == NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00003508 break;
3509 brklist = bc->nextlev;
3510 } while (--nl);
3511 if (nl) {
3512 err("bad break/continue level");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003513 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003514 }
Denis Vlasenko648b44f2008-02-12 06:04:06 +00003515 isbreak = (val != 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003516 longjmp(bc->brkpt, 1);
3517 /* NOTREACHED */
3518}
3519
Denis Vlasenko68404f12008-03-17 09:00:54 +00003520static int doexit(struct op *t ATTRIBUTE_UNUSED, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003521{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003522 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003523
3524 execflg = 0;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003525 cp = args[1];
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003526 if (cp != NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00003527 setstatus(getn(cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003528
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003529 DBGPRINTF(("DOEXIT: calling leave(), t=%p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003530
Eric Andersenff9eee42001-06-29 04:57:14 +00003531 leave();
3532 /* NOTREACHED */
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003533 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003534}
3535
Denis Vlasenko68404f12008-03-17 09:00:54 +00003536static int doexport(struct op *t ATTRIBUTE_UNUSED, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003537{
Denis Vlasenkofe218832008-03-01 09:35:39 +00003538 rdexp(args + 1, export, EXPORT);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003539 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003540}
3541
Denis Vlasenko68404f12008-03-17 09:00:54 +00003542static int doreadonly(struct op *t ATTRIBUTE_UNUSED, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003543{
Denis Vlasenkofe218832008-03-01 09:35:39 +00003544 rdexp(args + 1, ronly, RONLY);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003545 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003546}
3547
Eric Andersen8401eea2004-08-04 19:16:54 +00003548static void rdexp(char **wp, void (*f) (struct var *), int key)
Eric Andersenff9eee42001-06-29 04:57:14 +00003549{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003550 DBGPRINTF6(("RDEXP: enter, wp=%p, func=%p, key=%d\n", wp, f, key));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003551 DBGPRINTF6(("RDEXP: *wp=%s\n", *wp));
3552
Eric Andersenff9eee42001-06-29 04:57:14 +00003553 if (*wp != NULL) {
Matt Kraaif69bfc72001-07-12 19:39:59 +00003554 for (; *wp != NULL; wp++) {
3555 if (isassign(*wp)) {
3556 char *cp;
Eric Andersen8401eea2004-08-04 19:16:54 +00003557
Matt Kraaif69bfc72001-07-12 19:39:59 +00003558 assign(*wp, COPYV);
Denis Vlasenko509697f2008-03-02 12:49:39 +00003559 for (cp = *wp; *cp != '='; cp++)
3560 continue;
Matt Kraaif69bfc72001-07-12 19:39:59 +00003561 *cp = '\0';
3562 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003563 if (checkname(*wp))
Eric Andersen8401eea2004-08-04 19:16:54 +00003564 (*f) (lookup(*wp));
Eric Andersenff9eee42001-06-29 04:57:14 +00003565 else
3566 badid(*wp);
Matt Kraaif69bfc72001-07-12 19:39:59 +00003567 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003568 } else
3569 putvlist(key, 1);
3570}
3571
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003572static void badid(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003573{
3574 prs(s);
3575 err(": bad identifier");
3576}
3577
Denis Vlasenko68404f12008-03-17 09:00:54 +00003578static int doset(struct op *t ATTRIBUTE_UNUSED, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003579{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003580 struct var *vp;
3581 char *cp;
3582 int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003583
Denis Vlasenkofe218832008-03-01 09:35:39 +00003584 cp = args[1];
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003585 if (cp == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003586 for (vp = vlist; vp; vp = vp->next)
3587 varput(vp->name, 1);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003588 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003589 }
3590 if (*cp == '-') {
Denis Vlasenkofe218832008-03-01 09:35:39 +00003591 args++;
Eric Andersenff9eee42001-06-29 04:57:14 +00003592 if (*++cp == 0)
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003593 FLAG['x'] = FLAG['v'] = 0;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003594 else {
3595 for (; *cp; cp++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003596 switch (*cp) {
3597 case 'e':
3598 if (!interactive)
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003599 FLAG['e']++;
Eric Andersenff9eee42001-06-29 04:57:14 +00003600 break;
3601
3602 default:
Eric Andersen8401eea2004-08-04 19:16:54 +00003603 if (*cp >= 'a' && *cp <= 'z')
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003604 FLAG[(int) *cp]++;
Eric Andersenff9eee42001-06-29 04:57:14 +00003605 break;
3606 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003607 }
3608 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003609 setdash();
3610 }
Denis Vlasenkofe218832008-03-01 09:35:39 +00003611 if (args[1]) {
3612 args[0] = dolv[0];
3613 for (n = 1; args[n]; n++)
3614 setarea((char *) args[n], 0);
Eric Andersen8401eea2004-08-04 19:16:54 +00003615 dolc = n - 1;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003616 dolv = args;
Eric Andersenff9eee42001-06-29 04:57:14 +00003617 setval(lookup("#"), putn(dolc));
Eric Andersen8401eea2004-08-04 19:16:54 +00003618 setarea((char *) (dolv - 1), 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003619 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003620 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003621}
3622
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003623static void varput(char *s, int out)
Eric Andersenff9eee42001-06-29 04:57:14 +00003624{
Matt Kraai69edfec2001-08-06 14:14:18 +00003625 if (isalnum(*s) || *s == '_') {
Eric Andersenff9eee42001-06-29 04:57:14 +00003626 write(out, s, strlen(s));
3627 write(out, "\n", 1);
3628 }
3629}
3630
3631
3632/*
3633 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
3634 * This file contains code for the times builtin.
Eric Andersenff9eee42001-06-29 04:57:14 +00003635 */
Denis Vlasenkofe218832008-03-01 09:35:39 +00003636static void times_fmt(char *buf, clock_t val, unsigned clk_tck)
3637{
3638 unsigned min, sec;
3639 if (sizeof(val) > sizeof(int))
3640 sec = ((unsigned long)val) / clk_tck;
3641 else
3642 sec = ((unsigned)val) / clk_tck;
3643 min = sec / 60;
3644#if ENABLE_DESKTOP
3645 sprintf(buf, "%um%u.%03us", min, (sec - min * 60),
3646 /* msec: */ ((unsigned)(val - (clock_t)sec * clk_tck)) * 1000 / clk_tck
3647 );
3648#else
3649 sprintf(buf, "%um%us", min, (sec - min * 60));
3650#endif
3651}
3652
Denis Vlasenko68404f12008-03-17 09:00:54 +00003653static int dotimes(struct op *t ATTRIBUTE_UNUSED, char **args ATTRIBUTE_UNUSED)
Eric Andersenff9eee42001-06-29 04:57:14 +00003654{
3655 struct tms buf;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003656 unsigned clk_tck = sysconf(_SC_CLK_TCK);
3657 /* How much do we need for "NmN.NNNs" ? */
3658 enum { TIMEBUF_SIZE = sizeof(int)*3 + sizeof(int)*3 + 6 };
3659 char u[TIMEBUF_SIZE], s[TIMEBUF_SIZE];
3660 char cu[TIMEBUF_SIZE], cs[TIMEBUF_SIZE];
Eric Andersenff9eee42001-06-29 04:57:14 +00003661
3662 times(&buf);
Denis Vlasenkofe218832008-03-01 09:35:39 +00003663
3664 times_fmt(u, buf.tms_utime, clk_tck);
3665 times_fmt(s, buf.tms_stime, clk_tck);
3666 times_fmt(cu, buf.tms_cutime, clk_tck);
3667 times_fmt(cs, buf.tms_cstime, clk_tck);
3668
3669 printf("%s %s\n%s %s\n", u, s, cu, cs);
Eric Andersenff9eee42001-06-29 04:57:14 +00003670 return 0;
3671}
3672
3673
Eric Andersenff9eee42001-06-29 04:57:14 +00003674/* -------- eval.c -------- */
3675
3676/*
3677 * ${}
3678 * `command`
3679 * blank interpretation
3680 * quoting
3681 * glob
3682 */
3683
Eric Andersen8401eea2004-08-04 19:16:54 +00003684static char **eval(char **ap, int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003685{
3686 struct wdblock *wb;
3687 char **wp;
3688 char **wf;
3689 jmp_buf ev;
3690
3691#if __GNUC__
3692 /* Avoid longjmp clobbering */
3693 (void) &wp;
3694 (void) &ap;
3695#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00003696
3697 DBGPRINTF4(("EVAL: enter, f=%d\n", f));
3698
Eric Andersenff9eee42001-06-29 04:57:14 +00003699 wp = NULL;
3700 wb = NULL;
3701 wf = NULL;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003702 errpt = ev;
3703 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003704 while (*ap && isassign(*ap))
3705 expand(*ap++, &wb, f & ~DOGLOB);
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003706 if (FLAG['k']) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003707 for (wf = ap; *wf; wf++) {
3708 if (isassign(*wf))
3709 expand(*wf, &wb, f & ~DOGLOB);
3710 }
3711 }
Denis Vlasenko648b44f2008-02-12 06:04:06 +00003712 for (wb = addword((char *) NULL, wb); *ap; ap++) {
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003713 if (!FLAG['k'] || !isassign(*ap))
Eric Andersenff9eee42001-06-29 04:57:14 +00003714 expand(*ap, &wb, f & ~DOKEY);
3715 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003716 wb = addword((char *) 0, wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00003717 wp = getwords(wb);
3718 quitenv();
3719 } else
3720 gflg = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003721
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003722 return gflg ? (char **) NULL : wp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003723}
3724
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003725
Eric Andersenff9eee42001-06-29 04:57:14 +00003726/*
3727 * Make the exported environment from the exported
3728 * names in the dictionary. Keyword assignments
3729 * will already have been done.
3730 */
Eric Andersenfd7a4c82004-09-02 23:13:10 +00003731static char **makenv(int all, struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00003732{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003733 struct var *vp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003734
3735 DBGPRINTF5(("MAKENV: enter, all=%d\n", all));
Eric Andersenff9eee42001-06-29 04:57:14 +00003736
Eric Andersenff9eee42001-06-29 04:57:14 +00003737 for (vp = vlist; vp; vp = vp->next)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003738 if (all || vp->status & EXPORT)
Eric Andersenff9eee42001-06-29 04:57:14 +00003739 wb = addword(vp->name, wb);
Eric Andersen8401eea2004-08-04 19:16:54 +00003740 wb = addword((char *) 0, wb);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003741 return getwords(wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00003742}
3743
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003744static int expand(const char *cp, struct wdblock **wbp, int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003745{
3746 jmp_buf ev;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003747 char *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003748
3749#if __GNUC__
3750 /* Avoid longjmp clobbering */
3751 (void) &cp;
3752#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00003753
3754 DBGPRINTF3(("EXPAND: enter, f=%d\n", f));
3755
Eric Andersenff9eee42001-06-29 04:57:14 +00003756 gflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003757
Eric Andersenff9eee42001-06-29 04:57:14 +00003758 if (cp == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003759 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003760
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003761 if (!anys("$`'\"", cp) && !anys(ifs->value, cp)
3762 && ((f & DOGLOB) == 0 || !anys("[*?", cp))
3763 ) {
3764 xp = strsave(cp, areanum);
Eric Andersenff9eee42001-06-29 04:57:14 +00003765 if (f & DOTRIM)
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003766 unquote(xp);
3767 *wbp = addword(xp, *wbp);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003768 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003769 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003770 errpt = ev;
3771 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003772 PUSHIO(aword, cp, strchar);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003773 global_env.iobase = global_env.iop;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003774 while ((xp = blank(f)) && gflg == 0) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003775 global_env.linep = xp;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003776 xp = strsave(xp, areanum);
Eric Andersen8401eea2004-08-04 19:16:54 +00003777 if ((f & DOGLOB) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003778 if (f & DOTRIM)
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003779 unquote(xp);
3780 *wbp = addword(xp, *wbp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003781 } else
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003782 *wbp = glob(xp, *wbp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003783 }
3784 quitenv();
3785 } else
3786 gflg = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003787 return gflg == 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003788}
3789
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003790static char *evalstr(char *cp, int f)
3791{
3792 struct wdblock *wb;
3793
3794 DBGPRINTF6(("EVALSTR: enter, cp=%p, f=%d\n", cp, f));
3795
3796 wb = NULL;
3797 if (expand(cp, &wb, f)) {
3798 if (wb == NULL || wb->w_nword == 0
3799 || (cp = wb->w_words[0]) == NULL
3800 ) {
Denis Vlasenko8e858e22007-03-07 09:35:43 +00003801// TODO: I suspect that
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003802// char *evalstr(char *cp, int f) is actually
3803// const char *evalstr(const char *cp, int f)!
3804 cp = (char*)"";
3805 }
3806 DELETE(wb);
3807 } else
3808 cp = NULL;
3809 return cp;
3810}
3811
3812
Eric Andersenff9eee42001-06-29 04:57:14 +00003813/*
3814 * Blank interpretation and quoting
3815 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003816static char *blank(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003817{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003818 int c, c1;
3819 char *sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003820 int scanequals, foundequals;
3821
Eric Andersen12de6cf2004-08-04 19:19:10 +00003822 DBGPRINTF3(("BLANK: enter, f=%d\n", f));
3823
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003824 sp = global_env.linep;
Eric Andersenff9eee42001-06-29 04:57:14 +00003825 scanequals = f & DOKEY;
3826 foundequals = 0;
3827
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003828 loop:
3829 c = subgetc('"', foundequals);
3830 switch (c) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003831 case 0:
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003832 if (sp == global_env.linep)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003833 return 0;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003834 *global_env.linep++ = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003835 return sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003836
3837 default:
3838 if (f & DOBLANK && any(c, ifs->value))
3839 goto loop;
3840 break;
3841
3842 case '"':
3843 case '\'':
3844 scanequals = 0;
3845 if (INSUB())
3846 break;
3847 for (c1 = c; (c = subgetc(c1, 1)) != c1;) {
3848 if (c == 0)
3849 break;
3850 if (c == '\'' || !any(c, "$`\""))
3851 c |= QUOTE;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003852 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003853 }
3854 c = 0;
3855 }
3856 unget(c);
Matt Kraai69edfec2001-08-06 14:14:18 +00003857 if (!isalpha(c) && c != '_')
Eric Andersenff9eee42001-06-29 04:57:14 +00003858 scanequals = 0;
3859 for (;;) {
3860 c = subgetc('"', foundequals);
3861 if (c == 0 ||
Eric Andersen8401eea2004-08-04 19:16:54 +00003862 f & (DOBLANK && any(c, ifs->value)) ||
3863 (!INSUB() && any(c, "\"'"))) {
3864 scanequals = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003865 unget(c);
3866 if (any(c, "\"'"))
3867 goto loop;
3868 break;
3869 }
3870 if (scanequals) {
3871 if (c == '=') {
3872 foundequals = 1;
Eric Andersen8401eea2004-08-04 19:16:54 +00003873 scanequals = 0;
3874 } else if (!isalnum(c) && c != '_')
Eric Andersenff9eee42001-06-29 04:57:14 +00003875 scanequals = 0;
3876 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003877 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003878 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003879 *global_env.linep++ = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003880 return sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003881}
3882
3883/*
3884 * Get characters, substituting for ` and $
3885 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003886static int subgetc(char ec, int quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00003887{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003888 char c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003889
3890 DBGPRINTF3(("SUBGETC: enter, quoted=%d\n", quoted));
Eric Andersenff9eee42001-06-29 04:57:14 +00003891
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003892 again:
Eric Andersenff9eee42001-06-29 04:57:14 +00003893 c = my_getc(ec);
3894 if (!INSUB() && ec != '\'') {
3895 if (c == '`') {
3896 if (grave(quoted) == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003897 return 0;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003898 global_env.iop->task = XGRAVE;
Eric Andersenff9eee42001-06-29 04:57:14 +00003899 goto again;
3900 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003901 if (c == '$') {
3902 c = dollar(quoted);
3903 if (c == 0) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003904 global_env.iop->task = XDOLL;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003905 goto again;
3906 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003907 }
3908 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003909 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003910}
3911
3912/*
3913 * Prepare to generate the string returned by ${} substitution.
3914 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003915static int dollar(int quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00003916{
3917 int otask;
3918 struct io *oiop;
3919 char *dolp;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003920 char *s, c, *cp = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00003921 struct var *vp;
3922
Eric Andersen12de6cf2004-08-04 19:19:10 +00003923 DBGPRINTF3(("DOLLAR: enter, quoted=%d\n", quoted));
3924
Eric Andersenff9eee42001-06-29 04:57:14 +00003925 c = readc();
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003926 s = global_env.linep;
Eric Andersenff9eee42001-06-29 04:57:14 +00003927 if (c != '{') {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003928 *global_env.linep++ = c;
Matt Kraai69edfec2001-08-06 14:14:18 +00003929 if (isalpha(c) || c == '_') {
Eric Andersen8401eea2004-08-04 19:16:54 +00003930 while ((c = readc()) != 0 && (isalnum(c) || c == '_'))
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003931 if (global_env.linep < elinep)
3932 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003933 unget(c);
3934 }
3935 c = 0;
3936 } else {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003937 oiop = global_env.iop;
3938 otask = global_env.iop->task;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003939
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003940 global_env.iop->task = XOTHER;
Eric Andersen8401eea2004-08-04 19:16:54 +00003941 while ((c = subgetc('"', 0)) != 0 && c != '}' && c != '\n')
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003942 if (global_env.linep < elinep)
3943 *global_env.linep++ = c;
3944 if (oiop == global_env.iop)
3945 global_env.iop->task = otask;
Eric Andersenff9eee42001-06-29 04:57:14 +00003946 if (c != '}') {
3947 err("unclosed ${");
Denis Vlasenko648b44f2008-02-12 06:04:06 +00003948 gflg = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003949 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003950 }
3951 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003952 if (global_env.linep >= elinep) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003953 err("string in ${} too long");
Denis Vlasenko648b44f2008-02-12 06:04:06 +00003954 gflg = 1;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003955 global_env.linep -= 10;
Eric Andersenff9eee42001-06-29 04:57:14 +00003956 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003957 *global_env.linep = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003958 if (*s)
Eric Andersen8401eea2004-08-04 19:16:54 +00003959 for (cp = s + 1; *cp; cp++)
Eric Andersenff9eee42001-06-29 04:57:14 +00003960 if (any(*cp, "=-+?")) {
3961 c = *cp;
3962 *cp++ = 0;
3963 break;
3964 }
3965 if (s[1] == 0 && (*s == '*' || *s == '@')) {
3966 if (dolc > 1) {
3967 /* currently this does not distinguish $* and $@ */
3968 /* should check dollar */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003969 global_env.linep = s;
Eric Andersen8401eea2004-08-04 19:16:54 +00003970 PUSHIO(awordlist, dolv + 1, dolchar);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003971 return 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00003972 } else { /* trap the nasty ${=} */
Eric Andersenff9eee42001-06-29 04:57:14 +00003973 s[0] = '1';
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003974 s[1] = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00003975 }
3976 }
3977 vp = lookup(s);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003978 dolp = vp->value;
3979 if (dolp == null) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003980 switch (c) {
3981 case '=':
3982 if (isdigit(*s)) {
3983 err("cannot use ${...=...} with $n");
Denis Vlasenko648b44f2008-02-12 06:04:06 +00003984 gflg = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003985 break;
3986 }
3987 setval(vp, cp);
3988 dolp = vp->value;
3989 break;
3990
3991 case '-':
3992 dolp = strsave(cp, areanum);
3993 break;
3994
3995 case '?':
3996 if (*cp == 0) {
3997 prs("missing value for ");
3998 err(s);
3999 } else
4000 err(cp);
Denis Vlasenko648b44f2008-02-12 06:04:06 +00004001 gflg = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004002 break;
4003 }
4004 } else if (c == '+')
4005 dolp = strsave(cp, areanum);
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00004006 if (FLAG['u'] && dolp == null) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004007 prs("unset variable: ");
4008 err(s);
Denis Vlasenko648b44f2008-02-12 06:04:06 +00004009 gflg = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004010 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004011 global_env.linep = s;
Eric Andersenff9eee42001-06-29 04:57:14 +00004012 PUSHIO(aword, dolp, quoted ? qstrchar : strchar);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004013 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004014}
4015
4016/*
4017 * Run the command in `...` and read its output.
4018 */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004019
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004020static int grave(int quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00004021{
Denis Vlasenko55f30b02007-03-24 22:42:29 +00004022 /* moved to G: static char child_cmd[LINELIM]; */
4023
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004024 const char *cp;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004025 int i;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004026 int j;
Eric Andersenff9eee42001-06-29 04:57:14 +00004027 int pf[2];
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004028 const char *src;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004029 char *dest;
4030 int count;
4031 int ignore;
4032 int ignore_once;
4033 char *argument_list[4];
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004034 struct wdblock *wb = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004035
4036#if __GNUC__
4037 /* Avoid longjmp clobbering */
4038 (void) &cp;
4039#endif
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004040
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004041 for (cp = global_env.iop->argp->aword; *cp != '`'; cp++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004042 if (*cp == 0) {
4043 err("no closing `");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004044 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004045 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004046 }
Eric Andersen737f5fb2003-03-14 16:05:59 +00004047
4048 /* string copy with dollar expansion */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004049 src = global_env.iop->argp->aword;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004050 dest = child_cmd;
4051 count = 0;
4052 ignore = 0;
4053 ignore_once = 0;
4054 while ((*src != '`') && (count < LINELIM)) {
4055 if (*src == '\'')
4056 ignore = !ignore;
4057 if (*src == '\\')
4058 ignore_once = 1;
4059 if (*src == '$' && !ignore && !ignore_once) {
4060 struct var *vp;
Denis Vlasenkoab801872007-12-02 08:35:37 +00004061 /* moved to G to reduce stack usage
Eric Andersen737f5fb2003-03-14 16:05:59 +00004062 char var_name[LINELIM];
4063 char alt_value[LINELIM];
Denis Vlasenkoab801872007-12-02 08:35:37 +00004064 */
4065#define var_name (G.grave__var_name)
4066#define alt_value (G.grave__alt_value)
Eric Andersen737f5fb2003-03-14 16:05:59 +00004067 int var_index = 0;
4068 int alt_index = 0;
4069 char operator = 0;
4070 int braces = 0;
4071 char *value;
4072
4073 src++;
4074 if (*src == '{') {
4075 braces = 1;
4076 src++;
4077 }
4078
4079 var_name[var_index++] = *src++;
Paul Fox54690dc2005-07-20 18:33:12 +00004080 while (isalnum(*src) || *src=='_')
Eric Andersen737f5fb2003-03-14 16:05:59 +00004081 var_name[var_index++] = *src++;
4082 var_name[var_index] = 0;
4083
4084 if (braces) {
4085 switch (*src) {
4086 case '}':
4087 break;
4088 case '-':
4089 case '=':
4090 case '+':
4091 case '?':
Eric Andersen8401eea2004-08-04 19:16:54 +00004092 operator = * src;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004093 break;
4094 default:
4095 err("unclosed ${\n");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004096 return 0;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004097 }
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004098 if (operator) {
Eric Andersen737f5fb2003-03-14 16:05:59 +00004099 src++;
4100 while (*src && (*src != '}')) {
4101 alt_value[alt_index++] = *src++;
4102 }
4103 alt_value[alt_index] = 0;
4104 if (*src != '}') {
4105 err("unclosed ${\n");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004106 return 0;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004107 }
4108 }
4109 src++;
4110 }
4111
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004112 if (isalpha(*var_name)) {
4113 /* let subshell handle it instead */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004114
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004115 char *namep = var_name;
4116
4117 *dest++ = '$';
4118 if (braces)
4119 *dest++ = '{';
4120 while (*namep)
4121 *dest++ = *namep++;
4122 if (operator) {
4123 char *altp = alt_value;
4124 *dest++ = operator;
4125 while (*altp)
4126 *dest++ = *altp++;
4127 }
4128 if (braces)
4129 *dest++ = '}';
4130
4131 wb = addword(lookup(var_name)->name, wb);
4132 } else {
4133 /* expand */
4134
4135 vp = lookup(var_name);
4136 if (vp->value != null)
4137 value = (operator == '+') ?
4138 alt_value : vp->value;
4139 else if (operator == '?') {
4140 err(alt_value);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004141 return 0;
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004142 } else if (alt_index && (operator != '+')) {
4143 value = alt_value;
4144 if (operator == '=')
4145 setval(vp, value);
4146 } else
4147 continue;
4148
4149 while (*value && (count < LINELIM)) {
4150 *dest++ = *value++;
4151 count++;
4152 }
Eric Andersen737f5fb2003-03-14 16:05:59 +00004153 }
Denis Vlasenkoab801872007-12-02 08:35:37 +00004154#undef var_name
4155#undef alt_value
Eric Andersen737f5fb2003-03-14 16:05:59 +00004156 } else {
4157 *dest++ = *src++;
4158 count++;
4159 ignore_once = 0;
4160 }
4161 }
4162 *dest = '\0';
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004163
Eric Andersenff9eee42001-06-29 04:57:14 +00004164 if (openpipe(pf) < 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004165 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004166
Denis Vlasenko509697f2008-03-02 12:49:39 +00004167 while ((i = vfork()) == -1 && errno == EAGAIN)
4168 continue;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004169
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004170 DBGPRINTF3(("GRAVE: i is %p\n", io));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004171
Eric Andersen737f5fb2003-03-14 16:05:59 +00004172 if (i < 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004173 closepipe(pf);
Eric Andersen8401eea2004-08-04 19:16:54 +00004174 err((char *) bb_msg_memory_exhausted);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004175 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004176 }
4177 if (i != 0) {
Denis Vlasenkofb0eba72008-01-02 19:55:04 +00004178 waitpid(i, NULL, 0); // safe_waitpid?
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004179 global_env.iop->argp->aword = ++cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004180 close(pf[1]);
Eric Andersen8401eea2004-08-04 19:16:54 +00004181 PUSHIO(afile, remap(pf[0]),
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004182 (int (*)(struct ioarg *)) ((quoted) ? qgravechar : gravechar));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004183 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004184 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004185 /* allow trapped signals */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004186 /* XXX - Maybe this signal stuff should go as well? */
Eric Andersen8401eea2004-08-04 19:16:54 +00004187 for (j = 0; j <= _NSIG; j++)
Eric Andersen737f5fb2003-03-14 16:05:59 +00004188 if (ourtrap[j] && signal(j, SIG_IGN) != SIG_IGN)
4189 signal(j, SIG_DFL);
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004190
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00004191 /* Testcase where below checks are needed:
4192 * close stdout & run this script:
4193 * files=`ls`
4194 * echo "$files" >zz
4195 */
4196 xmove_fd(pf[1], 1);
Denis Vlasenko847fa772008-01-28 22:45:43 +00004197 if (pf[0] != 1)
4198 close(pf[0]);
Eric Andersen737f5fb2003-03-14 16:05:59 +00004199
Eric Andersen8401eea2004-08-04 19:16:54 +00004200 argument_list[0] = (char *) DEFAULT_SHELL;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004201 argument_list[1] = (char *) "-c";
Eric Andersen737f5fb2003-03-14 16:05:59 +00004202 argument_list[2] = child_cmd;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004203 argument_list[3] = NULL;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004204
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004205 cp = rexecve(argument_list[0], argument_list, makenv(1, wb));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004206 prs(argument_list[0]);
4207 prs(": ");
4208 err(cp);
Eric Andersen737f5fb2003-03-14 16:05:59 +00004209 _exit(1);
Eric Andersenff9eee42001-06-29 04:57:14 +00004210}
4211
Eric Andersen737f5fb2003-03-14 16:05:59 +00004212
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004213static char *unquote(char *as)
Eric Andersenff9eee42001-06-29 04:57:14 +00004214{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004215 char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00004216
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004217 s = as;
4218 if (s != NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00004219 while (*s)
4220 *s++ &= ~QUOTE;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004221 return as;
Eric Andersenff9eee42001-06-29 04:57:14 +00004222}
4223
4224/* -------- glob.c -------- */
4225
4226/*
4227 * glob
4228 */
4229
4230#define scopy(x) strsave((x), areanum)
4231#define BLKSIZ 512
4232#define NDENT ((BLKSIZ+sizeof(struct dirent)-1)/sizeof(struct dirent))
4233
Eric Andersen8401eea2004-08-04 19:16:54 +00004234static struct wdblock *cl, *nl;
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00004235static const char spcl[] ALIGN1= "[?*";
Eric Andersenff9eee42001-06-29 04:57:14 +00004236
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004237static struct wdblock *glob(char *cp, struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004238{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004239 int i;
4240 char *pp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004241
4242 if (cp == 0)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004243 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004244 i = 0;
4245 for (pp = cp; *pp; pp++)
4246 if (any(*pp, spcl))
4247 i++;
4248 else if (!any(*pp & ~QUOTE, spcl))
4249 *pp &= ~QUOTE;
4250 if (i != 0) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004251 for (cl = addword(scopy(cp), NULL); anyspcl(cl); cl = nl) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004252 nl = newword(cl->w_nword * 2);
4253 for (i = 0; i < cl->w_nword; i++) { /* for each argument */
Eric Andersenff9eee42001-06-29 04:57:14 +00004254 for (pp = cl->w_words[i]; *pp; pp++)
4255 if (any(*pp, spcl)) {
4256 globname(cl->w_words[i], pp);
4257 break;
4258 }
4259 if (*pp == '\0')
4260 nl = addword(scopy(cl->w_words[i]), nl);
4261 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004262 for (i = 0; i < cl->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004263 DELETE(cl->w_words[i]);
4264 DELETE(cl);
4265 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004266 if (cl->w_nword) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004267 for (i = 0; i < cl->w_nword; i++)
Denis Vlasenkofb290382008-03-02 12:51:26 +00004268 unquote(cl->w_words[i]);
4269 qsort_string_vector(cl->w_words, cl->w_nword);
4270 for (i = 0; i < cl->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004271 wb = addword(cl->w_words[i], wb);
4272 DELETE(cl);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004273 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004274 }
4275 }
4276 wb = addword(unquote(cp), wb);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004277 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004278}
4279
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004280static void globname(char *we, char *pp)
Eric Andersenff9eee42001-06-29 04:57:14 +00004281{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004282 char *np, *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004283 char *name, *gp, *dp;
4284 int k;
4285 DIR *dirp;
4286 struct dirent *de;
Eric Andersen8401eea2004-08-04 19:16:54 +00004287 char dname[NAME_MAX + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00004288 struct stat dbuf;
4289
4290 for (np = we; np != pp; pp--)
4291 if (pp[-1] == '/')
4292 break;
Denis Vlasenkofb290382008-03-02 12:51:26 +00004293 dp = cp = get_space((int) (pp - np) + 3);
4294 while (np < pp)
Eric Andersenff9eee42001-06-29 04:57:14 +00004295 *cp++ = *np++;
4296 *cp++ = '.';
4297 *cp = '\0';
Denis Vlasenkofb290382008-03-02 12:51:26 +00004298 gp = cp = get_space(strlen(pp) + 1);
4299 while (*np && *np != '/')
Eric Andersenff9eee42001-06-29 04:57:14 +00004300 *cp++ = *np++;
4301 *cp = '\0';
4302 dirp = opendir(dp);
4303 if (dirp == 0) {
4304 DELETE(dp);
4305 DELETE(gp);
4306 return;
4307 }
4308 dname[NAME_MAX] = '\0';
Eric Andersen8401eea2004-08-04 19:16:54 +00004309 while ((de = readdir(dirp)) != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004310 /* XXX Hmmm... What this could be? (abial) */
4311 /*
Eric Andersen8401eea2004-08-04 19:16:54 +00004312 if (ent[j].d_ino == 0)
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004313 continue;
Eric Andersen8401eea2004-08-04 19:16:54 +00004314 */
Eric Andersenff9eee42001-06-29 04:57:14 +00004315 strncpy(dname, de->d_name, NAME_MAX);
Eric Andersen8401eea2004-08-04 19:16:54 +00004316 if (dname[0] == '.')
4317 if (*gp != '.')
4318 continue;
4319 for (k = 0; k < NAME_MAX; k++)
4320 if (any(dname[k], spcl))
4321 dname[k] |= QUOTE;
4322 if (gmatch(dname, gp)) {
4323 name = generate(we, pp, dname, np);
4324 if (*np && !anys(np, spcl)) {
4325 if (stat(name, &dbuf)) {
4326 DELETE(name);
Eric Andersenff9eee42001-06-29 04:57:14 +00004327 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00004328 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004329 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004330 nl = addword(name, nl);
4331 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004332 }
4333 closedir(dirp);
4334 DELETE(dp);
4335 DELETE(gp);
4336}
4337
4338/*
4339 * generate a pathname as below.
4340 * start..end1 / middle end
4341 * the slashes come for free
4342 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004343static char *generate(char *start1, char *end1, char *middle, char *end)
Eric Andersenff9eee42001-06-29 04:57:14 +00004344{
4345 char *p;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004346 char *op, *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004347
Denis Vlasenko509697f2008-03-02 12:49:39 +00004348 p = op = get_space((int)(end1 - start1) + strlen(middle) + strlen(end) + 2);
4349 xp = start1;
4350 while (xp != end1)
Eric Andersenff9eee42001-06-29 04:57:14 +00004351 *op++ = *xp++;
Denis Vlasenko509697f2008-03-02 12:49:39 +00004352 xp = middle;
4353 while (*xp != '\0')
4354 *op++ = *xp++;
4355 strcpy(op, end);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004356 return p;
Eric Andersenff9eee42001-06-29 04:57:14 +00004357}
4358
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004359static int anyspcl(struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004360{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004361 int i;
4362 char **wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004363
4364 wd = wb->w_words;
Eric Andersen8401eea2004-08-04 19:16:54 +00004365 for (i = 0; i < wb->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004366 if (anys(spcl, *wd++))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004367 return 1;
4368 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004369}
4370
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004371
Eric Andersenff9eee42001-06-29 04:57:14 +00004372/* -------- word.c -------- */
4373
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004374static struct wdblock *newword(int nw)
Eric Andersenff9eee42001-06-29 04:57:14 +00004375{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004376 struct wdblock *wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004377
Denis Vlasenko509697f2008-03-02 12:49:39 +00004378 wb = get_space(sizeof(*wb) + nw * sizeof(char *));
Eric Andersenff9eee42001-06-29 04:57:14 +00004379 wb->w_bsize = nw;
4380 wb->w_nword = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004381 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004382}
4383
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004384static struct wdblock *addword(char *wd, struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004385{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004386 struct wdblock *wb2;
4387 int nw;
Eric Andersenff9eee42001-06-29 04:57:14 +00004388
4389 if (wb == NULL)
4390 wb = newword(NSTART);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004391 nw = wb->w_nword;
4392 if (nw >= wb->w_bsize) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004393 wb2 = newword(nw * 2);
Eric Andersen8401eea2004-08-04 19:16:54 +00004394 memcpy((char *) wb2->w_words, (char *) wb->w_words,
4395 nw * sizeof(char *));
Eric Andersenff9eee42001-06-29 04:57:14 +00004396 wb2->w_nword = nw;
4397 DELETE(wb);
4398 wb = wb2;
4399 }
4400 wb->w_words[wb->w_nword++] = wd;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004401 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004402}
Eric Andersen8401eea2004-08-04 19:16:54 +00004403
Denis Vlasenkoe4712752007-04-14 15:08:41 +00004404static char **getwords(struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004405{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004406 char **wd;
4407 int nb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004408
4409 if (wb == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004410 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004411 if (wb->w_nword == 0) {
4412 DELETE(wb);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004413 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004414 }
Denis Vlasenko509697f2008-03-02 12:49:39 +00004415 nb = sizeof(*wd) * wb->w_nword;
4416 wd = get_space(nb);
Denis Vlasenkofb290382008-03-02 12:51:26 +00004417 memcpy(wd, wb->w_words, nb);
4418 DELETE(wb); /* perhaps should done by caller */
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004419 return wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004420}
4421
Eric Andersenff9eee42001-06-29 04:57:14 +00004422
4423/* -------- io.c -------- */
4424
4425/*
4426 * shell IO
4427 */
4428
Eric Andersen8401eea2004-08-04 19:16:54 +00004429static int my_getc(int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00004430{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004431 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004432
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004433 if (global_env.linep > elinep) {
Denis Vlasenko509697f2008-03-02 12:49:39 +00004434 while ((c = readc()) != '\n' && c)
4435 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00004436 err("input line too long");
Denis Vlasenko648b44f2008-02-12 06:04:06 +00004437 gflg = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004438 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004439 }
4440 c = readc();
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004441 if ((ec != '\'') && (ec != '`') && (global_env.iop->task != XGRAVE)) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004442 if (c == '\\') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004443 c = readc();
4444 if (c == '\n' && ec != '\"')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004445 return my_getc(ec);
Eric Andersenff9eee42001-06-29 04:57:14 +00004446 c |= QUOTE;
4447 }
4448 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004449 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004450}
4451
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004452static void unget(int c)
Eric Andersenff9eee42001-06-29 04:57:14 +00004453{
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004454 if (global_env.iop >= global_env.iobase)
4455 global_env.iop->peekc = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004456}
4457
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004458static int eofc(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00004459{
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004460 return global_env.iop < global_env.iobase || (global_env.iop->peekc == 0 && global_env.iop->prev == 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004461}
4462
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004463static int readc(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00004464{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004465 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004466
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004467 RCPRINTF(("READC: global_env.iop %p, global_env.iobase %p\n", global_env.iop, global_env.iobase));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004468
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004469 for (; global_env.iop >= global_env.iobase; global_env.iop--) {
4470 RCPRINTF(("READC: global_env.iop %p, peekc 0x%x\n", global_env.iop, global_env.iop->peekc));
4471 c = global_env.iop->peekc;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004472 if (c != '\0') {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004473 global_env.iop->peekc = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004474 return c;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004475 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004476 if (global_env.iop->prev != 0) {
4477 c = (*global_env.iop->iofn)(global_env.iop->argp, global_env.iop);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004478 if (c != '\0') {
4479 if (c == -1) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004480 global_env.iop++;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004481 continue;
Eric Andersen8401eea2004-08-04 19:16:54 +00004482 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004483 if (global_env.iop == iostack)
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004484 ioecho(c);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004485 global_env.iop->prev = c;
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00004486 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004487 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004488 if (global_env.iop->task == XIO && global_env.iop->prev != '\n') {
4489 global_env.iop->prev = 0;
4490 if (global_env.iop == iostack)
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004491 ioecho('\n');
4492 return '\n';
Eric Andersen8401eea2004-08-04 19:16:54 +00004493 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004494 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004495 if (global_env.iop->task == XIO) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004496 if (multiline) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004497 global_env.iop->prev = 0;
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00004498 return 0;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004499 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004500 if (interactive && global_env.iop == iostack + 1) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004501#if ENABLE_FEATURE_EDITING
4502 current_prompt = prompt->value;
4503#else
4504 prs(prompt->value);
4505#endif
4506 }
4507 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004508 } /* FOR */
4509
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004510 if (global_env.iop >= iostack) {
4511 RCPRINTF(("READC: return 0, global_env.iop %p\n", global_env.iop));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004512 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004513 }
4514
4515 DBGPRINTF(("READC: leave()...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00004516 leave();
4517 /* NOTREACHED */
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004518 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004519}
4520
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004521static void ioecho(char c)
Eric Andersenff9eee42001-06-29 04:57:14 +00004522{
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00004523 if (FLAG['v'])
Eric Andersenff9eee42001-06-29 04:57:14 +00004524 write(2, &c, sizeof c);
4525}
4526
Eric Andersen8401eea2004-08-04 19:16:54 +00004527static void pushio(struct ioarg *argp, int (*fn) (struct ioarg *))
Eric Andersenff9eee42001-06-29 04:57:14 +00004528{
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004529 DBGPRINTF(("PUSHIO: argp %p, argp->afid 0x%x, global_env.iop %p\n", argp,
4530 argp->afid, global_env.iop));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004531
4532 /* Set env ptr for io source to next array spot and check for array overflow */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004533 if (++global_env.iop >= &iostack[NPUSH]) {
4534 global_env.iop--;
Eric Andersenff9eee42001-06-29 04:57:14 +00004535 err("Shell input nested too deeply");
Denis Vlasenko648b44f2008-02-12 06:04:06 +00004536 gflg = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004537 return;
4538 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004539
4540 /* We did not overflow the NPUSH array spots so setup data structs */
4541
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004542 global_env.iop->iofn = (int (*)(struct ioarg *, struct io *)) fn; /* Store data source func ptr */
Eric Andersenff9eee42001-06-29 04:57:14 +00004543
4544 if (argp->afid != AFID_NOBUF)
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004545 global_env.iop->argp = argp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004546 else {
Eric Andersen12de6cf2004-08-04 19:19:10 +00004547
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004548 global_env.iop->argp = ioargstack + (global_env.iop - iostack); /* MAL - index into stack */
4549 *global_env.iop->argp = *argp; /* copy data from temp area into stack spot */
Eric Andersen12de6cf2004-08-04 19:19:10 +00004550
4551 /* MAL - mainbuf is for 1st data source (command line?) and all nested use a single shared buffer? */
4552
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004553 if (global_env.iop == &iostack[0])
4554 global_env.iop->argp->afbuf = &mainbuf;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004555 else
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004556 global_env.iop->argp->afbuf = &sharedbuf;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004557
4558 /* MAL - if not a termimal AND (commandline OR readable file) then give it a buffer id? */
4559 /* This line appears to be active when running scripts from command line */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004560 if ((isatty(global_env.iop->argp->afile) == 0)
4561 && (global_env.iop == &iostack[0]
4562 || lseek(global_env.iop->argp->afile, 0L, SEEK_CUR) != -1)) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00004563 if (++bufid == AFID_NOBUF) /* counter rollover check, AFID_NOBUF = 11111111 */
4564 bufid = AFID_ID; /* AFID_ID = 0 */
4565
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004566 global_env.iop->argp->afid = bufid; /* assign buffer id */
Eric Andersen8401eea2004-08-04 19:16:54 +00004567 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004568
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004569 DBGPRINTF(("PUSHIO: iostack %p, global_env.iop %p, afbuf %p\n",
4570 iostack, global_env.iop, global_env.iop->argp->afbuf));
4571 DBGPRINTF(("PUSHIO: mbuf %p, sbuf %p, bid %d, global_env.iop %p\n",
4572 &mainbuf, &sharedbuf, bufid, global_env.iop));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004573
Eric Andersenff9eee42001-06-29 04:57:14 +00004574 }
4575
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004576 global_env.iop->prev = ~'\n';
4577 global_env.iop->peekc = 0;
4578 global_env.iop->xchar = 0;
4579 global_env.iop->nlcount = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004580
Eric Andersenff9eee42001-06-29 04:57:14 +00004581 if (fn == filechar || fn == linechar)
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004582 global_env.iop->task = XIO;
Eric Andersen8401eea2004-08-04 19:16:54 +00004583 else if (fn == (int (*)(struct ioarg *)) gravechar
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00004584 || fn == (int (*)(struct ioarg *)) qgravechar)
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004585 global_env.iop->task = XGRAVE;
Eric Andersenff9eee42001-06-29 04:57:14 +00004586 else
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004587 global_env.iop->task = XOTHER;
Eric Andersenff9eee42001-06-29 04:57:14 +00004588}
4589
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004590static struct io *setbase(struct io *ip)
Eric Andersenff9eee42001-06-29 04:57:14 +00004591{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004592 struct io *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004593
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004594 xp = global_env.iobase;
4595 global_env.iobase = ip;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004596 return xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004597}
4598
4599/*
4600 * Input generating functions
4601 */
4602
4603/*
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00004604 * Produce the characters of a string, then a newline, then NUL.
Eric Andersenff9eee42001-06-29 04:57:14 +00004605 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004606static int nlchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004607{
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00004608 char c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004609
4610 if (ap->aword == NULL)
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00004611 return '\0';
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004612 c = *ap->aword++;
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00004613 if (c == '\0') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004614 ap->aword = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004615 return '\n';
Eric Andersenff9eee42001-06-29 04:57:14 +00004616 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004617 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004618}
4619
4620/*
4621 * Given a list of words, produce the characters
4622 * in them, with a space after each word.
4623 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004624static int wdchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004625{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004626 char c;
4627 char **wl;
Eric Andersenff9eee42001-06-29 04:57:14 +00004628
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004629 wl = ap->awordlist;
4630 if (wl == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004631 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004632 if (*wl != NULL) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004633 c = *(*wl)++;
4634 if (c != 0)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004635 return c & 0177;
Eric Andersenff9eee42001-06-29 04:57:14 +00004636 ap->awordlist++;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004637 return ' ';
Eric Andersenff9eee42001-06-29 04:57:14 +00004638 }
4639 ap->awordlist = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004640 return '\n';
Eric Andersenff9eee42001-06-29 04:57:14 +00004641}
4642
4643/*
4644 * Return the characters of a list of words,
4645 * producing a space between them.
4646 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004647static int dolchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004648{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004649 char *wp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004650
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004651 wp = *ap->awordlist++;
4652 if (wp != NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004653 PUSHIO(aword, wp, *ap->awordlist == NULL ? strchar : xxchar);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004654 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004655 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004656 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004657}
4658
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004659static int xxchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004660{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004661 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004662
4663 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004664 return 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004665 c = *ap->aword++;
4666 if (c == '\0') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004667 ap->aword = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004668 return ' ';
Eric Andersenff9eee42001-06-29 04:57:14 +00004669 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004670 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004671}
4672
4673/*
4674 * Produce the characters from a single word (string).
4675 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004676static int strchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004677{
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004678 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004679 return 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004680 return *ap->aword++;
Eric Andersenff9eee42001-06-29 04:57:14 +00004681}
4682
4683/*
4684 * Produce quoted characters from a single word (string).
4685 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004686static int qstrchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004687{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004688 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004689
Denis Vlasenkob2abef32007-01-01 18:18:04 +00004690 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004691 return 0;
Denis Vlasenkob2abef32007-01-01 18:18:04 +00004692 c = *ap->aword++;
4693 if (c)
4694 c |= QUOTE;
4695 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004696}
4697
4698/*
4699 * Return the characters from a file.
4700 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004701static int filechar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004702{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004703 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004704 char c;
4705 struct iobuf *bp = ap->afbuf;
4706
4707 if (ap->afid != AFID_NOBUF) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004708 i = (ap->afid != bp->id);
4709 if (i || bp->bufp == bp->ebufp) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004710 if (i)
Denis Vlasenkoea620772006-10-14 02:23:43 +00004711 lseek(ap->afile, ap->afpos, SEEK_SET);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004712
Denis Vlasenkoe376d452008-02-20 22:23:24 +00004713 i = nonblock_safe_read(ap->afile, bp->buf, sizeof(bp->buf));
Eric Andersen8401eea2004-08-04 19:16:54 +00004714 if (i <= 0) {
4715 closef(ap->afile);
4716 return 0;
4717 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004718
Eric Andersen8401eea2004-08-04 19:16:54 +00004719 bp->id = ap->afid;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004720 bp->bufp = bp->buf;
4721 bp->ebufp = bp->bufp + i;
Eric Andersen8401eea2004-08-04 19:16:54 +00004722 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004723
Eric Andersen8401eea2004-08-04 19:16:54 +00004724 ap->afpos++;
4725 return *bp->bufp++ & 0177;
Eric Andersenff9eee42001-06-29 04:57:14 +00004726 }
Denis Vlasenko38f63192007-01-22 09:03:07 +00004727#if ENABLE_FEATURE_EDITING
Eric Andersen737f5fb2003-03-14 16:05:59 +00004728 if (interactive && isatty(ap->afile)) {
Denis Vlasenko55f30b02007-03-24 22:42:29 +00004729 /* moved to G: static char filechar_cmdbuf[BUFSIZ]; */
Eric Andersen8401eea2004-08-04 19:16:54 +00004730 static int position = 0, size = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004731
Eric Andersen8401eea2004-08-04 19:16:54 +00004732 while (size == 0 || position >= size) {
Denis Vlasenko6e602c42008-02-02 18:50:50 +00004733 size = read_line_input(current_prompt, filechar_cmdbuf, BUFSIZ, line_input_state);
4734 if (size < 0) /* Error/EOF */
4735 exit(0);
Eric Andersen8401eea2004-08-04 19:16:54 +00004736 position = 0;
Denis Vlasenko6e602c42008-02-02 18:50:50 +00004737 /* if Ctrl-C, size == 0 and loop will repeat */
Eric Andersen8401eea2004-08-04 19:16:54 +00004738 }
Denis Vlasenko55f30b02007-03-24 22:42:29 +00004739 c = filechar_cmdbuf[position];
Eric Andersen8401eea2004-08-04 19:16:54 +00004740 position++;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004741 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004742 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004743#endif
Denis Vlasenkoe376d452008-02-20 22:23:24 +00004744 i = nonblock_safe_read(ap->afile, &c, sizeof(c));
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004745 return i == sizeof(c) ? (c & 0x7f) : (closef(ap->afile), 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004746}
4747
4748/*
4749 * Return the characters from a here temp file.
4750 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004751static int herechar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004752{
4753 char c;
4754
Denis Vlasenkoe376d452008-02-20 22:23:24 +00004755 if (nonblock_safe_read(ap->afile, &c, sizeof(c)) != sizeof(c)) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004756 close(ap->afile);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004757 c = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00004758 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004759 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004760}
4761
4762/*
4763 * Return the characters produced by a process (`...`).
4764 * Quote them if required, and remove any trailing newline characters.
4765 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004766static int gravechar(struct ioarg *ap, struct io *iop)
Eric Andersenff9eee42001-06-29 04:57:14 +00004767{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004768 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004769
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004770 c = qgravechar(ap, iop) & ~QUOTE;
4771 if (c == '\n')
Eric Andersenff9eee42001-06-29 04:57:14 +00004772 c = ' ';
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004773 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004774}
4775
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004776static int qgravechar(struct ioarg *ap, struct io *iop)
Eric Andersenff9eee42001-06-29 04:57:14 +00004777{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004778 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004779
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004780 DBGPRINTF3(("QGRAVECHAR: enter, ap=%p, iop=%p\n", ap, iop));
Eric Andersenff9eee42001-06-29 04:57:14 +00004781
4782 if (iop->xchar) {
4783 if (iop->nlcount) {
4784 iop->nlcount--;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004785 return '\n' | QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00004786 }
4787 c = iop->xchar;
4788 iop->xchar = 0;
4789 } else if ((c = filechar(ap)) == '\n') {
4790 iop->nlcount = 1;
4791 while ((c = filechar(ap)) == '\n')
4792 iop->nlcount++;
4793 iop->xchar = c;
4794 if (c == 0)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004795 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004796 iop->nlcount--;
4797 c = '\n';
4798 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004799 return c != 0 ? c | QUOTE : 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004800}
4801
4802/*
4803 * Return a single command (usually the first line) from a file.
4804 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004805static int linechar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004806{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004807 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004808
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004809 c = filechar(ap);
4810 if (c == '\n') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004811 if (!multiline) {
4812 closef(ap->afile);
Eric Andersen8401eea2004-08-04 19:16:54 +00004813 ap->afile = -1; /* illegal value */
Eric Andersenff9eee42001-06-29 04:57:14 +00004814 }
4815 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004816 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004817}
4818
Eric Andersenff9eee42001-06-29 04:57:14 +00004819/*
4820 * remap fd into Shell's fd space
4821 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004822static int remap(int fd)
Eric Andersenff9eee42001-06-29 04:57:14 +00004823{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004824 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004825 int map[NOFILE];
Eric Andersen12de6cf2004-08-04 19:19:10 +00004826 int newfd;
4827
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004828 DBGPRINTF(("REMAP: fd=%d, global_env.iofd=%d\n", fd, global_env.iofd));
Eric Andersenff9eee42001-06-29 04:57:14 +00004829
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004830 if (fd < global_env.iofd) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004831 for (i = 0; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004832 map[i] = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004833
Eric Andersenff9eee42001-06-29 04:57:14 +00004834 do {
4835 map[fd] = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004836 newfd = dup(fd);
4837 fd = newfd;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004838 } while (fd >= 0 && fd < global_env.iofd);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004839
Eric Andersen8401eea2004-08-04 19:16:54 +00004840 for (i = 0; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004841 if (map[i])
4842 close(i);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004843
Eric Andersenff9eee42001-06-29 04:57:14 +00004844 if (fd < 0)
4845 err("too many files open in shell");
4846 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004847
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004848 return fd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004849}
4850
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004851static int openpipe(int *pv)
Eric Andersenff9eee42001-06-29 04:57:14 +00004852{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004853 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004854
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004855 i = pipe(pv);
4856 if (i < 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00004857 err("can't create pipe - try again");
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004858 return i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004859}
4860
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004861static void closepipe(int *pv)
Eric Andersenff9eee42001-06-29 04:57:14 +00004862{
4863 if (pv != NULL) {
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00004864 close(pv[0]);
4865 close(pv[1]);
Eric Andersenff9eee42001-06-29 04:57:14 +00004866 }
4867}
4868
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004869
Eric Andersenff9eee42001-06-29 04:57:14 +00004870/* -------- here.c -------- */
4871
4872/*
4873 * here documents
4874 */
4875
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004876static void markhere(char *s, struct ioword *iop)
Eric Andersenff9eee42001-06-29 04:57:14 +00004877{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004878 struct here *h, *lh;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004879
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004880 DBGPRINTF7(("MARKHERE: enter, s=%p\n", s));
Eric Andersenff9eee42001-06-29 04:57:14 +00004881
Denis Vlasenko509697f2008-03-02 12:49:39 +00004882 h = get_space(sizeof(struct here));
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004883 if (h == NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00004884 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004885
Eric Andersenff9eee42001-06-29 04:57:14 +00004886 h->h_tag = evalstr(s, DOSUB);
4887 if (h->h_tag == 0)
4888 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004889
Eric Andersenff9eee42001-06-29 04:57:14 +00004890 h->h_iop = iop;
4891 iop->io_name = 0;
4892 h->h_next = NULL;
4893 if (inhere == 0)
4894 inhere = h;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004895 else {
4896 for (lh = inhere; lh != NULL; lh = lh->h_next) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004897 if (lh->h_next == 0) {
4898 lh->h_next = h;
4899 break;
4900 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004901 }
4902 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004903 iop->io_flag |= IOHERE | IOXHERE;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004904 for (s = h->h_tag; *s; s++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004905 if (*s & QUOTE) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004906 iop->io_flag &= ~IOXHERE;
4907 *s &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00004908 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004909 }
Denis Vlasenko648b44f2008-02-12 06:04:06 +00004910 h->h_dosub = ((iop->io_flag & IOXHERE) ? '\0' : '\'');
Eric Andersenff9eee42001-06-29 04:57:14 +00004911}
4912
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004913static void gethere(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00004914{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004915 struct here *h, *hp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004916
4917 DBGPRINTF7(("GETHERE: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00004918
4919 /* Scan here files first leaving inhere list in place */
4920 for (hp = h = inhere; h != NULL; hp = h, h = h->h_next)
Denis Vlasenko648b44f2008-02-12 06:04:06 +00004921 readhere(&h->h_iop->io_name, h->h_tag, h->h_dosub /* NUL or ' */);
Eric Andersenff9eee42001-06-29 04:57:14 +00004922
4923 /* Make inhere list active - keep list intact for scraphere */
4924 if (hp != NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004925 hp->h_next = acthere;
4926 acthere = inhere;
4927 inhere = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004928 }
4929}
4930
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004931static void readhere(char **name, char *s, int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00004932{
4933 int tf;
4934 char tname[30] = ".msh_XXXXXX";
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004935 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004936 jmp_buf ev;
Eric Andersen8401eea2004-08-04 19:16:54 +00004937 char myline[LINELIM + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00004938 char *thenext;
4939
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004940 DBGPRINTF7(("READHERE: enter, name=%p, s=%p\n", name, s));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004941
Eric Andersenff9eee42001-06-29 04:57:14 +00004942 tf = mkstemp(tname);
4943 if (tf < 0)
4944 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004945
Eric Andersenff9eee42001-06-29 04:57:14 +00004946 *name = strsave(tname, areanum);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004947 errpt = ev;
4948 if (newenv(setjmp(errpt)) != 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00004949 unlink(tname);
4950 else {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004951 pushio(global_env.iop->argp, (int (*)(struct ioarg *)) global_env.iop->iofn);
4952 global_env.iobase = global_env.iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00004953 for (;;) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004954 if (interactive && global_env.iop <= iostack) {
Denis Vlasenko38f63192007-01-22 09:03:07 +00004955#if ENABLE_FEATURE_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00004956 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00004957#else
Eric Andersen8401eea2004-08-04 19:16:54 +00004958 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00004959#endif
4960 }
4961 thenext = myline;
4962 while ((c = my_getc(ec)) != '\n' && c) {
4963 if (ec == '\'')
Eric Andersen8401eea2004-08-04 19:16:54 +00004964 c &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00004965 if (thenext >= &myline[LINELIM]) {
4966 c = 0;
4967 break;
4968 }
4969 *thenext++ = c;
4970 }
4971 *thenext = 0;
4972 if (strcmp(s, myline) == 0 || c == 0)
4973 break;
4974 *thenext++ = '\n';
Eric Andersen8401eea2004-08-04 19:16:54 +00004975 write(tf, myline, (int) (thenext - myline));
Eric Andersenff9eee42001-06-29 04:57:14 +00004976 }
4977 if (c == 0) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004978 prs("here document `");
4979 prs(s);
4980 err("' unclosed");
Eric Andersenff9eee42001-06-29 04:57:14 +00004981 }
4982 quitenv();
4983 }
4984 close(tf);
4985}
4986
4987/*
4988 * open here temp file.
4989 * if unquoted here, expand here temp file into second temp file.
4990 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004991static int herein(char *hname, int xdoll)
Eric Andersenff9eee42001-06-29 04:57:14 +00004992{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004993 int hf;
Eric Andersenff9eee42001-06-29 04:57:14 +00004994 int tf;
4995
4996#if __GNUC__
4997 /* Avoid longjmp clobbering */
4998 (void) &tf;
4999#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00005000 if (hname == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00005001 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005002
5003 DBGPRINTF7(("HEREIN: hname is %s, xdoll=%d\n", hname, xdoll));
5004
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005005 hf = open(hname, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00005006 if (hf < 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00005007 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005008
Eric Andersenff9eee42001-06-29 04:57:14 +00005009 if (xdoll) {
5010 char c;
5011 char tname[30] = ".msh_XXXXXX";
5012 jmp_buf ev;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005013
Eric Andersenff9eee42001-06-29 04:57:14 +00005014 tf = mkstemp(tname);
5015 if (tf < 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00005016 return -1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00005017 errpt = ev;
5018 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00005019 PUSHIO(afile, hf, herechar);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005020 setbase(global_env.iop);
Eric Andersenff9eee42001-06-29 04:57:14 +00005021 while ((c = subgetc(0, 0)) != 0) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005022 c &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00005023 write(tf, &c, sizeof c);
5024 }
5025 quitenv();
5026 } else
5027 unlink(tname);
5028 close(tf);
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005029 tf = open(tname, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00005030 unlink(tname);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00005031 return tf;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00005032 }
5033 return hf;
Eric Andersenff9eee42001-06-29 04:57:14 +00005034}
5035
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005036static void scraphere(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00005037{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005038 struct here *h;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005039
5040 DBGPRINTF7(("SCRAPHERE: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00005041
5042 for (h = inhere; h != NULL; h = h->h_next) {
5043 if (h->h_iop && h->h_iop->io_name)
Eric Andersen8401eea2004-08-04 19:16:54 +00005044 unlink(h->h_iop->io_name);
Eric Andersenff9eee42001-06-29 04:57:14 +00005045 }
5046 inhere = NULL;
5047}
5048
5049/* unlink here temp files before a freearea(area) */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005050static void freehere(int area)
Eric Andersenff9eee42001-06-29 04:57:14 +00005051{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005052 struct here *h, *hl;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005053
5054 DBGPRINTF6(("FREEHERE: enter, area=%d\n", area));
Eric Andersenff9eee42001-06-29 04:57:14 +00005055
5056 hl = NULL;
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00005057 for (h = acthere; h != NULL; h = h->h_next) {
Eric Andersenff9eee42001-06-29 04:57:14 +00005058 if (getarea((char *) h) >= area) {
5059 if (h->h_iop->io_name != NULL)
5060 unlink(h->h_iop->io_name);
5061 if (hl == NULL)
5062 acthere = h->h_next;
5063 else
5064 hl->h_next = h->h_next;
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00005065 } else {
Eric Andersenff9eee42001-06-29 04:57:14 +00005066 hl = h;
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00005067 }
5068 }
Eric Andersenff9eee42001-06-29 04:57:14 +00005069}
5070
5071
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005072/* -------- sh.c -------- */
5073/*
5074 * shell
5075 */
5076
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00005077int msh_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005078int msh_main(int argc, char **argv)
5079{
5080 int f;
5081 char *s;
5082 int cflag;
5083 char *name, **ap;
5084 int (*iof) (struct ioarg *);
5085
Denis Vlasenkoab801872007-12-02 08:35:37 +00005086 INIT_G();
5087
Denis Vlasenko55f30b02007-03-24 22:42:29 +00005088 sharedbuf.id = AFID_NOBUF;
5089 mainbuf.id = AFID_NOBUF;
Denis Vlasenko55f30b02007-03-24 22:42:29 +00005090 elinep = line + sizeof(line) - 5;
5091
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005092#if ENABLE_FEATURE_EDITING
5093 line_input_state = new_line_input_t(FOR_SHELL);
5094#endif
5095
5096 DBGPRINTF(("MSH_MAIN: argc %d, environ %p\n", argc, environ));
5097
5098 initarea();
5099 ap = environ;
5100 if (ap != NULL) {
5101 while (*ap)
5102 assign(*ap++, !COPYV);
5103 for (ap = environ; *ap;)
5104 export(lookup(*ap++));
5105 }
5106 closeall();
5107 areanum = 1;
5108
5109 shell = lookup("SHELL");
5110 if (shell->value == null)
5111 setval(shell, (char *)DEFAULT_SHELL);
5112 export(shell);
5113
5114 homedir = lookup("HOME");
5115 if (homedir->value == null)
5116 setval(homedir, "/");
5117 export(homedir);
5118
5119 setval(lookup("$"), putn(getpid()));
5120
5121 path = lookup("PATH");
5122 if (path->value == null) {
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005123 /* Can be merged with same string elsewhere in bbox */
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005124 if (geteuid() == 0)
Denis Vlasenkof5f75c52007-06-12 22:35:19 +00005125 setval(path, bb_default_root_path);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005126 else
Denis Vlasenkof5f75c52007-06-12 22:35:19 +00005127 setval(path, bb_default_path);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005128 }
5129 export(path);
5130
5131 ifs = lookup("IFS");
5132 if (ifs->value == null)
5133 setval(ifs, " \t\n");
5134
5135#ifdef MSHDEBUG
5136 mshdbg_var = lookup("MSHDEBUG");
5137 if (mshdbg_var->value == null)
5138 setval(mshdbg_var, "0");
5139#endif
5140
5141 prompt = lookup("PS1");
5142#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
5143 if (prompt->value == null)
5144#endif
5145 setval(prompt, DEFAULT_USER_PROMPT);
5146 if (geteuid() == 0) {
5147 setval(prompt, DEFAULT_ROOT_PROMPT);
5148 prompt->status &= ~EXPORT;
5149 }
5150 cprompt = lookup("PS2");
5151#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
5152 if (cprompt->value == null)
5153#endif
5154 setval(cprompt, "> ");
5155
5156 iof = filechar;
5157 cflag = 0;
5158 name = *argv++;
5159 if (--argc >= 1) {
5160 if (argv[0][0] == '-' && argv[0][1] != '\0') {
5161 for (s = argv[0] + 1; *s; s++)
5162 switch (*s) {
5163 case 'c':
5164 prompt->status &= ~EXPORT;
5165 cprompt->status &= ~EXPORT;
5166 setval(prompt, "");
5167 setval(cprompt, "");
5168 cflag = 1;
5169 if (--argc > 0)
5170 PUSHIO(aword, *++argv, iof = nlchar);
5171 break;
5172
5173 case 'q':
5174 qflag = SIG_DFL;
5175 break;
5176
5177 case 's':
5178 /* standard input */
5179 break;
5180
5181 case 't':
5182 prompt->status &= ~EXPORT;
5183 setval(prompt, "");
5184 iof = linechar;
5185 break;
5186
5187 case 'i':
Denis Vlasenko648b44f2008-02-12 06:04:06 +00005188 interactive = 1;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005189 default:
5190 if (*s >= 'a' && *s <= 'z')
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00005191 FLAG[(int) *s]++;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005192 }
5193 } else {
5194 argv--;
5195 argc++;
5196 }
5197
5198 if (iof == filechar && --argc > 0) {
5199 setval(prompt, "");
5200 setval(cprompt, "");
5201 prompt->status &= ~EXPORT;
5202 cprompt->status &= ~EXPORT;
5203
5204/* Shell is non-interactive, activate printf-based debug */
5205#ifdef MSHDEBUG
5206 mshdbg = (int) (((char) (mshdbg_var->value[0])) - '0');
5207 if (mshdbg < 0)
5208 mshdbg = 0;
5209#endif
5210 DBGPRINTF(("MSH_MAIN: calling newfile()\n"));
5211
5212 name = *++argv;
5213 if (newfile(name))
5214 exit(1); /* Exit on error */
5215 }
5216 }
5217
5218 setdash();
5219
5220 /* This won't be true if PUSHIO has been called, say from newfile() above */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005221 if (global_env.iop < iostack) {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005222 PUSHIO(afile, 0, iof);
5223 if (isatty(0) && isatty(1) && !cflag) {
Denis Vlasenko648b44f2008-02-12 06:04:06 +00005224 interactive = 1;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005225#if !ENABLE_FEATURE_SH_EXTRA_QUIET
5226#ifdef MSHDEBUG
Denis Vlasenkoca525b42007-06-13 12:27:17 +00005227 printf("\n\n%s built-in shell (msh with debug)\n", bb_banner);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005228#else
Denis Vlasenkoca525b42007-06-13 12:27:17 +00005229 printf("\n\n%s built-in shell (msh)\n", bb_banner);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005230#endif
5231 printf("Enter 'help' for a list of built-in commands.\n\n");
5232#endif
5233 }
5234 }
5235
5236 signal(SIGQUIT, qflag);
5237 if (name && name[0] == '-') {
Denis Vlasenko648b44f2008-02-12 06:04:06 +00005238 interactive = 1;
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005239 f = open(".profile", O_RDONLY);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005240 if (f >= 0)
5241 next(remap(f));
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005242 f = open("/etc/profile", O_RDONLY);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005243 if (f >= 0)
5244 next(remap(f));
5245 }
5246 if (interactive)
5247 signal(SIGTERM, sig);
5248
5249 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
5250 signal(SIGINT, onintr);
Denis Vlasenkofee2d0c2008-02-12 10:12:18 +00005251
5252/* Handle "msh SCRIPT VAR=val params..." */
5253/* Disabled: bash does not do it! */
5254#if 0
5255 argv++;
5256 /* skip leading args of the form VAR=val */
5257 while (*argv && assign(*argv, !COPYV)) {
5258 argc--;
5259 argv++;
5260 }
5261 argv--;
5262#endif
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005263 dolv = argv;
5264 dolc = argc;
5265 dolv[0] = name;
Denis Vlasenkofee2d0c2008-02-12 10:12:18 +00005266
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005267 setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc));
5268
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005269 DBGPRINTF(("MSH_MAIN: begin FOR loop, interactive %d, global_env.iop %p, iostack %p\n", interactive, global_env.iop, iostack));
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005270
5271 for (;;) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005272 if (interactive && global_env.iop <= iostack) {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005273#if ENABLE_FEATURE_EDITING
5274 current_prompt = prompt->value;
5275#else
5276 prs(prompt->value);
5277#endif
5278 }
5279 onecommand();
5280 /* Ensure that getenv("PATH") stays current */
5281 setenv("PATH", path->value, 1);
5282 }
5283
5284 DBGPRINTF(("MSH_MAIN: returning.\n"));
5285}
5286
5287
Eric Andersenff9eee42001-06-29 04:57:14 +00005288/*
5289 * Copyright (c) 1987,1997, Prentice Hall
5290 * All rights reserved.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005291 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005292 * Redistribution and use of the MINIX operating system in source and
5293 * binary forms, with or without modification, are permitted provided
5294 * that the following conditions are met:
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005295 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005296 * Redistributions of source code must retain the above copyright
5297 * notice, this list of conditions and the following disclaimer.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005298 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005299 * Redistributions in binary form must reproduce the above
5300 * copyright notice, this list of conditions and the following
5301 * disclaimer in the documentation and/or other materials provided
5302 * with the distribution.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005303 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005304 * Neither the name of Prentice Hall nor the names of the software
5305 * authors or contributors may be used to endorse or promote
5306 * products derived from this software without specific prior
5307 * written permission.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005308 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005309 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND
5310 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
5311 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
5312 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
5313 * IN NO EVENT SHALL PRENTICE HALL OR ANY AUTHORS OR CONTRIBUTORS BE
5314 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
5315 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
5316 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
5317 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
5318 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
5319 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
5320 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5321 *
5322 */