blob: e98c6017a36df08dea8b048b84b58db9b56f1908 [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
Mike Frysinger14ff19b2006-06-20 20:37:01 +000093int mshdbg = MSHDEBUG;
Eric Andersen12de6cf2004-08-04 19:19:10 +000094
Denis Vlasenko51742f42007-04-12 00:32:05 +000095#define DBGPRINTF(x) if (mshdbg>0) printf x
96#define DBGPRINTF0(x) if (mshdbg>0) printf x
97#define DBGPRINTF1(x) if (mshdbg>1) printf x
98#define DBGPRINTF2(x) if (mshdbg>2) printf x
99#define DBGPRINTF3(x) if (mshdbg>3) printf x
100#define DBGPRINTF4(x) if (mshdbg>4) printf x
101#define DBGPRINTF5(x) if (mshdbg>5) printf x
102#define DBGPRINTF6(x) if (mshdbg>6) printf x
103#define DBGPRINTF7(x) if (mshdbg>7) printf x
104#define DBGPRINTF8(x) if (mshdbg>8) printf x
105#define DBGPRINTF9(x) if (mshdbg>9) printf x
Eric Andersen12de6cf2004-08-04 19:19:10 +0000106
107int mshdbg_rc = 0;
108
Denis Vlasenko51742f42007-04-12 00:32:05 +0000109#define RCPRINTF(x) if (mshdbg_rc) printf x
Eric Andersen12de6cf2004-08-04 19:19:10 +0000110
111#else
112
113#define DBGPRINTF(x)
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000114#define DBGPRINTF0(x) ((void)0)
115#define DBGPRINTF1(x) ((void)0)
116#define DBGPRINTF2(x) ((void)0)
117#define DBGPRINTF3(x) ((void)0)
118#define DBGPRINTF4(x) ((void)0)
119#define DBGPRINTF5(x) ((void)0)
120#define DBGPRINTF6(x) ((void)0)
121#define DBGPRINTF7(x) ((void)0)
122#define DBGPRINTF8(x) ((void)0)
123#define DBGPRINTF9(x) ((void)0)
Eric Andersen12de6cf2004-08-04 19:19:10 +0000124
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000125#define RCPRINTF(x) ((void)0)
Eric Andersen12de6cf2004-08-04 19:19:10 +0000126
127#endif /* MSHDEBUG */
128
129
Denis Vlasenko38f63192007-01-22 09:03:07 +0000130#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
Mike Frysinger2a131752006-06-06 06:26:12 +0000131# define DEFAULT_ROOT_PROMPT "\\u:\\w> "
132# define DEFAULT_USER_PROMPT "\\u:\\w$ "
133#else
134# define DEFAULT_ROOT_PROMPT "# "
135# define DEFAULT_USER_PROMPT "$ "
136#endif
137
138
Eric Andersenff9eee42001-06-29 04:57:14 +0000139/* -------- sh.h -------- */
140/*
141 * shell
142 */
143
Eric Andersen12de6cf2004-08-04 19:19:10 +0000144#define LINELIM 2100
145#define NPUSH 8 /* limit to input nesting */
Eric Andersenff9eee42001-06-29 04:57:14 +0000146
Eric Andersen392947c2002-12-11 07:42:46 +0000147#undef NOFILE
Eric Andersen12de6cf2004-08-04 19:19:10 +0000148#define NOFILE 20 /* Number of open files */
149#define NUFILE 10 /* Number of user-accessible files */
150#define FDBASE 10 /* First file usable by Shell */
Eric Andersenff9eee42001-06-29 04:57:14 +0000151
152/*
153 * values returned by wait
154 */
Denis Vlasenko5f9468e2007-04-14 13:22:09 +0000155#define WAITSIG(s) ((s) & 0177)
156#define WAITVAL(s) (((s) >> 8) & 0377)
157#define WAITCORE(s) (((s) & 0200) != 0)
Eric Andersenff9eee42001-06-29 04:57:14 +0000158
159/*
Eric Andersenaff114c2004-04-14 17:51:38 +0000160 * library and system definitions
Eric Andersenff9eee42001-06-29 04:57:14 +0000161 */
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000162typedef void xint; /* base type of jmp_buf, for not broken compilers */
Eric Andersenff9eee42001-06-29 04:57:14 +0000163
164/*
165 * shell components
166 */
Eric Andersenff9eee42001-06-29 04:57:14 +0000167#define NOBLOCK ((struct op *)NULL)
168#define NOWORD ((char *)NULL)
169#define NOWORDS ((char **)NULL)
170#define NOPIPE ((int *)NULL)
171
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000172/*
173 * redirection
174 */
175struct ioword {
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000176 short io_unit; /* unit affected */
177 short io_flag; /* action (below) */
178 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 Vlasenko648b44f2008-02-12 06:04:06 +0000189#define IODEFAULT (-1) /* token for default IO unit */
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 Vlasenko648b44f2008-02-12 06:04:06 +0000197 smallint type; /* operation type, see Txxxx below */
198 char **words; /* arguments to a command */
199 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);
530static int xstrcmp(char *p1, char *p2);
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000531static void glob0(char *a0, unsigned a1, int a2,
Eric Andersen8401eea2004-08-04 19:16:54 +0000532 int (*a3) (char *, char *));
Eric Andersen8401eea2004-08-04 19:16:54 +0000533static void readhere(char **name, char *s, int ec);
Eric Andersen8401eea2004-08-04 19:16:54 +0000534static int xxchar(struct ioarg *ap);
Eric Andersenff9eee42001-06-29 04:57:14 +0000535
Eric Andersen8401eea2004-08-04 19:16:54 +0000536struct here {
537 char *h_tag;
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000538 char h_dosub;
Eric Andersen8401eea2004-08-04 19:16:54 +0000539 struct ioword *h_iop;
540 struct here *h_next;
Eric Andersenff9eee42001-06-29 04:57:14 +0000541};
542
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000543static const char *const signame[] = {
Eric Andersenff9eee42001-06-29 04:57:14 +0000544 "Signal 0",
545 "Hangup",
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000546 NULL, /* interrupt */
Eric Andersenff9eee42001-06-29 04:57:14 +0000547 "Quit",
548 "Illegal instruction",
549 "Trace/BPT trap",
550 "Abort",
551 "Bus error",
552 "Floating Point Exception",
553 "Killed",
554 "SIGUSR1",
555 "SIGSEGV",
556 "SIGUSR2",
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000557 NULL, /* broken pipe */
Eric Andersenff9eee42001-06-29 04:57:14 +0000558 "Alarm clock",
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000559 "Terminated"
Eric Andersenff9eee42001-06-29 04:57:14 +0000560};
Eric Andersen8401eea2004-08-04 19:16:54 +0000561
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000562
Denis Vlasenkofe218832008-03-01 09:35:39 +0000563typedef int (*builtin_func_ptr)(struct op *, char **);
Denis Vlasenko7e497522008-02-12 09:51:03 +0000564
Eric Andersen1c039232001-07-07 00:05:55 +0000565struct builtincmd {
566 const char *name;
Denis Vlasenko7e497522008-02-12 09:51:03 +0000567 builtin_func_ptr builtinfunc;
Eric Andersenff9eee42001-06-29 04:57:14 +0000568};
Denis Vlasenko7e497522008-02-12 09:51:03 +0000569
Eric Andersen8401eea2004-08-04 19:16:54 +0000570static const struct builtincmd builtincmds[] = {
Denis Vlasenko95cb3262007-04-09 03:06:34 +0000571 { "." , dodot },
572 { ":" , dolabel },
573 { "break" , dobreak },
574 { "cd" , dochdir },
575 { "continue", docontinue },
576 { "eval" , doeval },
577 { "exec" , doexec },
578 { "exit" , doexit },
579 { "export" , doexport },
580 { "help" , dohelp },
581 { "login" , dologin },
582 { "newgrp" , dologin },
583 { "read" , doread },
584 { "readonly", doreadonly },
585 { "set" , doset },
586 { "shift" , doshift },
587 { "times" , dotimes },
588 { "trap" , dotrap },
589 { "umask" , doumask },
590 { "wait" , dowait },
591 { NULL , NULL },
Eric Andersenff9eee42001-06-29 04:57:14 +0000592};
593
"Vladimir N. Oleynik"ac973172005-09-22 14:38:17 +0000594static struct op *scantree(struct op *);
Eric Andersen12de6cf2004-08-04 19:19:10 +0000595static struct op *dowholefile(int, int);
596
Eric Andersen12de6cf2004-08-04 19:19:10 +0000597
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000598/* Globals */
Eric Andersen8401eea2004-08-04 19:16:54 +0000599static char **dolv;
600static int dolc;
601static int exstat;
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000602static smallint gflg; /* (seems to be a parse error indicator) */
603static smallint interactive; /* Is this an interactive shell */
604static smallint execflg;
605static smallint isbreak; /* "break" statement was seen */
606static int multiline; /* '\n' changed to ';' (counter) */
607static struct op *outtree; /* result from parser */
Eric Andersen8401eea2004-08-04 19:16:54 +0000608static xint *failpt;
609static xint *errpt;
610static struct brkcon *brklist;
Eric Andersen8401eea2004-08-04 19:16:54 +0000611static struct wdblock *wdlist;
612static struct wdblock *iolist;
Eric Andersen12de6cf2004-08-04 19:19:10 +0000613
614#ifdef MSHDEBUG
615static struct var *mshdbg_var;
616#endif
Eric Andersen8401eea2004-08-04 19:16:54 +0000617static struct var *vlist; /* dictionary */
618static struct var *homedir; /* home directory */
619static struct var *prompt; /* main prompt */
620static struct var *cprompt; /* continuation prompt */
621static struct var *path; /* search path for commands */
622static struct var *shell; /* shell to interpret command files */
623static struct var *ifs; /* field separators */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000624
Denis Vlasenko95cb3262007-04-09 03:06:34 +0000625static int areanum; /* current allocation area */
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000626static smallint intr; /* interrupt pending (bool) */
627static smallint heedint = 1; /* heed interrupt signals (bool) */
Eric Andersen8401eea2004-08-04 19:16:54 +0000628static int inparse;
Denis Vlasenko95cb3262007-04-09 03:06:34 +0000629static char *null = (char*)""; /* null value for variable */
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +0000630static void (*qflag)(int) = SIG_IGN;
Eric Andersen8401eea2004-08-04 19:16:54 +0000631static int startl;
632static int peeksym;
633static int nlseen;
634static int iounit = IODEFAULT;
635static YYSTYPE yylval;
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000636static char *elinep; /* done in main(): = line + sizeof(line) - 5 */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000637
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000638static struct here *inhere; /* list of hear docs while parsing */
639static struct here *acthere; /* list of active here documents */
640static struct region *areabot; /* bottom of area */
641static struct region *areatop; /* top of area */
642static struct region *areanxt; /* starting point of scan */
Eric Andersen8401eea2004-08-04 19:16:54 +0000643static void *brktop;
644static void *brkaddr;
Eric Andersenff9eee42001-06-29 04:57:14 +0000645
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000646#define AFID_NOBUF (~0)
647#define AFID_ID 0
648
649
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000650/*
651 * parsing & execution environment
652 */
653struct env {
654 char *linep;
655 struct io *iobase;
656 struct io *iop;
657 xint *errpt; /* void * */
658 int iofd;
659 struct env *oenv;
660};
661
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000662
663struct globals {
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000664 struct env global_env;
665 struct ioarg temparg; // = { .afid = AFID_NOBUF }; /* temporary for PUSHIO */
666 unsigned bufid; // = AFID_ID; /* buffer id counter */
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000667 char ourtrap[_NSIG + 1];
668 char *trap[_NSIG + 1];
669 struct iobuf sharedbuf; /* in main(): set to { AFID_NOBUF } */
670 struct iobuf mainbuf; /* in main(): set to { AFID_NOBUF } */
671 struct ioarg ioargstack[NPUSH];
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000672 /*
673 * flags:
674 * -e: quit on error
675 * -k: look for name=value everywhere on command line
676 * -n: no execution
677 * -t: exit after reading and executing one command
678 * -v: echo as read
679 * -x: trace
680 * -u: unset variables net diagnostic
681 */
682 char flags['z' - 'a' + 1];
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000683 char filechar_cmdbuf[BUFSIZ];
684 char line[LINELIM];
685 char child_cmd[LINELIM];
Denis Vlasenkoab801872007-12-02 08:35:37 +0000686
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000687 struct io iostack[NPUSH];
688
Denis Vlasenkoab801872007-12-02 08:35:37 +0000689 char grave__var_name[LINELIM];
690 char grave__alt_value[LINELIM];
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000691};
692
693#define G (*ptr_to_globals)
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000694#define global_env (G.global_env )
695#define temparg (G.temparg )
696#define bufid (G.bufid )
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000697#define ourtrap (G.ourtrap )
698#define trap (G.trap )
699#define sharedbuf (G.sharedbuf )
700#define mainbuf (G.mainbuf )
701#define ioargstack (G.ioargstack )
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000702/* this looks weird, but is OK ... we index FLAG with 'a'...'z' */
703#define FLAG (G.flags - 'a' )
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000704#define filechar_cmdbuf (G.filechar_cmdbuf)
705#define line (G.line )
706#define child_cmd (G.child_cmd )
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000707#define iostack (G.iostack )
Denis Vlasenkoab801872007-12-02 08:35:37 +0000708#define INIT_G() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000709 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000710 global_env.linep = line; \
711 global_env.iobase = iostack; \
712 global_env.iop = iostack - 1; \
713 global_env.iofd = FDBASE; \
714 temparg.afid = AFID_NOBUF; \
715 bufid = AFID_ID; \
Denis Vlasenkoab801872007-12-02 08:35:37 +0000716} while (0)
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000717
718
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000719/* in substitution */
720#define INSUB() (global_env.iop->task == XGRAVE || global_env.iop->task == XDOLL)
721
722#define RUN(what, arg, gen) ((temparg.what = (arg)), run(&temparg, (gen)))
723
Eric Andersen12de6cf2004-08-04 19:19:10 +0000724#ifdef MSHDEBUG
725void print_t(struct op *t)
726{
Mike Frysinger02d8fa42006-05-05 20:32:31 +0000727 DBGPRINTF(("T: t=%p, type %s, words=%p, IOword=%p\n", t,
728 T_CMD_NAMES[t->type], t->words, t->ioact));
Eric Andersen12de6cf2004-08-04 19:19:10 +0000729
730 if (t->words) {
731 DBGPRINTF(("T: W1: %s", t->words[0]));
732 }
Eric Andersen12de6cf2004-08-04 19:19:10 +0000733}
734
735void print_tree(struct op *head)
736{
737 if (head == NULL) {
738 DBGPRINTF(("PRINT_TREE: no tree\n"));
739 return;
740 }
741
Mike Frysinger02d8fa42006-05-05 20:32:31 +0000742 DBGPRINTF(("NODE: %p, left %p, right %p\n", head, head->left,
Eric Andersen12de6cf2004-08-04 19:19:10 +0000743 head->right));
744
745 if (head->left)
746 print_tree(head->left);
747
748 if (head->right)
749 print_tree(head->right);
Eric Andersen12de6cf2004-08-04 19:19:10 +0000750}
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000751#endif /* MSHDEBUG */
752
753
754/*
755 * IO functions
756 */
757static void prs(const char *s)
758{
759 if (*s)
760 write(2, s, strlen(s));
761}
762
763static void prn(unsigned u)
764{
765 prs(itoa(u));
766}
767
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000768static void echo(char **wp)
769{
770 int i;
771
772 prs("+");
773 for (i = 0; wp[i]; i++) {
774 if (i)
775 prs(" ");
776 prs(wp[i]);
777 }
778 prs("\n");
779}
780
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000781static void closef(int i)
782{
783 if (i > 2)
784 close(i);
785}
786
787static void closeall(void)
788{
789 int u;
790
791 for (u = NUFILE; u < NOFILE;)
792 close(u++);
793}
Eric Andersen12de6cf2004-08-04 19:19:10 +0000794
Eric Andersenff9eee42001-06-29 04:57:14 +0000795
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000796/* fail but return to process next command */
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000797static void fail(void) ATTRIBUTE_NORETURN;
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000798static void fail(void)
799{
800 longjmp(failpt, 1);
801 /* NOTREACHED */
802}
Eric Andersenff9eee42001-06-29 04:57:14 +0000803
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000804/* abort shell (or fail in subshell) */
805static void leave(void) ATTRIBUTE_NORETURN;
806static void leave(void)
807{
808 DBGPRINTF(("LEAVE: leave called!\n"));
809
810 if (execflg)
811 fail();
812 scraphere();
813 freehere(1);
814 runtrap(0);
815 _exit(exstat);
816 /* NOTREACHED */
817}
818
819static void warn(const char *s)
820{
821 if (*s) {
822 prs(s);
823 exstat = -1;
824 }
825 prs("\n");
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +0000826 if (FLAG['e'])
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000827 leave();
828}
829
830static void err(const char *s)
831{
832 warn(s);
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +0000833 if (FLAG['n'])
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000834 return;
835 if (!interactive)
836 leave();
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000837 if (global_env.errpt)
838 longjmp(global_env.errpt, 1);
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000839 closeall();
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000840 global_env.iop = global_env.iobase = iostack;
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000841}
842
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000843
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000844/* -------- area.c -------- */
845
Eric Andersenff9eee42001-06-29 04:57:14 +0000846/*
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000847 * All memory between (char *)areabot and (char *)(areatop+1) is
848 * exclusively administered by the area management routines.
849 * It is assumed that sbrk() and brk() manipulate the high end.
Eric Andersenff9eee42001-06-29 04:57:14 +0000850 */
851
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000852#define sbrk(X) ({ \
853 void * __q = (void *)-1; \
854 if (brkaddr + (int)(X) < brktop) { \
855 __q = brkaddr; \
856 brkaddr += (int)(X); \
857 } \
858 __q; \
859})
Eric Andersenff9eee42001-06-29 04:57:14 +0000860
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000861static void initarea(void)
Eric Andersenff9eee42001-06-29 04:57:14 +0000862{
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000863 brkaddr = xmalloc(AREASIZE);
864 brktop = brkaddr + AREASIZE;
Eric Andersenff9eee42001-06-29 04:57:14 +0000865
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000866 while ((long) sbrk(0) & ALIGN)
867 sbrk(1);
868 areabot = (struct region *) sbrk(REGSIZE);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +0000869
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000870 areabot->next = areabot;
871 areabot->area = BUSY;
872 areatop = areabot;
873 areanxt = areabot;
Eric Andersenff9eee42001-06-29 04:57:14 +0000874}
875
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000876static char *getcell(unsigned nbytes)
877{
878 int nregio;
879 struct region *p, *q;
880 int i;
881
882 if (nbytes == 0) {
883 puts("getcell(0)");
884 abort();
885 }
886 /* silly and defeats the algorithm */
887 /*
888 * round upwards and add administration area
889 */
890 nregio = (nbytes + (REGSIZE - 1)) / REGSIZE + 1;
891 p = areanxt;
892 for (;;) {
893 if (p->area > areanum) {
894 /*
895 * merge free cells
896 */
897 while ((q = p->next)->area > areanum && q != areanxt)
898 p->next = q->next;
899 /*
900 * exit loop if cell big enough
901 */
902 if (q >= p + nregio)
903 goto found;
904 }
905 p = p->next;
906 if (p == areanxt)
907 break;
908 }
909 i = nregio >= GROWBY ? nregio : GROWBY;
910 p = (struct region *) sbrk(i * REGSIZE);
911 if (p == (struct region *) -1)
912 return NULL;
913 p--;
914 if (p != areatop) {
915 puts("not contig");
916 abort(); /* allocated areas are contiguous */
917 }
918 q = p + i;
919 p->next = q;
920 p->area = FREE;
921 q->next = areabot;
922 q->area = BUSY;
923 areatop = q;
924 found:
925 /*
926 * we found a FREE area big enough, pointed to by 'p', and up to 'q'
927 */
928 areanxt = p + nregio;
929 if (areanxt < q) {
930 /*
931 * split into requested area and rest
932 */
933 if (areanxt + 1 > q) {
934 puts("OOM");
935 abort(); /* insufficient space left for admin */
936 }
937 areanxt->next = q;
938 areanxt->area = FREE;
939 p->next = areanxt;
940 }
941 p->area = areanum;
942 return (char *) (p + 1);
943}
944
945static void freecell(char *cp)
946{
947 struct region *p;
948
949 p = (struct region *) cp;
950 if (p != NULL) {
951 p--;
952 if (p < areanxt)
953 areanxt = p;
954 p->area = FREE;
955 }
956}
957#define DELETE(obj) freecell((char *)obj)
958
959static void freearea(int a)
960{
961 struct region *p, *top;
962
963 top = areatop;
964 for (p = areabot; p != top; p = p->next)
965 if (p->area >= a)
966 p->area = FREE;
967}
968
969static void setarea(char *cp, int a)
970{
971 struct region *p;
972
973 p = (struct region *) cp;
974 if (p != NULL)
975 (p - 1)->area = a;
976}
977
978static int getarea(char *cp)
979{
980 return ((struct region *) cp - 1)->area;
981}
982
983static void garbage(void)
984{
985 struct region *p, *q, *top;
986
987 top = areatop;
988 for (p = areabot; p != top; p = p->next) {
989 if (p->area > areanum) {
990 while ((q = p->next)->area > areanum)
991 p->next = q->next;
992 areanxt = p;
993 }
994 }
995#ifdef SHRINKBY
996 if (areatop >= q + SHRINKBY && q->area > areanum) {
997 brk((char *) (q + 1));
998 q->next = areabot;
999 q->area = BUSY;
1000 areatop = q;
1001 }
1002#endif
1003}
1004
1005static char *space(int n)
1006{
1007 char *cp;
1008
1009 cp = getcell(n);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001010 if (cp == NULL)
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001011 err("out of string space");
1012 return cp;
1013}
1014
1015static char *strsave(const char *s, int a)
1016{
1017 char *cp;
1018
1019 cp = space(strlen(s) + 1);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001020 if (cp == NULL) {
1021// FIXME: I highly doubt this is good.
1022 return (char*)"";
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001023 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001024 setarea(cp, a);
1025 strcpy(cp, s);
1026 return cp;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001027}
1028
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001029
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001030/* -------- var.c -------- */
1031
1032static int eqname(const char *n1, const char *n2)
1033{
1034 for (; *n1 != '=' && *n1 != '\0'; n1++)
1035 if (*n2++ != *n1)
1036 return 0;
1037 return *n2 == '\0' || *n2 == '=';
1038}
1039
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001040static const char *findeq(const char *cp)
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001041{
1042 while (*cp != '\0' && *cp != '=')
1043 cp++;
1044 return cp;
1045}
1046
1047/*
1048 * Find the given name in the dictionary
1049 * and return its value. If the name was
1050 * not previously there, enter it now and
1051 * return a null value.
1052 */
1053static struct var *lookup(const char *n)
1054{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001055// FIXME: dirty hack
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001056 static struct var dummy;
1057
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001058 struct var *vp;
1059 const char *cp;
1060 char *xp;
1061 int c;
1062
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001063 if (isdigit(*n)) {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001064 dummy.name = (char*)n;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001065 for (c = 0; isdigit(*n) && c < 1000; n++)
1066 c = c * 10 + *n - '0';
1067 dummy.status = RONLY;
1068 dummy.value = (c <= dolc ? dolv[c] : null);
1069 return &dummy;
1070 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001071
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001072 for (vp = vlist; vp; vp = vp->next)
1073 if (eqname(vp->name, n))
1074 return vp;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001075
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001076 cp = findeq(n);
1077 vp = (struct var *) space(sizeof(*vp));
1078 if (vp == 0 || (vp->name = space((int) (cp - n) + 2)) == 0) {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001079 dummy.name = dummy.value = (char*)"";
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001080 return &dummy;
1081 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001082
1083 xp = vp->name;
1084 while ((*xp = *n++) != '\0' && *xp != '=')
1085 xp++;
1086 *xp++ = '=';
1087 *xp = '\0';
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001088 setarea((char *) vp, 0);
1089 setarea((char *) vp->name, 0);
1090 vp->value = null;
1091 vp->next = vlist;
1092 vp->status = GETCELL;
1093 vlist = vp;
1094 return vp;
1095}
1096
1097/*
1098 * if name is not NULL, it must be
1099 * a prefix of the space `val',
1100 * and end with `='.
1101 * this is all so that exporting
1102 * values is reasonably painless.
1103 */
1104static void nameval(struct var *vp, const char *val, const char *name)
1105{
1106 const char *cp;
1107 char *xp;
1108 int fl;
1109
1110 if (vp->status & RONLY) {
1111 xp = vp->name;
1112 while (*xp && *xp != '=')
Denis Vlasenko4daad902007-09-27 10:20:47 +00001113 fputc(*xp++, stderr);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001114 err(" is read-only");
1115 return;
1116 }
1117 fl = 0;
1118 if (name == NULL) {
1119 xp = space(strlen(vp->name) + strlen(val) + 2);
1120 if (xp == NULL)
1121 return;
1122 /* make string: name=value */
1123 setarea(xp, 0);
1124 name = xp;
1125 cp = vp->name;
1126 while ((*xp = *cp++) != '\0' && *xp != '=')
1127 xp++;
1128 *xp++ = '=';
1129 strcpy(xp, val);
1130 val = xp;
1131 fl = GETCELL;
1132 }
1133 if (vp->status & GETCELL)
1134 freecell(vp->name); /* form new string `name=value' */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001135 vp->name = (char*)name;
1136 vp->value = (char*)val;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001137 vp->status |= fl;
1138}
1139
1140/*
1141 * give variable at `vp' the value `val'.
1142 */
1143static void setval(struct var *vp, const char *val)
1144{
1145 nameval(vp, val, NULL);
1146}
1147
1148static void export(struct var *vp)
1149{
1150 vp->status |= EXPORT;
1151}
1152
1153static void ronly(struct var *vp)
1154{
1155 if (isalpha(vp->name[0]) || vp->name[0] == '_') /* not an internal symbol */
1156 vp->status |= RONLY;
1157}
1158
1159static int isassign(const char *s)
1160{
1161 unsigned char c;
1162 DBGPRINTF7(("ISASSIGN: enter, s=%s\n", s));
1163
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001164 c = *s;
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001165 /* no isalpha() - we shouldn't use locale */
1166 /* c | 0x20 - lowercase (Latin) letters */
1167 if (c != '_' && (unsigned)((c|0x20) - 'a') > 25)
1168 /* not letter */
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001169 return 0;
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001170
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001171 while (1) {
1172 c = *++s;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001173 if (c == '=')
1174 return 1;
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001175 if (c == '\0')
1176 return 0;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001177 if (c != '_'
1178 && (unsigned)(c - '0') > 9 /* not number */
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001179 && (unsigned)((c|0x20) - 'a') > 25 /* not letter */
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001180 ) {
1181 return 0;
1182 }
1183 }
1184}
1185
1186static int assign(const char *s, int cf)
1187{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001188 const char *cp;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001189 struct var *vp;
1190
1191 DBGPRINTF7(("ASSIGN: enter, s=%s, cf=%d\n", s, cf));
1192
1193 if (!isalpha(*s) && *s != '_')
1194 return 0;
1195 for (cp = s; *cp != '='; cp++)
1196 if (*cp == '\0' || (!isalnum(*cp) && *cp != '_'))
1197 return 0;
1198 vp = lookup(s);
1199 nameval(vp, ++cp, cf == COPYV ? NULL : s);
1200 if (cf != COPYV)
1201 vp->status &= ~GETCELL;
1202 return 1;
1203}
1204
1205static int checkname(char *cp)
1206{
1207 DBGPRINTF7(("CHECKNAME: enter, cp=%s\n", cp));
1208
1209 if (!isalpha(*cp++) && *(cp - 1) != '_')
1210 return 0;
1211 while (*cp)
1212 if (!isalnum(*cp++) && *(cp - 1) != '_')
1213 return 0;
1214 return 1;
1215}
1216
1217static void putvlist(int f, int out)
1218{
1219 struct var *vp;
1220
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001221 for (vp = vlist; vp; vp = vp->next) {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001222 if (vp->status & f && (isalpha(*vp->name) || *vp->name == '_')) {
1223 if (vp->status & EXPORT)
1224 write(out, "export ", 7);
1225 if (vp->status & RONLY)
1226 write(out, "readonly ", 9);
1227 write(out, vp->name, (int) (findeq(vp->name) - vp->name));
1228 write(out, "\n", 1);
1229 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001230 }
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001231}
1232
1233
1234/*
1235 * trap handling
1236 */
1237static void sig(int i)
1238{
1239 trapset = i;
1240 signal(i, sig);
1241}
1242
1243static void runtrap(int i)
1244{
1245 char *trapstr;
1246
1247 trapstr = trap[i];
1248 if (trapstr == NULL)
1249 return;
1250
1251 if (i == 0)
1252 trap[i] = NULL;
1253
1254 RUN(aword, trapstr, nlchar);
1255}
1256
1257
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001258static void setdash(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001259{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001260 char *cp;
1261 int c;
Eric Andersen8401eea2004-08-04 19:16:54 +00001262 char m['z' - 'a' + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00001263
1264 cp = m;
Eric Andersen8401eea2004-08-04 19:16:54 +00001265 for (c = 'a'; c <= 'z'; c++)
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00001266 if (FLAG[c])
Eric Andersenff9eee42001-06-29 04:57:14 +00001267 *cp++ = c;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001268 *cp = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00001269 setval(lookup("-"), m);
1270}
1271
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001272static int newfile(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00001273{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001274 int f;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001275
1276 DBGPRINTF7(("NEWFILE: opening %s\n", s));
Eric Andersenff9eee42001-06-29 04:57:14 +00001277
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001278 f = 0;
Denis Vlasenko9f739442006-12-16 23:49:13 +00001279 if (NOT_LONE_DASH(s)) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001280 DBGPRINTF(("NEWFILE: s is %s\n", s));
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00001281 f = open(s, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00001282 if (f < 0) {
1283 prs(s);
1284 err(": cannot open");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001285 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001286 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001287 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001288
Eric Andersenff9eee42001-06-29 04:57:14 +00001289 next(remap(f));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001290 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001291}
1292
Eric Andersen12de6cf2004-08-04 19:19:10 +00001293
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001294struct op *scantree(struct op *head)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001295{
1296 struct op *dotnode;
1297
1298 if (head == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001299 return NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001300
1301 if (head->left != NULL) {
1302 dotnode = scantree(head->left);
1303 if (dotnode)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001304 return dotnode;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001305 }
1306
1307 if (head->right != NULL) {
1308 dotnode = scantree(head->right);
1309 if (dotnode)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001310 return dotnode;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001311 }
1312
1313 if (head->words == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001314 return NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001315
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001316 DBGPRINTF5(("SCANTREE: checking node %p\n", head));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001317
Denis Vlasenkocf787cf2007-02-04 17:11:25 +00001318 if ((head->type != TDOT) && LONE_CHAR(head->words[0], '.')) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001319 DBGPRINTF5(("SCANTREE: dot found in node %p\n", head));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001320 return head;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001321 }
1322
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001323 return NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001324}
1325
1326
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001327static void onecommand(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001328{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001329 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00001330 jmp_buf m1;
1331
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001332 DBGPRINTF(("ONECOMMAND: enter, outtree=%p\n", outtree));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001333
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001334 while (global_env.oenv)
Eric Andersenff9eee42001-06-29 04:57:14 +00001335 quitenv();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001336
Eric Andersenff9eee42001-06-29 04:57:14 +00001337 areanum = 1;
1338 freehere(areanum);
1339 freearea(areanum);
1340 garbage();
1341 wdlist = 0;
1342 iolist = 0;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001343 global_env.errpt = 0;
1344 global_env.linep = line;
Eric Andersenff9eee42001-06-29 04:57:14 +00001345 yynerrs = 0;
1346 multiline = 0;
1347 inparse = 1;
1348 intr = 0;
1349 execflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001350
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001351 failpt = m1;
1352 setjmp(failpt); /* Bruce Evans' fix */
1353 failpt = m1;
1354 if (setjmp(failpt) || yyparse() || intr) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001355 DBGPRINTF(("ONECOMMAND: this is not good.\n"));
1356
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001357 while (global_env.oenv)
Eric Andersenff9eee42001-06-29 04:57:14 +00001358 quitenv();
1359 scraphere();
1360 if (!interactive && intr)
1361 leave();
1362 inparse = 0;
1363 intr = 0;
1364 return;
1365 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001366
Eric Andersenff9eee42001-06-29 04:57:14 +00001367 inparse = 0;
1368 brklist = 0;
1369 intr = 0;
1370 execflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001371
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00001372 if (!FLAG['n']) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001373 DBGPRINTF(("ONECOMMAND: calling execute, t=outtree=%p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00001374 outtree));
Denis Vlasenko7e497522008-02-12 09:51:03 +00001375 execute(outtree, NOPIPE, NOPIPE, /* no_fork: */ 0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001376 }
1377
Eric Andersenff9eee42001-06-29 04:57:14 +00001378 if (!interactive && intr) {
1379 execflg = 0;
1380 leave();
1381 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001382
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001383 i = trapset;
1384 if (i != 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001385 trapset = 0;
1386 runtrap(i);
1387 }
1388}
1389
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001390static int newenv(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00001391{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001392 struct env *ep;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001393
1394 DBGPRINTF(("NEWENV: f=%d (indicates quitenv and return)\n", f));
Eric Andersenff9eee42001-06-29 04:57:14 +00001395
1396 if (f) {
1397 quitenv();
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001398 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001399 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001400
Eric Andersenff9eee42001-06-29 04:57:14 +00001401 ep = (struct env *) space(sizeof(*ep));
1402 if (ep == NULL) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001403 while (global_env.oenv)
Eric Andersenff9eee42001-06-29 04:57:14 +00001404 quitenv();
1405 fail();
1406 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001407 *ep = global_env;
1408 global_env.oenv = ep;
1409 global_env.errpt = errpt;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001410
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001411 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001412}
1413
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001414static void quitenv(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001415{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001416 struct env *ep;
1417 int fd;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001418
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001419 DBGPRINTF(("QUITENV: global_env.oenv=%p\n", global_env.oenv));
Eric Andersenff9eee42001-06-29 04:57:14 +00001420
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001421 ep = global_env.oenv;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001422 if (ep != NULL) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001423 fd = global_env.iofd;
1424 global_env = *ep;
Eric Andersenff9eee42001-06-29 04:57:14 +00001425 /* should close `'d files */
1426 DELETE(ep);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001427 while (--fd >= global_env.iofd)
Eric Andersenff9eee42001-06-29 04:57:14 +00001428 close(fd);
1429 }
1430}
1431
1432/*
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001433 * Is character c in s?
Eric Andersenff9eee42001-06-29 04:57:14 +00001434 */
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001435static int any(int c, const char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00001436{
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001437 while (*s)
1438 if (*s++ == c)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001439 return 1;
1440 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001441}
1442
1443/*
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001444 * Is any character from s1 in s2?
Eric Andersenff9eee42001-06-29 04:57:14 +00001445 */
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001446static int anys(const char *s1, const char *s2)
Eric Andersenff9eee42001-06-29 04:57:14 +00001447{
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001448 while (*s1)
1449 if (any(*s1++, s2))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001450 return 1;
1451 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001452}
1453
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001454static char *putn(int n)
Eric Andersenff9eee42001-06-29 04:57:14 +00001455{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001456 return itoa(n);
Eric Andersenff9eee42001-06-29 04:57:14 +00001457}
1458
Eric Andersen8401eea2004-08-04 19:16:54 +00001459static void next(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00001460{
1461 PUSHIO(afile, f, filechar);
1462}
1463
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001464static void onintr(int s) /* ANSI C requires a parameter */
Eric Andersenff9eee42001-06-29 04:57:14 +00001465{
1466 signal(SIGINT, onintr);
1467 intr = 1;
1468 if (interactive) {
1469 if (inparse) {
1470 prs("\n");
1471 fail();
1472 }
Eric Andersen8401eea2004-08-04 19:16:54 +00001473 } else if (heedint) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001474 execflg = 0;
1475 leave();
1476 }
1477}
1478
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001479
Eric Andersenff9eee42001-06-29 04:57:14 +00001480/* -------- gmatch.c -------- */
1481/*
1482 * int gmatch(string, pattern)
1483 * char *string, *pattern;
1484 *
1485 * Match a pattern as in sh(1).
1486 */
1487
1488#define CMASK 0377
1489#define QUOTE 0200
Denis Vlasenko55f30b02007-03-24 22:42:29 +00001490#define QMASK (CMASK & ~QUOTE)
Eric Andersen8401eea2004-08-04 19:16:54 +00001491#define NOT '!' /* might use ^ */
Eric Andersenff9eee42001-06-29 04:57:14 +00001492
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001493static const char *cclass(const char *p, int sub)
1494{
1495 int c, d, not, found;
1496
1497 not = (*p == NOT);
1498 if (not != 0)
1499 p++;
1500 found = not;
1501 do {
1502 if (*p == '\0')
1503 return NULL;
1504 c = *p & CMASK;
1505 if (p[1] == '-' && p[2] != ']') {
1506 d = p[2] & CMASK;
1507 p++;
1508 } else
1509 d = c;
1510 if (c == sub || (c <= sub && sub <= d))
1511 found = !not;
1512 } while (*++p != ']');
1513 return found ? p + 1 : NULL;
1514}
1515
1516static int gmatch(const char *s, const char *p)
Eric Andersenff9eee42001-06-29 04:57:14 +00001517{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001518 int sc, pc;
Eric Andersenff9eee42001-06-29 04:57:14 +00001519
1520 if (s == NULL || p == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001521 return 0;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001522
Eric Andersenff9eee42001-06-29 04:57:14 +00001523 while ((pc = *p++ & CMASK) != '\0') {
1524 sc = *s++ & QMASK;
1525 switch (pc) {
1526 case '[':
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001527 p = cclass(p, sc);
1528 if (p == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001529 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001530 break;
1531
1532 case '?':
1533 if (sc == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001534 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001535 break;
1536
1537 case '*':
1538 s--;
1539 do {
1540 if (*p == '\0' || gmatch(s, p))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001541 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001542 } while (*s++ != '\0');
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001543 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001544
1545 default:
Eric Andersen8401eea2004-08-04 19:16:54 +00001546 if (sc != (pc & ~QUOTE))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001547 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001548 }
1549 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001550 return *s == '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00001551}
1552
Eric Andersenff9eee42001-06-29 04:57:14 +00001553
Eric Andersenff9eee42001-06-29 04:57:14 +00001554/* -------- csyn.c -------- */
1555/*
1556 * shell: syntax (C version)
1557 */
1558
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001559static void yyerror(const char *s) ATTRIBUTE_NORETURN;
1560static void yyerror(const char *s)
1561{
Denis Vlasenko648b44f2008-02-12 06:04:06 +00001562 yynerrs = 1;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001563 if (interactive && global_env.iop <= iostack) {
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001564 multiline = 0;
Denis Vlasenko648b44f2008-02-12 06:04:06 +00001565 while (eofc() == 0 && yylex(0) != '\n')
1566 continue;
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001567 }
1568 err(s);
1569 fail();
1570}
1571
1572static void zzerr(void) ATTRIBUTE_NORETURN;
1573static void zzerr(void)
1574{
1575 yyerror("syntax error");
1576}
1577
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001578int yyparse(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001579{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001580 DBGPRINTF7(("YYPARSE: enter...\n"));
1581
Eric Andersen8401eea2004-08-04 19:16:54 +00001582 startl = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001583 peeksym = 0;
1584 yynerrs = 0;
1585 outtree = c_list();
1586 musthave('\n', 0);
Denis Vlasenko648b44f2008-02-12 06:04:06 +00001587 return yynerrs; /* 0/1 */
Eric Andersenff9eee42001-06-29 04:57:14 +00001588}
1589
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001590static struct op *pipeline(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001591{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001592 struct op *t, *p;
1593 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001594
1595 DBGPRINTF7(("PIPELINE: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001596
1597 t = command(cf);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001598
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001599 DBGPRINTF9(("PIPELINE: t=%p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001600
Eric Andersenff9eee42001-06-29 04:57:14 +00001601 if (t != NULL) {
1602 while ((c = yylex(0)) == '|') {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001603 p = command(CONTIN);
1604 if (p == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001605 DBGPRINTF8(("PIPELINE: error!\n"));
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001606 zzerr();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001607 }
1608
Eric Andersenff9eee42001-06-29 04:57:14 +00001609 if (t->type != TPAREN && t->type != TCOM) {
1610 /* shell statement */
1611 t = block(TPAREN, t, NOBLOCK, NOWORDS);
1612 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001613
Eric Andersenff9eee42001-06-29 04:57:14 +00001614 t = block(TPIPE, t, p, NOWORDS);
1615 }
1616 peeksym = c;
1617 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001618
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001619 DBGPRINTF7(("PIPELINE: returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001620 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001621}
1622
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001623static struct op *andor(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001624{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001625 struct op *t, *p;
1626 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001627
1628 DBGPRINTF7(("ANDOR: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001629
1630 t = pipeline(0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001631
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001632 DBGPRINTF9(("ANDOR: t=%p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001633
Eric Andersenff9eee42001-06-29 04:57:14 +00001634 if (t != NULL) {
1635 while ((c = yylex(0)) == LOGAND || c == LOGOR) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001636 p = pipeline(CONTIN);
1637 if (p == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001638 DBGPRINTF8(("ANDOR: error!\n"));
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001639 zzerr();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001640 }
1641
Eric Andersen8401eea2004-08-04 19:16:54 +00001642 t = block(c == LOGAND ? TAND : TOR, t, p, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001643 } /* WHILE */
1644
Eric Andersenff9eee42001-06-29 04:57:14 +00001645 peeksym = c;
1646 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001647
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001648 DBGPRINTF7(("ANDOR: returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001649 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001650}
1651
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001652static struct op *c_list(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001653{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001654 struct op *t, *p;
1655 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001656
1657 DBGPRINTF7(("C_LIST: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001658
1659 t = andor();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001660
Eric Andersenff9eee42001-06-29 04:57:14 +00001661 if (t != NULL) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001662 peeksym = yylex(0);
1663 if (peeksym == '&')
Eric Andersenff9eee42001-06-29 04:57:14 +00001664 t = block(TASYNC, t, NOBLOCK, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001665
Eric Andersen8401eea2004-08-04 19:16:54 +00001666 while ((c = yylex(0)) == ';' || c == '&'
1667 || (multiline && c == '\n')) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001668
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001669 p = andor();
1670 if (p== NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001671 return t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001672
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001673 peeksym = yylex(0);
1674 if (peeksym == '&')
Eric Andersenff9eee42001-06-29 04:57:14 +00001675 p = block(TASYNC, p, NOBLOCK, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001676
Eric Andersenff9eee42001-06-29 04:57:14 +00001677 t = list(t, p);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001678 } /* WHILE */
1679
Eric Andersenff9eee42001-06-29 04:57:14 +00001680 peeksym = c;
1681 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001682 /* IF */
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001683 DBGPRINTF7(("C_LIST: returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001684 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001685}
1686
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001687static int synio(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001688{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001689 struct ioword *iop;
1690 int i;
1691 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001692
1693 DBGPRINTF7(("SYNIO: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001694
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001695 c = yylex(cf);
1696 if (c != '<' && c != '>') {
Eric Andersenff9eee42001-06-29 04:57:14 +00001697 peeksym = c;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001698 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001699 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001700
Eric Andersenff9eee42001-06-29 04:57:14 +00001701 i = yylval.i;
1702 musthave(WORD, 0);
1703 iop = io(iounit, i, yylval.cp);
1704 iounit = IODEFAULT;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001705
Eric Andersenff9eee42001-06-29 04:57:14 +00001706 if (i & IOHERE)
1707 markhere(yylval.cp, iop);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001708
1709 DBGPRINTF7(("SYNIO: returning 1\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001710 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001711}
1712
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001713static void musthave(int c, int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001714{
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001715 peeksym = yylex(cf);
1716 if (peeksym != c) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001717 DBGPRINTF7(("MUSTHAVE: error!\n"));
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001718 zzerr();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001719 }
1720
Eric Andersenff9eee42001-06-29 04:57:14 +00001721 peeksym = 0;
1722}
1723
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001724static struct op *simple(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001725{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001726 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001727
1728 t = NULL;
1729 for (;;) {
1730 switch (peeksym = yylex(0)) {
1731 case '<':
1732 case '>':
1733 (void) synio(0);
1734 break;
1735
1736 case WORD:
1737 if (t == NULL) {
1738 t = newtp();
1739 t->type = TCOM;
1740 }
1741 peeksym = 0;
1742 word(yylval.cp);
1743 break;
1744
1745 default:
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001746 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001747 }
1748 }
1749}
1750
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001751static struct op *nested(int type, int mark)
Eric Andersenff9eee42001-06-29 04:57:14 +00001752{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001753 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001754
1755 DBGPRINTF3(("NESTED: enter, type=%d, mark=%d\n", type, mark));
Eric Andersenff9eee42001-06-29 04:57:14 +00001756
1757 multiline++;
1758 t = c_list();
1759 musthave(mark, 0);
1760 multiline--;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001761 return block(type, t, NOBLOCK, NOWORDS);
Eric Andersenff9eee42001-06-29 04:57:14 +00001762}
1763
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001764static struct op *command(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001765{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001766 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001767 struct wdblock *iosave;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001768 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001769
1770 DBGPRINTF(("COMMAND: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001771
1772 iosave = iolist;
1773 iolist = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001774
Eric Andersenff9eee42001-06-29 04:57:14 +00001775 if (multiline)
1776 cf |= CONTIN;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001777
Eric Andersenff9eee42001-06-29 04:57:14 +00001778 while (synio(cf))
1779 cf = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001780
1781 c = yylex(cf);
1782
1783 switch (c) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001784 default:
1785 peeksym = c;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001786 t = simple();
1787 if (t == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001788 if (iolist == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001789 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001790 t = newtp();
1791 t->type = TCOM;
1792 }
1793 break;
1794
1795 case '(':
1796 t = nested(TPAREN, ')');
1797 break;
1798
1799 case '{':
1800 t = nested(TBRACE, '}');
1801 break;
1802
1803 case FOR:
1804 t = newtp();
1805 t->type = TFOR;
1806 musthave(WORD, 0);
1807 startl = 1;
1808 t->str = yylval.cp;
1809 multiline++;
1810 t->words = wordlist();
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001811 c = yylex(0);
1812 if (c != '\n' && c != ';')
Eric Andersenff9eee42001-06-29 04:57:14 +00001813 peeksym = c;
1814 t->left = dogroup(0);
1815 multiline--;
1816 break;
1817
1818 case WHILE:
1819 case UNTIL:
1820 multiline++;
1821 t = newtp();
Denis Vlasenko648b44f2008-02-12 06:04:06 +00001822 t->type = (c == WHILE ? TWHILE : TUNTIL);
Eric Andersenff9eee42001-06-29 04:57:14 +00001823 t->left = c_list();
1824 t->right = dogroup(1);
Denis Vlasenkofe218832008-03-01 09:35:39 +00001825 /* t->words = NULL; - newtp() did this */
Eric Andersenff9eee42001-06-29 04:57:14 +00001826 multiline--;
1827 break;
1828
1829 case CASE:
1830 t = newtp();
1831 t->type = TCASE;
1832 musthave(WORD, 0);
1833 t->str = yylval.cp;
1834 startl++;
1835 multiline++;
1836 musthave(IN, CONTIN);
1837 startl++;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001838
Eric Andersenff9eee42001-06-29 04:57:14 +00001839 t->left = caselist();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001840
Eric Andersenff9eee42001-06-29 04:57:14 +00001841 musthave(ESAC, 0);
1842 multiline--;
1843 break;
1844
1845 case IF:
1846 multiline++;
1847 t = newtp();
1848 t->type = TIF;
1849 t->left = c_list();
1850 t->right = thenpart();
1851 musthave(FI, 0);
1852 multiline--;
1853 break;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001854
1855 case DOT:
1856 t = newtp();
1857 t->type = TDOT;
1858
1859 musthave(WORD, 0); /* gets name of file */
1860 DBGPRINTF7(("COMMAND: DOT clause, yylval.cp is %s\n", yylval.cp));
1861
1862 word(yylval.cp); /* add word to wdlist */
1863 word(NOWORD); /* terminate wdlist */
1864 t->words = copyw(); /* dup wdlist */
1865 break;
1866
Eric Andersenff9eee42001-06-29 04:57:14 +00001867 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001868
Eric Andersen8401eea2004-08-04 19:16:54 +00001869 while (synio(0));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001870
Eric Andersenff9eee42001-06-29 04:57:14 +00001871 t = namelist(t);
1872 iolist = iosave;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001873
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001874 DBGPRINTF(("COMMAND: returning %p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001875
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001876 return t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001877}
1878
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001879static struct op *dowholefile(int type, int mark)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001880{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001881 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001882
1883 DBGPRINTF(("DOWHOLEFILE: enter, type=%d, mark=%d\n", type, mark));
1884
1885 multiline++;
1886 t = c_list();
1887 multiline--;
1888 t = block(type, t, NOBLOCK, NOWORDS);
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001889 DBGPRINTF(("DOWHOLEFILE: return t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001890 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001891}
1892
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001893static struct op *dogroup(int onlydone)
Eric Andersenff9eee42001-06-29 04:57:14 +00001894{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001895 int c;
1896 struct op *mylist;
Eric Andersenff9eee42001-06-29 04:57:14 +00001897
1898 c = yylex(CONTIN);
1899 if (c == DONE && onlydone)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001900 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001901 if (c != DO)
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001902 zzerr();
Eric Andersenff9eee42001-06-29 04:57:14 +00001903 mylist = c_list();
1904 musthave(DONE, 0);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001905 return mylist;
Eric Andersenff9eee42001-06-29 04:57:14 +00001906}
1907
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001908static struct op *thenpart(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001909{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001910 int c;
1911 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001912
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001913 c = yylex(0);
1914 if (c != THEN) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001915 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001916 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001917 }
1918 t = newtp();
Denis Vlasenko648b44f2008-02-12 06:04:06 +00001919 /*t->type = 0; - newtp() did this */
Eric Andersenff9eee42001-06-29 04:57:14 +00001920 t->left = c_list();
1921 if (t->left == NULL)
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001922 zzerr();
Eric Andersenff9eee42001-06-29 04:57:14 +00001923 t->right = elsepart();
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001924 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001925}
1926
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001927static struct op *elsepart(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001928{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001929 int c;
1930 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001931
1932 switch (c = yylex(0)) {
1933 case ELSE:
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001934 t = c_list();
1935 if (t == NULL)
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001936 zzerr();
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001937 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001938
1939 case ELIF:
1940 t = newtp();
1941 t->type = TELIF;
1942 t->left = c_list();
1943 t->right = thenpart();
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001944 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001945
1946 default:
1947 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001948 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001949 }
1950}
1951
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001952static struct op *caselist(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001953{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001954 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001955
1956 t = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001957 while ((peeksym = yylex(CONTIN)) != ESAC) {
1958 DBGPRINTF(("CASELIST, doing yylex, peeksym=%d\n", peeksym));
Eric Andersenff9eee42001-06-29 04:57:14 +00001959 t = list(t, casepart());
Eric Andersen12de6cf2004-08-04 19:19:10 +00001960 }
1961
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001962 DBGPRINTF(("CASELIST, returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001963 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001964}
1965
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001966static struct op *casepart(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001967{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001968 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001969
1970 DBGPRINTF7(("CASEPART: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001971
1972 t = newtp();
1973 t->type = TPAT;
1974 t->words = pattern();
1975 musthave(')', 0);
1976 t->left = c_list();
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001977 peeksym = yylex(CONTIN);
1978 if (peeksym != ESAC)
Eric Andersenff9eee42001-06-29 04:57:14 +00001979 musthave(BREAK, CONTIN);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001980
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001981 DBGPRINTF7(("CASEPART: made newtp(TPAT, t=%p)\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001982
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001983 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001984}
1985
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001986static char **pattern(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001987{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001988 int c, cf;
Eric Andersenff9eee42001-06-29 04:57:14 +00001989
1990 cf = CONTIN;
1991 do {
1992 musthave(WORD, cf);
1993 word(yylval.cp);
1994 cf = 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001995 c = yylex(0);
1996 } while (c == '|');
Eric Andersenff9eee42001-06-29 04:57:14 +00001997 peeksym = c;
1998 word(NOWORD);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001999
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002000 return copyw();
Eric Andersenff9eee42001-06-29 04:57:14 +00002001}
2002
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002003static char **wordlist(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002004{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002005 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002006
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002007 c = yylex(0);
2008 if (c != IN) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002009 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002010 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00002011 }
2012 startl = 0;
2013 while ((c = yylex(0)) == WORD)
2014 word(yylval.cp);
2015 word(NOWORD);
2016 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002017 return copyw();
Eric Andersenff9eee42001-06-29 04:57:14 +00002018}
2019
2020/*
2021 * supporting functions
2022 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002023static struct op *list(struct op *t1, struct op *t2)
Eric Andersenff9eee42001-06-29 04:57:14 +00002024{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002025 DBGPRINTF7(("LIST: enter, t1=%p, t2=%p\n", t1, t2));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002026
Eric Andersenff9eee42001-06-29 04:57:14 +00002027 if (t1 == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002028 return t2;
Eric Andersenff9eee42001-06-29 04:57:14 +00002029 if (t2 == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002030 return t1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002031
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002032 return block(TLIST, t1, t2, NOWORDS);
Eric Andersenff9eee42001-06-29 04:57:14 +00002033}
2034
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002035static struct op *block(int type, struct op *t1, struct op *t2, char **wp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002036{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002037 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002038
2039 DBGPRINTF7(("BLOCK: enter, type=%d (%s)\n", type, T_CMD_NAMES[type]));
Eric Andersenff9eee42001-06-29 04:57:14 +00002040
2041 t = newtp();
2042 t->type = type;
2043 t->left = t1;
2044 t->right = t2;
2045 t->words = wp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002046
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002047 DBGPRINTF7(("BLOCK: inserted %p between %p and %p\n", t, t1, t2));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002048
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002049 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002050}
2051
Eric Andersen12de6cf2004-08-04 19:19:10 +00002052/* See if given string is a shell multiline (FOR, IF, etc) */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002053static int rlookup(char *n)
Eric Andersenff9eee42001-06-29 04:57:14 +00002054{
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002055 struct res {
2056 char r_name[6];
2057 int16_t r_val;
2058 };
2059 static const struct res restab[] = {
2060 { "for" , FOR },
2061 { "case" , CASE },
2062 { "esac" , ESAC },
2063 { "while", WHILE },
2064 { "do" , DO },
2065 { "done" , DONE },
2066 { "if" , IF },
2067 { "in" , IN },
2068 { "then" , THEN },
2069 { "else" , ELSE },
2070 { "elif" , ELIF },
2071 { "until", UNTIL },
2072 { "fi" , FI },
2073 { ";;" , BREAK },
2074 { "||" , LOGOR },
2075 { "&&" , LOGAND },
2076 { "{" , '{' },
2077 { "}" , '}' },
2078 { "." , DOT },
2079 { },
2080 };
2081
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002082 const struct res *rp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002083
2084 DBGPRINTF7(("RLOOKUP: enter, n is %s\n", n));
Eric Andersenff9eee42001-06-29 04:57:14 +00002085
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002086 for (rp = restab; rp->r_name[0]; rp++)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002087 if (strcmp(rp->r_name, n) == 0) {
2088 DBGPRINTF7(("RLOOKUP: match, returning %d\n", rp->r_val));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002089 return rp->r_val; /* Return numeric code for shell multiline */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002090 }
2091
2092 DBGPRINTF7(("RLOOKUP: NO match, returning 0\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002093 return 0; /* Not a shell multiline */
Eric Andersenff9eee42001-06-29 04:57:14 +00002094}
2095
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002096static struct op *newtp(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002097{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002098 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002099
Eric Andersen8401eea2004-08-04 19:16:54 +00002100 t = (struct op *) tree(sizeof(*t));
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002101 memset(t, 0, sizeof(*t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002102
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002103 DBGPRINTF3(("NEWTP: allocated %p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002104
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002105 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002106}
2107
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002108static struct op *namelist(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00002109{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002110 DBGPRINTF7(("NAMELIST: enter, t=%p, type %s, iolist=%p\n", t,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002111 T_CMD_NAMES[t->type], iolist));
2112
Eric Andersenff9eee42001-06-29 04:57:14 +00002113 if (iolist) {
Eric Andersen8401eea2004-08-04 19:16:54 +00002114 iolist = addword((char *) NULL, iolist);
Eric Andersenff9eee42001-06-29 04:57:14 +00002115 t->ioact = copyio();
2116 } else
2117 t->ioact = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002118
Eric Andersenff9eee42001-06-29 04:57:14 +00002119 if (t->type != TCOM) {
2120 if (t->type != TPAREN && t->ioact != NULL) {
2121 t = block(TPAREN, t, NOBLOCK, NOWORDS);
2122 t->ioact = t->left->ioact;
2123 t->left->ioact = NULL;
2124 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002125 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002126 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002127
Eric Andersenff9eee42001-06-29 04:57:14 +00002128 word(NOWORD);
2129 t->words = copyw();
Eric Andersen12de6cf2004-08-04 19:19:10 +00002130
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002131 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002132}
2133
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002134static char **copyw(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002135{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002136 char **wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00002137
2138 wd = getwords(wdlist);
2139 wdlist = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002140 return wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00002141}
2142
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002143static void word(char *cp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002144{
2145 wdlist = addword(cp, wdlist);
2146}
2147
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002148static struct ioword **copyio(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002149{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002150 struct ioword **iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002151
2152 iop = (struct ioword **) getwords(iolist);
2153 iolist = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002154 return iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002155}
2156
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002157static struct ioword *io(int u, int f, char *cp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002158{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002159 struct ioword *iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002160
2161 iop = (struct ioword *) tree(sizeof(*iop));
2162 iop->io_unit = u;
2163 iop->io_flag = f;
2164 iop->io_name = cp;
Eric Andersen8401eea2004-08-04 19:16:54 +00002165 iolist = addword((char *) iop, iolist);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002166 return iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002167}
2168
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002169static int yylex(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00002170{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002171 int c, c1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002172 int atstart;
2173
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002174 c = peeksym;
2175 if (c > 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002176 peeksym = 0;
2177 if (c == '\n')
2178 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002179 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002180 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002181
Eric Andersenff9eee42001-06-29 04:57:14 +00002182 nlseen = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002183 atstart = startl;
2184 startl = 0;
2185 yylval.i = 0;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002186 global_env.linep = line;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002187
2188/* MALAMO */
2189 line[LINELIM - 1] = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00002190
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002191 loop:
Eric Andersen12de6cf2004-08-04 19:19:10 +00002192 while ((c = my_getc(0)) == ' ' || c == '\t') /* Skip whitespace */
2193 ;
2194
Eric Andersenff9eee42001-06-29 04:57:14 +00002195 switch (c) {
2196 default:
2197 if (any(c, "0123456789")) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002198 c1 = my_getc(0);
2199 unget(c1);
Eric Andersenff9eee42001-06-29 04:57:14 +00002200 if (c1 == '<' || c1 == '>') {
2201 iounit = c - '0';
2202 goto loop;
2203 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002204 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002205 c = c1;
2206 }
2207 break;
2208
Eric Andersen12de6cf2004-08-04 19:19:10 +00002209 case '#': /* Comment, skip to next newline or End-of-string */
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002210 while ((c = my_getc(0)) != '\0' && c != '\n');
Eric Andersenff9eee42001-06-29 04:57:14 +00002211 unget(c);
2212 goto loop;
2213
2214 case 0:
Eric Andersen12de6cf2004-08-04 19:19:10 +00002215 DBGPRINTF5(("YYLEX: return 0, c=%d\n", c));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002216 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002217
2218 case '$':
Eric Andersen12de6cf2004-08-04 19:19:10 +00002219 DBGPRINTF9(("YYLEX: found $\n"));
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002220 *global_env.linep++ = c;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002221 c = my_getc(0);
2222 if (c == '{') {
2223 c = collect(c, '}');
2224 if (c != '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002225 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002226 goto pack;
2227 }
2228 break;
2229
2230 case '`':
2231 case '\'':
2232 case '"':
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002233 c = collect(c, c);
2234 if (c != '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002235 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002236 goto pack;
2237
2238 case '|':
2239 case '&':
2240 case ';':
Eric Andersenff9eee42001-06-29 04:57:14 +00002241 startl = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002242 /* If more chars process them, else return NULL char */
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002243 c1 = dual(c);
2244 if (c1 != '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002245 return c1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002246 return c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002247
Eric Andersenff9eee42001-06-29 04:57:14 +00002248 case '^':
2249 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002250 return '|';
Eric Andersenff9eee42001-06-29 04:57:14 +00002251 case '>':
2252 case '<':
2253 diag(c);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002254 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002255
2256 case '\n':
2257 nlseen++;
2258 gethere();
2259 startl = 1;
2260 if (multiline || cf & CONTIN) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002261 if (interactive && global_env.iop <= iostack) {
Denis Vlasenko38f63192007-01-22 09:03:07 +00002262#if ENABLE_FEATURE_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00002263 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00002264#else
Eric Andersen8401eea2004-08-04 19:16:54 +00002265 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00002266#endif
2267 }
2268 if (cf & CONTIN)
2269 goto loop;
2270 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002271 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002272
2273 case '(':
2274 case ')':
2275 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002276 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002277 }
2278
2279 unget(c);
2280
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002281 pack:
2282 while ((c = my_getc(0)) != '\0' && !any(c, "`$ '\"\t;&<>()|^\n")) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002283 if (global_env.linep >= elinep)
Eric Andersenff9eee42001-06-29 04:57:14 +00002284 err("word too long");
2285 else
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002286 *global_env.linep++ = c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002287 };
2288
Eric Andersenff9eee42001-06-29 04:57:14 +00002289 unget(c);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002290
Eric Andersen8401eea2004-08-04 19:16:54 +00002291 if (any(c, "\"'`$"))
Eric Andersenff9eee42001-06-29 04:57:14 +00002292 goto loop;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002293
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002294 *global_env.linep++ = '\0';
Eric Andersen12de6cf2004-08-04 19:19:10 +00002295
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002296 if (atstart) {
2297 c = rlookup(line);
2298 if (c != 0) {
2299 startl = 1;
2300 return c;
2301 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002302 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002303
Eric Andersenff9eee42001-06-29 04:57:14 +00002304 yylval.cp = strsave(line, areanum);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002305 return WORD;
Eric Andersenff9eee42001-06-29 04:57:14 +00002306}
2307
Eric Andersen12de6cf2004-08-04 19:19:10 +00002308
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002309static int collect(int c, int c1)
Eric Andersenff9eee42001-06-29 04:57:14 +00002310{
2311 char s[2];
2312
Eric Andersen12de6cf2004-08-04 19:19:10 +00002313 DBGPRINTF8(("COLLECT: enter, c=%d, c1=%d\n", c, c1));
2314
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002315 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002316 while ((c = my_getc(c1)) != c1) {
2317 if (c == 0) {
2318 unget(c);
2319 s[0] = c1;
2320 s[1] = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00002321 prs("no closing ");
2322 yyerror(s);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002323 return YYERRCODE;
Eric Andersenff9eee42001-06-29 04:57:14 +00002324 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002325 if (interactive && c == '\n' && global_env.iop <= iostack) {
Denis Vlasenko38f63192007-01-22 09:03:07 +00002326#if ENABLE_FEATURE_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00002327 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00002328#else
Eric Andersen8401eea2004-08-04 19:16:54 +00002329 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00002330#endif
2331 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002332 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002333 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002334
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002335 *global_env.linep++ = c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002336
2337 DBGPRINTF8(("COLLECT: return 0, line is %s\n", line));
2338
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002339 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002340}
2341
Eric Andersen12de6cf2004-08-04 19:19:10 +00002342/* "multiline commands" helper func */
2343/* see if next 2 chars form a shell multiline */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002344static int dual(int c)
Eric Andersenff9eee42001-06-29 04:57:14 +00002345{
2346 char s[3];
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002347 char *cp = s;
Eric Andersenff9eee42001-06-29 04:57:14 +00002348
Eric Andersen12de6cf2004-08-04 19:19:10 +00002349 DBGPRINTF8(("DUAL: enter, c=%d\n", c));
2350
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002351 *cp++ = c; /* c is the given "peek" char */
2352 *cp++ = my_getc(0); /* get next char of input */
2353 *cp = '\0'; /* add EOS marker */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002354
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002355 c = rlookup(s); /* see if 2 chars form a shell multiline */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002356 if (c == 0)
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002357 unget(*--cp); /* String is not a shell multiline, put peek char back */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002358
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002359 return c; /* String is multiline, return numeric multiline (restab) code */
Eric Andersenff9eee42001-06-29 04:57:14 +00002360}
2361
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002362static void diag(int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00002363{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002364 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002365
2366 DBGPRINTF8(("DIAG: enter, ec=%d\n", ec));
Eric Andersenff9eee42001-06-29 04:57:14 +00002367
2368 c = my_getc(0);
2369 if (c == '>' || c == '<') {
2370 if (c != ec)
2371 zzerr();
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002372 yylval.i = (ec == '>' ? IOWRITE | IOCAT : IOHERE);
Eric Andersenff9eee42001-06-29 04:57:14 +00002373 c = my_getc(0);
2374 } else
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002375 yylval.i = (ec == '>' ? IOWRITE : IOREAD);
Eric Andersenff9eee42001-06-29 04:57:14 +00002376 if (c != '&' || yylval.i == IOHERE)
2377 unget(c);
2378 else
2379 yylval.i |= IODUP;
2380}
2381
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002382static char *tree(unsigned size)
Eric Andersenff9eee42001-06-29 04:57:14 +00002383{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002384 char *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002385
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002386 t = getcell(size);
2387 if (t == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002388 DBGPRINTF2(("TREE: getcell(%d) failed!\n", size));
Eric Andersenff9eee42001-06-29 04:57:14 +00002389 prs("command line too complicated\n");
2390 fail();
2391 /* NOTREACHED */
2392 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002393 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002394}
2395
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002396
Eric Andersenff9eee42001-06-29 04:57:14 +00002397/* VARARGS1 */
2398/* ARGSUSED */
2399
2400/* -------- exec.c -------- */
2401
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002402static struct op **find1case(struct op *t, const char *w)
2403{
2404 struct op *t1;
2405 struct op **tp;
2406 char **wp;
2407 char *cp;
2408
2409 if (t == NULL) {
2410 DBGPRINTF3(("FIND1CASE: enter, t==NULL, returning.\n"));
2411 return NULL;
2412 }
2413
2414 DBGPRINTF3(("FIND1CASE: enter, t->type=%d (%s)\n", t->type,
2415 T_CMD_NAMES[t->type]));
2416
2417 if (t->type == TLIST) {
2418 tp = find1case(t->left, w);
2419 if (tp != NULL) {
2420 DBGPRINTF3(("FIND1CASE: found one to the left, returning tp=%p\n", tp));
2421 return tp;
2422 }
2423 t1 = t->right; /* TPAT */
2424 } else
2425 t1 = t;
2426
2427 for (wp = t1->words; *wp;) {
2428 cp = evalstr(*wp++, DOSUB);
2429 if (cp && gmatch(w, cp)) {
2430 DBGPRINTF3(("FIND1CASE: returning &t1->left= %p.\n",
2431 &t1->left));
2432 return &t1->left;
2433 }
2434 }
2435
2436 DBGPRINTF(("FIND1CASE: returning NULL\n"));
2437 return NULL;
2438}
2439
2440static struct op *findcase(struct op *t, const char *w)
2441{
2442 struct op **tp;
2443
2444 tp = find1case(t, w);
2445 return tp != NULL ? *tp : NULL;
2446}
2447
Eric Andersenff9eee42001-06-29 04:57:14 +00002448/*
2449 * execute tree
2450 */
2451
Denis Vlasenko7e497522008-02-12 09:51:03 +00002452static int execute(struct op *t, int *pin, int *pout, int no_fork)
Eric Andersenff9eee42001-06-29 04:57:14 +00002453{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002454 struct op *t1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002455 volatile int i, rv, a;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002456 const char *cp;
2457 char **wp, **wp2;
Eric Andersenff9eee42001-06-29 04:57:14 +00002458 struct var *vp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002459 struct op *outtree_save;
Eric Andersenff9eee42001-06-29 04:57:14 +00002460 struct brkcon bc;
2461
2462#if __GNUC__
2463 /* Avoid longjmp clobbering */
2464 (void) &wp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002465#endif
Eric Andersenff9eee42001-06-29 04:57:14 +00002466
Eric Andersen12de6cf2004-08-04 19:19:10 +00002467 if (t == NULL) {
2468 DBGPRINTF4(("EXECUTE: enter, t==null, returning.\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002469 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002470 }
2471
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002472 DBGPRINTF(("EXECUTE: t=%p, t->type=%d (%s), t->words is %s\n", t,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002473 t->type, T_CMD_NAMES[t->type],
2474 ((t->words == NULL) ? "NULL" : t->words[0])));
2475
Eric Andersenff9eee42001-06-29 04:57:14 +00002476 rv = 0;
2477 a = areanum++;
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002478 wp2 = t->words;
2479 wp = (wp2 != NULL)
Eric Andersen8401eea2004-08-04 19:16:54 +00002480 ? eval(wp2, t->type == TCOM ? DOALL : DOALL & ~DOKEY)
2481 : NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00002482
Eric Andersen8401eea2004-08-04 19:16:54 +00002483 switch (t->type) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002484 case TDOT:
2485 DBGPRINTF3(("EXECUTE: TDOT\n"));
2486
2487 outtree_save = outtree;
2488
2489 newfile(evalstr(t->words[0], DOALL));
2490
2491 t->left = dowholefile(TLIST, 0);
2492 t->right = NULL;
2493
2494 outtree = outtree_save;
2495
2496 if (t->left)
Denis Vlasenko7e497522008-02-12 09:51:03 +00002497 rv = execute(t->left, pin, pout, /* no_fork: */ 0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002498 if (t->right)
Denis Vlasenko7e497522008-02-12 09:51:03 +00002499 rv = execute(t->right, pin, pout, /* no_fork: */ 0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002500 break;
2501
Eric Andersenff9eee42001-06-29 04:57:14 +00002502 case TPAREN:
Denis Vlasenko7e497522008-02-12 09:51:03 +00002503 rv = execute(t->left, pin, pout, /* no_fork: */ 0);
Eric Andersen737f5fb2003-03-14 16:05:59 +00002504 break;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002505
Eric Andersenff9eee42001-06-29 04:57:14 +00002506 case TCOM:
Denis Vlasenko7e497522008-02-12 09:51:03 +00002507 rv = forkexec(t, pin, pout, no_fork, wp);
Eric Andersenff9eee42001-06-29 04:57:14 +00002508 break;
2509
2510 case TPIPE:
2511 {
Eric Andersen8401eea2004-08-04 19:16:54 +00002512 int pv[2];
2513
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002514 rv = openpipe(pv);
2515 if (rv < 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00002516 break;
2517 pv[0] = remap(pv[0]);
2518 pv[1] = remap(pv[1]);
Denis Vlasenko7e497522008-02-12 09:51:03 +00002519 (void) execute(t->left, pin, pv, /* no_fork: */ 0);
2520 rv = execute(t->right, pv, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002521 }
2522 break;
2523
2524 case TLIST:
Denis Vlasenko7e497522008-02-12 09:51:03 +00002525 (void) execute(t->left, pin, pout, /* no_fork: */ 0);
2526 rv = execute(t->right, pin, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002527 break;
2528
2529 case TASYNC:
Eric Andersen8401eea2004-08-04 19:16:54 +00002530 {
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002531 smallint hinteractive = interactive;
Eric Andersenff9eee42001-06-29 04:57:14 +00002532
Eric Andersen12de6cf2004-08-04 19:19:10 +00002533 DBGPRINTF7(("EXECUTE: TASYNC clause, calling vfork()...\n"));
2534
Eric Andersen8401eea2004-08-04 19:16:54 +00002535 i = vfork();
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002536 if (i == 0) { /* child */
Eric Andersen8401eea2004-08-04 19:16:54 +00002537 signal(SIGINT, SIG_IGN);
2538 signal(SIGQUIT, SIG_IGN);
2539 if (interactive)
2540 signal(SIGTERM, SIG_DFL);
2541 interactive = 0;
2542 if (pin == NULL) {
2543 close(0);
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00002544 xopen(bb_dev_null, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00002545 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002546 _exit(execute(t->left, pin, pout, /* no_fork: */ 1));
Eric Andersenff9eee42001-06-29 04:57:14 +00002547 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002548 interactive = hinteractive;
2549 if (i != -1) {
2550 setval(lookup("!"), putn(i));
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002551 closepipe(pin);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002552 if (interactive) {
2553 prs(putn(i));
2554 prs("\n");
2555 }
2556 } else
2557 rv = -1;
2558 setstatus(rv);
Eric Andersenff9eee42001-06-29 04:57:14 +00002559 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002560 break;
2561
2562 case TOR:
2563 case TAND:
Denis Vlasenko7e497522008-02-12 09:51:03 +00002564 rv = execute(t->left, pin, pout, /* no_fork: */ 0);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002565 t1 = t->right;
2566 if (t1 != NULL && (rv == 0) == (t->type == TAND))
Denis Vlasenko7e497522008-02-12 09:51:03 +00002567 rv = execute(t1, pin, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002568 break;
2569
2570 case TFOR:
2571 if (wp == NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00002572 wp = dolv + 1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002573 i = dolc;
2574 if (i < 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00002575 i = 0;
2576 } else {
2577 i = -1;
Eric Andersen8401eea2004-08-04 19:16:54 +00002578 while (*wp++ != NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00002579 }
2580 vp = lookup(t->str);
2581 while (setjmp(bc.brkpt))
2582 if (isbreak)
2583 goto broken;
2584 brkset(&bc);
2585 for (t1 = t->left; i-- && *wp != NULL;) {
2586 setval(vp, *wp++);
Denis Vlasenko7e497522008-02-12 09:51:03 +00002587 rv = execute(t1, pin, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002588 }
2589 brklist = brklist->nextlev;
2590 break;
2591
2592 case TWHILE:
2593 case TUNTIL:
2594 while (setjmp(bc.brkpt))
2595 if (isbreak)
2596 goto broken;
2597 brkset(&bc);
2598 t1 = t->left;
Denis Vlasenko7e497522008-02-12 09:51:03 +00002599 while ((execute(t1, pin, pout, /* no_fork: */ 0) == 0) == (t->type == TWHILE))
2600 rv = execute(t->right, pin, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002601 brklist = brklist->nextlev;
2602 break;
2603
2604 case TIF:
2605 case TELIF:
Eric Andersen8401eea2004-08-04 19:16:54 +00002606 if (t->right != NULL) {
Denis Vlasenko7e497522008-02-12 09:51:03 +00002607 rv = !execute(t->left, pin, pout, /* no_fork: */ 0) ?
2608 execute(t->right->left, pin, pout, /* no_fork: */ 0) :
2609 execute(t->right->right, pin, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002610 }
2611 break;
2612
2613 case TCASE:
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002614 cp = evalstr(t->str, DOSUB | DOTRIM);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002615 if (cp == NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00002616 cp = "";
Eric Andersen12de6cf2004-08-04 19:19:10 +00002617
2618 DBGPRINTF7(("EXECUTE: TCASE, t->str is %s, cp is %s\n",
2619 ((t->str == NULL) ? "NULL" : t->str),
2620 ((cp == NULL) ? "NULL" : cp)));
2621
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002622 t1 = findcase(t->left, cp);
2623 if (t1 != NULL) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002624 DBGPRINTF7(("EXECUTE: TCASE, calling execute(t=%p, t1=%p)...\n", t, t1));
Denis Vlasenko7e497522008-02-12 09:51:03 +00002625 rv = execute(t1, pin, pout, /* no_fork: */ 0);
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002626 DBGPRINTF7(("EXECUTE: TCASE, back from execute(t=%p, t1=%p)...\n", t, t1));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002627 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002628 break;
2629
2630 case TBRACE:
2631/*
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002632 iopp = t->ioact;
2633 if (i)
Eric Andersenff9eee42001-06-29 04:57:14 +00002634 while (*iopp)
2635 if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) {
2636 rv = -1;
2637 break;
2638 }
2639*/
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002640 if (rv >= 0) {
2641 t1 = t->left;
2642 if (t1) {
Denis Vlasenko7e497522008-02-12 09:51:03 +00002643 rv = execute(t1, pin, pout, /* no_fork: */ 0);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002644 }
2645 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002646 break;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002647
2648 };
Eric Andersenff9eee42001-06-29 04:57:14 +00002649
Denis Vlasenkoe4712752007-04-14 15:08:41 +00002650 broken:
Eric Andersenff9eee42001-06-29 04:57:14 +00002651 t->words = wp2;
2652 isbreak = 0;
2653 freehere(areanum);
2654 freearea(areanum);
2655 areanum = a;
2656 if (interactive && intr) {
2657 closeall();
2658 fail();
2659 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002660
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002661 i = trapset;
2662 if (i != 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002663 trapset = 0;
2664 runtrap(i);
2665 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002666
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002667 DBGPRINTF(("EXECUTE: returning from t=%p, rv=%d\n", t, rv));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002668 return rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00002669}
2670
Denis Vlasenkoe4712752007-04-14 15:08:41 +00002671static builtin_func_ptr inbuilt(const char *s)
2672{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002673 const struct builtincmd *bp;
2674
Denis Vlasenko95cb3262007-04-09 03:06:34 +00002675 for (bp = builtincmds; bp->name; bp++)
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002676 if (strcmp(bp->name, s) == 0)
2677 return bp->builtinfunc;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002678 return NULL;
2679}
2680
Denis Vlasenko7e497522008-02-12 09:51:03 +00002681static int forkexec(struct op *t, int *pin, int *pout, int no_fork, char **wp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002682{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002683 pid_t newpid;
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002684 int i;
2685 builtin_func_ptr bltin = NULL;
Denis Vlasenko7e497522008-02-12 09:51:03 +00002686 const char *bltin_name = NULL;
2687 const char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00002688 struct ioword **iopp;
2689 int resetsig;
2690 char **owp;
Denis Vlasenko7e497522008-02-12 09:51:03 +00002691 int forked;
Eric Andersenff9eee42001-06-29 04:57:14 +00002692
2693 int *hpin = pin;
2694 int *hpout = pout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002695 char *hwp;
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002696 smallint hinteractive;
2697 smallint hintr;
2698 smallint hexecflg;
Eric Andersen8401eea2004-08-04 19:16:54 +00002699 struct brkcon *hbrklist;
Eric Andersenff9eee42001-06-29 04:57:14 +00002700
2701#if __GNUC__
2702 /* Avoid longjmp clobbering */
2703 (void) &pin;
2704 (void) &pout;
2705 (void) &wp;
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002706 (void) &bltin;
Eric Andersenff9eee42001-06-29 04:57:14 +00002707 (void) &cp;
2708 (void) &resetsig;
2709 (void) &owp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002710#endif
Eric Andersenff9eee42001-06-29 04:57:14 +00002711
Denis Vlasenko7e497522008-02-12 09:51:03 +00002712 DBGPRINTF(("FORKEXEC: t=%p, pin %p, pout %p, no_fork %d\n", t, pin,
2713 pout, no_fork));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002714 DBGPRINTF7(("FORKEXEC: t->words is %s\n",
Denis Vlasenko7e497522008-02-12 09:51:03 +00002715 ((t->words == NULL) ? "NULL" : t->words[0])));
Eric Andersenff9eee42001-06-29 04:57:14 +00002716 owp = wp;
2717 resetsig = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002718 if (t->type == TCOM) {
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00002719 while (*wp++ != NULL)
2720 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00002721 cp = *wp;
2722
2723 /* strip all initial assignments */
Denis Vlasenko7e497522008-02-12 09:51:03 +00002724 /* FIXME: not correct wrt PATH=yyy command etc */
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00002725 if (FLAG['x']) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002726 DBGPRINTF9(("FORKEXEC: echo'ing, cp=%p, wp=%p, owp=%p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00002727 cp, wp, owp));
Eric Andersen8401eea2004-08-04 19:16:54 +00002728 echo(cp ? wp : owp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002729 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002730
Denis Vlasenko7e497522008-02-12 09:51:03 +00002731 if (cp == NULL) {
2732 if (t->ioact == NULL) {
2733 while ((cp = *owp++) != NULL && assign(cp, COPYV))
2734 continue;
2735 DBGPRINTF(("FORKEXEC: returning setstatus(0)\n"));
2736 return setstatus(0);
2737 }
2738 } else { /* cp != NULL */
2739 bltin_name = cp;
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002740 bltin = inbuilt(cp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002741 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002742 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002743
Denis Vlasenko7e497522008-02-12 09:51:03 +00002744 forked = 0;
Denis Vlasenkofe218832008-03-01 09:35:39 +00002745 // We were pointing t->words to temporary (expanded) arg list:
2746 // t->words = wp;
2747 // and restored it later (in execute()), but "break"
2748 // longjmps away (at "Run builtin" below), leaving t->words clobbered!
2749 // See http://bugs.busybox.net/view.php?id=846.
2750 // Now we do not touch t->words, but separately pass wp as param list
2751 // to builtins
Denis Vlasenko7e497522008-02-12 09:51:03 +00002752 DBGPRINTF(("FORKEXEC: bltin %p, no_fork %d, owp %p\n", bltin,
2753 no_fork, owp));
2754 /* Don't fork if it is a lone builtin (not in pipe)
2755 * OR we are told to _not_ fork */
2756 if ((!bltin || pin || pout) /* not lone bltin AND */
2757 && !no_fork /* not told to avoid fork */
2758 ) {
2759 /* Save values in case child alters them after vfork */
Eric Andersenff9eee42001-06-29 04:57:14 +00002760 hpin = pin;
2761 hpout = pout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002762 hwp = *wp;
2763 hinteractive = interactive;
2764 hintr = intr;
2765 hbrklist = brklist;
2766 hexecflg = execflg;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002767
Eric Andersen12de6cf2004-08-04 19:19:10 +00002768 DBGPRINTF3(("FORKEXEC: calling vfork()...\n"));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002769 newpid = vfork();
Eric Andersen12de6cf2004-08-04 19:19:10 +00002770 if (newpid == -1) {
Denis Vlasenko89f0b342006-11-18 22:04:09 +00002771 DBGPRINTF(("FORKEXEC: ERROR, cannot vfork()!\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002772 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002773 }
2774
Denis Vlasenko489f93e2007-02-01 01:43:16 +00002775 if (newpid > 0) { /* Parent */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002776 /* Restore values */
Eric Andersenff9eee42001-06-29 04:57:14 +00002777 pin = hpin;
2778 pout = hpout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002779 *wp = hwp;
2780 interactive = hinteractive;
2781 intr = hintr;
2782 brklist = hbrklist;
2783 execflg = hexecflg;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002784
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002785 closepipe(pin);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002786 return (pout == NULL ? setstatus(waitfor(newpid, 0)) : 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002787 }
2788
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002789 /* Child */
Denis Vlasenko7e497522008-02-12 09:51:03 +00002790 DBGPRINTF(("FORKEXEC: child process, bltin=%p (%s)\n", bltin, bltin_name));
Eric Andersenff9eee42001-06-29 04:57:14 +00002791 if (interactive) {
2792 signal(SIGINT, SIG_IGN);
2793 signal(SIGQUIT, SIG_IGN);
2794 resetsig = 1;
2795 }
2796 interactive = 0;
2797 intr = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002798 forked = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002799 brklist = 0;
2800 execflg = 0;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002801 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002802
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002803 if (owp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002804 while ((cp = *owp++) != NULL && assign(cp, COPYV))
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002805 if (!bltin)
Eric Andersenff9eee42001-06-29 04:57:14 +00002806 export(lookup(cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002807
Denis Vlasenko284d0fa2008-02-16 13:18:17 +00002808 if (pin) { /* NB: close _first_, then move fds! */
2809 close(pin[1]);
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00002810 xmove_fd(pin[0], 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002811 }
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002812 if (pout) {
Denis Vlasenko284d0fa2008-02-16 13:18:17 +00002813 close(pout[0]);
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00002814 xmove_fd(pout[1], 1);
Eric Andersenff9eee42001-06-29 04:57:14 +00002815 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002816
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002817 iopp = t->ioact;
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002818 if (iopp) {
2819 if (bltin && bltin != doexec) {
Denis Vlasenko7e497522008-02-12 09:51:03 +00002820 prs(bltin_name);
Eric Andersenff9eee42001-06-29 04:57:14 +00002821 err(": cannot redirect shell command");
Eric Andersen12de6cf2004-08-04 19:19:10 +00002822 if (forked)
2823 _exit(-1);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002824 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002825 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002826 while (*iopp) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002827 if (iosetup(*iopp++, pin != NULL, pout != NULL)) {
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002828 /* system-detected error */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002829 if (forked)
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002830 _exit(-1);
2831 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002832 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002833 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002834 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002835
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002836 if (bltin) {
Denis Vlasenko7e497522008-02-12 09:51:03 +00002837 if (forked || pin || pout) {
2838 /* Builtin in pipe: disallowed */
2839 /* TODO: allow "exec"? */
2840 prs(bltin_name);
2841 err(": cannot run builtin as part of pipe");
2842 if (forked)
2843 _exit(-1);
2844 return -1;
2845 }
Denis Vlasenkofe218832008-03-01 09:35:39 +00002846 /* Run builtin */
2847 i = setstatus(bltin(t, wp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002848 if (forked)
2849 _exit(i);
2850 DBGPRINTF(("FORKEXEC: returning i=%d\n", i));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002851 return i;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002852 }
2853
Eric Andersenff9eee42001-06-29 04:57:14 +00002854 /* should use FIOCEXCL */
Eric Andersen8401eea2004-08-04 19:16:54 +00002855 for (i = FDBASE; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00002856 close(i);
2857 if (resetsig) {
2858 signal(SIGINT, SIG_DFL);
2859 signal(SIGQUIT, SIG_DFL);
2860 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002861
Eric Andersen12de6cf2004-08-04 19:19:10 +00002862 if (t->type == TPAREN)
Denis Vlasenko7e497522008-02-12 09:51:03 +00002863 _exit(execute(t->left, NOPIPE, NOPIPE, /* no_fork: */ 1));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002864 if (wp[0] == NULL)
2865 _exit(0);
2866
Eric Andersenfd7a4c82004-09-02 23:13:10 +00002867 cp = rexecve(wp[0], wp, makenv(0, NULL));
Eric Andersen8401eea2004-08-04 19:16:54 +00002868 prs(wp[0]);
2869 prs(": ");
Eric Andersen12de6cf2004-08-04 19:19:10 +00002870 err(cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00002871 if (!execflg)
2872 trap[0] = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002873
Denis Vlasenko7e497522008-02-12 09:51:03 +00002874 DBGPRINTF(("FORKEXEC: calling leave(), pid=%d\n", getpid()));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002875
Eric Andersenff9eee42001-06-29 04:57:14 +00002876 leave();
2877 /* NOTREACHED */
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002878 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002879}
2880
2881/*
2882 * 0< 1> are ignored as required
2883 * within pipelines.
2884 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002885static int iosetup(struct ioword *iop, int pipein, int pipeout)
Eric Andersenff9eee42001-06-29 04:57:14 +00002886{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002887 int u = -1;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002888 char *cp = NULL;
2889 const char *msg;
Eric Andersenff9eee42001-06-29 04:57:14 +00002890
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002891 DBGPRINTF(("IOSETUP: iop %p, pipein %i, pipeout %i\n", iop,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002892 pipein, pipeout));
2893
Eric Andersenff9eee42001-06-29 04:57:14 +00002894 if (iop->io_unit == IODEFAULT) /* take default */
Eric Andersen8401eea2004-08-04 19:16:54 +00002895 iop->io_unit = iop->io_flag & (IOREAD | IOHERE) ? 0 : 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002896
Eric Andersenff9eee42001-06-29 04:57:14 +00002897 if (pipein && iop->io_unit == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002898 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002899
Eric Andersenff9eee42001-06-29 04:57:14 +00002900 if (pipeout && iop->io_unit == 1)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002901 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002902
Eric Andersen8401eea2004-08-04 19:16:54 +00002903 msg = iop->io_flag & (IOREAD | IOHERE) ? "open" : "create";
Eric Andersenff9eee42001-06-29 04:57:14 +00002904 if ((iop->io_flag & IOHERE) == 0) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002905 cp = iop->io_name; /* huh?? */
2906 cp = evalstr(cp, DOSUB | DOTRIM);
2907 if (cp == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002908 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002909 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002910
Eric Andersenff9eee42001-06-29 04:57:14 +00002911 if (iop->io_flag & IODUP) {
2912 if (cp[1] || (!isdigit(*cp) && *cp != '-')) {
2913 prs(cp);
2914 err(": illegal >& argument");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002915 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002916 }
2917 if (*cp == '-')
2918 iop->io_flag = IOCLOSE;
Eric Andersen8401eea2004-08-04 19:16:54 +00002919 iop->io_flag &= ~(IOREAD | IOWRITE);
Eric Andersenff9eee42001-06-29 04:57:14 +00002920 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002921
Eric Andersenff9eee42001-06-29 04:57:14 +00002922 switch (iop->io_flag) {
2923 case IOREAD:
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00002924 u = open(cp, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00002925 break;
2926
2927 case IOHERE:
Eric Andersen8401eea2004-08-04 19:16:54 +00002928 case IOHERE | IOXHERE:
2929 u = herein(iop->io_name, iop->io_flag & IOXHERE);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002930 cp = (char*)"here file";
Eric Andersenff9eee42001-06-29 04:57:14 +00002931 break;
2932
Eric Andersen8401eea2004-08-04 19:16:54 +00002933 case IOWRITE | IOCAT:
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00002934 u = open(cp, O_WRONLY);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002935 if (u >= 0) {
Denis Vlasenkoea620772006-10-14 02:23:43 +00002936 lseek(u, (long) 0, SEEK_END);
Eric Andersenff9eee42001-06-29 04:57:14 +00002937 break;
2938 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002939 /* fall through to creation if >>file doesn't exist */
2940
Eric Andersenff9eee42001-06-29 04:57:14 +00002941 case IOWRITE:
2942 u = creat(cp, 0666);
2943 break;
2944
2945 case IODUP:
Eric Andersen8401eea2004-08-04 19:16:54 +00002946 u = dup2(*cp - '0', iop->io_unit);
Eric Andersenff9eee42001-06-29 04:57:14 +00002947 break;
2948
2949 case IOCLOSE:
2950 close(iop->io_unit);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002951 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002952 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002953
Eric Andersenff9eee42001-06-29 04:57:14 +00002954 if (u < 0) {
2955 prs(cp);
2956 prs(": cannot ");
2957 warn(msg);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002958 return 1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002959 }
2960 if (u != iop->io_unit) {
2961 dup2(u, iop->io_unit);
2962 close(u);
Eric Andersenff9eee42001-06-29 04:57:14 +00002963 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002964 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002965}
2966
Eric Andersenff9eee42001-06-29 04:57:14 +00002967/*
2968 * Enter a new loop level (marked for break/continue).
2969 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002970static void brkset(struct brkcon *bc)
Eric Andersenff9eee42001-06-29 04:57:14 +00002971{
2972 bc->nextlev = brklist;
2973 brklist = bc;
2974}
2975
2976/*
2977 * Wait for the last process created.
2978 * Print a message for each process found
2979 * that was killed by a signal.
2980 * Ignore interrupt signals while waiting
2981 * unless `canintr' is true.
2982 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002983static int waitfor(int lastpid, int canintr)
Eric Andersenff9eee42001-06-29 04:57:14 +00002984{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002985 int pid, rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00002986 int s;
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002987 smallint oheedint = heedint;
Eric Andersenff9eee42001-06-29 04:57:14 +00002988
2989 heedint = 0;
2990 rv = 0;
2991 do {
2992 pid = wait(&s);
2993 if (pid == -1) {
2994 if (errno != EINTR || canintr)
2995 break;
2996 } else {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002997 rv = WAITSIG(s);
2998 if (rv != 0) {
Denis Vlasenko80b8b392007-06-25 10:55:35 +00002999 if (rv < ARRAY_SIZE(signame)) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003000 if (signame[rv] != NULL) {
3001 if (pid != lastpid) {
3002 prn(pid);
3003 prs(": ");
3004 }
3005 prs(signame[rv]);
3006 }
3007 } else {
3008 if (pid != lastpid) {
3009 prn(pid);
3010 prs(": ");
3011 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003012 prs("Signal ");
3013 prn(rv);
3014 prs(" ");
Eric Andersenff9eee42001-06-29 04:57:14 +00003015 }
3016 if (WAITCORE(s))
3017 prs(" - core dumped");
Denis Vlasenko80b8b392007-06-25 10:55:35 +00003018 if (rv >= ARRAY_SIZE(signame) || signame[rv])
Eric Andersenff9eee42001-06-29 04:57:14 +00003019 prs("\n");
3020 rv = -1;
3021 } else
3022 rv = WAITVAL(s);
3023 }
3024 } while (pid != lastpid);
3025 heedint = oheedint;
3026 if (intr) {
3027 if (interactive) {
3028 if (canintr)
3029 intr = 0;
3030 } else {
Eric Andersen8401eea2004-08-04 19:16:54 +00003031 if (exstat == 0)
3032 exstat = rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003033 onintr(0);
3034 }
3035 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003036 return rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003037}
3038
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003039static int setstatus(int s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003040{
3041 exstat = s;
3042 setval(lookup("?"), putn(s));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003043 return s;
Eric Andersenff9eee42001-06-29 04:57:14 +00003044}
3045
3046/*
3047 * PATH-searching interface to execve.
3048 * If getenv("PATH") were kept up-to-date,
3049 * execvp might be used.
3050 */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003051static const char *rexecve(char *c, char **v, char **envp)
Eric Andersenff9eee42001-06-29 04:57:14 +00003052{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003053 int i;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003054 const char *sp;
3055 char *tp;
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00003056 int asis = 0;
Eric Andersen1c039232001-07-07 00:05:55 +00003057 char *name = c;
Eric Andersen8401eea2004-08-04 19:16:54 +00003058
Denis Vlasenko80d14be2007-04-10 23:03:30 +00003059 if (ENABLE_FEATURE_SH_STANDALONE) {
Denis Vlasenko1aa7e472007-11-28 06:49:03 +00003060 if (find_applet_by_name(name) >= 0) {
Rob Landleya299efb2006-08-10 21:46:43 +00003061 /* We have to exec here since we vforked. Running
Denis Vlasenkoe4f2d062007-04-11 17:03:19 +00003062 * run_applet_and_exit() won't work and bad things
Rob Landleya299efb2006-08-10 21:46:43 +00003063 * will happen. */
Denis Vlasenkobdbbb7e2007-06-08 15:02:55 +00003064 execve(bb_busybox_exec_path, v, envp);
Rob Landleya299efb2006-08-10 21:46:43 +00003065 }
Eric Andersen1c039232001-07-07 00:05:55 +00003066 }
Eric Andersen1c039232001-07-07 00:05:55 +00003067
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003068 DBGPRINTF(("REXECVE: c=%p, v=%p, envp=%p\n", c, v, envp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003069
Eric Andersen8401eea2004-08-04 19:16:54 +00003070 sp = any('/', c) ? "" : path->value;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003071 asis = (*sp == '\0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003072 while (asis || *sp != '\0') {
3073 asis = 0;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003074 tp = global_env.linep;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003075 for (; *sp != '\0'; tp++) {
3076 *tp = *sp++;
3077 if (*tp == ':') {
3078 asis = (*sp == '\0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003079 break;
3080 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003081 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003082 if (tp != global_env.linep)
Eric Andersenff9eee42001-06-29 04:57:14 +00003083 *tp++ = '/';
Eric Andersen8401eea2004-08-04 19:16:54 +00003084 for (i = 0; (*tp++ = c[i++]) != '\0';);
Eric Andersen1c039232001-07-07 00:05:55 +00003085
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003086 DBGPRINTF3(("REXECVE: global_env.linep is %s\n", global_env.linep));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003087
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003088 execve(global_env.linep, v, envp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003089
Eric Andersenff9eee42001-06-29 04:57:14 +00003090 switch (errno) {
3091 case ENOEXEC:
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003092 *v = global_env.linep;
Eric Andersenff9eee42001-06-29 04:57:14 +00003093 tp = *--v;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003094 *v = global_env.linep;
Glenn L McGrathdc4e75e2003-09-02 02:36:18 +00003095 execve(DEFAULT_SHELL, v, envp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003096 *v = tp;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003097 return "no Shell";
Eric Andersenff9eee42001-06-29 04:57:14 +00003098
3099 case ENOMEM:
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003100 return (char *) bb_msg_memory_exhausted;
Eric Andersenff9eee42001-06-29 04:57:14 +00003101
3102 case E2BIG:
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003103 return "argument list too long";
Eric Andersenff9eee42001-06-29 04:57:14 +00003104 }
3105 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003106 return errno == ENOENT ? "not found" : "cannot execute";
Eric Andersenff9eee42001-06-29 04:57:14 +00003107}
3108
3109/*
3110 * Run the command produced by generator `f'
3111 * applied to stream `arg'.
3112 */
Eric Andersen8401eea2004-08-04 19:16:54 +00003113static int run(struct ioarg *argp, int (*f) (struct ioarg *))
Eric Andersenff9eee42001-06-29 04:57:14 +00003114{
3115 struct op *otree;
3116 struct wdblock *swdlist;
3117 struct wdblock *siolist;
3118 jmp_buf ev, rt;
3119 xint *ofail;
3120 int rv;
3121
3122#if __GNUC__
3123 /* Avoid longjmp clobbering */
3124 (void) &rv;
3125#endif
3126
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003127 DBGPRINTF(("RUN: enter, areanum %d, outtree %p, failpt %p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00003128 areanum, outtree, failpt));
3129
Eric Andersenff9eee42001-06-29 04:57:14 +00003130 areanum++;
3131 swdlist = wdlist;
3132 siolist = iolist;
3133 otree = outtree;
3134 ofail = failpt;
3135 rv = -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003136
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003137 errpt = ev;
3138 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003139 wdlist = 0;
3140 iolist = 0;
3141 pushio(argp, f);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003142 global_env.iobase = global_env.iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00003143 yynerrs = 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003144 failpt = rt;
3145 if (setjmp(failpt) == 0 && yyparse() == 0)
Denis Vlasenko7e497522008-02-12 09:51:03 +00003146 rv = execute(outtree, NOPIPE, NOPIPE, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003147 quitenv();
Eric Andersen12de6cf2004-08-04 19:19:10 +00003148 } else {
3149 DBGPRINTF(("RUN: error from newenv()!\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00003150 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00003151
Eric Andersenff9eee42001-06-29 04:57:14 +00003152 wdlist = swdlist;
3153 iolist = siolist;
3154 failpt = ofail;
3155 outtree = otree;
3156 freearea(areanum--);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003157
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003158 return rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003159}
3160
3161/* -------- do.c -------- */
3162
3163/*
3164 * built-in commands: doX
3165 */
3166
Denis Vlasenkofe218832008-03-01 09:35:39 +00003167static int dohelp(struct op *t, char **args)
Eric Andersen1c039232001-07-07 00:05:55 +00003168{
3169 int col;
3170 const struct builtincmd *x;
3171
Denis Vlasenko0ee39992006-12-24 15:23:28 +00003172 puts("\nBuilt-in commands:\n"
3173 "-------------------");
Eric Andersen1c039232001-07-07 00:05:55 +00003174
Denis Vlasenko95cb3262007-04-09 03:06:34 +00003175 col = 0;
3176 x = builtincmds;
3177 while (x->name) {
3178 col += printf("%c%s", ((col == 0) ? '\t' : ' '), x->name);
Eric Andersen1c039232001-07-07 00:05:55 +00003179 if (col > 60) {
Denis Vlasenko4daad902007-09-27 10:20:47 +00003180 bb_putchar('\n');
Eric Andersen1c039232001-07-07 00:05:55 +00003181 col = 0;
3182 }
Denis Vlasenko95cb3262007-04-09 03:06:34 +00003183 x++;
Eric Andersen1c039232001-07-07 00:05:55 +00003184 }
Denis Vlasenko80d14be2007-04-10 23:03:30 +00003185#if ENABLE_FEATURE_SH_STANDALONE
Eric Andersen1c039232001-07-07 00:05:55 +00003186 {
Denis Vlasenko1aa7e472007-11-28 06:49:03 +00003187 const char *applet = applet_names;
Eric Andersen1c039232001-07-07 00:05:55 +00003188
Denis Vlasenko1aa7e472007-11-28 06:49:03 +00003189 while (*applet) {
3190 col += printf("%c%s", ((col == 0) ? '\t' : ' '), applet);
Eric Andersen1c039232001-07-07 00:05:55 +00003191 if (col > 60) {
Denis Vlasenko4daad902007-09-27 10:20:47 +00003192 bb_putchar('\n');
Eric Andersen1c039232001-07-07 00:05:55 +00003193 col = 0;
3194 }
Denis Vlasenko1aa7e472007-11-28 06:49:03 +00003195 applet += strlen(applet) + 1;
Eric Andersen1c039232001-07-07 00:05:55 +00003196 }
3197 }
3198#endif
Denis Vlasenko0ee39992006-12-24 15:23:28 +00003199 puts("\n");
Eric Andersen1c039232001-07-07 00:05:55 +00003200 return EXIT_SUCCESS;
3201}
3202
Denis Vlasenkofe218832008-03-01 09:35:39 +00003203static int dolabel(struct op *t, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003204{
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003205 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003206}
3207
Denis Vlasenkofe218832008-03-01 09:35:39 +00003208static int dochdir(struct op *t, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003209{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003210 const char *cp, *er;
Eric Andersenff9eee42001-06-29 04:57:14 +00003211
Denis Vlasenkofe218832008-03-01 09:35:39 +00003212 cp = args[1];
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003213 if (cp == NULL) {
3214 cp = homedir->value;
Denis Vlasenkod244c5e2007-02-09 17:30:14 +00003215 if (cp != NULL)
3216 goto do_cd;
3217 er = ": no home directory";
3218 } else {
3219 do_cd:
3220 if (chdir(cp) >= 0)
3221 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003222 er = ": bad directory";
Denis Vlasenkod244c5e2007-02-09 17:30:14 +00003223 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003224 prs(cp != NULL ? cp : "cd");
Eric Andersenff9eee42001-06-29 04:57:14 +00003225 err(er);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003226 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003227}
3228
Denis Vlasenkofe218832008-03-01 09:35:39 +00003229static int doshift(struct op *t, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003230{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003231 int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003232
Denis Vlasenkofe218832008-03-01 09:35:39 +00003233 n = args[1] ? getn(args[1]) : 1;
Eric Andersen8401eea2004-08-04 19:16:54 +00003234 if (dolc < n) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003235 err("nothing to shift");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003236 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003237 }
3238 dolv[n] = dolv[0];
3239 dolv += n;
3240 dolc -= n;
3241 setval(lookup("#"), putn(dolc));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003242 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003243}
3244
3245/*
3246 * execute login and newgrp directly
3247 */
Denis Vlasenkofe218832008-03-01 09:35:39 +00003248static int dologin(struct op *t, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003249{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003250 const char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003251
3252 if (interactive) {
3253 signal(SIGINT, SIG_DFL);
3254 signal(SIGQUIT, SIG_DFL);
3255 }
Denis Vlasenkofe218832008-03-01 09:35:39 +00003256 cp = rexecve(args[0], args, makenv(0, NULL));
3257 prs(args[0]);
Eric Andersen8401eea2004-08-04 19:16:54 +00003258 prs(": ");
3259 err(cp);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003260 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003261}
3262
Denis Vlasenkofe218832008-03-01 09:35:39 +00003263static int doumask(struct op *t, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003264{
Denis Vlasenko7e497522008-02-12 09:51:03 +00003265 int i;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003266 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003267
Denis Vlasenkofe218832008-03-01 09:35:39 +00003268 cp = args[1];
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003269 if (cp == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003270 i = umask(0);
3271 umask(i);
Denis Vlasenko7e497522008-02-12 09:51:03 +00003272 printf("%04o\n", i);
Eric Andersenff9eee42001-06-29 04:57:14 +00003273 } else {
Denis Vlasenko7e497522008-02-12 09:51:03 +00003274 i = bb_strtou(cp, NULL, 8);
3275 if (errno) {
3276 err("umask: bad octal number");
3277 return 1;
3278 }
3279 umask(i);
Eric Andersenff9eee42001-06-29 04:57:14 +00003280 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003281 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003282}
3283
Denis Vlasenkofe218832008-03-01 09:35:39 +00003284static int doexec(struct op *t, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003285{
Eric Andersenff9eee42001-06-29 04:57:14 +00003286 jmp_buf ex;
3287 xint *ofail;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003288 char **sv_words;
Eric Andersenff9eee42001-06-29 04:57:14 +00003289
3290 t->ioact = NULL;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003291 if (!args[1])
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003292 return 1;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003293
Eric Andersenff9eee42001-06-29 04:57:14 +00003294 execflg = 1;
3295 ofail = failpt;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003296 failpt = ex;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003297
3298 sv_words = t->words;
3299 t->words = args + 1;
3300// TODO: test what will happen with "exec break" -
3301// will it leave t->words pointing to garbage?
3302// (see http://bugs.busybox.net/view.php?id=846)
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003303 if (setjmp(failpt) == 0)
Denis Vlasenko7e497522008-02-12 09:51:03 +00003304 execute(t, NOPIPE, NOPIPE, /* no_fork: */ 1);
Denis Vlasenkofe218832008-03-01 09:35:39 +00003305 t->words = sv_words;
3306
Eric Andersenff9eee42001-06-29 04:57:14 +00003307 failpt = ofail;
3308 execflg = 0;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003309
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003310 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003311}
3312
Denis Vlasenkofe218832008-03-01 09:35:39 +00003313static int dodot(struct op *t, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003314{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003315 int i;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003316 const char *sp;
3317 char *tp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003318 char *cp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003319 int maltmp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003320
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003321 DBGPRINTF(("DODOT: enter, t=%p, tleft %p, tright %p, global_env.linep is %s\n",
3322 t, t->left, t->right, ((global_env.linep == NULL) ? "NULL" : global_env.linep)));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003323
Denis Vlasenkofe218832008-03-01 09:35:39 +00003324 cp = args[1];
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003325 if (cp == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00003326 DBGPRINTF(("DODOT: bad args, ret 0\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003327 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003328 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003329 DBGPRINTF(("DODOT: cp is %s\n", cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003330
Eric Andersen8401eea2004-08-04 19:16:54 +00003331 sp = any('/', cp) ? ":" : path->value;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003332
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003333 DBGPRINTF(("DODOT: sp is %s, global_env.linep is %s\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00003334 ((sp == NULL) ? "NULL" : sp),
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003335 ((global_env.linep == NULL) ? "NULL" : global_env.linep)));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003336
Eric Andersenff9eee42001-06-29 04:57:14 +00003337 while (*sp) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003338 tp = global_env.linep;
Eric Andersenff9eee42001-06-29 04:57:14 +00003339 while (*sp && (*tp = *sp++) != ':')
3340 tp++;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003341 if (tp != global_env.linep)
Eric Andersenff9eee42001-06-29 04:57:14 +00003342 *tp++ = '/';
Eric Andersen12de6cf2004-08-04 19:19:10 +00003343
Eric Andersen8401eea2004-08-04 19:16:54 +00003344 for (i = 0; (*tp++ = cp[i++]) != '\0';);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003345
3346 /* Original code */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003347 i = open(global_env.linep, O_RDONLY);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003348 if (i >= 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003349 exstat = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003350 maltmp = remap(i);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003351 DBGPRINTF(("DODOT: remap=%d, exstat=%d, global_env.iofd %d, i %d, global_env.linep is %s\n",
3352 maltmp, exstat, global_env.iofd, i, global_env.linep));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003353
3354 next(maltmp); /* Basically a PUSHIO */
3355
3356 DBGPRINTF(("DODOT: returning exstat=%d\n", exstat));
3357
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003358 return exstat;
Eric Andersenff9eee42001-06-29 04:57:14 +00003359 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003360 } /* while */
Eric Andersen12de6cf2004-08-04 19:19:10 +00003361
Eric Andersenff9eee42001-06-29 04:57:14 +00003362 prs(cp);
3363 err(": not found");
Eric Andersen12de6cf2004-08-04 19:19:10 +00003364
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003365 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003366}
3367
Denis Vlasenkofe218832008-03-01 09:35:39 +00003368static int dowait(struct op *t, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003369{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003370 int i;
3371 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003372
Denis Vlasenkofe218832008-03-01 09:35:39 +00003373 cp = args[1];
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003374 if (cp != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003375 i = getn(cp);
3376 if (i == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003377 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003378 } else
3379 i = -1;
3380 setstatus(waitfor(i, 1));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003381 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003382}
3383
Denis Vlasenkofe218832008-03-01 09:35:39 +00003384static int doread(struct op *t, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003385{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003386 char *cp, **wp;
3387 int nb = 0;
3388 int nl = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003389
Denis Vlasenkofe218832008-03-01 09:35:39 +00003390 if (args[1] == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003391 err("Usage: read name ...");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003392 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003393 }
Denis Vlasenkofe218832008-03-01 09:35:39 +00003394 for (wp = args + 1; *wp; wp++) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003395 for (cp = global_env.linep; !nl && cp < elinep - 1; cp++) {
Denis Vlasenkoe376d452008-02-20 22:23:24 +00003396 nb = nonblock_safe_read(0, cp, sizeof(*cp));
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003397 if (nb != sizeof(*cp))
Eric Andersenff9eee42001-06-29 04:57:14 +00003398 break;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003399 nl = (*cp == '\n');
3400 if (nl || (wp[1] && any(*cp, ifs->value)))
3401 break;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003402 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003403 *cp = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00003404 if (nb <= 0)
3405 break;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003406 setval(lookup(*wp), global_env.linep);
Eric Andersenff9eee42001-06-29 04:57:14 +00003407 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003408 return nb <= 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003409}
3410
Denis Vlasenkofe218832008-03-01 09:35:39 +00003411static int doeval(struct op *t, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003412{
Denis Vlasenkofe218832008-03-01 09:35:39 +00003413 return RUN(awordlist, args + 1, wdchar);
Eric Andersenff9eee42001-06-29 04:57:14 +00003414}
3415
Denis Vlasenkofe218832008-03-01 09:35:39 +00003416static int dotrap(struct op *t, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003417{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003418 int n, i;
3419 int resetsig;
Eric Andersenff9eee42001-06-29 04:57:14 +00003420
Denis Vlasenkofe218832008-03-01 09:35:39 +00003421 if (args[1] == NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00003422 for (i = 0; i <= _NSIG; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00003423 if (trap[i]) {
3424 prn(i);
3425 prs(": ");
3426 prs(trap[i]);
3427 prs("\n");
3428 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003429 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003430 }
Denis Vlasenkofe218832008-03-01 09:35:39 +00003431 resetsig = isdigit(args[1][0]);
3432 for (i = resetsig ? 1 : 2; args[i] != NULL; ++i) {
3433 n = getsig(args[i]);
Eric Andersenff9eee42001-06-29 04:57:14 +00003434 freecell(trap[n]);
3435 trap[n] = 0;
3436 if (!resetsig) {
Denis Vlasenkofe218832008-03-01 09:35:39 +00003437 if (args[1][0] != '\0') {
3438 trap[n] = strsave(args[1], 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003439 setsig(n, sig);
3440 } else
3441 setsig(n, SIG_IGN);
3442 } else {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00003443 if (interactive) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003444 if (n == SIGINT)
3445 setsig(n, onintr);
3446 else
Eric Andersen8401eea2004-08-04 19:16:54 +00003447 setsig(n, n == SIGQUIT ? SIG_IGN : SIG_DFL);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00003448 } else
Eric Andersenff9eee42001-06-29 04:57:14 +00003449 setsig(n, SIG_DFL);
3450 }
3451 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003452 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003453}
3454
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003455static int getsig(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003456{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003457 int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003458
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003459 n = getn(s);
3460 if (n < 0 || n > _NSIG) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003461 err("trap: bad signal number");
3462 n = 0;
3463 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003464 return n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003465}
3466
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003467static void setsig(int n, sighandler_t f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003468{
3469 if (n == 0)
3470 return;
3471 if (signal(n, SIG_IGN) != SIG_IGN || ourtrap[n]) {
3472 ourtrap[n] = 1;
3473 signal(n, f);
3474 }
3475}
3476
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003477static int getn(char *as)
Eric Andersenff9eee42001-06-29 04:57:14 +00003478{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003479 char *s;
3480 int n, m;
Eric Andersenff9eee42001-06-29 04:57:14 +00003481
3482 s = as;
3483 m = 1;
3484 if (*s == '-') {
3485 m = -1;
3486 s++;
3487 }
3488 for (n = 0; isdigit(*s); s++)
Eric Andersen8401eea2004-08-04 19:16:54 +00003489 n = (n * 10) + (*s - '0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003490 if (*s) {
3491 prs(as);
3492 err(": bad number");
3493 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003494 return n * m;
Eric Andersenff9eee42001-06-29 04:57:14 +00003495}
3496
Denis Vlasenkofe218832008-03-01 09:35:39 +00003497static int dobreak(struct op *t, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003498{
Denis Vlasenkofe218832008-03-01 09:35:39 +00003499 return brkcontin(args[1], 1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003500}
3501
Denis Vlasenkofe218832008-03-01 09:35:39 +00003502static int docontinue(struct op *t, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003503{
Denis Vlasenkofe218832008-03-01 09:35:39 +00003504 return brkcontin(args[1], 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003505}
3506
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003507static int brkcontin(char *cp, int val)
Eric Andersenff9eee42001-06-29 04:57:14 +00003508{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003509 struct brkcon *bc;
3510 int nl;
Eric Andersenff9eee42001-06-29 04:57:14 +00003511
Eric Andersen8401eea2004-08-04 19:16:54 +00003512 nl = cp == NULL ? 1 : getn(cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003513 if (nl <= 0)
3514 nl = 999;
3515 do {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003516 bc = brklist;
3517 if (bc == NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00003518 break;
3519 brklist = bc->nextlev;
3520 } while (--nl);
3521 if (nl) {
3522 err("bad break/continue level");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003523 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003524 }
Denis Vlasenko648b44f2008-02-12 06:04:06 +00003525 isbreak = (val != 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003526 longjmp(bc->brkpt, 1);
3527 /* NOTREACHED */
3528}
3529
Denis Vlasenkofe218832008-03-01 09:35:39 +00003530static int doexit(struct op *t, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003531{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003532 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003533
3534 execflg = 0;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003535 cp = args[1];
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003536 if (cp != NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00003537 setstatus(getn(cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003538
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003539 DBGPRINTF(("DOEXIT: calling leave(), t=%p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003540
Eric Andersenff9eee42001-06-29 04:57:14 +00003541 leave();
3542 /* NOTREACHED */
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003543 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003544}
3545
Denis Vlasenkofe218832008-03-01 09:35:39 +00003546static int doexport(struct op *t, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003547{
Denis Vlasenkofe218832008-03-01 09:35:39 +00003548 rdexp(args + 1, export, EXPORT);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003549 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003550}
3551
Denis Vlasenkofe218832008-03-01 09:35:39 +00003552static int doreadonly(struct op *t, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003553{
Denis Vlasenkofe218832008-03-01 09:35:39 +00003554 rdexp(args + 1, ronly, RONLY);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003555 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003556}
3557
Eric Andersen8401eea2004-08-04 19:16:54 +00003558static void rdexp(char **wp, void (*f) (struct var *), int key)
Eric Andersenff9eee42001-06-29 04:57:14 +00003559{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003560 DBGPRINTF6(("RDEXP: enter, wp=%p, func=%p, key=%d\n", wp, f, key));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003561 DBGPRINTF6(("RDEXP: *wp=%s\n", *wp));
3562
Eric Andersenff9eee42001-06-29 04:57:14 +00003563 if (*wp != NULL) {
Matt Kraaif69bfc72001-07-12 19:39:59 +00003564 for (; *wp != NULL; wp++) {
3565 if (isassign(*wp)) {
3566 char *cp;
Eric Andersen8401eea2004-08-04 19:16:54 +00003567
Matt Kraaif69bfc72001-07-12 19:39:59 +00003568 assign(*wp, COPYV);
Eric Andersen8401eea2004-08-04 19:16:54 +00003569 for (cp = *wp; *cp != '='; cp++);
Matt Kraaif69bfc72001-07-12 19:39:59 +00003570 *cp = '\0';
3571 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003572 if (checkname(*wp))
Eric Andersen8401eea2004-08-04 19:16:54 +00003573 (*f) (lookup(*wp));
Eric Andersenff9eee42001-06-29 04:57:14 +00003574 else
3575 badid(*wp);
Matt Kraaif69bfc72001-07-12 19:39:59 +00003576 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003577 } else
3578 putvlist(key, 1);
3579}
3580
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003581static void badid(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003582{
3583 prs(s);
3584 err(": bad identifier");
3585}
3586
Denis Vlasenkofe218832008-03-01 09:35:39 +00003587static int doset(struct op *t, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003588{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003589 struct var *vp;
3590 char *cp;
3591 int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003592
Denis Vlasenkofe218832008-03-01 09:35:39 +00003593 cp = args[1];
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003594 if (cp == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003595 for (vp = vlist; vp; vp = vp->next)
3596 varput(vp->name, 1);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003597 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003598 }
3599 if (*cp == '-') {
Denis Vlasenkofe218832008-03-01 09:35:39 +00003600 args++;
Eric Andersenff9eee42001-06-29 04:57:14 +00003601 if (*++cp == 0)
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003602 FLAG['x'] = FLAG['v'] = 0;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003603 else {
3604 for (; *cp; cp++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003605 switch (*cp) {
3606 case 'e':
3607 if (!interactive)
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003608 FLAG['e']++;
Eric Andersenff9eee42001-06-29 04:57:14 +00003609 break;
3610
3611 default:
Eric Andersen8401eea2004-08-04 19:16:54 +00003612 if (*cp >= 'a' && *cp <= 'z')
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003613 FLAG[(int) *cp]++;
Eric Andersenff9eee42001-06-29 04:57:14 +00003614 break;
3615 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003616 }
3617 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003618 setdash();
3619 }
Denis Vlasenkofe218832008-03-01 09:35:39 +00003620 if (args[1]) {
3621 args[0] = dolv[0];
3622 for (n = 1; args[n]; n++)
3623 setarea((char *) args[n], 0);
Eric Andersen8401eea2004-08-04 19:16:54 +00003624 dolc = n - 1;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003625 dolv = args;
Eric Andersenff9eee42001-06-29 04:57:14 +00003626 setval(lookup("#"), putn(dolc));
Eric Andersen8401eea2004-08-04 19:16:54 +00003627 setarea((char *) (dolv - 1), 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003628 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003629 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003630}
3631
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003632static void varput(char *s, int out)
Eric Andersenff9eee42001-06-29 04:57:14 +00003633{
Matt Kraai69edfec2001-08-06 14:14:18 +00003634 if (isalnum(*s) || *s == '_') {
Eric Andersenff9eee42001-06-29 04:57:14 +00003635 write(out, s, strlen(s));
3636 write(out, "\n", 1);
3637 }
3638}
3639
3640
3641/*
3642 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
3643 * This file contains code for the times builtin.
Eric Andersenff9eee42001-06-29 04:57:14 +00003644 */
Denis Vlasenkofe218832008-03-01 09:35:39 +00003645static void times_fmt(char *buf, clock_t val, unsigned clk_tck)
3646{
3647 unsigned min, sec;
3648 if (sizeof(val) > sizeof(int))
3649 sec = ((unsigned long)val) / clk_tck;
3650 else
3651 sec = ((unsigned)val) / clk_tck;
3652 min = sec / 60;
3653#if ENABLE_DESKTOP
3654 sprintf(buf, "%um%u.%03us", min, (sec - min * 60),
3655 /* msec: */ ((unsigned)(val - (clock_t)sec * clk_tck)) * 1000 / clk_tck
3656 );
3657#else
3658 sprintf(buf, "%um%us", min, (sec - min * 60));
3659#endif
3660}
3661
3662static int dotimes(struct op *t, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003663{
3664 struct tms buf;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003665 unsigned clk_tck = sysconf(_SC_CLK_TCK);
3666 /* How much do we need for "NmN.NNNs" ? */
3667 enum { TIMEBUF_SIZE = sizeof(int)*3 + sizeof(int)*3 + 6 };
3668 char u[TIMEBUF_SIZE], s[TIMEBUF_SIZE];
3669 char cu[TIMEBUF_SIZE], cs[TIMEBUF_SIZE];
Eric Andersenff9eee42001-06-29 04:57:14 +00003670
3671 times(&buf);
Denis Vlasenkofe218832008-03-01 09:35:39 +00003672
3673 times_fmt(u, buf.tms_utime, clk_tck);
3674 times_fmt(s, buf.tms_stime, clk_tck);
3675 times_fmt(cu, buf.tms_cutime, clk_tck);
3676 times_fmt(cs, buf.tms_cstime, clk_tck);
3677
3678 printf("%s %s\n%s %s\n", u, s, cu, cs);
Eric Andersenff9eee42001-06-29 04:57:14 +00003679 return 0;
3680}
3681
3682
Eric Andersenff9eee42001-06-29 04:57:14 +00003683/* -------- eval.c -------- */
3684
3685/*
3686 * ${}
3687 * `command`
3688 * blank interpretation
3689 * quoting
3690 * glob
3691 */
3692
Eric Andersen8401eea2004-08-04 19:16:54 +00003693static char **eval(char **ap, int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003694{
3695 struct wdblock *wb;
3696 char **wp;
3697 char **wf;
3698 jmp_buf ev;
3699
3700#if __GNUC__
3701 /* Avoid longjmp clobbering */
3702 (void) &wp;
3703 (void) &ap;
3704#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00003705
3706 DBGPRINTF4(("EVAL: enter, f=%d\n", f));
3707
Eric Andersenff9eee42001-06-29 04:57:14 +00003708 wp = NULL;
3709 wb = NULL;
3710 wf = NULL;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003711 errpt = ev;
3712 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003713 while (*ap && isassign(*ap))
3714 expand(*ap++, &wb, f & ~DOGLOB);
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003715 if (FLAG['k']) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003716 for (wf = ap; *wf; wf++) {
3717 if (isassign(*wf))
3718 expand(*wf, &wb, f & ~DOGLOB);
3719 }
3720 }
Denis Vlasenko648b44f2008-02-12 06:04:06 +00003721 for (wb = addword((char *) NULL, wb); *ap; ap++) {
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003722 if (!FLAG['k'] || !isassign(*ap))
Eric Andersenff9eee42001-06-29 04:57:14 +00003723 expand(*ap, &wb, f & ~DOKEY);
3724 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003725 wb = addword((char *) 0, wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00003726 wp = getwords(wb);
3727 quitenv();
3728 } else
3729 gflg = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003730
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003731 return gflg ? (char **) NULL : wp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003732}
3733
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003734
Eric Andersenff9eee42001-06-29 04:57:14 +00003735/*
3736 * Make the exported environment from the exported
3737 * names in the dictionary. Keyword assignments
3738 * will already have been done.
3739 */
Eric Andersenfd7a4c82004-09-02 23:13:10 +00003740static char **makenv(int all, struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00003741{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003742 struct var *vp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003743
3744 DBGPRINTF5(("MAKENV: enter, all=%d\n", all));
Eric Andersenff9eee42001-06-29 04:57:14 +00003745
Eric Andersenff9eee42001-06-29 04:57:14 +00003746 for (vp = vlist; vp; vp = vp->next)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003747 if (all || vp->status & EXPORT)
Eric Andersenff9eee42001-06-29 04:57:14 +00003748 wb = addword(vp->name, wb);
Eric Andersen8401eea2004-08-04 19:16:54 +00003749 wb = addword((char *) 0, wb);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003750 return getwords(wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00003751}
3752
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003753static int expand(const char *cp, struct wdblock **wbp, int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003754{
3755 jmp_buf ev;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003756 char *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003757
3758#if __GNUC__
3759 /* Avoid longjmp clobbering */
3760 (void) &cp;
3761#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00003762
3763 DBGPRINTF3(("EXPAND: enter, f=%d\n", f));
3764
Eric Andersenff9eee42001-06-29 04:57:14 +00003765 gflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003766
Eric Andersenff9eee42001-06-29 04:57:14 +00003767 if (cp == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003768 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003769
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003770 if (!anys("$`'\"", cp) && !anys(ifs->value, cp)
3771 && ((f & DOGLOB) == 0 || !anys("[*?", cp))
3772 ) {
3773 xp = strsave(cp, areanum);
Eric Andersenff9eee42001-06-29 04:57:14 +00003774 if (f & DOTRIM)
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003775 unquote(xp);
3776 *wbp = addword(xp, *wbp);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003777 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003778 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003779 errpt = ev;
3780 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003781 PUSHIO(aword, cp, strchar);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003782 global_env.iobase = global_env.iop;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003783 while ((xp = blank(f)) && gflg == 0) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003784 global_env.linep = xp;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003785 xp = strsave(xp, areanum);
Eric Andersen8401eea2004-08-04 19:16:54 +00003786 if ((f & DOGLOB) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003787 if (f & DOTRIM)
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003788 unquote(xp);
3789 *wbp = addword(xp, *wbp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003790 } else
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003791 *wbp = glob(xp, *wbp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003792 }
3793 quitenv();
3794 } else
3795 gflg = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003796 return gflg == 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003797}
3798
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003799static char *evalstr(char *cp, int f)
3800{
3801 struct wdblock *wb;
3802
3803 DBGPRINTF6(("EVALSTR: enter, cp=%p, f=%d\n", cp, f));
3804
3805 wb = NULL;
3806 if (expand(cp, &wb, f)) {
3807 if (wb == NULL || wb->w_nword == 0
3808 || (cp = wb->w_words[0]) == NULL
3809 ) {
Denis Vlasenko8e858e22007-03-07 09:35:43 +00003810// TODO: I suspect that
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003811// char *evalstr(char *cp, int f) is actually
3812// const char *evalstr(const char *cp, int f)!
3813 cp = (char*)"";
3814 }
3815 DELETE(wb);
3816 } else
3817 cp = NULL;
3818 return cp;
3819}
3820
3821
Eric Andersenff9eee42001-06-29 04:57:14 +00003822/*
3823 * Blank interpretation and quoting
3824 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003825static char *blank(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003826{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003827 int c, c1;
3828 char *sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003829 int scanequals, foundequals;
3830
Eric Andersen12de6cf2004-08-04 19:19:10 +00003831 DBGPRINTF3(("BLANK: enter, f=%d\n", f));
3832
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003833 sp = global_env.linep;
Eric Andersenff9eee42001-06-29 04:57:14 +00003834 scanequals = f & DOKEY;
3835 foundequals = 0;
3836
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003837 loop:
3838 c = subgetc('"', foundequals);
3839 switch (c) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003840 case 0:
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003841 if (sp == global_env.linep)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003842 return 0;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003843 *global_env.linep++ = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003844 return sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003845
3846 default:
3847 if (f & DOBLANK && any(c, ifs->value))
3848 goto loop;
3849 break;
3850
3851 case '"':
3852 case '\'':
3853 scanequals = 0;
3854 if (INSUB())
3855 break;
3856 for (c1 = c; (c = subgetc(c1, 1)) != c1;) {
3857 if (c == 0)
3858 break;
3859 if (c == '\'' || !any(c, "$`\""))
3860 c |= QUOTE;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003861 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003862 }
3863 c = 0;
3864 }
3865 unget(c);
Matt Kraai69edfec2001-08-06 14:14:18 +00003866 if (!isalpha(c) && c != '_')
Eric Andersenff9eee42001-06-29 04:57:14 +00003867 scanequals = 0;
3868 for (;;) {
3869 c = subgetc('"', foundequals);
3870 if (c == 0 ||
Eric Andersen8401eea2004-08-04 19:16:54 +00003871 f & (DOBLANK && any(c, ifs->value)) ||
3872 (!INSUB() && any(c, "\"'"))) {
3873 scanequals = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003874 unget(c);
3875 if (any(c, "\"'"))
3876 goto loop;
3877 break;
3878 }
3879 if (scanequals) {
3880 if (c == '=') {
3881 foundequals = 1;
Eric Andersen8401eea2004-08-04 19:16:54 +00003882 scanequals = 0;
3883 } else if (!isalnum(c) && c != '_')
Eric Andersenff9eee42001-06-29 04:57:14 +00003884 scanequals = 0;
3885 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003886 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003887 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003888 *global_env.linep++ = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003889 return sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003890}
3891
3892/*
3893 * Get characters, substituting for ` and $
3894 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003895static int subgetc(char ec, int quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00003896{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003897 char c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003898
3899 DBGPRINTF3(("SUBGETC: enter, quoted=%d\n", quoted));
Eric Andersenff9eee42001-06-29 04:57:14 +00003900
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003901 again:
Eric Andersenff9eee42001-06-29 04:57:14 +00003902 c = my_getc(ec);
3903 if (!INSUB() && ec != '\'') {
3904 if (c == '`') {
3905 if (grave(quoted) == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003906 return 0;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003907 global_env.iop->task = XGRAVE;
Eric Andersenff9eee42001-06-29 04:57:14 +00003908 goto again;
3909 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003910 if (c == '$') {
3911 c = dollar(quoted);
3912 if (c == 0) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003913 global_env.iop->task = XDOLL;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003914 goto again;
3915 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003916 }
3917 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003918 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003919}
3920
3921/*
3922 * Prepare to generate the string returned by ${} substitution.
3923 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003924static int dollar(int quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00003925{
3926 int otask;
3927 struct io *oiop;
3928 char *dolp;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003929 char *s, c, *cp = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00003930 struct var *vp;
3931
Eric Andersen12de6cf2004-08-04 19:19:10 +00003932 DBGPRINTF3(("DOLLAR: enter, quoted=%d\n", quoted));
3933
Eric Andersenff9eee42001-06-29 04:57:14 +00003934 c = readc();
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003935 s = global_env.linep;
Eric Andersenff9eee42001-06-29 04:57:14 +00003936 if (c != '{') {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003937 *global_env.linep++ = c;
Matt Kraai69edfec2001-08-06 14:14:18 +00003938 if (isalpha(c) || c == '_') {
Eric Andersen8401eea2004-08-04 19:16:54 +00003939 while ((c = readc()) != 0 && (isalnum(c) || c == '_'))
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003940 if (global_env.linep < elinep)
3941 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003942 unget(c);
3943 }
3944 c = 0;
3945 } else {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003946 oiop = global_env.iop;
3947 otask = global_env.iop->task;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003948
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003949 global_env.iop->task = XOTHER;
Eric Andersen8401eea2004-08-04 19:16:54 +00003950 while ((c = subgetc('"', 0)) != 0 && c != '}' && c != '\n')
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003951 if (global_env.linep < elinep)
3952 *global_env.linep++ = c;
3953 if (oiop == global_env.iop)
3954 global_env.iop->task = otask;
Eric Andersenff9eee42001-06-29 04:57:14 +00003955 if (c != '}') {
3956 err("unclosed ${");
Denis Vlasenko648b44f2008-02-12 06:04:06 +00003957 gflg = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003958 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003959 }
3960 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003961 if (global_env.linep >= elinep) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003962 err("string in ${} too long");
Denis Vlasenko648b44f2008-02-12 06:04:06 +00003963 gflg = 1;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003964 global_env.linep -= 10;
Eric Andersenff9eee42001-06-29 04:57:14 +00003965 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003966 *global_env.linep = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003967 if (*s)
Eric Andersen8401eea2004-08-04 19:16:54 +00003968 for (cp = s + 1; *cp; cp++)
Eric Andersenff9eee42001-06-29 04:57:14 +00003969 if (any(*cp, "=-+?")) {
3970 c = *cp;
3971 *cp++ = 0;
3972 break;
3973 }
3974 if (s[1] == 0 && (*s == '*' || *s == '@')) {
3975 if (dolc > 1) {
3976 /* currently this does not distinguish $* and $@ */
3977 /* should check dollar */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003978 global_env.linep = s;
Eric Andersen8401eea2004-08-04 19:16:54 +00003979 PUSHIO(awordlist, dolv + 1, dolchar);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003980 return 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00003981 } else { /* trap the nasty ${=} */
Eric Andersenff9eee42001-06-29 04:57:14 +00003982 s[0] = '1';
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003983 s[1] = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00003984 }
3985 }
3986 vp = lookup(s);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003987 dolp = vp->value;
3988 if (dolp == null) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003989 switch (c) {
3990 case '=':
3991 if (isdigit(*s)) {
3992 err("cannot use ${...=...} with $n");
Denis Vlasenko648b44f2008-02-12 06:04:06 +00003993 gflg = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003994 break;
3995 }
3996 setval(vp, cp);
3997 dolp = vp->value;
3998 break;
3999
4000 case '-':
4001 dolp = strsave(cp, areanum);
4002 break;
4003
4004 case '?':
4005 if (*cp == 0) {
4006 prs("missing value for ");
4007 err(s);
4008 } else
4009 err(cp);
Denis Vlasenko648b44f2008-02-12 06:04:06 +00004010 gflg = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004011 break;
4012 }
4013 } else if (c == '+')
4014 dolp = strsave(cp, areanum);
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00004015 if (FLAG['u'] && dolp == null) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004016 prs("unset variable: ");
4017 err(s);
Denis Vlasenko648b44f2008-02-12 06:04:06 +00004018 gflg = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004019 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004020 global_env.linep = s;
Eric Andersenff9eee42001-06-29 04:57:14 +00004021 PUSHIO(aword, dolp, quoted ? qstrchar : strchar);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004022 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004023}
4024
4025/*
4026 * Run the command in `...` and read its output.
4027 */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004028
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004029static int grave(int quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00004030{
Denis Vlasenko55f30b02007-03-24 22:42:29 +00004031 /* moved to G: static char child_cmd[LINELIM]; */
4032
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004033 const char *cp;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004034 int i;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004035 int j;
Eric Andersenff9eee42001-06-29 04:57:14 +00004036 int pf[2];
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004037 const char *src;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004038 char *dest;
4039 int count;
4040 int ignore;
4041 int ignore_once;
4042 char *argument_list[4];
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004043 struct wdblock *wb = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004044
4045#if __GNUC__
4046 /* Avoid longjmp clobbering */
4047 (void) &cp;
4048#endif
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004049
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004050 for (cp = global_env.iop->argp->aword; *cp != '`'; cp++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004051 if (*cp == 0) {
4052 err("no closing `");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004053 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004054 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004055 }
Eric Andersen737f5fb2003-03-14 16:05:59 +00004056
4057 /* string copy with dollar expansion */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004058 src = global_env.iop->argp->aword;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004059 dest = child_cmd;
4060 count = 0;
4061 ignore = 0;
4062 ignore_once = 0;
4063 while ((*src != '`') && (count < LINELIM)) {
4064 if (*src == '\'')
4065 ignore = !ignore;
4066 if (*src == '\\')
4067 ignore_once = 1;
4068 if (*src == '$' && !ignore && !ignore_once) {
4069 struct var *vp;
Denis Vlasenkoab801872007-12-02 08:35:37 +00004070 /* moved to G to reduce stack usage
Eric Andersen737f5fb2003-03-14 16:05:59 +00004071 char var_name[LINELIM];
4072 char alt_value[LINELIM];
Denis Vlasenkoab801872007-12-02 08:35:37 +00004073 */
4074#define var_name (G.grave__var_name)
4075#define alt_value (G.grave__alt_value)
Eric Andersen737f5fb2003-03-14 16:05:59 +00004076 int var_index = 0;
4077 int alt_index = 0;
4078 char operator = 0;
4079 int braces = 0;
4080 char *value;
4081
4082 src++;
4083 if (*src == '{') {
4084 braces = 1;
4085 src++;
4086 }
4087
4088 var_name[var_index++] = *src++;
Paul Fox54690dc2005-07-20 18:33:12 +00004089 while (isalnum(*src) || *src=='_')
Eric Andersen737f5fb2003-03-14 16:05:59 +00004090 var_name[var_index++] = *src++;
4091 var_name[var_index] = 0;
4092
4093 if (braces) {
4094 switch (*src) {
4095 case '}':
4096 break;
4097 case '-':
4098 case '=':
4099 case '+':
4100 case '?':
Eric Andersen8401eea2004-08-04 19:16:54 +00004101 operator = * src;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004102 break;
4103 default:
4104 err("unclosed ${\n");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004105 return 0;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004106 }
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004107 if (operator) {
Eric Andersen737f5fb2003-03-14 16:05:59 +00004108 src++;
4109 while (*src && (*src != '}')) {
4110 alt_value[alt_index++] = *src++;
4111 }
4112 alt_value[alt_index] = 0;
4113 if (*src != '}') {
4114 err("unclosed ${\n");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004115 return 0;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004116 }
4117 }
4118 src++;
4119 }
4120
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004121 if (isalpha(*var_name)) {
4122 /* let subshell handle it instead */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004123
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004124 char *namep = var_name;
4125
4126 *dest++ = '$';
4127 if (braces)
4128 *dest++ = '{';
4129 while (*namep)
4130 *dest++ = *namep++;
4131 if (operator) {
4132 char *altp = alt_value;
4133 *dest++ = operator;
4134 while (*altp)
4135 *dest++ = *altp++;
4136 }
4137 if (braces)
4138 *dest++ = '}';
4139
4140 wb = addword(lookup(var_name)->name, wb);
4141 } else {
4142 /* expand */
4143
4144 vp = lookup(var_name);
4145 if (vp->value != null)
4146 value = (operator == '+') ?
4147 alt_value : vp->value;
4148 else if (operator == '?') {
4149 err(alt_value);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004150 return 0;
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004151 } else if (alt_index && (operator != '+')) {
4152 value = alt_value;
4153 if (operator == '=')
4154 setval(vp, value);
4155 } else
4156 continue;
4157
4158 while (*value && (count < LINELIM)) {
4159 *dest++ = *value++;
4160 count++;
4161 }
Eric Andersen737f5fb2003-03-14 16:05:59 +00004162 }
Denis Vlasenkoab801872007-12-02 08:35:37 +00004163#undef var_name
4164#undef alt_value
Eric Andersen737f5fb2003-03-14 16:05:59 +00004165 } else {
4166 *dest++ = *src++;
4167 count++;
4168 ignore_once = 0;
4169 }
4170 }
4171 *dest = '\0';
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004172
Eric Andersenff9eee42001-06-29 04:57:14 +00004173 if (openpipe(pf) < 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004174 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004175
Eric Andersen8401eea2004-08-04 19:16:54 +00004176 while ((i = vfork()) == -1 && errno == EAGAIN);
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);
Eric Andersen737f5fb2003-03-14 16:05:59 +00004217 _exit(1);
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 Andersen8401eea2004-08-04 19:16:54 +00004274 for (i = 0; i < cl->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004275 unquote(cl->w_words[i]);
Eric Andersen8401eea2004-08-04 19:16:54 +00004276 glob0((char *) cl->w_words, cl->w_nword, sizeof(char *), xstrcmp);
Eric Andersenff9eee42001-06-29 04:57:14 +00004277 if (cl->w_nword) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004278 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;
Eric Andersen8401eea2004-08-04 19:16:54 +00004301 for (dp = cp = space((int) (pp - np) + 3); np < pp;)
Eric Andersenff9eee42001-06-29 04:57:14 +00004302 *cp++ = *np++;
4303 *cp++ = '.';
4304 *cp = '\0';
Eric Andersen8401eea2004-08-04 19:16:54 +00004305 for (gp = cp = space(strlen(pp) + 1); *np && *np != '/';)
Eric Andersenff9eee42001-06-29 04:57:14 +00004306 *cp++ = *np++;
4307 *cp = '\0';
4308 dirp = opendir(dp);
4309 if (dirp == 0) {
4310 DELETE(dp);
4311 DELETE(gp);
4312 return;
4313 }
4314 dname[NAME_MAX] = '\0';
Eric Andersen8401eea2004-08-04 19:16:54 +00004315 while ((de = readdir(dirp)) != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004316 /* XXX Hmmm... What this could be? (abial) */
4317 /*
Eric Andersen8401eea2004-08-04 19:16:54 +00004318 if (ent[j].d_ino == 0)
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004319 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 Vlasenko00ccf952007-02-01 01:39:24 +00004354 p = op = space((int)(end1 - start1) + strlen(middle) + strlen(end) + 2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004355 for (xp = start1; xp != end1;)
4356 *op++ = *xp++;
Eric Andersen8401eea2004-08-04 19:16:54 +00004357 for (xp = middle; (*op++ = *xp++) != '\0';);
Eric Andersenff9eee42001-06-29 04:57:14 +00004358 op--;
Eric Andersen8401eea2004-08-04 19:16:54 +00004359 for (xp = end; (*op++ = *xp++) != '\0';);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004360 return p;
Eric Andersenff9eee42001-06-29 04:57:14 +00004361}
4362
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004363static int anyspcl(struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004364{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004365 int i;
4366 char **wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004367
4368 wd = wb->w_words;
Eric Andersen8401eea2004-08-04 19:16:54 +00004369 for (i = 0; i < wb->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004370 if (anys(spcl, *wd++))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004371 return 1;
4372 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004373}
4374
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004375static int xstrcmp(char *p1, char *p2)
Eric Andersenff9eee42001-06-29 04:57:14 +00004376{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004377 return strcmp(*(char **) p1, *(char **) p2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004378}
4379
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004380
Eric Andersenff9eee42001-06-29 04:57:14 +00004381/* -------- word.c -------- */
4382
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004383static struct wdblock *newword(int nw)
Eric Andersenff9eee42001-06-29 04:57:14 +00004384{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004385 struct wdblock *wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004386
Eric Andersen8401eea2004-08-04 19:16:54 +00004387 wb = (struct wdblock *) space(sizeof(*wb) + nw * sizeof(char *));
Eric Andersenff9eee42001-06-29 04:57:14 +00004388 wb->w_bsize = nw;
4389 wb->w_nword = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004390 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004391}
4392
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004393static struct wdblock *addword(char *wd, struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004394{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004395 struct wdblock *wb2;
4396 int nw;
Eric Andersenff9eee42001-06-29 04:57:14 +00004397
4398 if (wb == NULL)
4399 wb = newword(NSTART);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004400 nw = wb->w_nword;
4401 if (nw >= wb->w_bsize) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004402 wb2 = newword(nw * 2);
Eric Andersen8401eea2004-08-04 19:16:54 +00004403 memcpy((char *) wb2->w_words, (char *) wb->w_words,
4404 nw * sizeof(char *));
Eric Andersenff9eee42001-06-29 04:57:14 +00004405 wb2->w_nword = nw;
4406 DELETE(wb);
4407 wb = wb2;
4408 }
4409 wb->w_words[wb->w_nword++] = wd;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004410 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004411}
Eric Andersen8401eea2004-08-04 19:16:54 +00004412
Denis Vlasenkoe4712752007-04-14 15:08:41 +00004413static char **getwords(struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004414{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004415 char **wd;
4416 int nb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004417
4418 if (wb == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004419 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004420 if (wb->w_nword == 0) {
4421 DELETE(wb);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004422 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004423 }
4424 wd = (char **) space(nb = sizeof(*wd) * wb->w_nword);
Eric Andersen8401eea2004-08-04 19:16:54 +00004425 memcpy((char *) wd, (char *) wb->w_words, nb);
4426 DELETE(wb); /* perhaps should done by caller */
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004427 return wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004428}
4429
"Vladimir N. Oleynik"ac973172005-09-22 14:38:17 +00004430static int (*func) (char *, char *);
4431static int globv;
Eric Andersenff9eee42001-06-29 04:57:14 +00004432
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004433static void glob3(char *i, char *j, char *k)
Eric Andersenff9eee42001-06-29 04:57:14 +00004434{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004435 char *index1, *index2, *index3;
4436 int c;
4437 int m;
4438
4439 m = globv;
4440 index1 = i;
4441 index2 = j;
4442 index3 = k;
4443 do {
4444 c = *index1;
4445 *index1++ = *index3;
4446 *index3++ = *index2;
4447 *index2++ = c;
4448 } while (--m);
4449}
4450
4451static void glob2(char *i, char *j)
4452{
4453 char *index1, *index2, c;
4454 int m;
4455
4456 m = globv;
4457 index1 = i;
4458 index2 = j;
4459 do {
4460 c = *index1;
4461 *index1++ = *index2;
4462 *index2++ = c;
4463 } while (--m);
Eric Andersenff9eee42001-06-29 04:57:14 +00004464}
4465
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004466static void glob1(char *base, char *lim)
Eric Andersenff9eee42001-06-29 04:57:14 +00004467{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004468 char *i, *j;
Eric Andersenff9eee42001-06-29 04:57:14 +00004469 int v2;
4470 char *lptr, *hptr;
4471 int c;
4472 unsigned n;
4473
Eric Andersenff9eee42001-06-29 04:57:14 +00004474 v2 = globv;
4475
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004476 top:
4477 n = (int) (lim - base);
4478 if (n <= v2)
Eric Andersenff9eee42001-06-29 04:57:14 +00004479 return;
Eric Andersen8401eea2004-08-04 19:16:54 +00004480 n = v2 * (n / (2 * v2));
4481 hptr = lptr = base + n;
Eric Andersenff9eee42001-06-29 04:57:14 +00004482 i = base;
Eric Andersen8401eea2004-08-04 19:16:54 +00004483 j = lim - v2;
4484 for (;;) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004485 if (i < lptr) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004486 c = (*func) (i, lptr);
4487 if (c == 0) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004488 lptr -= v2;
4489 glob2(i, lptr);
Eric Andersenff9eee42001-06-29 04:57:14 +00004490 continue;
4491 }
4492 if (c < 0) {
4493 i += v2;
4494 continue;
4495 }
4496 }
4497
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004498 begin:
Eric Andersenff9eee42001-06-29 04:57:14 +00004499 if (j > hptr) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004500 c = (*func) (hptr, j);
4501 if (c == 0) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004502 hptr += v2;
4503 glob2(hptr, j);
Eric Andersenff9eee42001-06-29 04:57:14 +00004504 goto begin;
4505 }
4506 if (c > 0) {
4507 if (i == lptr) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004508 hptr += v2;
4509 glob3(i, hptr, j);
4510 i = (lptr += v2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004511 goto begin;
4512 }
4513 glob2(i, j);
4514 j -= v2;
4515 i += v2;
4516 continue;
4517 }
4518 j -= v2;
4519 goto begin;
4520 }
4521
4522
4523 if (i == lptr) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004524 if (lptr - base >= lim - hptr) {
4525 glob1(hptr + v2, lim);
Eric Andersenff9eee42001-06-29 04:57:14 +00004526 lim = lptr;
4527 } else {
4528 glob1(base, lptr);
Eric Andersen8401eea2004-08-04 19:16:54 +00004529 base = hptr + v2;
Eric Andersenff9eee42001-06-29 04:57:14 +00004530 }
4531 goto top;
4532 }
4533
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004534 lptr -= v2;
4535 glob3(j, lptr, i);
4536 j = (hptr -= v2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004537 }
4538}
4539
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004540static void glob0(char *a0, unsigned a1, int a2, int (*a3) (char *, char *))
Eric Andersenff9eee42001-06-29 04:57:14 +00004541{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004542 func = a3;
4543 globv = a2;
4544 glob1(a0, a0 + a1 * a2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004545}
4546
Eric Andersenff9eee42001-06-29 04:57:14 +00004547
4548/* -------- io.c -------- */
4549
4550/*
4551 * shell IO
4552 */
4553
Eric Andersen8401eea2004-08-04 19:16:54 +00004554static int my_getc(int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00004555{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004556 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004557
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004558 if (global_env.linep > elinep) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004559 while ((c = readc()) != '\n' && c);
Eric Andersenff9eee42001-06-29 04:57:14 +00004560 err("input line too long");
Denis Vlasenko648b44f2008-02-12 06:04:06 +00004561 gflg = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004562 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004563 }
4564 c = readc();
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004565 if ((ec != '\'') && (ec != '`') && (global_env.iop->task != XGRAVE)) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004566 if (c == '\\') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004567 c = readc();
4568 if (c == '\n' && ec != '\"')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004569 return my_getc(ec);
Eric Andersenff9eee42001-06-29 04:57:14 +00004570 c |= QUOTE;
4571 }
4572 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004573 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004574}
4575
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004576static void unget(int c)
Eric Andersenff9eee42001-06-29 04:57:14 +00004577{
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004578 if (global_env.iop >= global_env.iobase)
4579 global_env.iop->peekc = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004580}
4581
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004582static int eofc(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00004583{
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004584 return global_env.iop < global_env.iobase || (global_env.iop->peekc == 0 && global_env.iop->prev == 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004585}
4586
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004587static int readc(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00004588{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004589 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004590
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004591 RCPRINTF(("READC: global_env.iop %p, global_env.iobase %p\n", global_env.iop, global_env.iobase));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004592
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004593 for (; global_env.iop >= global_env.iobase; global_env.iop--) {
4594 RCPRINTF(("READC: global_env.iop %p, peekc 0x%x\n", global_env.iop, global_env.iop->peekc));
4595 c = global_env.iop->peekc;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004596 if (c != '\0') {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004597 global_env.iop->peekc = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004598 return c;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004599 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004600 if (global_env.iop->prev != 0) {
4601 c = (*global_env.iop->iofn)(global_env.iop->argp, global_env.iop);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004602 if (c != '\0') {
4603 if (c == -1) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004604 global_env.iop++;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004605 continue;
Eric Andersen8401eea2004-08-04 19:16:54 +00004606 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004607 if (global_env.iop == iostack)
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004608 ioecho(c);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004609 global_env.iop->prev = c;
4610 return global_env.iop->prev;
Eric Andersenff9eee42001-06-29 04:57:14 +00004611 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004612 if (global_env.iop->task == XIO && global_env.iop->prev != '\n') {
4613 global_env.iop->prev = 0;
4614 if (global_env.iop == iostack)
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004615 ioecho('\n');
4616 return '\n';
Eric Andersen8401eea2004-08-04 19:16:54 +00004617 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004618 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004619 if (global_env.iop->task == XIO) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004620 if (multiline) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004621 global_env.iop->prev = 0;
4622 return global_env.iop->prev;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004623 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004624 if (interactive && global_env.iop == iostack + 1) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004625#if ENABLE_FEATURE_EDITING
4626 current_prompt = prompt->value;
4627#else
4628 prs(prompt->value);
4629#endif
4630 }
4631 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004632 } /* FOR */
4633
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004634 if (global_env.iop >= iostack) {
4635 RCPRINTF(("READC: return 0, global_env.iop %p\n", global_env.iop));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004636 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004637 }
4638
4639 DBGPRINTF(("READC: leave()...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00004640 leave();
4641 /* NOTREACHED */
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004642 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004643}
4644
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004645static void ioecho(char c)
Eric Andersenff9eee42001-06-29 04:57:14 +00004646{
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00004647 if (FLAG['v'])
Eric Andersenff9eee42001-06-29 04:57:14 +00004648 write(2, &c, sizeof c);
4649}
4650
Eric Andersen8401eea2004-08-04 19:16:54 +00004651static void pushio(struct ioarg *argp, int (*fn) (struct ioarg *))
Eric Andersenff9eee42001-06-29 04:57:14 +00004652{
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004653 DBGPRINTF(("PUSHIO: argp %p, argp->afid 0x%x, global_env.iop %p\n", argp,
4654 argp->afid, global_env.iop));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004655
4656 /* Set env ptr for io source to next array spot and check for array overflow */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004657 if (++global_env.iop >= &iostack[NPUSH]) {
4658 global_env.iop--;
Eric Andersenff9eee42001-06-29 04:57:14 +00004659 err("Shell input nested too deeply");
Denis Vlasenko648b44f2008-02-12 06:04:06 +00004660 gflg = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004661 return;
4662 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004663
4664 /* We did not overflow the NPUSH array spots so setup data structs */
4665
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004666 global_env.iop->iofn = (int (*)(struct ioarg *, struct io *)) fn; /* Store data source func ptr */
Eric Andersenff9eee42001-06-29 04:57:14 +00004667
4668 if (argp->afid != AFID_NOBUF)
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004669 global_env.iop->argp = argp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004670 else {
Eric Andersen12de6cf2004-08-04 19:19:10 +00004671
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004672 global_env.iop->argp = ioargstack + (global_env.iop - iostack); /* MAL - index into stack */
4673 *global_env.iop->argp = *argp; /* copy data from temp area into stack spot */
Eric Andersen12de6cf2004-08-04 19:19:10 +00004674
4675 /* MAL - mainbuf is for 1st data source (command line?) and all nested use a single shared buffer? */
4676
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004677 if (global_env.iop == &iostack[0])
4678 global_env.iop->argp->afbuf = &mainbuf;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004679 else
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004680 global_env.iop->argp->afbuf = &sharedbuf;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004681
4682 /* MAL - if not a termimal AND (commandline OR readable file) then give it a buffer id? */
4683 /* This line appears to be active when running scripts from command line */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004684 if ((isatty(global_env.iop->argp->afile) == 0)
4685 && (global_env.iop == &iostack[0]
4686 || lseek(global_env.iop->argp->afile, 0L, SEEK_CUR) != -1)) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00004687 if (++bufid == AFID_NOBUF) /* counter rollover check, AFID_NOBUF = 11111111 */
4688 bufid = AFID_ID; /* AFID_ID = 0 */
4689
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004690 global_env.iop->argp->afid = bufid; /* assign buffer id */
Eric Andersen8401eea2004-08-04 19:16:54 +00004691 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004692
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004693 DBGPRINTF(("PUSHIO: iostack %p, global_env.iop %p, afbuf %p\n",
4694 iostack, global_env.iop, global_env.iop->argp->afbuf));
4695 DBGPRINTF(("PUSHIO: mbuf %p, sbuf %p, bid %d, global_env.iop %p\n",
4696 &mainbuf, &sharedbuf, bufid, global_env.iop));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004697
Eric Andersenff9eee42001-06-29 04:57:14 +00004698 }
4699
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004700 global_env.iop->prev = ~'\n';
4701 global_env.iop->peekc = 0;
4702 global_env.iop->xchar = 0;
4703 global_env.iop->nlcount = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004704
Eric Andersenff9eee42001-06-29 04:57:14 +00004705 if (fn == filechar || fn == linechar)
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004706 global_env.iop->task = XIO;
Eric Andersen8401eea2004-08-04 19:16:54 +00004707 else if (fn == (int (*)(struct ioarg *)) gravechar
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004708 || fn == (int (*)(struct ioarg *)) qgravechar)
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004709 global_env.iop->task = XGRAVE;
Eric Andersenff9eee42001-06-29 04:57:14 +00004710 else
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004711 global_env.iop->task = XOTHER;
Eric Andersenff9eee42001-06-29 04:57:14 +00004712}
4713
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004714static struct io *setbase(struct io *ip)
Eric Andersenff9eee42001-06-29 04:57:14 +00004715{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004716 struct io *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004717
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004718 xp = global_env.iobase;
4719 global_env.iobase = ip;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004720 return xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004721}
4722
4723/*
4724 * Input generating functions
4725 */
4726
4727/*
4728 * Produce the characters of a string, then a newline, then EOF.
4729 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004730static int nlchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004731{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004732 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004733
4734 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004735 return 0;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004736 c = *ap->aword++;
4737 if (c == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004738 ap->aword = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004739 return '\n';
Eric Andersenff9eee42001-06-29 04:57:14 +00004740 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004741 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004742}
4743
4744/*
4745 * Given a list of words, produce the characters
4746 * in them, with a space after each word.
4747 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004748static int wdchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004749{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004750 char c;
4751 char **wl;
Eric Andersenff9eee42001-06-29 04:57:14 +00004752
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004753 wl = ap->awordlist;
4754 if (wl == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004755 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004756 if (*wl != NULL) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004757 c = *(*wl)++;
4758 if (c != 0)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004759 return c & 0177;
Eric Andersenff9eee42001-06-29 04:57:14 +00004760 ap->awordlist++;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004761 return ' ';
Eric Andersenff9eee42001-06-29 04:57:14 +00004762 }
4763 ap->awordlist = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004764 return '\n';
Eric Andersenff9eee42001-06-29 04:57:14 +00004765}
4766
4767/*
4768 * Return the characters of a list of words,
4769 * producing a space between them.
4770 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004771static int dolchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004772{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004773 char *wp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004774
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004775 wp = *ap->awordlist++;
4776 if (wp != NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004777 PUSHIO(aword, wp, *ap->awordlist == NULL ? strchar : xxchar);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004778 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004779 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004780 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004781}
4782
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004783static int xxchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004784{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004785 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004786
4787 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004788 return 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004789 c = *ap->aword++;
4790 if (c == '\0') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004791 ap->aword = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004792 return ' ';
Eric Andersenff9eee42001-06-29 04:57:14 +00004793 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004794 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004795}
4796
4797/*
4798 * Produce the characters from a single word (string).
4799 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004800static int strchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004801{
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004802 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004803 return 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004804 return *ap->aword++;
Eric Andersenff9eee42001-06-29 04:57:14 +00004805}
4806
4807/*
4808 * Produce quoted characters from a single word (string).
4809 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004810static int qstrchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004811{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004812 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004813
Denis Vlasenkob2abef32007-01-01 18:18:04 +00004814 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004815 return 0;
Denis Vlasenkob2abef32007-01-01 18:18:04 +00004816 c = *ap->aword++;
4817 if (c)
4818 c |= QUOTE;
4819 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004820}
4821
4822/*
4823 * Return the characters from a file.
4824 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004825static int filechar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004826{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004827 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004828 char c;
4829 struct iobuf *bp = ap->afbuf;
4830
4831 if (ap->afid != AFID_NOBUF) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004832 i = (ap->afid != bp->id);
4833 if (i || bp->bufp == bp->ebufp) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004834 if (i)
Denis Vlasenkoea620772006-10-14 02:23:43 +00004835 lseek(ap->afile, ap->afpos, SEEK_SET);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004836
Denis Vlasenkoe376d452008-02-20 22:23:24 +00004837 i = nonblock_safe_read(ap->afile, bp->buf, sizeof(bp->buf));
Eric Andersen8401eea2004-08-04 19:16:54 +00004838 if (i <= 0) {
4839 closef(ap->afile);
4840 return 0;
4841 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004842
Eric Andersen8401eea2004-08-04 19:16:54 +00004843 bp->id = ap->afid;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004844 bp->bufp = bp->buf;
4845 bp->ebufp = bp->bufp + i;
Eric Andersen8401eea2004-08-04 19:16:54 +00004846 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004847
Eric Andersen8401eea2004-08-04 19:16:54 +00004848 ap->afpos++;
4849 return *bp->bufp++ & 0177;
Eric Andersenff9eee42001-06-29 04:57:14 +00004850 }
Denis Vlasenko38f63192007-01-22 09:03:07 +00004851#if ENABLE_FEATURE_EDITING
Eric Andersen737f5fb2003-03-14 16:05:59 +00004852 if (interactive && isatty(ap->afile)) {
Denis Vlasenko55f30b02007-03-24 22:42:29 +00004853 /* moved to G: static char filechar_cmdbuf[BUFSIZ]; */
Eric Andersen8401eea2004-08-04 19:16:54 +00004854 static int position = 0, size = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004855
Eric Andersen8401eea2004-08-04 19:16:54 +00004856 while (size == 0 || position >= size) {
Denis Vlasenko6e602c42008-02-02 18:50:50 +00004857 size = read_line_input(current_prompt, filechar_cmdbuf, BUFSIZ, line_input_state);
4858 if (size < 0) /* Error/EOF */
4859 exit(0);
Eric Andersen8401eea2004-08-04 19:16:54 +00004860 position = 0;
Denis Vlasenko6e602c42008-02-02 18:50:50 +00004861 /* if Ctrl-C, size == 0 and loop will repeat */
Eric Andersen8401eea2004-08-04 19:16:54 +00004862 }
Denis Vlasenko55f30b02007-03-24 22:42:29 +00004863 c = filechar_cmdbuf[position];
Eric Andersen8401eea2004-08-04 19:16:54 +00004864 position++;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004865 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004866 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004867#endif
Denis Vlasenkoe376d452008-02-20 22:23:24 +00004868 i = nonblock_safe_read(ap->afile, &c, sizeof(c));
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004869 return i == sizeof(c) ? (c & 0x7f) : (closef(ap->afile), 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004870}
4871
4872/*
4873 * Return the characters from a here temp file.
4874 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004875static int herechar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004876{
4877 char c;
4878
Denis Vlasenkoe376d452008-02-20 22:23:24 +00004879 if (nonblock_safe_read(ap->afile, &c, sizeof(c)) != sizeof(c)) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004880 close(ap->afile);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004881 c = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00004882 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004883 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004884}
4885
4886/*
4887 * Return the characters produced by a process (`...`).
4888 * Quote them if required, and remove any trailing newline characters.
4889 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004890static int gravechar(struct ioarg *ap, struct io *iop)
Eric Andersenff9eee42001-06-29 04:57:14 +00004891{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004892 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004893
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004894 c = qgravechar(ap, iop) & ~QUOTE;
4895 if (c == '\n')
Eric Andersenff9eee42001-06-29 04:57:14 +00004896 c = ' ';
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004897 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004898}
4899
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004900static int qgravechar(struct ioarg *ap, struct io *iop)
Eric Andersenff9eee42001-06-29 04:57:14 +00004901{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004902 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004903
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004904 DBGPRINTF3(("QGRAVECHAR: enter, ap=%p, iop=%p\n", ap, iop));
Eric Andersenff9eee42001-06-29 04:57:14 +00004905
4906 if (iop->xchar) {
4907 if (iop->nlcount) {
4908 iop->nlcount--;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004909 return '\n' | QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00004910 }
4911 c = iop->xchar;
4912 iop->xchar = 0;
4913 } else if ((c = filechar(ap)) == '\n') {
4914 iop->nlcount = 1;
4915 while ((c = filechar(ap)) == '\n')
4916 iop->nlcount++;
4917 iop->xchar = c;
4918 if (c == 0)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004919 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004920 iop->nlcount--;
4921 c = '\n';
4922 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004923 return c != 0 ? c | QUOTE : 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004924}
4925
4926/*
4927 * Return a single command (usually the first line) from a file.
4928 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004929static int linechar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004930{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004931 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004932
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004933 c = filechar(ap);
4934 if (c == '\n') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004935 if (!multiline) {
4936 closef(ap->afile);
Eric Andersen8401eea2004-08-04 19:16:54 +00004937 ap->afile = -1; /* illegal value */
Eric Andersenff9eee42001-06-29 04:57:14 +00004938 }
4939 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004940 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004941}
4942
Eric Andersenff9eee42001-06-29 04:57:14 +00004943/*
4944 * remap fd into Shell's fd space
4945 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004946static int remap(int fd)
Eric Andersenff9eee42001-06-29 04:57:14 +00004947{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004948 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004949 int map[NOFILE];
Eric Andersen12de6cf2004-08-04 19:19:10 +00004950 int newfd;
4951
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004952 DBGPRINTF(("REMAP: fd=%d, global_env.iofd=%d\n", fd, global_env.iofd));
Eric Andersenff9eee42001-06-29 04:57:14 +00004953
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004954 if (fd < global_env.iofd) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004955 for (i = 0; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004956 map[i] = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004957
Eric Andersenff9eee42001-06-29 04:57:14 +00004958 do {
4959 map[fd] = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004960 newfd = dup(fd);
4961 fd = newfd;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004962 } while (fd >= 0 && fd < global_env.iofd);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004963
Eric Andersen8401eea2004-08-04 19:16:54 +00004964 for (i = 0; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004965 if (map[i])
4966 close(i);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004967
Eric Andersenff9eee42001-06-29 04:57:14 +00004968 if (fd < 0)
4969 err("too many files open in shell");
4970 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004971
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004972 return fd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004973}
4974
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004975static int openpipe(int *pv)
Eric Andersenff9eee42001-06-29 04:57:14 +00004976{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004977 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004978
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004979 i = pipe(pv);
4980 if (i < 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00004981 err("can't create pipe - try again");
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004982 return i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004983}
4984
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004985static void closepipe(int *pv)
Eric Andersenff9eee42001-06-29 04:57:14 +00004986{
4987 if (pv != NULL) {
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00004988 close(pv[0]);
4989 close(pv[1]);
Eric Andersenff9eee42001-06-29 04:57:14 +00004990 }
4991}
4992
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004993
Eric Andersenff9eee42001-06-29 04:57:14 +00004994/* -------- here.c -------- */
4995
4996/*
4997 * here documents
4998 */
4999
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005000static void markhere(char *s, struct ioword *iop)
Eric Andersenff9eee42001-06-29 04:57:14 +00005001{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005002 struct here *h, *lh;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005003
Mike Frysinger02d8fa42006-05-05 20:32:31 +00005004 DBGPRINTF7(("MARKHERE: enter, s=%p\n", s));
Eric Andersenff9eee42001-06-29 04:57:14 +00005005
5006 h = (struct here *) space(sizeof(struct here));
Denis Vlasenko00ccf952007-02-01 01:39:24 +00005007 if (h == NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00005008 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005009
Eric Andersenff9eee42001-06-29 04:57:14 +00005010 h->h_tag = evalstr(s, DOSUB);
5011 if (h->h_tag == 0)
5012 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005013
Eric Andersenff9eee42001-06-29 04:57:14 +00005014 h->h_iop = iop;
5015 iop->io_name = 0;
5016 h->h_next = NULL;
5017 if (inhere == 0)
5018 inhere = h;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00005019 else {
5020 for (lh = inhere; lh != NULL; lh = lh->h_next) {
Eric Andersenff9eee42001-06-29 04:57:14 +00005021 if (lh->h_next == 0) {
5022 lh->h_next = h;
5023 break;
5024 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00005025 }
5026 }
Eric Andersen8401eea2004-08-04 19:16:54 +00005027 iop->io_flag |= IOHERE | IOXHERE;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00005028 for (s = h->h_tag; *s; s++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00005029 if (*s & QUOTE) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005030 iop->io_flag &= ~IOXHERE;
5031 *s &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00005032 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00005033 }
Denis Vlasenko648b44f2008-02-12 06:04:06 +00005034 h->h_dosub = ((iop->io_flag & IOXHERE) ? '\0' : '\'');
Eric Andersenff9eee42001-06-29 04:57:14 +00005035}
5036
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005037static void gethere(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00005038{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005039 struct here *h, *hp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005040
5041 DBGPRINTF7(("GETHERE: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00005042
5043 /* Scan here files first leaving inhere list in place */
5044 for (hp = h = inhere; h != NULL; hp = h, h = h->h_next)
Denis Vlasenko648b44f2008-02-12 06:04:06 +00005045 readhere(&h->h_iop->io_name, h->h_tag, h->h_dosub /* NUL or ' */);
Eric Andersenff9eee42001-06-29 04:57:14 +00005046
5047 /* Make inhere list active - keep list intact for scraphere */
5048 if (hp != NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005049 hp->h_next = acthere;
5050 acthere = inhere;
5051 inhere = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00005052 }
5053}
5054
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005055static void readhere(char **name, char *s, int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00005056{
5057 int tf;
5058 char tname[30] = ".msh_XXXXXX";
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005059 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00005060 jmp_buf ev;
Eric Andersen8401eea2004-08-04 19:16:54 +00005061 char myline[LINELIM + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00005062 char *thenext;
5063
Mike Frysinger02d8fa42006-05-05 20:32:31 +00005064 DBGPRINTF7(("READHERE: enter, name=%p, s=%p\n", name, s));
Eric Andersen12de6cf2004-08-04 19:19:10 +00005065
Eric Andersenff9eee42001-06-29 04:57:14 +00005066 tf = mkstemp(tname);
5067 if (tf < 0)
5068 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005069
Eric Andersenff9eee42001-06-29 04:57:14 +00005070 *name = strsave(tname, areanum);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00005071 errpt = ev;
5072 if (newenv(setjmp(errpt)) != 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00005073 unlink(tname);
5074 else {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005075 pushio(global_env.iop->argp, (int (*)(struct ioarg *)) global_env.iop->iofn);
5076 global_env.iobase = global_env.iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00005077 for (;;) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005078 if (interactive && global_env.iop <= iostack) {
Denis Vlasenko38f63192007-01-22 09:03:07 +00005079#if ENABLE_FEATURE_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00005080 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00005081#else
Eric Andersen8401eea2004-08-04 19:16:54 +00005082 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00005083#endif
5084 }
5085 thenext = myline;
5086 while ((c = my_getc(ec)) != '\n' && c) {
5087 if (ec == '\'')
Eric Andersen8401eea2004-08-04 19:16:54 +00005088 c &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00005089 if (thenext >= &myline[LINELIM]) {
5090 c = 0;
5091 break;
5092 }
5093 *thenext++ = c;
5094 }
5095 *thenext = 0;
5096 if (strcmp(s, myline) == 0 || c == 0)
5097 break;
5098 *thenext++ = '\n';
Eric Andersen8401eea2004-08-04 19:16:54 +00005099 write(tf, myline, (int) (thenext - myline));
Eric Andersenff9eee42001-06-29 04:57:14 +00005100 }
5101 if (c == 0) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005102 prs("here document `");
5103 prs(s);
5104 err("' unclosed");
Eric Andersenff9eee42001-06-29 04:57:14 +00005105 }
5106 quitenv();
5107 }
5108 close(tf);
5109}
5110
5111/*
5112 * open here temp file.
5113 * if unquoted here, expand here temp file into second temp file.
5114 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005115static int herein(char *hname, int xdoll)
Eric Andersenff9eee42001-06-29 04:57:14 +00005116{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005117 int hf;
Eric Andersenff9eee42001-06-29 04:57:14 +00005118 int tf;
5119
5120#if __GNUC__
5121 /* Avoid longjmp clobbering */
5122 (void) &tf;
5123#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00005124 if (hname == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00005125 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005126
5127 DBGPRINTF7(("HEREIN: hname is %s, xdoll=%d\n", hname, xdoll));
5128
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005129 hf = open(hname, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00005130 if (hf < 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00005131 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005132
Eric Andersenff9eee42001-06-29 04:57:14 +00005133 if (xdoll) {
5134 char c;
5135 char tname[30] = ".msh_XXXXXX";
5136 jmp_buf ev;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005137
Eric Andersenff9eee42001-06-29 04:57:14 +00005138 tf = mkstemp(tname);
5139 if (tf < 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00005140 return -1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00005141 errpt = ev;
5142 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00005143 PUSHIO(afile, hf, herechar);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005144 setbase(global_env.iop);
Eric Andersenff9eee42001-06-29 04:57:14 +00005145 while ((c = subgetc(0, 0)) != 0) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005146 c &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00005147 write(tf, &c, sizeof c);
5148 }
5149 quitenv();
5150 } else
5151 unlink(tname);
5152 close(tf);
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005153 tf = open(tname, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00005154 unlink(tname);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00005155 return tf;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00005156 }
5157 return hf;
Eric Andersenff9eee42001-06-29 04:57:14 +00005158}
5159
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005160static void scraphere(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00005161{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005162 struct here *h;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005163
5164 DBGPRINTF7(("SCRAPHERE: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00005165
5166 for (h = inhere; h != NULL; h = h->h_next) {
5167 if (h->h_iop && h->h_iop->io_name)
Eric Andersen8401eea2004-08-04 19:16:54 +00005168 unlink(h->h_iop->io_name);
Eric Andersenff9eee42001-06-29 04:57:14 +00005169 }
5170 inhere = NULL;
5171}
5172
5173/* unlink here temp files before a freearea(area) */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005174static void freehere(int area)
Eric Andersenff9eee42001-06-29 04:57:14 +00005175{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005176 struct here *h, *hl;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005177
5178 DBGPRINTF6(("FREEHERE: enter, area=%d\n", area));
Eric Andersenff9eee42001-06-29 04:57:14 +00005179
5180 hl = NULL;
5181 for (h = acthere; h != NULL; h = h->h_next)
5182 if (getarea((char *) h) >= area) {
5183 if (h->h_iop->io_name != NULL)
5184 unlink(h->h_iop->io_name);
5185 if (hl == NULL)
5186 acthere = h->h_next;
5187 else
5188 hl->h_next = h->h_next;
5189 } else
5190 hl = h;
5191}
5192
5193
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005194/* -------- sh.c -------- */
5195/*
5196 * shell
5197 */
5198
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00005199int msh_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005200int msh_main(int argc, char **argv)
5201{
5202 int f;
5203 char *s;
5204 int cflag;
5205 char *name, **ap;
5206 int (*iof) (struct ioarg *);
5207
Denis Vlasenkoab801872007-12-02 08:35:37 +00005208 INIT_G();
5209
Denis Vlasenko55f30b02007-03-24 22:42:29 +00005210 sharedbuf.id = AFID_NOBUF;
5211 mainbuf.id = AFID_NOBUF;
Denis Vlasenko55f30b02007-03-24 22:42:29 +00005212 elinep = line + sizeof(line) - 5;
5213
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005214#if ENABLE_FEATURE_EDITING
5215 line_input_state = new_line_input_t(FOR_SHELL);
5216#endif
5217
5218 DBGPRINTF(("MSH_MAIN: argc %d, environ %p\n", argc, environ));
5219
5220 initarea();
5221 ap = environ;
5222 if (ap != NULL) {
5223 while (*ap)
5224 assign(*ap++, !COPYV);
5225 for (ap = environ; *ap;)
5226 export(lookup(*ap++));
5227 }
5228 closeall();
5229 areanum = 1;
5230
5231 shell = lookup("SHELL");
5232 if (shell->value == null)
5233 setval(shell, (char *)DEFAULT_SHELL);
5234 export(shell);
5235
5236 homedir = lookup("HOME");
5237 if (homedir->value == null)
5238 setval(homedir, "/");
5239 export(homedir);
5240
5241 setval(lookup("$"), putn(getpid()));
5242
5243 path = lookup("PATH");
5244 if (path->value == null) {
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005245 /* Can be merged with same string elsewhere in bbox */
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005246 if (geteuid() == 0)
Denis Vlasenkof5f75c52007-06-12 22:35:19 +00005247 setval(path, bb_default_root_path);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005248 else
Denis Vlasenkof5f75c52007-06-12 22:35:19 +00005249 setval(path, bb_default_path);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005250 }
5251 export(path);
5252
5253 ifs = lookup("IFS");
5254 if (ifs->value == null)
5255 setval(ifs, " \t\n");
5256
5257#ifdef MSHDEBUG
5258 mshdbg_var = lookup("MSHDEBUG");
5259 if (mshdbg_var->value == null)
5260 setval(mshdbg_var, "0");
5261#endif
5262
5263 prompt = lookup("PS1");
5264#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
5265 if (prompt->value == null)
5266#endif
5267 setval(prompt, DEFAULT_USER_PROMPT);
5268 if (geteuid() == 0) {
5269 setval(prompt, DEFAULT_ROOT_PROMPT);
5270 prompt->status &= ~EXPORT;
5271 }
5272 cprompt = lookup("PS2");
5273#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
5274 if (cprompt->value == null)
5275#endif
5276 setval(cprompt, "> ");
5277
5278 iof = filechar;
5279 cflag = 0;
5280 name = *argv++;
5281 if (--argc >= 1) {
5282 if (argv[0][0] == '-' && argv[0][1] != '\0') {
5283 for (s = argv[0] + 1; *s; s++)
5284 switch (*s) {
5285 case 'c':
5286 prompt->status &= ~EXPORT;
5287 cprompt->status &= ~EXPORT;
5288 setval(prompt, "");
5289 setval(cprompt, "");
5290 cflag = 1;
5291 if (--argc > 0)
5292 PUSHIO(aword, *++argv, iof = nlchar);
5293 break;
5294
5295 case 'q':
5296 qflag = SIG_DFL;
5297 break;
5298
5299 case 's':
5300 /* standard input */
5301 break;
5302
5303 case 't':
5304 prompt->status &= ~EXPORT;
5305 setval(prompt, "");
5306 iof = linechar;
5307 break;
5308
5309 case 'i':
Denis Vlasenko648b44f2008-02-12 06:04:06 +00005310 interactive = 1;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005311 default:
5312 if (*s >= 'a' && *s <= 'z')
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00005313 FLAG[(int) *s]++;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005314 }
5315 } else {
5316 argv--;
5317 argc++;
5318 }
5319
5320 if (iof == filechar && --argc > 0) {
5321 setval(prompt, "");
5322 setval(cprompt, "");
5323 prompt->status &= ~EXPORT;
5324 cprompt->status &= ~EXPORT;
5325
5326/* Shell is non-interactive, activate printf-based debug */
5327#ifdef MSHDEBUG
5328 mshdbg = (int) (((char) (mshdbg_var->value[0])) - '0');
5329 if (mshdbg < 0)
5330 mshdbg = 0;
5331#endif
5332 DBGPRINTF(("MSH_MAIN: calling newfile()\n"));
5333
5334 name = *++argv;
5335 if (newfile(name))
5336 exit(1); /* Exit on error */
5337 }
5338 }
5339
5340 setdash();
5341
5342 /* This won't be true if PUSHIO has been called, say from newfile() above */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005343 if (global_env.iop < iostack) {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005344 PUSHIO(afile, 0, iof);
5345 if (isatty(0) && isatty(1) && !cflag) {
Denis Vlasenko648b44f2008-02-12 06:04:06 +00005346 interactive = 1;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005347#if !ENABLE_FEATURE_SH_EXTRA_QUIET
5348#ifdef MSHDEBUG
Denis Vlasenkoca525b42007-06-13 12:27:17 +00005349 printf("\n\n%s built-in shell (msh with debug)\n", bb_banner);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005350#else
Denis Vlasenkoca525b42007-06-13 12:27:17 +00005351 printf("\n\n%s built-in shell (msh)\n", bb_banner);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005352#endif
5353 printf("Enter 'help' for a list of built-in commands.\n\n");
5354#endif
5355 }
5356 }
5357
5358 signal(SIGQUIT, qflag);
5359 if (name && name[0] == '-') {
Denis Vlasenko648b44f2008-02-12 06:04:06 +00005360 interactive = 1;
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005361 f = open(".profile", O_RDONLY);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005362 if (f >= 0)
5363 next(remap(f));
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005364 f = open("/etc/profile", O_RDONLY);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005365 if (f >= 0)
5366 next(remap(f));
5367 }
5368 if (interactive)
5369 signal(SIGTERM, sig);
5370
5371 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
5372 signal(SIGINT, onintr);
Denis Vlasenkofee2d0c2008-02-12 10:12:18 +00005373
5374/* Handle "msh SCRIPT VAR=val params..." */
5375/* Disabled: bash does not do it! */
5376#if 0
5377 argv++;
5378 /* skip leading args of the form VAR=val */
5379 while (*argv && assign(*argv, !COPYV)) {
5380 argc--;
5381 argv++;
5382 }
5383 argv--;
5384#endif
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005385 dolv = argv;
5386 dolc = argc;
5387 dolv[0] = name;
Denis Vlasenkofee2d0c2008-02-12 10:12:18 +00005388
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005389 setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc));
5390
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005391 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 +00005392
5393 for (;;) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005394 if (interactive && global_env.iop <= iostack) {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005395#if ENABLE_FEATURE_EDITING
5396 current_prompt = prompt->value;
5397#else
5398 prs(prompt->value);
5399#endif
5400 }
5401 onecommand();
5402 /* Ensure that getenv("PATH") stays current */
5403 setenv("PATH", path->value, 1);
5404 }
5405
5406 DBGPRINTF(("MSH_MAIN: returning.\n"));
5407}
5408
5409
Eric Andersenff9eee42001-06-29 04:57:14 +00005410/*
5411 * Copyright (c) 1987,1997, Prentice Hall
5412 * All rights reserved.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005413 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005414 * Redistribution and use of the MINIX operating system in source and
5415 * binary forms, with or without modification, are permitted provided
5416 * that the following conditions are met:
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005417 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005418 * Redistributions of source code must retain the above copyright
5419 * notice, this list of conditions and the following disclaimer.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005420 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005421 * Redistributions in binary form must reproduce the above
5422 * copyright notice, this list of conditions and the following
5423 * disclaimer in the documentation and/or other materials provided
5424 * with the distribution.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005425 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005426 * Neither the name of Prentice Hall nor the names of the software
5427 * authors or contributors may be used to endorse or promote
5428 * products derived from this software without specific prior
5429 * written permission.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005430 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005431 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND
5432 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
5433 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
5434 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
5435 * IN NO EVENT SHALL PRENTICE HALL OR ANY AUTHORS OR CONTRIBUTORS BE
5436 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
5437 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
5438 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
5439 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
5440 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
5441 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
5442 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5443 *
5444 */