blob: 2b6b3853f44b36cf2a40731e644ae56e72576d83 [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 Vlasenkoed9d6212008-06-09 07:44:19 +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
Denis Vlasenkoed9d6212008-06-09 07:44:19 +0000127#endif /* MSHDEBUG */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000128
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
Denis Vlasenkoed9d6212008-06-09 07:44:19 +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
Denis Vlasenkoed9d6212008-06-09 07:44:19 +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 Vlasenkoed9d6212008-06-09 07:44:19 +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;
Denis Vlasenko447bd662008-05-30 22:28:32 +0000597static uint8_t 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
Denis Vlasenkoed9d6212008-06-09 07:44:19 +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)
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +0000746 write(STDERR_FILENO, s, strlen(s));
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000747}
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);
Denis Vlasenko447bd662008-05-30 22:28:32 +0000809 if (!exstat)
810 exstat = 255;
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000811 }
812 prs("\n");
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +0000813 if (FLAG['e'])
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000814 leave();
815}
816
817static void err(const char *s)
818{
819 warn(s);
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +0000820 if (FLAG['n'])
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000821 return;
822 if (!interactive)
823 leave();
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000824 if (global_env.errpt)
825 longjmp(global_env.errpt, 1);
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000826 closeall();
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000827 global_env.iop = global_env.iobase = iostack;
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000828}
829
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000830
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000831/* -------- area.c -------- */
832
Eric Andersenff9eee42001-06-29 04:57:14 +0000833/*
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000834 * All memory between (char *)areabot and (char *)(areatop+1) is
835 * exclusively administered by the area management routines.
836 * It is assumed that sbrk() and brk() manipulate the high end.
Eric Andersenff9eee42001-06-29 04:57:14 +0000837 */
838
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000839#define sbrk(X) ({ \
840 void * __q = (void *)-1; \
841 if (brkaddr + (int)(X) < brktop) { \
842 __q = brkaddr; \
843 brkaddr += (int)(X); \
844 } \
845 __q; \
846})
Eric Andersenff9eee42001-06-29 04:57:14 +0000847
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000848static void initarea(void)
Eric Andersenff9eee42001-06-29 04:57:14 +0000849{
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000850 brkaddr = xmalloc(AREASIZE);
851 brktop = brkaddr + AREASIZE;
Eric Andersenff9eee42001-06-29 04:57:14 +0000852
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000853 while ((long) sbrk(0) & ALIGN)
854 sbrk(1);
855 areabot = (struct region *) sbrk(REGSIZE);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +0000856
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000857 areabot->next = areabot;
858 areabot->area = BUSY;
859 areatop = areabot;
860 areanxt = areabot;
Eric Andersenff9eee42001-06-29 04:57:14 +0000861}
862
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000863static char *getcell(unsigned nbytes)
864{
865 int nregio;
866 struct region *p, *q;
867 int i;
868
869 if (nbytes == 0) {
870 puts("getcell(0)");
871 abort();
872 }
873 /* silly and defeats the algorithm */
874 /*
875 * round upwards and add administration area
876 */
877 nregio = (nbytes + (REGSIZE - 1)) / REGSIZE + 1;
878 p = areanxt;
879 for (;;) {
880 if (p->area > areanum) {
881 /*
882 * merge free cells
883 */
884 while ((q = p->next)->area > areanum && q != areanxt)
885 p->next = q->next;
886 /*
887 * exit loop if cell big enough
888 */
889 if (q >= p + nregio)
890 goto found;
891 }
892 p = p->next;
893 if (p == areanxt)
894 break;
895 }
896 i = nregio >= GROWBY ? nregio : GROWBY;
897 p = (struct region *) sbrk(i * REGSIZE);
898 if (p == (struct region *) -1)
899 return NULL;
900 p--;
901 if (p != areatop) {
902 puts("not contig");
903 abort(); /* allocated areas are contiguous */
904 }
905 q = p + i;
906 p->next = q;
907 p->area = FREE;
908 q->next = areabot;
909 q->area = BUSY;
910 areatop = q;
911 found:
912 /*
913 * we found a FREE area big enough, pointed to by 'p', and up to 'q'
914 */
915 areanxt = p + nregio;
916 if (areanxt < q) {
917 /*
918 * split into requested area and rest
919 */
920 if (areanxt + 1 > q) {
921 puts("OOM");
922 abort(); /* insufficient space left for admin */
923 }
924 areanxt->next = q;
925 areanxt->area = FREE;
926 p->next = areanxt;
927 }
928 p->area = areanum;
929 return (char *) (p + 1);
930}
931
932static void freecell(char *cp)
933{
934 struct region *p;
935
936 p = (struct region *) cp;
937 if (p != NULL) {
938 p--;
939 if (p < areanxt)
940 areanxt = p;
941 p->area = FREE;
942 }
943}
944#define DELETE(obj) freecell((char *)obj)
945
946static void freearea(int a)
947{
948 struct region *p, *top;
949
950 top = areatop;
951 for (p = areabot; p != top; p = p->next)
952 if (p->area >= a)
953 p->area = FREE;
954}
955
956static void setarea(char *cp, int a)
957{
958 struct region *p;
959
960 p = (struct region *) cp;
961 if (p != NULL)
962 (p - 1)->area = a;
963}
964
965static int getarea(char *cp)
966{
967 return ((struct region *) cp - 1)->area;
968}
969
970static void garbage(void)
971{
972 struct region *p, *q, *top;
973
974 top = areatop;
975 for (p = areabot; p != top; p = p->next) {
976 if (p->area > areanum) {
977 while ((q = p->next)->area > areanum)
978 p->next = q->next;
979 areanxt = p;
980 }
981 }
982#ifdef SHRINKBY
983 if (areatop >= q + SHRINKBY && q->area > areanum) {
984 brk((char *) (q + 1));
985 q->next = areabot;
986 q->area = BUSY;
987 areatop = q;
988 }
989#endif
990}
991
Denis Vlasenko509697f2008-03-02 12:49:39 +0000992static void *get_space(int n)
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000993{
994 char *cp;
995
996 cp = getcell(n);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000997 if (cp == NULL)
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000998 err("out of string space");
999 return cp;
1000}
1001
1002static char *strsave(const char *s, int a)
1003{
1004 char *cp;
1005
Denis Vlasenko509697f2008-03-02 12:49:39 +00001006 cp = get_space(strlen(s) + 1);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001007 if (cp == NULL) {
1008// FIXME: I highly doubt this is good.
1009 return (char*)"";
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001010 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001011 setarea(cp, a);
1012 strcpy(cp, s);
1013 return cp;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001014}
1015
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001016
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001017/* -------- var.c -------- */
1018
1019static int eqname(const char *n1, const char *n2)
1020{
1021 for (; *n1 != '=' && *n1 != '\0'; n1++)
1022 if (*n2++ != *n1)
1023 return 0;
1024 return *n2 == '\0' || *n2 == '=';
1025}
1026
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001027static const char *findeq(const char *cp)
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001028{
1029 while (*cp != '\0' && *cp != '=')
1030 cp++;
1031 return cp;
1032}
1033
1034/*
1035 * Find the given name in the dictionary
1036 * and return its value. If the name was
1037 * not previously there, enter it now and
1038 * return a null value.
1039 */
1040static struct var *lookup(const char *n)
1041{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001042// FIXME: dirty hack
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001043 static struct var dummy;
1044
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001045 struct var *vp;
1046 const char *cp;
1047 char *xp;
1048 int c;
1049
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001050 if (isdigit(*n)) {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001051 dummy.name = (char*)n;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001052 for (c = 0; isdigit(*n) && c < 1000; n++)
1053 c = c * 10 + *n - '0';
1054 dummy.status = RONLY;
1055 dummy.value = (c <= dolc ? dolv[c] : null);
1056 return &dummy;
1057 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001058
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001059 for (vp = vlist; vp; vp = vp->next)
1060 if (eqname(vp->name, n))
1061 return vp;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001062
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001063 cp = findeq(n);
Denis Vlasenko509697f2008-03-02 12:49:39 +00001064 vp = get_space(sizeof(*vp));
1065 if (vp == 0 || (vp->name = get_space((int) (cp - n) + 2)) == NULL) {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001066 dummy.name = dummy.value = (char*)"";
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001067 return &dummy;
1068 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001069
1070 xp = vp->name;
1071 while ((*xp = *n++) != '\0' && *xp != '=')
1072 xp++;
1073 *xp++ = '=';
1074 *xp = '\0';
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001075 setarea((char *) vp, 0);
1076 setarea((char *) vp->name, 0);
1077 vp->value = null;
1078 vp->next = vlist;
1079 vp->status = GETCELL;
1080 vlist = vp;
1081 return vp;
1082}
1083
1084/*
1085 * if name is not NULL, it must be
1086 * a prefix of the space `val',
1087 * and end with `='.
1088 * this is all so that exporting
1089 * values is reasonably painless.
1090 */
1091static void nameval(struct var *vp, const char *val, const char *name)
1092{
1093 const char *cp;
1094 char *xp;
1095 int fl;
1096
1097 if (vp->status & RONLY) {
1098 xp = vp->name;
1099 while (*xp && *xp != '=')
Denis Vlasenko4daad902007-09-27 10:20:47 +00001100 fputc(*xp++, stderr);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001101 err(" is read-only");
1102 return;
1103 }
1104 fl = 0;
1105 if (name == NULL) {
Denis Vlasenko509697f2008-03-02 12:49:39 +00001106 xp = get_space(strlen(vp->name) + strlen(val) + 2);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001107 if (xp == NULL)
1108 return;
1109 /* make string: name=value */
1110 setarea(xp, 0);
1111 name = xp;
1112 cp = vp->name;
1113 while ((*xp = *cp++) != '\0' && *xp != '=')
1114 xp++;
1115 *xp++ = '=';
1116 strcpy(xp, val);
1117 val = xp;
1118 fl = GETCELL;
1119 }
1120 if (vp->status & GETCELL)
1121 freecell(vp->name); /* form new string `name=value' */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001122 vp->name = (char*)name;
1123 vp->value = (char*)val;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001124 vp->status |= fl;
1125}
1126
1127/*
1128 * give variable at `vp' the value `val'.
1129 */
1130static void setval(struct var *vp, const char *val)
1131{
1132 nameval(vp, val, NULL);
1133}
1134
1135static void export(struct var *vp)
1136{
1137 vp->status |= EXPORT;
1138}
1139
1140static void ronly(struct var *vp)
1141{
1142 if (isalpha(vp->name[0]) || vp->name[0] == '_') /* not an internal symbol */
1143 vp->status |= RONLY;
1144}
1145
1146static int isassign(const char *s)
1147{
1148 unsigned char c;
1149 DBGPRINTF7(("ISASSIGN: enter, s=%s\n", s));
1150
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001151 c = *s;
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001152 /* no isalpha() - we shouldn't use locale */
1153 /* c | 0x20 - lowercase (Latin) letters */
1154 if (c != '_' && (unsigned)((c|0x20) - 'a') > 25)
1155 /* not letter */
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001156 return 0;
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001157
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001158 while (1) {
1159 c = *++s;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001160 if (c == '=')
1161 return 1;
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001162 if (c == '\0')
1163 return 0;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001164 if (c != '_'
1165 && (unsigned)(c - '0') > 9 /* not number */
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001166 && (unsigned)((c|0x20) - 'a') > 25 /* not letter */
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001167 ) {
1168 return 0;
1169 }
1170 }
1171}
1172
1173static int assign(const char *s, int cf)
1174{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001175 const char *cp;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001176 struct var *vp;
1177
1178 DBGPRINTF7(("ASSIGN: enter, s=%s, cf=%d\n", s, cf));
1179
1180 if (!isalpha(*s) && *s != '_')
1181 return 0;
1182 for (cp = s; *cp != '='; cp++)
1183 if (*cp == '\0' || (!isalnum(*cp) && *cp != '_'))
1184 return 0;
1185 vp = lookup(s);
1186 nameval(vp, ++cp, cf == COPYV ? NULL : s);
1187 if (cf != COPYV)
1188 vp->status &= ~GETCELL;
1189 return 1;
1190}
1191
1192static int checkname(char *cp)
1193{
1194 DBGPRINTF7(("CHECKNAME: enter, cp=%s\n", cp));
1195
1196 if (!isalpha(*cp++) && *(cp - 1) != '_')
1197 return 0;
1198 while (*cp)
1199 if (!isalnum(*cp++) && *(cp - 1) != '_')
1200 return 0;
1201 return 1;
1202}
1203
1204static void putvlist(int f, int out)
1205{
1206 struct var *vp;
1207
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001208 for (vp = vlist; vp; vp = vp->next) {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001209 if (vp->status & f && (isalpha(*vp->name) || *vp->name == '_')) {
1210 if (vp->status & EXPORT)
1211 write(out, "export ", 7);
1212 if (vp->status & RONLY)
1213 write(out, "readonly ", 9);
1214 write(out, vp->name, (int) (findeq(vp->name) - vp->name));
1215 write(out, "\n", 1);
1216 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001217 }
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001218}
1219
1220
1221/*
1222 * trap handling
1223 */
1224static void sig(int i)
1225{
1226 trapset = i;
1227 signal(i, sig);
1228}
1229
1230static void runtrap(int i)
1231{
1232 char *trapstr;
1233
1234 trapstr = trap[i];
1235 if (trapstr == NULL)
1236 return;
1237
1238 if (i == 0)
1239 trap[i] = NULL;
1240
1241 RUN(aword, trapstr, nlchar);
1242}
1243
1244
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001245static void setdash(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001246{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001247 char *cp;
1248 int c;
Eric Andersen8401eea2004-08-04 19:16:54 +00001249 char m['z' - 'a' + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00001250
1251 cp = m;
Eric Andersen8401eea2004-08-04 19:16:54 +00001252 for (c = 'a'; c <= 'z'; c++)
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00001253 if (FLAG[c])
Eric Andersenff9eee42001-06-29 04:57:14 +00001254 *cp++ = c;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001255 *cp = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00001256 setval(lookup("-"), m);
1257}
1258
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001259static int newfile(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00001260{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001261 int f;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001262
1263 DBGPRINTF7(("NEWFILE: opening %s\n", s));
Eric Andersenff9eee42001-06-29 04:57:14 +00001264
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001265 f = 0;
Denis Vlasenko9f739442006-12-16 23:49:13 +00001266 if (NOT_LONE_DASH(s)) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001267 DBGPRINTF(("NEWFILE: s is %s\n", s));
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00001268 f = open(s, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00001269 if (f < 0) {
1270 prs(s);
1271 err(": cannot open");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001272 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001273 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001274 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001275
Eric Andersenff9eee42001-06-29 04:57:14 +00001276 next(remap(f));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001277 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001278}
1279
Eric Andersen12de6cf2004-08-04 19:19:10 +00001280
Denis Vlasenkobc1918a2008-04-15 01:17:50 +00001281#ifdef UNUSED
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001282struct op *scantree(struct op *head)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001283{
1284 struct op *dotnode;
1285
1286 if (head == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001287 return NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001288
1289 if (head->left != NULL) {
1290 dotnode = scantree(head->left);
1291 if (dotnode)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001292 return dotnode;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001293 }
1294
1295 if (head->right != NULL) {
1296 dotnode = scantree(head->right);
1297 if (dotnode)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001298 return dotnode;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001299 }
1300
Denis Vlasenko509697f2008-03-02 12:49:39 +00001301 if (head->op_words == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001302 return NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001303
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001304 DBGPRINTF5(("SCANTREE: checking node %p\n", head));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001305
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001306 if ((head->op_type != TDOT) && LONE_CHAR(head->op_words[0], '.')) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001307 DBGPRINTF5(("SCANTREE: dot found in node %p\n", head));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001308 return head;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001309 }
1310
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001311 return NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001312}
Denis Vlasenkobc1918a2008-04-15 01:17:50 +00001313#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00001314
1315
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001316static void onecommand(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001317{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001318 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00001319 jmp_buf m1;
1320
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001321 DBGPRINTF(("ONECOMMAND: enter, outtree=%p\n", outtree));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001322
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001323 while (global_env.oenv)
Eric Andersenff9eee42001-06-29 04:57:14 +00001324 quitenv();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001325
Eric Andersenff9eee42001-06-29 04:57:14 +00001326 areanum = 1;
1327 freehere(areanum);
1328 freearea(areanum);
1329 garbage();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001330 wdlist = NULL;
1331 iolist = NULL;
1332 global_env.errpt = NULL;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001333 global_env.linep = line;
Eric Andersenff9eee42001-06-29 04:57:14 +00001334 yynerrs = 0;
1335 multiline = 0;
1336 inparse = 1;
1337 intr = 0;
1338 execflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001339
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001340 failpt = m1;
1341 setjmp(failpt); /* Bruce Evans' fix */
1342 failpt = m1;
1343 if (setjmp(failpt) || yyparse() || intr) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001344 DBGPRINTF(("ONECOMMAND: this is not good.\n"));
1345
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001346 while (global_env.oenv)
Eric Andersenff9eee42001-06-29 04:57:14 +00001347 quitenv();
1348 scraphere();
1349 if (!interactive && intr)
1350 leave();
1351 inparse = 0;
1352 intr = 0;
1353 return;
1354 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001355
Eric Andersenff9eee42001-06-29 04:57:14 +00001356 inparse = 0;
1357 brklist = 0;
1358 intr = 0;
1359 execflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001360
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00001361 if (!FLAG['n']) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001362 DBGPRINTF(("ONECOMMAND: calling execute, t=outtree=%p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00001363 outtree));
Denis Vlasenko7e497522008-02-12 09:51:03 +00001364 execute(outtree, NOPIPE, NOPIPE, /* no_fork: */ 0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001365 }
1366
Eric Andersenff9eee42001-06-29 04:57:14 +00001367 if (!interactive && intr) {
1368 execflg = 0;
1369 leave();
1370 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001371
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001372 i = trapset;
1373 if (i != 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001374 trapset = 0;
1375 runtrap(i);
1376 }
1377}
1378
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001379static int newenv(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00001380{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001381 struct env *ep;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001382
1383 DBGPRINTF(("NEWENV: f=%d (indicates quitenv and return)\n", f));
Eric Andersenff9eee42001-06-29 04:57:14 +00001384
1385 if (f) {
1386 quitenv();
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001387 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001388 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001389
Denis Vlasenko509697f2008-03-02 12:49:39 +00001390 ep = get_space(sizeof(*ep));
Eric Andersenff9eee42001-06-29 04:57:14 +00001391 if (ep == NULL) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001392 while (global_env.oenv)
Eric Andersenff9eee42001-06-29 04:57:14 +00001393 quitenv();
1394 fail();
1395 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001396 *ep = global_env;
1397 global_env.oenv = ep;
1398 global_env.errpt = errpt;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001399
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001400 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001401}
1402
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001403static void quitenv(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001404{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001405 struct env *ep;
1406 int fd;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001407
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001408 DBGPRINTF(("QUITENV: global_env.oenv=%p\n", global_env.oenv));
Eric Andersenff9eee42001-06-29 04:57:14 +00001409
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001410 ep = global_env.oenv;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001411 if (ep != NULL) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001412 fd = global_env.iofd;
1413 global_env = *ep;
Eric Andersenff9eee42001-06-29 04:57:14 +00001414 /* should close `'d files */
1415 DELETE(ep);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001416 while (--fd >= global_env.iofd)
Eric Andersenff9eee42001-06-29 04:57:14 +00001417 close(fd);
1418 }
1419}
1420
1421/*
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001422 * Is character c in s?
Eric Andersenff9eee42001-06-29 04:57:14 +00001423 */
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001424static int any(int c, const char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00001425{
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001426 while (*s)
1427 if (*s++ == c)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001428 return 1;
1429 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001430}
1431
1432/*
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001433 * Is any character from s1 in s2?
Eric Andersenff9eee42001-06-29 04:57:14 +00001434 */
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001435static int anys(const char *s1, const char *s2)
Eric Andersenff9eee42001-06-29 04:57:14 +00001436{
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001437 while (*s1)
1438 if (any(*s1++, s2))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001439 return 1;
1440 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001441}
1442
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001443static char *putn(int n)
Eric Andersenff9eee42001-06-29 04:57:14 +00001444{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001445 return itoa(n);
Eric Andersenff9eee42001-06-29 04:57:14 +00001446}
1447
Eric Andersen8401eea2004-08-04 19:16:54 +00001448static void next(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00001449{
1450 PUSHIO(afile, f, filechar);
1451}
1452
Denis Vlasenko68404f12008-03-17 09:00:54 +00001453static void onintr(int s ATTRIBUTE_UNUSED) /* ANSI C requires a parameter */
Eric Andersenff9eee42001-06-29 04:57:14 +00001454{
1455 signal(SIGINT, onintr);
1456 intr = 1;
1457 if (interactive) {
1458 if (inparse) {
1459 prs("\n");
1460 fail();
1461 }
Eric Andersen8401eea2004-08-04 19:16:54 +00001462 } else if (heedint) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001463 execflg = 0;
1464 leave();
1465 }
1466}
1467
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001468
Eric Andersenff9eee42001-06-29 04:57:14 +00001469/* -------- gmatch.c -------- */
1470/*
1471 * int gmatch(string, pattern)
1472 * char *string, *pattern;
1473 *
1474 * Match a pattern as in sh(1).
1475 */
1476
1477#define CMASK 0377
1478#define QUOTE 0200
Denis Vlasenko55f30b02007-03-24 22:42:29 +00001479#define QMASK (CMASK & ~QUOTE)
Eric Andersen8401eea2004-08-04 19:16:54 +00001480#define NOT '!' /* might use ^ */
Eric Andersenff9eee42001-06-29 04:57:14 +00001481
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001482static const char *cclass(const char *p, int sub)
1483{
1484 int c, d, not, found;
1485
1486 not = (*p == NOT);
1487 if (not != 0)
1488 p++;
1489 found = not;
1490 do {
1491 if (*p == '\0')
1492 return NULL;
1493 c = *p & CMASK;
1494 if (p[1] == '-' && p[2] != ']') {
1495 d = p[2] & CMASK;
1496 p++;
1497 } else
1498 d = c;
1499 if (c == sub || (c <= sub && sub <= d))
1500 found = !not;
1501 } while (*++p != ']');
1502 return found ? p + 1 : NULL;
1503}
1504
1505static int gmatch(const char *s, const char *p)
Eric Andersenff9eee42001-06-29 04:57:14 +00001506{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001507 int sc, pc;
Eric Andersenff9eee42001-06-29 04:57:14 +00001508
1509 if (s == NULL || p == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001510 return 0;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001511
Eric Andersenff9eee42001-06-29 04:57:14 +00001512 while ((pc = *p++ & CMASK) != '\0') {
1513 sc = *s++ & QMASK;
1514 switch (pc) {
1515 case '[':
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001516 p = cclass(p, sc);
1517 if (p == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001518 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001519 break;
1520
1521 case '?':
1522 if (sc == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001523 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001524 break;
1525
1526 case '*':
1527 s--;
1528 do {
1529 if (*p == '\0' || gmatch(s, p))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001530 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001531 } while (*s++ != '\0');
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001532 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001533
1534 default:
Eric Andersen8401eea2004-08-04 19:16:54 +00001535 if (sc != (pc & ~QUOTE))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001536 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001537 }
1538 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001539 return *s == '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00001540}
1541
Eric Andersenff9eee42001-06-29 04:57:14 +00001542
Eric Andersenff9eee42001-06-29 04:57:14 +00001543/* -------- csyn.c -------- */
1544/*
1545 * shell: syntax (C version)
1546 */
1547
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001548static void yyerror(const char *s) ATTRIBUTE_NORETURN;
1549static void yyerror(const char *s)
1550{
Denis Vlasenko648b44f2008-02-12 06:04:06 +00001551 yynerrs = 1;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001552 if (interactive && global_env.iop <= iostack) {
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001553 multiline = 0;
Denis Vlasenko648b44f2008-02-12 06:04:06 +00001554 while (eofc() == 0 && yylex(0) != '\n')
1555 continue;
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001556 }
1557 err(s);
1558 fail();
1559}
1560
1561static void zzerr(void) ATTRIBUTE_NORETURN;
1562static void zzerr(void)
1563{
1564 yyerror("syntax error");
1565}
1566
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001567int yyparse(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001568{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001569 DBGPRINTF7(("YYPARSE: enter...\n"));
1570
Eric Andersen8401eea2004-08-04 19:16:54 +00001571 startl = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001572 peeksym = 0;
1573 yynerrs = 0;
1574 outtree = c_list();
1575 musthave('\n', 0);
Denis Vlasenko648b44f2008-02-12 06:04:06 +00001576 return yynerrs; /* 0/1 */
Eric Andersenff9eee42001-06-29 04:57:14 +00001577}
1578
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001579static struct op *pipeline(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001580{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001581 struct op *t, *p;
1582 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001583
1584 DBGPRINTF7(("PIPELINE: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001585
1586 t = command(cf);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001587
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001588 DBGPRINTF9(("PIPELINE: t=%p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001589
Eric Andersenff9eee42001-06-29 04:57:14 +00001590 if (t != NULL) {
1591 while ((c = yylex(0)) == '|') {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001592 p = command(CONTIN);
1593 if (p == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001594 DBGPRINTF8(("PIPELINE: error!\n"));
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001595 zzerr();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001596 }
1597
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001598 if (t->op_type != TPAREN && t->op_type != TCOM) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001599 /* shell statement */
1600 t = block(TPAREN, t, NOBLOCK, NOWORDS);
1601 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001602
Eric Andersenff9eee42001-06-29 04:57:14 +00001603 t = block(TPIPE, t, p, NOWORDS);
1604 }
1605 peeksym = c;
1606 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001607
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001608 DBGPRINTF7(("PIPELINE: returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001609 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001610}
1611
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001612static struct op *andor(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001613{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001614 struct op *t, *p;
1615 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001616
1617 DBGPRINTF7(("ANDOR: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001618
1619 t = pipeline(0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001620
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001621 DBGPRINTF9(("ANDOR: t=%p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001622
Eric Andersenff9eee42001-06-29 04:57:14 +00001623 if (t != NULL) {
1624 while ((c = yylex(0)) == LOGAND || c == LOGOR) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001625 p = pipeline(CONTIN);
1626 if (p == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001627 DBGPRINTF8(("ANDOR: error!\n"));
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001628 zzerr();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001629 }
1630
Eric Andersen8401eea2004-08-04 19:16:54 +00001631 t = block(c == LOGAND ? TAND : TOR, t, p, NOWORDS);
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001632 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001633
Eric Andersenff9eee42001-06-29 04:57:14 +00001634 peeksym = c;
1635 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001636
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001637 DBGPRINTF7(("ANDOR: returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001638 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001639}
1640
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001641static struct op *c_list(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001642{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001643 struct op *t, *p;
1644 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001645
1646 DBGPRINTF7(("C_LIST: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001647
1648 t = andor();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001649
Eric Andersenff9eee42001-06-29 04:57:14 +00001650 if (t != NULL) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001651 peeksym = yylex(0);
1652 if (peeksym == '&')
Eric Andersenff9eee42001-06-29 04:57:14 +00001653 t = block(TASYNC, t, NOBLOCK, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001654
Eric Andersen8401eea2004-08-04 19:16:54 +00001655 while ((c = yylex(0)) == ';' || c == '&'
Denis Vlasenko509697f2008-03-02 12:49:39 +00001656 || (multiline && c == '\n')
1657 ) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001658 p = andor();
1659 if (p== NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001660 return t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001661
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001662 peeksym = yylex(0);
1663 if (peeksym == '&')
Eric Andersenff9eee42001-06-29 04:57:14 +00001664 p = block(TASYNC, p, NOBLOCK, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001665
Eric Andersenff9eee42001-06-29 04:57:14 +00001666 t = list(t, p);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001667 } /* WHILE */
1668
Eric Andersenff9eee42001-06-29 04:57:14 +00001669 peeksym = c;
1670 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001671 /* IF */
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001672 DBGPRINTF7(("C_LIST: returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001673 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001674}
1675
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001676static int synio(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001677{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001678 struct ioword *iop;
1679 int i;
1680 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001681
1682 DBGPRINTF7(("SYNIO: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001683
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001684 c = yylex(cf);
1685 if (c != '<' && c != '>') {
Eric Andersenff9eee42001-06-29 04:57:14 +00001686 peeksym = c;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001687 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001688 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001689
Eric Andersenff9eee42001-06-29 04:57:14 +00001690 i = yylval.i;
1691 musthave(WORD, 0);
1692 iop = io(iounit, i, yylval.cp);
1693 iounit = IODEFAULT;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001694
Eric Andersenff9eee42001-06-29 04:57:14 +00001695 if (i & IOHERE)
1696 markhere(yylval.cp, iop);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001697
1698 DBGPRINTF7(("SYNIO: returning 1\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001699 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001700}
1701
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001702static void musthave(int c, int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001703{
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001704 peeksym = yylex(cf);
1705 if (peeksym != c) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001706 DBGPRINTF7(("MUSTHAVE: error!\n"));
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001707 zzerr();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001708 }
1709
Eric Andersenff9eee42001-06-29 04:57:14 +00001710 peeksym = 0;
1711}
1712
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001713static struct op *simple(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001714{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001715 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001716
1717 t = NULL;
1718 for (;;) {
1719 switch (peeksym = yylex(0)) {
1720 case '<':
1721 case '>':
1722 (void) synio(0);
1723 break;
1724
1725 case WORD:
1726 if (t == NULL) {
1727 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001728 t->op_type = TCOM;
Eric Andersenff9eee42001-06-29 04:57:14 +00001729 }
1730 peeksym = 0;
1731 word(yylval.cp);
1732 break;
1733
1734 default:
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001735 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001736 }
1737 }
1738}
1739
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001740static struct op *nested(int type, int mark)
Eric Andersenff9eee42001-06-29 04:57:14 +00001741{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001742 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001743
1744 DBGPRINTF3(("NESTED: enter, type=%d, mark=%d\n", type, mark));
Eric Andersenff9eee42001-06-29 04:57:14 +00001745
1746 multiline++;
1747 t = c_list();
1748 musthave(mark, 0);
1749 multiline--;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001750 return block(type, t, NOBLOCK, NOWORDS);
Eric Andersenff9eee42001-06-29 04:57:14 +00001751}
1752
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001753static struct op *command(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001754{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001755 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001756 struct wdblock *iosave;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001757 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001758
1759 DBGPRINTF(("COMMAND: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001760
1761 iosave = iolist;
1762 iolist = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001763
Eric Andersenff9eee42001-06-29 04:57:14 +00001764 if (multiline)
1765 cf |= CONTIN;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001766
Eric Andersenff9eee42001-06-29 04:57:14 +00001767 while (synio(cf))
1768 cf = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001769
1770 c = yylex(cf);
1771
1772 switch (c) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001773 default:
1774 peeksym = c;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001775 t = simple();
1776 if (t == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001777 if (iolist == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001778 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001779 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001780 t->op_type = TCOM;
Eric Andersenff9eee42001-06-29 04:57:14 +00001781 }
1782 break;
1783
1784 case '(':
1785 t = nested(TPAREN, ')');
1786 break;
1787
1788 case '{':
1789 t = nested(TBRACE, '}');
1790 break;
1791
1792 case FOR:
1793 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001794 t->op_type = TFOR;
Eric Andersenff9eee42001-06-29 04:57:14 +00001795 musthave(WORD, 0);
1796 startl = 1;
1797 t->str = yylval.cp;
1798 multiline++;
Denis Vlasenko509697f2008-03-02 12:49:39 +00001799 t->op_words = wordlist();
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001800 c = yylex(0);
1801 if (c != '\n' && c != ';')
Eric Andersenff9eee42001-06-29 04:57:14 +00001802 peeksym = c;
1803 t->left = dogroup(0);
1804 multiline--;
1805 break;
1806
1807 case WHILE:
1808 case UNTIL:
1809 multiline++;
1810 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001811 t->op_type = (c == WHILE ? TWHILE : TUNTIL);
Eric Andersenff9eee42001-06-29 04:57:14 +00001812 t->left = c_list();
1813 t->right = dogroup(1);
Denis Vlasenko509697f2008-03-02 12:49:39 +00001814 /* t->op_words = NULL; - newtp() did this */
Eric Andersenff9eee42001-06-29 04:57:14 +00001815 multiline--;
1816 break;
1817
1818 case CASE:
1819 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001820 t->op_type = TCASE;
Eric Andersenff9eee42001-06-29 04:57:14 +00001821 musthave(WORD, 0);
1822 t->str = yylval.cp;
1823 startl++;
1824 multiline++;
1825 musthave(IN, CONTIN);
1826 startl++;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001827
Eric Andersenff9eee42001-06-29 04:57:14 +00001828 t->left = caselist();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001829
Eric Andersenff9eee42001-06-29 04:57:14 +00001830 musthave(ESAC, 0);
1831 multiline--;
1832 break;
1833
1834 case IF:
1835 multiline++;
1836 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001837 t->op_type = TIF;
Eric Andersenff9eee42001-06-29 04:57:14 +00001838 t->left = c_list();
1839 t->right = thenpart();
1840 musthave(FI, 0);
1841 multiline--;
1842 break;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001843
1844 case DOT:
1845 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001846 t->op_type = TDOT;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001847
Denis Vlasenko509697f2008-03-02 12:49:39 +00001848 musthave(WORD, 0); /* gets name of file */
Eric Andersen12de6cf2004-08-04 19:19:10 +00001849 DBGPRINTF7(("COMMAND: DOT clause, yylval.cp is %s\n", yylval.cp));
1850
Denis Vlasenko509697f2008-03-02 12:49:39 +00001851 word(yylval.cp); /* add word to wdlist */
1852 word(NOWORD); /* terminate wdlist */
1853 t->op_words = copyw(); /* dup wdlist */
Eric Andersen12de6cf2004-08-04 19:19:10 +00001854 break;
1855
Eric Andersenff9eee42001-06-29 04:57:14 +00001856 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001857
Denis Vlasenko509697f2008-03-02 12:49:39 +00001858 while (synio(0))
1859 continue;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001860
Eric Andersenff9eee42001-06-29 04:57:14 +00001861 t = namelist(t);
1862 iolist = iosave;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001863
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001864 DBGPRINTF(("COMMAND: returning %p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001865
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001866 return t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001867}
1868
Denis Vlasenko68404f12008-03-17 09:00:54 +00001869static struct op *dowholefile(int type /*, int mark*/)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001870{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001871 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001872
Denis Vlasenko68404f12008-03-17 09:00:54 +00001873 DBGPRINTF(("DOWHOLEFILE: enter, type=%d\n", type /*, mark*/));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001874
1875 multiline++;
1876 t = c_list();
1877 multiline--;
1878 t = block(type, t, NOBLOCK, NOWORDS);
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001879 DBGPRINTF(("DOWHOLEFILE: return t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001880 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001881}
1882
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001883static struct op *dogroup(int onlydone)
Eric Andersenff9eee42001-06-29 04:57:14 +00001884{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001885 int c;
1886 struct op *mylist;
Eric Andersenff9eee42001-06-29 04:57:14 +00001887
1888 c = yylex(CONTIN);
1889 if (c == DONE && onlydone)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001890 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001891 if (c != DO)
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001892 zzerr();
Eric Andersenff9eee42001-06-29 04:57:14 +00001893 mylist = c_list();
1894 musthave(DONE, 0);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001895 return mylist;
Eric Andersenff9eee42001-06-29 04:57:14 +00001896}
1897
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001898static struct op *thenpart(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001899{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001900 int c;
1901 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001902
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001903 c = yylex(0);
1904 if (c != THEN) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001905 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001906 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001907 }
1908 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001909 /*t->op_type = 0; - newtp() did this */
Eric Andersenff9eee42001-06-29 04:57:14 +00001910 t->left = c_list();
1911 if (t->left == NULL)
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001912 zzerr();
Eric Andersenff9eee42001-06-29 04:57:14 +00001913 t->right = elsepart();
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001914 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001915}
1916
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001917static struct op *elsepart(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001918{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001919 int c;
1920 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001921
1922 switch (c = yylex(0)) {
1923 case ELSE:
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001924 t = c_list();
1925 if (t == NULL)
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001926 zzerr();
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001927 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001928
1929 case ELIF:
1930 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001931 t->op_type = TELIF;
Eric Andersenff9eee42001-06-29 04:57:14 +00001932 t->left = c_list();
1933 t->right = thenpart();
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001934 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001935
1936 default:
1937 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001938 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001939 }
1940}
1941
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001942static struct op *caselist(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001943{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001944 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001945
1946 t = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001947 while ((peeksym = yylex(CONTIN)) != ESAC) {
1948 DBGPRINTF(("CASELIST, doing yylex, peeksym=%d\n", peeksym));
Eric Andersenff9eee42001-06-29 04:57:14 +00001949 t = list(t, casepart());
Eric Andersen12de6cf2004-08-04 19:19:10 +00001950 }
1951
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001952 DBGPRINTF(("CASELIST, returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001953 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001954}
1955
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001956static struct op *casepart(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001957{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001958 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001959
1960 DBGPRINTF7(("CASEPART: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001961
1962 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001963 t->op_type = TPAT;
Denis Vlasenko509697f2008-03-02 12:49:39 +00001964 t->op_words = pattern();
Eric Andersenff9eee42001-06-29 04:57:14 +00001965 musthave(')', 0);
1966 t->left = c_list();
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001967 peeksym = yylex(CONTIN);
1968 if (peeksym != ESAC)
Eric Andersenff9eee42001-06-29 04:57:14 +00001969 musthave(BREAK, CONTIN);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001970
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001971 DBGPRINTF7(("CASEPART: made newtp(TPAT, t=%p)\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001972
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001973 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001974}
1975
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001976static char **pattern(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001977{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001978 int c, cf;
Eric Andersenff9eee42001-06-29 04:57:14 +00001979
1980 cf = CONTIN;
1981 do {
1982 musthave(WORD, cf);
1983 word(yylval.cp);
1984 cf = 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001985 c = yylex(0);
1986 } while (c == '|');
Eric Andersenff9eee42001-06-29 04:57:14 +00001987 peeksym = c;
1988 word(NOWORD);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001989
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001990 return copyw();
Eric Andersenff9eee42001-06-29 04:57:14 +00001991}
1992
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001993static char **wordlist(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001994{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001995 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00001996
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001997 c = yylex(0);
1998 if (c != IN) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001999 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002000 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00002001 }
2002 startl = 0;
2003 while ((c = yylex(0)) == WORD)
2004 word(yylval.cp);
2005 word(NOWORD);
2006 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002007 return copyw();
Eric Andersenff9eee42001-06-29 04:57:14 +00002008}
2009
2010/*
2011 * supporting functions
2012 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002013static struct op *list(struct op *t1, struct op *t2)
Eric Andersenff9eee42001-06-29 04:57:14 +00002014{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002015 DBGPRINTF7(("LIST: enter, t1=%p, t2=%p\n", t1, t2));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002016
Eric Andersenff9eee42001-06-29 04:57:14 +00002017 if (t1 == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002018 return t2;
Eric Andersenff9eee42001-06-29 04:57:14 +00002019 if (t2 == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002020 return t1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002021
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002022 return block(TLIST, t1, t2, NOWORDS);
Eric Andersenff9eee42001-06-29 04:57:14 +00002023}
2024
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002025static struct op *block(int type, struct op *t1, struct op *t2, char **wp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002026{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002027 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002028
2029 DBGPRINTF7(("BLOCK: enter, type=%d (%s)\n", type, T_CMD_NAMES[type]));
Eric Andersenff9eee42001-06-29 04:57:14 +00002030
2031 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002032 t->op_type = type;
Eric Andersenff9eee42001-06-29 04:57:14 +00002033 t->left = t1;
2034 t->right = t2;
Denis Vlasenko509697f2008-03-02 12:49:39 +00002035 t->op_words = wp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002036
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002037 DBGPRINTF7(("BLOCK: inserted %p between %p and %p\n", t, t1, t2));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002038
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002039 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002040}
2041
Eric Andersen12de6cf2004-08-04 19:19:10 +00002042/* See if given string is a shell multiline (FOR, IF, etc) */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002043static int rlookup(char *n)
Eric Andersenff9eee42001-06-29 04:57:14 +00002044{
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002045 struct res {
2046 char r_name[6];
2047 int16_t r_val;
2048 };
2049 static const struct res restab[] = {
2050 { "for" , FOR },
2051 { "case" , CASE },
2052 { "esac" , ESAC },
2053 { "while", WHILE },
2054 { "do" , DO },
2055 { "done" , DONE },
2056 { "if" , IF },
2057 { "in" , IN },
2058 { "then" , THEN },
2059 { "else" , ELSE },
2060 { "elif" , ELIF },
2061 { "until", UNTIL },
2062 { "fi" , FI },
2063 { ";;" , BREAK },
2064 { "||" , LOGOR },
2065 { "&&" , LOGAND },
2066 { "{" , '{' },
2067 { "}" , '}' },
2068 { "." , DOT },
2069 { },
2070 };
2071
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002072 const struct res *rp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002073
2074 DBGPRINTF7(("RLOOKUP: enter, n is %s\n", n));
Eric Andersenff9eee42001-06-29 04:57:14 +00002075
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002076 for (rp = restab; rp->r_name[0]; rp++)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002077 if (strcmp(rp->r_name, n) == 0) {
2078 DBGPRINTF7(("RLOOKUP: match, returning %d\n", rp->r_val));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002079 return rp->r_val; /* Return numeric code for shell multiline */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002080 }
2081
2082 DBGPRINTF7(("RLOOKUP: NO match, returning 0\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002083 return 0; /* Not a shell multiline */
Eric Andersenff9eee42001-06-29 04:57:14 +00002084}
2085
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002086static struct op *newtp(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002087{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002088 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002089
Eric Andersen8401eea2004-08-04 19:16:54 +00002090 t = (struct op *) tree(sizeof(*t));
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002091 memset(t, 0, sizeof(*t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002092
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002093 DBGPRINTF3(("NEWTP: allocated %p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002094
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002095 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002096}
2097
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002098static struct op *namelist(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00002099{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002100 DBGPRINTF7(("NAMELIST: enter, t=%p, type %s, iolist=%p\n", t,
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002101 T_CMD_NAMES[t->op_type], iolist));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002102
Eric Andersenff9eee42001-06-29 04:57:14 +00002103 if (iolist) {
Eric Andersen8401eea2004-08-04 19:16:54 +00002104 iolist = addword((char *) NULL, iolist);
Eric Andersenff9eee42001-06-29 04:57:14 +00002105 t->ioact = copyio();
2106 } else
2107 t->ioact = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002108
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002109 if (t->op_type != TCOM) {
2110 if (t->op_type != TPAREN && t->ioact != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002111 t = block(TPAREN, t, NOBLOCK, NOWORDS);
2112 t->ioact = t->left->ioact;
2113 t->left->ioact = NULL;
2114 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002115 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002116 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002117
Eric Andersenff9eee42001-06-29 04:57:14 +00002118 word(NOWORD);
Denis Vlasenko509697f2008-03-02 12:49:39 +00002119 t->op_words = copyw();
Eric Andersen12de6cf2004-08-04 19:19:10 +00002120
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002121 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002122}
2123
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002124static char **copyw(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002125{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002126 char **wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00002127
2128 wd = getwords(wdlist);
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002129 wdlist = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002130 return wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00002131}
2132
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002133static void word(char *cp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002134{
2135 wdlist = addword(cp, wdlist);
2136}
2137
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002138static struct ioword **copyio(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002139{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002140 struct ioword **iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002141
2142 iop = (struct ioword **) getwords(iolist);
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002143 iolist = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002144 return iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002145}
2146
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002147static struct ioword *io(int u, int f, char *cp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002148{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002149 struct ioword *iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002150
2151 iop = (struct ioword *) tree(sizeof(*iop));
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002152 iop->io_fd = u;
Eric Andersenff9eee42001-06-29 04:57:14 +00002153 iop->io_flag = f;
2154 iop->io_name = cp;
Eric Andersen8401eea2004-08-04 19:16:54 +00002155 iolist = addword((char *) iop, iolist);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002156 return iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002157}
2158
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002159static int yylex(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00002160{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002161 int c, c1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002162 int atstart;
2163
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002164 c = peeksym;
2165 if (c > 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002166 peeksym = 0;
2167 if (c == '\n')
2168 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002169 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002170 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002171
Eric Andersenff9eee42001-06-29 04:57:14 +00002172 nlseen = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002173 atstart = startl;
2174 startl = 0;
2175 yylval.i = 0;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002176 global_env.linep = line;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002177
2178/* MALAMO */
2179 line[LINELIM - 1] = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00002180
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002181 loop:
Eric Andersen12de6cf2004-08-04 19:19:10 +00002182 while ((c = my_getc(0)) == ' ' || c == '\t') /* Skip whitespace */
Denis Vlasenko509697f2008-03-02 12:49:39 +00002183 continue;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002184
Eric Andersenff9eee42001-06-29 04:57:14 +00002185 switch (c) {
2186 default:
2187 if (any(c, "0123456789")) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002188 c1 = my_getc(0);
2189 unget(c1);
Eric Andersenff9eee42001-06-29 04:57:14 +00002190 if (c1 == '<' || c1 == '>') {
2191 iounit = c - '0';
2192 goto loop;
2193 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002194 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002195 c = c1;
2196 }
2197 break;
2198
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002199 case '#': /* Comment, skip to next newline or End-of-string */
Denis Vlasenko509697f2008-03-02 12:49:39 +00002200 while ((c = my_getc(0)) != '\0' && c != '\n')
2201 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00002202 unget(c);
2203 goto loop;
2204
2205 case 0:
Eric Andersen12de6cf2004-08-04 19:19:10 +00002206 DBGPRINTF5(("YYLEX: return 0, c=%d\n", c));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002207 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002208
2209 case '$':
Eric Andersen12de6cf2004-08-04 19:19:10 +00002210 DBGPRINTF9(("YYLEX: found $\n"));
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002211 *global_env.linep++ = c;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002212 c = my_getc(0);
2213 if (c == '{') {
2214 c = collect(c, '}');
2215 if (c != '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002216 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002217 goto pack;
2218 }
2219 break;
2220
2221 case '`':
2222 case '\'':
2223 case '"':
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002224 c = collect(c, c);
2225 if (c != '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002226 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002227 goto pack;
2228
2229 case '|':
2230 case '&':
2231 case ';':
Eric Andersenff9eee42001-06-29 04:57:14 +00002232 startl = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002233 /* If more chars process them, else return NULL char */
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002234 c1 = dual(c);
2235 if (c1 != '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002236 return c1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002237 return c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002238
Eric Andersenff9eee42001-06-29 04:57:14 +00002239 case '^':
2240 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002241 return '|';
Eric Andersenff9eee42001-06-29 04:57:14 +00002242 case '>':
2243 case '<':
2244 diag(c);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002245 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002246
2247 case '\n':
2248 nlseen++;
2249 gethere();
2250 startl = 1;
2251 if (multiline || cf & CONTIN) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002252 if (interactive && global_env.iop <= iostack) {
Denis Vlasenko38f63192007-01-22 09:03:07 +00002253#if ENABLE_FEATURE_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00002254 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00002255#else
Eric Andersen8401eea2004-08-04 19:16:54 +00002256 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00002257#endif
2258 }
2259 if (cf & CONTIN)
2260 goto loop;
2261 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002262 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002263
2264 case '(':
2265 case ')':
2266 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002267 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002268 }
2269
2270 unget(c);
2271
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002272 pack:
2273 while ((c = my_getc(0)) != '\0' && !any(c, "`$ '\"\t;&<>()|^\n")) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002274 if (global_env.linep >= elinep)
Eric Andersenff9eee42001-06-29 04:57:14 +00002275 err("word too long");
2276 else
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002277 *global_env.linep++ = c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002278 };
2279
Eric Andersenff9eee42001-06-29 04:57:14 +00002280 unget(c);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002281
Eric Andersen8401eea2004-08-04 19:16:54 +00002282 if (any(c, "\"'`$"))
Eric Andersenff9eee42001-06-29 04:57:14 +00002283 goto loop;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002284
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002285 *global_env.linep++ = '\0';
Eric Andersen12de6cf2004-08-04 19:19:10 +00002286
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002287 if (atstart) {
2288 c = rlookup(line);
2289 if (c != 0) {
2290 startl = 1;
2291 return c;
2292 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002293 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002294
Eric Andersenff9eee42001-06-29 04:57:14 +00002295 yylval.cp = strsave(line, areanum);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002296 return WORD;
Eric Andersenff9eee42001-06-29 04:57:14 +00002297}
2298
Eric Andersen12de6cf2004-08-04 19:19:10 +00002299
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002300static int collect(int c, int c1)
Eric Andersenff9eee42001-06-29 04:57:14 +00002301{
2302 char s[2];
2303
Eric Andersen12de6cf2004-08-04 19:19:10 +00002304 DBGPRINTF8(("COLLECT: enter, c=%d, c1=%d\n", c, c1));
2305
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002306 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002307 while ((c = my_getc(c1)) != c1) {
2308 if (c == 0) {
2309 unget(c);
2310 s[0] = c1;
2311 s[1] = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00002312 prs("no closing ");
2313 yyerror(s);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002314 return YYERRCODE;
Eric Andersenff9eee42001-06-29 04:57:14 +00002315 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002316 if (interactive && c == '\n' && global_env.iop <= iostack) {
Denis Vlasenko38f63192007-01-22 09:03:07 +00002317#if ENABLE_FEATURE_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00002318 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00002319#else
Eric Andersen8401eea2004-08-04 19:16:54 +00002320 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00002321#endif
2322 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002323 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002324 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002325
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002326 *global_env.linep++ = c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002327
2328 DBGPRINTF8(("COLLECT: return 0, line is %s\n", line));
2329
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002330 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002331}
2332
Eric Andersen12de6cf2004-08-04 19:19:10 +00002333/* "multiline commands" helper func */
2334/* see if next 2 chars form a shell multiline */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002335static int dual(int c)
Eric Andersenff9eee42001-06-29 04:57:14 +00002336{
2337 char s[3];
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002338 char *cp = s;
Eric Andersenff9eee42001-06-29 04:57:14 +00002339
Eric Andersen12de6cf2004-08-04 19:19:10 +00002340 DBGPRINTF8(("DUAL: enter, c=%d\n", c));
2341
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002342 *cp++ = c; /* c is the given "peek" char */
2343 *cp++ = my_getc(0); /* get next char of input */
2344 *cp = '\0'; /* add EOS marker */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002345
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002346 c = rlookup(s); /* see if 2 chars form a shell multiline */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002347 if (c == 0)
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002348 unget(*--cp); /* String is not a shell multiline, put peek char back */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002349
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002350 return c; /* String is multiline, return numeric multiline (restab) code */
Eric Andersenff9eee42001-06-29 04:57:14 +00002351}
2352
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002353static void diag(int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00002354{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002355 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002356
2357 DBGPRINTF8(("DIAG: enter, ec=%d\n", ec));
Eric Andersenff9eee42001-06-29 04:57:14 +00002358
2359 c = my_getc(0);
2360 if (c == '>' || c == '<') {
2361 if (c != ec)
2362 zzerr();
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002363 yylval.i = (ec == '>' ? IOWRITE | IOCAT : IOHERE);
Eric Andersenff9eee42001-06-29 04:57:14 +00002364 c = my_getc(0);
2365 } else
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002366 yylval.i = (ec == '>' ? IOWRITE : IOREAD);
Eric Andersenff9eee42001-06-29 04:57:14 +00002367 if (c != '&' || yylval.i == IOHERE)
2368 unget(c);
2369 else
2370 yylval.i |= IODUP;
2371}
2372
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002373static char *tree(unsigned size)
Eric Andersenff9eee42001-06-29 04:57:14 +00002374{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002375 char *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002376
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002377 t = getcell(size);
2378 if (t == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002379 DBGPRINTF2(("TREE: getcell(%d) failed!\n", size));
Eric Andersenff9eee42001-06-29 04:57:14 +00002380 prs("command line too complicated\n");
2381 fail();
2382 /* NOTREACHED */
2383 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002384 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002385}
2386
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002387
Eric Andersenff9eee42001-06-29 04:57:14 +00002388/* VARARGS1 */
2389/* ARGSUSED */
2390
2391/* -------- exec.c -------- */
2392
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002393static struct op **find1case(struct op *t, const char *w)
2394{
2395 struct op *t1;
2396 struct op **tp;
2397 char **wp;
2398 char *cp;
2399
2400 if (t == NULL) {
2401 DBGPRINTF3(("FIND1CASE: enter, t==NULL, returning.\n"));
2402 return NULL;
2403 }
2404
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002405 DBGPRINTF3(("FIND1CASE: enter, t->op_type=%d (%s)\n", t->op_type,
2406 T_CMD_NAMES[t->op_type]));
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002407
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002408 if (t->op_type == TLIST) {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002409 tp = find1case(t->left, w);
2410 if (tp != NULL) {
2411 DBGPRINTF3(("FIND1CASE: found one to the left, returning tp=%p\n", tp));
2412 return tp;
2413 }
2414 t1 = t->right; /* TPAT */
2415 } else
2416 t1 = t;
2417
Denis Vlasenko509697f2008-03-02 12:49:39 +00002418 for (wp = t1->op_words; *wp;) {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002419 cp = evalstr(*wp++, DOSUB);
2420 if (cp && gmatch(w, cp)) {
2421 DBGPRINTF3(("FIND1CASE: returning &t1->left= %p.\n",
2422 &t1->left));
2423 return &t1->left;
2424 }
2425 }
2426
2427 DBGPRINTF(("FIND1CASE: returning NULL\n"));
2428 return NULL;
2429}
2430
2431static struct op *findcase(struct op *t, const char *w)
2432{
2433 struct op **tp;
2434
2435 tp = find1case(t, w);
2436 return tp != NULL ? *tp : NULL;
2437}
2438
Eric Andersenff9eee42001-06-29 04:57:14 +00002439/*
2440 * execute tree
2441 */
2442
Denis Vlasenko7e497522008-02-12 09:51:03 +00002443static int execute(struct op *t, int *pin, int *pout, int no_fork)
Eric Andersenff9eee42001-06-29 04:57:14 +00002444{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002445 struct op *t1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002446 volatile int i, rv, a;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002447 const char *cp;
2448 char **wp, **wp2;
Eric Andersenff9eee42001-06-29 04:57:14 +00002449 struct var *vp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002450 struct op *outtree_save;
Eric Andersenff9eee42001-06-29 04:57:14 +00002451 struct brkcon bc;
2452
2453#if __GNUC__
2454 /* Avoid longjmp clobbering */
2455 (void) &wp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002456#endif
Eric Andersenff9eee42001-06-29 04:57:14 +00002457
Eric Andersen12de6cf2004-08-04 19:19:10 +00002458 if (t == NULL) {
2459 DBGPRINTF4(("EXECUTE: enter, t==null, returning.\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002460 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002461 }
2462
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002463 DBGPRINTF(("EXECUTE: t=%p, t->op_type=%d (%s), t->op_words is %s\n", t,
2464 t->op_type, T_CMD_NAMES[t->op_type],
Denis Vlasenko509697f2008-03-02 12:49:39 +00002465 ((t->op_words == NULL) ? "NULL" : t->op_words[0])));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002466
Eric Andersenff9eee42001-06-29 04:57:14 +00002467 rv = 0;
2468 a = areanum++;
Denis Vlasenko509697f2008-03-02 12:49:39 +00002469 wp2 = t->op_words;
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002470 wp = (wp2 != NULL)
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002471 ? eval(wp2, t->op_type == TCOM ? DOALL : DOALL & ~DOKEY)
Eric Andersen8401eea2004-08-04 19:16:54 +00002472 : NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00002473
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002474 switch (t->op_type) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002475 case TDOT:
2476 DBGPRINTF3(("EXECUTE: TDOT\n"));
2477
2478 outtree_save = outtree;
2479
Denis Vlasenko509697f2008-03-02 12:49:39 +00002480 newfile(evalstr(t->op_words[0], DOALL));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002481
Denis Vlasenko68404f12008-03-17 09:00:54 +00002482 t->left = dowholefile(TLIST /*, 0*/);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002483 t->right = NULL;
2484
2485 outtree = outtree_save;
2486
2487 if (t->left)
Denis Vlasenko7e497522008-02-12 09:51:03 +00002488 rv = execute(t->left, pin, pout, /* no_fork: */ 0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002489 if (t->right)
Denis Vlasenko7e497522008-02-12 09:51:03 +00002490 rv = execute(t->right, pin, pout, /* no_fork: */ 0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002491 break;
2492
Eric Andersenff9eee42001-06-29 04:57:14 +00002493 case TPAREN:
Denis Vlasenko7e497522008-02-12 09:51:03 +00002494 rv = execute(t->left, pin, pout, /* no_fork: */ 0);
Eric Andersen737f5fb2003-03-14 16:05:59 +00002495 break;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002496
Eric Andersenff9eee42001-06-29 04:57:14 +00002497 case TCOM:
Denis Vlasenko7e497522008-02-12 09:51:03 +00002498 rv = forkexec(t, pin, pout, no_fork, wp);
Eric Andersenff9eee42001-06-29 04:57:14 +00002499 break;
2500
2501 case TPIPE:
2502 {
Eric Andersen8401eea2004-08-04 19:16:54 +00002503 int pv[2];
2504
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002505 rv = openpipe(pv);
2506 if (rv < 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00002507 break;
2508 pv[0] = remap(pv[0]);
2509 pv[1] = remap(pv[1]);
Denis Vlasenko7e497522008-02-12 09:51:03 +00002510 (void) execute(t->left, pin, pv, /* no_fork: */ 0);
2511 rv = execute(t->right, pv, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002512 }
2513 break;
2514
2515 case TLIST:
Denis Vlasenko7e497522008-02-12 09:51:03 +00002516 (void) execute(t->left, pin, pout, /* no_fork: */ 0);
2517 rv = execute(t->right, pin, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002518 break;
2519
2520 case TASYNC:
Eric Andersen8401eea2004-08-04 19:16:54 +00002521 {
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002522 smallint hinteractive = interactive;
Eric Andersenff9eee42001-06-29 04:57:14 +00002523
Eric Andersen12de6cf2004-08-04 19:19:10 +00002524 DBGPRINTF7(("EXECUTE: TASYNC clause, calling vfork()...\n"));
2525
Eric Andersen8401eea2004-08-04 19:16:54 +00002526 i = vfork();
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002527 if (i == 0) { /* child */
Eric Andersen8401eea2004-08-04 19:16:54 +00002528 signal(SIGINT, SIG_IGN);
2529 signal(SIGQUIT, SIG_IGN);
2530 if (interactive)
2531 signal(SIGTERM, SIG_DFL);
2532 interactive = 0;
2533 if (pin == NULL) {
2534 close(0);
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00002535 xopen(bb_dev_null, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00002536 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002537 _exit(execute(t->left, pin, pout, /* no_fork: */ 1));
Eric Andersenff9eee42001-06-29 04:57:14 +00002538 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002539 interactive = hinteractive;
2540 if (i != -1) {
2541 setval(lookup("!"), putn(i));
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002542 closepipe(pin);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002543 if (interactive) {
2544 prs(putn(i));
2545 prs("\n");
2546 }
2547 } else
2548 rv = -1;
2549 setstatus(rv);
Eric Andersenff9eee42001-06-29 04:57:14 +00002550 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002551 break;
2552
2553 case TOR:
2554 case TAND:
Denis Vlasenko7e497522008-02-12 09:51:03 +00002555 rv = execute(t->left, pin, pout, /* no_fork: */ 0);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002556 t1 = t->right;
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002557 if (t1 != NULL && (rv == 0) == (t->op_type == TAND))
Denis Vlasenko7e497522008-02-12 09:51:03 +00002558 rv = execute(t1, pin, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002559 break;
2560
2561 case TFOR:
2562 if (wp == NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00002563 wp = dolv + 1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002564 i = dolc;
2565 if (i < 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00002566 i = 0;
2567 } else {
2568 i = -1;
Denis Vlasenko509697f2008-03-02 12:49:39 +00002569 while (*wp++ != NULL)
2570 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00002571 }
2572 vp = lookup(t->str);
2573 while (setjmp(bc.brkpt))
2574 if (isbreak)
2575 goto broken;
2576 brkset(&bc);
2577 for (t1 = t->left; i-- && *wp != NULL;) {
2578 setval(vp, *wp++);
Denis Vlasenko7e497522008-02-12 09:51:03 +00002579 rv = execute(t1, pin, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002580 }
2581 brklist = brklist->nextlev;
2582 break;
2583
2584 case TWHILE:
2585 case TUNTIL:
2586 while (setjmp(bc.brkpt))
2587 if (isbreak)
2588 goto broken;
2589 brkset(&bc);
2590 t1 = t->left;
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002591 while ((execute(t1, pin, pout, /* no_fork: */ 0) == 0) == (t->op_type == TWHILE))
Denis Vlasenko7e497522008-02-12 09:51:03 +00002592 rv = execute(t->right, pin, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002593 brklist = brklist->nextlev;
2594 break;
2595
2596 case TIF:
2597 case TELIF:
Eric Andersen8401eea2004-08-04 19:16:54 +00002598 if (t->right != NULL) {
Denis Vlasenko7e497522008-02-12 09:51:03 +00002599 rv = !execute(t->left, pin, pout, /* no_fork: */ 0) ?
2600 execute(t->right->left, pin, pout, /* no_fork: */ 0) :
2601 execute(t->right->right, pin, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002602 }
2603 break;
2604
2605 case TCASE:
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002606 cp = evalstr(t->str, DOSUB | DOTRIM);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002607 if (cp == NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00002608 cp = "";
Eric Andersen12de6cf2004-08-04 19:19:10 +00002609
2610 DBGPRINTF7(("EXECUTE: TCASE, t->str is %s, cp is %s\n",
2611 ((t->str == NULL) ? "NULL" : t->str),
2612 ((cp == NULL) ? "NULL" : cp)));
2613
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002614 t1 = findcase(t->left, cp);
2615 if (t1 != NULL) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002616 DBGPRINTF7(("EXECUTE: TCASE, calling execute(t=%p, t1=%p)...\n", t, t1));
Denis Vlasenko7e497522008-02-12 09:51:03 +00002617 rv = execute(t1, pin, pout, /* no_fork: */ 0);
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002618 DBGPRINTF7(("EXECUTE: TCASE, back from execute(t=%p, t1=%p)...\n", t, t1));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002619 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002620 break;
2621
2622 case TBRACE:
2623/*
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002624 iopp = t->ioact;
2625 if (i)
Eric Andersenff9eee42001-06-29 04:57:14 +00002626 while (*iopp)
2627 if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) {
2628 rv = -1;
2629 break;
2630 }
2631*/
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002632 if (rv >= 0) {
2633 t1 = t->left;
2634 if (t1) {
Denis Vlasenko7e497522008-02-12 09:51:03 +00002635 rv = execute(t1, pin, pout, /* no_fork: */ 0);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002636 }
2637 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002638 break;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002639
2640 };
Eric Andersenff9eee42001-06-29 04:57:14 +00002641
Denis Vlasenkoe4712752007-04-14 15:08:41 +00002642 broken:
Denis Vlasenko509697f2008-03-02 12:49:39 +00002643// Restoring op_words is most likely not needed now: see comment in forkexec()
2644// (also take a look at exec builtin (doexec) - it touches t->op_words)
2645 t->op_words = wp2;
Eric Andersenff9eee42001-06-29 04:57:14 +00002646 isbreak = 0;
2647 freehere(areanum);
2648 freearea(areanum);
2649 areanum = a;
2650 if (interactive && intr) {
2651 closeall();
2652 fail();
2653 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002654
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002655 i = trapset;
2656 if (i != 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002657 trapset = 0;
2658 runtrap(i);
2659 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002660
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002661 DBGPRINTF(("EXECUTE: returning from t=%p, rv=%d\n", t, rv));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002662 return rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00002663}
2664
Denis Vlasenkoe4712752007-04-14 15:08:41 +00002665static builtin_func_ptr inbuilt(const char *s)
2666{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002667 const struct builtincmd *bp;
2668
Denis Vlasenko95cb3262007-04-09 03:06:34 +00002669 for (bp = builtincmds; bp->name; bp++)
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002670 if (strcmp(bp->name, s) == 0)
2671 return bp->builtinfunc;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002672 return NULL;
2673}
2674
Denis Vlasenko7e497522008-02-12 09:51:03 +00002675static int forkexec(struct op *t, int *pin, int *pout, int no_fork, char **wp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002676{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002677 pid_t newpid;
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002678 int i;
2679 builtin_func_ptr bltin = NULL;
Denis Vlasenko7e497522008-02-12 09:51:03 +00002680 const char *bltin_name = NULL;
2681 const char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00002682 struct ioword **iopp;
2683 int resetsig;
2684 char **owp;
Denis Vlasenko7e497522008-02-12 09:51:03 +00002685 int forked;
Eric Andersenff9eee42001-06-29 04:57:14 +00002686
2687 int *hpin = pin;
2688 int *hpout = pout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002689 char *hwp;
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002690 smallint hinteractive;
2691 smallint hintr;
2692 smallint hexecflg;
Eric Andersen8401eea2004-08-04 19:16:54 +00002693 struct brkcon *hbrklist;
Eric Andersenff9eee42001-06-29 04:57:14 +00002694
2695#if __GNUC__
2696 /* Avoid longjmp clobbering */
2697 (void) &pin;
2698 (void) &pout;
2699 (void) &wp;
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002700 (void) &bltin;
Eric Andersenff9eee42001-06-29 04:57:14 +00002701 (void) &cp;
2702 (void) &resetsig;
2703 (void) &owp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002704#endif
Eric Andersenff9eee42001-06-29 04:57:14 +00002705
Denis Vlasenko7e497522008-02-12 09:51:03 +00002706 DBGPRINTF(("FORKEXEC: t=%p, pin %p, pout %p, no_fork %d\n", t, pin,
2707 pout, no_fork));
Denis Vlasenko509697f2008-03-02 12:49:39 +00002708 DBGPRINTF7(("FORKEXEC: t->op_words is %s\n",
2709 ((t->op_words == NULL) ? "NULL" : t->op_words[0])));
Eric Andersenff9eee42001-06-29 04:57:14 +00002710 owp = wp;
2711 resetsig = 0;
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002712 if (t->op_type == TCOM) {
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00002713 while (*wp++ != NULL)
2714 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00002715 cp = *wp;
2716
2717 /* strip all initial assignments */
Denis Vlasenko7e497522008-02-12 09:51:03 +00002718 /* FIXME: not correct wrt PATH=yyy command etc */
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00002719 if (FLAG['x']) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002720 DBGPRINTF9(("FORKEXEC: echo'ing, cp=%p, wp=%p, owp=%p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00002721 cp, wp, owp));
Eric Andersen8401eea2004-08-04 19:16:54 +00002722 echo(cp ? wp : owp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002723 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002724
Denis Vlasenko7e497522008-02-12 09:51:03 +00002725 if (cp == NULL) {
2726 if (t->ioact == NULL) {
2727 while ((cp = *owp++) != NULL && assign(cp, COPYV))
2728 continue;
2729 DBGPRINTF(("FORKEXEC: returning setstatus(0)\n"));
2730 return setstatus(0);
2731 }
2732 } else { /* cp != NULL */
2733 bltin_name = cp;
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002734 bltin = inbuilt(cp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002735 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002736 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002737
Denis Vlasenko7e497522008-02-12 09:51:03 +00002738 forked = 0;
Denis Vlasenko509697f2008-03-02 12:49:39 +00002739 // We were pointing t->op_words to temporary (expanded) arg list:
2740 // t->op_words = wp;
Denis Vlasenkofe218832008-03-01 09:35:39 +00002741 // and restored it later (in execute()), but "break"
Denis Vlasenko509697f2008-03-02 12:49:39 +00002742 // longjmps away (at "Run builtin" below), leaving t->op_words clobbered!
Denis Vlasenkofe218832008-03-01 09:35:39 +00002743 // See http://bugs.busybox.net/view.php?id=846.
Denis Vlasenko509697f2008-03-02 12:49:39 +00002744 // Now we do not touch t->op_words, but separately pass wp as param list
Denis Vlasenko42cc3042008-03-24 02:05:58 +00002745 // to builtins
Denis Vlasenko7e497522008-02-12 09:51:03 +00002746 DBGPRINTF(("FORKEXEC: bltin %p, no_fork %d, owp %p\n", bltin,
2747 no_fork, owp));
2748 /* Don't fork if it is a lone builtin (not in pipe)
2749 * OR we are told to _not_ fork */
2750 if ((!bltin || pin || pout) /* not lone bltin AND */
2751 && !no_fork /* not told to avoid fork */
2752 ) {
2753 /* Save values in case child alters them after vfork */
Eric Andersenff9eee42001-06-29 04:57:14 +00002754 hpin = pin;
2755 hpout = pout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002756 hwp = *wp;
2757 hinteractive = interactive;
2758 hintr = intr;
2759 hbrklist = brklist;
2760 hexecflg = execflg;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002761
Eric Andersen12de6cf2004-08-04 19:19:10 +00002762 DBGPRINTF3(("FORKEXEC: calling vfork()...\n"));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002763 newpid = vfork();
Eric Andersen12de6cf2004-08-04 19:19:10 +00002764 if (newpid == -1) {
Denis Vlasenko89f0b342006-11-18 22:04:09 +00002765 DBGPRINTF(("FORKEXEC: ERROR, cannot vfork()!\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002766 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002767 }
2768
Denis Vlasenko489f93e2007-02-01 01:43:16 +00002769 if (newpid > 0) { /* Parent */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002770 /* Restore values */
Eric Andersenff9eee42001-06-29 04:57:14 +00002771 pin = hpin;
2772 pout = hpout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002773 *wp = hwp;
2774 interactive = hinteractive;
2775 intr = hintr;
2776 brklist = hbrklist;
2777 execflg = hexecflg;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002778
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002779 closepipe(pin);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002780 return (pout == NULL ? setstatus(waitfor(newpid, 0)) : 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002781 }
2782
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002783 /* Child */
Denis Vlasenko7e497522008-02-12 09:51:03 +00002784 DBGPRINTF(("FORKEXEC: child process, bltin=%p (%s)\n", bltin, bltin_name));
Eric Andersenff9eee42001-06-29 04:57:14 +00002785 if (interactive) {
2786 signal(SIGINT, SIG_IGN);
2787 signal(SIGQUIT, SIG_IGN);
2788 resetsig = 1;
2789 }
2790 interactive = 0;
2791 intr = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002792 forked = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002793 brklist = 0;
2794 execflg = 0;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002795 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002796
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002797 if (owp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002798 while ((cp = *owp++) != NULL && assign(cp, COPYV))
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002799 if (!bltin)
Eric Andersenff9eee42001-06-29 04:57:14 +00002800 export(lookup(cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002801
Denis Vlasenko284d0fa2008-02-16 13:18:17 +00002802 if (pin) { /* NB: close _first_, then move fds! */
2803 close(pin[1]);
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00002804 xmove_fd(pin[0], 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002805 }
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002806 if (pout) {
Denis Vlasenko284d0fa2008-02-16 13:18:17 +00002807 close(pout[0]);
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00002808 xmove_fd(pout[1], 1);
Eric Andersenff9eee42001-06-29 04:57:14 +00002809 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002810
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002811 iopp = t->ioact;
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002812 if (iopp) {
2813 if (bltin && bltin != doexec) {
Denis Vlasenko7e497522008-02-12 09:51:03 +00002814 prs(bltin_name);
Eric Andersenff9eee42001-06-29 04:57:14 +00002815 err(": cannot redirect shell command");
Eric Andersen12de6cf2004-08-04 19:19:10 +00002816 if (forked)
2817 _exit(-1);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002818 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002819 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002820 while (*iopp) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002821 if (iosetup(*iopp++, pin != NULL, pout != NULL)) {
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002822 /* system-detected error */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002823 if (forked)
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002824 _exit(-1);
2825 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002826 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002827 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002828 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002829
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002830 if (bltin) {
Denis Vlasenko7e497522008-02-12 09:51:03 +00002831 if (forked || pin || pout) {
2832 /* Builtin in pipe: disallowed */
2833 /* TODO: allow "exec"? */
2834 prs(bltin_name);
2835 err(": cannot run builtin as part of pipe");
2836 if (forked)
2837 _exit(-1);
2838 return -1;
2839 }
Denis Vlasenkofe218832008-03-01 09:35:39 +00002840 /* Run builtin */
2841 i = setstatus(bltin(t, wp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002842 if (forked)
2843 _exit(i);
2844 DBGPRINTF(("FORKEXEC: returning i=%d\n", i));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002845 return i;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002846 }
2847
Eric Andersenff9eee42001-06-29 04:57:14 +00002848 /* should use FIOCEXCL */
Eric Andersen8401eea2004-08-04 19:16:54 +00002849 for (i = FDBASE; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00002850 close(i);
2851 if (resetsig) {
2852 signal(SIGINT, SIG_DFL);
2853 signal(SIGQUIT, SIG_DFL);
2854 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002855
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002856 if (t->op_type == TPAREN)
Denis Vlasenko7e497522008-02-12 09:51:03 +00002857 _exit(execute(t->left, NOPIPE, NOPIPE, /* no_fork: */ 1));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002858 if (wp[0] == NULL)
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +00002859 _exit(EXIT_SUCCESS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002860
Eric Andersenfd7a4c82004-09-02 23:13:10 +00002861 cp = rexecve(wp[0], wp, makenv(0, NULL));
Eric Andersen8401eea2004-08-04 19:16:54 +00002862 prs(wp[0]);
2863 prs(": ");
Eric Andersen12de6cf2004-08-04 19:19:10 +00002864 err(cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00002865 if (!execflg)
2866 trap[0] = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002867
Denis Vlasenko7e497522008-02-12 09:51:03 +00002868 DBGPRINTF(("FORKEXEC: calling leave(), pid=%d\n", getpid()));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002869
Eric Andersenff9eee42001-06-29 04:57:14 +00002870 leave();
2871 /* NOTREACHED */
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002872 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002873}
2874
2875/*
2876 * 0< 1> are ignored as required
2877 * within pipelines.
2878 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002879static int iosetup(struct ioword *iop, int pipein, int pipeout)
Eric Andersenff9eee42001-06-29 04:57:14 +00002880{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002881 int u = -1;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002882 char *cp = NULL;
2883 const char *msg;
Eric Andersenff9eee42001-06-29 04:57:14 +00002884
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002885 DBGPRINTF(("IOSETUP: iop %p, pipein %i, pipeout %i\n", iop,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002886 pipein, pipeout));
2887
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002888 if (iop->io_fd == IODEFAULT) /* take default */
2889 iop->io_fd = iop->io_flag & (IOREAD | IOHERE) ? 0 : 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002890
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002891 if (pipein && iop->io_fd == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002892 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002893
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002894 if (pipeout && iop->io_fd == 1)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002895 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002896
Eric Andersen8401eea2004-08-04 19:16:54 +00002897 msg = iop->io_flag & (IOREAD | IOHERE) ? "open" : "create";
Eric Andersenff9eee42001-06-29 04:57:14 +00002898 if ((iop->io_flag & IOHERE) == 0) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002899 cp = iop->io_name; /* huh?? */
2900 cp = evalstr(cp, DOSUB | DOTRIM);
2901 if (cp == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002902 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002903 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002904
Eric Andersenff9eee42001-06-29 04:57:14 +00002905 if (iop->io_flag & IODUP) {
2906 if (cp[1] || (!isdigit(*cp) && *cp != '-')) {
2907 prs(cp);
2908 err(": illegal >& argument");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002909 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002910 }
2911 if (*cp == '-')
2912 iop->io_flag = IOCLOSE;
Eric Andersen8401eea2004-08-04 19:16:54 +00002913 iop->io_flag &= ~(IOREAD | IOWRITE);
Eric Andersenff9eee42001-06-29 04:57:14 +00002914 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002915
Eric Andersenff9eee42001-06-29 04:57:14 +00002916 switch (iop->io_flag) {
2917 case IOREAD:
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00002918 u = open(cp, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00002919 break;
2920
2921 case IOHERE:
Eric Andersen8401eea2004-08-04 19:16:54 +00002922 case IOHERE | IOXHERE:
2923 u = herein(iop->io_name, iop->io_flag & IOXHERE);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002924 cp = (char*)"here file";
Eric Andersenff9eee42001-06-29 04:57:14 +00002925 break;
2926
Eric Andersen8401eea2004-08-04 19:16:54 +00002927 case IOWRITE | IOCAT:
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00002928 u = open(cp, O_WRONLY);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002929 if (u >= 0) {
Denis Vlasenkoea620772006-10-14 02:23:43 +00002930 lseek(u, (long) 0, SEEK_END);
Eric Andersenff9eee42001-06-29 04:57:14 +00002931 break;
2932 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002933 /* fall through to creation if >>file doesn't exist */
2934
Eric Andersenff9eee42001-06-29 04:57:14 +00002935 case IOWRITE:
2936 u = creat(cp, 0666);
2937 break;
2938
2939 case IODUP:
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002940 u = dup2(*cp - '0', iop->io_fd);
Eric Andersenff9eee42001-06-29 04:57:14 +00002941 break;
2942
2943 case IOCLOSE:
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002944 close(iop->io_fd);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002945 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002946 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002947
Eric Andersenff9eee42001-06-29 04:57:14 +00002948 if (u < 0) {
2949 prs(cp);
2950 prs(": cannot ");
2951 warn(msg);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002952 return 1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002953 }
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002954 xmove_fd(u, iop->io_fd);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002955 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002956}
2957
Eric Andersenff9eee42001-06-29 04:57:14 +00002958/*
2959 * Enter a new loop level (marked for break/continue).
2960 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002961static void brkset(struct brkcon *bc)
Eric Andersenff9eee42001-06-29 04:57:14 +00002962{
2963 bc->nextlev = brklist;
2964 brklist = bc;
2965}
2966
2967/*
2968 * Wait for the last process created.
2969 * Print a message for each process found
2970 * that was killed by a signal.
2971 * Ignore interrupt signals while waiting
2972 * unless `canintr' is true.
2973 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002974static int waitfor(int lastpid, int canintr)
Eric Andersenff9eee42001-06-29 04:57:14 +00002975{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002976 int pid, rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00002977 int s;
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002978 smallint oheedint = heedint;
Eric Andersenff9eee42001-06-29 04:57:14 +00002979
2980 heedint = 0;
2981 rv = 0;
2982 do {
2983 pid = wait(&s);
2984 if (pid == -1) {
2985 if (errno != EINTR || canintr)
2986 break;
2987 } else {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002988 rv = WAITSIG(s);
2989 if (rv != 0) {
Denis Vlasenko80b8b392007-06-25 10:55:35 +00002990 if (rv < ARRAY_SIZE(signame)) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002991 if (signame[rv] != NULL) {
2992 if (pid != lastpid) {
2993 prn(pid);
2994 prs(": ");
2995 }
2996 prs(signame[rv]);
2997 }
2998 } else {
2999 if (pid != lastpid) {
3000 prn(pid);
3001 prs(": ");
3002 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003003 prs("Signal ");
3004 prn(rv);
3005 prs(" ");
Eric Andersenff9eee42001-06-29 04:57:14 +00003006 }
3007 if (WAITCORE(s))
3008 prs(" - core dumped");
Denis Vlasenko80b8b392007-06-25 10:55:35 +00003009 if (rv >= ARRAY_SIZE(signame) || signame[rv])
Eric Andersenff9eee42001-06-29 04:57:14 +00003010 prs("\n");
Mike Frysingerb81f97b2008-05-14 11:51:04 +00003011 rv |= 0x80;
Eric Andersenff9eee42001-06-29 04:57:14 +00003012 } else
3013 rv = WAITVAL(s);
3014 }
3015 } while (pid != lastpid);
3016 heedint = oheedint;
3017 if (intr) {
3018 if (interactive) {
3019 if (canintr)
3020 intr = 0;
3021 } else {
Eric Andersen8401eea2004-08-04 19:16:54 +00003022 if (exstat == 0)
3023 exstat = rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003024 onintr(0);
3025 }
3026 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003027 return rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003028}
3029
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003030static int setstatus(int s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003031{
3032 exstat = s;
3033 setval(lookup("?"), putn(s));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003034 return s;
Eric Andersenff9eee42001-06-29 04:57:14 +00003035}
3036
3037/*
3038 * PATH-searching interface to execve.
3039 * If getenv("PATH") were kept up-to-date,
3040 * execvp might be used.
3041 */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003042static const char *rexecve(char *c, char **v, char **envp)
Eric Andersenff9eee42001-06-29 04:57:14 +00003043{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003044 const char *sp;
3045 char *tp;
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00003046 int asis = 0;
Eric Andersen1c039232001-07-07 00:05:55 +00003047 char *name = c;
Eric Andersen8401eea2004-08-04 19:16:54 +00003048
Denis Vlasenko80d14be2007-04-10 23:03:30 +00003049 if (ENABLE_FEATURE_SH_STANDALONE) {
Denis Vlasenko1aa7e472007-11-28 06:49:03 +00003050 if (find_applet_by_name(name) >= 0) {
Rob Landleya299efb2006-08-10 21:46:43 +00003051 /* We have to exec here since we vforked. Running
Denis Vlasenkoe4f2d062007-04-11 17:03:19 +00003052 * run_applet_and_exit() won't work and bad things
Rob Landleya299efb2006-08-10 21:46:43 +00003053 * will happen. */
Denis Vlasenkobdbbb7e2007-06-08 15:02:55 +00003054 execve(bb_busybox_exec_path, v, envp);
Rob Landleya299efb2006-08-10 21:46:43 +00003055 }
Eric Andersen1c039232001-07-07 00:05:55 +00003056 }
Eric Andersen1c039232001-07-07 00:05:55 +00003057
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003058 DBGPRINTF(("REXECVE: c=%p, v=%p, envp=%p\n", c, v, envp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003059
Eric Andersen8401eea2004-08-04 19:16:54 +00003060 sp = any('/', c) ? "" : path->value;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003061 asis = (*sp == '\0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003062 while (asis || *sp != '\0') {
3063 asis = 0;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003064 tp = global_env.linep;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003065 for (; *sp != '\0'; tp++) {
3066 *tp = *sp++;
3067 if (*tp == ':') {
3068 asis = (*sp == '\0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003069 break;
3070 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003071 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003072 if (tp != global_env.linep)
Eric Andersenff9eee42001-06-29 04:57:14 +00003073 *tp++ = '/';
Denis Vlasenko509697f2008-03-02 12:49:39 +00003074 strcpy(tp, c);
Eric Andersen1c039232001-07-07 00:05:55 +00003075
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003076 DBGPRINTF3(("REXECVE: global_env.linep is %s\n", global_env.linep));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003077
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003078 execve(global_env.linep, v, envp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003079
Eric Andersenff9eee42001-06-29 04:57:14 +00003080 switch (errno) {
3081 case ENOEXEC:
Denis Vlasenko447bd662008-05-30 22:28:32 +00003082 /* File is executable but file format isnt recognized */
3083 /* Run it as a shell script */
3084 /* (execve above didnt do it itself, unlike execvp) */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003085 *v = global_env.linep;
Denis Vlasenko509697f2008-03-02 12:49:39 +00003086 v--;
3087 tp = *v;
Denis Vlasenko447bd662008-05-30 22:28:32 +00003088 *v = (char*)DEFAULT_SHELL;
Glenn L McGrathdc4e75e2003-09-02 02:36:18 +00003089 execve(DEFAULT_SHELL, v, envp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003090 *v = tp;
Denis Vlasenko509697f2008-03-02 12:49:39 +00003091 return "no shell";
Eric Andersenff9eee42001-06-29 04:57:14 +00003092
3093 case ENOMEM:
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003094 return (char *) bb_msg_memory_exhausted;
Eric Andersenff9eee42001-06-29 04:57:14 +00003095
3096 case E2BIG:
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003097 return "argument list too long";
Eric Andersenff9eee42001-06-29 04:57:14 +00003098 }
3099 }
Denis Vlasenko447bd662008-05-30 22:28:32 +00003100 if (errno == ENOENT) {
3101 exstat = 127; /* standards require this */
3102 return "not found";
3103 }
3104 exstat = 126; /* mimic bash */
3105 return "cannot execute";
Eric Andersenff9eee42001-06-29 04:57:14 +00003106}
3107
3108/*
3109 * Run the command produced by generator `f'
3110 * applied to stream `arg'.
3111 */
Eric Andersen8401eea2004-08-04 19:16:54 +00003112static int run(struct ioarg *argp, int (*f) (struct ioarg *))
Eric Andersenff9eee42001-06-29 04:57:14 +00003113{
3114 struct op *otree;
3115 struct wdblock *swdlist;
3116 struct wdblock *siolist;
3117 jmp_buf ev, rt;
3118 xint *ofail;
3119 int rv;
3120
3121#if __GNUC__
3122 /* Avoid longjmp clobbering */
3123 (void) &rv;
3124#endif
3125
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003126 DBGPRINTF(("RUN: enter, areanum %d, outtree %p, failpt %p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00003127 areanum, outtree, failpt));
3128
Eric Andersenff9eee42001-06-29 04:57:14 +00003129 areanum++;
3130 swdlist = wdlist;
3131 siolist = iolist;
3132 otree = outtree;
3133 ofail = failpt;
3134 rv = -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003135
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003136 errpt = ev;
3137 if (newenv(setjmp(errpt)) == 0) {
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00003138 wdlist = NULL;
3139 iolist = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00003140 pushio(argp, f);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003141 global_env.iobase = global_env.iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00003142 yynerrs = 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003143 failpt = rt;
3144 if (setjmp(failpt) == 0 && yyparse() == 0)
Denis Vlasenko7e497522008-02-12 09:51:03 +00003145 rv = execute(outtree, NOPIPE, NOPIPE, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003146 quitenv();
Eric Andersen12de6cf2004-08-04 19:19:10 +00003147 } else {
3148 DBGPRINTF(("RUN: error from newenv()!\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00003149 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00003150
Eric Andersenff9eee42001-06-29 04:57:14 +00003151 wdlist = swdlist;
3152 iolist = siolist;
3153 failpt = ofail;
3154 outtree = otree;
3155 freearea(areanum--);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003156
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003157 return rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003158}
3159
3160/* -------- do.c -------- */
3161
3162/*
3163 * built-in commands: doX
3164 */
3165
Denis Vlasenko68404f12008-03-17 09:00:54 +00003166static int dohelp(struct op *t ATTRIBUTE_UNUSED, char **args ATTRIBUTE_UNUSED)
Eric Andersen1c039232001-07-07 00:05:55 +00003167{
3168 int col;
3169 const struct builtincmd *x;
3170
Denis Vlasenko0ee39992006-12-24 15:23:28 +00003171 puts("\nBuilt-in commands:\n"
3172 "-------------------");
Eric Andersen1c039232001-07-07 00:05:55 +00003173
Denis Vlasenko95cb3262007-04-09 03:06:34 +00003174 col = 0;
3175 x = builtincmds;
3176 while (x->name) {
3177 col += printf("%c%s", ((col == 0) ? '\t' : ' '), x->name);
Eric Andersen1c039232001-07-07 00:05:55 +00003178 if (col > 60) {
Denis Vlasenko4daad902007-09-27 10:20:47 +00003179 bb_putchar('\n');
Eric Andersen1c039232001-07-07 00:05:55 +00003180 col = 0;
3181 }
Denis Vlasenko95cb3262007-04-09 03:06:34 +00003182 x++;
Eric Andersen1c039232001-07-07 00:05:55 +00003183 }
Denis Vlasenko80d14be2007-04-10 23:03:30 +00003184#if ENABLE_FEATURE_SH_STANDALONE
Eric Andersen1c039232001-07-07 00:05:55 +00003185 {
Denis Vlasenko1aa7e472007-11-28 06:49:03 +00003186 const char *applet = applet_names;
Eric Andersen1c039232001-07-07 00:05:55 +00003187
Denis Vlasenko1aa7e472007-11-28 06:49:03 +00003188 while (*applet) {
3189 col += printf("%c%s", ((col == 0) ? '\t' : ' '), applet);
Eric Andersen1c039232001-07-07 00:05:55 +00003190 if (col > 60) {
Denis Vlasenko4daad902007-09-27 10:20:47 +00003191 bb_putchar('\n');
Eric Andersen1c039232001-07-07 00:05:55 +00003192 col = 0;
3193 }
Denis Vlasenko1aa7e472007-11-28 06:49:03 +00003194 applet += strlen(applet) + 1;
Eric Andersen1c039232001-07-07 00:05:55 +00003195 }
3196 }
3197#endif
Denis Vlasenko0ee39992006-12-24 15:23:28 +00003198 puts("\n");
Eric Andersen1c039232001-07-07 00:05:55 +00003199 return EXIT_SUCCESS;
3200}
3201
Denis Vlasenko68404f12008-03-17 09:00:54 +00003202static int dolabel(struct op *t ATTRIBUTE_UNUSED, char **args ATTRIBUTE_UNUSED)
Eric Andersenff9eee42001-06-29 04:57:14 +00003203{
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003204 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003205}
3206
Denis Vlasenko68404f12008-03-17 09:00:54 +00003207static int dochdir(struct op *t ATTRIBUTE_UNUSED, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003208{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003209 const char *cp, *er;
Eric Andersenff9eee42001-06-29 04:57:14 +00003210
Denis Vlasenkofe218832008-03-01 09:35:39 +00003211 cp = args[1];
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003212 if (cp == NULL) {
3213 cp = homedir->value;
Denis Vlasenkod244c5e2007-02-09 17:30:14 +00003214 if (cp != NULL)
3215 goto do_cd;
3216 er = ": no home directory";
3217 } else {
3218 do_cd:
3219 if (chdir(cp) >= 0)
3220 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003221 er = ": bad directory";
Denis Vlasenkod244c5e2007-02-09 17:30:14 +00003222 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003223 prs(cp != NULL ? cp : "cd");
Eric Andersenff9eee42001-06-29 04:57:14 +00003224 err(er);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003225 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003226}
3227
Denis Vlasenko68404f12008-03-17 09:00:54 +00003228static int doshift(struct op *t ATTRIBUTE_UNUSED, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003229{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003230 int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003231
Denis Vlasenkofe218832008-03-01 09:35:39 +00003232 n = args[1] ? getn(args[1]) : 1;
Eric Andersen8401eea2004-08-04 19:16:54 +00003233 if (dolc < n) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003234 err("nothing to shift");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003235 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003236 }
3237 dolv[n] = dolv[0];
3238 dolv += n;
3239 dolc -= n;
3240 setval(lookup("#"), putn(dolc));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003241 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003242}
3243
3244/*
3245 * execute login and newgrp directly
3246 */
Denis Vlasenko68404f12008-03-17 09:00:54 +00003247static int dologin(struct op *t ATTRIBUTE_UNUSED, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003248{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003249 const char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003250
3251 if (interactive) {
3252 signal(SIGINT, SIG_DFL);
3253 signal(SIGQUIT, SIG_DFL);
3254 }
Denis Vlasenkofe218832008-03-01 09:35:39 +00003255 cp = rexecve(args[0], args, makenv(0, NULL));
3256 prs(args[0]);
Eric Andersen8401eea2004-08-04 19:16:54 +00003257 prs(": ");
3258 err(cp);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003259 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003260}
3261
Denis Vlasenko68404f12008-03-17 09:00:54 +00003262static int doumask(struct op *t ATTRIBUTE_UNUSED, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003263{
Denis Vlasenko7e497522008-02-12 09:51:03 +00003264 int i;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003265 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003266
Denis Vlasenkofe218832008-03-01 09:35:39 +00003267 cp = args[1];
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003268 if (cp == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003269 i = umask(0);
3270 umask(i);
Denis Vlasenko7e497522008-02-12 09:51:03 +00003271 printf("%04o\n", i);
Eric Andersenff9eee42001-06-29 04:57:14 +00003272 } else {
Denis Vlasenko7e497522008-02-12 09:51:03 +00003273 i = bb_strtou(cp, NULL, 8);
3274 if (errno) {
3275 err("umask: bad octal number");
3276 return 1;
3277 }
3278 umask(i);
Eric Andersenff9eee42001-06-29 04:57:14 +00003279 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003280 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003281}
3282
Denis Vlasenkofe218832008-03-01 09:35:39 +00003283static int doexec(struct op *t, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003284{
Eric Andersenff9eee42001-06-29 04:57:14 +00003285 jmp_buf ex;
3286 xint *ofail;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003287 char **sv_words;
Eric Andersenff9eee42001-06-29 04:57:14 +00003288
3289 t->ioact = NULL;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003290 if (!args[1])
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003291 return 1;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003292
Eric Andersenff9eee42001-06-29 04:57:14 +00003293 execflg = 1;
3294 ofail = failpt;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003295 failpt = ex;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003296
Denis Vlasenko509697f2008-03-02 12:49:39 +00003297 sv_words = t->op_words;
3298 t->op_words = args + 1;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003299// TODO: test what will happen with "exec break" -
Denis Vlasenko509697f2008-03-02 12:49:39 +00003300// will it leave t->op_words pointing to garbage?
Denis Vlasenkofe218832008-03-01 09:35:39 +00003301// (see http://bugs.busybox.net/view.php?id=846)
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003302 if (setjmp(failpt) == 0)
Denis Vlasenko7e497522008-02-12 09:51:03 +00003303 execute(t, NOPIPE, NOPIPE, /* no_fork: */ 1);
Denis Vlasenko509697f2008-03-02 12:49:39 +00003304 t->op_words = sv_words;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003305
Eric Andersenff9eee42001-06-29 04:57:14 +00003306 failpt = ofail;
3307 execflg = 0;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003308
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003309 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003310}
3311
Denis Vlasenko68404f12008-03-17 09:00:54 +00003312static int dodot(struct op *t ATTRIBUTE_UNUSED, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003313{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003314 int i;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003315 const char *sp;
3316 char *tp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003317 char *cp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003318 int maltmp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003319
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003320 DBGPRINTF(("DODOT: enter, t=%p, tleft %p, tright %p, global_env.linep is %s\n",
3321 t, t->left, t->right, ((global_env.linep == NULL) ? "NULL" : global_env.linep)));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003322
Denis Vlasenkofe218832008-03-01 09:35:39 +00003323 cp = args[1];
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003324 if (cp == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00003325 DBGPRINTF(("DODOT: bad args, ret 0\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003326 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003327 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003328 DBGPRINTF(("DODOT: cp is %s\n", cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003329
Eric Andersen8401eea2004-08-04 19:16:54 +00003330 sp = any('/', cp) ? ":" : path->value;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003331
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003332 DBGPRINTF(("DODOT: sp is %s, global_env.linep is %s\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00003333 ((sp == NULL) ? "NULL" : sp),
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003334 ((global_env.linep == NULL) ? "NULL" : global_env.linep)));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003335
Eric Andersenff9eee42001-06-29 04:57:14 +00003336 while (*sp) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003337 tp = global_env.linep;
Eric Andersenff9eee42001-06-29 04:57:14 +00003338 while (*sp && (*tp = *sp++) != ':')
3339 tp++;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003340 if (tp != global_env.linep)
Eric Andersenff9eee42001-06-29 04:57:14 +00003341 *tp++ = '/';
Denis Vlasenko509697f2008-03-02 12:49:39 +00003342 strcpy(tp, cp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003343
3344 /* Original code */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003345 i = open(global_env.linep, O_RDONLY);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003346 if (i >= 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003347 exstat = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003348 maltmp = remap(i);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003349 DBGPRINTF(("DODOT: remap=%d, exstat=%d, global_env.iofd %d, i %d, global_env.linep is %s\n",
3350 maltmp, exstat, global_env.iofd, i, global_env.linep));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003351
3352 next(maltmp); /* Basically a PUSHIO */
3353
3354 DBGPRINTF(("DODOT: returning exstat=%d\n", exstat));
3355
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003356 return exstat;
Eric Andersenff9eee42001-06-29 04:57:14 +00003357 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003358 } /* while */
Eric Andersen12de6cf2004-08-04 19:19:10 +00003359
Eric Andersenff9eee42001-06-29 04:57:14 +00003360 prs(cp);
3361 err(": not found");
Eric Andersen12de6cf2004-08-04 19:19:10 +00003362
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003363 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003364}
3365
Denis Vlasenko68404f12008-03-17 09:00:54 +00003366static int dowait(struct op *t ATTRIBUTE_UNUSED, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003367{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003368 int i;
3369 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003370
Denis Vlasenkofe218832008-03-01 09:35:39 +00003371 cp = args[1];
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003372 if (cp != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003373 i = getn(cp);
3374 if (i == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003375 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003376 } else
3377 i = -1;
3378 setstatus(waitfor(i, 1));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003379 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003380}
3381
Denis Vlasenko68404f12008-03-17 09:00:54 +00003382static int doread(struct op *t ATTRIBUTE_UNUSED, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003383{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003384 char *cp, **wp;
3385 int nb = 0;
3386 int nl = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003387
Denis Vlasenkofe218832008-03-01 09:35:39 +00003388 if (args[1] == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003389 err("Usage: read name ...");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003390 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003391 }
Denis Vlasenkofe218832008-03-01 09:35:39 +00003392 for (wp = args + 1; *wp; wp++) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003393 for (cp = global_env.linep; !nl && cp < elinep - 1; cp++) {
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +00003394 nb = nonblock_safe_read(STDIN_FILENO, cp, sizeof(*cp));
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003395 if (nb != sizeof(*cp))
Eric Andersenff9eee42001-06-29 04:57:14 +00003396 break;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003397 nl = (*cp == '\n');
3398 if (nl || (wp[1] && any(*cp, ifs->value)))
3399 break;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003400 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003401 *cp = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00003402 if (nb <= 0)
3403 break;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003404 setval(lookup(*wp), global_env.linep);
Eric Andersenff9eee42001-06-29 04:57:14 +00003405 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003406 return nb <= 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003407}
3408
Denis Vlasenko68404f12008-03-17 09:00:54 +00003409static int doeval(struct op *t ATTRIBUTE_UNUSED, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003410{
Denis Vlasenkofe218832008-03-01 09:35:39 +00003411 return RUN(awordlist, args + 1, wdchar);
Eric Andersenff9eee42001-06-29 04:57:14 +00003412}
3413
Denis Vlasenko68404f12008-03-17 09:00:54 +00003414static int dotrap(struct op *t ATTRIBUTE_UNUSED, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003415{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003416 int n, i;
3417 int resetsig;
Eric Andersenff9eee42001-06-29 04:57:14 +00003418
Denis Vlasenkofe218832008-03-01 09:35:39 +00003419 if (args[1] == NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00003420 for (i = 0; i <= _NSIG; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00003421 if (trap[i]) {
3422 prn(i);
3423 prs(": ");
3424 prs(trap[i]);
3425 prs("\n");
3426 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003427 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003428 }
Denis Vlasenkofe218832008-03-01 09:35:39 +00003429 resetsig = isdigit(args[1][0]);
3430 for (i = resetsig ? 1 : 2; args[i] != NULL; ++i) {
3431 n = getsig(args[i]);
Eric Andersenff9eee42001-06-29 04:57:14 +00003432 freecell(trap[n]);
3433 trap[n] = 0;
3434 if (!resetsig) {
Denis Vlasenkofe218832008-03-01 09:35:39 +00003435 if (args[1][0] != '\0') {
3436 trap[n] = strsave(args[1], 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003437 setsig(n, sig);
3438 } else
3439 setsig(n, SIG_IGN);
3440 } else {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00003441 if (interactive) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003442 if (n == SIGINT)
3443 setsig(n, onintr);
3444 else
Eric Andersen8401eea2004-08-04 19:16:54 +00003445 setsig(n, n == SIGQUIT ? SIG_IGN : SIG_DFL);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00003446 } else
Eric Andersenff9eee42001-06-29 04:57:14 +00003447 setsig(n, SIG_DFL);
3448 }
3449 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003450 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003451}
3452
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003453static int getsig(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003454{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003455 int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003456
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003457 n = getn(s);
3458 if (n < 0 || n > _NSIG) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003459 err("trap: bad signal number");
3460 n = 0;
3461 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003462 return n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003463}
3464
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003465static void setsig(int n, sighandler_t f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003466{
3467 if (n == 0)
3468 return;
3469 if (signal(n, SIG_IGN) != SIG_IGN || ourtrap[n]) {
3470 ourtrap[n] = 1;
3471 signal(n, f);
3472 }
3473}
3474
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003475static int getn(char *as)
Eric Andersenff9eee42001-06-29 04:57:14 +00003476{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003477 char *s;
3478 int n, m;
Eric Andersenff9eee42001-06-29 04:57:14 +00003479
3480 s = as;
3481 m = 1;
3482 if (*s == '-') {
3483 m = -1;
3484 s++;
3485 }
3486 for (n = 0; isdigit(*s); s++)
Eric Andersen8401eea2004-08-04 19:16:54 +00003487 n = (n * 10) + (*s - '0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003488 if (*s) {
3489 prs(as);
3490 err(": bad number");
3491 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003492 return n * m;
Eric Andersenff9eee42001-06-29 04:57:14 +00003493}
3494
Denis Vlasenko68404f12008-03-17 09:00:54 +00003495static int dobreak(struct op *t ATTRIBUTE_UNUSED, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003496{
Denis Vlasenkofe218832008-03-01 09:35:39 +00003497 return brkcontin(args[1], 1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003498}
3499
Denis Vlasenko68404f12008-03-17 09:00:54 +00003500static int docontinue(struct op *t ATTRIBUTE_UNUSED, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003501{
Denis Vlasenkofe218832008-03-01 09:35:39 +00003502 return brkcontin(args[1], 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003503}
3504
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003505static int brkcontin(char *cp, int val)
Eric Andersenff9eee42001-06-29 04:57:14 +00003506{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003507 struct brkcon *bc;
3508 int nl;
Eric Andersenff9eee42001-06-29 04:57:14 +00003509
Eric Andersen8401eea2004-08-04 19:16:54 +00003510 nl = cp == NULL ? 1 : getn(cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003511 if (nl <= 0)
3512 nl = 999;
3513 do {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003514 bc = brklist;
3515 if (bc == NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00003516 break;
3517 brklist = bc->nextlev;
3518 } while (--nl);
3519 if (nl) {
3520 err("bad break/continue level");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003521 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003522 }
Denis Vlasenko648b44f2008-02-12 06:04:06 +00003523 isbreak = (val != 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003524 longjmp(bc->brkpt, 1);
3525 /* NOTREACHED */
3526}
3527
Denis Vlasenko68404f12008-03-17 09:00:54 +00003528static int doexit(struct op *t ATTRIBUTE_UNUSED, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003529{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003530 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003531
3532 execflg = 0;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003533 cp = args[1];
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003534 if (cp != NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00003535 setstatus(getn(cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003536
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003537 DBGPRINTF(("DOEXIT: calling leave(), t=%p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003538
Eric Andersenff9eee42001-06-29 04:57:14 +00003539 leave();
3540 /* NOTREACHED */
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003541 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003542}
3543
Denis Vlasenko68404f12008-03-17 09:00:54 +00003544static int doexport(struct op *t ATTRIBUTE_UNUSED, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003545{
Denis Vlasenkofe218832008-03-01 09:35:39 +00003546 rdexp(args + 1, export, EXPORT);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003547 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003548}
3549
Denis Vlasenko68404f12008-03-17 09:00:54 +00003550static int doreadonly(struct op *t ATTRIBUTE_UNUSED, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003551{
Denis Vlasenkofe218832008-03-01 09:35:39 +00003552 rdexp(args + 1, ronly, RONLY);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003553 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003554}
3555
Eric Andersen8401eea2004-08-04 19:16:54 +00003556static void rdexp(char **wp, void (*f) (struct var *), int key)
Eric Andersenff9eee42001-06-29 04:57:14 +00003557{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003558 DBGPRINTF6(("RDEXP: enter, wp=%p, func=%p, key=%d\n", wp, f, key));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003559 DBGPRINTF6(("RDEXP: *wp=%s\n", *wp));
3560
Eric Andersenff9eee42001-06-29 04:57:14 +00003561 if (*wp != NULL) {
Matt Kraaif69bfc72001-07-12 19:39:59 +00003562 for (; *wp != NULL; wp++) {
3563 if (isassign(*wp)) {
3564 char *cp;
Eric Andersen8401eea2004-08-04 19:16:54 +00003565
Matt Kraaif69bfc72001-07-12 19:39:59 +00003566 assign(*wp, COPYV);
Denis Vlasenko509697f2008-03-02 12:49:39 +00003567 for (cp = *wp; *cp != '='; cp++)
3568 continue;
Matt Kraaif69bfc72001-07-12 19:39:59 +00003569 *cp = '\0';
3570 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003571 if (checkname(*wp))
Eric Andersen8401eea2004-08-04 19:16:54 +00003572 (*f) (lookup(*wp));
Eric Andersenff9eee42001-06-29 04:57:14 +00003573 else
3574 badid(*wp);
Matt Kraaif69bfc72001-07-12 19:39:59 +00003575 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003576 } else
3577 putvlist(key, 1);
3578}
3579
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003580static void badid(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003581{
3582 prs(s);
3583 err(": bad identifier");
3584}
3585
Denis Vlasenko68404f12008-03-17 09:00:54 +00003586static int doset(struct op *t ATTRIBUTE_UNUSED, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003587{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003588 struct var *vp;
3589 char *cp;
3590 int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003591
Denis Vlasenkofe218832008-03-01 09:35:39 +00003592 cp = args[1];
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003593 if (cp == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003594 for (vp = vlist; vp; vp = vp->next)
3595 varput(vp->name, 1);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003596 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003597 }
3598 if (*cp == '-') {
Denis Vlasenkofe218832008-03-01 09:35:39 +00003599 args++;
Eric Andersenff9eee42001-06-29 04:57:14 +00003600 if (*++cp == 0)
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003601 FLAG['x'] = FLAG['v'] = 0;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003602 else {
3603 for (; *cp; cp++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003604 switch (*cp) {
3605 case 'e':
3606 if (!interactive)
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003607 FLAG['e']++;
Eric Andersenff9eee42001-06-29 04:57:14 +00003608 break;
3609
3610 default:
Eric Andersen8401eea2004-08-04 19:16:54 +00003611 if (*cp >= 'a' && *cp <= 'z')
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003612 FLAG[(int) *cp]++;
Eric Andersenff9eee42001-06-29 04:57:14 +00003613 break;
3614 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003615 }
3616 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003617 setdash();
3618 }
Denis Vlasenkofe218832008-03-01 09:35:39 +00003619 if (args[1]) {
3620 args[0] = dolv[0];
3621 for (n = 1; args[n]; n++)
3622 setarea((char *) args[n], 0);
Eric Andersen8401eea2004-08-04 19:16:54 +00003623 dolc = n - 1;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003624 dolv = args;
Eric Andersenff9eee42001-06-29 04:57:14 +00003625 setval(lookup("#"), putn(dolc));
Eric Andersen8401eea2004-08-04 19:16:54 +00003626 setarea((char *) (dolv - 1), 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003627 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003628 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003629}
3630
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003631static void varput(char *s, int out)
Eric Andersenff9eee42001-06-29 04:57:14 +00003632{
Matt Kraai69edfec2001-08-06 14:14:18 +00003633 if (isalnum(*s) || *s == '_') {
Eric Andersenff9eee42001-06-29 04:57:14 +00003634 write(out, s, strlen(s));
3635 write(out, "\n", 1);
3636 }
3637}
3638
3639
3640/*
3641 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
3642 * This file contains code for the times builtin.
Eric Andersenff9eee42001-06-29 04:57:14 +00003643 */
Denis Vlasenkofe218832008-03-01 09:35:39 +00003644static void times_fmt(char *buf, clock_t val, unsigned clk_tck)
3645{
3646 unsigned min, sec;
3647 if (sizeof(val) > sizeof(int))
3648 sec = ((unsigned long)val) / clk_tck;
3649 else
3650 sec = ((unsigned)val) / clk_tck;
3651 min = sec / 60;
3652#if ENABLE_DESKTOP
3653 sprintf(buf, "%um%u.%03us", min, (sec - min * 60),
3654 /* msec: */ ((unsigned)(val - (clock_t)sec * clk_tck)) * 1000 / clk_tck
3655 );
3656#else
3657 sprintf(buf, "%um%us", min, (sec - min * 60));
3658#endif
3659}
3660
Denis Vlasenko68404f12008-03-17 09:00:54 +00003661static int dotimes(struct op *t ATTRIBUTE_UNUSED, char **args ATTRIBUTE_UNUSED)
Eric Andersenff9eee42001-06-29 04:57:14 +00003662{
3663 struct tms buf;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003664 unsigned clk_tck = sysconf(_SC_CLK_TCK);
3665 /* How much do we need for "NmN.NNNs" ? */
3666 enum { TIMEBUF_SIZE = sizeof(int)*3 + sizeof(int)*3 + 6 };
3667 char u[TIMEBUF_SIZE], s[TIMEBUF_SIZE];
3668 char cu[TIMEBUF_SIZE], cs[TIMEBUF_SIZE];
Eric Andersenff9eee42001-06-29 04:57:14 +00003669
3670 times(&buf);
Denis Vlasenkofe218832008-03-01 09:35:39 +00003671
3672 times_fmt(u, buf.tms_utime, clk_tck);
3673 times_fmt(s, buf.tms_stime, clk_tck);
3674 times_fmt(cu, buf.tms_cutime, clk_tck);
3675 times_fmt(cs, buf.tms_cstime, clk_tck);
3676
3677 printf("%s %s\n%s %s\n", u, s, cu, cs);
Eric Andersenff9eee42001-06-29 04:57:14 +00003678 return 0;
3679}
3680
3681
Eric Andersenff9eee42001-06-29 04:57:14 +00003682/* -------- eval.c -------- */
3683
3684/*
3685 * ${}
3686 * `command`
3687 * blank interpretation
3688 * quoting
3689 * glob
3690 */
3691
Eric Andersen8401eea2004-08-04 19:16:54 +00003692static char **eval(char **ap, int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003693{
3694 struct wdblock *wb;
3695 char **wp;
3696 char **wf;
3697 jmp_buf ev;
3698
3699#if __GNUC__
3700 /* Avoid longjmp clobbering */
3701 (void) &wp;
3702 (void) &ap;
3703#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00003704
3705 DBGPRINTF4(("EVAL: enter, f=%d\n", f));
3706
Eric Andersenff9eee42001-06-29 04:57:14 +00003707 wp = NULL;
3708 wb = NULL;
3709 wf = NULL;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003710 errpt = ev;
3711 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003712 while (*ap && isassign(*ap))
3713 expand(*ap++, &wb, f & ~DOGLOB);
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003714 if (FLAG['k']) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003715 for (wf = ap; *wf; wf++) {
3716 if (isassign(*wf))
3717 expand(*wf, &wb, f & ~DOGLOB);
3718 }
3719 }
Denis Vlasenko648b44f2008-02-12 06:04:06 +00003720 for (wb = addword((char *) NULL, wb); *ap; ap++) {
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003721 if (!FLAG['k'] || !isassign(*ap))
Eric Andersenff9eee42001-06-29 04:57:14 +00003722 expand(*ap, &wb, f & ~DOKEY);
3723 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003724 wb = addword((char *) 0, wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00003725 wp = getwords(wb);
3726 quitenv();
3727 } else
3728 gflg = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003729
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003730 return gflg ? (char **) NULL : wp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003731}
3732
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003733
Eric Andersenff9eee42001-06-29 04:57:14 +00003734/*
3735 * Make the exported environment from the exported
3736 * names in the dictionary. Keyword assignments
3737 * will already have been done.
3738 */
Eric Andersenfd7a4c82004-09-02 23:13:10 +00003739static char **makenv(int all, struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00003740{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003741 struct var *vp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003742
3743 DBGPRINTF5(("MAKENV: enter, all=%d\n", all));
Eric Andersenff9eee42001-06-29 04:57:14 +00003744
Eric Andersenff9eee42001-06-29 04:57:14 +00003745 for (vp = vlist; vp; vp = vp->next)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003746 if (all || vp->status & EXPORT)
Eric Andersenff9eee42001-06-29 04:57:14 +00003747 wb = addword(vp->name, wb);
Eric Andersen8401eea2004-08-04 19:16:54 +00003748 wb = addword((char *) 0, wb);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003749 return getwords(wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00003750}
3751
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003752static int expand(const char *cp, struct wdblock **wbp, int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003753{
3754 jmp_buf ev;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003755 char *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003756
3757#if __GNUC__
3758 /* Avoid longjmp clobbering */
3759 (void) &cp;
3760#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00003761
3762 DBGPRINTF3(("EXPAND: enter, f=%d\n", f));
3763
Eric Andersenff9eee42001-06-29 04:57:14 +00003764 gflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003765
Eric Andersenff9eee42001-06-29 04:57:14 +00003766 if (cp == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003767 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003768
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003769 if (!anys("$`'\"", cp) && !anys(ifs->value, cp)
3770 && ((f & DOGLOB) == 0 || !anys("[*?", cp))
3771 ) {
3772 xp = strsave(cp, areanum);
Eric Andersenff9eee42001-06-29 04:57:14 +00003773 if (f & DOTRIM)
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003774 unquote(xp);
3775 *wbp = addword(xp, *wbp);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003776 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003777 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003778 errpt = ev;
3779 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003780 PUSHIO(aword, cp, strchar);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003781 global_env.iobase = global_env.iop;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003782 while ((xp = blank(f)) && gflg == 0) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003783 global_env.linep = xp;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003784 xp = strsave(xp, areanum);
Eric Andersen8401eea2004-08-04 19:16:54 +00003785 if ((f & DOGLOB) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003786 if (f & DOTRIM)
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003787 unquote(xp);
3788 *wbp = addword(xp, *wbp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003789 } else
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003790 *wbp = glob(xp, *wbp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003791 }
3792 quitenv();
3793 } else
3794 gflg = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003795 return gflg == 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003796}
3797
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003798static char *evalstr(char *cp, int f)
3799{
3800 struct wdblock *wb;
3801
3802 DBGPRINTF6(("EVALSTR: enter, cp=%p, f=%d\n", cp, f));
3803
3804 wb = NULL;
3805 if (expand(cp, &wb, f)) {
3806 if (wb == NULL || wb->w_nword == 0
3807 || (cp = wb->w_words[0]) == NULL
3808 ) {
Denis Vlasenko8e858e22007-03-07 09:35:43 +00003809// TODO: I suspect that
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003810// char *evalstr(char *cp, int f) is actually
3811// const char *evalstr(const char *cp, int f)!
3812 cp = (char*)"";
3813 }
3814 DELETE(wb);
3815 } else
3816 cp = NULL;
3817 return cp;
3818}
3819
3820
Eric Andersenff9eee42001-06-29 04:57:14 +00003821/*
3822 * Blank interpretation and quoting
3823 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003824static char *blank(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003825{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003826 int c, c1;
3827 char *sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003828 int scanequals, foundequals;
3829
Eric Andersen12de6cf2004-08-04 19:19:10 +00003830 DBGPRINTF3(("BLANK: enter, f=%d\n", f));
3831
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003832 sp = global_env.linep;
Eric Andersenff9eee42001-06-29 04:57:14 +00003833 scanequals = f & DOKEY;
3834 foundequals = 0;
3835
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003836 loop:
3837 c = subgetc('"', foundequals);
3838 switch (c) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003839 case 0:
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003840 if (sp == global_env.linep)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003841 return 0;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003842 *global_env.linep++ = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003843 return sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003844
3845 default:
3846 if (f & DOBLANK && any(c, ifs->value))
3847 goto loop;
3848 break;
3849
3850 case '"':
3851 case '\'':
3852 scanequals = 0;
3853 if (INSUB())
3854 break;
3855 for (c1 = c; (c = subgetc(c1, 1)) != c1;) {
3856 if (c == 0)
3857 break;
3858 if (c == '\'' || !any(c, "$`\""))
3859 c |= QUOTE;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003860 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003861 }
3862 c = 0;
3863 }
3864 unget(c);
Matt Kraai69edfec2001-08-06 14:14:18 +00003865 if (!isalpha(c) && c != '_')
Eric Andersenff9eee42001-06-29 04:57:14 +00003866 scanequals = 0;
3867 for (;;) {
3868 c = subgetc('"', foundequals);
3869 if (c == 0 ||
Eric Andersen8401eea2004-08-04 19:16:54 +00003870 f & (DOBLANK && any(c, ifs->value)) ||
3871 (!INSUB() && any(c, "\"'"))) {
3872 scanequals = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003873 unget(c);
3874 if (any(c, "\"'"))
3875 goto loop;
3876 break;
3877 }
3878 if (scanequals) {
3879 if (c == '=') {
3880 foundequals = 1;
Eric Andersen8401eea2004-08-04 19:16:54 +00003881 scanequals = 0;
3882 } else if (!isalnum(c) && c != '_')
Eric Andersenff9eee42001-06-29 04:57:14 +00003883 scanequals = 0;
3884 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003885 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003886 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003887 *global_env.linep++ = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003888 return sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003889}
3890
3891/*
3892 * Get characters, substituting for ` and $
3893 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003894static int subgetc(char ec, int quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00003895{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003896 char c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003897
3898 DBGPRINTF3(("SUBGETC: enter, quoted=%d\n", quoted));
Eric Andersenff9eee42001-06-29 04:57:14 +00003899
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003900 again:
Eric Andersenff9eee42001-06-29 04:57:14 +00003901 c = my_getc(ec);
3902 if (!INSUB() && ec != '\'') {
3903 if (c == '`') {
3904 if (grave(quoted) == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003905 return 0;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003906 global_env.iop->task = XGRAVE;
Eric Andersenff9eee42001-06-29 04:57:14 +00003907 goto again;
3908 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003909 if (c == '$') {
3910 c = dollar(quoted);
3911 if (c == 0) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003912 global_env.iop->task = XDOLL;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003913 goto again;
3914 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003915 }
3916 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003917 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003918}
3919
3920/*
3921 * Prepare to generate the string returned by ${} substitution.
3922 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003923static int dollar(int quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00003924{
3925 int otask;
3926 struct io *oiop;
3927 char *dolp;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003928 char *s, c, *cp = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00003929 struct var *vp;
3930
Eric Andersen12de6cf2004-08-04 19:19:10 +00003931 DBGPRINTF3(("DOLLAR: enter, quoted=%d\n", quoted));
3932
Eric Andersenff9eee42001-06-29 04:57:14 +00003933 c = readc();
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003934 s = global_env.linep;
Eric Andersenff9eee42001-06-29 04:57:14 +00003935 if (c != '{') {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003936 *global_env.linep++ = c;
Matt Kraai69edfec2001-08-06 14:14:18 +00003937 if (isalpha(c) || c == '_') {
Eric Andersen8401eea2004-08-04 19:16:54 +00003938 while ((c = readc()) != 0 && (isalnum(c) || c == '_'))
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003939 if (global_env.linep < elinep)
3940 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003941 unget(c);
3942 }
3943 c = 0;
3944 } else {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003945 oiop = global_env.iop;
3946 otask = global_env.iop->task;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003947
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003948 global_env.iop->task = XOTHER;
Eric Andersen8401eea2004-08-04 19:16:54 +00003949 while ((c = subgetc('"', 0)) != 0 && c != '}' && c != '\n')
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003950 if (global_env.linep < elinep)
3951 *global_env.linep++ = c;
3952 if (oiop == global_env.iop)
3953 global_env.iop->task = otask;
Eric Andersenff9eee42001-06-29 04:57:14 +00003954 if (c != '}') {
3955 err("unclosed ${");
Denis Vlasenko648b44f2008-02-12 06:04:06 +00003956 gflg = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003957 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003958 }
3959 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003960 if (global_env.linep >= elinep) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003961 err("string in ${} too long");
Denis Vlasenko648b44f2008-02-12 06:04:06 +00003962 gflg = 1;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003963 global_env.linep -= 10;
Eric Andersenff9eee42001-06-29 04:57:14 +00003964 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003965 *global_env.linep = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003966 if (*s)
Eric Andersen8401eea2004-08-04 19:16:54 +00003967 for (cp = s + 1; *cp; cp++)
Eric Andersenff9eee42001-06-29 04:57:14 +00003968 if (any(*cp, "=-+?")) {
3969 c = *cp;
3970 *cp++ = 0;
3971 break;
3972 }
3973 if (s[1] == 0 && (*s == '*' || *s == '@')) {
3974 if (dolc > 1) {
3975 /* currently this does not distinguish $* and $@ */
3976 /* should check dollar */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003977 global_env.linep = s;
Eric Andersen8401eea2004-08-04 19:16:54 +00003978 PUSHIO(awordlist, dolv + 1, dolchar);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003979 return 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00003980 } else { /* trap the nasty ${=} */
Eric Andersenff9eee42001-06-29 04:57:14 +00003981 s[0] = '1';
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003982 s[1] = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00003983 }
3984 }
3985 vp = lookup(s);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003986 dolp = vp->value;
3987 if (dolp == null) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003988 switch (c) {
3989 case '=':
3990 if (isdigit(*s)) {
3991 err("cannot use ${...=...} with $n");
Denis Vlasenko648b44f2008-02-12 06:04:06 +00003992 gflg = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003993 break;
3994 }
3995 setval(vp, cp);
3996 dolp = vp->value;
3997 break;
3998
3999 case '-':
4000 dolp = strsave(cp, areanum);
4001 break;
4002
4003 case '?':
4004 if (*cp == 0) {
4005 prs("missing value for ");
4006 err(s);
4007 } else
4008 err(cp);
Denis Vlasenko648b44f2008-02-12 06:04:06 +00004009 gflg = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004010 break;
4011 }
4012 } else if (c == '+')
4013 dolp = strsave(cp, areanum);
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00004014 if (FLAG['u'] && dolp == null) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004015 prs("unset variable: ");
4016 err(s);
Denis Vlasenko648b44f2008-02-12 06:04:06 +00004017 gflg = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004018 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004019 global_env.linep = s;
Eric Andersenff9eee42001-06-29 04:57:14 +00004020 PUSHIO(aword, dolp, quoted ? qstrchar : strchar);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004021 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004022}
4023
4024/*
4025 * Run the command in `...` and read its output.
4026 */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004027
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004028static int grave(int quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00004029{
Denis Vlasenko55f30b02007-03-24 22:42:29 +00004030 /* moved to G: static char child_cmd[LINELIM]; */
4031
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004032 const char *cp;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004033 int i;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004034 int j;
Eric Andersenff9eee42001-06-29 04:57:14 +00004035 int pf[2];
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004036 const char *src;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004037 char *dest;
4038 int count;
4039 int ignore;
4040 int ignore_once;
4041 char *argument_list[4];
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004042 struct wdblock *wb = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004043
4044#if __GNUC__
4045 /* Avoid longjmp clobbering */
4046 (void) &cp;
4047#endif
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004048
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004049 for (cp = global_env.iop->argp->aword; *cp != '`'; cp++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004050 if (*cp == 0) {
4051 err("no closing `");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004052 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004053 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004054 }
Eric Andersen737f5fb2003-03-14 16:05:59 +00004055
4056 /* string copy with dollar expansion */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004057 src = global_env.iop->argp->aword;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004058 dest = child_cmd;
4059 count = 0;
4060 ignore = 0;
4061 ignore_once = 0;
4062 while ((*src != '`') && (count < LINELIM)) {
4063 if (*src == '\'')
4064 ignore = !ignore;
4065 if (*src == '\\')
4066 ignore_once = 1;
4067 if (*src == '$' && !ignore && !ignore_once) {
4068 struct var *vp;
Denis Vlasenkoab801872007-12-02 08:35:37 +00004069 /* moved to G to reduce stack usage
Eric Andersen737f5fb2003-03-14 16:05:59 +00004070 char var_name[LINELIM];
4071 char alt_value[LINELIM];
Denis Vlasenkoab801872007-12-02 08:35:37 +00004072 */
4073#define var_name (G.grave__var_name)
4074#define alt_value (G.grave__alt_value)
Eric Andersen737f5fb2003-03-14 16:05:59 +00004075 int var_index = 0;
4076 int alt_index = 0;
4077 char operator = 0;
4078 int braces = 0;
4079 char *value;
4080
4081 src++;
4082 if (*src == '{') {
4083 braces = 1;
4084 src++;
4085 }
4086
4087 var_name[var_index++] = *src++;
Paul Fox54690dc2005-07-20 18:33:12 +00004088 while (isalnum(*src) || *src=='_')
Eric Andersen737f5fb2003-03-14 16:05:59 +00004089 var_name[var_index++] = *src++;
4090 var_name[var_index] = 0;
4091
4092 if (braces) {
4093 switch (*src) {
4094 case '}':
4095 break;
4096 case '-':
4097 case '=':
4098 case '+':
4099 case '?':
Eric Andersen8401eea2004-08-04 19:16:54 +00004100 operator = * src;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004101 break;
4102 default:
4103 err("unclosed ${\n");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004104 return 0;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004105 }
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004106 if (operator) {
Eric Andersen737f5fb2003-03-14 16:05:59 +00004107 src++;
4108 while (*src && (*src != '}')) {
4109 alt_value[alt_index++] = *src++;
4110 }
4111 alt_value[alt_index] = 0;
4112 if (*src != '}') {
4113 err("unclosed ${\n");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004114 return 0;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004115 }
4116 }
4117 src++;
4118 }
4119
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004120 if (isalpha(*var_name)) {
4121 /* let subshell handle it instead */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004122
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004123 char *namep = var_name;
4124
4125 *dest++ = '$';
4126 if (braces)
4127 *dest++ = '{';
4128 while (*namep)
4129 *dest++ = *namep++;
4130 if (operator) {
4131 char *altp = alt_value;
4132 *dest++ = operator;
4133 while (*altp)
4134 *dest++ = *altp++;
4135 }
4136 if (braces)
4137 *dest++ = '}';
4138
4139 wb = addword(lookup(var_name)->name, wb);
4140 } else {
4141 /* expand */
4142
4143 vp = lookup(var_name);
4144 if (vp->value != null)
4145 value = (operator == '+') ?
4146 alt_value : vp->value;
4147 else if (operator == '?') {
4148 err(alt_value);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004149 return 0;
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004150 } else if (alt_index && (operator != '+')) {
4151 value = alt_value;
4152 if (operator == '=')
4153 setval(vp, value);
4154 } else
4155 continue;
4156
4157 while (*value && (count < LINELIM)) {
4158 *dest++ = *value++;
4159 count++;
4160 }
Eric Andersen737f5fb2003-03-14 16:05:59 +00004161 }
Denis Vlasenkoab801872007-12-02 08:35:37 +00004162#undef var_name
4163#undef alt_value
Eric Andersen737f5fb2003-03-14 16:05:59 +00004164 } else {
4165 *dest++ = *src++;
4166 count++;
4167 ignore_once = 0;
4168 }
4169 }
4170 *dest = '\0';
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004171
Eric Andersenff9eee42001-06-29 04:57:14 +00004172 if (openpipe(pf) < 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004173 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004174
Denis Vlasenko509697f2008-03-02 12:49:39 +00004175 while ((i = vfork()) == -1 && errno == EAGAIN)
4176 continue;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004177
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004178 DBGPRINTF3(("GRAVE: i is %p\n", io));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004179
Eric Andersen737f5fb2003-03-14 16:05:59 +00004180 if (i < 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004181 closepipe(pf);
Eric Andersen8401eea2004-08-04 19:16:54 +00004182 err((char *) bb_msg_memory_exhausted);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004183 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004184 }
4185 if (i != 0) {
Denis Vlasenkofb0eba72008-01-02 19:55:04 +00004186 waitpid(i, NULL, 0); // safe_waitpid?
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004187 global_env.iop->argp->aword = ++cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004188 close(pf[1]);
Eric Andersen8401eea2004-08-04 19:16:54 +00004189 PUSHIO(afile, remap(pf[0]),
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004190 (int (*)(struct ioarg *)) ((quoted) ? qgravechar : gravechar));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004191 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004192 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004193 /* allow trapped signals */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004194 /* XXX - Maybe this signal stuff should go as well? */
Eric Andersen8401eea2004-08-04 19:16:54 +00004195 for (j = 0; j <= _NSIG; j++)
Eric Andersen737f5fb2003-03-14 16:05:59 +00004196 if (ourtrap[j] && signal(j, SIG_IGN) != SIG_IGN)
4197 signal(j, SIG_DFL);
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004198
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00004199 /* Testcase where below checks are needed:
4200 * close stdout & run this script:
4201 * files=`ls`
4202 * echo "$files" >zz
4203 */
4204 xmove_fd(pf[1], 1);
Denis Vlasenko847fa772008-01-28 22:45:43 +00004205 if (pf[0] != 1)
4206 close(pf[0]);
Eric Andersen737f5fb2003-03-14 16:05:59 +00004207
Eric Andersen8401eea2004-08-04 19:16:54 +00004208 argument_list[0] = (char *) DEFAULT_SHELL;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004209 argument_list[1] = (char *) "-c";
Eric Andersen737f5fb2003-03-14 16:05:59 +00004210 argument_list[2] = child_cmd;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004211 argument_list[3] = NULL;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004212
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004213 cp = rexecve(argument_list[0], argument_list, makenv(1, wb));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004214 prs(argument_list[0]);
4215 prs(": ");
4216 err(cp);
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +00004217 _exit(EXIT_FAILURE);
Eric Andersenff9eee42001-06-29 04:57:14 +00004218}
4219
Eric Andersen737f5fb2003-03-14 16:05:59 +00004220
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004221static char *unquote(char *as)
Eric Andersenff9eee42001-06-29 04:57:14 +00004222{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004223 char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00004224
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004225 s = as;
4226 if (s != NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00004227 while (*s)
4228 *s++ &= ~QUOTE;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004229 return as;
Eric Andersenff9eee42001-06-29 04:57:14 +00004230}
4231
4232/* -------- glob.c -------- */
4233
4234/*
4235 * glob
4236 */
4237
4238#define scopy(x) strsave((x), areanum)
4239#define BLKSIZ 512
4240#define NDENT ((BLKSIZ+sizeof(struct dirent)-1)/sizeof(struct dirent))
4241
Eric Andersen8401eea2004-08-04 19:16:54 +00004242static struct wdblock *cl, *nl;
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00004243static const char spcl[] ALIGN1= "[?*";
Eric Andersenff9eee42001-06-29 04:57:14 +00004244
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004245static struct wdblock *glob(char *cp, struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004246{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004247 int i;
4248 char *pp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004249
4250 if (cp == 0)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004251 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004252 i = 0;
4253 for (pp = cp; *pp; pp++)
4254 if (any(*pp, spcl))
4255 i++;
4256 else if (!any(*pp & ~QUOTE, spcl))
4257 *pp &= ~QUOTE;
4258 if (i != 0) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004259 for (cl = addword(scopy(cp), NULL); anyspcl(cl); cl = nl) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004260 nl = newword(cl->w_nword * 2);
4261 for (i = 0; i < cl->w_nword; i++) { /* for each argument */
Eric Andersenff9eee42001-06-29 04:57:14 +00004262 for (pp = cl->w_words[i]; *pp; pp++)
4263 if (any(*pp, spcl)) {
4264 globname(cl->w_words[i], pp);
4265 break;
4266 }
4267 if (*pp == '\0')
4268 nl = addword(scopy(cl->w_words[i]), nl);
4269 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004270 for (i = 0; i < cl->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004271 DELETE(cl->w_words[i]);
4272 DELETE(cl);
4273 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004274 if (cl->w_nword) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004275 for (i = 0; i < cl->w_nword; i++)
Denis Vlasenkofb290382008-03-02 12:51:26 +00004276 unquote(cl->w_words[i]);
4277 qsort_string_vector(cl->w_words, cl->w_nword);
4278 for (i = 0; i < cl->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004279 wb = addword(cl->w_words[i], wb);
4280 DELETE(cl);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004281 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004282 }
4283 }
4284 wb = addword(unquote(cp), wb);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004285 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004286}
4287
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004288static void globname(char *we, char *pp)
Eric Andersenff9eee42001-06-29 04:57:14 +00004289{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004290 char *np, *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004291 char *name, *gp, *dp;
4292 int k;
4293 DIR *dirp;
4294 struct dirent *de;
Eric Andersen8401eea2004-08-04 19:16:54 +00004295 char dname[NAME_MAX + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00004296 struct stat dbuf;
4297
4298 for (np = we; np != pp; pp--)
4299 if (pp[-1] == '/')
4300 break;
Denis Vlasenkofb290382008-03-02 12:51:26 +00004301 dp = cp = get_space((int) (pp - np) + 3);
4302 while (np < pp)
Eric Andersenff9eee42001-06-29 04:57:14 +00004303 *cp++ = *np++;
4304 *cp++ = '.';
4305 *cp = '\0';
Denis Vlasenkofb290382008-03-02 12:51:26 +00004306 gp = cp = get_space(strlen(pp) + 1);
4307 while (*np && *np != '/')
Eric Andersenff9eee42001-06-29 04:57:14 +00004308 *cp++ = *np++;
4309 *cp = '\0';
4310 dirp = opendir(dp);
4311 if (dirp == 0) {
4312 DELETE(dp);
4313 DELETE(gp);
4314 return;
4315 }
4316 dname[NAME_MAX] = '\0';
Eric Andersen8401eea2004-08-04 19:16:54 +00004317 while ((de = readdir(dirp)) != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004318 /* XXX Hmmm... What this could be? (abial) */
Denis Vlasenkoed9d6212008-06-09 07:44:19 +00004319 /* if (ent[j].d_ino == 0) continue;
Eric Andersen8401eea2004-08-04 19:16:54 +00004320 */
Eric Andersenff9eee42001-06-29 04:57:14 +00004321 strncpy(dname, de->d_name, NAME_MAX);
Eric Andersen8401eea2004-08-04 19:16:54 +00004322 if (dname[0] == '.')
4323 if (*gp != '.')
4324 continue;
4325 for (k = 0; k < NAME_MAX; k++)
4326 if (any(dname[k], spcl))
4327 dname[k] |= QUOTE;
4328 if (gmatch(dname, gp)) {
4329 name = generate(we, pp, dname, np);
4330 if (*np && !anys(np, spcl)) {
4331 if (stat(name, &dbuf)) {
4332 DELETE(name);
Eric Andersenff9eee42001-06-29 04:57:14 +00004333 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00004334 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004335 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004336 nl = addword(name, nl);
4337 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004338 }
4339 closedir(dirp);
4340 DELETE(dp);
4341 DELETE(gp);
4342}
4343
4344/*
4345 * generate a pathname as below.
4346 * start..end1 / middle end
4347 * the slashes come for free
4348 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004349static char *generate(char *start1, char *end1, char *middle, char *end)
Eric Andersenff9eee42001-06-29 04:57:14 +00004350{
4351 char *p;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004352 char *op, *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004353
Denis Vlasenko509697f2008-03-02 12:49:39 +00004354 p = op = get_space((int)(end1 - start1) + strlen(middle) + strlen(end) + 2);
4355 xp = start1;
4356 while (xp != end1)
Eric Andersenff9eee42001-06-29 04:57:14 +00004357 *op++ = *xp++;
Denis Vlasenko509697f2008-03-02 12:49:39 +00004358 xp = middle;
4359 while (*xp != '\0')
4360 *op++ = *xp++;
4361 strcpy(op, end);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004362 return p;
Eric Andersenff9eee42001-06-29 04:57:14 +00004363}
4364
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004365static int anyspcl(struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004366{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004367 int i;
4368 char **wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004369
4370 wd = wb->w_words;
Eric Andersen8401eea2004-08-04 19:16:54 +00004371 for (i = 0; i < wb->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004372 if (anys(spcl, *wd++))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004373 return 1;
4374 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004375}
4376
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004377
Eric Andersenff9eee42001-06-29 04:57:14 +00004378/* -------- word.c -------- */
4379
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004380static struct wdblock *newword(int nw)
Eric Andersenff9eee42001-06-29 04:57:14 +00004381{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004382 struct wdblock *wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004383
Denis Vlasenko509697f2008-03-02 12:49:39 +00004384 wb = get_space(sizeof(*wb) + nw * sizeof(char *));
Eric Andersenff9eee42001-06-29 04:57:14 +00004385 wb->w_bsize = nw;
4386 wb->w_nword = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004387 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004388}
4389
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004390static struct wdblock *addword(char *wd, struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004391{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004392 struct wdblock *wb2;
4393 int nw;
Eric Andersenff9eee42001-06-29 04:57:14 +00004394
4395 if (wb == NULL)
4396 wb = newword(NSTART);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004397 nw = wb->w_nword;
4398 if (nw >= wb->w_bsize) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004399 wb2 = newword(nw * 2);
Eric Andersen8401eea2004-08-04 19:16:54 +00004400 memcpy((char *) wb2->w_words, (char *) wb->w_words,
4401 nw * sizeof(char *));
Eric Andersenff9eee42001-06-29 04:57:14 +00004402 wb2->w_nword = nw;
4403 DELETE(wb);
4404 wb = wb2;
4405 }
4406 wb->w_words[wb->w_nword++] = wd;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004407 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004408}
Eric Andersen8401eea2004-08-04 19:16:54 +00004409
Denis Vlasenkoe4712752007-04-14 15:08:41 +00004410static char **getwords(struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004411{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004412 char **wd;
4413 int nb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004414
4415 if (wb == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004416 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004417 if (wb->w_nword == 0) {
4418 DELETE(wb);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004419 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004420 }
Denis Vlasenko509697f2008-03-02 12:49:39 +00004421 nb = sizeof(*wd) * wb->w_nword;
4422 wd = get_space(nb);
Denis Vlasenkofb290382008-03-02 12:51:26 +00004423 memcpy(wd, wb->w_words, nb);
4424 DELETE(wb); /* perhaps should done by caller */
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004425 return wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004426}
4427
Eric Andersenff9eee42001-06-29 04:57:14 +00004428
4429/* -------- io.c -------- */
4430
4431/*
4432 * shell IO
4433 */
4434
Eric Andersen8401eea2004-08-04 19:16:54 +00004435static int my_getc(int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00004436{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004437 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004438
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004439 if (global_env.linep > elinep) {
Denis Vlasenko509697f2008-03-02 12:49:39 +00004440 while ((c = readc()) != '\n' && c)
4441 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00004442 err("input line too long");
Denis Vlasenko648b44f2008-02-12 06:04:06 +00004443 gflg = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004444 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004445 }
4446 c = readc();
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004447 if ((ec != '\'') && (ec != '`') && (global_env.iop->task != XGRAVE)) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004448 if (c == '\\') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004449 c = readc();
4450 if (c == '\n' && ec != '\"')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004451 return my_getc(ec);
Eric Andersenff9eee42001-06-29 04:57:14 +00004452 c |= QUOTE;
4453 }
4454 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004455 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004456}
4457
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004458static void unget(int c)
Eric Andersenff9eee42001-06-29 04:57:14 +00004459{
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004460 if (global_env.iop >= global_env.iobase)
4461 global_env.iop->peekc = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004462}
4463
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004464static int eofc(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00004465{
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004466 return global_env.iop < global_env.iobase || (global_env.iop->peekc == 0 && global_env.iop->prev == 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004467}
4468
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004469static int readc(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00004470{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004471 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004472
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004473 RCPRINTF(("READC: global_env.iop %p, global_env.iobase %p\n", global_env.iop, global_env.iobase));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004474
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004475 for (; global_env.iop >= global_env.iobase; global_env.iop--) {
4476 RCPRINTF(("READC: global_env.iop %p, peekc 0x%x\n", global_env.iop, global_env.iop->peekc));
4477 c = global_env.iop->peekc;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004478 if (c != '\0') {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004479 global_env.iop->peekc = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004480 return c;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004481 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004482 if (global_env.iop->prev != 0) {
4483 c = (*global_env.iop->iofn)(global_env.iop->argp, global_env.iop);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004484 if (c != '\0') {
4485 if (c == -1) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004486 global_env.iop++;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004487 continue;
Eric Andersen8401eea2004-08-04 19:16:54 +00004488 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004489 if (global_env.iop == iostack)
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004490 ioecho(c);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004491 global_env.iop->prev = c;
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00004492 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004493 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004494 if (global_env.iop->task == XIO && global_env.iop->prev != '\n') {
4495 global_env.iop->prev = 0;
4496 if (global_env.iop == iostack)
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004497 ioecho('\n');
4498 return '\n';
Eric Andersen8401eea2004-08-04 19:16:54 +00004499 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004500 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004501 if (global_env.iop->task == XIO) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004502 if (multiline) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004503 global_env.iop->prev = 0;
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00004504 return 0;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004505 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004506 if (interactive && global_env.iop == iostack + 1) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004507#if ENABLE_FEATURE_EDITING
4508 current_prompt = prompt->value;
4509#else
4510 prs(prompt->value);
4511#endif
4512 }
4513 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004514 } /* FOR */
4515
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004516 if (global_env.iop >= iostack) {
4517 RCPRINTF(("READC: return 0, global_env.iop %p\n", global_env.iop));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004518 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004519 }
4520
4521 DBGPRINTF(("READC: leave()...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00004522 leave();
4523 /* NOTREACHED */
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004524 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004525}
4526
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004527static void ioecho(char c)
Eric Andersenff9eee42001-06-29 04:57:14 +00004528{
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00004529 if (FLAG['v'])
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +00004530 write(STDERR_FILENO, &c, sizeof c);
Eric Andersenff9eee42001-06-29 04:57:14 +00004531}
4532
Eric Andersen8401eea2004-08-04 19:16:54 +00004533static void pushio(struct ioarg *argp, int (*fn) (struct ioarg *))
Eric Andersenff9eee42001-06-29 04:57:14 +00004534{
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004535 DBGPRINTF(("PUSHIO: argp %p, argp->afid 0x%x, global_env.iop %p\n", argp,
4536 argp->afid, global_env.iop));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004537
4538 /* Set env ptr for io source to next array spot and check for array overflow */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004539 if (++global_env.iop >= &iostack[NPUSH]) {
4540 global_env.iop--;
Eric Andersenff9eee42001-06-29 04:57:14 +00004541 err("Shell input nested too deeply");
Denis Vlasenko648b44f2008-02-12 06:04:06 +00004542 gflg = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004543 return;
4544 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004545
4546 /* We did not overflow the NPUSH array spots so setup data structs */
4547
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004548 global_env.iop->iofn = (int (*)(struct ioarg *, struct io *)) fn; /* Store data source func ptr */
Eric Andersenff9eee42001-06-29 04:57:14 +00004549
4550 if (argp->afid != AFID_NOBUF)
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004551 global_env.iop->argp = argp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004552 else {
Eric Andersen12de6cf2004-08-04 19:19:10 +00004553
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004554 global_env.iop->argp = ioargstack + (global_env.iop - iostack); /* MAL - index into stack */
4555 *global_env.iop->argp = *argp; /* copy data from temp area into stack spot */
Eric Andersen12de6cf2004-08-04 19:19:10 +00004556
4557 /* MAL - mainbuf is for 1st data source (command line?) and all nested use a single shared buffer? */
4558
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004559 if (global_env.iop == &iostack[0])
4560 global_env.iop->argp->afbuf = &mainbuf;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004561 else
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004562 global_env.iop->argp->afbuf = &sharedbuf;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004563
4564 /* MAL - if not a termimal AND (commandline OR readable file) then give it a buffer id? */
4565 /* This line appears to be active when running scripts from command line */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004566 if ((isatty(global_env.iop->argp->afile) == 0)
4567 && (global_env.iop == &iostack[0]
4568 || lseek(global_env.iop->argp->afile, 0L, SEEK_CUR) != -1)) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00004569 if (++bufid == AFID_NOBUF) /* counter rollover check, AFID_NOBUF = 11111111 */
4570 bufid = AFID_ID; /* AFID_ID = 0 */
4571
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004572 global_env.iop->argp->afid = bufid; /* assign buffer id */
Eric Andersen8401eea2004-08-04 19:16:54 +00004573 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004574
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004575 DBGPRINTF(("PUSHIO: iostack %p, global_env.iop %p, afbuf %p\n",
4576 iostack, global_env.iop, global_env.iop->argp->afbuf));
4577 DBGPRINTF(("PUSHIO: mbuf %p, sbuf %p, bid %d, global_env.iop %p\n",
4578 &mainbuf, &sharedbuf, bufid, global_env.iop));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004579
Eric Andersenff9eee42001-06-29 04:57:14 +00004580 }
4581
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004582 global_env.iop->prev = ~'\n';
4583 global_env.iop->peekc = 0;
4584 global_env.iop->xchar = 0;
4585 global_env.iop->nlcount = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004586
Eric Andersenff9eee42001-06-29 04:57:14 +00004587 if (fn == filechar || fn == linechar)
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004588 global_env.iop->task = XIO;
Eric Andersen8401eea2004-08-04 19:16:54 +00004589 else if (fn == (int (*)(struct ioarg *)) gravechar
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00004590 || fn == (int (*)(struct ioarg *)) qgravechar)
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004591 global_env.iop->task = XGRAVE;
Eric Andersenff9eee42001-06-29 04:57:14 +00004592 else
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004593 global_env.iop->task = XOTHER;
Eric Andersenff9eee42001-06-29 04:57:14 +00004594}
4595
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004596static struct io *setbase(struct io *ip)
Eric Andersenff9eee42001-06-29 04:57:14 +00004597{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004598 struct io *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004599
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004600 xp = global_env.iobase;
4601 global_env.iobase = ip;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004602 return xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004603}
4604
4605/*
4606 * Input generating functions
4607 */
4608
4609/*
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00004610 * Produce the characters of a string, then a newline, then NUL.
Eric Andersenff9eee42001-06-29 04:57:14 +00004611 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004612static int nlchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004613{
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00004614 char c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004615
4616 if (ap->aword == NULL)
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00004617 return '\0';
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004618 c = *ap->aword++;
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00004619 if (c == '\0') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004620 ap->aword = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004621 return '\n';
Eric Andersenff9eee42001-06-29 04:57:14 +00004622 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004623 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004624}
4625
4626/*
4627 * Given a list of words, produce the characters
4628 * in them, with a space after each word.
4629 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004630static int wdchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004631{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004632 char c;
4633 char **wl;
Eric Andersenff9eee42001-06-29 04:57:14 +00004634
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004635 wl = ap->awordlist;
4636 if (wl == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004637 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004638 if (*wl != NULL) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004639 c = *(*wl)++;
4640 if (c != 0)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004641 return c & 0177;
Eric Andersenff9eee42001-06-29 04:57:14 +00004642 ap->awordlist++;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004643 return ' ';
Eric Andersenff9eee42001-06-29 04:57:14 +00004644 }
4645 ap->awordlist = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004646 return '\n';
Eric Andersenff9eee42001-06-29 04:57:14 +00004647}
4648
4649/*
4650 * Return the characters of a list of words,
4651 * producing a space between them.
4652 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004653static int dolchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004654{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004655 char *wp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004656
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004657 wp = *ap->awordlist++;
4658 if (wp != NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004659 PUSHIO(aword, wp, *ap->awordlist == NULL ? strchar : xxchar);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004660 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004661 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004662 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004663}
4664
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004665static int xxchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004666{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004667 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004668
4669 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004670 return 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004671 c = *ap->aword++;
4672 if (c == '\0') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004673 ap->aword = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004674 return ' ';
Eric Andersenff9eee42001-06-29 04:57:14 +00004675 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004676 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004677}
4678
4679/*
4680 * Produce the characters from a single word (string).
4681 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004682static int strchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004683{
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004684 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004685 return 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004686 return *ap->aword++;
Eric Andersenff9eee42001-06-29 04:57:14 +00004687}
4688
4689/*
4690 * Produce quoted characters from a single word (string).
4691 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004692static int qstrchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004693{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004694 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004695
Denis Vlasenkob2abef32007-01-01 18:18:04 +00004696 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004697 return 0;
Denis Vlasenkob2abef32007-01-01 18:18:04 +00004698 c = *ap->aword++;
4699 if (c)
4700 c |= QUOTE;
4701 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004702}
4703
4704/*
4705 * Return the characters from a file.
4706 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004707static int filechar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004708{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004709 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004710 char c;
4711 struct iobuf *bp = ap->afbuf;
4712
4713 if (ap->afid != AFID_NOBUF) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004714 i = (ap->afid != bp->id);
4715 if (i || bp->bufp == bp->ebufp) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004716 if (i)
Denis Vlasenkoea620772006-10-14 02:23:43 +00004717 lseek(ap->afile, ap->afpos, SEEK_SET);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004718
Denis Vlasenkoe376d452008-02-20 22:23:24 +00004719 i = nonblock_safe_read(ap->afile, bp->buf, sizeof(bp->buf));
Eric Andersen8401eea2004-08-04 19:16:54 +00004720 if (i <= 0) {
4721 closef(ap->afile);
4722 return 0;
4723 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004724
Eric Andersen8401eea2004-08-04 19:16:54 +00004725 bp->id = ap->afid;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004726 bp->bufp = bp->buf;
4727 bp->ebufp = bp->bufp + i;
Eric Andersen8401eea2004-08-04 19:16:54 +00004728 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004729
Eric Andersen8401eea2004-08-04 19:16:54 +00004730 ap->afpos++;
4731 return *bp->bufp++ & 0177;
Eric Andersenff9eee42001-06-29 04:57:14 +00004732 }
Denis Vlasenko38f63192007-01-22 09:03:07 +00004733#if ENABLE_FEATURE_EDITING
Eric Andersen737f5fb2003-03-14 16:05:59 +00004734 if (interactive && isatty(ap->afile)) {
Denis Vlasenko55f30b02007-03-24 22:42:29 +00004735 /* moved to G: static char filechar_cmdbuf[BUFSIZ]; */
Eric Andersen8401eea2004-08-04 19:16:54 +00004736 static int position = 0, size = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004737
Eric Andersen8401eea2004-08-04 19:16:54 +00004738 while (size == 0 || position >= size) {
Denis Vlasenko6e602c42008-02-02 18:50:50 +00004739 size = read_line_input(current_prompt, filechar_cmdbuf, BUFSIZ, line_input_state);
4740 if (size < 0) /* Error/EOF */
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +00004741 exit(EXIT_SUCCESS);
Eric Andersen8401eea2004-08-04 19:16:54 +00004742 position = 0;
Denis Vlasenko6e602c42008-02-02 18:50:50 +00004743 /* if Ctrl-C, size == 0 and loop will repeat */
Eric Andersen8401eea2004-08-04 19:16:54 +00004744 }
Denis Vlasenko55f30b02007-03-24 22:42:29 +00004745 c = filechar_cmdbuf[position];
Eric Andersen8401eea2004-08-04 19:16:54 +00004746 position++;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004747 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004748 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004749#endif
Denis Vlasenkoe376d452008-02-20 22:23:24 +00004750 i = nonblock_safe_read(ap->afile, &c, sizeof(c));
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004751 return i == sizeof(c) ? (c & 0x7f) : (closef(ap->afile), 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004752}
4753
4754/*
4755 * Return the characters from a here temp file.
4756 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004757static int herechar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004758{
4759 char c;
4760
Denis Vlasenkoe376d452008-02-20 22:23:24 +00004761 if (nonblock_safe_read(ap->afile, &c, sizeof(c)) != sizeof(c)) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004762 close(ap->afile);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004763 c = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00004764 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004765 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004766}
4767
4768/*
4769 * Return the characters produced by a process (`...`).
4770 * Quote them if required, and remove any trailing newline characters.
4771 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004772static int gravechar(struct ioarg *ap, struct io *iop)
Eric Andersenff9eee42001-06-29 04:57:14 +00004773{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004774 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004775
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004776 c = qgravechar(ap, iop) & ~QUOTE;
4777 if (c == '\n')
Eric Andersenff9eee42001-06-29 04:57:14 +00004778 c = ' ';
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004779 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004780}
4781
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004782static int qgravechar(struct ioarg *ap, struct io *iop)
Eric Andersenff9eee42001-06-29 04:57:14 +00004783{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004784 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004785
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004786 DBGPRINTF3(("QGRAVECHAR: enter, ap=%p, iop=%p\n", ap, iop));
Eric Andersenff9eee42001-06-29 04:57:14 +00004787
4788 if (iop->xchar) {
4789 if (iop->nlcount) {
4790 iop->nlcount--;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004791 return '\n' | QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00004792 }
4793 c = iop->xchar;
4794 iop->xchar = 0;
4795 } else if ((c = filechar(ap)) == '\n') {
4796 iop->nlcount = 1;
4797 while ((c = filechar(ap)) == '\n')
4798 iop->nlcount++;
4799 iop->xchar = c;
4800 if (c == 0)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004801 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004802 iop->nlcount--;
4803 c = '\n';
4804 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004805 return c != 0 ? c | QUOTE : 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004806}
4807
4808/*
4809 * Return a single command (usually the first line) from a file.
4810 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004811static int linechar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004812{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004813 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004814
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004815 c = filechar(ap);
4816 if (c == '\n') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004817 if (!multiline) {
4818 closef(ap->afile);
Eric Andersen8401eea2004-08-04 19:16:54 +00004819 ap->afile = -1; /* illegal value */
Eric Andersenff9eee42001-06-29 04:57:14 +00004820 }
4821 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004822 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004823}
4824
Eric Andersenff9eee42001-06-29 04:57:14 +00004825/*
Denis Vlasenkoed9d6212008-06-09 07:44:19 +00004826 * Remap fd into shell's fd space
Eric Andersenff9eee42001-06-29 04:57:14 +00004827 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004828static int remap(int fd)
Eric Andersenff9eee42001-06-29 04:57:14 +00004829{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004830 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004831 int map[NOFILE];
Eric Andersen12de6cf2004-08-04 19:19:10 +00004832 int newfd;
4833
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004834 DBGPRINTF(("REMAP: fd=%d, global_env.iofd=%d\n", fd, global_env.iofd));
Eric Andersenff9eee42001-06-29 04:57:14 +00004835
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004836 if (fd < global_env.iofd) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004837 for (i = 0; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004838 map[i] = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004839
Eric Andersenff9eee42001-06-29 04:57:14 +00004840 do {
4841 map[fd] = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004842 newfd = dup(fd);
4843 fd = newfd;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004844 } while (fd >= 0 && fd < global_env.iofd);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004845
Eric Andersen8401eea2004-08-04 19:16:54 +00004846 for (i = 0; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004847 if (map[i])
4848 close(i);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004849
Eric Andersenff9eee42001-06-29 04:57:14 +00004850 if (fd < 0)
4851 err("too many files open in shell");
4852 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004853
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004854 return fd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004855}
4856
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004857static int openpipe(int *pv)
Eric Andersenff9eee42001-06-29 04:57:14 +00004858{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004859 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004860
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004861 i = pipe(pv);
4862 if (i < 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00004863 err("can't create pipe - try again");
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004864 return i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004865}
4866
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004867static void closepipe(int *pv)
Eric Andersenff9eee42001-06-29 04:57:14 +00004868{
4869 if (pv != NULL) {
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00004870 close(pv[0]);
4871 close(pv[1]);
Eric Andersenff9eee42001-06-29 04:57:14 +00004872 }
4873}
4874
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004875
Eric Andersenff9eee42001-06-29 04:57:14 +00004876/* -------- here.c -------- */
4877
4878/*
4879 * here documents
4880 */
4881
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004882static void markhere(char *s, struct ioword *iop)
Eric Andersenff9eee42001-06-29 04:57:14 +00004883{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004884 struct here *h, *lh;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004885
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004886 DBGPRINTF7(("MARKHERE: enter, s=%p\n", s));
Eric Andersenff9eee42001-06-29 04:57:14 +00004887
Denis Vlasenko509697f2008-03-02 12:49:39 +00004888 h = get_space(sizeof(struct here));
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004889 if (h == NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00004890 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004891
Eric Andersenff9eee42001-06-29 04:57:14 +00004892 h->h_tag = evalstr(s, DOSUB);
4893 if (h->h_tag == 0)
4894 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004895
Eric Andersenff9eee42001-06-29 04:57:14 +00004896 h->h_iop = iop;
4897 iop->io_name = 0;
4898 h->h_next = NULL;
4899 if (inhere == 0)
4900 inhere = h;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004901 else {
4902 for (lh = inhere; lh != NULL; lh = lh->h_next) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004903 if (lh->h_next == 0) {
4904 lh->h_next = h;
4905 break;
4906 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004907 }
4908 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004909 iop->io_flag |= IOHERE | IOXHERE;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004910 for (s = h->h_tag; *s; s++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004911 if (*s & QUOTE) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004912 iop->io_flag &= ~IOXHERE;
4913 *s &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00004914 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004915 }
Denis Vlasenko648b44f2008-02-12 06:04:06 +00004916 h->h_dosub = ((iop->io_flag & IOXHERE) ? '\0' : '\'');
Eric Andersenff9eee42001-06-29 04:57:14 +00004917}
4918
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004919static void gethere(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00004920{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004921 struct here *h, *hp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004922
4923 DBGPRINTF7(("GETHERE: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00004924
4925 /* Scan here files first leaving inhere list in place */
4926 for (hp = h = inhere; h != NULL; hp = h, h = h->h_next)
Denis Vlasenko648b44f2008-02-12 06:04:06 +00004927 readhere(&h->h_iop->io_name, h->h_tag, h->h_dosub /* NUL or ' */);
Eric Andersenff9eee42001-06-29 04:57:14 +00004928
4929 /* Make inhere list active - keep list intact for scraphere */
4930 if (hp != NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004931 hp->h_next = acthere;
4932 acthere = inhere;
4933 inhere = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004934 }
4935}
4936
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004937static void readhere(char **name, char *s, int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00004938{
4939 int tf;
4940 char tname[30] = ".msh_XXXXXX";
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004941 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004942 jmp_buf ev;
Eric Andersen8401eea2004-08-04 19:16:54 +00004943 char myline[LINELIM + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00004944 char *thenext;
4945
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004946 DBGPRINTF7(("READHERE: enter, name=%p, s=%p\n", name, s));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004947
Eric Andersenff9eee42001-06-29 04:57:14 +00004948 tf = mkstemp(tname);
4949 if (tf < 0)
4950 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004951
Eric Andersenff9eee42001-06-29 04:57:14 +00004952 *name = strsave(tname, areanum);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004953 errpt = ev;
4954 if (newenv(setjmp(errpt)) != 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00004955 unlink(tname);
4956 else {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004957 pushio(global_env.iop->argp, (int (*)(struct ioarg *)) global_env.iop->iofn);
4958 global_env.iobase = global_env.iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00004959 for (;;) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004960 if (interactive && global_env.iop <= iostack) {
Denis Vlasenko38f63192007-01-22 09:03:07 +00004961#if ENABLE_FEATURE_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00004962 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00004963#else
Eric Andersen8401eea2004-08-04 19:16:54 +00004964 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00004965#endif
4966 }
4967 thenext = myline;
4968 while ((c = my_getc(ec)) != '\n' && c) {
4969 if (ec == '\'')
Eric Andersen8401eea2004-08-04 19:16:54 +00004970 c &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00004971 if (thenext >= &myline[LINELIM]) {
4972 c = 0;
4973 break;
4974 }
4975 *thenext++ = c;
4976 }
4977 *thenext = 0;
4978 if (strcmp(s, myline) == 0 || c == 0)
4979 break;
4980 *thenext++ = '\n';
Eric Andersen8401eea2004-08-04 19:16:54 +00004981 write(tf, myline, (int) (thenext - myline));
Eric Andersenff9eee42001-06-29 04:57:14 +00004982 }
4983 if (c == 0) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004984 prs("here document `");
4985 prs(s);
4986 err("' unclosed");
Eric Andersenff9eee42001-06-29 04:57:14 +00004987 }
4988 quitenv();
4989 }
4990 close(tf);
4991}
4992
4993/*
4994 * open here temp file.
4995 * if unquoted here, expand here temp file into second temp file.
4996 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004997static int herein(char *hname, int xdoll)
Eric Andersenff9eee42001-06-29 04:57:14 +00004998{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004999 int hf;
Eric Andersenff9eee42001-06-29 04:57:14 +00005000 int tf;
5001
5002#if __GNUC__
5003 /* Avoid longjmp clobbering */
5004 (void) &tf;
5005#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00005006 if (hname == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00005007 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005008
5009 DBGPRINTF7(("HEREIN: hname is %s, xdoll=%d\n", hname, xdoll));
5010
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005011 hf = open(hname, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00005012 if (hf < 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00005013 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005014
Eric Andersenff9eee42001-06-29 04:57:14 +00005015 if (xdoll) {
5016 char c;
5017 char tname[30] = ".msh_XXXXXX";
5018 jmp_buf ev;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005019
Eric Andersenff9eee42001-06-29 04:57:14 +00005020 tf = mkstemp(tname);
5021 if (tf < 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00005022 return -1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00005023 errpt = ev;
5024 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00005025 PUSHIO(afile, hf, herechar);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005026 setbase(global_env.iop);
Eric Andersenff9eee42001-06-29 04:57:14 +00005027 while ((c = subgetc(0, 0)) != 0) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005028 c &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00005029 write(tf, &c, sizeof c);
5030 }
5031 quitenv();
5032 } else
5033 unlink(tname);
5034 close(tf);
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005035 tf = open(tname, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00005036 unlink(tname);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00005037 return tf;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00005038 }
5039 return hf;
Eric Andersenff9eee42001-06-29 04:57:14 +00005040}
5041
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005042static void scraphere(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00005043{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005044 struct here *h;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005045
5046 DBGPRINTF7(("SCRAPHERE: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00005047
5048 for (h = inhere; h != NULL; h = h->h_next) {
5049 if (h->h_iop && h->h_iop->io_name)
Eric Andersen8401eea2004-08-04 19:16:54 +00005050 unlink(h->h_iop->io_name);
Eric Andersenff9eee42001-06-29 04:57:14 +00005051 }
5052 inhere = NULL;
5053}
5054
5055/* unlink here temp files before a freearea(area) */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005056static void freehere(int area)
Eric Andersenff9eee42001-06-29 04:57:14 +00005057{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005058 struct here *h, *hl;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005059
5060 DBGPRINTF6(("FREEHERE: enter, area=%d\n", area));
Eric Andersenff9eee42001-06-29 04:57:14 +00005061
5062 hl = NULL;
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00005063 for (h = acthere; h != NULL; h = h->h_next) {
Eric Andersenff9eee42001-06-29 04:57:14 +00005064 if (getarea((char *) h) >= area) {
5065 if (h->h_iop->io_name != NULL)
5066 unlink(h->h_iop->io_name);
5067 if (hl == NULL)
5068 acthere = h->h_next;
5069 else
5070 hl->h_next = h->h_next;
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00005071 } else {
Eric Andersenff9eee42001-06-29 04:57:14 +00005072 hl = h;
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00005073 }
5074 }
Eric Andersenff9eee42001-06-29 04:57:14 +00005075}
5076
5077
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005078/* -------- sh.c -------- */
5079/*
5080 * shell
5081 */
5082
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00005083int msh_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005084int msh_main(int argc, char **argv)
5085{
5086 int f;
5087 char *s;
5088 int cflag;
5089 char *name, **ap;
5090 int (*iof) (struct ioarg *);
5091
Denis Vlasenkoab801872007-12-02 08:35:37 +00005092 INIT_G();
5093
Denis Vlasenko55f30b02007-03-24 22:42:29 +00005094 sharedbuf.id = AFID_NOBUF;
5095 mainbuf.id = AFID_NOBUF;
Denis Vlasenko55f30b02007-03-24 22:42:29 +00005096 elinep = line + sizeof(line) - 5;
5097
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005098#if ENABLE_FEATURE_EDITING
5099 line_input_state = new_line_input_t(FOR_SHELL);
5100#endif
5101
5102 DBGPRINTF(("MSH_MAIN: argc %d, environ %p\n", argc, environ));
5103
5104 initarea();
5105 ap = environ;
5106 if (ap != NULL) {
5107 while (*ap)
5108 assign(*ap++, !COPYV);
5109 for (ap = environ; *ap;)
5110 export(lookup(*ap++));
5111 }
5112 closeall();
5113 areanum = 1;
5114
5115 shell = lookup("SHELL");
5116 if (shell->value == null)
5117 setval(shell, (char *)DEFAULT_SHELL);
5118 export(shell);
5119
5120 homedir = lookup("HOME");
5121 if (homedir->value == null)
5122 setval(homedir, "/");
5123 export(homedir);
5124
5125 setval(lookup("$"), putn(getpid()));
5126
5127 path = lookup("PATH");
5128 if (path->value == null) {
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005129 /* Can be merged with same string elsewhere in bbox */
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005130 if (geteuid() == 0)
Denis Vlasenkof5f75c52007-06-12 22:35:19 +00005131 setval(path, bb_default_root_path);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005132 else
Denis Vlasenkof5f75c52007-06-12 22:35:19 +00005133 setval(path, bb_default_path);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005134 }
5135 export(path);
5136
5137 ifs = lookup("IFS");
5138 if (ifs->value == null)
5139 setval(ifs, " \t\n");
5140
5141#ifdef MSHDEBUG
5142 mshdbg_var = lookup("MSHDEBUG");
5143 if (mshdbg_var->value == null)
5144 setval(mshdbg_var, "0");
5145#endif
5146
5147 prompt = lookup("PS1");
5148#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
5149 if (prompt->value == null)
5150#endif
5151 setval(prompt, DEFAULT_USER_PROMPT);
5152 if (geteuid() == 0) {
5153 setval(prompt, DEFAULT_ROOT_PROMPT);
5154 prompt->status &= ~EXPORT;
5155 }
5156 cprompt = lookup("PS2");
5157#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
5158 if (cprompt->value == null)
5159#endif
5160 setval(cprompt, "> ");
5161
5162 iof = filechar;
5163 cflag = 0;
5164 name = *argv++;
5165 if (--argc >= 1) {
5166 if (argv[0][0] == '-' && argv[0][1] != '\0') {
5167 for (s = argv[0] + 1; *s; s++)
5168 switch (*s) {
5169 case 'c':
5170 prompt->status &= ~EXPORT;
5171 cprompt->status &= ~EXPORT;
5172 setval(prompt, "");
5173 setval(cprompt, "");
5174 cflag = 1;
5175 if (--argc > 0)
5176 PUSHIO(aword, *++argv, iof = nlchar);
5177 break;
5178
5179 case 'q':
5180 qflag = SIG_DFL;
5181 break;
5182
5183 case 's':
5184 /* standard input */
5185 break;
5186
5187 case 't':
5188 prompt->status &= ~EXPORT;
5189 setval(prompt, "");
5190 iof = linechar;
5191 break;
5192
5193 case 'i':
Denis Vlasenko648b44f2008-02-12 06:04:06 +00005194 interactive = 1;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005195 default:
5196 if (*s >= 'a' && *s <= 'z')
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00005197 FLAG[(int) *s]++;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005198 }
5199 } else {
5200 argv--;
5201 argc++;
5202 }
5203
5204 if (iof == filechar && --argc > 0) {
5205 setval(prompt, "");
5206 setval(cprompt, "");
5207 prompt->status &= ~EXPORT;
5208 cprompt->status &= ~EXPORT;
5209
5210/* Shell is non-interactive, activate printf-based debug */
5211#ifdef MSHDEBUG
Denis Vlasenkoed9d6212008-06-09 07:44:19 +00005212 mshdbg = mshdbg_var->value[0] - '0';
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005213 if (mshdbg < 0)
5214 mshdbg = 0;
5215#endif
5216 DBGPRINTF(("MSH_MAIN: calling newfile()\n"));
5217
5218 name = *++argv;
5219 if (newfile(name))
Denis Vlasenkoed9d6212008-06-09 07:44:19 +00005220 exit(EXIT_FAILURE); /* Exit on error */
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005221 }
5222 }
5223
5224 setdash();
5225
5226 /* This won't be true if PUSHIO has been called, say from newfile() above */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005227 if (global_env.iop < iostack) {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005228 PUSHIO(afile, 0, iof);
5229 if (isatty(0) && isatty(1) && !cflag) {
Denis Vlasenko648b44f2008-02-12 06:04:06 +00005230 interactive = 1;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005231#if !ENABLE_FEATURE_SH_EXTRA_QUIET
5232#ifdef MSHDEBUG
Denis Vlasenkoca525b42007-06-13 12:27:17 +00005233 printf("\n\n%s built-in shell (msh with debug)\n", bb_banner);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005234#else
Denis Vlasenkoca525b42007-06-13 12:27:17 +00005235 printf("\n\n%s built-in shell (msh)\n", bb_banner);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005236#endif
5237 printf("Enter 'help' for a list of built-in commands.\n\n");
5238#endif
5239 }
5240 }
5241
5242 signal(SIGQUIT, qflag);
5243 if (name && name[0] == '-') {
Denis Vlasenko648b44f2008-02-12 06:04:06 +00005244 interactive = 1;
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005245 f = open(".profile", O_RDONLY);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005246 if (f >= 0)
5247 next(remap(f));
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005248 f = open("/etc/profile", O_RDONLY);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005249 if (f >= 0)
5250 next(remap(f));
5251 }
5252 if (interactive)
5253 signal(SIGTERM, sig);
5254
5255 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
5256 signal(SIGINT, onintr);
Denis Vlasenkofee2d0c2008-02-12 10:12:18 +00005257
5258/* Handle "msh SCRIPT VAR=val params..." */
5259/* Disabled: bash does not do it! */
5260#if 0
5261 argv++;
5262 /* skip leading args of the form VAR=val */
5263 while (*argv && assign(*argv, !COPYV)) {
5264 argc--;
5265 argv++;
5266 }
5267 argv--;
5268#endif
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005269 dolv = argv;
5270 dolc = argc;
5271 dolv[0] = name;
Denis Vlasenkofee2d0c2008-02-12 10:12:18 +00005272
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005273 setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc));
5274
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005275 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 +00005276
5277 for (;;) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005278 if (interactive && global_env.iop <= iostack) {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005279#if ENABLE_FEATURE_EDITING
5280 current_prompt = prompt->value;
5281#else
5282 prs(prompt->value);
5283#endif
5284 }
5285 onecommand();
5286 /* Ensure that getenv("PATH") stays current */
5287 setenv("PATH", path->value, 1);
5288 }
5289
5290 DBGPRINTF(("MSH_MAIN: returning.\n"));
5291}
5292
5293
Eric Andersenff9eee42001-06-29 04:57:14 +00005294/*
5295 * Copyright (c) 1987,1997, Prentice Hall
5296 * All rights reserved.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005297 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005298 * Redistribution and use of the MINIX operating system in source and
5299 * binary forms, with or without modification, are permitted provided
5300 * that the following conditions are met:
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005301 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005302 * Redistributions of source code must retain the above copyright
5303 * notice, this list of conditions and the following disclaimer.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005304 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005305 * Redistributions in binary form must reproduce the above
5306 * copyright notice, this list of conditions and the following
5307 * disclaimer in the documentation and/or other materials provided
5308 * with the distribution.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005309 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005310 * Neither the name of Prentice Hall nor the names of the software
5311 * authors or contributors may be used to endorse or promote
5312 * products derived from this software without specific prior
5313 * written permission.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005314 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005315 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND
5316 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
5317 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
5318 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
5319 * IN NO EVENT SHALL PRENTICE HALL OR ANY AUTHORS OR CONTRIBUTORS BE
5320 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
5321 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
5322 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
5323 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
5324 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
5325 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
5326 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5327 *
5328 */