blob: a96e799e2a66ee9a16dab3b98ef8191fccc8b5f1 [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 Vlasenkoc6938402008-03-24 02:18:03 +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
Denis Vlasenko68404f12008-03-17 09:00:54 +0000591static struct op *dowholefile(int /*, int*/);
Eric Andersen12de6cf2004-08-04 19:19:10 +0000592
Eric Andersen12de6cf2004-08-04 19:19:10 +0000593
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000594/* Globals */
Eric Andersen8401eea2004-08-04 19:16:54 +0000595static char **dolv;
596static int dolc;
597static int exstat;
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000598static smallint gflg; /* (seems to be a parse error indicator) */
599static smallint interactive; /* Is this an interactive shell */
600static smallint execflg;
601static smallint isbreak; /* "break" statement was seen */
602static int multiline; /* '\n' changed to ';' (counter) */
603static struct op *outtree; /* result from parser */
Eric Andersen8401eea2004-08-04 19:16:54 +0000604static xint *failpt;
605static xint *errpt;
606static struct brkcon *brklist;
Eric Andersen8401eea2004-08-04 19:16:54 +0000607static struct wdblock *wdlist;
608static struct wdblock *iolist;
Eric Andersen12de6cf2004-08-04 19:19:10 +0000609
610#ifdef MSHDEBUG
611static struct var *mshdbg_var;
612#endif
Eric Andersen8401eea2004-08-04 19:16:54 +0000613static struct var *vlist; /* dictionary */
614static struct var *homedir; /* home directory */
615static struct var *prompt; /* main prompt */
616static struct var *cprompt; /* continuation prompt */
617static struct var *path; /* search path for commands */
618static struct var *shell; /* shell to interpret command files */
619static struct var *ifs; /* field separators */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000620
Denis Vlasenko95cb3262007-04-09 03:06:34 +0000621static int areanum; /* current allocation area */
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000622static smallint intr; /* interrupt pending (bool) */
623static smallint heedint = 1; /* heed interrupt signals (bool) */
Eric Andersen8401eea2004-08-04 19:16:54 +0000624static int inparse;
Denis Vlasenko95cb3262007-04-09 03:06:34 +0000625static char *null = (char*)""; /* null value for variable */
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +0000626static void (*qflag)(int) = SIG_IGN;
Eric Andersen8401eea2004-08-04 19:16:54 +0000627static int startl;
628static int peeksym;
629static int nlseen;
630static int iounit = IODEFAULT;
631static YYSTYPE yylval;
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000632static char *elinep; /* done in main(): = line + sizeof(line) - 5 */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000633
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000634static struct here *inhere; /* list of hear docs while parsing */
635static struct here *acthere; /* list of active here documents */
636static struct region *areabot; /* bottom of area */
637static struct region *areatop; /* top of area */
638static struct region *areanxt; /* starting point of scan */
Eric Andersen8401eea2004-08-04 19:16:54 +0000639static void *brktop;
640static void *brkaddr;
Eric Andersenff9eee42001-06-29 04:57:14 +0000641
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000642#define AFID_NOBUF (~0)
643#define AFID_ID 0
644
645
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000646/*
647 * parsing & execution environment
648 */
649struct env {
650 char *linep;
651 struct io *iobase;
652 struct io *iop;
653 xint *errpt; /* void * */
654 int iofd;
655 struct env *oenv;
656};
657
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000658
659struct globals {
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000660 struct env global_env;
661 struct ioarg temparg; // = { .afid = AFID_NOBUF }; /* temporary for PUSHIO */
662 unsigned bufid; // = AFID_ID; /* buffer id counter */
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000663 char ourtrap[_NSIG + 1];
664 char *trap[_NSIG + 1];
665 struct iobuf sharedbuf; /* in main(): set to { AFID_NOBUF } */
666 struct iobuf mainbuf; /* in main(): set to { AFID_NOBUF } */
667 struct ioarg ioargstack[NPUSH];
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000668 /*
669 * flags:
670 * -e: quit on error
671 * -k: look for name=value everywhere on command line
672 * -n: no execution
673 * -t: exit after reading and executing one command
674 * -v: echo as read
675 * -x: trace
676 * -u: unset variables net diagnostic
677 */
678 char flags['z' - 'a' + 1];
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000679 char filechar_cmdbuf[BUFSIZ];
680 char line[LINELIM];
681 char child_cmd[LINELIM];
Denis Vlasenkoab801872007-12-02 08:35:37 +0000682
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000683 struct io iostack[NPUSH];
684
Denis Vlasenkoab801872007-12-02 08:35:37 +0000685 char grave__var_name[LINELIM];
686 char grave__alt_value[LINELIM];
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000687};
688
689#define G (*ptr_to_globals)
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000690#define global_env (G.global_env )
691#define temparg (G.temparg )
692#define bufid (G.bufid )
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000693#define ourtrap (G.ourtrap )
694#define trap (G.trap )
695#define sharedbuf (G.sharedbuf )
696#define mainbuf (G.mainbuf )
697#define ioargstack (G.ioargstack )
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000698/* this looks weird, but is OK ... we index FLAG with 'a'...'z' */
699#define FLAG (G.flags - 'a' )
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000700#define filechar_cmdbuf (G.filechar_cmdbuf)
701#define line (G.line )
702#define child_cmd (G.child_cmd )
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000703#define iostack (G.iostack )
Denis Vlasenkoab801872007-12-02 08:35:37 +0000704#define INIT_G() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000705 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000706 global_env.linep = line; \
707 global_env.iobase = iostack; \
708 global_env.iop = iostack - 1; \
709 global_env.iofd = FDBASE; \
710 temparg.afid = AFID_NOBUF; \
711 bufid = AFID_ID; \
Denis Vlasenkoab801872007-12-02 08:35:37 +0000712} while (0)
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000713
714
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000715/* in substitution */
716#define INSUB() (global_env.iop->task == XGRAVE || global_env.iop->task == XDOLL)
717
718#define RUN(what, arg, gen) ((temparg.what = (arg)), run(&temparg, (gen)))
719
Eric Andersen12de6cf2004-08-04 19:19:10 +0000720#ifdef MSHDEBUG
Denis Vlasenko509697f2008-03-02 12:49:39 +0000721static void print_tree(struct op *head)
Eric Andersen12de6cf2004-08-04 19:19:10 +0000722{
723 if (head == NULL) {
724 DBGPRINTF(("PRINT_TREE: no tree\n"));
725 return;
726 }
727
Mike Frysinger02d8fa42006-05-05 20:32:31 +0000728 DBGPRINTF(("NODE: %p, left %p, right %p\n", head, head->left,
Eric Andersen12de6cf2004-08-04 19:19:10 +0000729 head->right));
730
731 if (head->left)
732 print_tree(head->left);
733
734 if (head->right)
735 print_tree(head->right);
Eric Andersen12de6cf2004-08-04 19:19:10 +0000736}
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000737#endif /* MSHDEBUG */
738
739
740/*
741 * IO functions
742 */
743static void prs(const char *s)
744{
745 if (*s)
746 write(2, s, strlen(s));
747}
748
749static void prn(unsigned u)
750{
751 prs(itoa(u));
752}
753
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000754static void echo(char **wp)
755{
756 int i;
757
758 prs("+");
759 for (i = 0; wp[i]; i++) {
760 if (i)
761 prs(" ");
762 prs(wp[i]);
763 }
764 prs("\n");
765}
766
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000767static void closef(int i)
768{
769 if (i > 2)
770 close(i);
771}
772
773static void closeall(void)
774{
775 int u;
776
777 for (u = NUFILE; u < NOFILE;)
778 close(u++);
779}
Eric Andersen12de6cf2004-08-04 19:19:10 +0000780
Eric Andersenff9eee42001-06-29 04:57:14 +0000781
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000782/* fail but return to process next command */
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000783static void fail(void) ATTRIBUTE_NORETURN;
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000784static void fail(void)
785{
786 longjmp(failpt, 1);
787 /* NOTREACHED */
788}
Eric Andersenff9eee42001-06-29 04:57:14 +0000789
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000790/* abort shell (or fail in subshell) */
791static void leave(void) ATTRIBUTE_NORETURN;
792static void leave(void)
793{
794 DBGPRINTF(("LEAVE: leave called!\n"));
795
796 if (execflg)
797 fail();
798 scraphere();
799 freehere(1);
800 runtrap(0);
801 _exit(exstat);
802 /* NOTREACHED */
803}
804
805static void warn(const char *s)
806{
807 if (*s) {
808 prs(s);
809 exstat = -1;
810 }
811 prs("\n");
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +0000812 if (FLAG['e'])
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000813 leave();
814}
815
816static void err(const char *s)
817{
818 warn(s);
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +0000819 if (FLAG['n'])
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000820 return;
821 if (!interactive)
822 leave();
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000823 if (global_env.errpt)
824 longjmp(global_env.errpt, 1);
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000825 closeall();
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000826 global_env.iop = global_env.iobase = iostack;
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000827}
828
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000829
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000830/* -------- area.c -------- */
831
Eric Andersenff9eee42001-06-29 04:57:14 +0000832/*
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000833 * All memory between (char *)areabot and (char *)(areatop+1) is
834 * exclusively administered by the area management routines.
835 * It is assumed that sbrk() and brk() manipulate the high end.
Eric Andersenff9eee42001-06-29 04:57:14 +0000836 */
837
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000838#define sbrk(X) ({ \
839 void * __q = (void *)-1; \
840 if (brkaddr + (int)(X) < brktop) { \
841 __q = brkaddr; \
842 brkaddr += (int)(X); \
843 } \
844 __q; \
845})
Eric Andersenff9eee42001-06-29 04:57:14 +0000846
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000847static void initarea(void)
Eric Andersenff9eee42001-06-29 04:57:14 +0000848{
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000849 brkaddr = xmalloc(AREASIZE);
850 brktop = brkaddr + AREASIZE;
Eric Andersenff9eee42001-06-29 04:57:14 +0000851
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000852 while ((long) sbrk(0) & ALIGN)
853 sbrk(1);
854 areabot = (struct region *) sbrk(REGSIZE);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +0000855
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000856 areabot->next = areabot;
857 areabot->area = BUSY;
858 areatop = areabot;
859 areanxt = areabot;
Eric Andersenff9eee42001-06-29 04:57:14 +0000860}
861
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000862static char *getcell(unsigned nbytes)
863{
864 int nregio;
865 struct region *p, *q;
866 int i;
867
868 if (nbytes == 0) {
869 puts("getcell(0)");
870 abort();
871 }
872 /* silly and defeats the algorithm */
873 /*
874 * round upwards and add administration area
875 */
876 nregio = (nbytes + (REGSIZE - 1)) / REGSIZE + 1;
877 p = areanxt;
878 for (;;) {
879 if (p->area > areanum) {
880 /*
881 * merge free cells
882 */
883 while ((q = p->next)->area > areanum && q != areanxt)
884 p->next = q->next;
885 /*
886 * exit loop if cell big enough
887 */
888 if (q >= p + nregio)
889 goto found;
890 }
891 p = p->next;
892 if (p == areanxt)
893 break;
894 }
895 i = nregio >= GROWBY ? nregio : GROWBY;
896 p = (struct region *) sbrk(i * REGSIZE);
897 if (p == (struct region *) -1)
898 return NULL;
899 p--;
900 if (p != areatop) {
901 puts("not contig");
902 abort(); /* allocated areas are contiguous */
903 }
904 q = p + i;
905 p->next = q;
906 p->area = FREE;
907 q->next = areabot;
908 q->area = BUSY;
909 areatop = q;
910 found:
911 /*
912 * we found a FREE area big enough, pointed to by 'p', and up to 'q'
913 */
914 areanxt = p + nregio;
915 if (areanxt < q) {
916 /*
917 * split into requested area and rest
918 */
919 if (areanxt + 1 > q) {
920 puts("OOM");
921 abort(); /* insufficient space left for admin */
922 }
923 areanxt->next = q;
924 areanxt->area = FREE;
925 p->next = areanxt;
926 }
927 p->area = areanum;
928 return (char *) (p + 1);
929}
930
931static void freecell(char *cp)
932{
933 struct region *p;
934
935 p = (struct region *) cp;
936 if (p != NULL) {
937 p--;
938 if (p < areanxt)
939 areanxt = p;
940 p->area = FREE;
941 }
942}
943#define DELETE(obj) freecell((char *)obj)
944
945static void freearea(int a)
946{
947 struct region *p, *top;
948
949 top = areatop;
950 for (p = areabot; p != top; p = p->next)
951 if (p->area >= a)
952 p->area = FREE;
953}
954
955static void setarea(char *cp, int a)
956{
957 struct region *p;
958
959 p = (struct region *) cp;
960 if (p != NULL)
961 (p - 1)->area = a;
962}
963
964static int getarea(char *cp)
965{
966 return ((struct region *) cp - 1)->area;
967}
968
969static void garbage(void)
970{
971 struct region *p, *q, *top;
972
973 top = areatop;
974 for (p = areabot; p != top; p = p->next) {
975 if (p->area > areanum) {
976 while ((q = p->next)->area > areanum)
977 p->next = q->next;
978 areanxt = p;
979 }
980 }
981#ifdef SHRINKBY
982 if (areatop >= q + SHRINKBY && q->area > areanum) {
983 brk((char *) (q + 1));
984 q->next = areabot;
985 q->area = BUSY;
986 areatop = q;
987 }
988#endif
989}
990
Denis Vlasenko509697f2008-03-02 12:49:39 +0000991static void *get_space(int n)
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000992{
993 char *cp;
994
995 cp = getcell(n);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000996 if (cp == NULL)
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000997 err("out of string space");
998 return cp;
999}
1000
1001static char *strsave(const char *s, int a)
1002{
1003 char *cp;
1004
Denis Vlasenko509697f2008-03-02 12:49:39 +00001005 cp = get_space(strlen(s) + 1);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001006 if (cp == NULL) {
1007// FIXME: I highly doubt this is good.
1008 return (char*)"";
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001009 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001010 setarea(cp, a);
1011 strcpy(cp, s);
1012 return cp;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001013}
1014
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001015
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001016/* -------- var.c -------- */
1017
1018static int eqname(const char *n1, const char *n2)
1019{
1020 for (; *n1 != '=' && *n1 != '\0'; n1++)
1021 if (*n2++ != *n1)
1022 return 0;
1023 return *n2 == '\0' || *n2 == '=';
1024}
1025
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001026static const char *findeq(const char *cp)
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001027{
1028 while (*cp != '\0' && *cp != '=')
1029 cp++;
1030 return cp;
1031}
1032
1033/*
1034 * Find the given name in the dictionary
1035 * and return its value. If the name was
1036 * not previously there, enter it now and
1037 * return a null value.
1038 */
1039static struct var *lookup(const char *n)
1040{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001041// FIXME: dirty hack
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001042 static struct var dummy;
1043
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001044 struct var *vp;
1045 const char *cp;
1046 char *xp;
1047 int c;
1048
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001049 if (isdigit(*n)) {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001050 dummy.name = (char*)n;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001051 for (c = 0; isdigit(*n) && c < 1000; n++)
1052 c = c * 10 + *n - '0';
1053 dummy.status = RONLY;
1054 dummy.value = (c <= dolc ? dolv[c] : null);
1055 return &dummy;
1056 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001057
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001058 for (vp = vlist; vp; vp = vp->next)
1059 if (eqname(vp->name, n))
1060 return vp;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001061
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001062 cp = findeq(n);
Denis Vlasenko509697f2008-03-02 12:49:39 +00001063 vp = get_space(sizeof(*vp));
1064 if (vp == 0 || (vp->name = get_space((int) (cp - n) + 2)) == NULL) {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001065 dummy.name = dummy.value = (char*)"";
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001066 return &dummy;
1067 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001068
1069 xp = vp->name;
1070 while ((*xp = *n++) != '\0' && *xp != '=')
1071 xp++;
1072 *xp++ = '=';
1073 *xp = '\0';
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001074 setarea((char *) vp, 0);
1075 setarea((char *) vp->name, 0);
1076 vp->value = null;
1077 vp->next = vlist;
1078 vp->status = GETCELL;
1079 vlist = vp;
1080 return vp;
1081}
1082
1083/*
1084 * if name is not NULL, it must be
1085 * a prefix of the space `val',
1086 * and end with `='.
1087 * this is all so that exporting
1088 * values is reasonably painless.
1089 */
1090static void nameval(struct var *vp, const char *val, const char *name)
1091{
1092 const char *cp;
1093 char *xp;
1094 int fl;
1095
1096 if (vp->status & RONLY) {
1097 xp = vp->name;
1098 while (*xp && *xp != '=')
Denis Vlasenko4daad902007-09-27 10:20:47 +00001099 fputc(*xp++, stderr);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001100 err(" is read-only");
1101 return;
1102 }
1103 fl = 0;
1104 if (name == NULL) {
Denis Vlasenko509697f2008-03-02 12:49:39 +00001105 xp = get_space(strlen(vp->name) + strlen(val) + 2);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001106 if (xp == NULL)
1107 return;
1108 /* make string: name=value */
1109 setarea(xp, 0);
1110 name = xp;
1111 cp = vp->name;
1112 while ((*xp = *cp++) != '\0' && *xp != '=')
1113 xp++;
1114 *xp++ = '=';
1115 strcpy(xp, val);
1116 val = xp;
1117 fl = GETCELL;
1118 }
1119 if (vp->status & GETCELL)
1120 freecell(vp->name); /* form new string `name=value' */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001121 vp->name = (char*)name;
1122 vp->value = (char*)val;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001123 vp->status |= fl;
1124}
1125
1126/*
1127 * give variable at `vp' the value `val'.
1128 */
1129static void setval(struct var *vp, const char *val)
1130{
1131 nameval(vp, val, NULL);
1132}
1133
1134static void export(struct var *vp)
1135{
1136 vp->status |= EXPORT;
1137}
1138
1139static void ronly(struct var *vp)
1140{
1141 if (isalpha(vp->name[0]) || vp->name[0] == '_') /* not an internal symbol */
1142 vp->status |= RONLY;
1143}
1144
1145static int isassign(const char *s)
1146{
1147 unsigned char c;
1148 DBGPRINTF7(("ISASSIGN: enter, s=%s\n", s));
1149
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001150 c = *s;
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001151 /* no isalpha() - we shouldn't use locale */
1152 /* c | 0x20 - lowercase (Latin) letters */
1153 if (c != '_' && (unsigned)((c|0x20) - 'a') > 25)
1154 /* not letter */
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001155 return 0;
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001156
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001157 while (1) {
1158 c = *++s;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001159 if (c == '=')
1160 return 1;
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001161 if (c == '\0')
1162 return 0;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001163 if (c != '_'
1164 && (unsigned)(c - '0') > 9 /* not number */
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001165 && (unsigned)((c|0x20) - 'a') > 25 /* not letter */
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001166 ) {
1167 return 0;
1168 }
1169 }
1170}
1171
1172static int assign(const char *s, int cf)
1173{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001174 const char *cp;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001175 struct var *vp;
1176
1177 DBGPRINTF7(("ASSIGN: enter, s=%s, cf=%d\n", s, cf));
1178
1179 if (!isalpha(*s) && *s != '_')
1180 return 0;
1181 for (cp = s; *cp != '='; cp++)
1182 if (*cp == '\0' || (!isalnum(*cp) && *cp != '_'))
1183 return 0;
1184 vp = lookup(s);
1185 nameval(vp, ++cp, cf == COPYV ? NULL : s);
1186 if (cf != COPYV)
1187 vp->status &= ~GETCELL;
1188 return 1;
1189}
1190
1191static int checkname(char *cp)
1192{
1193 DBGPRINTF7(("CHECKNAME: enter, cp=%s\n", cp));
1194
1195 if (!isalpha(*cp++) && *(cp - 1) != '_')
1196 return 0;
1197 while (*cp)
1198 if (!isalnum(*cp++) && *(cp - 1) != '_')
1199 return 0;
1200 return 1;
1201}
1202
1203static void putvlist(int f, int out)
1204{
1205 struct var *vp;
1206
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001207 for (vp = vlist; vp; vp = vp->next) {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001208 if (vp->status & f && (isalpha(*vp->name) || *vp->name == '_')) {
1209 if (vp->status & EXPORT)
1210 write(out, "export ", 7);
1211 if (vp->status & RONLY)
1212 write(out, "readonly ", 9);
1213 write(out, vp->name, (int) (findeq(vp->name) - vp->name));
1214 write(out, "\n", 1);
1215 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001216 }
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001217}
1218
1219
1220/*
1221 * trap handling
1222 */
1223static void sig(int i)
1224{
1225 trapset = i;
1226 signal(i, sig);
1227}
1228
1229static void runtrap(int i)
1230{
1231 char *trapstr;
1232
1233 trapstr = trap[i];
1234 if (trapstr == NULL)
1235 return;
1236
1237 if (i == 0)
1238 trap[i] = NULL;
1239
1240 RUN(aword, trapstr, nlchar);
1241}
1242
1243
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001244static void setdash(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001245{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001246 char *cp;
1247 int c;
Eric Andersen8401eea2004-08-04 19:16:54 +00001248 char m['z' - 'a' + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00001249
1250 cp = m;
Eric Andersen8401eea2004-08-04 19:16:54 +00001251 for (c = 'a'; c <= 'z'; c++)
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00001252 if (FLAG[c])
Eric Andersenff9eee42001-06-29 04:57:14 +00001253 *cp++ = c;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001254 *cp = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00001255 setval(lookup("-"), m);
1256}
1257
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001258static int newfile(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00001259{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001260 int f;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001261
1262 DBGPRINTF7(("NEWFILE: opening %s\n", s));
Eric Andersenff9eee42001-06-29 04:57:14 +00001263
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001264 f = 0;
Denis Vlasenko9f739442006-12-16 23:49:13 +00001265 if (NOT_LONE_DASH(s)) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001266 DBGPRINTF(("NEWFILE: s is %s\n", s));
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00001267 f = open(s, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00001268 if (f < 0) {
1269 prs(s);
1270 err(": cannot open");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001271 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001272 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001273 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001274
Eric Andersenff9eee42001-06-29 04:57:14 +00001275 next(remap(f));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001276 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001277}
1278
Eric Andersen12de6cf2004-08-04 19:19:10 +00001279
Denis Vlasenkobc1918a2008-04-15 01:17:50 +00001280#ifdef UNUSED
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}
Denis Vlasenkobc1918a2008-04-15 01:17:50 +00001312#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00001313
1314
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001315static void onecommand(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001316{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001317 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00001318 jmp_buf m1;
1319
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001320 DBGPRINTF(("ONECOMMAND: enter, outtree=%p\n", outtree));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001321
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001322 while (global_env.oenv)
Eric Andersenff9eee42001-06-29 04:57:14 +00001323 quitenv();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001324
Eric Andersenff9eee42001-06-29 04:57:14 +00001325 areanum = 1;
1326 freehere(areanum);
1327 freearea(areanum);
1328 garbage();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001329 wdlist = NULL;
1330 iolist = NULL;
1331 global_env.errpt = NULL;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001332 global_env.linep = line;
Eric Andersenff9eee42001-06-29 04:57:14 +00001333 yynerrs = 0;
1334 multiline = 0;
1335 inparse = 1;
1336 intr = 0;
1337 execflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001338
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001339 failpt = m1;
1340 setjmp(failpt); /* Bruce Evans' fix */
1341 failpt = m1;
1342 if (setjmp(failpt) || yyparse() || intr) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001343 DBGPRINTF(("ONECOMMAND: this is not good.\n"));
1344
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001345 while (global_env.oenv)
Eric Andersenff9eee42001-06-29 04:57:14 +00001346 quitenv();
1347 scraphere();
1348 if (!interactive && intr)
1349 leave();
1350 inparse = 0;
1351 intr = 0;
1352 return;
1353 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001354
Eric Andersenff9eee42001-06-29 04:57:14 +00001355 inparse = 0;
1356 brklist = 0;
1357 intr = 0;
1358 execflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001359
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00001360 if (!FLAG['n']) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001361 DBGPRINTF(("ONECOMMAND: calling execute, t=outtree=%p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00001362 outtree));
Denis Vlasenko7e497522008-02-12 09:51:03 +00001363 execute(outtree, NOPIPE, NOPIPE, /* no_fork: */ 0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001364 }
1365
Eric Andersenff9eee42001-06-29 04:57:14 +00001366 if (!interactive && intr) {
1367 execflg = 0;
1368 leave();
1369 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001370
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001371 i = trapset;
1372 if (i != 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001373 trapset = 0;
1374 runtrap(i);
1375 }
1376}
1377
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001378static int newenv(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00001379{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001380 struct env *ep;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001381
1382 DBGPRINTF(("NEWENV: f=%d (indicates quitenv and return)\n", f));
Eric Andersenff9eee42001-06-29 04:57:14 +00001383
1384 if (f) {
1385 quitenv();
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001386 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001387 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001388
Denis Vlasenko509697f2008-03-02 12:49:39 +00001389 ep = get_space(sizeof(*ep));
Eric Andersenff9eee42001-06-29 04:57:14 +00001390 if (ep == NULL) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001391 while (global_env.oenv)
Eric Andersenff9eee42001-06-29 04:57:14 +00001392 quitenv();
1393 fail();
1394 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001395 *ep = global_env;
1396 global_env.oenv = ep;
1397 global_env.errpt = errpt;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001398
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001399 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001400}
1401
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001402static void quitenv(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001403{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001404 struct env *ep;
1405 int fd;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001406
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001407 DBGPRINTF(("QUITENV: global_env.oenv=%p\n", global_env.oenv));
Eric Andersenff9eee42001-06-29 04:57:14 +00001408
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001409 ep = global_env.oenv;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001410 if (ep != NULL) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001411 fd = global_env.iofd;
1412 global_env = *ep;
Eric Andersenff9eee42001-06-29 04:57:14 +00001413 /* should close `'d files */
1414 DELETE(ep);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001415 while (--fd >= global_env.iofd)
Eric Andersenff9eee42001-06-29 04:57:14 +00001416 close(fd);
1417 }
1418}
1419
1420/*
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001421 * Is character c in s?
Eric Andersenff9eee42001-06-29 04:57:14 +00001422 */
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001423static int any(int c, const char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00001424{
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001425 while (*s)
1426 if (*s++ == c)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001427 return 1;
1428 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001429}
1430
1431/*
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001432 * Is any character from s1 in s2?
Eric Andersenff9eee42001-06-29 04:57:14 +00001433 */
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001434static int anys(const char *s1, const char *s2)
Eric Andersenff9eee42001-06-29 04:57:14 +00001435{
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001436 while (*s1)
1437 if (any(*s1++, s2))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001438 return 1;
1439 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001440}
1441
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001442static char *putn(int n)
Eric Andersenff9eee42001-06-29 04:57:14 +00001443{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001444 return itoa(n);
Eric Andersenff9eee42001-06-29 04:57:14 +00001445}
1446
Eric Andersen8401eea2004-08-04 19:16:54 +00001447static void next(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00001448{
1449 PUSHIO(afile, f, filechar);
1450}
1451
Denis Vlasenko68404f12008-03-17 09:00:54 +00001452static void onintr(int s ATTRIBUTE_UNUSED) /* ANSI C requires a parameter */
Eric Andersenff9eee42001-06-29 04:57:14 +00001453{
1454 signal(SIGINT, onintr);
1455 intr = 1;
1456 if (interactive) {
1457 if (inparse) {
1458 prs("\n");
1459 fail();
1460 }
Eric Andersen8401eea2004-08-04 19:16:54 +00001461 } else if (heedint) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001462 execflg = 0;
1463 leave();
1464 }
1465}
1466
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001467
Eric Andersenff9eee42001-06-29 04:57:14 +00001468/* -------- gmatch.c -------- */
1469/*
1470 * int gmatch(string, pattern)
1471 * char *string, *pattern;
1472 *
1473 * Match a pattern as in sh(1).
1474 */
1475
1476#define CMASK 0377
1477#define QUOTE 0200
Denis Vlasenko55f30b02007-03-24 22:42:29 +00001478#define QMASK (CMASK & ~QUOTE)
Eric Andersen8401eea2004-08-04 19:16:54 +00001479#define NOT '!' /* might use ^ */
Eric Andersenff9eee42001-06-29 04:57:14 +00001480
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001481static const char *cclass(const char *p, int sub)
1482{
1483 int c, d, not, found;
1484
1485 not = (*p == NOT);
1486 if (not != 0)
1487 p++;
1488 found = not;
1489 do {
1490 if (*p == '\0')
1491 return NULL;
1492 c = *p & CMASK;
1493 if (p[1] == '-' && p[2] != ']') {
1494 d = p[2] & CMASK;
1495 p++;
1496 } else
1497 d = c;
1498 if (c == sub || (c <= sub && sub <= d))
1499 found = !not;
1500 } while (*++p != ']');
1501 return found ? p + 1 : NULL;
1502}
1503
1504static int gmatch(const char *s, const char *p)
Eric Andersenff9eee42001-06-29 04:57:14 +00001505{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001506 int sc, pc;
Eric Andersenff9eee42001-06-29 04:57:14 +00001507
1508 if (s == NULL || p == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001509 return 0;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001510
Eric Andersenff9eee42001-06-29 04:57:14 +00001511 while ((pc = *p++ & CMASK) != '\0') {
1512 sc = *s++ & QMASK;
1513 switch (pc) {
1514 case '[':
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001515 p = cclass(p, sc);
1516 if (p == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001517 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001518 break;
1519
1520 case '?':
1521 if (sc == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001522 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001523 break;
1524
1525 case '*':
1526 s--;
1527 do {
1528 if (*p == '\0' || gmatch(s, p))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001529 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001530 } while (*s++ != '\0');
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001531 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001532
1533 default:
Eric Andersen8401eea2004-08-04 19:16:54 +00001534 if (sc != (pc & ~QUOTE))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001535 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001536 }
1537 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001538 return *s == '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00001539}
1540
Eric Andersenff9eee42001-06-29 04:57:14 +00001541
Eric Andersenff9eee42001-06-29 04:57:14 +00001542/* -------- csyn.c -------- */
1543/*
1544 * shell: syntax (C version)
1545 */
1546
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001547static void yyerror(const char *s) ATTRIBUTE_NORETURN;
1548static void yyerror(const char *s)
1549{
Denis Vlasenko648b44f2008-02-12 06:04:06 +00001550 yynerrs = 1;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001551 if (interactive && global_env.iop <= iostack) {
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001552 multiline = 0;
Denis Vlasenko648b44f2008-02-12 06:04:06 +00001553 while (eofc() == 0 && yylex(0) != '\n')
1554 continue;
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001555 }
1556 err(s);
1557 fail();
1558}
1559
1560static void zzerr(void) ATTRIBUTE_NORETURN;
1561static void zzerr(void)
1562{
1563 yyerror("syntax error");
1564}
1565
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001566int yyparse(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001567{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001568 DBGPRINTF7(("YYPARSE: enter...\n"));
1569
Eric Andersen8401eea2004-08-04 19:16:54 +00001570 startl = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001571 peeksym = 0;
1572 yynerrs = 0;
1573 outtree = c_list();
1574 musthave('\n', 0);
Denis Vlasenko648b44f2008-02-12 06:04:06 +00001575 return yynerrs; /* 0/1 */
Eric Andersenff9eee42001-06-29 04:57:14 +00001576}
1577
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001578static struct op *pipeline(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001579{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001580 struct op *t, *p;
1581 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001582
1583 DBGPRINTF7(("PIPELINE: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001584
1585 t = command(cf);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001586
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001587 DBGPRINTF9(("PIPELINE: t=%p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001588
Eric Andersenff9eee42001-06-29 04:57:14 +00001589 if (t != NULL) {
1590 while ((c = yylex(0)) == '|') {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001591 p = command(CONTIN);
1592 if (p == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001593 DBGPRINTF8(("PIPELINE: error!\n"));
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001594 zzerr();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001595 }
1596
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001597 if (t->op_type != TPAREN && t->op_type != TCOM) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001598 /* shell statement */
1599 t = block(TPAREN, t, NOBLOCK, NOWORDS);
1600 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001601
Eric Andersenff9eee42001-06-29 04:57:14 +00001602 t = block(TPIPE, t, p, NOWORDS);
1603 }
1604 peeksym = c;
1605 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001606
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001607 DBGPRINTF7(("PIPELINE: returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001608 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001609}
1610
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001611static struct op *andor(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001612{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001613 struct op *t, *p;
1614 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001615
1616 DBGPRINTF7(("ANDOR: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001617
1618 t = pipeline(0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001619
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001620 DBGPRINTF9(("ANDOR: t=%p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001621
Eric Andersenff9eee42001-06-29 04:57:14 +00001622 if (t != NULL) {
1623 while ((c = yylex(0)) == LOGAND || c == LOGOR) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001624 p = pipeline(CONTIN);
1625 if (p == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001626 DBGPRINTF8(("ANDOR: error!\n"));
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001627 zzerr();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001628 }
1629
Eric Andersen8401eea2004-08-04 19:16:54 +00001630 t = block(c == LOGAND ? TAND : TOR, t, p, NOWORDS);
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001631 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001632
Eric Andersenff9eee42001-06-29 04:57:14 +00001633 peeksym = c;
1634 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001635
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001636 DBGPRINTF7(("ANDOR: returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001637 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001638}
1639
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001640static struct op *c_list(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001641{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001642 struct op *t, *p;
1643 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001644
1645 DBGPRINTF7(("C_LIST: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001646
1647 t = andor();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001648
Eric Andersenff9eee42001-06-29 04:57:14 +00001649 if (t != NULL) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001650 peeksym = yylex(0);
1651 if (peeksym == '&')
Eric Andersenff9eee42001-06-29 04:57:14 +00001652 t = block(TASYNC, t, NOBLOCK, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001653
Eric Andersen8401eea2004-08-04 19:16:54 +00001654 while ((c = yylex(0)) == ';' || c == '&'
Denis Vlasenko509697f2008-03-02 12:49:39 +00001655 || (multiline && c == '\n')
1656 ) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001657 p = andor();
1658 if (p== NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001659 return t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001660
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001661 peeksym = yylex(0);
1662 if (peeksym == '&')
Eric Andersenff9eee42001-06-29 04:57:14 +00001663 p = block(TASYNC, p, NOBLOCK, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001664
Eric Andersenff9eee42001-06-29 04:57:14 +00001665 t = list(t, p);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001666 } /* WHILE */
1667
Eric Andersenff9eee42001-06-29 04:57:14 +00001668 peeksym = c;
1669 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001670 /* IF */
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001671 DBGPRINTF7(("C_LIST: returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001672 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001673}
1674
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001675static int synio(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001676{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001677 struct ioword *iop;
1678 int i;
1679 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001680
1681 DBGPRINTF7(("SYNIO: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001682
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001683 c = yylex(cf);
1684 if (c != '<' && c != '>') {
Eric Andersenff9eee42001-06-29 04:57:14 +00001685 peeksym = c;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001686 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001687 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001688
Eric Andersenff9eee42001-06-29 04:57:14 +00001689 i = yylval.i;
1690 musthave(WORD, 0);
1691 iop = io(iounit, i, yylval.cp);
1692 iounit = IODEFAULT;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001693
Eric Andersenff9eee42001-06-29 04:57:14 +00001694 if (i & IOHERE)
1695 markhere(yylval.cp, iop);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001696
1697 DBGPRINTF7(("SYNIO: returning 1\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001698 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001699}
1700
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001701static void musthave(int c, int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001702{
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001703 peeksym = yylex(cf);
1704 if (peeksym != c) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001705 DBGPRINTF7(("MUSTHAVE: error!\n"));
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001706 zzerr();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001707 }
1708
Eric Andersenff9eee42001-06-29 04:57:14 +00001709 peeksym = 0;
1710}
1711
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001712static struct op *simple(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001713{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001714 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001715
1716 t = NULL;
1717 for (;;) {
1718 switch (peeksym = yylex(0)) {
1719 case '<':
1720 case '>':
1721 (void) synio(0);
1722 break;
1723
1724 case WORD:
1725 if (t == NULL) {
1726 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001727 t->op_type = TCOM;
Eric Andersenff9eee42001-06-29 04:57:14 +00001728 }
1729 peeksym = 0;
1730 word(yylval.cp);
1731 break;
1732
1733 default:
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001734 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001735 }
1736 }
1737}
1738
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001739static struct op *nested(int type, int mark)
Eric Andersenff9eee42001-06-29 04:57:14 +00001740{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001741 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001742
1743 DBGPRINTF3(("NESTED: enter, type=%d, mark=%d\n", type, mark));
Eric Andersenff9eee42001-06-29 04:57:14 +00001744
1745 multiline++;
1746 t = c_list();
1747 musthave(mark, 0);
1748 multiline--;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001749 return block(type, t, NOBLOCK, NOWORDS);
Eric Andersenff9eee42001-06-29 04:57:14 +00001750}
1751
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001752static struct op *command(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001753{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001754 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001755 struct wdblock *iosave;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001756 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001757
1758 DBGPRINTF(("COMMAND: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001759
1760 iosave = iolist;
1761 iolist = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001762
Eric Andersenff9eee42001-06-29 04:57:14 +00001763 if (multiline)
1764 cf |= CONTIN;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001765
Eric Andersenff9eee42001-06-29 04:57:14 +00001766 while (synio(cf))
1767 cf = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001768
1769 c = yylex(cf);
1770
1771 switch (c) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001772 default:
1773 peeksym = c;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001774 t = simple();
1775 if (t == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001776 if (iolist == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001777 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001778 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001779 t->op_type = TCOM;
Eric Andersenff9eee42001-06-29 04:57:14 +00001780 }
1781 break;
1782
1783 case '(':
1784 t = nested(TPAREN, ')');
1785 break;
1786
1787 case '{':
1788 t = nested(TBRACE, '}');
1789 break;
1790
1791 case FOR:
1792 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001793 t->op_type = TFOR;
Eric Andersenff9eee42001-06-29 04:57:14 +00001794 musthave(WORD, 0);
1795 startl = 1;
1796 t->str = yylval.cp;
1797 multiline++;
Denis Vlasenko509697f2008-03-02 12:49:39 +00001798 t->op_words = wordlist();
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001799 c = yylex(0);
1800 if (c != '\n' && c != ';')
Eric Andersenff9eee42001-06-29 04:57:14 +00001801 peeksym = c;
1802 t->left = dogroup(0);
1803 multiline--;
1804 break;
1805
1806 case WHILE:
1807 case UNTIL:
1808 multiline++;
1809 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001810 t->op_type = (c == WHILE ? TWHILE : TUNTIL);
Eric Andersenff9eee42001-06-29 04:57:14 +00001811 t->left = c_list();
1812 t->right = dogroup(1);
Denis Vlasenko509697f2008-03-02 12:49:39 +00001813 /* t->op_words = NULL; - newtp() did this */
Eric Andersenff9eee42001-06-29 04:57:14 +00001814 multiline--;
1815 break;
1816
1817 case CASE:
1818 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001819 t->op_type = TCASE;
Eric Andersenff9eee42001-06-29 04:57:14 +00001820 musthave(WORD, 0);
1821 t->str = yylval.cp;
1822 startl++;
1823 multiline++;
1824 musthave(IN, CONTIN);
1825 startl++;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001826
Eric Andersenff9eee42001-06-29 04:57:14 +00001827 t->left = caselist();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001828
Eric Andersenff9eee42001-06-29 04:57:14 +00001829 musthave(ESAC, 0);
1830 multiline--;
1831 break;
1832
1833 case IF:
1834 multiline++;
1835 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001836 t->op_type = TIF;
Eric Andersenff9eee42001-06-29 04:57:14 +00001837 t->left = c_list();
1838 t->right = thenpart();
1839 musthave(FI, 0);
1840 multiline--;
1841 break;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001842
1843 case DOT:
1844 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001845 t->op_type = TDOT;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001846
Denis Vlasenko509697f2008-03-02 12:49:39 +00001847 musthave(WORD, 0); /* gets name of file */
Eric Andersen12de6cf2004-08-04 19:19:10 +00001848 DBGPRINTF7(("COMMAND: DOT clause, yylval.cp is %s\n", yylval.cp));
1849
Denis Vlasenko509697f2008-03-02 12:49:39 +00001850 word(yylval.cp); /* add word to wdlist */
1851 word(NOWORD); /* terminate wdlist */
1852 t->op_words = copyw(); /* dup wdlist */
Eric Andersen12de6cf2004-08-04 19:19:10 +00001853 break;
1854
Eric Andersenff9eee42001-06-29 04:57:14 +00001855 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001856
Denis Vlasenko509697f2008-03-02 12:49:39 +00001857 while (synio(0))
1858 continue;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001859
Eric Andersenff9eee42001-06-29 04:57:14 +00001860 t = namelist(t);
1861 iolist = iosave;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001862
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001863 DBGPRINTF(("COMMAND: returning %p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001864
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001865 return t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001866}
1867
Denis Vlasenko68404f12008-03-17 09:00:54 +00001868static struct op *dowholefile(int type /*, int mark*/)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001869{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001870 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001871
Denis Vlasenko68404f12008-03-17 09:00:54 +00001872 DBGPRINTF(("DOWHOLEFILE: enter, type=%d\n", type /*, mark*/));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001873
1874 multiline++;
1875 t = c_list();
1876 multiline--;
1877 t = block(type, t, NOBLOCK, NOWORDS);
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001878 DBGPRINTF(("DOWHOLEFILE: return t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001879 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001880}
1881
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001882static struct op *dogroup(int onlydone)
Eric Andersenff9eee42001-06-29 04:57:14 +00001883{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001884 int c;
1885 struct op *mylist;
Eric Andersenff9eee42001-06-29 04:57:14 +00001886
1887 c = yylex(CONTIN);
1888 if (c == DONE && onlydone)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001889 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001890 if (c != DO)
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001891 zzerr();
Eric Andersenff9eee42001-06-29 04:57:14 +00001892 mylist = c_list();
1893 musthave(DONE, 0);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001894 return mylist;
Eric Andersenff9eee42001-06-29 04:57:14 +00001895}
1896
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001897static struct op *thenpart(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001898{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001899 int c;
1900 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001901
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001902 c = yylex(0);
1903 if (c != THEN) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001904 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001905 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001906 }
1907 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001908 /*t->op_type = 0; - newtp() did this */
Eric Andersenff9eee42001-06-29 04:57:14 +00001909 t->left = c_list();
1910 if (t->left == NULL)
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001911 zzerr();
Eric Andersenff9eee42001-06-29 04:57:14 +00001912 t->right = elsepart();
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001913 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001914}
1915
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001916static struct op *elsepart(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001917{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001918 int c;
1919 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001920
1921 switch (c = yylex(0)) {
1922 case ELSE:
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001923 t = c_list();
1924 if (t == NULL)
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001925 zzerr();
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001926 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001927
1928 case ELIF:
1929 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001930 t->op_type = TELIF;
Eric Andersenff9eee42001-06-29 04:57:14 +00001931 t->left = c_list();
1932 t->right = thenpart();
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001933 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001934
1935 default:
1936 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001937 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001938 }
1939}
1940
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001941static struct op *caselist(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001942{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001943 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001944
1945 t = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001946 while ((peeksym = yylex(CONTIN)) != ESAC) {
1947 DBGPRINTF(("CASELIST, doing yylex, peeksym=%d\n", peeksym));
Eric Andersenff9eee42001-06-29 04:57:14 +00001948 t = list(t, casepart());
Eric Andersen12de6cf2004-08-04 19:19:10 +00001949 }
1950
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001951 DBGPRINTF(("CASELIST, returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001952 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001953}
1954
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001955static struct op *casepart(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001956{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001957 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001958
1959 DBGPRINTF7(("CASEPART: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001960
1961 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001962 t->op_type = TPAT;
Denis Vlasenko509697f2008-03-02 12:49:39 +00001963 t->op_words = pattern();
Eric Andersenff9eee42001-06-29 04:57:14 +00001964 musthave(')', 0);
1965 t->left = c_list();
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001966 peeksym = yylex(CONTIN);
1967 if (peeksym != ESAC)
Eric Andersenff9eee42001-06-29 04:57:14 +00001968 musthave(BREAK, CONTIN);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001969
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001970 DBGPRINTF7(("CASEPART: made newtp(TPAT, t=%p)\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001971
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001972 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001973}
1974
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001975static char **pattern(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001976{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001977 int c, cf;
Eric Andersenff9eee42001-06-29 04:57:14 +00001978
1979 cf = CONTIN;
1980 do {
1981 musthave(WORD, cf);
1982 word(yylval.cp);
1983 cf = 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001984 c = yylex(0);
1985 } while (c == '|');
Eric Andersenff9eee42001-06-29 04:57:14 +00001986 peeksym = c;
1987 word(NOWORD);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001988
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001989 return copyw();
Eric Andersenff9eee42001-06-29 04:57:14 +00001990}
1991
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001992static char **wordlist(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001993{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001994 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00001995
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001996 c = yylex(0);
1997 if (c != IN) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001998 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001999 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00002000 }
2001 startl = 0;
2002 while ((c = yylex(0)) == WORD)
2003 word(yylval.cp);
2004 word(NOWORD);
2005 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002006 return copyw();
Eric Andersenff9eee42001-06-29 04:57:14 +00002007}
2008
2009/*
2010 * supporting functions
2011 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002012static struct op *list(struct op *t1, struct op *t2)
Eric Andersenff9eee42001-06-29 04:57:14 +00002013{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002014 DBGPRINTF7(("LIST: enter, t1=%p, t2=%p\n", t1, t2));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002015
Eric Andersenff9eee42001-06-29 04:57:14 +00002016 if (t1 == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002017 return t2;
Eric Andersenff9eee42001-06-29 04:57:14 +00002018 if (t2 == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002019 return t1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002020
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002021 return block(TLIST, t1, t2, NOWORDS);
Eric Andersenff9eee42001-06-29 04:57:14 +00002022}
2023
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002024static struct op *block(int type, struct op *t1, struct op *t2, char **wp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002025{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002026 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002027
2028 DBGPRINTF7(("BLOCK: enter, type=%d (%s)\n", type, T_CMD_NAMES[type]));
Eric Andersenff9eee42001-06-29 04:57:14 +00002029
2030 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002031 t->op_type = type;
Eric Andersenff9eee42001-06-29 04:57:14 +00002032 t->left = t1;
2033 t->right = t2;
Denis Vlasenko509697f2008-03-02 12:49:39 +00002034 t->op_words = wp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002035
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002036 DBGPRINTF7(("BLOCK: inserted %p between %p and %p\n", t, t1, t2));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002037
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002038 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002039}
2040
Eric Andersen12de6cf2004-08-04 19:19:10 +00002041/* See if given string is a shell multiline (FOR, IF, etc) */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002042static int rlookup(char *n)
Eric Andersenff9eee42001-06-29 04:57:14 +00002043{
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002044 struct res {
2045 char r_name[6];
2046 int16_t r_val;
2047 };
2048 static const struct res restab[] = {
2049 { "for" , FOR },
2050 { "case" , CASE },
2051 { "esac" , ESAC },
2052 { "while", WHILE },
2053 { "do" , DO },
2054 { "done" , DONE },
2055 { "if" , IF },
2056 { "in" , IN },
2057 { "then" , THEN },
2058 { "else" , ELSE },
2059 { "elif" , ELIF },
2060 { "until", UNTIL },
2061 { "fi" , FI },
2062 { ";;" , BREAK },
2063 { "||" , LOGOR },
2064 { "&&" , LOGAND },
2065 { "{" , '{' },
2066 { "}" , '}' },
2067 { "." , DOT },
2068 { },
2069 };
2070
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002071 const struct res *rp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002072
2073 DBGPRINTF7(("RLOOKUP: enter, n is %s\n", n));
Eric Andersenff9eee42001-06-29 04:57:14 +00002074
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002075 for (rp = restab; rp->r_name[0]; rp++)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002076 if (strcmp(rp->r_name, n) == 0) {
2077 DBGPRINTF7(("RLOOKUP: match, returning %d\n", rp->r_val));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002078 return rp->r_val; /* Return numeric code for shell multiline */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002079 }
2080
2081 DBGPRINTF7(("RLOOKUP: NO match, returning 0\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002082 return 0; /* Not a shell multiline */
Eric Andersenff9eee42001-06-29 04:57:14 +00002083}
2084
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002085static struct op *newtp(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002086{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002087 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002088
Eric Andersen8401eea2004-08-04 19:16:54 +00002089 t = (struct op *) tree(sizeof(*t));
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002090 memset(t, 0, sizeof(*t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002091
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002092 DBGPRINTF3(("NEWTP: allocated %p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002093
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002094 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002095}
2096
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002097static struct op *namelist(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00002098{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002099 DBGPRINTF7(("NAMELIST: enter, t=%p, type %s, iolist=%p\n", t,
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002100 T_CMD_NAMES[t->op_type], iolist));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002101
Eric Andersenff9eee42001-06-29 04:57:14 +00002102 if (iolist) {
Eric Andersen8401eea2004-08-04 19:16:54 +00002103 iolist = addword((char *) NULL, iolist);
Eric Andersenff9eee42001-06-29 04:57:14 +00002104 t->ioact = copyio();
2105 } else
2106 t->ioact = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002107
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002108 if (t->op_type != TCOM) {
2109 if (t->op_type != TPAREN && t->ioact != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002110 t = block(TPAREN, t, NOBLOCK, NOWORDS);
2111 t->ioact = t->left->ioact;
2112 t->left->ioact = NULL;
2113 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002114 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002115 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002116
Eric Andersenff9eee42001-06-29 04:57:14 +00002117 word(NOWORD);
Denis Vlasenko509697f2008-03-02 12:49:39 +00002118 t->op_words = copyw();
Eric Andersen12de6cf2004-08-04 19:19:10 +00002119
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002120 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002121}
2122
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002123static char **copyw(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002124{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002125 char **wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00002126
2127 wd = getwords(wdlist);
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002128 wdlist = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002129 return wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00002130}
2131
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002132static void word(char *cp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002133{
2134 wdlist = addword(cp, wdlist);
2135}
2136
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002137static struct ioword **copyio(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002138{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002139 struct ioword **iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002140
2141 iop = (struct ioword **) getwords(iolist);
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002142 iolist = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002143 return iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002144}
2145
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002146static struct ioword *io(int u, int f, char *cp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002147{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002148 struct ioword *iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002149
2150 iop = (struct ioword *) tree(sizeof(*iop));
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002151 iop->io_fd = u;
Eric Andersenff9eee42001-06-29 04:57:14 +00002152 iop->io_flag = f;
2153 iop->io_name = cp;
Eric Andersen8401eea2004-08-04 19:16:54 +00002154 iolist = addword((char *) iop, iolist);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002155 return iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002156}
2157
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002158static int yylex(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00002159{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002160 int c, c1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002161 int atstart;
2162
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002163 c = peeksym;
2164 if (c > 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002165 peeksym = 0;
2166 if (c == '\n')
2167 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002168 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002169 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002170
Eric Andersenff9eee42001-06-29 04:57:14 +00002171 nlseen = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002172 atstart = startl;
2173 startl = 0;
2174 yylval.i = 0;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002175 global_env.linep = line;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002176
2177/* MALAMO */
2178 line[LINELIM - 1] = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00002179
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002180 loop:
Eric Andersen12de6cf2004-08-04 19:19:10 +00002181 while ((c = my_getc(0)) == ' ' || c == '\t') /* Skip whitespace */
Denis Vlasenko509697f2008-03-02 12:49:39 +00002182 continue;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002183
Eric Andersenff9eee42001-06-29 04:57:14 +00002184 switch (c) {
2185 default:
2186 if (any(c, "0123456789")) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002187 c1 = my_getc(0);
2188 unget(c1);
Eric Andersenff9eee42001-06-29 04:57:14 +00002189 if (c1 == '<' || c1 == '>') {
2190 iounit = c - '0';
2191 goto loop;
2192 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002193 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002194 c = c1;
2195 }
2196 break;
2197
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002198 case '#': /* Comment, skip to next newline or End-of-string */
Denis Vlasenko509697f2008-03-02 12:49:39 +00002199 while ((c = my_getc(0)) != '\0' && c != '\n')
2200 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00002201 unget(c);
2202 goto loop;
2203
2204 case 0:
Eric Andersen12de6cf2004-08-04 19:19:10 +00002205 DBGPRINTF5(("YYLEX: return 0, c=%d\n", c));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002206 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002207
2208 case '$':
Eric Andersen12de6cf2004-08-04 19:19:10 +00002209 DBGPRINTF9(("YYLEX: found $\n"));
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002210 *global_env.linep++ = c;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002211 c = my_getc(0);
2212 if (c == '{') {
2213 c = collect(c, '}');
2214 if (c != '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002215 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002216 goto pack;
2217 }
2218 break;
2219
2220 case '`':
2221 case '\'':
2222 case '"':
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002223 c = collect(c, c);
2224 if (c != '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002225 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002226 goto pack;
2227
2228 case '|':
2229 case '&':
2230 case ';':
Eric Andersenff9eee42001-06-29 04:57:14 +00002231 startl = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002232 /* If more chars process them, else return NULL char */
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002233 c1 = dual(c);
2234 if (c1 != '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002235 return c1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002236 return c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002237
Eric Andersenff9eee42001-06-29 04:57:14 +00002238 case '^':
2239 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002240 return '|';
Eric Andersenff9eee42001-06-29 04:57:14 +00002241 case '>':
2242 case '<':
2243 diag(c);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002244 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002245
2246 case '\n':
2247 nlseen++;
2248 gethere();
2249 startl = 1;
2250 if (multiline || cf & CONTIN) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002251 if (interactive && global_env.iop <= iostack) {
Denis Vlasenko38f63192007-01-22 09:03:07 +00002252#if ENABLE_FEATURE_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00002253 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00002254#else
Eric Andersen8401eea2004-08-04 19:16:54 +00002255 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00002256#endif
2257 }
2258 if (cf & CONTIN)
2259 goto loop;
2260 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002261 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002262
2263 case '(':
2264 case ')':
2265 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002266 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002267 }
2268
2269 unget(c);
2270
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002271 pack:
2272 while ((c = my_getc(0)) != '\0' && !any(c, "`$ '\"\t;&<>()|^\n")) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002273 if (global_env.linep >= elinep)
Eric Andersenff9eee42001-06-29 04:57:14 +00002274 err("word too long");
2275 else
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002276 *global_env.linep++ = c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002277 };
2278
Eric Andersenff9eee42001-06-29 04:57:14 +00002279 unget(c);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002280
Eric Andersen8401eea2004-08-04 19:16:54 +00002281 if (any(c, "\"'`$"))
Eric Andersenff9eee42001-06-29 04:57:14 +00002282 goto loop;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002283
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002284 *global_env.linep++ = '\0';
Eric Andersen12de6cf2004-08-04 19:19:10 +00002285
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002286 if (atstart) {
2287 c = rlookup(line);
2288 if (c != 0) {
2289 startl = 1;
2290 return c;
2291 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002292 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002293
Eric Andersenff9eee42001-06-29 04:57:14 +00002294 yylval.cp = strsave(line, areanum);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002295 return WORD;
Eric Andersenff9eee42001-06-29 04:57:14 +00002296}
2297
Eric Andersen12de6cf2004-08-04 19:19:10 +00002298
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002299static int collect(int c, int c1)
Eric Andersenff9eee42001-06-29 04:57:14 +00002300{
2301 char s[2];
2302
Eric Andersen12de6cf2004-08-04 19:19:10 +00002303 DBGPRINTF8(("COLLECT: enter, c=%d, c1=%d\n", c, c1));
2304
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002305 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002306 while ((c = my_getc(c1)) != c1) {
2307 if (c == 0) {
2308 unget(c);
2309 s[0] = c1;
2310 s[1] = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00002311 prs("no closing ");
2312 yyerror(s);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002313 return YYERRCODE;
Eric Andersenff9eee42001-06-29 04:57:14 +00002314 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002315 if (interactive && c == '\n' && global_env.iop <= iostack) {
Denis Vlasenko38f63192007-01-22 09:03:07 +00002316#if ENABLE_FEATURE_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00002317 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00002318#else
Eric Andersen8401eea2004-08-04 19:16:54 +00002319 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00002320#endif
2321 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002322 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002323 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002324
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002325 *global_env.linep++ = c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002326
2327 DBGPRINTF8(("COLLECT: return 0, line is %s\n", line));
2328
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002329 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002330}
2331
Eric Andersen12de6cf2004-08-04 19:19:10 +00002332/* "multiline commands" helper func */
2333/* see if next 2 chars form a shell multiline */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002334static int dual(int c)
Eric Andersenff9eee42001-06-29 04:57:14 +00002335{
2336 char s[3];
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002337 char *cp = s;
Eric Andersenff9eee42001-06-29 04:57:14 +00002338
Eric Andersen12de6cf2004-08-04 19:19:10 +00002339 DBGPRINTF8(("DUAL: enter, c=%d\n", c));
2340
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002341 *cp++ = c; /* c is the given "peek" char */
2342 *cp++ = my_getc(0); /* get next char of input */
2343 *cp = '\0'; /* add EOS marker */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002344
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002345 c = rlookup(s); /* see if 2 chars form a shell multiline */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002346 if (c == 0)
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002347 unget(*--cp); /* String is not a shell multiline, put peek char back */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002348
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002349 return c; /* String is multiline, return numeric multiline (restab) code */
Eric Andersenff9eee42001-06-29 04:57:14 +00002350}
2351
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002352static void diag(int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00002353{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002354 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002355
2356 DBGPRINTF8(("DIAG: enter, ec=%d\n", ec));
Eric Andersenff9eee42001-06-29 04:57:14 +00002357
2358 c = my_getc(0);
2359 if (c == '>' || c == '<') {
2360 if (c != ec)
2361 zzerr();
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002362 yylval.i = (ec == '>' ? IOWRITE | IOCAT : IOHERE);
Eric Andersenff9eee42001-06-29 04:57:14 +00002363 c = my_getc(0);
2364 } else
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002365 yylval.i = (ec == '>' ? IOWRITE : IOREAD);
Eric Andersenff9eee42001-06-29 04:57:14 +00002366 if (c != '&' || yylval.i == IOHERE)
2367 unget(c);
2368 else
2369 yylval.i |= IODUP;
2370}
2371
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002372static char *tree(unsigned size)
Eric Andersenff9eee42001-06-29 04:57:14 +00002373{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002374 char *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002375
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002376 t = getcell(size);
2377 if (t == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002378 DBGPRINTF2(("TREE: getcell(%d) failed!\n", size));
Eric Andersenff9eee42001-06-29 04:57:14 +00002379 prs("command line too complicated\n");
2380 fail();
2381 /* NOTREACHED */
2382 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002383 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002384}
2385
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002386
Eric Andersenff9eee42001-06-29 04:57:14 +00002387/* VARARGS1 */
2388/* ARGSUSED */
2389
2390/* -------- exec.c -------- */
2391
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002392static struct op **find1case(struct op *t, const char *w)
2393{
2394 struct op *t1;
2395 struct op **tp;
2396 char **wp;
2397 char *cp;
2398
2399 if (t == NULL) {
2400 DBGPRINTF3(("FIND1CASE: enter, t==NULL, returning.\n"));
2401 return NULL;
2402 }
2403
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002404 DBGPRINTF3(("FIND1CASE: enter, t->op_type=%d (%s)\n", t->op_type,
2405 T_CMD_NAMES[t->op_type]));
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002406
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002407 if (t->op_type == TLIST) {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002408 tp = find1case(t->left, w);
2409 if (tp != NULL) {
2410 DBGPRINTF3(("FIND1CASE: found one to the left, returning tp=%p\n", tp));
2411 return tp;
2412 }
2413 t1 = t->right; /* TPAT */
2414 } else
2415 t1 = t;
2416
Denis Vlasenko509697f2008-03-02 12:49:39 +00002417 for (wp = t1->op_words; *wp;) {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002418 cp = evalstr(*wp++, DOSUB);
2419 if (cp && gmatch(w, cp)) {
2420 DBGPRINTF3(("FIND1CASE: returning &t1->left= %p.\n",
2421 &t1->left));
2422 return &t1->left;
2423 }
2424 }
2425
2426 DBGPRINTF(("FIND1CASE: returning NULL\n"));
2427 return NULL;
2428}
2429
2430static struct op *findcase(struct op *t, const char *w)
2431{
2432 struct op **tp;
2433
2434 tp = find1case(t, w);
2435 return tp != NULL ? *tp : NULL;
2436}
2437
Eric Andersenff9eee42001-06-29 04:57:14 +00002438/*
2439 * execute tree
2440 */
2441
Denis Vlasenko7e497522008-02-12 09:51:03 +00002442static int execute(struct op *t, int *pin, int *pout, int no_fork)
Eric Andersenff9eee42001-06-29 04:57:14 +00002443{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002444 struct op *t1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002445 volatile int i, rv, a;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002446 const char *cp;
2447 char **wp, **wp2;
Eric Andersenff9eee42001-06-29 04:57:14 +00002448 struct var *vp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002449 struct op *outtree_save;
Eric Andersenff9eee42001-06-29 04:57:14 +00002450 struct brkcon bc;
2451
2452#if __GNUC__
2453 /* Avoid longjmp clobbering */
2454 (void) &wp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002455#endif
Eric Andersenff9eee42001-06-29 04:57:14 +00002456
Eric Andersen12de6cf2004-08-04 19:19:10 +00002457 if (t == NULL) {
2458 DBGPRINTF4(("EXECUTE: enter, t==null, returning.\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002459 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002460 }
2461
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002462 DBGPRINTF(("EXECUTE: t=%p, t->op_type=%d (%s), t->op_words is %s\n", t,
2463 t->op_type, T_CMD_NAMES[t->op_type],
Denis Vlasenko509697f2008-03-02 12:49:39 +00002464 ((t->op_words == NULL) ? "NULL" : t->op_words[0])));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002465
Eric Andersenff9eee42001-06-29 04:57:14 +00002466 rv = 0;
2467 a = areanum++;
Denis Vlasenko509697f2008-03-02 12:49:39 +00002468 wp2 = t->op_words;
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002469 wp = (wp2 != NULL)
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002470 ? eval(wp2, t->op_type == TCOM ? DOALL : DOALL & ~DOKEY)
Eric Andersen8401eea2004-08-04 19:16:54 +00002471 : NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00002472
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002473 switch (t->op_type) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002474 case TDOT:
2475 DBGPRINTF3(("EXECUTE: TDOT\n"));
2476
2477 outtree_save = outtree;
2478
Denis Vlasenko509697f2008-03-02 12:49:39 +00002479 newfile(evalstr(t->op_words[0], DOALL));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002480
Denis Vlasenko68404f12008-03-17 09:00:54 +00002481 t->left = dowholefile(TLIST /*, 0*/);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002482 t->right = NULL;
2483
2484 outtree = outtree_save;
2485
2486 if (t->left)
Denis Vlasenko7e497522008-02-12 09:51:03 +00002487 rv = execute(t->left, pin, pout, /* no_fork: */ 0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002488 if (t->right)
Denis Vlasenko7e497522008-02-12 09:51:03 +00002489 rv = execute(t->right, pin, pout, /* no_fork: */ 0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002490 break;
2491
Eric Andersenff9eee42001-06-29 04:57:14 +00002492 case TPAREN:
Denis Vlasenko7e497522008-02-12 09:51:03 +00002493 rv = execute(t->left, pin, pout, /* no_fork: */ 0);
Eric Andersen737f5fb2003-03-14 16:05:59 +00002494 break;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002495
Eric Andersenff9eee42001-06-29 04:57:14 +00002496 case TCOM:
Denis Vlasenko7e497522008-02-12 09:51:03 +00002497 rv = forkexec(t, pin, pout, no_fork, wp);
Eric Andersenff9eee42001-06-29 04:57:14 +00002498 break;
2499
2500 case TPIPE:
2501 {
Eric Andersen8401eea2004-08-04 19:16:54 +00002502 int pv[2];
2503
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002504 rv = openpipe(pv);
2505 if (rv < 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00002506 break;
2507 pv[0] = remap(pv[0]);
2508 pv[1] = remap(pv[1]);
Denis Vlasenko7e497522008-02-12 09:51:03 +00002509 (void) execute(t->left, pin, pv, /* no_fork: */ 0);
2510 rv = execute(t->right, pv, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002511 }
2512 break;
2513
2514 case TLIST:
Denis Vlasenko7e497522008-02-12 09:51:03 +00002515 (void) execute(t->left, pin, pout, /* no_fork: */ 0);
2516 rv = execute(t->right, pin, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002517 break;
2518
2519 case TASYNC:
Eric Andersen8401eea2004-08-04 19:16:54 +00002520 {
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002521 smallint hinteractive = interactive;
Eric Andersenff9eee42001-06-29 04:57:14 +00002522
Eric Andersen12de6cf2004-08-04 19:19:10 +00002523 DBGPRINTF7(("EXECUTE: TASYNC clause, calling vfork()...\n"));
2524
Eric Andersen8401eea2004-08-04 19:16:54 +00002525 i = vfork();
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002526 if (i == 0) { /* child */
Eric Andersen8401eea2004-08-04 19:16:54 +00002527 signal(SIGINT, SIG_IGN);
2528 signal(SIGQUIT, SIG_IGN);
2529 if (interactive)
2530 signal(SIGTERM, SIG_DFL);
2531 interactive = 0;
2532 if (pin == NULL) {
2533 close(0);
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00002534 xopen(bb_dev_null, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00002535 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002536 _exit(execute(t->left, pin, pout, /* no_fork: */ 1));
Eric Andersenff9eee42001-06-29 04:57:14 +00002537 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002538 interactive = hinteractive;
2539 if (i != -1) {
2540 setval(lookup("!"), putn(i));
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002541 closepipe(pin);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002542 if (interactive) {
2543 prs(putn(i));
2544 prs("\n");
2545 }
2546 } else
2547 rv = -1;
2548 setstatus(rv);
Eric Andersenff9eee42001-06-29 04:57:14 +00002549 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002550 break;
2551
2552 case TOR:
2553 case TAND:
Denis Vlasenko7e497522008-02-12 09:51:03 +00002554 rv = execute(t->left, pin, pout, /* no_fork: */ 0);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002555 t1 = t->right;
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002556 if (t1 != NULL && (rv == 0) == (t->op_type == TAND))
Denis Vlasenko7e497522008-02-12 09:51:03 +00002557 rv = execute(t1, pin, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002558 break;
2559
2560 case TFOR:
2561 if (wp == NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00002562 wp = dolv + 1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002563 i = dolc;
2564 if (i < 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00002565 i = 0;
2566 } else {
2567 i = -1;
Denis Vlasenko509697f2008-03-02 12:49:39 +00002568 while (*wp++ != NULL)
2569 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00002570 }
2571 vp = lookup(t->str);
2572 while (setjmp(bc.brkpt))
2573 if (isbreak)
2574 goto broken;
2575 brkset(&bc);
2576 for (t1 = t->left; i-- && *wp != NULL;) {
2577 setval(vp, *wp++);
Denis Vlasenko7e497522008-02-12 09:51:03 +00002578 rv = execute(t1, pin, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002579 }
2580 brklist = brklist->nextlev;
2581 break;
2582
2583 case TWHILE:
2584 case TUNTIL:
2585 while (setjmp(bc.brkpt))
2586 if (isbreak)
2587 goto broken;
2588 brkset(&bc);
2589 t1 = t->left;
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002590 while ((execute(t1, pin, pout, /* no_fork: */ 0) == 0) == (t->op_type == TWHILE))
Denis Vlasenko7e497522008-02-12 09:51:03 +00002591 rv = execute(t->right, pin, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002592 brklist = brklist->nextlev;
2593 break;
2594
2595 case TIF:
2596 case TELIF:
Eric Andersen8401eea2004-08-04 19:16:54 +00002597 if (t->right != NULL) {
Denis Vlasenko7e497522008-02-12 09:51:03 +00002598 rv = !execute(t->left, pin, pout, /* no_fork: */ 0) ?
2599 execute(t->right->left, pin, pout, /* no_fork: */ 0) :
2600 execute(t->right->right, pin, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002601 }
2602 break;
2603
2604 case TCASE:
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002605 cp = evalstr(t->str, DOSUB | DOTRIM);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002606 if (cp == NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00002607 cp = "";
Eric Andersen12de6cf2004-08-04 19:19:10 +00002608
2609 DBGPRINTF7(("EXECUTE: TCASE, t->str is %s, cp is %s\n",
2610 ((t->str == NULL) ? "NULL" : t->str),
2611 ((cp == NULL) ? "NULL" : cp)));
2612
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002613 t1 = findcase(t->left, cp);
2614 if (t1 != NULL) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002615 DBGPRINTF7(("EXECUTE: TCASE, calling execute(t=%p, t1=%p)...\n", t, t1));
Denis Vlasenko7e497522008-02-12 09:51:03 +00002616 rv = execute(t1, pin, pout, /* no_fork: */ 0);
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002617 DBGPRINTF7(("EXECUTE: TCASE, back from execute(t=%p, t1=%p)...\n", t, t1));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002618 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002619 break;
2620
2621 case TBRACE:
2622/*
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002623 iopp = t->ioact;
2624 if (i)
Eric Andersenff9eee42001-06-29 04:57:14 +00002625 while (*iopp)
2626 if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) {
2627 rv = -1;
2628 break;
2629 }
2630*/
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002631 if (rv >= 0) {
2632 t1 = t->left;
2633 if (t1) {
Denis Vlasenko7e497522008-02-12 09:51:03 +00002634 rv = execute(t1, pin, pout, /* no_fork: */ 0);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002635 }
2636 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002637 break;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002638
2639 };
Eric Andersenff9eee42001-06-29 04:57:14 +00002640
Denis Vlasenkoe4712752007-04-14 15:08:41 +00002641 broken:
Denis Vlasenko509697f2008-03-02 12:49:39 +00002642// Restoring op_words is most likely not needed now: see comment in forkexec()
2643// (also take a look at exec builtin (doexec) - it touches t->op_words)
2644 t->op_words = wp2;
Eric Andersenff9eee42001-06-29 04:57:14 +00002645 isbreak = 0;
2646 freehere(areanum);
2647 freearea(areanum);
2648 areanum = a;
2649 if (interactive && intr) {
2650 closeall();
2651 fail();
2652 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002653
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002654 i = trapset;
2655 if (i != 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002656 trapset = 0;
2657 runtrap(i);
2658 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002659
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002660 DBGPRINTF(("EXECUTE: returning from t=%p, rv=%d\n", t, rv));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002661 return rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00002662}
2663
Denis Vlasenkoe4712752007-04-14 15:08:41 +00002664static builtin_func_ptr inbuilt(const char *s)
2665{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002666 const struct builtincmd *bp;
2667
Denis Vlasenko95cb3262007-04-09 03:06:34 +00002668 for (bp = builtincmds; bp->name; bp++)
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002669 if (strcmp(bp->name, s) == 0)
2670 return bp->builtinfunc;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002671 return NULL;
2672}
2673
Denis Vlasenko7e497522008-02-12 09:51:03 +00002674static int forkexec(struct op *t, int *pin, int *pout, int no_fork, char **wp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002675{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002676 pid_t newpid;
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002677 int i;
2678 builtin_func_ptr bltin = NULL;
Denis Vlasenko7e497522008-02-12 09:51:03 +00002679 const char *bltin_name = NULL;
2680 const char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00002681 struct ioword **iopp;
2682 int resetsig;
2683 char **owp;
Denis Vlasenko7e497522008-02-12 09:51:03 +00002684 int forked;
Eric Andersenff9eee42001-06-29 04:57:14 +00002685
2686 int *hpin = pin;
2687 int *hpout = pout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002688 char *hwp;
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002689 smallint hinteractive;
2690 smallint hintr;
2691 smallint hexecflg;
Eric Andersen8401eea2004-08-04 19:16:54 +00002692 struct brkcon *hbrklist;
Eric Andersenff9eee42001-06-29 04:57:14 +00002693
2694#if __GNUC__
2695 /* Avoid longjmp clobbering */
2696 (void) &pin;
2697 (void) &pout;
2698 (void) &wp;
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002699 (void) &bltin;
Eric Andersenff9eee42001-06-29 04:57:14 +00002700 (void) &cp;
2701 (void) &resetsig;
2702 (void) &owp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002703#endif
Eric Andersenff9eee42001-06-29 04:57:14 +00002704
Denis Vlasenko7e497522008-02-12 09:51:03 +00002705 DBGPRINTF(("FORKEXEC: t=%p, pin %p, pout %p, no_fork %d\n", t, pin,
2706 pout, no_fork));
Denis Vlasenko509697f2008-03-02 12:49:39 +00002707 DBGPRINTF7(("FORKEXEC: t->op_words is %s\n",
2708 ((t->op_words == NULL) ? "NULL" : t->op_words[0])));
Eric Andersenff9eee42001-06-29 04:57:14 +00002709 owp = wp;
2710 resetsig = 0;
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002711 if (t->op_type == TCOM) {
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00002712 while (*wp++ != NULL)
2713 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00002714 cp = *wp;
2715
2716 /* strip all initial assignments */
Denis Vlasenko7e497522008-02-12 09:51:03 +00002717 /* FIXME: not correct wrt PATH=yyy command etc */
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00002718 if (FLAG['x']) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002719 DBGPRINTF9(("FORKEXEC: echo'ing, cp=%p, wp=%p, owp=%p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00002720 cp, wp, owp));
Eric Andersen8401eea2004-08-04 19:16:54 +00002721 echo(cp ? wp : owp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002722 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002723
Denis Vlasenko7e497522008-02-12 09:51:03 +00002724 if (cp == NULL) {
2725 if (t->ioact == NULL) {
2726 while ((cp = *owp++) != NULL && assign(cp, COPYV))
2727 continue;
2728 DBGPRINTF(("FORKEXEC: returning setstatus(0)\n"));
2729 return setstatus(0);
2730 }
2731 } else { /* cp != NULL */
2732 bltin_name = cp;
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002733 bltin = inbuilt(cp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002734 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002735 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002736
Denis Vlasenko7e497522008-02-12 09:51:03 +00002737 forked = 0;
Denis Vlasenko509697f2008-03-02 12:49:39 +00002738 // We were pointing t->op_words to temporary (expanded) arg list:
2739 // t->op_words = wp;
Denis Vlasenkofe218832008-03-01 09:35:39 +00002740 // and restored it later (in execute()), but "break"
Denis Vlasenko509697f2008-03-02 12:49:39 +00002741 // longjmps away (at "Run builtin" below), leaving t->op_words clobbered!
Denis Vlasenkofe218832008-03-01 09:35:39 +00002742 // See http://bugs.busybox.net/view.php?id=846.
Denis Vlasenko509697f2008-03-02 12:49:39 +00002743 // Now we do not touch t->op_words, but separately pass wp as param list
Denis Vlasenko42cc3042008-03-24 02:05:58 +00002744 // to builtins
Denis Vlasenko7e497522008-02-12 09:51:03 +00002745 DBGPRINTF(("FORKEXEC: bltin %p, no_fork %d, owp %p\n", bltin,
2746 no_fork, owp));
2747 /* Don't fork if it is a lone builtin (not in pipe)
2748 * OR we are told to _not_ fork */
2749 if ((!bltin || pin || pout) /* not lone bltin AND */
2750 && !no_fork /* not told to avoid fork */
2751 ) {
2752 /* Save values in case child alters them after vfork */
Eric Andersenff9eee42001-06-29 04:57:14 +00002753 hpin = pin;
2754 hpout = pout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002755 hwp = *wp;
2756 hinteractive = interactive;
2757 hintr = intr;
2758 hbrklist = brklist;
2759 hexecflg = execflg;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002760
Eric Andersen12de6cf2004-08-04 19:19:10 +00002761 DBGPRINTF3(("FORKEXEC: calling vfork()...\n"));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002762 newpid = vfork();
Eric Andersen12de6cf2004-08-04 19:19:10 +00002763 if (newpid == -1) {
Denis Vlasenko89f0b342006-11-18 22:04:09 +00002764 DBGPRINTF(("FORKEXEC: ERROR, cannot vfork()!\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002765 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002766 }
2767
Denis Vlasenko489f93e2007-02-01 01:43:16 +00002768 if (newpid > 0) { /* Parent */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002769 /* Restore values */
Eric Andersenff9eee42001-06-29 04:57:14 +00002770 pin = hpin;
2771 pout = hpout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002772 *wp = hwp;
2773 interactive = hinteractive;
2774 intr = hintr;
2775 brklist = hbrklist;
2776 execflg = hexecflg;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002777
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002778 closepipe(pin);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002779 return (pout == NULL ? setstatus(waitfor(newpid, 0)) : 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002780 }
2781
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002782 /* Child */
Denis Vlasenko7e497522008-02-12 09:51:03 +00002783 DBGPRINTF(("FORKEXEC: child process, bltin=%p (%s)\n", bltin, bltin_name));
Eric Andersenff9eee42001-06-29 04:57:14 +00002784 if (interactive) {
2785 signal(SIGINT, SIG_IGN);
2786 signal(SIGQUIT, SIG_IGN);
2787 resetsig = 1;
2788 }
2789 interactive = 0;
2790 intr = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002791 forked = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002792 brklist = 0;
2793 execflg = 0;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002794 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002795
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002796 if (owp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002797 while ((cp = *owp++) != NULL && assign(cp, COPYV))
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002798 if (!bltin)
Eric Andersenff9eee42001-06-29 04:57:14 +00002799 export(lookup(cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002800
Denis Vlasenko284d0fa2008-02-16 13:18:17 +00002801 if (pin) { /* NB: close _first_, then move fds! */
2802 close(pin[1]);
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00002803 xmove_fd(pin[0], 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002804 }
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002805 if (pout) {
Denis Vlasenko284d0fa2008-02-16 13:18:17 +00002806 close(pout[0]);
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00002807 xmove_fd(pout[1], 1);
Eric Andersenff9eee42001-06-29 04:57:14 +00002808 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002809
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002810 iopp = t->ioact;
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002811 if (iopp) {
2812 if (bltin && bltin != doexec) {
Denis Vlasenko7e497522008-02-12 09:51:03 +00002813 prs(bltin_name);
Eric Andersenff9eee42001-06-29 04:57:14 +00002814 err(": cannot redirect shell command");
Eric Andersen12de6cf2004-08-04 19:19:10 +00002815 if (forked)
2816 _exit(-1);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002817 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002818 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002819 while (*iopp) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002820 if (iosetup(*iopp++, pin != NULL, pout != NULL)) {
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002821 /* system-detected error */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002822 if (forked)
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002823 _exit(-1);
2824 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002825 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002826 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002827 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002828
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002829 if (bltin) {
Denis Vlasenko7e497522008-02-12 09:51:03 +00002830 if (forked || pin || pout) {
2831 /* Builtin in pipe: disallowed */
2832 /* TODO: allow "exec"? */
2833 prs(bltin_name);
2834 err(": cannot run builtin as part of pipe");
2835 if (forked)
2836 _exit(-1);
2837 return -1;
2838 }
Denis Vlasenkofe218832008-03-01 09:35:39 +00002839 /* Run builtin */
2840 i = setstatus(bltin(t, wp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002841 if (forked)
2842 _exit(i);
2843 DBGPRINTF(("FORKEXEC: returning i=%d\n", i));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002844 return i;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002845 }
2846
Eric Andersenff9eee42001-06-29 04:57:14 +00002847 /* should use FIOCEXCL */
Eric Andersen8401eea2004-08-04 19:16:54 +00002848 for (i = FDBASE; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00002849 close(i);
2850 if (resetsig) {
2851 signal(SIGINT, SIG_DFL);
2852 signal(SIGQUIT, SIG_DFL);
2853 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002854
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002855 if (t->op_type == TPAREN)
Denis Vlasenko7e497522008-02-12 09:51:03 +00002856 _exit(execute(t->left, NOPIPE, NOPIPE, /* no_fork: */ 1));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002857 if (wp[0] == NULL)
2858 _exit(0);
2859
Eric Andersenfd7a4c82004-09-02 23:13:10 +00002860 cp = rexecve(wp[0], wp, makenv(0, NULL));
Eric Andersen8401eea2004-08-04 19:16:54 +00002861 prs(wp[0]);
2862 prs(": ");
Eric Andersen12de6cf2004-08-04 19:19:10 +00002863 err(cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00002864 if (!execflg)
2865 trap[0] = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002866
Denis Vlasenko7e497522008-02-12 09:51:03 +00002867 DBGPRINTF(("FORKEXEC: calling leave(), pid=%d\n", getpid()));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002868
Eric Andersenff9eee42001-06-29 04:57:14 +00002869 leave();
2870 /* NOTREACHED */
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002871 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002872}
2873
2874/*
2875 * 0< 1> are ignored as required
2876 * within pipelines.
2877 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002878static int iosetup(struct ioword *iop, int pipein, int pipeout)
Eric Andersenff9eee42001-06-29 04:57:14 +00002879{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002880 int u = -1;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002881 char *cp = NULL;
2882 const char *msg;
Eric Andersenff9eee42001-06-29 04:57:14 +00002883
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002884 DBGPRINTF(("IOSETUP: iop %p, pipein %i, pipeout %i\n", iop,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002885 pipein, pipeout));
2886
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002887 if (iop->io_fd == IODEFAULT) /* take default */
2888 iop->io_fd = iop->io_flag & (IOREAD | IOHERE) ? 0 : 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002889
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002890 if (pipein && iop->io_fd == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002891 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002892
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002893 if (pipeout && iop->io_fd == 1)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002894 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002895
Eric Andersen8401eea2004-08-04 19:16:54 +00002896 msg = iop->io_flag & (IOREAD | IOHERE) ? "open" : "create";
Eric Andersenff9eee42001-06-29 04:57:14 +00002897 if ((iop->io_flag & IOHERE) == 0) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002898 cp = iop->io_name; /* huh?? */
2899 cp = evalstr(cp, DOSUB | DOTRIM);
2900 if (cp == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002901 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002902 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002903
Eric Andersenff9eee42001-06-29 04:57:14 +00002904 if (iop->io_flag & IODUP) {
2905 if (cp[1] || (!isdigit(*cp) && *cp != '-')) {
2906 prs(cp);
2907 err(": illegal >& argument");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002908 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002909 }
2910 if (*cp == '-')
2911 iop->io_flag = IOCLOSE;
Eric Andersen8401eea2004-08-04 19:16:54 +00002912 iop->io_flag &= ~(IOREAD | IOWRITE);
Eric Andersenff9eee42001-06-29 04:57:14 +00002913 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002914
Eric Andersenff9eee42001-06-29 04:57:14 +00002915 switch (iop->io_flag) {
2916 case IOREAD:
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00002917 u = open(cp, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00002918 break;
2919
2920 case IOHERE:
Eric Andersen8401eea2004-08-04 19:16:54 +00002921 case IOHERE | IOXHERE:
2922 u = herein(iop->io_name, iop->io_flag & IOXHERE);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002923 cp = (char*)"here file";
Eric Andersenff9eee42001-06-29 04:57:14 +00002924 break;
2925
Eric Andersen8401eea2004-08-04 19:16:54 +00002926 case IOWRITE | IOCAT:
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00002927 u = open(cp, O_WRONLY);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002928 if (u >= 0) {
Denis Vlasenkoea620772006-10-14 02:23:43 +00002929 lseek(u, (long) 0, SEEK_END);
Eric Andersenff9eee42001-06-29 04:57:14 +00002930 break;
2931 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002932 /* fall through to creation if >>file doesn't exist */
2933
Eric Andersenff9eee42001-06-29 04:57:14 +00002934 case IOWRITE:
2935 u = creat(cp, 0666);
2936 break;
2937
2938 case IODUP:
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002939 u = dup2(*cp - '0', iop->io_fd);
Eric Andersenff9eee42001-06-29 04:57:14 +00002940 break;
2941
2942 case IOCLOSE:
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002943 close(iop->io_fd);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002944 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002945 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002946
Eric Andersenff9eee42001-06-29 04:57:14 +00002947 if (u < 0) {
2948 prs(cp);
2949 prs(": cannot ");
2950 warn(msg);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002951 return 1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002952 }
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002953 xmove_fd(u, iop->io_fd);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002954 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002955}
2956
Eric Andersenff9eee42001-06-29 04:57:14 +00002957/*
2958 * Enter a new loop level (marked for break/continue).
2959 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002960static void brkset(struct brkcon *bc)
Eric Andersenff9eee42001-06-29 04:57:14 +00002961{
2962 bc->nextlev = brklist;
2963 brklist = bc;
2964}
2965
2966/*
2967 * Wait for the last process created.
2968 * Print a message for each process found
2969 * that was killed by a signal.
2970 * Ignore interrupt signals while waiting
2971 * unless `canintr' is true.
2972 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002973static int waitfor(int lastpid, int canintr)
Eric Andersenff9eee42001-06-29 04:57:14 +00002974{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002975 int pid, rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00002976 int s;
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002977 smallint oheedint = heedint;
Eric Andersenff9eee42001-06-29 04:57:14 +00002978
2979 heedint = 0;
2980 rv = 0;
2981 do {
2982 pid = wait(&s);
2983 if (pid == -1) {
2984 if (errno != EINTR || canintr)
2985 break;
2986 } else {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002987 rv = WAITSIG(s);
2988 if (rv != 0) {
Denis Vlasenko80b8b392007-06-25 10:55:35 +00002989 if (rv < ARRAY_SIZE(signame)) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002990 if (signame[rv] != NULL) {
2991 if (pid != lastpid) {
2992 prn(pid);
2993 prs(": ");
2994 }
2995 prs(signame[rv]);
2996 }
2997 } else {
2998 if (pid != lastpid) {
2999 prn(pid);
3000 prs(": ");
3001 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003002 prs("Signal ");
3003 prn(rv);
3004 prs(" ");
Eric Andersenff9eee42001-06-29 04:57:14 +00003005 }
3006 if (WAITCORE(s))
3007 prs(" - core dumped");
Denis Vlasenko80b8b392007-06-25 10:55:35 +00003008 if (rv >= ARRAY_SIZE(signame) || signame[rv])
Eric Andersenff9eee42001-06-29 04:57:14 +00003009 prs("\n");
3010 rv = -1;
3011 } else
3012 rv = WAITVAL(s);
3013 }
3014 } while (pid != lastpid);
3015 heedint = oheedint;
3016 if (intr) {
3017 if (interactive) {
3018 if (canintr)
3019 intr = 0;
3020 } else {
Eric Andersen8401eea2004-08-04 19:16:54 +00003021 if (exstat == 0)
3022 exstat = rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003023 onintr(0);
3024 }
3025 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003026 return rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003027}
3028
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003029static int setstatus(int s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003030{
3031 exstat = s;
3032 setval(lookup("?"), putn(s));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003033 return s;
Eric Andersenff9eee42001-06-29 04:57:14 +00003034}
3035
3036/*
3037 * PATH-searching interface to execve.
3038 * If getenv("PATH") were kept up-to-date,
3039 * execvp might be used.
3040 */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003041static const char *rexecve(char *c, char **v, char **envp)
Eric Andersenff9eee42001-06-29 04:57:14 +00003042{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003043 const char *sp;
3044 char *tp;
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00003045 int asis = 0;
Eric Andersen1c039232001-07-07 00:05:55 +00003046 char *name = c;
Eric Andersen8401eea2004-08-04 19:16:54 +00003047
Denis Vlasenko80d14be2007-04-10 23:03:30 +00003048 if (ENABLE_FEATURE_SH_STANDALONE) {
Denis Vlasenko1aa7e472007-11-28 06:49:03 +00003049 if (find_applet_by_name(name) >= 0) {
Rob Landleya299efb2006-08-10 21:46:43 +00003050 /* We have to exec here since we vforked. Running
Denis Vlasenkoe4f2d062007-04-11 17:03:19 +00003051 * run_applet_and_exit() won't work and bad things
Rob Landleya299efb2006-08-10 21:46:43 +00003052 * will happen. */
Denis Vlasenkobdbbb7e2007-06-08 15:02:55 +00003053 execve(bb_busybox_exec_path, v, envp);
Rob Landleya299efb2006-08-10 21:46:43 +00003054 }
Eric Andersen1c039232001-07-07 00:05:55 +00003055 }
Eric Andersen1c039232001-07-07 00:05:55 +00003056
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003057 DBGPRINTF(("REXECVE: c=%p, v=%p, envp=%p\n", c, v, envp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003058
Eric Andersen8401eea2004-08-04 19:16:54 +00003059 sp = any('/', c) ? "" : path->value;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003060 asis = (*sp == '\0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003061 while (asis || *sp != '\0') {
3062 asis = 0;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003063 tp = global_env.linep;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003064 for (; *sp != '\0'; tp++) {
3065 *tp = *sp++;
3066 if (*tp == ':') {
3067 asis = (*sp == '\0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003068 break;
3069 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003070 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003071 if (tp != global_env.linep)
Eric Andersenff9eee42001-06-29 04:57:14 +00003072 *tp++ = '/';
Denis Vlasenko509697f2008-03-02 12:49:39 +00003073 strcpy(tp, c);
3074 //for (i = 0; (*tp++ = c[i++]) != '\0';)
3075 // continue;
Eric Andersen1c039232001-07-07 00:05:55 +00003076
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003077 DBGPRINTF3(("REXECVE: global_env.linep is %s\n", global_env.linep));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003078
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003079 execve(global_env.linep, v, envp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003080
Eric Andersenff9eee42001-06-29 04:57:14 +00003081 switch (errno) {
3082 case ENOEXEC:
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003083 *v = global_env.linep;
Denis Vlasenko509697f2008-03-02 12:49:39 +00003084 v--;
3085 tp = *v;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003086 *v = global_env.linep;
Glenn L McGrathdc4e75e2003-09-02 02:36:18 +00003087 execve(DEFAULT_SHELL, v, envp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003088 *v = tp;
Denis Vlasenko509697f2008-03-02 12:49:39 +00003089 return "no shell";
Eric Andersenff9eee42001-06-29 04:57:14 +00003090
3091 case ENOMEM:
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003092 return (char *) bb_msg_memory_exhausted;
Eric Andersenff9eee42001-06-29 04:57:14 +00003093
3094 case E2BIG:
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003095 return "argument list too long";
Eric Andersenff9eee42001-06-29 04:57:14 +00003096 }
3097 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003098 return errno == ENOENT ? "not found" : "cannot execute";
Eric Andersenff9eee42001-06-29 04:57:14 +00003099}
3100
3101/*
3102 * Run the command produced by generator `f'
3103 * applied to stream `arg'.
3104 */
Eric Andersen8401eea2004-08-04 19:16:54 +00003105static int run(struct ioarg *argp, int (*f) (struct ioarg *))
Eric Andersenff9eee42001-06-29 04:57:14 +00003106{
3107 struct op *otree;
3108 struct wdblock *swdlist;
3109 struct wdblock *siolist;
3110 jmp_buf ev, rt;
3111 xint *ofail;
3112 int rv;
3113
3114#if __GNUC__
3115 /* Avoid longjmp clobbering */
3116 (void) &rv;
3117#endif
3118
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003119 DBGPRINTF(("RUN: enter, areanum %d, outtree %p, failpt %p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00003120 areanum, outtree, failpt));
3121
Eric Andersenff9eee42001-06-29 04:57:14 +00003122 areanum++;
3123 swdlist = wdlist;
3124 siolist = iolist;
3125 otree = outtree;
3126 ofail = failpt;
3127 rv = -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003128
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003129 errpt = ev;
3130 if (newenv(setjmp(errpt)) == 0) {
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00003131 wdlist = NULL;
3132 iolist = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00003133 pushio(argp, f);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003134 global_env.iobase = global_env.iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00003135 yynerrs = 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003136 failpt = rt;
3137 if (setjmp(failpt) == 0 && yyparse() == 0)
Denis Vlasenko7e497522008-02-12 09:51:03 +00003138 rv = execute(outtree, NOPIPE, NOPIPE, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003139 quitenv();
Eric Andersen12de6cf2004-08-04 19:19:10 +00003140 } else {
3141 DBGPRINTF(("RUN: error from newenv()!\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00003142 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00003143
Eric Andersenff9eee42001-06-29 04:57:14 +00003144 wdlist = swdlist;
3145 iolist = siolist;
3146 failpt = ofail;
3147 outtree = otree;
3148 freearea(areanum--);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003149
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003150 return rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003151}
3152
3153/* -------- do.c -------- */
3154
3155/*
3156 * built-in commands: doX
3157 */
3158
Denis Vlasenko68404f12008-03-17 09:00:54 +00003159static int dohelp(struct op *t ATTRIBUTE_UNUSED, char **args ATTRIBUTE_UNUSED)
Eric Andersen1c039232001-07-07 00:05:55 +00003160{
3161 int col;
3162 const struct builtincmd *x;
3163
Denis Vlasenko0ee39992006-12-24 15:23:28 +00003164 puts("\nBuilt-in commands:\n"
3165 "-------------------");
Eric Andersen1c039232001-07-07 00:05:55 +00003166
Denis Vlasenko95cb3262007-04-09 03:06:34 +00003167 col = 0;
3168 x = builtincmds;
3169 while (x->name) {
3170 col += printf("%c%s", ((col == 0) ? '\t' : ' '), x->name);
Eric Andersen1c039232001-07-07 00:05:55 +00003171 if (col > 60) {
Denis Vlasenko4daad902007-09-27 10:20:47 +00003172 bb_putchar('\n');
Eric Andersen1c039232001-07-07 00:05:55 +00003173 col = 0;
3174 }
Denis Vlasenko95cb3262007-04-09 03:06:34 +00003175 x++;
Eric Andersen1c039232001-07-07 00:05:55 +00003176 }
Denis Vlasenko80d14be2007-04-10 23:03:30 +00003177#if ENABLE_FEATURE_SH_STANDALONE
Eric Andersen1c039232001-07-07 00:05:55 +00003178 {
Denis Vlasenko1aa7e472007-11-28 06:49:03 +00003179 const char *applet = applet_names;
Eric Andersen1c039232001-07-07 00:05:55 +00003180
Denis Vlasenko1aa7e472007-11-28 06:49:03 +00003181 while (*applet) {
3182 col += printf("%c%s", ((col == 0) ? '\t' : ' '), applet);
Eric Andersen1c039232001-07-07 00:05:55 +00003183 if (col > 60) {
Denis Vlasenko4daad902007-09-27 10:20:47 +00003184 bb_putchar('\n');
Eric Andersen1c039232001-07-07 00:05:55 +00003185 col = 0;
3186 }
Denis Vlasenko1aa7e472007-11-28 06:49:03 +00003187 applet += strlen(applet) + 1;
Eric Andersen1c039232001-07-07 00:05:55 +00003188 }
3189 }
3190#endif
Denis Vlasenko0ee39992006-12-24 15:23:28 +00003191 puts("\n");
Eric Andersen1c039232001-07-07 00:05:55 +00003192 return EXIT_SUCCESS;
3193}
3194
Denis Vlasenko68404f12008-03-17 09:00:54 +00003195static int dolabel(struct op *t ATTRIBUTE_UNUSED, char **args ATTRIBUTE_UNUSED)
Eric Andersenff9eee42001-06-29 04:57:14 +00003196{
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003197 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003198}
3199
Denis Vlasenko68404f12008-03-17 09:00:54 +00003200static int dochdir(struct op *t ATTRIBUTE_UNUSED, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003201{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003202 const char *cp, *er;
Eric Andersenff9eee42001-06-29 04:57:14 +00003203
Denis Vlasenkofe218832008-03-01 09:35:39 +00003204 cp = args[1];
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003205 if (cp == NULL) {
3206 cp = homedir->value;
Denis Vlasenkod244c5e2007-02-09 17:30:14 +00003207 if (cp != NULL)
3208 goto do_cd;
3209 er = ": no home directory";
3210 } else {
3211 do_cd:
3212 if (chdir(cp) >= 0)
3213 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003214 er = ": bad directory";
Denis Vlasenkod244c5e2007-02-09 17:30:14 +00003215 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003216 prs(cp != NULL ? cp : "cd");
Eric Andersenff9eee42001-06-29 04:57:14 +00003217 err(er);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003218 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003219}
3220
Denis Vlasenko68404f12008-03-17 09:00:54 +00003221static int doshift(struct op *t ATTRIBUTE_UNUSED, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003222{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003223 int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003224
Denis Vlasenkofe218832008-03-01 09:35:39 +00003225 n = args[1] ? getn(args[1]) : 1;
Eric Andersen8401eea2004-08-04 19:16:54 +00003226 if (dolc < n) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003227 err("nothing to shift");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003228 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003229 }
3230 dolv[n] = dolv[0];
3231 dolv += n;
3232 dolc -= n;
3233 setval(lookup("#"), putn(dolc));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003234 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003235}
3236
3237/*
3238 * execute login and newgrp directly
3239 */
Denis Vlasenko68404f12008-03-17 09:00:54 +00003240static int dologin(struct op *t ATTRIBUTE_UNUSED, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003241{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003242 const char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003243
3244 if (interactive) {
3245 signal(SIGINT, SIG_DFL);
3246 signal(SIGQUIT, SIG_DFL);
3247 }
Denis Vlasenkofe218832008-03-01 09:35:39 +00003248 cp = rexecve(args[0], args, makenv(0, NULL));
3249 prs(args[0]);
Eric Andersen8401eea2004-08-04 19:16:54 +00003250 prs(": ");
3251 err(cp);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003252 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003253}
3254
Denis Vlasenko68404f12008-03-17 09:00:54 +00003255static int doumask(struct op *t ATTRIBUTE_UNUSED, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003256{
Denis Vlasenko7e497522008-02-12 09:51:03 +00003257 int i;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003258 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003259
Denis Vlasenkofe218832008-03-01 09:35:39 +00003260 cp = args[1];
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003261 if (cp == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003262 i = umask(0);
3263 umask(i);
Denis Vlasenko7e497522008-02-12 09:51:03 +00003264 printf("%04o\n", i);
Eric Andersenff9eee42001-06-29 04:57:14 +00003265 } else {
Denis Vlasenko7e497522008-02-12 09:51:03 +00003266 i = bb_strtou(cp, NULL, 8);
3267 if (errno) {
3268 err("umask: bad octal number");
3269 return 1;
3270 }
3271 umask(i);
Eric Andersenff9eee42001-06-29 04:57:14 +00003272 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003273 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003274}
3275
Denis Vlasenkofe218832008-03-01 09:35:39 +00003276static int doexec(struct op *t, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003277{
Eric Andersenff9eee42001-06-29 04:57:14 +00003278 jmp_buf ex;
3279 xint *ofail;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003280 char **sv_words;
Eric Andersenff9eee42001-06-29 04:57:14 +00003281
3282 t->ioact = NULL;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003283 if (!args[1])
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003284 return 1;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003285
Eric Andersenff9eee42001-06-29 04:57:14 +00003286 execflg = 1;
3287 ofail = failpt;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003288 failpt = ex;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003289
Denis Vlasenko509697f2008-03-02 12:49:39 +00003290 sv_words = t->op_words;
3291 t->op_words = args + 1;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003292// TODO: test what will happen with "exec break" -
Denis Vlasenko509697f2008-03-02 12:49:39 +00003293// will it leave t->op_words pointing to garbage?
Denis Vlasenkofe218832008-03-01 09:35:39 +00003294// (see http://bugs.busybox.net/view.php?id=846)
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003295 if (setjmp(failpt) == 0)
Denis Vlasenko7e497522008-02-12 09:51:03 +00003296 execute(t, NOPIPE, NOPIPE, /* no_fork: */ 1);
Denis Vlasenko509697f2008-03-02 12:49:39 +00003297 t->op_words = sv_words;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003298
Eric Andersenff9eee42001-06-29 04:57:14 +00003299 failpt = ofail;
3300 execflg = 0;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003301
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003302 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003303}
3304
Denis Vlasenko68404f12008-03-17 09:00:54 +00003305static int dodot(struct op *t ATTRIBUTE_UNUSED, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003306{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003307 int i;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003308 const char *sp;
3309 char *tp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003310 char *cp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003311 int maltmp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003312
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003313 DBGPRINTF(("DODOT: enter, t=%p, tleft %p, tright %p, global_env.linep is %s\n",
3314 t, t->left, t->right, ((global_env.linep == NULL) ? "NULL" : global_env.linep)));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003315
Denis Vlasenkofe218832008-03-01 09:35:39 +00003316 cp = args[1];
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003317 if (cp == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00003318 DBGPRINTF(("DODOT: bad args, ret 0\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003319 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003320 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003321 DBGPRINTF(("DODOT: cp is %s\n", cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003322
Eric Andersen8401eea2004-08-04 19:16:54 +00003323 sp = any('/', cp) ? ":" : path->value;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003324
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003325 DBGPRINTF(("DODOT: sp is %s, global_env.linep is %s\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00003326 ((sp == NULL) ? "NULL" : sp),
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003327 ((global_env.linep == NULL) ? "NULL" : global_env.linep)));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003328
Eric Andersenff9eee42001-06-29 04:57:14 +00003329 while (*sp) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003330 tp = global_env.linep;
Eric Andersenff9eee42001-06-29 04:57:14 +00003331 while (*sp && (*tp = *sp++) != ':')
3332 tp++;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003333 if (tp != global_env.linep)
Eric Andersenff9eee42001-06-29 04:57:14 +00003334 *tp++ = '/';
Denis Vlasenko509697f2008-03-02 12:49:39 +00003335 strcpy(tp, cp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003336
3337 /* Original code */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003338 i = open(global_env.linep, O_RDONLY);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003339 if (i >= 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003340 exstat = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003341 maltmp = remap(i);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003342 DBGPRINTF(("DODOT: remap=%d, exstat=%d, global_env.iofd %d, i %d, global_env.linep is %s\n",
3343 maltmp, exstat, global_env.iofd, i, global_env.linep));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003344
3345 next(maltmp); /* Basically a PUSHIO */
3346
3347 DBGPRINTF(("DODOT: returning exstat=%d\n", exstat));
3348
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003349 return exstat;
Eric Andersenff9eee42001-06-29 04:57:14 +00003350 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003351 } /* while */
Eric Andersen12de6cf2004-08-04 19:19:10 +00003352
Eric Andersenff9eee42001-06-29 04:57:14 +00003353 prs(cp);
3354 err(": not found");
Eric Andersen12de6cf2004-08-04 19:19:10 +00003355
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003356 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003357}
3358
Denis Vlasenko68404f12008-03-17 09:00:54 +00003359static int dowait(struct op *t ATTRIBUTE_UNUSED, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003360{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003361 int i;
3362 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003363
Denis Vlasenkofe218832008-03-01 09:35:39 +00003364 cp = args[1];
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003365 if (cp != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003366 i = getn(cp);
3367 if (i == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003368 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003369 } else
3370 i = -1;
3371 setstatus(waitfor(i, 1));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003372 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003373}
3374
Denis Vlasenko68404f12008-03-17 09:00:54 +00003375static int doread(struct op *t ATTRIBUTE_UNUSED, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003376{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003377 char *cp, **wp;
3378 int nb = 0;
3379 int nl = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003380
Denis Vlasenkofe218832008-03-01 09:35:39 +00003381 if (args[1] == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003382 err("Usage: read name ...");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003383 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003384 }
Denis Vlasenkofe218832008-03-01 09:35:39 +00003385 for (wp = args + 1; *wp; wp++) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003386 for (cp = global_env.linep; !nl && cp < elinep - 1; cp++) {
Denis Vlasenkoe376d452008-02-20 22:23:24 +00003387 nb = nonblock_safe_read(0, cp, sizeof(*cp));
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003388 if (nb != sizeof(*cp))
Eric Andersenff9eee42001-06-29 04:57:14 +00003389 break;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003390 nl = (*cp == '\n');
3391 if (nl || (wp[1] && any(*cp, ifs->value)))
3392 break;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003393 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003394 *cp = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00003395 if (nb <= 0)
3396 break;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003397 setval(lookup(*wp), global_env.linep);
Eric Andersenff9eee42001-06-29 04:57:14 +00003398 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003399 return nb <= 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003400}
3401
Denis Vlasenko68404f12008-03-17 09:00:54 +00003402static int doeval(struct op *t ATTRIBUTE_UNUSED, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003403{
Denis Vlasenkofe218832008-03-01 09:35:39 +00003404 return RUN(awordlist, args + 1, wdchar);
Eric Andersenff9eee42001-06-29 04:57:14 +00003405}
3406
Denis Vlasenko68404f12008-03-17 09:00:54 +00003407static int dotrap(struct op *t ATTRIBUTE_UNUSED, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003408{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003409 int n, i;
3410 int resetsig;
Eric Andersenff9eee42001-06-29 04:57:14 +00003411
Denis Vlasenkofe218832008-03-01 09:35:39 +00003412 if (args[1] == NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00003413 for (i = 0; i <= _NSIG; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00003414 if (trap[i]) {
3415 prn(i);
3416 prs(": ");
3417 prs(trap[i]);
3418 prs("\n");
3419 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003420 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003421 }
Denis Vlasenkofe218832008-03-01 09:35:39 +00003422 resetsig = isdigit(args[1][0]);
3423 for (i = resetsig ? 1 : 2; args[i] != NULL; ++i) {
3424 n = getsig(args[i]);
Eric Andersenff9eee42001-06-29 04:57:14 +00003425 freecell(trap[n]);
3426 trap[n] = 0;
3427 if (!resetsig) {
Denis Vlasenkofe218832008-03-01 09:35:39 +00003428 if (args[1][0] != '\0') {
3429 trap[n] = strsave(args[1], 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003430 setsig(n, sig);
3431 } else
3432 setsig(n, SIG_IGN);
3433 } else {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00003434 if (interactive) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003435 if (n == SIGINT)
3436 setsig(n, onintr);
3437 else
Eric Andersen8401eea2004-08-04 19:16:54 +00003438 setsig(n, n == SIGQUIT ? SIG_IGN : SIG_DFL);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00003439 } else
Eric Andersenff9eee42001-06-29 04:57:14 +00003440 setsig(n, SIG_DFL);
3441 }
3442 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003443 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003444}
3445
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003446static int getsig(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003447{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003448 int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003449
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003450 n = getn(s);
3451 if (n < 0 || n > _NSIG) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003452 err("trap: bad signal number");
3453 n = 0;
3454 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003455 return n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003456}
3457
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003458static void setsig(int n, sighandler_t f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003459{
3460 if (n == 0)
3461 return;
3462 if (signal(n, SIG_IGN) != SIG_IGN || ourtrap[n]) {
3463 ourtrap[n] = 1;
3464 signal(n, f);
3465 }
3466}
3467
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003468static int getn(char *as)
Eric Andersenff9eee42001-06-29 04:57:14 +00003469{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003470 char *s;
3471 int n, m;
Eric Andersenff9eee42001-06-29 04:57:14 +00003472
3473 s = as;
3474 m = 1;
3475 if (*s == '-') {
3476 m = -1;
3477 s++;
3478 }
3479 for (n = 0; isdigit(*s); s++)
Eric Andersen8401eea2004-08-04 19:16:54 +00003480 n = (n * 10) + (*s - '0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003481 if (*s) {
3482 prs(as);
3483 err(": bad number");
3484 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003485 return n * m;
Eric Andersenff9eee42001-06-29 04:57:14 +00003486}
3487
Denis Vlasenko68404f12008-03-17 09:00:54 +00003488static int dobreak(struct op *t ATTRIBUTE_UNUSED, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003489{
Denis Vlasenkofe218832008-03-01 09:35:39 +00003490 return brkcontin(args[1], 1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003491}
3492
Denis Vlasenko68404f12008-03-17 09:00:54 +00003493static int docontinue(struct op *t ATTRIBUTE_UNUSED, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003494{
Denis Vlasenkofe218832008-03-01 09:35:39 +00003495 return brkcontin(args[1], 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003496}
3497
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003498static int brkcontin(char *cp, int val)
Eric Andersenff9eee42001-06-29 04:57:14 +00003499{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003500 struct brkcon *bc;
3501 int nl;
Eric Andersenff9eee42001-06-29 04:57:14 +00003502
Eric Andersen8401eea2004-08-04 19:16:54 +00003503 nl = cp == NULL ? 1 : getn(cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003504 if (nl <= 0)
3505 nl = 999;
3506 do {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003507 bc = brklist;
3508 if (bc == NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00003509 break;
3510 brklist = bc->nextlev;
3511 } while (--nl);
3512 if (nl) {
3513 err("bad break/continue level");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003514 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003515 }
Denis Vlasenko648b44f2008-02-12 06:04:06 +00003516 isbreak = (val != 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003517 longjmp(bc->brkpt, 1);
3518 /* NOTREACHED */
3519}
3520
Denis Vlasenko68404f12008-03-17 09:00:54 +00003521static int doexit(struct op *t ATTRIBUTE_UNUSED, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003522{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003523 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003524
3525 execflg = 0;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003526 cp = args[1];
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003527 if (cp != NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00003528 setstatus(getn(cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003529
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003530 DBGPRINTF(("DOEXIT: calling leave(), t=%p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003531
Eric Andersenff9eee42001-06-29 04:57:14 +00003532 leave();
3533 /* NOTREACHED */
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003534 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003535}
3536
Denis Vlasenko68404f12008-03-17 09:00:54 +00003537static int doexport(struct op *t ATTRIBUTE_UNUSED, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003538{
Denis Vlasenkofe218832008-03-01 09:35:39 +00003539 rdexp(args + 1, export, EXPORT);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003540 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003541}
3542
Denis Vlasenko68404f12008-03-17 09:00:54 +00003543static int doreadonly(struct op *t ATTRIBUTE_UNUSED, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003544{
Denis Vlasenkofe218832008-03-01 09:35:39 +00003545 rdexp(args + 1, ronly, RONLY);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003546 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003547}
3548
Eric Andersen8401eea2004-08-04 19:16:54 +00003549static void rdexp(char **wp, void (*f) (struct var *), int key)
Eric Andersenff9eee42001-06-29 04:57:14 +00003550{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003551 DBGPRINTF6(("RDEXP: enter, wp=%p, func=%p, key=%d\n", wp, f, key));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003552 DBGPRINTF6(("RDEXP: *wp=%s\n", *wp));
3553
Eric Andersenff9eee42001-06-29 04:57:14 +00003554 if (*wp != NULL) {
Matt Kraaif69bfc72001-07-12 19:39:59 +00003555 for (; *wp != NULL; wp++) {
3556 if (isassign(*wp)) {
3557 char *cp;
Eric Andersen8401eea2004-08-04 19:16:54 +00003558
Matt Kraaif69bfc72001-07-12 19:39:59 +00003559 assign(*wp, COPYV);
Denis Vlasenko509697f2008-03-02 12:49:39 +00003560 for (cp = *wp; *cp != '='; cp++)
3561 continue;
Matt Kraaif69bfc72001-07-12 19:39:59 +00003562 *cp = '\0';
3563 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003564 if (checkname(*wp))
Eric Andersen8401eea2004-08-04 19:16:54 +00003565 (*f) (lookup(*wp));
Eric Andersenff9eee42001-06-29 04:57:14 +00003566 else
3567 badid(*wp);
Matt Kraaif69bfc72001-07-12 19:39:59 +00003568 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003569 } else
3570 putvlist(key, 1);
3571}
3572
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003573static void badid(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003574{
3575 prs(s);
3576 err(": bad identifier");
3577}
3578
Denis Vlasenko68404f12008-03-17 09:00:54 +00003579static int doset(struct op *t ATTRIBUTE_UNUSED, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003580{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003581 struct var *vp;
3582 char *cp;
3583 int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003584
Denis Vlasenkofe218832008-03-01 09:35:39 +00003585 cp = args[1];
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003586 if (cp == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003587 for (vp = vlist; vp; vp = vp->next)
3588 varput(vp->name, 1);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003589 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003590 }
3591 if (*cp == '-') {
Denis Vlasenkofe218832008-03-01 09:35:39 +00003592 args++;
Eric Andersenff9eee42001-06-29 04:57:14 +00003593 if (*++cp == 0)
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003594 FLAG['x'] = FLAG['v'] = 0;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003595 else {
3596 for (; *cp; cp++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003597 switch (*cp) {
3598 case 'e':
3599 if (!interactive)
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003600 FLAG['e']++;
Eric Andersenff9eee42001-06-29 04:57:14 +00003601 break;
3602
3603 default:
Eric Andersen8401eea2004-08-04 19:16:54 +00003604 if (*cp >= 'a' && *cp <= 'z')
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003605 FLAG[(int) *cp]++;
Eric Andersenff9eee42001-06-29 04:57:14 +00003606 break;
3607 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003608 }
3609 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003610 setdash();
3611 }
Denis Vlasenkofe218832008-03-01 09:35:39 +00003612 if (args[1]) {
3613 args[0] = dolv[0];
3614 for (n = 1; args[n]; n++)
3615 setarea((char *) args[n], 0);
Eric Andersen8401eea2004-08-04 19:16:54 +00003616 dolc = n - 1;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003617 dolv = args;
Eric Andersenff9eee42001-06-29 04:57:14 +00003618 setval(lookup("#"), putn(dolc));
Eric Andersen8401eea2004-08-04 19:16:54 +00003619 setarea((char *) (dolv - 1), 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003620 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003621 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003622}
3623
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003624static void varput(char *s, int out)
Eric Andersenff9eee42001-06-29 04:57:14 +00003625{
Matt Kraai69edfec2001-08-06 14:14:18 +00003626 if (isalnum(*s) || *s == '_') {
Eric Andersenff9eee42001-06-29 04:57:14 +00003627 write(out, s, strlen(s));
3628 write(out, "\n", 1);
3629 }
3630}
3631
3632
3633/*
3634 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
3635 * This file contains code for the times builtin.
Eric Andersenff9eee42001-06-29 04:57:14 +00003636 */
Denis Vlasenkofe218832008-03-01 09:35:39 +00003637static void times_fmt(char *buf, clock_t val, unsigned clk_tck)
3638{
3639 unsigned min, sec;
3640 if (sizeof(val) > sizeof(int))
3641 sec = ((unsigned long)val) / clk_tck;
3642 else
3643 sec = ((unsigned)val) / clk_tck;
3644 min = sec / 60;
3645#if ENABLE_DESKTOP
3646 sprintf(buf, "%um%u.%03us", min, (sec - min * 60),
3647 /* msec: */ ((unsigned)(val - (clock_t)sec * clk_tck)) * 1000 / clk_tck
3648 );
3649#else
3650 sprintf(buf, "%um%us", min, (sec - min * 60));
3651#endif
3652}
3653
Denis Vlasenko68404f12008-03-17 09:00:54 +00003654static int dotimes(struct op *t ATTRIBUTE_UNUSED, char **args ATTRIBUTE_UNUSED)
Eric Andersenff9eee42001-06-29 04:57:14 +00003655{
3656 struct tms buf;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003657 unsigned clk_tck = sysconf(_SC_CLK_TCK);
3658 /* How much do we need for "NmN.NNNs" ? */
3659 enum { TIMEBUF_SIZE = sizeof(int)*3 + sizeof(int)*3 + 6 };
3660 char u[TIMEBUF_SIZE], s[TIMEBUF_SIZE];
3661 char cu[TIMEBUF_SIZE], cs[TIMEBUF_SIZE];
Eric Andersenff9eee42001-06-29 04:57:14 +00003662
3663 times(&buf);
Denis Vlasenkofe218832008-03-01 09:35:39 +00003664
3665 times_fmt(u, buf.tms_utime, clk_tck);
3666 times_fmt(s, buf.tms_stime, clk_tck);
3667 times_fmt(cu, buf.tms_cutime, clk_tck);
3668 times_fmt(cs, buf.tms_cstime, clk_tck);
3669
3670 printf("%s %s\n%s %s\n", u, s, cu, cs);
Eric Andersenff9eee42001-06-29 04:57:14 +00003671 return 0;
3672}
3673
3674
Eric Andersenff9eee42001-06-29 04:57:14 +00003675/* -------- eval.c -------- */
3676
3677/*
3678 * ${}
3679 * `command`
3680 * blank interpretation
3681 * quoting
3682 * glob
3683 */
3684
Eric Andersen8401eea2004-08-04 19:16:54 +00003685static char **eval(char **ap, int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003686{
3687 struct wdblock *wb;
3688 char **wp;
3689 char **wf;
3690 jmp_buf ev;
3691
3692#if __GNUC__
3693 /* Avoid longjmp clobbering */
3694 (void) &wp;
3695 (void) &ap;
3696#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00003697
3698 DBGPRINTF4(("EVAL: enter, f=%d\n", f));
3699
Eric Andersenff9eee42001-06-29 04:57:14 +00003700 wp = NULL;
3701 wb = NULL;
3702 wf = NULL;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003703 errpt = ev;
3704 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003705 while (*ap && isassign(*ap))
3706 expand(*ap++, &wb, f & ~DOGLOB);
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003707 if (FLAG['k']) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003708 for (wf = ap; *wf; wf++) {
3709 if (isassign(*wf))
3710 expand(*wf, &wb, f & ~DOGLOB);
3711 }
3712 }
Denis Vlasenko648b44f2008-02-12 06:04:06 +00003713 for (wb = addword((char *) NULL, wb); *ap; ap++) {
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003714 if (!FLAG['k'] || !isassign(*ap))
Eric Andersenff9eee42001-06-29 04:57:14 +00003715 expand(*ap, &wb, f & ~DOKEY);
3716 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003717 wb = addword((char *) 0, wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00003718 wp = getwords(wb);
3719 quitenv();
3720 } else
3721 gflg = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003722
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003723 return gflg ? (char **) NULL : wp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003724}
3725
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003726
Eric Andersenff9eee42001-06-29 04:57:14 +00003727/*
3728 * Make the exported environment from the exported
3729 * names in the dictionary. Keyword assignments
3730 * will already have been done.
3731 */
Eric Andersenfd7a4c82004-09-02 23:13:10 +00003732static char **makenv(int all, struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00003733{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003734 struct var *vp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003735
3736 DBGPRINTF5(("MAKENV: enter, all=%d\n", all));
Eric Andersenff9eee42001-06-29 04:57:14 +00003737
Eric Andersenff9eee42001-06-29 04:57:14 +00003738 for (vp = vlist; vp; vp = vp->next)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003739 if (all || vp->status & EXPORT)
Eric Andersenff9eee42001-06-29 04:57:14 +00003740 wb = addword(vp->name, wb);
Eric Andersen8401eea2004-08-04 19:16:54 +00003741 wb = addword((char *) 0, wb);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003742 return getwords(wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00003743}
3744
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003745static int expand(const char *cp, struct wdblock **wbp, int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003746{
3747 jmp_buf ev;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003748 char *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003749
3750#if __GNUC__
3751 /* Avoid longjmp clobbering */
3752 (void) &cp;
3753#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00003754
3755 DBGPRINTF3(("EXPAND: enter, f=%d\n", f));
3756
Eric Andersenff9eee42001-06-29 04:57:14 +00003757 gflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003758
Eric Andersenff9eee42001-06-29 04:57:14 +00003759 if (cp == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003760 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003761
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003762 if (!anys("$`'\"", cp) && !anys(ifs->value, cp)
3763 && ((f & DOGLOB) == 0 || !anys("[*?", cp))
3764 ) {
3765 xp = strsave(cp, areanum);
Eric Andersenff9eee42001-06-29 04:57:14 +00003766 if (f & DOTRIM)
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003767 unquote(xp);
3768 *wbp = addword(xp, *wbp);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003769 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003770 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003771 errpt = ev;
3772 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003773 PUSHIO(aword, cp, strchar);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003774 global_env.iobase = global_env.iop;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003775 while ((xp = blank(f)) && gflg == 0) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003776 global_env.linep = xp;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003777 xp = strsave(xp, areanum);
Eric Andersen8401eea2004-08-04 19:16:54 +00003778 if ((f & DOGLOB) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003779 if (f & DOTRIM)
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003780 unquote(xp);
3781 *wbp = addword(xp, *wbp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003782 } else
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003783 *wbp = glob(xp, *wbp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003784 }
3785 quitenv();
3786 } else
3787 gflg = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003788 return gflg == 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003789}
3790
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003791static char *evalstr(char *cp, int f)
3792{
3793 struct wdblock *wb;
3794
3795 DBGPRINTF6(("EVALSTR: enter, cp=%p, f=%d\n", cp, f));
3796
3797 wb = NULL;
3798 if (expand(cp, &wb, f)) {
3799 if (wb == NULL || wb->w_nword == 0
3800 || (cp = wb->w_words[0]) == NULL
3801 ) {
Denis Vlasenko8e858e22007-03-07 09:35:43 +00003802// TODO: I suspect that
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003803// char *evalstr(char *cp, int f) is actually
3804// const char *evalstr(const char *cp, int f)!
3805 cp = (char*)"";
3806 }
3807 DELETE(wb);
3808 } else
3809 cp = NULL;
3810 return cp;
3811}
3812
3813
Eric Andersenff9eee42001-06-29 04:57:14 +00003814/*
3815 * Blank interpretation and quoting
3816 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003817static char *blank(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003818{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003819 int c, c1;
3820 char *sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003821 int scanequals, foundequals;
3822
Eric Andersen12de6cf2004-08-04 19:19:10 +00003823 DBGPRINTF3(("BLANK: enter, f=%d\n", f));
3824
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003825 sp = global_env.linep;
Eric Andersenff9eee42001-06-29 04:57:14 +00003826 scanequals = f & DOKEY;
3827 foundequals = 0;
3828
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003829 loop:
3830 c = subgetc('"', foundequals);
3831 switch (c) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003832 case 0:
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003833 if (sp == global_env.linep)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003834 return 0;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003835 *global_env.linep++ = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003836 return sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003837
3838 default:
3839 if (f & DOBLANK && any(c, ifs->value))
3840 goto loop;
3841 break;
3842
3843 case '"':
3844 case '\'':
3845 scanequals = 0;
3846 if (INSUB())
3847 break;
3848 for (c1 = c; (c = subgetc(c1, 1)) != c1;) {
3849 if (c == 0)
3850 break;
3851 if (c == '\'' || !any(c, "$`\""))
3852 c |= QUOTE;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003853 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003854 }
3855 c = 0;
3856 }
3857 unget(c);
Matt Kraai69edfec2001-08-06 14:14:18 +00003858 if (!isalpha(c) && c != '_')
Eric Andersenff9eee42001-06-29 04:57:14 +00003859 scanequals = 0;
3860 for (;;) {
3861 c = subgetc('"', foundequals);
3862 if (c == 0 ||
Eric Andersen8401eea2004-08-04 19:16:54 +00003863 f & (DOBLANK && any(c, ifs->value)) ||
3864 (!INSUB() && any(c, "\"'"))) {
3865 scanequals = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003866 unget(c);
3867 if (any(c, "\"'"))
3868 goto loop;
3869 break;
3870 }
3871 if (scanequals) {
3872 if (c == '=') {
3873 foundequals = 1;
Eric Andersen8401eea2004-08-04 19:16:54 +00003874 scanequals = 0;
3875 } else if (!isalnum(c) && c != '_')
Eric Andersenff9eee42001-06-29 04:57:14 +00003876 scanequals = 0;
3877 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003878 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003879 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003880 *global_env.linep++ = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003881 return sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003882}
3883
3884/*
3885 * Get characters, substituting for ` and $
3886 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003887static int subgetc(char ec, int quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00003888{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003889 char c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003890
3891 DBGPRINTF3(("SUBGETC: enter, quoted=%d\n", quoted));
Eric Andersenff9eee42001-06-29 04:57:14 +00003892
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003893 again:
Eric Andersenff9eee42001-06-29 04:57:14 +00003894 c = my_getc(ec);
3895 if (!INSUB() && ec != '\'') {
3896 if (c == '`') {
3897 if (grave(quoted) == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003898 return 0;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003899 global_env.iop->task = XGRAVE;
Eric Andersenff9eee42001-06-29 04:57:14 +00003900 goto again;
3901 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003902 if (c == '$') {
3903 c = dollar(quoted);
3904 if (c == 0) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003905 global_env.iop->task = XDOLL;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003906 goto again;
3907 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003908 }
3909 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003910 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003911}
3912
3913/*
3914 * Prepare to generate the string returned by ${} substitution.
3915 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003916static int dollar(int quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00003917{
3918 int otask;
3919 struct io *oiop;
3920 char *dolp;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003921 char *s, c, *cp = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00003922 struct var *vp;
3923
Eric Andersen12de6cf2004-08-04 19:19:10 +00003924 DBGPRINTF3(("DOLLAR: enter, quoted=%d\n", quoted));
3925
Eric Andersenff9eee42001-06-29 04:57:14 +00003926 c = readc();
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003927 s = global_env.linep;
Eric Andersenff9eee42001-06-29 04:57:14 +00003928 if (c != '{') {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003929 *global_env.linep++ = c;
Matt Kraai69edfec2001-08-06 14:14:18 +00003930 if (isalpha(c) || c == '_') {
Eric Andersen8401eea2004-08-04 19:16:54 +00003931 while ((c = readc()) != 0 && (isalnum(c) || c == '_'))
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003932 if (global_env.linep < elinep)
3933 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003934 unget(c);
3935 }
3936 c = 0;
3937 } else {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003938 oiop = global_env.iop;
3939 otask = global_env.iop->task;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003940
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003941 global_env.iop->task = XOTHER;
Eric Andersen8401eea2004-08-04 19:16:54 +00003942 while ((c = subgetc('"', 0)) != 0 && c != '}' && c != '\n')
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003943 if (global_env.linep < elinep)
3944 *global_env.linep++ = c;
3945 if (oiop == global_env.iop)
3946 global_env.iop->task = otask;
Eric Andersenff9eee42001-06-29 04:57:14 +00003947 if (c != '}') {
3948 err("unclosed ${");
Denis Vlasenko648b44f2008-02-12 06:04:06 +00003949 gflg = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003950 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003951 }
3952 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003953 if (global_env.linep >= elinep) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003954 err("string in ${} too long");
Denis Vlasenko648b44f2008-02-12 06:04:06 +00003955 gflg = 1;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003956 global_env.linep -= 10;
Eric Andersenff9eee42001-06-29 04:57:14 +00003957 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003958 *global_env.linep = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003959 if (*s)
Eric Andersen8401eea2004-08-04 19:16:54 +00003960 for (cp = s + 1; *cp; cp++)
Eric Andersenff9eee42001-06-29 04:57:14 +00003961 if (any(*cp, "=-+?")) {
3962 c = *cp;
3963 *cp++ = 0;
3964 break;
3965 }
3966 if (s[1] == 0 && (*s == '*' || *s == '@')) {
3967 if (dolc > 1) {
3968 /* currently this does not distinguish $* and $@ */
3969 /* should check dollar */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003970 global_env.linep = s;
Eric Andersen8401eea2004-08-04 19:16:54 +00003971 PUSHIO(awordlist, dolv + 1, dolchar);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003972 return 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00003973 } else { /* trap the nasty ${=} */
Eric Andersenff9eee42001-06-29 04:57:14 +00003974 s[0] = '1';
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003975 s[1] = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00003976 }
3977 }
3978 vp = lookup(s);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003979 dolp = vp->value;
3980 if (dolp == null) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003981 switch (c) {
3982 case '=':
3983 if (isdigit(*s)) {
3984 err("cannot use ${...=...} with $n");
Denis Vlasenko648b44f2008-02-12 06:04:06 +00003985 gflg = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003986 break;
3987 }
3988 setval(vp, cp);
3989 dolp = vp->value;
3990 break;
3991
3992 case '-':
3993 dolp = strsave(cp, areanum);
3994 break;
3995
3996 case '?':
3997 if (*cp == 0) {
3998 prs("missing value for ");
3999 err(s);
4000 } else
4001 err(cp);
Denis Vlasenko648b44f2008-02-12 06:04:06 +00004002 gflg = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004003 break;
4004 }
4005 } else if (c == '+')
4006 dolp = strsave(cp, areanum);
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00004007 if (FLAG['u'] && dolp == null) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004008 prs("unset variable: ");
4009 err(s);
Denis Vlasenko648b44f2008-02-12 06:04:06 +00004010 gflg = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004011 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004012 global_env.linep = s;
Eric Andersenff9eee42001-06-29 04:57:14 +00004013 PUSHIO(aword, dolp, quoted ? qstrchar : strchar);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004014 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004015}
4016
4017/*
4018 * Run the command in `...` and read its output.
4019 */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004020
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004021static int grave(int quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00004022{
Denis Vlasenko55f30b02007-03-24 22:42:29 +00004023 /* moved to G: static char child_cmd[LINELIM]; */
4024
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004025 const char *cp;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004026 int i;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004027 int j;
Eric Andersenff9eee42001-06-29 04:57:14 +00004028 int pf[2];
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004029 const char *src;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004030 char *dest;
4031 int count;
4032 int ignore;
4033 int ignore_once;
4034 char *argument_list[4];
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004035 struct wdblock *wb = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004036
4037#if __GNUC__
4038 /* Avoid longjmp clobbering */
4039 (void) &cp;
4040#endif
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004041
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004042 for (cp = global_env.iop->argp->aword; *cp != '`'; cp++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004043 if (*cp == 0) {
4044 err("no closing `");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004045 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004046 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004047 }
Eric Andersen737f5fb2003-03-14 16:05:59 +00004048
4049 /* string copy with dollar expansion */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004050 src = global_env.iop->argp->aword;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004051 dest = child_cmd;
4052 count = 0;
4053 ignore = 0;
4054 ignore_once = 0;
4055 while ((*src != '`') && (count < LINELIM)) {
4056 if (*src == '\'')
4057 ignore = !ignore;
4058 if (*src == '\\')
4059 ignore_once = 1;
4060 if (*src == '$' && !ignore && !ignore_once) {
4061 struct var *vp;
Denis Vlasenkoab801872007-12-02 08:35:37 +00004062 /* moved to G to reduce stack usage
Eric Andersen737f5fb2003-03-14 16:05:59 +00004063 char var_name[LINELIM];
4064 char alt_value[LINELIM];
Denis Vlasenkoab801872007-12-02 08:35:37 +00004065 */
4066#define var_name (G.grave__var_name)
4067#define alt_value (G.grave__alt_value)
Eric Andersen737f5fb2003-03-14 16:05:59 +00004068 int var_index = 0;
4069 int alt_index = 0;
4070 char operator = 0;
4071 int braces = 0;
4072 char *value;
4073
4074 src++;
4075 if (*src == '{') {
4076 braces = 1;
4077 src++;
4078 }
4079
4080 var_name[var_index++] = *src++;
Paul Fox54690dc2005-07-20 18:33:12 +00004081 while (isalnum(*src) || *src=='_')
Eric Andersen737f5fb2003-03-14 16:05:59 +00004082 var_name[var_index++] = *src++;
4083 var_name[var_index] = 0;
4084
4085 if (braces) {
4086 switch (*src) {
4087 case '}':
4088 break;
4089 case '-':
4090 case '=':
4091 case '+':
4092 case '?':
Eric Andersen8401eea2004-08-04 19:16:54 +00004093 operator = * src;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004094 break;
4095 default:
4096 err("unclosed ${\n");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004097 return 0;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004098 }
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004099 if (operator) {
Eric Andersen737f5fb2003-03-14 16:05:59 +00004100 src++;
4101 while (*src && (*src != '}')) {
4102 alt_value[alt_index++] = *src++;
4103 }
4104 alt_value[alt_index] = 0;
4105 if (*src != '}') {
4106 err("unclosed ${\n");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004107 return 0;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004108 }
4109 }
4110 src++;
4111 }
4112
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004113 if (isalpha(*var_name)) {
4114 /* let subshell handle it instead */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004115
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004116 char *namep = var_name;
4117
4118 *dest++ = '$';
4119 if (braces)
4120 *dest++ = '{';
4121 while (*namep)
4122 *dest++ = *namep++;
4123 if (operator) {
4124 char *altp = alt_value;
4125 *dest++ = operator;
4126 while (*altp)
4127 *dest++ = *altp++;
4128 }
4129 if (braces)
4130 *dest++ = '}';
4131
4132 wb = addword(lookup(var_name)->name, wb);
4133 } else {
4134 /* expand */
4135
4136 vp = lookup(var_name);
4137 if (vp->value != null)
4138 value = (operator == '+') ?
4139 alt_value : vp->value;
4140 else if (operator == '?') {
4141 err(alt_value);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004142 return 0;
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004143 } else if (alt_index && (operator != '+')) {
4144 value = alt_value;
4145 if (operator == '=')
4146 setval(vp, value);
4147 } else
4148 continue;
4149
4150 while (*value && (count < LINELIM)) {
4151 *dest++ = *value++;
4152 count++;
4153 }
Eric Andersen737f5fb2003-03-14 16:05:59 +00004154 }
Denis Vlasenkoab801872007-12-02 08:35:37 +00004155#undef var_name
4156#undef alt_value
Eric Andersen737f5fb2003-03-14 16:05:59 +00004157 } else {
4158 *dest++ = *src++;
4159 count++;
4160 ignore_once = 0;
4161 }
4162 }
4163 *dest = '\0';
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004164
Eric Andersenff9eee42001-06-29 04:57:14 +00004165 if (openpipe(pf) < 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004166 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004167
Denis Vlasenko509697f2008-03-02 12:49:39 +00004168 while ((i = vfork()) == -1 && errno == EAGAIN)
4169 continue;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004170
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004171 DBGPRINTF3(("GRAVE: i is %p\n", io));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004172
Eric Andersen737f5fb2003-03-14 16:05:59 +00004173 if (i < 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004174 closepipe(pf);
Eric Andersen8401eea2004-08-04 19:16:54 +00004175 err((char *) bb_msg_memory_exhausted);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004176 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004177 }
4178 if (i != 0) {
Denis Vlasenkofb0eba72008-01-02 19:55:04 +00004179 waitpid(i, NULL, 0); // safe_waitpid?
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004180 global_env.iop->argp->aword = ++cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004181 close(pf[1]);
Eric Andersen8401eea2004-08-04 19:16:54 +00004182 PUSHIO(afile, remap(pf[0]),
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004183 (int (*)(struct ioarg *)) ((quoted) ? qgravechar : gravechar));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004184 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004185 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004186 /* allow trapped signals */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004187 /* XXX - Maybe this signal stuff should go as well? */
Eric Andersen8401eea2004-08-04 19:16:54 +00004188 for (j = 0; j <= _NSIG; j++)
Eric Andersen737f5fb2003-03-14 16:05:59 +00004189 if (ourtrap[j] && signal(j, SIG_IGN) != SIG_IGN)
4190 signal(j, SIG_DFL);
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004191
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00004192 /* Testcase where below checks are needed:
4193 * close stdout & run this script:
4194 * files=`ls`
4195 * echo "$files" >zz
4196 */
4197 xmove_fd(pf[1], 1);
Denis Vlasenko847fa772008-01-28 22:45:43 +00004198 if (pf[0] != 1)
4199 close(pf[0]);
Eric Andersen737f5fb2003-03-14 16:05:59 +00004200
Eric Andersen8401eea2004-08-04 19:16:54 +00004201 argument_list[0] = (char *) DEFAULT_SHELL;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004202 argument_list[1] = (char *) "-c";
Eric Andersen737f5fb2003-03-14 16:05:59 +00004203 argument_list[2] = child_cmd;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004204 argument_list[3] = NULL;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004205
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004206 cp = rexecve(argument_list[0], argument_list, makenv(1, wb));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004207 prs(argument_list[0]);
4208 prs(": ");
4209 err(cp);
Eric Andersen737f5fb2003-03-14 16:05:59 +00004210 _exit(1);
Eric Andersenff9eee42001-06-29 04:57:14 +00004211}
4212
Eric Andersen737f5fb2003-03-14 16:05:59 +00004213
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004214static char *unquote(char *as)
Eric Andersenff9eee42001-06-29 04:57:14 +00004215{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004216 char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00004217
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004218 s = as;
4219 if (s != NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00004220 while (*s)
4221 *s++ &= ~QUOTE;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004222 return as;
Eric Andersenff9eee42001-06-29 04:57:14 +00004223}
4224
4225/* -------- glob.c -------- */
4226
4227/*
4228 * glob
4229 */
4230
4231#define scopy(x) strsave((x), areanum)
4232#define BLKSIZ 512
4233#define NDENT ((BLKSIZ+sizeof(struct dirent)-1)/sizeof(struct dirent))
4234
Eric Andersen8401eea2004-08-04 19:16:54 +00004235static struct wdblock *cl, *nl;
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00004236static const char spcl[] ALIGN1= "[?*";
Eric Andersenff9eee42001-06-29 04:57:14 +00004237
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004238static struct wdblock *glob(char *cp, struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004239{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004240 int i;
4241 char *pp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004242
4243 if (cp == 0)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004244 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004245 i = 0;
4246 for (pp = cp; *pp; pp++)
4247 if (any(*pp, spcl))
4248 i++;
4249 else if (!any(*pp & ~QUOTE, spcl))
4250 *pp &= ~QUOTE;
4251 if (i != 0) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004252 for (cl = addword(scopy(cp), NULL); anyspcl(cl); cl = nl) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004253 nl = newword(cl->w_nword * 2);
4254 for (i = 0; i < cl->w_nword; i++) { /* for each argument */
Eric Andersenff9eee42001-06-29 04:57:14 +00004255 for (pp = cl->w_words[i]; *pp; pp++)
4256 if (any(*pp, spcl)) {
4257 globname(cl->w_words[i], pp);
4258 break;
4259 }
4260 if (*pp == '\0')
4261 nl = addword(scopy(cl->w_words[i]), nl);
4262 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004263 for (i = 0; i < cl->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004264 DELETE(cl->w_words[i]);
4265 DELETE(cl);
4266 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004267 if (cl->w_nword) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004268 for (i = 0; i < cl->w_nword; i++)
Denis Vlasenkofb290382008-03-02 12:51:26 +00004269 unquote(cl->w_words[i]);
4270 qsort_string_vector(cl->w_words, cl->w_nword);
4271 for (i = 0; i < cl->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004272 wb = addword(cl->w_words[i], wb);
4273 DELETE(cl);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004274 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004275 }
4276 }
4277 wb = addword(unquote(cp), wb);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004278 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004279}
4280
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004281static void globname(char *we, char *pp)
Eric Andersenff9eee42001-06-29 04:57:14 +00004282{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004283 char *np, *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004284 char *name, *gp, *dp;
4285 int k;
4286 DIR *dirp;
4287 struct dirent *de;
Eric Andersen8401eea2004-08-04 19:16:54 +00004288 char dname[NAME_MAX + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00004289 struct stat dbuf;
4290
4291 for (np = we; np != pp; pp--)
4292 if (pp[-1] == '/')
4293 break;
Denis Vlasenkofb290382008-03-02 12:51:26 +00004294 dp = cp = get_space((int) (pp - np) + 3);
4295 while (np < pp)
Eric Andersenff9eee42001-06-29 04:57:14 +00004296 *cp++ = *np++;
4297 *cp++ = '.';
4298 *cp = '\0';
Denis Vlasenkofb290382008-03-02 12:51:26 +00004299 gp = cp = get_space(strlen(pp) + 1);
4300 while (*np && *np != '/')
Eric Andersenff9eee42001-06-29 04:57:14 +00004301 *cp++ = *np++;
4302 *cp = '\0';
4303 dirp = opendir(dp);
4304 if (dirp == 0) {
4305 DELETE(dp);
4306 DELETE(gp);
4307 return;
4308 }
4309 dname[NAME_MAX] = '\0';
Eric Andersen8401eea2004-08-04 19:16:54 +00004310 while ((de = readdir(dirp)) != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004311 /* XXX Hmmm... What this could be? (abial) */
4312 /*
Eric Andersen8401eea2004-08-04 19:16:54 +00004313 if (ent[j].d_ino == 0)
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004314 continue;
Eric Andersen8401eea2004-08-04 19:16:54 +00004315 */
Eric Andersenff9eee42001-06-29 04:57:14 +00004316 strncpy(dname, de->d_name, NAME_MAX);
Eric Andersen8401eea2004-08-04 19:16:54 +00004317 if (dname[0] == '.')
4318 if (*gp != '.')
4319 continue;
4320 for (k = 0; k < NAME_MAX; k++)
4321 if (any(dname[k], spcl))
4322 dname[k] |= QUOTE;
4323 if (gmatch(dname, gp)) {
4324 name = generate(we, pp, dname, np);
4325 if (*np && !anys(np, spcl)) {
4326 if (stat(name, &dbuf)) {
4327 DELETE(name);
Eric Andersenff9eee42001-06-29 04:57:14 +00004328 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00004329 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004330 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004331 nl = addword(name, nl);
4332 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004333 }
4334 closedir(dirp);
4335 DELETE(dp);
4336 DELETE(gp);
4337}
4338
4339/*
4340 * generate a pathname as below.
4341 * start..end1 / middle end
4342 * the slashes come for free
4343 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004344static char *generate(char *start1, char *end1, char *middle, char *end)
Eric Andersenff9eee42001-06-29 04:57:14 +00004345{
4346 char *p;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004347 char *op, *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004348
Denis Vlasenko509697f2008-03-02 12:49:39 +00004349 p = op = get_space((int)(end1 - start1) + strlen(middle) + strlen(end) + 2);
4350 xp = start1;
4351 while (xp != end1)
Eric Andersenff9eee42001-06-29 04:57:14 +00004352 *op++ = *xp++;
Denis Vlasenko509697f2008-03-02 12:49:39 +00004353 xp = middle;
4354 while (*xp != '\0')
4355 *op++ = *xp++;
4356 strcpy(op, end);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004357 return p;
Eric Andersenff9eee42001-06-29 04:57:14 +00004358}
4359
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004360static int anyspcl(struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004361{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004362 int i;
4363 char **wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004364
4365 wd = wb->w_words;
Eric Andersen8401eea2004-08-04 19:16:54 +00004366 for (i = 0; i < wb->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004367 if (anys(spcl, *wd++))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004368 return 1;
4369 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004370}
4371
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004372
Eric Andersenff9eee42001-06-29 04:57:14 +00004373/* -------- word.c -------- */
4374
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004375static struct wdblock *newword(int nw)
Eric Andersenff9eee42001-06-29 04:57:14 +00004376{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004377 struct wdblock *wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004378
Denis Vlasenko509697f2008-03-02 12:49:39 +00004379 wb = get_space(sizeof(*wb) + nw * sizeof(char *));
Eric Andersenff9eee42001-06-29 04:57:14 +00004380 wb->w_bsize = nw;
4381 wb->w_nword = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004382 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004383}
4384
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004385static struct wdblock *addword(char *wd, struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004386{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004387 struct wdblock *wb2;
4388 int nw;
Eric Andersenff9eee42001-06-29 04:57:14 +00004389
4390 if (wb == NULL)
4391 wb = newword(NSTART);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004392 nw = wb->w_nword;
4393 if (nw >= wb->w_bsize) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004394 wb2 = newword(nw * 2);
Eric Andersen8401eea2004-08-04 19:16:54 +00004395 memcpy((char *) wb2->w_words, (char *) wb->w_words,
4396 nw * sizeof(char *));
Eric Andersenff9eee42001-06-29 04:57:14 +00004397 wb2->w_nword = nw;
4398 DELETE(wb);
4399 wb = wb2;
4400 }
4401 wb->w_words[wb->w_nword++] = wd;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004402 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004403}
Eric Andersen8401eea2004-08-04 19:16:54 +00004404
Denis Vlasenkoe4712752007-04-14 15:08:41 +00004405static char **getwords(struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004406{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004407 char **wd;
4408 int nb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004409
4410 if (wb == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004411 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004412 if (wb->w_nword == 0) {
4413 DELETE(wb);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004414 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004415 }
Denis Vlasenko509697f2008-03-02 12:49:39 +00004416 nb = sizeof(*wd) * wb->w_nword;
4417 wd = get_space(nb);
Denis Vlasenkofb290382008-03-02 12:51:26 +00004418 memcpy(wd, wb->w_words, nb);
4419 DELETE(wb); /* perhaps should done by caller */
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004420 return wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004421}
4422
Eric Andersenff9eee42001-06-29 04:57:14 +00004423
4424/* -------- io.c -------- */
4425
4426/*
4427 * shell IO
4428 */
4429
Eric Andersen8401eea2004-08-04 19:16:54 +00004430static int my_getc(int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00004431{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004432 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004433
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004434 if (global_env.linep > elinep) {
Denis Vlasenko509697f2008-03-02 12:49:39 +00004435 while ((c = readc()) != '\n' && c)
4436 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00004437 err("input line too long");
Denis Vlasenko648b44f2008-02-12 06:04:06 +00004438 gflg = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004439 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004440 }
4441 c = readc();
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004442 if ((ec != '\'') && (ec != '`') && (global_env.iop->task != XGRAVE)) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004443 if (c == '\\') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004444 c = readc();
4445 if (c == '\n' && ec != '\"')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004446 return my_getc(ec);
Eric Andersenff9eee42001-06-29 04:57:14 +00004447 c |= QUOTE;
4448 }
4449 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004450 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004451}
4452
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004453static void unget(int c)
Eric Andersenff9eee42001-06-29 04:57:14 +00004454{
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004455 if (global_env.iop >= global_env.iobase)
4456 global_env.iop->peekc = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004457}
4458
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004459static int eofc(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00004460{
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004461 return global_env.iop < global_env.iobase || (global_env.iop->peekc == 0 && global_env.iop->prev == 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004462}
4463
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004464static int readc(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00004465{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004466 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004467
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004468 RCPRINTF(("READC: global_env.iop %p, global_env.iobase %p\n", global_env.iop, global_env.iobase));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004469
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004470 for (; global_env.iop >= global_env.iobase; global_env.iop--) {
4471 RCPRINTF(("READC: global_env.iop %p, peekc 0x%x\n", global_env.iop, global_env.iop->peekc));
4472 c = global_env.iop->peekc;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004473 if (c != '\0') {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004474 global_env.iop->peekc = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004475 return c;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004476 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004477 if (global_env.iop->prev != 0) {
4478 c = (*global_env.iop->iofn)(global_env.iop->argp, global_env.iop);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004479 if (c != '\0') {
4480 if (c == -1) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004481 global_env.iop++;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004482 continue;
Eric Andersen8401eea2004-08-04 19:16:54 +00004483 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004484 if (global_env.iop == iostack)
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004485 ioecho(c);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004486 global_env.iop->prev = c;
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00004487 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004488 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004489 if (global_env.iop->task == XIO && global_env.iop->prev != '\n') {
4490 global_env.iop->prev = 0;
4491 if (global_env.iop == iostack)
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004492 ioecho('\n');
4493 return '\n';
Eric Andersen8401eea2004-08-04 19:16:54 +00004494 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004495 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004496 if (global_env.iop->task == XIO) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004497 if (multiline) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004498 global_env.iop->prev = 0;
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00004499 return 0;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004500 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004501 if (interactive && global_env.iop == iostack + 1) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004502#if ENABLE_FEATURE_EDITING
4503 current_prompt = prompt->value;
4504#else
4505 prs(prompt->value);
4506#endif
4507 }
4508 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004509 } /* FOR */
4510
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004511 if (global_env.iop >= iostack) {
4512 RCPRINTF(("READC: return 0, global_env.iop %p\n", global_env.iop));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004513 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004514 }
4515
4516 DBGPRINTF(("READC: leave()...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00004517 leave();
4518 /* NOTREACHED */
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004519 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004520}
4521
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004522static void ioecho(char c)
Eric Andersenff9eee42001-06-29 04:57:14 +00004523{
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00004524 if (FLAG['v'])
Eric Andersenff9eee42001-06-29 04:57:14 +00004525 write(2, &c, sizeof c);
4526}
4527
Eric Andersen8401eea2004-08-04 19:16:54 +00004528static void pushio(struct ioarg *argp, int (*fn) (struct ioarg *))
Eric Andersenff9eee42001-06-29 04:57:14 +00004529{
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004530 DBGPRINTF(("PUSHIO: argp %p, argp->afid 0x%x, global_env.iop %p\n", argp,
4531 argp->afid, global_env.iop));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004532
4533 /* Set env ptr for io source to next array spot and check for array overflow */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004534 if (++global_env.iop >= &iostack[NPUSH]) {
4535 global_env.iop--;
Eric Andersenff9eee42001-06-29 04:57:14 +00004536 err("Shell input nested too deeply");
Denis Vlasenko648b44f2008-02-12 06:04:06 +00004537 gflg = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004538 return;
4539 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004540
4541 /* We did not overflow the NPUSH array spots so setup data structs */
4542
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004543 global_env.iop->iofn = (int (*)(struct ioarg *, struct io *)) fn; /* Store data source func ptr */
Eric Andersenff9eee42001-06-29 04:57:14 +00004544
4545 if (argp->afid != AFID_NOBUF)
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004546 global_env.iop->argp = argp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004547 else {
Eric Andersen12de6cf2004-08-04 19:19:10 +00004548
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004549 global_env.iop->argp = ioargstack + (global_env.iop - iostack); /* MAL - index into stack */
4550 *global_env.iop->argp = *argp; /* copy data from temp area into stack spot */
Eric Andersen12de6cf2004-08-04 19:19:10 +00004551
4552 /* MAL - mainbuf is for 1st data source (command line?) and all nested use a single shared buffer? */
4553
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004554 if (global_env.iop == &iostack[0])
4555 global_env.iop->argp->afbuf = &mainbuf;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004556 else
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004557 global_env.iop->argp->afbuf = &sharedbuf;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004558
4559 /* MAL - if not a termimal AND (commandline OR readable file) then give it a buffer id? */
4560 /* This line appears to be active when running scripts from command line */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004561 if ((isatty(global_env.iop->argp->afile) == 0)
4562 && (global_env.iop == &iostack[0]
4563 || lseek(global_env.iop->argp->afile, 0L, SEEK_CUR) != -1)) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00004564 if (++bufid == AFID_NOBUF) /* counter rollover check, AFID_NOBUF = 11111111 */
4565 bufid = AFID_ID; /* AFID_ID = 0 */
4566
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004567 global_env.iop->argp->afid = bufid; /* assign buffer id */
Eric Andersen8401eea2004-08-04 19:16:54 +00004568 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004569
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004570 DBGPRINTF(("PUSHIO: iostack %p, global_env.iop %p, afbuf %p\n",
4571 iostack, global_env.iop, global_env.iop->argp->afbuf));
4572 DBGPRINTF(("PUSHIO: mbuf %p, sbuf %p, bid %d, global_env.iop %p\n",
4573 &mainbuf, &sharedbuf, bufid, global_env.iop));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004574
Eric Andersenff9eee42001-06-29 04:57:14 +00004575 }
4576
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004577 global_env.iop->prev = ~'\n';
4578 global_env.iop->peekc = 0;
4579 global_env.iop->xchar = 0;
4580 global_env.iop->nlcount = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004581
Eric Andersenff9eee42001-06-29 04:57:14 +00004582 if (fn == filechar || fn == linechar)
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004583 global_env.iop->task = XIO;
Eric Andersen8401eea2004-08-04 19:16:54 +00004584 else if (fn == (int (*)(struct ioarg *)) gravechar
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00004585 || fn == (int (*)(struct ioarg *)) qgravechar)
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004586 global_env.iop->task = XGRAVE;
Eric Andersenff9eee42001-06-29 04:57:14 +00004587 else
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004588 global_env.iop->task = XOTHER;
Eric Andersenff9eee42001-06-29 04:57:14 +00004589}
4590
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004591static struct io *setbase(struct io *ip)
Eric Andersenff9eee42001-06-29 04:57:14 +00004592{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004593 struct io *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004594
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004595 xp = global_env.iobase;
4596 global_env.iobase = ip;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004597 return xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004598}
4599
4600/*
4601 * Input generating functions
4602 */
4603
4604/*
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00004605 * Produce the characters of a string, then a newline, then NUL.
Eric Andersenff9eee42001-06-29 04:57:14 +00004606 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004607static int nlchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004608{
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00004609 char c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004610
4611 if (ap->aword == NULL)
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00004612 return '\0';
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004613 c = *ap->aword++;
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00004614 if (c == '\0') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004615 ap->aword = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004616 return '\n';
Eric Andersenff9eee42001-06-29 04:57:14 +00004617 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004618 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004619}
4620
4621/*
4622 * Given a list of words, produce the characters
4623 * in them, with a space after each word.
4624 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004625static int wdchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004626{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004627 char c;
4628 char **wl;
Eric Andersenff9eee42001-06-29 04:57:14 +00004629
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004630 wl = ap->awordlist;
4631 if (wl == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004632 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004633 if (*wl != NULL) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004634 c = *(*wl)++;
4635 if (c != 0)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004636 return c & 0177;
Eric Andersenff9eee42001-06-29 04:57:14 +00004637 ap->awordlist++;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004638 return ' ';
Eric Andersenff9eee42001-06-29 04:57:14 +00004639 }
4640 ap->awordlist = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004641 return '\n';
Eric Andersenff9eee42001-06-29 04:57:14 +00004642}
4643
4644/*
4645 * Return the characters of a list of words,
4646 * producing a space between them.
4647 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004648static int dolchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004649{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004650 char *wp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004651
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004652 wp = *ap->awordlist++;
4653 if (wp != NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004654 PUSHIO(aword, wp, *ap->awordlist == NULL ? strchar : xxchar);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004655 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004656 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004657 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004658}
4659
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004660static int xxchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004661{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004662 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004663
4664 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004665 return 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004666 c = *ap->aword++;
4667 if (c == '\0') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004668 ap->aword = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004669 return ' ';
Eric Andersenff9eee42001-06-29 04:57:14 +00004670 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004671 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004672}
4673
4674/*
4675 * Produce the characters from a single word (string).
4676 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004677static int strchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004678{
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004679 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004680 return 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004681 return *ap->aword++;
Eric Andersenff9eee42001-06-29 04:57:14 +00004682}
4683
4684/*
4685 * Produce quoted characters from a single word (string).
4686 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004687static int qstrchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004688{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004689 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004690
Denis Vlasenkob2abef32007-01-01 18:18:04 +00004691 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004692 return 0;
Denis Vlasenkob2abef32007-01-01 18:18:04 +00004693 c = *ap->aword++;
4694 if (c)
4695 c |= QUOTE;
4696 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004697}
4698
4699/*
4700 * Return the characters from a file.
4701 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004702static int filechar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004703{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004704 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004705 char c;
4706 struct iobuf *bp = ap->afbuf;
4707
4708 if (ap->afid != AFID_NOBUF) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004709 i = (ap->afid != bp->id);
4710 if (i || bp->bufp == bp->ebufp) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004711 if (i)
Denis Vlasenkoea620772006-10-14 02:23:43 +00004712 lseek(ap->afile, ap->afpos, SEEK_SET);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004713
Denis Vlasenkoe376d452008-02-20 22:23:24 +00004714 i = nonblock_safe_read(ap->afile, bp->buf, sizeof(bp->buf));
Eric Andersen8401eea2004-08-04 19:16:54 +00004715 if (i <= 0) {
4716 closef(ap->afile);
4717 return 0;
4718 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004719
Eric Andersen8401eea2004-08-04 19:16:54 +00004720 bp->id = ap->afid;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004721 bp->bufp = bp->buf;
4722 bp->ebufp = bp->bufp + i;
Eric Andersen8401eea2004-08-04 19:16:54 +00004723 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004724
Eric Andersen8401eea2004-08-04 19:16:54 +00004725 ap->afpos++;
4726 return *bp->bufp++ & 0177;
Eric Andersenff9eee42001-06-29 04:57:14 +00004727 }
Denis Vlasenko38f63192007-01-22 09:03:07 +00004728#if ENABLE_FEATURE_EDITING
Eric Andersen737f5fb2003-03-14 16:05:59 +00004729 if (interactive && isatty(ap->afile)) {
Denis Vlasenko55f30b02007-03-24 22:42:29 +00004730 /* moved to G: static char filechar_cmdbuf[BUFSIZ]; */
Eric Andersen8401eea2004-08-04 19:16:54 +00004731 static int position = 0, size = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004732
Eric Andersen8401eea2004-08-04 19:16:54 +00004733 while (size == 0 || position >= size) {
Denis Vlasenko6e602c42008-02-02 18:50:50 +00004734 size = read_line_input(current_prompt, filechar_cmdbuf, BUFSIZ, line_input_state);
4735 if (size < 0) /* Error/EOF */
4736 exit(0);
Eric Andersen8401eea2004-08-04 19:16:54 +00004737 position = 0;
Denis Vlasenko6e602c42008-02-02 18:50:50 +00004738 /* if Ctrl-C, size == 0 and loop will repeat */
Eric Andersen8401eea2004-08-04 19:16:54 +00004739 }
Denis Vlasenko55f30b02007-03-24 22:42:29 +00004740 c = filechar_cmdbuf[position];
Eric Andersen8401eea2004-08-04 19:16:54 +00004741 position++;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004742 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004743 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004744#endif
Denis Vlasenkoe376d452008-02-20 22:23:24 +00004745 i = nonblock_safe_read(ap->afile, &c, sizeof(c));
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004746 return i == sizeof(c) ? (c & 0x7f) : (closef(ap->afile), 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004747}
4748
4749/*
4750 * Return the characters from a here temp file.
4751 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004752static int herechar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004753{
4754 char c;
4755
Denis Vlasenkoe376d452008-02-20 22:23:24 +00004756 if (nonblock_safe_read(ap->afile, &c, sizeof(c)) != sizeof(c)) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004757 close(ap->afile);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004758 c = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00004759 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004760 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004761}
4762
4763/*
4764 * Return the characters produced by a process (`...`).
4765 * Quote them if required, and remove any trailing newline characters.
4766 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004767static int gravechar(struct ioarg *ap, struct io *iop)
Eric Andersenff9eee42001-06-29 04:57:14 +00004768{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004769 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004770
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004771 c = qgravechar(ap, iop) & ~QUOTE;
4772 if (c == '\n')
Eric Andersenff9eee42001-06-29 04:57:14 +00004773 c = ' ';
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004774 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004775}
4776
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004777static int qgravechar(struct ioarg *ap, struct io *iop)
Eric Andersenff9eee42001-06-29 04:57:14 +00004778{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004779 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004780
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004781 DBGPRINTF3(("QGRAVECHAR: enter, ap=%p, iop=%p\n", ap, iop));
Eric Andersenff9eee42001-06-29 04:57:14 +00004782
4783 if (iop->xchar) {
4784 if (iop->nlcount) {
4785 iop->nlcount--;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004786 return '\n' | QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00004787 }
4788 c = iop->xchar;
4789 iop->xchar = 0;
4790 } else if ((c = filechar(ap)) == '\n') {
4791 iop->nlcount = 1;
4792 while ((c = filechar(ap)) == '\n')
4793 iop->nlcount++;
4794 iop->xchar = c;
4795 if (c == 0)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004796 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004797 iop->nlcount--;
4798 c = '\n';
4799 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004800 return c != 0 ? c | QUOTE : 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004801}
4802
4803/*
4804 * Return a single command (usually the first line) from a file.
4805 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004806static int linechar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004807{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004808 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004809
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004810 c = filechar(ap);
4811 if (c == '\n') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004812 if (!multiline) {
4813 closef(ap->afile);
Eric Andersen8401eea2004-08-04 19:16:54 +00004814 ap->afile = -1; /* illegal value */
Eric Andersenff9eee42001-06-29 04:57:14 +00004815 }
4816 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004817 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004818}
4819
Eric Andersenff9eee42001-06-29 04:57:14 +00004820/*
4821 * remap fd into Shell's fd space
4822 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004823static int remap(int fd)
Eric Andersenff9eee42001-06-29 04:57:14 +00004824{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004825 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004826 int map[NOFILE];
Eric Andersen12de6cf2004-08-04 19:19:10 +00004827 int newfd;
4828
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004829 DBGPRINTF(("REMAP: fd=%d, global_env.iofd=%d\n", fd, global_env.iofd));
Eric Andersenff9eee42001-06-29 04:57:14 +00004830
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004831 if (fd < global_env.iofd) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004832 for (i = 0; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004833 map[i] = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004834
Eric Andersenff9eee42001-06-29 04:57:14 +00004835 do {
4836 map[fd] = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004837 newfd = dup(fd);
4838 fd = newfd;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004839 } while (fd >= 0 && fd < global_env.iofd);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004840
Eric Andersen8401eea2004-08-04 19:16:54 +00004841 for (i = 0; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004842 if (map[i])
4843 close(i);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004844
Eric Andersenff9eee42001-06-29 04:57:14 +00004845 if (fd < 0)
4846 err("too many files open in shell");
4847 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004848
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004849 return fd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004850}
4851
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004852static int openpipe(int *pv)
Eric Andersenff9eee42001-06-29 04:57:14 +00004853{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004854 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004855
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004856 i = pipe(pv);
4857 if (i < 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00004858 err("can't create pipe - try again");
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004859 return i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004860}
4861
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004862static void closepipe(int *pv)
Eric Andersenff9eee42001-06-29 04:57:14 +00004863{
4864 if (pv != NULL) {
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00004865 close(pv[0]);
4866 close(pv[1]);
Eric Andersenff9eee42001-06-29 04:57:14 +00004867 }
4868}
4869
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004870
Eric Andersenff9eee42001-06-29 04:57:14 +00004871/* -------- here.c -------- */
4872
4873/*
4874 * here documents
4875 */
4876
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004877static void markhere(char *s, struct ioword *iop)
Eric Andersenff9eee42001-06-29 04:57:14 +00004878{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004879 struct here *h, *lh;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004880
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004881 DBGPRINTF7(("MARKHERE: enter, s=%p\n", s));
Eric Andersenff9eee42001-06-29 04:57:14 +00004882
Denis Vlasenko509697f2008-03-02 12:49:39 +00004883 h = get_space(sizeof(struct here));
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004884 if (h == NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00004885 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004886
Eric Andersenff9eee42001-06-29 04:57:14 +00004887 h->h_tag = evalstr(s, DOSUB);
4888 if (h->h_tag == 0)
4889 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004890
Eric Andersenff9eee42001-06-29 04:57:14 +00004891 h->h_iop = iop;
4892 iop->io_name = 0;
4893 h->h_next = NULL;
4894 if (inhere == 0)
4895 inhere = h;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004896 else {
4897 for (lh = inhere; lh != NULL; lh = lh->h_next) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004898 if (lh->h_next == 0) {
4899 lh->h_next = h;
4900 break;
4901 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004902 }
4903 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004904 iop->io_flag |= IOHERE | IOXHERE;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004905 for (s = h->h_tag; *s; s++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004906 if (*s & QUOTE) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004907 iop->io_flag &= ~IOXHERE;
4908 *s &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00004909 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004910 }
Denis Vlasenko648b44f2008-02-12 06:04:06 +00004911 h->h_dosub = ((iop->io_flag & IOXHERE) ? '\0' : '\'');
Eric Andersenff9eee42001-06-29 04:57:14 +00004912}
4913
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004914static void gethere(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00004915{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004916 struct here *h, *hp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004917
4918 DBGPRINTF7(("GETHERE: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00004919
4920 /* Scan here files first leaving inhere list in place */
4921 for (hp = h = inhere; h != NULL; hp = h, h = h->h_next)
Denis Vlasenko648b44f2008-02-12 06:04:06 +00004922 readhere(&h->h_iop->io_name, h->h_tag, h->h_dosub /* NUL or ' */);
Eric Andersenff9eee42001-06-29 04:57:14 +00004923
4924 /* Make inhere list active - keep list intact for scraphere */
4925 if (hp != NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004926 hp->h_next = acthere;
4927 acthere = inhere;
4928 inhere = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004929 }
4930}
4931
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004932static void readhere(char **name, char *s, int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00004933{
4934 int tf;
4935 char tname[30] = ".msh_XXXXXX";
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004936 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004937 jmp_buf ev;
Eric Andersen8401eea2004-08-04 19:16:54 +00004938 char myline[LINELIM + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00004939 char *thenext;
4940
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004941 DBGPRINTF7(("READHERE: enter, name=%p, s=%p\n", name, s));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004942
Eric Andersenff9eee42001-06-29 04:57:14 +00004943 tf = mkstemp(tname);
4944 if (tf < 0)
4945 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004946
Eric Andersenff9eee42001-06-29 04:57:14 +00004947 *name = strsave(tname, areanum);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004948 errpt = ev;
4949 if (newenv(setjmp(errpt)) != 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00004950 unlink(tname);
4951 else {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004952 pushio(global_env.iop->argp, (int (*)(struct ioarg *)) global_env.iop->iofn);
4953 global_env.iobase = global_env.iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00004954 for (;;) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004955 if (interactive && global_env.iop <= iostack) {
Denis Vlasenko38f63192007-01-22 09:03:07 +00004956#if ENABLE_FEATURE_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00004957 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00004958#else
Eric Andersen8401eea2004-08-04 19:16:54 +00004959 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00004960#endif
4961 }
4962 thenext = myline;
4963 while ((c = my_getc(ec)) != '\n' && c) {
4964 if (ec == '\'')
Eric Andersen8401eea2004-08-04 19:16:54 +00004965 c &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00004966 if (thenext >= &myline[LINELIM]) {
4967 c = 0;
4968 break;
4969 }
4970 *thenext++ = c;
4971 }
4972 *thenext = 0;
4973 if (strcmp(s, myline) == 0 || c == 0)
4974 break;
4975 *thenext++ = '\n';
Eric Andersen8401eea2004-08-04 19:16:54 +00004976 write(tf, myline, (int) (thenext - myline));
Eric Andersenff9eee42001-06-29 04:57:14 +00004977 }
4978 if (c == 0) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004979 prs("here document `");
4980 prs(s);
4981 err("' unclosed");
Eric Andersenff9eee42001-06-29 04:57:14 +00004982 }
4983 quitenv();
4984 }
4985 close(tf);
4986}
4987
4988/*
4989 * open here temp file.
4990 * if unquoted here, expand here temp file into second temp file.
4991 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004992static int herein(char *hname, int xdoll)
Eric Andersenff9eee42001-06-29 04:57:14 +00004993{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004994 int hf;
Eric Andersenff9eee42001-06-29 04:57:14 +00004995 int tf;
4996
4997#if __GNUC__
4998 /* Avoid longjmp clobbering */
4999 (void) &tf;
5000#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00005001 if (hname == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00005002 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005003
5004 DBGPRINTF7(("HEREIN: hname is %s, xdoll=%d\n", hname, xdoll));
5005
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005006 hf = open(hname, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00005007 if (hf < 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00005008 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005009
Eric Andersenff9eee42001-06-29 04:57:14 +00005010 if (xdoll) {
5011 char c;
5012 char tname[30] = ".msh_XXXXXX";
5013 jmp_buf ev;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005014
Eric Andersenff9eee42001-06-29 04:57:14 +00005015 tf = mkstemp(tname);
5016 if (tf < 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00005017 return -1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00005018 errpt = ev;
5019 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00005020 PUSHIO(afile, hf, herechar);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005021 setbase(global_env.iop);
Eric Andersenff9eee42001-06-29 04:57:14 +00005022 while ((c = subgetc(0, 0)) != 0) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005023 c &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00005024 write(tf, &c, sizeof c);
5025 }
5026 quitenv();
5027 } else
5028 unlink(tname);
5029 close(tf);
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005030 tf = open(tname, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00005031 unlink(tname);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00005032 return tf;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00005033 }
5034 return hf;
Eric Andersenff9eee42001-06-29 04:57:14 +00005035}
5036
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005037static void scraphere(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00005038{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005039 struct here *h;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005040
5041 DBGPRINTF7(("SCRAPHERE: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00005042
5043 for (h = inhere; h != NULL; h = h->h_next) {
5044 if (h->h_iop && h->h_iop->io_name)
Eric Andersen8401eea2004-08-04 19:16:54 +00005045 unlink(h->h_iop->io_name);
Eric Andersenff9eee42001-06-29 04:57:14 +00005046 }
5047 inhere = NULL;
5048}
5049
5050/* unlink here temp files before a freearea(area) */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005051static void freehere(int area)
Eric Andersenff9eee42001-06-29 04:57:14 +00005052{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005053 struct here *h, *hl;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005054
5055 DBGPRINTF6(("FREEHERE: enter, area=%d\n", area));
Eric Andersenff9eee42001-06-29 04:57:14 +00005056
5057 hl = NULL;
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00005058 for (h = acthere; h != NULL; h = h->h_next) {
Eric Andersenff9eee42001-06-29 04:57:14 +00005059 if (getarea((char *) h) >= area) {
5060 if (h->h_iop->io_name != NULL)
5061 unlink(h->h_iop->io_name);
5062 if (hl == NULL)
5063 acthere = h->h_next;
5064 else
5065 hl->h_next = h->h_next;
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00005066 } else {
Eric Andersenff9eee42001-06-29 04:57:14 +00005067 hl = h;
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00005068 }
5069 }
Eric Andersenff9eee42001-06-29 04:57:14 +00005070}
5071
5072
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005073/* -------- sh.c -------- */
5074/*
5075 * shell
5076 */
5077
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00005078int msh_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005079int msh_main(int argc, char **argv)
5080{
5081 int f;
5082 char *s;
5083 int cflag;
5084 char *name, **ap;
5085 int (*iof) (struct ioarg *);
5086
Denis Vlasenkoab801872007-12-02 08:35:37 +00005087 INIT_G();
5088
Denis Vlasenko55f30b02007-03-24 22:42:29 +00005089 sharedbuf.id = AFID_NOBUF;
5090 mainbuf.id = AFID_NOBUF;
Denis Vlasenko55f30b02007-03-24 22:42:29 +00005091 elinep = line + sizeof(line) - 5;
5092
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005093#if ENABLE_FEATURE_EDITING
5094 line_input_state = new_line_input_t(FOR_SHELL);
5095#endif
5096
5097 DBGPRINTF(("MSH_MAIN: argc %d, environ %p\n", argc, environ));
5098
5099 initarea();
5100 ap = environ;
5101 if (ap != NULL) {
5102 while (*ap)
5103 assign(*ap++, !COPYV);
5104 for (ap = environ; *ap;)
5105 export(lookup(*ap++));
5106 }
5107 closeall();
5108 areanum = 1;
5109
5110 shell = lookup("SHELL");
5111 if (shell->value == null)
5112 setval(shell, (char *)DEFAULT_SHELL);
5113 export(shell);
5114
5115 homedir = lookup("HOME");
5116 if (homedir->value == null)
5117 setval(homedir, "/");
5118 export(homedir);
5119
5120 setval(lookup("$"), putn(getpid()));
5121
5122 path = lookup("PATH");
5123 if (path->value == null) {
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005124 /* Can be merged with same string elsewhere in bbox */
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005125 if (geteuid() == 0)
Denis Vlasenkof5f75c52007-06-12 22:35:19 +00005126 setval(path, bb_default_root_path);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005127 else
Denis Vlasenkof5f75c52007-06-12 22:35:19 +00005128 setval(path, bb_default_path);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005129 }
5130 export(path);
5131
5132 ifs = lookup("IFS");
5133 if (ifs->value == null)
5134 setval(ifs, " \t\n");
5135
5136#ifdef MSHDEBUG
5137 mshdbg_var = lookup("MSHDEBUG");
5138 if (mshdbg_var->value == null)
5139 setval(mshdbg_var, "0");
5140#endif
5141
5142 prompt = lookup("PS1");
5143#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
5144 if (prompt->value == null)
5145#endif
5146 setval(prompt, DEFAULT_USER_PROMPT);
5147 if (geteuid() == 0) {
5148 setval(prompt, DEFAULT_ROOT_PROMPT);
5149 prompt->status &= ~EXPORT;
5150 }
5151 cprompt = lookup("PS2");
5152#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
5153 if (cprompt->value == null)
5154#endif
5155 setval(cprompt, "> ");
5156
5157 iof = filechar;
5158 cflag = 0;
5159 name = *argv++;
5160 if (--argc >= 1) {
5161 if (argv[0][0] == '-' && argv[0][1] != '\0') {
5162 for (s = argv[0] + 1; *s; s++)
5163 switch (*s) {
5164 case 'c':
5165 prompt->status &= ~EXPORT;
5166 cprompt->status &= ~EXPORT;
5167 setval(prompt, "");
5168 setval(cprompt, "");
5169 cflag = 1;
5170 if (--argc > 0)
5171 PUSHIO(aword, *++argv, iof = nlchar);
5172 break;
5173
5174 case 'q':
5175 qflag = SIG_DFL;
5176 break;
5177
5178 case 's':
5179 /* standard input */
5180 break;
5181
5182 case 't':
5183 prompt->status &= ~EXPORT;
5184 setval(prompt, "");
5185 iof = linechar;
5186 break;
5187
5188 case 'i':
Denis Vlasenko648b44f2008-02-12 06:04:06 +00005189 interactive = 1;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005190 default:
5191 if (*s >= 'a' && *s <= 'z')
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00005192 FLAG[(int) *s]++;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005193 }
5194 } else {
5195 argv--;
5196 argc++;
5197 }
5198
5199 if (iof == filechar && --argc > 0) {
5200 setval(prompt, "");
5201 setval(cprompt, "");
5202 prompt->status &= ~EXPORT;
5203 cprompt->status &= ~EXPORT;
5204
5205/* Shell is non-interactive, activate printf-based debug */
5206#ifdef MSHDEBUG
5207 mshdbg = (int) (((char) (mshdbg_var->value[0])) - '0');
5208 if (mshdbg < 0)
5209 mshdbg = 0;
5210#endif
5211 DBGPRINTF(("MSH_MAIN: calling newfile()\n"));
5212
5213 name = *++argv;
5214 if (newfile(name))
5215 exit(1); /* Exit on error */
5216 }
5217 }
5218
5219 setdash();
5220
5221 /* This won't be true if PUSHIO has been called, say from newfile() above */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005222 if (global_env.iop < iostack) {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005223 PUSHIO(afile, 0, iof);
5224 if (isatty(0) && isatty(1) && !cflag) {
Denis Vlasenko648b44f2008-02-12 06:04:06 +00005225 interactive = 1;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005226#if !ENABLE_FEATURE_SH_EXTRA_QUIET
5227#ifdef MSHDEBUG
Denis Vlasenkoca525b42007-06-13 12:27:17 +00005228 printf("\n\n%s built-in shell (msh with debug)\n", bb_banner);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005229#else
Denis Vlasenkoca525b42007-06-13 12:27:17 +00005230 printf("\n\n%s built-in shell (msh)\n", bb_banner);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005231#endif
5232 printf("Enter 'help' for a list of built-in commands.\n\n");
5233#endif
5234 }
5235 }
5236
5237 signal(SIGQUIT, qflag);
5238 if (name && name[0] == '-') {
Denis Vlasenko648b44f2008-02-12 06:04:06 +00005239 interactive = 1;
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005240 f = open(".profile", O_RDONLY);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005241 if (f >= 0)
5242 next(remap(f));
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005243 f = open("/etc/profile", O_RDONLY);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005244 if (f >= 0)
5245 next(remap(f));
5246 }
5247 if (interactive)
5248 signal(SIGTERM, sig);
5249
5250 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
5251 signal(SIGINT, onintr);
Denis Vlasenkofee2d0c2008-02-12 10:12:18 +00005252
5253/* Handle "msh SCRIPT VAR=val params..." */
5254/* Disabled: bash does not do it! */
5255#if 0
5256 argv++;
5257 /* skip leading args of the form VAR=val */
5258 while (*argv && assign(*argv, !COPYV)) {
5259 argc--;
5260 argv++;
5261 }
5262 argv--;
5263#endif
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005264 dolv = argv;
5265 dolc = argc;
5266 dolv[0] = name;
Denis Vlasenkofee2d0c2008-02-12 10:12:18 +00005267
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005268 setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc));
5269
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005270 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 +00005271
5272 for (;;) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005273 if (interactive && global_env.iop <= iostack) {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005274#if ENABLE_FEATURE_EDITING
5275 current_prompt = prompt->value;
5276#else
5277 prs(prompt->value);
5278#endif
5279 }
5280 onecommand();
5281 /* Ensure that getenv("PATH") stays current */
5282 setenv("PATH", path->value, 1);
5283 }
5284
5285 DBGPRINTF(("MSH_MAIN: returning.\n"));
5286}
5287
5288
Eric Andersenff9eee42001-06-29 04:57:14 +00005289/*
5290 * Copyright (c) 1987,1997, Prentice Hall
5291 * All rights reserved.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005292 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005293 * Redistribution and use of the MINIX operating system in source and
5294 * binary forms, with or without modification, are permitted provided
5295 * that the following conditions are met:
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005296 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005297 * Redistributions of source code must retain the above copyright
5298 * notice, this list of conditions and the following disclaimer.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005299 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005300 * Redistributions in binary form must reproduce the above
5301 * copyright notice, this list of conditions and the following
5302 * disclaimer in the documentation and/or other materials provided
5303 * with the distribution.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005304 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005305 * Neither the name of Prentice Hall nor the names of the software
5306 * authors or contributors may be used to endorse or promote
5307 * products derived from this software without specific prior
5308 * written permission.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005309 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005310 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND
5311 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
5312 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
5313 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
5314 * IN NO EVENT SHALL PRENTICE HALL OR ANY AUTHORS OR CONTRIBUTORS BE
5315 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
5316 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
5317 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
5318 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
5319 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
5320 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
5321 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5322 *
5323 */