blob: 569011bbd3fcdeda846c5cc04c7f4248bc63d37f [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 Vlasenko7e497522008-02-12 09:51:03 +0000492static int forkexec(struct op *t, int *pin, int *pout, int no_fork, char **wp);
493static int execute(struct op *t, int *pin, int *pout, int no_fork);
Eric Andersen8401eea2004-08-04 19:16:54 +0000494static int iosetup(struct ioword *iop, int pipein, int pipeout);
Eric Andersen8401eea2004-08-04 19:16:54 +0000495static void brkset(struct brkcon *bc);
496static int dolabel(struct op *t);
497static int dohelp(struct op *t);
498static int dochdir(struct op *t);
499static int doshift(struct op *t);
500static int dologin(struct op *t);
501static int doumask(struct op *t);
502static int doexec(struct op *t);
503static int dodot(struct op *t);
504static int dowait(struct op *t);
505static int doread(struct op *t);
506static int doeval(struct op *t);
507static int dotrap(struct op *t);
508static int getsig(char *s);
509static void setsig(int n, sighandler_t f);
510static int getn(char *as);
511static int dobreak(struct op *t);
512static int docontinue(struct op *t);
513static int brkcontin(char *cp, int val);
514static int doexit(struct op *t);
515static int doexport(struct op *t);
516static int doreadonly(struct op *t);
517static void rdexp(char **wp, void (*f) (struct var *), int key);
518static void badid(char *s);
519static int doset(struct op *t);
520static void varput(char *s, int out);
521static int dotimes(struct op *t);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000522static int expand(const char *cp, struct wdblock **wbp, int f);
Eric Andersen8401eea2004-08-04 19:16:54 +0000523static char *blank(int f);
524static int dollar(int quoted);
525static int grave(int quoted);
526static void globname(char *we, char *pp);
527static char *generate(char *start1, char *end1, char *middle, char *end);
528static int anyspcl(struct wdblock *wb);
529static int xstrcmp(char *p1, char *p2);
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000530static void glob0(char *a0, unsigned a1, int a2,
Eric Andersen8401eea2004-08-04 19:16:54 +0000531 int (*a3) (char *, char *));
Eric Andersen8401eea2004-08-04 19:16:54 +0000532static void readhere(char **name, char *s, int ec);
Eric Andersen8401eea2004-08-04 19:16:54 +0000533static int xxchar(struct ioarg *ap);
Eric Andersenff9eee42001-06-29 04:57:14 +0000534
Eric Andersen8401eea2004-08-04 19:16:54 +0000535struct here {
536 char *h_tag;
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000537 char h_dosub;
Eric Andersen8401eea2004-08-04 19:16:54 +0000538 struct ioword *h_iop;
539 struct here *h_next;
Eric Andersenff9eee42001-06-29 04:57:14 +0000540};
541
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000542static const char *const signame[] = {
Eric Andersenff9eee42001-06-29 04:57:14 +0000543 "Signal 0",
544 "Hangup",
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000545 NULL, /* interrupt */
Eric Andersenff9eee42001-06-29 04:57:14 +0000546 "Quit",
547 "Illegal instruction",
548 "Trace/BPT trap",
549 "Abort",
550 "Bus error",
551 "Floating Point Exception",
552 "Killed",
553 "SIGUSR1",
554 "SIGSEGV",
555 "SIGUSR2",
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000556 NULL, /* broken pipe */
Eric Andersenff9eee42001-06-29 04:57:14 +0000557 "Alarm clock",
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000558 "Terminated"
Eric Andersenff9eee42001-06-29 04:57:14 +0000559};
Eric Andersen8401eea2004-08-04 19:16:54 +0000560
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000561
Denis Vlasenko7e497522008-02-12 09:51:03 +0000562typedef int (*builtin_func_ptr)(struct op *);
563
Eric Andersen1c039232001-07-07 00:05:55 +0000564struct builtincmd {
565 const char *name;
Denis Vlasenko7e497522008-02-12 09:51:03 +0000566 builtin_func_ptr builtinfunc;
Eric Andersenff9eee42001-06-29 04:57:14 +0000567};
Denis Vlasenko7e497522008-02-12 09:51:03 +0000568
Eric Andersen8401eea2004-08-04 19:16:54 +0000569static const struct builtincmd builtincmds[] = {
Denis Vlasenko95cb3262007-04-09 03:06:34 +0000570 { "." , dodot },
571 { ":" , dolabel },
572 { "break" , dobreak },
573 { "cd" , dochdir },
574 { "continue", docontinue },
575 { "eval" , doeval },
576 { "exec" , doexec },
577 { "exit" , doexit },
578 { "export" , doexport },
579 { "help" , dohelp },
580 { "login" , dologin },
581 { "newgrp" , dologin },
582 { "read" , doread },
583 { "readonly", doreadonly },
584 { "set" , doset },
585 { "shift" , doshift },
586 { "times" , dotimes },
587 { "trap" , dotrap },
588 { "umask" , doumask },
589 { "wait" , dowait },
590 { NULL , NULL },
Eric Andersenff9eee42001-06-29 04:57:14 +0000591};
592
"Vladimir N. Oleynik"ac973172005-09-22 14:38:17 +0000593static struct op *scantree(struct op *);
Eric Andersen12de6cf2004-08-04 19:19:10 +0000594static struct op *dowholefile(int, int);
595
Eric Andersen12de6cf2004-08-04 19:19:10 +0000596
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000597/* Globals */
Eric Andersen8401eea2004-08-04 19:16:54 +0000598static char **dolv;
599static int dolc;
600static int exstat;
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000601static smallint gflg; /* (seems to be a parse error indicator) */
602static smallint interactive; /* Is this an interactive shell */
603static smallint execflg;
604static smallint isbreak; /* "break" statement was seen */
605static int multiline; /* '\n' changed to ';' (counter) */
606static struct op *outtree; /* result from parser */
Eric Andersen8401eea2004-08-04 19:16:54 +0000607static xint *failpt;
608static xint *errpt;
609static struct brkcon *brklist;
Eric Andersen8401eea2004-08-04 19:16:54 +0000610static struct wdblock *wdlist;
611static struct wdblock *iolist;
Eric Andersen12de6cf2004-08-04 19:19:10 +0000612
613#ifdef MSHDEBUG
614static struct var *mshdbg_var;
615#endif
Eric Andersen8401eea2004-08-04 19:16:54 +0000616static struct var *vlist; /* dictionary */
617static struct var *homedir; /* home directory */
618static struct var *prompt; /* main prompt */
619static struct var *cprompt; /* continuation prompt */
620static struct var *path; /* search path for commands */
621static struct var *shell; /* shell to interpret command files */
622static struct var *ifs; /* field separators */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000623
Denis Vlasenko95cb3262007-04-09 03:06:34 +0000624static int areanum; /* current allocation area */
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000625static smallint intr; /* interrupt pending (bool) */
626static smallint heedint = 1; /* heed interrupt signals (bool) */
Eric Andersen8401eea2004-08-04 19:16:54 +0000627static int inparse;
Denis Vlasenko95cb3262007-04-09 03:06:34 +0000628static char *null = (char*)""; /* null value for variable */
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +0000629static void (*qflag)(int) = SIG_IGN;
Eric Andersen8401eea2004-08-04 19:16:54 +0000630static int startl;
631static int peeksym;
632static int nlseen;
633static int iounit = IODEFAULT;
634static YYSTYPE yylval;
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000635static char *elinep; /* done in main(): = line + sizeof(line) - 5 */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000636
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000637static struct here *inhere; /* list of hear docs while parsing */
638static struct here *acthere; /* list of active here documents */
639static struct region *areabot; /* bottom of area */
640static struct region *areatop; /* top of area */
641static struct region *areanxt; /* starting point of scan */
Eric Andersen8401eea2004-08-04 19:16:54 +0000642static void *brktop;
643static void *brkaddr;
Eric Andersenff9eee42001-06-29 04:57:14 +0000644
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000645#define AFID_NOBUF (~0)
646#define AFID_ID 0
647
648
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000649/*
650 * parsing & execution environment
651 */
652struct env {
653 char *linep;
654 struct io *iobase;
655 struct io *iop;
656 xint *errpt; /* void * */
657 int iofd;
658 struct env *oenv;
659};
660
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000661
662struct globals {
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000663 struct env global_env;
664 struct ioarg temparg; // = { .afid = AFID_NOBUF }; /* temporary for PUSHIO */
665 unsigned bufid; // = AFID_ID; /* buffer id counter */
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000666 char ourtrap[_NSIG + 1];
667 char *trap[_NSIG + 1];
668 struct iobuf sharedbuf; /* in main(): set to { AFID_NOBUF } */
669 struct iobuf mainbuf; /* in main(): set to { AFID_NOBUF } */
670 struct ioarg ioargstack[NPUSH];
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000671 /*
672 * flags:
673 * -e: quit on error
674 * -k: look for name=value everywhere on command line
675 * -n: no execution
676 * -t: exit after reading and executing one command
677 * -v: echo as read
678 * -x: trace
679 * -u: unset variables net diagnostic
680 */
681 char flags['z' - 'a' + 1];
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000682 char filechar_cmdbuf[BUFSIZ];
683 char line[LINELIM];
684 char child_cmd[LINELIM];
Denis Vlasenkoab801872007-12-02 08:35:37 +0000685
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000686 struct io iostack[NPUSH];
687
Denis Vlasenkoab801872007-12-02 08:35:37 +0000688 char grave__var_name[LINELIM];
689 char grave__alt_value[LINELIM];
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000690};
691
692#define G (*ptr_to_globals)
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000693#define global_env (G.global_env )
694#define temparg (G.temparg )
695#define bufid (G.bufid )
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000696#define ourtrap (G.ourtrap )
697#define trap (G.trap )
698#define sharedbuf (G.sharedbuf )
699#define mainbuf (G.mainbuf )
700#define ioargstack (G.ioargstack )
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000701/* this looks weird, but is OK ... we index FLAG with 'a'...'z' */
702#define FLAG (G.flags - 'a' )
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000703#define filechar_cmdbuf (G.filechar_cmdbuf)
704#define line (G.line )
705#define child_cmd (G.child_cmd )
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000706#define iostack (G.iostack )
Denis Vlasenkoab801872007-12-02 08:35:37 +0000707#define INIT_G() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000708 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000709 global_env.linep = line; \
710 global_env.iobase = iostack; \
711 global_env.iop = iostack - 1; \
712 global_env.iofd = FDBASE; \
713 temparg.afid = AFID_NOBUF; \
714 bufid = AFID_ID; \
Denis Vlasenkoab801872007-12-02 08:35:37 +0000715} while (0)
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000716
717
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000718/* in substitution */
719#define INSUB() (global_env.iop->task == XGRAVE || global_env.iop->task == XDOLL)
720
721#define RUN(what, arg, gen) ((temparg.what = (arg)), run(&temparg, (gen)))
722
Eric Andersen12de6cf2004-08-04 19:19:10 +0000723#ifdef MSHDEBUG
724void print_t(struct op *t)
725{
Mike Frysinger02d8fa42006-05-05 20:32:31 +0000726 DBGPRINTF(("T: t=%p, type %s, words=%p, IOword=%p\n", t,
727 T_CMD_NAMES[t->type], t->words, t->ioact));
Eric Andersen12de6cf2004-08-04 19:19:10 +0000728
729 if (t->words) {
730 DBGPRINTF(("T: W1: %s", t->words[0]));
731 }
Eric Andersen12de6cf2004-08-04 19:19:10 +0000732}
733
734void print_tree(struct op *head)
735{
736 if (head == NULL) {
737 DBGPRINTF(("PRINT_TREE: no tree\n"));
738 return;
739 }
740
Mike Frysinger02d8fa42006-05-05 20:32:31 +0000741 DBGPRINTF(("NODE: %p, left %p, right %p\n", head, head->left,
Eric Andersen12de6cf2004-08-04 19:19:10 +0000742 head->right));
743
744 if (head->left)
745 print_tree(head->left);
746
747 if (head->right)
748 print_tree(head->right);
Eric Andersen12de6cf2004-08-04 19:19:10 +0000749}
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000750#endif /* MSHDEBUG */
751
752
753/*
754 * IO functions
755 */
756static void prs(const char *s)
757{
758 if (*s)
759 write(2, s, strlen(s));
760}
761
762static void prn(unsigned u)
763{
764 prs(itoa(u));
765}
766
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000767static void echo(char **wp)
768{
769 int i;
770
771 prs("+");
772 for (i = 0; wp[i]; i++) {
773 if (i)
774 prs(" ");
775 prs(wp[i]);
776 }
777 prs("\n");
778}
779
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000780static void closef(int i)
781{
782 if (i > 2)
783 close(i);
784}
785
786static void closeall(void)
787{
788 int u;
789
790 for (u = NUFILE; u < NOFILE;)
791 close(u++);
792}
Eric Andersen12de6cf2004-08-04 19:19:10 +0000793
Eric Andersenff9eee42001-06-29 04:57:14 +0000794
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000795/* fail but return to process next command */
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000796static void fail(void) ATTRIBUTE_NORETURN;
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000797static void fail(void)
798{
799 longjmp(failpt, 1);
800 /* NOTREACHED */
801}
Eric Andersenff9eee42001-06-29 04:57:14 +0000802
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000803/* abort shell (or fail in subshell) */
804static void leave(void) ATTRIBUTE_NORETURN;
805static void leave(void)
806{
807 DBGPRINTF(("LEAVE: leave called!\n"));
808
809 if (execflg)
810 fail();
811 scraphere();
812 freehere(1);
813 runtrap(0);
814 _exit(exstat);
815 /* NOTREACHED */
816}
817
818static void warn(const char *s)
819{
820 if (*s) {
821 prs(s);
822 exstat = -1;
823 }
824 prs("\n");
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +0000825 if (FLAG['e'])
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000826 leave();
827}
828
829static void err(const char *s)
830{
831 warn(s);
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +0000832 if (FLAG['n'])
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000833 return;
834 if (!interactive)
835 leave();
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000836 if (global_env.errpt)
837 longjmp(global_env.errpt, 1);
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000838 closeall();
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000839 global_env.iop = global_env.iobase = iostack;
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000840}
841
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000842
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000843/* -------- area.c -------- */
844
Eric Andersenff9eee42001-06-29 04:57:14 +0000845/*
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000846 * All memory between (char *)areabot and (char *)(areatop+1) is
847 * exclusively administered by the area management routines.
848 * It is assumed that sbrk() and brk() manipulate the high end.
Eric Andersenff9eee42001-06-29 04:57:14 +0000849 */
850
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000851#define sbrk(X) ({ \
852 void * __q = (void *)-1; \
853 if (brkaddr + (int)(X) < brktop) { \
854 __q = brkaddr; \
855 brkaddr += (int)(X); \
856 } \
857 __q; \
858})
Eric Andersenff9eee42001-06-29 04:57:14 +0000859
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000860static void initarea(void)
Eric Andersenff9eee42001-06-29 04:57:14 +0000861{
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000862 brkaddr = xmalloc(AREASIZE);
863 brktop = brkaddr + AREASIZE;
Eric Andersenff9eee42001-06-29 04:57:14 +0000864
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000865 while ((long) sbrk(0) & ALIGN)
866 sbrk(1);
867 areabot = (struct region *) sbrk(REGSIZE);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +0000868
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000869 areabot->next = areabot;
870 areabot->area = BUSY;
871 areatop = areabot;
872 areanxt = areabot;
Eric Andersenff9eee42001-06-29 04:57:14 +0000873}
874
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000875static char *getcell(unsigned nbytes)
876{
877 int nregio;
878 struct region *p, *q;
879 int i;
880
881 if (nbytes == 0) {
882 puts("getcell(0)");
883 abort();
884 }
885 /* silly and defeats the algorithm */
886 /*
887 * round upwards and add administration area
888 */
889 nregio = (nbytes + (REGSIZE - 1)) / REGSIZE + 1;
890 p = areanxt;
891 for (;;) {
892 if (p->area > areanum) {
893 /*
894 * merge free cells
895 */
896 while ((q = p->next)->area > areanum && q != areanxt)
897 p->next = q->next;
898 /*
899 * exit loop if cell big enough
900 */
901 if (q >= p + nregio)
902 goto found;
903 }
904 p = p->next;
905 if (p == areanxt)
906 break;
907 }
908 i = nregio >= GROWBY ? nregio : GROWBY;
909 p = (struct region *) sbrk(i * REGSIZE);
910 if (p == (struct region *) -1)
911 return NULL;
912 p--;
913 if (p != areatop) {
914 puts("not contig");
915 abort(); /* allocated areas are contiguous */
916 }
917 q = p + i;
918 p->next = q;
919 p->area = FREE;
920 q->next = areabot;
921 q->area = BUSY;
922 areatop = q;
923 found:
924 /*
925 * we found a FREE area big enough, pointed to by 'p', and up to 'q'
926 */
927 areanxt = p + nregio;
928 if (areanxt < q) {
929 /*
930 * split into requested area and rest
931 */
932 if (areanxt + 1 > q) {
933 puts("OOM");
934 abort(); /* insufficient space left for admin */
935 }
936 areanxt->next = q;
937 areanxt->area = FREE;
938 p->next = areanxt;
939 }
940 p->area = areanum;
941 return (char *) (p + 1);
942}
943
944static void freecell(char *cp)
945{
946 struct region *p;
947
948 p = (struct region *) cp;
949 if (p != NULL) {
950 p--;
951 if (p < areanxt)
952 areanxt = p;
953 p->area = FREE;
954 }
955}
956#define DELETE(obj) freecell((char *)obj)
957
958static void freearea(int a)
959{
960 struct region *p, *top;
961
962 top = areatop;
963 for (p = areabot; p != top; p = p->next)
964 if (p->area >= a)
965 p->area = FREE;
966}
967
968static void setarea(char *cp, int a)
969{
970 struct region *p;
971
972 p = (struct region *) cp;
973 if (p != NULL)
974 (p - 1)->area = a;
975}
976
977static int getarea(char *cp)
978{
979 return ((struct region *) cp - 1)->area;
980}
981
982static void garbage(void)
983{
984 struct region *p, *q, *top;
985
986 top = areatop;
987 for (p = areabot; p != top; p = p->next) {
988 if (p->area > areanum) {
989 while ((q = p->next)->area > areanum)
990 p->next = q->next;
991 areanxt = p;
992 }
993 }
994#ifdef SHRINKBY
995 if (areatop >= q + SHRINKBY && q->area > areanum) {
996 brk((char *) (q + 1));
997 q->next = areabot;
998 q->area = BUSY;
999 areatop = q;
1000 }
1001#endif
1002}
1003
1004static char *space(int n)
1005{
1006 char *cp;
1007
1008 cp = getcell(n);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001009 if (cp == NULL)
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001010 err("out of string space");
1011 return cp;
1012}
1013
1014static char *strsave(const char *s, int a)
1015{
1016 char *cp;
1017
1018 cp = space(strlen(s) + 1);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001019 if (cp == NULL) {
1020// FIXME: I highly doubt this is good.
1021 return (char*)"";
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001022 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001023 setarea(cp, a);
1024 strcpy(cp, s);
1025 return cp;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001026}
1027
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001028
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001029/* -------- var.c -------- */
1030
1031static int eqname(const char *n1, const char *n2)
1032{
1033 for (; *n1 != '=' && *n1 != '\0'; n1++)
1034 if (*n2++ != *n1)
1035 return 0;
1036 return *n2 == '\0' || *n2 == '=';
1037}
1038
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001039static const char *findeq(const char *cp)
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001040{
1041 while (*cp != '\0' && *cp != '=')
1042 cp++;
1043 return cp;
1044}
1045
1046/*
1047 * Find the given name in the dictionary
1048 * and return its value. If the name was
1049 * not previously there, enter it now and
1050 * return a null value.
1051 */
1052static struct var *lookup(const char *n)
1053{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001054// FIXME: dirty hack
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001055 static struct var dummy;
1056
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001057 struct var *vp;
1058 const char *cp;
1059 char *xp;
1060 int c;
1061
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001062 if (isdigit(*n)) {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001063 dummy.name = (char*)n;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001064 for (c = 0; isdigit(*n) && c < 1000; n++)
1065 c = c * 10 + *n - '0';
1066 dummy.status = RONLY;
1067 dummy.value = (c <= dolc ? dolv[c] : null);
1068 return &dummy;
1069 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001070
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001071 for (vp = vlist; vp; vp = vp->next)
1072 if (eqname(vp->name, n))
1073 return vp;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001074
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001075 cp = findeq(n);
1076 vp = (struct var *) space(sizeof(*vp));
1077 if (vp == 0 || (vp->name = space((int) (cp - n) + 2)) == 0) {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001078 dummy.name = dummy.value = (char*)"";
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001079 return &dummy;
1080 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001081
1082 xp = vp->name;
1083 while ((*xp = *n++) != '\0' && *xp != '=')
1084 xp++;
1085 *xp++ = '=';
1086 *xp = '\0';
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001087 setarea((char *) vp, 0);
1088 setarea((char *) vp->name, 0);
1089 vp->value = null;
1090 vp->next = vlist;
1091 vp->status = GETCELL;
1092 vlist = vp;
1093 return vp;
1094}
1095
1096/*
1097 * if name is not NULL, it must be
1098 * a prefix of the space `val',
1099 * and end with `='.
1100 * this is all so that exporting
1101 * values is reasonably painless.
1102 */
1103static void nameval(struct var *vp, const char *val, const char *name)
1104{
1105 const char *cp;
1106 char *xp;
1107 int fl;
1108
1109 if (vp->status & RONLY) {
1110 xp = vp->name;
1111 while (*xp && *xp != '=')
Denis Vlasenko4daad902007-09-27 10:20:47 +00001112 fputc(*xp++, stderr);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001113 err(" is read-only");
1114 return;
1115 }
1116 fl = 0;
1117 if (name == NULL) {
1118 xp = space(strlen(vp->name) + strlen(val) + 2);
1119 if (xp == NULL)
1120 return;
1121 /* make string: name=value */
1122 setarea(xp, 0);
1123 name = xp;
1124 cp = vp->name;
1125 while ((*xp = *cp++) != '\0' && *xp != '=')
1126 xp++;
1127 *xp++ = '=';
1128 strcpy(xp, val);
1129 val = xp;
1130 fl = GETCELL;
1131 }
1132 if (vp->status & GETCELL)
1133 freecell(vp->name); /* form new string `name=value' */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001134 vp->name = (char*)name;
1135 vp->value = (char*)val;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001136 vp->status |= fl;
1137}
1138
1139/*
1140 * give variable at `vp' the value `val'.
1141 */
1142static void setval(struct var *vp, const char *val)
1143{
1144 nameval(vp, val, NULL);
1145}
1146
1147static void export(struct var *vp)
1148{
1149 vp->status |= EXPORT;
1150}
1151
1152static void ronly(struct var *vp)
1153{
1154 if (isalpha(vp->name[0]) || vp->name[0] == '_') /* not an internal symbol */
1155 vp->status |= RONLY;
1156}
1157
1158static int isassign(const char *s)
1159{
1160 unsigned char c;
1161 DBGPRINTF7(("ISASSIGN: enter, s=%s\n", s));
1162
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001163 c = *s;
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001164 /* no isalpha() - we shouldn't use locale */
1165 /* c | 0x20 - lowercase (Latin) letters */
1166 if (c != '_' && (unsigned)((c|0x20) - 'a') > 25)
1167 /* not letter */
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001168 return 0;
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001169
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001170 while (1) {
1171 c = *++s;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001172 if (c == '=')
1173 return 1;
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001174 if (c == '\0')
1175 return 0;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001176 if (c != '_'
1177 && (unsigned)(c - '0') > 9 /* not number */
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001178 && (unsigned)((c|0x20) - 'a') > 25 /* not letter */
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001179 ) {
1180 return 0;
1181 }
1182 }
1183}
1184
1185static int assign(const char *s, int cf)
1186{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001187 const char *cp;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001188 struct var *vp;
1189
1190 DBGPRINTF7(("ASSIGN: enter, s=%s, cf=%d\n", s, cf));
1191
1192 if (!isalpha(*s) && *s != '_')
1193 return 0;
1194 for (cp = s; *cp != '='; cp++)
1195 if (*cp == '\0' || (!isalnum(*cp) && *cp != '_'))
1196 return 0;
1197 vp = lookup(s);
1198 nameval(vp, ++cp, cf == COPYV ? NULL : s);
1199 if (cf != COPYV)
1200 vp->status &= ~GETCELL;
1201 return 1;
1202}
1203
1204static int checkname(char *cp)
1205{
1206 DBGPRINTF7(("CHECKNAME: enter, cp=%s\n", cp));
1207
1208 if (!isalpha(*cp++) && *(cp - 1) != '_')
1209 return 0;
1210 while (*cp)
1211 if (!isalnum(*cp++) && *(cp - 1) != '_')
1212 return 0;
1213 return 1;
1214}
1215
1216static void putvlist(int f, int out)
1217{
1218 struct var *vp;
1219
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001220 for (vp = vlist; vp; vp = vp->next) {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001221 if (vp->status & f && (isalpha(*vp->name) || *vp->name == '_')) {
1222 if (vp->status & EXPORT)
1223 write(out, "export ", 7);
1224 if (vp->status & RONLY)
1225 write(out, "readonly ", 9);
1226 write(out, vp->name, (int) (findeq(vp->name) - vp->name));
1227 write(out, "\n", 1);
1228 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001229 }
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001230}
1231
1232
1233/*
1234 * trap handling
1235 */
1236static void sig(int i)
1237{
1238 trapset = i;
1239 signal(i, sig);
1240}
1241
1242static void runtrap(int i)
1243{
1244 char *trapstr;
1245
1246 trapstr = trap[i];
1247 if (trapstr == NULL)
1248 return;
1249
1250 if (i == 0)
1251 trap[i] = NULL;
1252
1253 RUN(aword, trapstr, nlchar);
1254}
1255
1256
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001257static void setdash(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001258{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001259 char *cp;
1260 int c;
Eric Andersen8401eea2004-08-04 19:16:54 +00001261 char m['z' - 'a' + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00001262
1263 cp = m;
Eric Andersen8401eea2004-08-04 19:16:54 +00001264 for (c = 'a'; c <= 'z'; c++)
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00001265 if (FLAG[c])
Eric Andersenff9eee42001-06-29 04:57:14 +00001266 *cp++ = c;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001267 *cp = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00001268 setval(lookup("-"), m);
1269}
1270
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001271static int newfile(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00001272{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001273 int f;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001274
1275 DBGPRINTF7(("NEWFILE: opening %s\n", s));
Eric Andersenff9eee42001-06-29 04:57:14 +00001276
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001277 f = 0;
Denis Vlasenko9f739442006-12-16 23:49:13 +00001278 if (NOT_LONE_DASH(s)) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001279 DBGPRINTF(("NEWFILE: s is %s\n", s));
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00001280 f = open(s, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00001281 if (f < 0) {
1282 prs(s);
1283 err(": cannot open");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001284 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001285 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001286 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001287
Eric Andersenff9eee42001-06-29 04:57:14 +00001288 next(remap(f));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001289 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001290}
1291
Eric Andersen12de6cf2004-08-04 19:19:10 +00001292
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001293struct op *scantree(struct op *head)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001294{
1295 struct op *dotnode;
1296
1297 if (head == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001298 return NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001299
1300 if (head->left != NULL) {
1301 dotnode = scantree(head->left);
1302 if (dotnode)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001303 return dotnode;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001304 }
1305
1306 if (head->right != NULL) {
1307 dotnode = scantree(head->right);
1308 if (dotnode)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001309 return dotnode;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001310 }
1311
1312 if (head->words == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001313 return NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001314
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001315 DBGPRINTF5(("SCANTREE: checking node %p\n", head));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001316
Denis Vlasenkocf787cf2007-02-04 17:11:25 +00001317 if ((head->type != TDOT) && LONE_CHAR(head->words[0], '.')) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001318 DBGPRINTF5(("SCANTREE: dot found in node %p\n", head));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001319 return head;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001320 }
1321
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001322 return NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001323}
1324
1325
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001326static void onecommand(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001327{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001328 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00001329 jmp_buf m1;
1330
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001331 DBGPRINTF(("ONECOMMAND: enter, outtree=%p\n", outtree));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001332
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001333 while (global_env.oenv)
Eric Andersenff9eee42001-06-29 04:57:14 +00001334 quitenv();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001335
Eric Andersenff9eee42001-06-29 04:57:14 +00001336 areanum = 1;
1337 freehere(areanum);
1338 freearea(areanum);
1339 garbage();
1340 wdlist = 0;
1341 iolist = 0;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001342 global_env.errpt = 0;
1343 global_env.linep = line;
Eric Andersenff9eee42001-06-29 04:57:14 +00001344 yynerrs = 0;
1345 multiline = 0;
1346 inparse = 1;
1347 intr = 0;
1348 execflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001349
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001350 failpt = m1;
1351 setjmp(failpt); /* Bruce Evans' fix */
1352 failpt = m1;
1353 if (setjmp(failpt) || yyparse() || intr) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001354 DBGPRINTF(("ONECOMMAND: this is not good.\n"));
1355
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001356 while (global_env.oenv)
Eric Andersenff9eee42001-06-29 04:57:14 +00001357 quitenv();
1358 scraphere();
1359 if (!interactive && intr)
1360 leave();
1361 inparse = 0;
1362 intr = 0;
1363 return;
1364 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001365
Eric Andersenff9eee42001-06-29 04:57:14 +00001366 inparse = 0;
1367 brklist = 0;
1368 intr = 0;
1369 execflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001370
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00001371 if (!FLAG['n']) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001372 DBGPRINTF(("ONECOMMAND: calling execute, t=outtree=%p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00001373 outtree));
Denis Vlasenko7e497522008-02-12 09:51:03 +00001374 execute(outtree, NOPIPE, NOPIPE, /* no_fork: */ 0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001375 }
1376
Eric Andersenff9eee42001-06-29 04:57:14 +00001377 if (!interactive && intr) {
1378 execflg = 0;
1379 leave();
1380 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001381
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001382 i = trapset;
1383 if (i != 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001384 trapset = 0;
1385 runtrap(i);
1386 }
1387}
1388
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001389static int newenv(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00001390{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001391 struct env *ep;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001392
1393 DBGPRINTF(("NEWENV: f=%d (indicates quitenv and return)\n", f));
Eric Andersenff9eee42001-06-29 04:57:14 +00001394
1395 if (f) {
1396 quitenv();
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001397 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001398 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001399
Eric Andersenff9eee42001-06-29 04:57:14 +00001400 ep = (struct env *) space(sizeof(*ep));
1401 if (ep == NULL) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001402 while (global_env.oenv)
Eric Andersenff9eee42001-06-29 04:57:14 +00001403 quitenv();
1404 fail();
1405 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001406 *ep = global_env;
1407 global_env.oenv = ep;
1408 global_env.errpt = errpt;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001409
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001410 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001411}
1412
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001413static void quitenv(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001414{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001415 struct env *ep;
1416 int fd;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001417
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001418 DBGPRINTF(("QUITENV: global_env.oenv=%p\n", global_env.oenv));
Eric Andersenff9eee42001-06-29 04:57:14 +00001419
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001420 ep = global_env.oenv;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001421 if (ep != NULL) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001422 fd = global_env.iofd;
1423 global_env = *ep;
Eric Andersenff9eee42001-06-29 04:57:14 +00001424 /* should close `'d files */
1425 DELETE(ep);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001426 while (--fd >= global_env.iofd)
Eric Andersenff9eee42001-06-29 04:57:14 +00001427 close(fd);
1428 }
1429}
1430
1431/*
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001432 * Is character c in s?
Eric Andersenff9eee42001-06-29 04:57:14 +00001433 */
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001434static int any(int c, const char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00001435{
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001436 while (*s)
1437 if (*s++ == c)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001438 return 1;
1439 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001440}
1441
1442/*
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001443 * Is any character from s1 in s2?
Eric Andersenff9eee42001-06-29 04:57:14 +00001444 */
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001445static int anys(const char *s1, const char *s2)
Eric Andersenff9eee42001-06-29 04:57:14 +00001446{
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001447 while (*s1)
1448 if (any(*s1++, s2))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001449 return 1;
1450 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001451}
1452
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001453static char *putn(int n)
Eric Andersenff9eee42001-06-29 04:57:14 +00001454{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001455 return itoa(n);
Eric Andersenff9eee42001-06-29 04:57:14 +00001456}
1457
Eric Andersen8401eea2004-08-04 19:16:54 +00001458static void next(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00001459{
1460 PUSHIO(afile, f, filechar);
1461}
1462
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001463static void onintr(int s) /* ANSI C requires a parameter */
Eric Andersenff9eee42001-06-29 04:57:14 +00001464{
1465 signal(SIGINT, onintr);
1466 intr = 1;
1467 if (interactive) {
1468 if (inparse) {
1469 prs("\n");
1470 fail();
1471 }
Eric Andersen8401eea2004-08-04 19:16:54 +00001472 } else if (heedint) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001473 execflg = 0;
1474 leave();
1475 }
1476}
1477
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001478
Eric Andersenff9eee42001-06-29 04:57:14 +00001479/* -------- gmatch.c -------- */
1480/*
1481 * int gmatch(string, pattern)
1482 * char *string, *pattern;
1483 *
1484 * Match a pattern as in sh(1).
1485 */
1486
1487#define CMASK 0377
1488#define QUOTE 0200
Denis Vlasenko55f30b02007-03-24 22:42:29 +00001489#define QMASK (CMASK & ~QUOTE)
Eric Andersen8401eea2004-08-04 19:16:54 +00001490#define NOT '!' /* might use ^ */
Eric Andersenff9eee42001-06-29 04:57:14 +00001491
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001492static const char *cclass(const char *p, int sub)
1493{
1494 int c, d, not, found;
1495
1496 not = (*p == NOT);
1497 if (not != 0)
1498 p++;
1499 found = not;
1500 do {
1501 if (*p == '\0')
1502 return NULL;
1503 c = *p & CMASK;
1504 if (p[1] == '-' && p[2] != ']') {
1505 d = p[2] & CMASK;
1506 p++;
1507 } else
1508 d = c;
1509 if (c == sub || (c <= sub && sub <= d))
1510 found = !not;
1511 } while (*++p != ']');
1512 return found ? p + 1 : NULL;
1513}
1514
1515static int gmatch(const char *s, const char *p)
Eric Andersenff9eee42001-06-29 04:57:14 +00001516{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001517 int sc, pc;
Eric Andersenff9eee42001-06-29 04:57:14 +00001518
1519 if (s == NULL || p == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001520 return 0;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001521
Eric Andersenff9eee42001-06-29 04:57:14 +00001522 while ((pc = *p++ & CMASK) != '\0') {
1523 sc = *s++ & QMASK;
1524 switch (pc) {
1525 case '[':
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001526 p = cclass(p, sc);
1527 if (p == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001528 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001529 break;
1530
1531 case '?':
1532 if (sc == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001533 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001534 break;
1535
1536 case '*':
1537 s--;
1538 do {
1539 if (*p == '\0' || gmatch(s, p))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001540 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001541 } while (*s++ != '\0');
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001542 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001543
1544 default:
Eric Andersen8401eea2004-08-04 19:16:54 +00001545 if (sc != (pc & ~QUOTE))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001546 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001547 }
1548 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001549 return *s == '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00001550}
1551
Eric Andersenff9eee42001-06-29 04:57:14 +00001552
Eric Andersenff9eee42001-06-29 04:57:14 +00001553/* -------- csyn.c -------- */
1554/*
1555 * shell: syntax (C version)
1556 */
1557
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001558static void yyerror(const char *s) ATTRIBUTE_NORETURN;
1559static void yyerror(const char *s)
1560{
Denis Vlasenko648b44f2008-02-12 06:04:06 +00001561 yynerrs = 1;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001562 if (interactive && global_env.iop <= iostack) {
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001563 multiline = 0;
Denis Vlasenko648b44f2008-02-12 06:04:06 +00001564 while (eofc() == 0 && yylex(0) != '\n')
1565 continue;
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001566 }
1567 err(s);
1568 fail();
1569}
1570
1571static void zzerr(void) ATTRIBUTE_NORETURN;
1572static void zzerr(void)
1573{
1574 yyerror("syntax error");
1575}
1576
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001577int yyparse(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001578{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001579 DBGPRINTF7(("YYPARSE: enter...\n"));
1580
Eric Andersen8401eea2004-08-04 19:16:54 +00001581 startl = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001582 peeksym = 0;
1583 yynerrs = 0;
1584 outtree = c_list();
1585 musthave('\n', 0);
Denis Vlasenko648b44f2008-02-12 06:04:06 +00001586 return yynerrs; /* 0/1 */
Eric Andersenff9eee42001-06-29 04:57:14 +00001587}
1588
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001589static struct op *pipeline(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001590{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001591 struct op *t, *p;
1592 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001593
1594 DBGPRINTF7(("PIPELINE: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001595
1596 t = command(cf);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001597
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001598 DBGPRINTF9(("PIPELINE: t=%p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001599
Eric Andersenff9eee42001-06-29 04:57:14 +00001600 if (t != NULL) {
1601 while ((c = yylex(0)) == '|') {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001602 p = command(CONTIN);
1603 if (p == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001604 DBGPRINTF8(("PIPELINE: error!\n"));
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001605 zzerr();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001606 }
1607
Eric Andersenff9eee42001-06-29 04:57:14 +00001608 if (t->type != TPAREN && t->type != TCOM) {
1609 /* shell statement */
1610 t = block(TPAREN, t, NOBLOCK, NOWORDS);
1611 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001612
Eric Andersenff9eee42001-06-29 04:57:14 +00001613 t = block(TPIPE, t, p, NOWORDS);
1614 }
1615 peeksym = c;
1616 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001617
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001618 DBGPRINTF7(("PIPELINE: returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001619 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001620}
1621
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001622static struct op *andor(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001623{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001624 struct op *t, *p;
1625 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001626
1627 DBGPRINTF7(("ANDOR: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001628
1629 t = pipeline(0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001630
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001631 DBGPRINTF9(("ANDOR: t=%p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001632
Eric Andersenff9eee42001-06-29 04:57:14 +00001633 if (t != NULL) {
1634 while ((c = yylex(0)) == LOGAND || c == LOGOR) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001635 p = pipeline(CONTIN);
1636 if (p == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001637 DBGPRINTF8(("ANDOR: error!\n"));
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001638 zzerr();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001639 }
1640
Eric Andersen8401eea2004-08-04 19:16:54 +00001641 t = block(c == LOGAND ? TAND : TOR, t, p, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001642 } /* WHILE */
1643
Eric Andersenff9eee42001-06-29 04:57:14 +00001644 peeksym = c;
1645 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001646
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001647 DBGPRINTF7(("ANDOR: returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001648 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001649}
1650
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001651static struct op *c_list(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001652{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001653 struct op *t, *p;
1654 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001655
1656 DBGPRINTF7(("C_LIST: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001657
1658 t = andor();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001659
Eric Andersenff9eee42001-06-29 04:57:14 +00001660 if (t != NULL) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001661 peeksym = yylex(0);
1662 if (peeksym == '&')
Eric Andersenff9eee42001-06-29 04:57:14 +00001663 t = block(TASYNC, t, NOBLOCK, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001664
Eric Andersen8401eea2004-08-04 19:16:54 +00001665 while ((c = yylex(0)) == ';' || c == '&'
1666 || (multiline && c == '\n')) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001667
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001668 p = andor();
1669 if (p== NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001670 return t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001671
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001672 peeksym = yylex(0);
1673 if (peeksym == '&')
Eric Andersenff9eee42001-06-29 04:57:14 +00001674 p = block(TASYNC, p, NOBLOCK, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001675
Eric Andersenff9eee42001-06-29 04:57:14 +00001676 t = list(t, p);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001677 } /* WHILE */
1678
Eric Andersenff9eee42001-06-29 04:57:14 +00001679 peeksym = c;
1680 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001681 /* IF */
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001682 DBGPRINTF7(("C_LIST: returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001683 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001684}
1685
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001686static int synio(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001687{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001688 struct ioword *iop;
1689 int i;
1690 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001691
1692 DBGPRINTF7(("SYNIO: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001693
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001694 c = yylex(cf);
1695 if (c != '<' && c != '>') {
Eric Andersenff9eee42001-06-29 04:57:14 +00001696 peeksym = c;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001697 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001698 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001699
Eric Andersenff9eee42001-06-29 04:57:14 +00001700 i = yylval.i;
1701 musthave(WORD, 0);
1702 iop = io(iounit, i, yylval.cp);
1703 iounit = IODEFAULT;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001704
Eric Andersenff9eee42001-06-29 04:57:14 +00001705 if (i & IOHERE)
1706 markhere(yylval.cp, iop);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001707
1708 DBGPRINTF7(("SYNIO: returning 1\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001709 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001710}
1711
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001712static void musthave(int c, int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001713{
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001714 peeksym = yylex(cf);
1715 if (peeksym != c) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001716 DBGPRINTF7(("MUSTHAVE: error!\n"));
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001717 zzerr();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001718 }
1719
Eric Andersenff9eee42001-06-29 04:57:14 +00001720 peeksym = 0;
1721}
1722
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001723static struct op *simple(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001724{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001725 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001726
1727 t = NULL;
1728 for (;;) {
1729 switch (peeksym = yylex(0)) {
1730 case '<':
1731 case '>':
1732 (void) synio(0);
1733 break;
1734
1735 case WORD:
1736 if (t == NULL) {
1737 t = newtp();
1738 t->type = TCOM;
1739 }
1740 peeksym = 0;
1741 word(yylval.cp);
1742 break;
1743
1744 default:
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001745 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001746 }
1747 }
1748}
1749
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001750static struct op *nested(int type, int mark)
Eric Andersenff9eee42001-06-29 04:57:14 +00001751{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001752 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001753
1754 DBGPRINTF3(("NESTED: enter, type=%d, mark=%d\n", type, mark));
Eric Andersenff9eee42001-06-29 04:57:14 +00001755
1756 multiline++;
1757 t = c_list();
1758 musthave(mark, 0);
1759 multiline--;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001760 return block(type, t, NOBLOCK, NOWORDS);
Eric Andersenff9eee42001-06-29 04:57:14 +00001761}
1762
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001763static struct op *command(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001764{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001765 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001766 struct wdblock *iosave;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001767 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001768
1769 DBGPRINTF(("COMMAND: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001770
1771 iosave = iolist;
1772 iolist = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001773
Eric Andersenff9eee42001-06-29 04:57:14 +00001774 if (multiline)
1775 cf |= CONTIN;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001776
Eric Andersenff9eee42001-06-29 04:57:14 +00001777 while (synio(cf))
1778 cf = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001779
1780 c = yylex(cf);
1781
1782 switch (c) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001783 default:
1784 peeksym = c;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001785 t = simple();
1786 if (t == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001787 if (iolist == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001788 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001789 t = newtp();
1790 t->type = TCOM;
1791 }
1792 break;
1793
1794 case '(':
1795 t = nested(TPAREN, ')');
1796 break;
1797
1798 case '{':
1799 t = nested(TBRACE, '}');
1800 break;
1801
1802 case FOR:
1803 t = newtp();
1804 t->type = TFOR;
1805 musthave(WORD, 0);
1806 startl = 1;
1807 t->str = yylval.cp;
1808 multiline++;
1809 t->words = wordlist();
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001810 c = yylex(0);
1811 if (c != '\n' && c != ';')
Eric Andersenff9eee42001-06-29 04:57:14 +00001812 peeksym = c;
1813 t->left = dogroup(0);
1814 multiline--;
1815 break;
1816
1817 case WHILE:
1818 case UNTIL:
1819 multiline++;
1820 t = newtp();
Denis Vlasenko648b44f2008-02-12 06:04:06 +00001821 t->type = (c == WHILE ? TWHILE : TUNTIL);
Eric Andersenff9eee42001-06-29 04:57:14 +00001822 t->left = c_list();
1823 t->right = dogroup(1);
1824 t->words = NULL;
1825 multiline--;
1826 break;
1827
1828 case CASE:
1829 t = newtp();
1830 t->type = TCASE;
1831 musthave(WORD, 0);
1832 t->str = yylval.cp;
1833 startl++;
1834 multiline++;
1835 musthave(IN, CONTIN);
1836 startl++;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001837
Eric Andersenff9eee42001-06-29 04:57:14 +00001838 t->left = caselist();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001839
Eric Andersenff9eee42001-06-29 04:57:14 +00001840 musthave(ESAC, 0);
1841 multiline--;
1842 break;
1843
1844 case IF:
1845 multiline++;
1846 t = newtp();
1847 t->type = TIF;
1848 t->left = c_list();
1849 t->right = thenpart();
1850 musthave(FI, 0);
1851 multiline--;
1852 break;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001853
1854 case DOT:
1855 t = newtp();
1856 t->type = TDOT;
1857
1858 musthave(WORD, 0); /* gets name of file */
1859 DBGPRINTF7(("COMMAND: DOT clause, yylval.cp is %s\n", yylval.cp));
1860
1861 word(yylval.cp); /* add word to wdlist */
1862 word(NOWORD); /* terminate wdlist */
1863 t->words = copyw(); /* dup wdlist */
1864 break;
1865
Eric Andersenff9eee42001-06-29 04:57:14 +00001866 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001867
Eric Andersen8401eea2004-08-04 19:16:54 +00001868 while (synio(0));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001869
Eric Andersenff9eee42001-06-29 04:57:14 +00001870 t = namelist(t);
1871 iolist = iosave;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001872
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001873 DBGPRINTF(("COMMAND: returning %p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001874
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001875 return t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001876}
1877
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001878static struct op *dowholefile(int type, int mark)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001879{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001880 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001881
1882 DBGPRINTF(("DOWHOLEFILE: enter, type=%d, mark=%d\n", type, mark));
1883
1884 multiline++;
1885 t = c_list();
1886 multiline--;
1887 t = block(type, t, NOBLOCK, NOWORDS);
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001888 DBGPRINTF(("DOWHOLEFILE: return t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001889 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001890}
1891
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001892static struct op *dogroup(int onlydone)
Eric Andersenff9eee42001-06-29 04:57:14 +00001893{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001894 int c;
1895 struct op *mylist;
Eric Andersenff9eee42001-06-29 04:57:14 +00001896
1897 c = yylex(CONTIN);
1898 if (c == DONE && onlydone)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001899 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001900 if (c != DO)
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001901 zzerr();
Eric Andersenff9eee42001-06-29 04:57:14 +00001902 mylist = c_list();
1903 musthave(DONE, 0);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001904 return mylist;
Eric Andersenff9eee42001-06-29 04:57:14 +00001905}
1906
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001907static struct op *thenpart(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001908{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001909 int c;
1910 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001911
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001912 c = yylex(0);
1913 if (c != THEN) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001914 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001915 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001916 }
1917 t = newtp();
Denis Vlasenko648b44f2008-02-12 06:04:06 +00001918 /*t->type = 0; - newtp() did this */
Eric Andersenff9eee42001-06-29 04:57:14 +00001919 t->left = c_list();
1920 if (t->left == NULL)
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001921 zzerr();
Eric Andersenff9eee42001-06-29 04:57:14 +00001922 t->right = elsepart();
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001923 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001924}
1925
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001926static struct op *elsepart(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001927{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001928 int c;
1929 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001930
1931 switch (c = yylex(0)) {
1932 case ELSE:
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001933 t = c_list();
1934 if (t == NULL)
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001935 zzerr();
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001936 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001937
1938 case ELIF:
1939 t = newtp();
1940 t->type = TELIF;
1941 t->left = c_list();
1942 t->right = thenpart();
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001943 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001944
1945 default:
1946 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001947 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001948 }
1949}
1950
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001951static struct op *caselist(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001952{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001953 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001954
1955 t = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001956 while ((peeksym = yylex(CONTIN)) != ESAC) {
1957 DBGPRINTF(("CASELIST, doing yylex, peeksym=%d\n", peeksym));
Eric Andersenff9eee42001-06-29 04:57:14 +00001958 t = list(t, casepart());
Eric Andersen12de6cf2004-08-04 19:19:10 +00001959 }
1960
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001961 DBGPRINTF(("CASELIST, returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001962 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001963}
1964
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001965static struct op *casepart(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001966{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001967 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001968
1969 DBGPRINTF7(("CASEPART: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001970
1971 t = newtp();
1972 t->type = TPAT;
1973 t->words = pattern();
1974 musthave(')', 0);
1975 t->left = c_list();
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001976 peeksym = yylex(CONTIN);
1977 if (peeksym != ESAC)
Eric Andersenff9eee42001-06-29 04:57:14 +00001978 musthave(BREAK, CONTIN);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001979
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001980 DBGPRINTF7(("CASEPART: made newtp(TPAT, t=%p)\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001981
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001982 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001983}
1984
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001985static char **pattern(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001986{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001987 int c, cf;
Eric Andersenff9eee42001-06-29 04:57:14 +00001988
1989 cf = CONTIN;
1990 do {
1991 musthave(WORD, cf);
1992 word(yylval.cp);
1993 cf = 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001994 c = yylex(0);
1995 } while (c == '|');
Eric Andersenff9eee42001-06-29 04:57:14 +00001996 peeksym = c;
1997 word(NOWORD);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001998
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001999 return copyw();
Eric Andersenff9eee42001-06-29 04:57:14 +00002000}
2001
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002002static char **wordlist(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002003{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002004 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002005
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002006 c = yylex(0);
2007 if (c != IN) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002008 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002009 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00002010 }
2011 startl = 0;
2012 while ((c = yylex(0)) == WORD)
2013 word(yylval.cp);
2014 word(NOWORD);
2015 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002016 return copyw();
Eric Andersenff9eee42001-06-29 04:57:14 +00002017}
2018
2019/*
2020 * supporting functions
2021 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002022static struct op *list(struct op *t1, struct op *t2)
Eric Andersenff9eee42001-06-29 04:57:14 +00002023{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002024 DBGPRINTF7(("LIST: enter, t1=%p, t2=%p\n", t1, t2));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002025
Eric Andersenff9eee42001-06-29 04:57:14 +00002026 if (t1 == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002027 return t2;
Eric Andersenff9eee42001-06-29 04:57:14 +00002028 if (t2 == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002029 return t1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002030
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002031 return block(TLIST, t1, t2, NOWORDS);
Eric Andersenff9eee42001-06-29 04:57:14 +00002032}
2033
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002034static struct op *block(int type, struct op *t1, struct op *t2, char **wp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002035{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002036 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002037
2038 DBGPRINTF7(("BLOCK: enter, type=%d (%s)\n", type, T_CMD_NAMES[type]));
Eric Andersenff9eee42001-06-29 04:57:14 +00002039
2040 t = newtp();
2041 t->type = type;
2042 t->left = t1;
2043 t->right = t2;
2044 t->words = wp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002045
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002046 DBGPRINTF7(("BLOCK: inserted %p between %p and %p\n", t, t1, t2));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002047
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002048 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002049}
2050
Eric Andersen12de6cf2004-08-04 19:19:10 +00002051/* See if given string is a shell multiline (FOR, IF, etc) */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002052static int rlookup(char *n)
Eric Andersenff9eee42001-06-29 04:57:14 +00002053{
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002054 struct res {
2055 char r_name[6];
2056 int16_t r_val;
2057 };
2058 static const struct res restab[] = {
2059 { "for" , FOR },
2060 { "case" , CASE },
2061 { "esac" , ESAC },
2062 { "while", WHILE },
2063 { "do" , DO },
2064 { "done" , DONE },
2065 { "if" , IF },
2066 { "in" , IN },
2067 { "then" , THEN },
2068 { "else" , ELSE },
2069 { "elif" , ELIF },
2070 { "until", UNTIL },
2071 { "fi" , FI },
2072 { ";;" , BREAK },
2073 { "||" , LOGOR },
2074 { "&&" , LOGAND },
2075 { "{" , '{' },
2076 { "}" , '}' },
2077 { "." , DOT },
2078 { },
2079 };
2080
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002081 const struct res *rp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002082
2083 DBGPRINTF7(("RLOOKUP: enter, n is %s\n", n));
Eric Andersenff9eee42001-06-29 04:57:14 +00002084
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002085 for (rp = restab; rp->r_name[0]; rp++)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002086 if (strcmp(rp->r_name, n) == 0) {
2087 DBGPRINTF7(("RLOOKUP: match, returning %d\n", rp->r_val));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002088 return rp->r_val; /* Return numeric code for shell multiline */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002089 }
2090
2091 DBGPRINTF7(("RLOOKUP: NO match, returning 0\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002092 return 0; /* Not a shell multiline */
Eric Andersenff9eee42001-06-29 04:57:14 +00002093}
2094
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002095static struct op *newtp(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002096{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002097 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002098
Eric Andersen8401eea2004-08-04 19:16:54 +00002099 t = (struct op *) tree(sizeof(*t));
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002100 memset(t, 0, sizeof(*t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002101
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002102 DBGPRINTF3(("NEWTP: allocated %p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002103
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002104 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002105}
2106
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002107static struct op *namelist(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00002108{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002109 DBGPRINTF7(("NAMELIST: enter, t=%p, type %s, iolist=%p\n", t,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002110 T_CMD_NAMES[t->type], iolist));
2111
Eric Andersenff9eee42001-06-29 04:57:14 +00002112 if (iolist) {
Eric Andersen8401eea2004-08-04 19:16:54 +00002113 iolist = addword((char *) NULL, iolist);
Eric Andersenff9eee42001-06-29 04:57:14 +00002114 t->ioact = copyio();
2115 } else
2116 t->ioact = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002117
Eric Andersenff9eee42001-06-29 04:57:14 +00002118 if (t->type != TCOM) {
2119 if (t->type != TPAREN && t->ioact != NULL) {
2120 t = block(TPAREN, t, NOBLOCK, NOWORDS);
2121 t->ioact = t->left->ioact;
2122 t->left->ioact = NULL;
2123 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002124 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002125 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002126
Eric Andersenff9eee42001-06-29 04:57:14 +00002127 word(NOWORD);
2128 t->words = copyw();
Eric Andersen12de6cf2004-08-04 19:19:10 +00002129
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002130 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002131}
2132
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002133static char **copyw(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002134{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002135 char **wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00002136
2137 wd = getwords(wdlist);
2138 wdlist = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002139 return wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00002140}
2141
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002142static void word(char *cp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002143{
2144 wdlist = addword(cp, wdlist);
2145}
2146
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002147static struct ioword **copyio(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002148{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002149 struct ioword **iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002150
2151 iop = (struct ioword **) getwords(iolist);
2152 iolist = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002153 return iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002154}
2155
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002156static struct ioword *io(int u, int f, char *cp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002157{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002158 struct ioword *iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002159
2160 iop = (struct ioword *) tree(sizeof(*iop));
2161 iop->io_unit = u;
2162 iop->io_flag = f;
2163 iop->io_name = cp;
Eric Andersen8401eea2004-08-04 19:16:54 +00002164 iolist = addword((char *) iop, iolist);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002165 return iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002166}
2167
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002168static int yylex(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00002169{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002170 int c, c1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002171 int atstart;
2172
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002173 c = peeksym;
2174 if (c > 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002175 peeksym = 0;
2176 if (c == '\n')
2177 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002178 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002179 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002180
Eric Andersenff9eee42001-06-29 04:57:14 +00002181 nlseen = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002182 atstart = startl;
2183 startl = 0;
2184 yylval.i = 0;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002185 global_env.linep = line;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002186
2187/* MALAMO */
2188 line[LINELIM - 1] = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00002189
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002190 loop:
Eric Andersen12de6cf2004-08-04 19:19:10 +00002191 while ((c = my_getc(0)) == ' ' || c == '\t') /* Skip whitespace */
2192 ;
2193
Eric Andersenff9eee42001-06-29 04:57:14 +00002194 switch (c) {
2195 default:
2196 if (any(c, "0123456789")) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002197 c1 = my_getc(0);
2198 unget(c1);
Eric Andersenff9eee42001-06-29 04:57:14 +00002199 if (c1 == '<' || c1 == '>') {
2200 iounit = c - '0';
2201 goto loop;
2202 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002203 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002204 c = c1;
2205 }
2206 break;
2207
Eric Andersen12de6cf2004-08-04 19:19:10 +00002208 case '#': /* Comment, skip to next newline or End-of-string */
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002209 while ((c = my_getc(0)) != '\0' && c != '\n');
Eric Andersenff9eee42001-06-29 04:57:14 +00002210 unget(c);
2211 goto loop;
2212
2213 case 0:
Eric Andersen12de6cf2004-08-04 19:19:10 +00002214 DBGPRINTF5(("YYLEX: return 0, c=%d\n", c));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002215 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002216
2217 case '$':
Eric Andersen12de6cf2004-08-04 19:19:10 +00002218 DBGPRINTF9(("YYLEX: found $\n"));
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002219 *global_env.linep++ = c;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002220 c = my_getc(0);
2221 if (c == '{') {
2222 c = collect(c, '}');
2223 if (c != '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002224 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002225 goto pack;
2226 }
2227 break;
2228
2229 case '`':
2230 case '\'':
2231 case '"':
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002232 c = collect(c, c);
2233 if (c != '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002234 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002235 goto pack;
2236
2237 case '|':
2238 case '&':
2239 case ';':
Eric Andersenff9eee42001-06-29 04:57:14 +00002240 startl = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002241 /* If more chars process them, else return NULL char */
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002242 c1 = dual(c);
2243 if (c1 != '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002244 return c1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002245 return c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002246
Eric Andersenff9eee42001-06-29 04:57:14 +00002247 case '^':
2248 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002249 return '|';
Eric Andersenff9eee42001-06-29 04:57:14 +00002250 case '>':
2251 case '<':
2252 diag(c);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002253 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002254
2255 case '\n':
2256 nlseen++;
2257 gethere();
2258 startl = 1;
2259 if (multiline || cf & CONTIN) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002260 if (interactive && global_env.iop <= iostack) {
Denis Vlasenko38f63192007-01-22 09:03:07 +00002261#if ENABLE_FEATURE_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00002262 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00002263#else
Eric Andersen8401eea2004-08-04 19:16:54 +00002264 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00002265#endif
2266 }
2267 if (cf & CONTIN)
2268 goto loop;
2269 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002270 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002271
2272 case '(':
2273 case ')':
2274 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002275 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002276 }
2277
2278 unget(c);
2279
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002280 pack:
2281 while ((c = my_getc(0)) != '\0' && !any(c, "`$ '\"\t;&<>()|^\n")) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002282 if (global_env.linep >= elinep)
Eric Andersenff9eee42001-06-29 04:57:14 +00002283 err("word too long");
2284 else
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002285 *global_env.linep++ = c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002286 };
2287
Eric Andersenff9eee42001-06-29 04:57:14 +00002288 unget(c);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002289
Eric Andersen8401eea2004-08-04 19:16:54 +00002290 if (any(c, "\"'`$"))
Eric Andersenff9eee42001-06-29 04:57:14 +00002291 goto loop;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002292
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002293 *global_env.linep++ = '\0';
Eric Andersen12de6cf2004-08-04 19:19:10 +00002294
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002295 if (atstart) {
2296 c = rlookup(line);
2297 if (c != 0) {
2298 startl = 1;
2299 return c;
2300 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002301 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002302
Eric Andersenff9eee42001-06-29 04:57:14 +00002303 yylval.cp = strsave(line, areanum);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002304 return WORD;
Eric Andersenff9eee42001-06-29 04:57:14 +00002305}
2306
Eric Andersen12de6cf2004-08-04 19:19:10 +00002307
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002308static int collect(int c, int c1)
Eric Andersenff9eee42001-06-29 04:57:14 +00002309{
2310 char s[2];
2311
Eric Andersen12de6cf2004-08-04 19:19:10 +00002312 DBGPRINTF8(("COLLECT: enter, c=%d, c1=%d\n", c, c1));
2313
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002314 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002315 while ((c = my_getc(c1)) != c1) {
2316 if (c == 0) {
2317 unget(c);
2318 s[0] = c1;
2319 s[1] = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00002320 prs("no closing ");
2321 yyerror(s);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002322 return YYERRCODE;
Eric Andersenff9eee42001-06-29 04:57:14 +00002323 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002324 if (interactive && c == '\n' && global_env.iop <= iostack) {
Denis Vlasenko38f63192007-01-22 09:03:07 +00002325#if ENABLE_FEATURE_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00002326 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00002327#else
Eric Andersen8401eea2004-08-04 19:16:54 +00002328 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00002329#endif
2330 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002331 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002332 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002333
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002334 *global_env.linep++ = c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002335
2336 DBGPRINTF8(("COLLECT: return 0, line is %s\n", line));
2337
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002338 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002339}
2340
Eric Andersen12de6cf2004-08-04 19:19:10 +00002341/* "multiline commands" helper func */
2342/* see if next 2 chars form a shell multiline */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002343static int dual(int c)
Eric Andersenff9eee42001-06-29 04:57:14 +00002344{
2345 char s[3];
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002346 char *cp = s;
Eric Andersenff9eee42001-06-29 04:57:14 +00002347
Eric Andersen12de6cf2004-08-04 19:19:10 +00002348 DBGPRINTF8(("DUAL: enter, c=%d\n", c));
2349
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002350 *cp++ = c; /* c is the given "peek" char */
2351 *cp++ = my_getc(0); /* get next char of input */
2352 *cp = '\0'; /* add EOS marker */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002353
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002354 c = rlookup(s); /* see if 2 chars form a shell multiline */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002355 if (c == 0)
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002356 unget(*--cp); /* String is not a shell multiline, put peek char back */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002357
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002358 return c; /* String is multiline, return numeric multiline (restab) code */
Eric Andersenff9eee42001-06-29 04:57:14 +00002359}
2360
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002361static void diag(int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00002362{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002363 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002364
2365 DBGPRINTF8(("DIAG: enter, ec=%d\n", ec));
Eric Andersenff9eee42001-06-29 04:57:14 +00002366
2367 c = my_getc(0);
2368 if (c == '>' || c == '<') {
2369 if (c != ec)
2370 zzerr();
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002371 yylval.i = (ec == '>' ? IOWRITE | IOCAT : IOHERE);
Eric Andersenff9eee42001-06-29 04:57:14 +00002372 c = my_getc(0);
2373 } else
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002374 yylval.i = (ec == '>' ? IOWRITE : IOREAD);
Eric Andersenff9eee42001-06-29 04:57:14 +00002375 if (c != '&' || yylval.i == IOHERE)
2376 unget(c);
2377 else
2378 yylval.i |= IODUP;
2379}
2380
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002381static char *tree(unsigned size)
Eric Andersenff9eee42001-06-29 04:57:14 +00002382{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002383 char *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002384
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002385 t = getcell(size);
2386 if (t == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002387 DBGPRINTF2(("TREE: getcell(%d) failed!\n", size));
Eric Andersenff9eee42001-06-29 04:57:14 +00002388 prs("command line too complicated\n");
2389 fail();
2390 /* NOTREACHED */
2391 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002392 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002393}
2394
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002395
Eric Andersenff9eee42001-06-29 04:57:14 +00002396/* VARARGS1 */
2397/* ARGSUSED */
2398
2399/* -------- exec.c -------- */
2400
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002401static struct op **find1case(struct op *t, const char *w)
2402{
2403 struct op *t1;
2404 struct op **tp;
2405 char **wp;
2406 char *cp;
2407
2408 if (t == NULL) {
2409 DBGPRINTF3(("FIND1CASE: enter, t==NULL, returning.\n"));
2410 return NULL;
2411 }
2412
2413 DBGPRINTF3(("FIND1CASE: enter, t->type=%d (%s)\n", t->type,
2414 T_CMD_NAMES[t->type]));
2415
2416 if (t->type == TLIST) {
2417 tp = find1case(t->left, w);
2418 if (tp != NULL) {
2419 DBGPRINTF3(("FIND1CASE: found one to the left, returning tp=%p\n", tp));
2420 return tp;
2421 }
2422 t1 = t->right; /* TPAT */
2423 } else
2424 t1 = t;
2425
2426 for (wp = t1->words; *wp;) {
2427 cp = evalstr(*wp++, DOSUB);
2428 if (cp && gmatch(w, cp)) {
2429 DBGPRINTF3(("FIND1CASE: returning &t1->left= %p.\n",
2430 &t1->left));
2431 return &t1->left;
2432 }
2433 }
2434
2435 DBGPRINTF(("FIND1CASE: returning NULL\n"));
2436 return NULL;
2437}
2438
2439static struct op *findcase(struct op *t, const char *w)
2440{
2441 struct op **tp;
2442
2443 tp = find1case(t, w);
2444 return tp != NULL ? *tp : NULL;
2445}
2446
Eric Andersenff9eee42001-06-29 04:57:14 +00002447/*
2448 * execute tree
2449 */
2450
Denis Vlasenko7e497522008-02-12 09:51:03 +00002451static int execute(struct op *t, int *pin, int *pout, int no_fork)
Eric Andersenff9eee42001-06-29 04:57:14 +00002452{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002453 struct op *t1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002454 volatile int i, rv, a;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002455 const char *cp;
2456 char **wp, **wp2;
Eric Andersenff9eee42001-06-29 04:57:14 +00002457 struct var *vp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002458 struct op *outtree_save;
Eric Andersenff9eee42001-06-29 04:57:14 +00002459 struct brkcon bc;
2460
2461#if __GNUC__
2462 /* Avoid longjmp clobbering */
2463 (void) &wp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002464#endif
Eric Andersenff9eee42001-06-29 04:57:14 +00002465
Eric Andersen12de6cf2004-08-04 19:19:10 +00002466 if (t == NULL) {
2467 DBGPRINTF4(("EXECUTE: enter, t==null, returning.\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002468 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002469 }
2470
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002471 DBGPRINTF(("EXECUTE: t=%p, t->type=%d (%s), t->words is %s\n", t,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002472 t->type, T_CMD_NAMES[t->type],
2473 ((t->words == NULL) ? "NULL" : t->words[0])));
2474
Eric Andersenff9eee42001-06-29 04:57:14 +00002475 rv = 0;
2476 a = areanum++;
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002477 wp2 = t->words;
2478 wp = (wp2 != NULL)
Eric Andersen8401eea2004-08-04 19:16:54 +00002479 ? eval(wp2, t->type == TCOM ? DOALL : DOALL & ~DOKEY)
2480 : NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00002481
Eric Andersen8401eea2004-08-04 19:16:54 +00002482 switch (t->type) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002483 case TDOT:
2484 DBGPRINTF3(("EXECUTE: TDOT\n"));
2485
2486 outtree_save = outtree;
2487
2488 newfile(evalstr(t->words[0], DOALL));
2489
2490 t->left = dowholefile(TLIST, 0);
2491 t->right = NULL;
2492
2493 outtree = outtree_save;
2494
2495 if (t->left)
Denis Vlasenko7e497522008-02-12 09:51:03 +00002496 rv = execute(t->left, pin, pout, /* no_fork: */ 0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002497 if (t->right)
Denis Vlasenko7e497522008-02-12 09:51:03 +00002498 rv = execute(t->right, pin, pout, /* no_fork: */ 0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002499 break;
2500
Eric Andersenff9eee42001-06-29 04:57:14 +00002501 case TPAREN:
Denis Vlasenko7e497522008-02-12 09:51:03 +00002502 rv = execute(t->left, pin, pout, /* no_fork: */ 0);
Eric Andersen737f5fb2003-03-14 16:05:59 +00002503 break;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002504
Eric Andersenff9eee42001-06-29 04:57:14 +00002505 case TCOM:
Denis Vlasenko7e497522008-02-12 09:51:03 +00002506 rv = forkexec(t, pin, pout, no_fork, wp);
Eric Andersenff9eee42001-06-29 04:57:14 +00002507 break;
2508
2509 case TPIPE:
2510 {
Eric Andersen8401eea2004-08-04 19:16:54 +00002511 int pv[2];
2512
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002513 rv = openpipe(pv);
2514 if (rv < 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00002515 break;
2516 pv[0] = remap(pv[0]);
2517 pv[1] = remap(pv[1]);
Denis Vlasenko7e497522008-02-12 09:51:03 +00002518 (void) execute(t->left, pin, pv, /* no_fork: */ 0);
2519 rv = execute(t->right, pv, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002520 }
2521 break;
2522
2523 case TLIST:
Denis Vlasenko7e497522008-02-12 09:51:03 +00002524 (void) execute(t->left, pin, pout, /* no_fork: */ 0);
2525 rv = execute(t->right, pin, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002526 break;
2527
2528 case TASYNC:
Eric Andersen8401eea2004-08-04 19:16:54 +00002529 {
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002530 smallint hinteractive = interactive;
Eric Andersenff9eee42001-06-29 04:57:14 +00002531
Eric Andersen12de6cf2004-08-04 19:19:10 +00002532 DBGPRINTF7(("EXECUTE: TASYNC clause, calling vfork()...\n"));
2533
Eric Andersen8401eea2004-08-04 19:16:54 +00002534 i = vfork();
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002535 if (i == 0) { /* child */
Eric Andersen8401eea2004-08-04 19:16:54 +00002536 signal(SIGINT, SIG_IGN);
2537 signal(SIGQUIT, SIG_IGN);
2538 if (interactive)
2539 signal(SIGTERM, SIG_DFL);
2540 interactive = 0;
2541 if (pin == NULL) {
2542 close(0);
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00002543 xopen(bb_dev_null, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00002544 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002545 _exit(execute(t->left, pin, pout, /* no_fork: */ 1));
Eric Andersenff9eee42001-06-29 04:57:14 +00002546 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002547 interactive = hinteractive;
2548 if (i != -1) {
2549 setval(lookup("!"), putn(i));
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002550 closepipe(pin);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002551 if (interactive) {
2552 prs(putn(i));
2553 prs("\n");
2554 }
2555 } else
2556 rv = -1;
2557 setstatus(rv);
Eric Andersenff9eee42001-06-29 04:57:14 +00002558 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002559 break;
2560
2561 case TOR:
2562 case TAND:
Denis Vlasenko7e497522008-02-12 09:51:03 +00002563 rv = execute(t->left, pin, pout, /* no_fork: */ 0);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002564 t1 = t->right;
2565 if (t1 != NULL && (rv == 0) == (t->type == TAND))
Denis Vlasenko7e497522008-02-12 09:51:03 +00002566 rv = execute(t1, pin, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002567 break;
2568
2569 case TFOR:
2570 if (wp == NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00002571 wp = dolv + 1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002572 i = dolc;
2573 if (i < 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00002574 i = 0;
2575 } else {
2576 i = -1;
Eric Andersen8401eea2004-08-04 19:16:54 +00002577 while (*wp++ != NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00002578 }
2579 vp = lookup(t->str);
2580 while (setjmp(bc.brkpt))
2581 if (isbreak)
2582 goto broken;
2583 brkset(&bc);
2584 for (t1 = t->left; i-- && *wp != NULL;) {
2585 setval(vp, *wp++);
Denis Vlasenko7e497522008-02-12 09:51:03 +00002586 rv = execute(t1, pin, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002587 }
2588 brklist = brklist->nextlev;
2589 break;
2590
2591 case TWHILE:
2592 case TUNTIL:
2593 while (setjmp(bc.brkpt))
2594 if (isbreak)
2595 goto broken;
2596 brkset(&bc);
2597 t1 = t->left;
Denis Vlasenko7e497522008-02-12 09:51:03 +00002598 while ((execute(t1, pin, pout, /* no_fork: */ 0) == 0) == (t->type == TWHILE))
2599 rv = execute(t->right, pin, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002600 brklist = brklist->nextlev;
2601 break;
2602
2603 case TIF:
2604 case TELIF:
Eric Andersen8401eea2004-08-04 19:16:54 +00002605 if (t->right != NULL) {
Denis Vlasenko7e497522008-02-12 09:51:03 +00002606 rv = !execute(t->left, pin, pout, /* no_fork: */ 0) ?
2607 execute(t->right->left, pin, pout, /* no_fork: */ 0) :
2608 execute(t->right->right, pin, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002609 }
2610 break;
2611
2612 case TCASE:
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002613 cp = evalstr(t->str, DOSUB | DOTRIM);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002614 if (cp == NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00002615 cp = "";
Eric Andersen12de6cf2004-08-04 19:19:10 +00002616
2617 DBGPRINTF7(("EXECUTE: TCASE, t->str is %s, cp is %s\n",
2618 ((t->str == NULL) ? "NULL" : t->str),
2619 ((cp == NULL) ? "NULL" : cp)));
2620
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002621 t1 = findcase(t->left, cp);
2622 if (t1 != NULL) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002623 DBGPRINTF7(("EXECUTE: TCASE, calling execute(t=%p, t1=%p)...\n", t, t1));
Denis Vlasenko7e497522008-02-12 09:51:03 +00002624 rv = execute(t1, pin, pout, /* no_fork: */ 0);
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002625 DBGPRINTF7(("EXECUTE: TCASE, back from execute(t=%p, t1=%p)...\n", t, t1));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002626 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002627 break;
2628
2629 case TBRACE:
2630/*
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002631 iopp = t->ioact;
2632 if (i)
Eric Andersenff9eee42001-06-29 04:57:14 +00002633 while (*iopp)
2634 if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) {
2635 rv = -1;
2636 break;
2637 }
2638*/
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002639 if (rv >= 0) {
2640 t1 = t->left;
2641 if (t1) {
Denis Vlasenko7e497522008-02-12 09:51:03 +00002642 rv = execute(t1, pin, pout, /* no_fork: */ 0);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002643 }
2644 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002645 break;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002646
2647 };
Eric Andersenff9eee42001-06-29 04:57:14 +00002648
Denis Vlasenkoe4712752007-04-14 15:08:41 +00002649 broken:
Eric Andersenff9eee42001-06-29 04:57:14 +00002650 t->words = wp2;
2651 isbreak = 0;
2652 freehere(areanum);
2653 freearea(areanum);
2654 areanum = a;
2655 if (interactive && intr) {
2656 closeall();
2657 fail();
2658 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002659
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002660 i = trapset;
2661 if (i != 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002662 trapset = 0;
2663 runtrap(i);
2664 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002665
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002666 DBGPRINTF(("EXECUTE: returning from t=%p, rv=%d\n", t, rv));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002667 return rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00002668}
2669
Denis Vlasenkoe4712752007-04-14 15:08:41 +00002670static builtin_func_ptr inbuilt(const char *s)
2671{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002672 const struct builtincmd *bp;
2673
Denis Vlasenko95cb3262007-04-09 03:06:34 +00002674 for (bp = builtincmds; bp->name; bp++)
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002675 if (strcmp(bp->name, s) == 0)
2676 return bp->builtinfunc;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002677 return NULL;
2678}
2679
Denis Vlasenko7e497522008-02-12 09:51:03 +00002680static int forkexec(struct op *t, int *pin, int *pout, int no_fork, char **wp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002681{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002682 pid_t newpid;
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002683 int i;
2684 builtin_func_ptr bltin = NULL;
Denis Vlasenko7e497522008-02-12 09:51:03 +00002685 const char *bltin_name = NULL;
2686 const char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00002687 struct ioword **iopp;
2688 int resetsig;
2689 char **owp;
Denis Vlasenko7e497522008-02-12 09:51:03 +00002690 int forked;
Eric Andersenff9eee42001-06-29 04:57:14 +00002691
2692 int *hpin = pin;
2693 int *hpout = pout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002694 char *hwp;
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002695 smallint hinteractive;
2696 smallint hintr;
2697 smallint hexecflg;
Eric Andersen8401eea2004-08-04 19:16:54 +00002698 struct brkcon *hbrklist;
Eric Andersenff9eee42001-06-29 04:57:14 +00002699
2700#if __GNUC__
2701 /* Avoid longjmp clobbering */
2702 (void) &pin;
2703 (void) &pout;
2704 (void) &wp;
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002705 (void) &bltin;
Eric Andersenff9eee42001-06-29 04:57:14 +00002706 (void) &cp;
2707 (void) &resetsig;
2708 (void) &owp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002709#endif
Eric Andersenff9eee42001-06-29 04:57:14 +00002710
Denis Vlasenko7e497522008-02-12 09:51:03 +00002711 DBGPRINTF(("FORKEXEC: t=%p, pin %p, pout %p, no_fork %d\n", t, pin,
2712 pout, no_fork));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002713 DBGPRINTF7(("FORKEXEC: t->words is %s\n",
Denis Vlasenko7e497522008-02-12 09:51:03 +00002714 ((t->words == NULL) ? "NULL" : t->words[0])));
Eric Andersenff9eee42001-06-29 04:57:14 +00002715 owp = wp;
2716 resetsig = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002717 if (t->type == TCOM) {
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00002718 while (*wp++ != NULL)
2719 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00002720 cp = *wp;
2721
2722 /* strip all initial assignments */
Denis Vlasenko7e497522008-02-12 09:51:03 +00002723 /* FIXME: not correct wrt PATH=yyy command etc */
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00002724 if (FLAG['x']) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002725 DBGPRINTF9(("FORKEXEC: echo'ing, cp=%p, wp=%p, owp=%p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00002726 cp, wp, owp));
Eric Andersen8401eea2004-08-04 19:16:54 +00002727 echo(cp ? wp : owp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002728 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002729
Denis Vlasenko7e497522008-02-12 09:51:03 +00002730 if (cp == NULL) {
2731 if (t->ioact == NULL) {
2732 while ((cp = *owp++) != NULL && assign(cp, COPYV))
2733 continue;
2734 DBGPRINTF(("FORKEXEC: returning setstatus(0)\n"));
2735 return setstatus(0);
2736 }
2737 } else { /* cp != NULL */
2738 bltin_name = cp;
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002739 bltin = inbuilt(cp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002740 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002741 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002742
Denis Vlasenko7e497522008-02-12 09:51:03 +00002743 forked = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002744 t->words = wp;
Denis Vlasenko7e497522008-02-12 09:51:03 +00002745 DBGPRINTF(("FORKEXEC: bltin %p, no_fork %d, owp %p\n", bltin,
2746 no_fork, owp));
2747 /* Don't fork if it is a lone builtin (not in pipe)
2748 * OR we are told to _not_ fork */
2749 if ((!bltin || pin || pout) /* not lone bltin AND */
2750 && !no_fork /* not told to avoid fork */
2751 ) {
2752 /* Save values in case child alters them after vfork */
Eric Andersenff9eee42001-06-29 04:57:14 +00002753 hpin = pin;
2754 hpout = pout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002755 hwp = *wp;
2756 hinteractive = interactive;
2757 hintr = intr;
2758 hbrklist = brklist;
2759 hexecflg = execflg;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002760
Eric Andersen12de6cf2004-08-04 19:19:10 +00002761 DBGPRINTF3(("FORKEXEC: calling vfork()...\n"));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002762 newpid = vfork();
Eric Andersen12de6cf2004-08-04 19:19:10 +00002763 if (newpid == -1) {
Denis Vlasenko89f0b342006-11-18 22:04:09 +00002764 DBGPRINTF(("FORKEXEC: ERROR, cannot vfork()!\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002765 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002766 }
2767
Denis Vlasenko489f93e2007-02-01 01:43:16 +00002768 if (newpid > 0) { /* Parent */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002769 /* Restore values */
Eric Andersenff9eee42001-06-29 04:57:14 +00002770 pin = hpin;
2771 pout = hpout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002772 *wp = hwp;
2773 interactive = hinteractive;
2774 intr = hintr;
2775 brklist = hbrklist;
2776 execflg = hexecflg;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002777
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002778 closepipe(pin);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002779 return (pout == NULL ? setstatus(waitfor(newpid, 0)) : 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002780 }
2781
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002782 /* Child */
Denis Vlasenko7e497522008-02-12 09:51:03 +00002783 DBGPRINTF(("FORKEXEC: child process, bltin=%p (%s)\n", bltin, bltin_name));
Eric Andersenff9eee42001-06-29 04:57:14 +00002784 if (interactive) {
2785 signal(SIGINT, SIG_IGN);
2786 signal(SIGQUIT, SIG_IGN);
2787 resetsig = 1;
2788 }
2789 interactive = 0;
2790 intr = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002791 forked = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002792 brklist = 0;
2793 execflg = 0;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002794 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002795
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002796 if (owp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002797 while ((cp = *owp++) != NULL && assign(cp, COPYV))
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002798 if (!bltin)
Eric Andersenff9eee42001-06-29 04:57:14 +00002799 export(lookup(cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002800
Denis Vlasenko284d0fa2008-02-16 13:18:17 +00002801 if (pin) { /* NB: close _first_, then move fds! */
2802 close(pin[1]);
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00002803 xmove_fd(pin[0], 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002804 }
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002805 if (pout) {
Denis Vlasenko284d0fa2008-02-16 13:18:17 +00002806 close(pout[0]);
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00002807 xmove_fd(pout[1], 1);
Eric Andersenff9eee42001-06-29 04:57:14 +00002808 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002809
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002810 iopp = t->ioact;
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002811 if (iopp) {
2812 if (bltin && bltin != doexec) {
Denis Vlasenko7e497522008-02-12 09:51:03 +00002813 prs(bltin_name);
Eric Andersenff9eee42001-06-29 04:57:14 +00002814 err(": cannot redirect shell command");
Eric Andersen12de6cf2004-08-04 19:19:10 +00002815 if (forked)
2816 _exit(-1);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002817 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002818 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002819 while (*iopp) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002820 if (iosetup(*iopp++, pin != NULL, pout != NULL)) {
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002821 /* system-detected error */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002822 if (forked)
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002823 _exit(-1);
2824 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002825 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002826 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002827 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002828
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002829 if (bltin) {
Denis Vlasenko7e497522008-02-12 09:51:03 +00002830 if (forked || pin || pout) {
2831 /* Builtin in pipe: disallowed */
2832 /* TODO: allow "exec"? */
2833 prs(bltin_name);
2834 err(": cannot run builtin as part of pipe");
2835 if (forked)
2836 _exit(-1);
2837 return -1;
2838 }
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002839 i = setstatus(bltin(t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002840 if (forked)
2841 _exit(i);
2842 DBGPRINTF(("FORKEXEC: returning i=%d\n", i));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002843 return i;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002844 }
2845
Eric Andersenff9eee42001-06-29 04:57:14 +00002846 /* should use FIOCEXCL */
Eric Andersen8401eea2004-08-04 19:16:54 +00002847 for (i = FDBASE; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00002848 close(i);
2849 if (resetsig) {
2850 signal(SIGINT, SIG_DFL);
2851 signal(SIGQUIT, SIG_DFL);
2852 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002853
Eric Andersen12de6cf2004-08-04 19:19:10 +00002854 if (t->type == TPAREN)
Denis Vlasenko7e497522008-02-12 09:51:03 +00002855 _exit(execute(t->left, NOPIPE, NOPIPE, /* no_fork: */ 1));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002856 if (wp[0] == NULL)
2857 _exit(0);
2858
Eric Andersenfd7a4c82004-09-02 23:13:10 +00002859 cp = rexecve(wp[0], wp, makenv(0, NULL));
Eric Andersen8401eea2004-08-04 19:16:54 +00002860 prs(wp[0]);
2861 prs(": ");
Eric Andersen12de6cf2004-08-04 19:19:10 +00002862 err(cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00002863 if (!execflg)
2864 trap[0] = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002865
Denis Vlasenko7e497522008-02-12 09:51:03 +00002866 DBGPRINTF(("FORKEXEC: calling leave(), pid=%d\n", getpid()));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002867
Eric Andersenff9eee42001-06-29 04:57:14 +00002868 leave();
2869 /* NOTREACHED */
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002870 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002871}
2872
2873/*
2874 * 0< 1> are ignored as required
2875 * within pipelines.
2876 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002877static int iosetup(struct ioword *iop, int pipein, int pipeout)
Eric Andersenff9eee42001-06-29 04:57:14 +00002878{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002879 int u = -1;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002880 char *cp = NULL;
2881 const char *msg;
Eric Andersenff9eee42001-06-29 04:57:14 +00002882
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002883 DBGPRINTF(("IOSETUP: iop %p, pipein %i, pipeout %i\n", iop,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002884 pipein, pipeout));
2885
Eric Andersenff9eee42001-06-29 04:57:14 +00002886 if (iop->io_unit == IODEFAULT) /* take default */
Eric Andersen8401eea2004-08-04 19:16:54 +00002887 iop->io_unit = iop->io_flag & (IOREAD | IOHERE) ? 0 : 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002888
Eric Andersenff9eee42001-06-29 04:57:14 +00002889 if (pipein && iop->io_unit == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002890 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002891
Eric Andersenff9eee42001-06-29 04:57:14 +00002892 if (pipeout && iop->io_unit == 1)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002893 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002894
Eric Andersen8401eea2004-08-04 19:16:54 +00002895 msg = iop->io_flag & (IOREAD | IOHERE) ? "open" : "create";
Eric Andersenff9eee42001-06-29 04:57:14 +00002896 if ((iop->io_flag & IOHERE) == 0) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002897 cp = iop->io_name; /* huh?? */
2898 cp = evalstr(cp, DOSUB | DOTRIM);
2899 if (cp == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002900 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002901 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002902
Eric Andersenff9eee42001-06-29 04:57:14 +00002903 if (iop->io_flag & IODUP) {
2904 if (cp[1] || (!isdigit(*cp) && *cp != '-')) {
2905 prs(cp);
2906 err(": illegal >& argument");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002907 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002908 }
2909 if (*cp == '-')
2910 iop->io_flag = IOCLOSE;
Eric Andersen8401eea2004-08-04 19:16:54 +00002911 iop->io_flag &= ~(IOREAD | IOWRITE);
Eric Andersenff9eee42001-06-29 04:57:14 +00002912 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002913
Eric Andersenff9eee42001-06-29 04:57:14 +00002914 switch (iop->io_flag) {
2915 case IOREAD:
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00002916 u = open(cp, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00002917 break;
2918
2919 case IOHERE:
Eric Andersen8401eea2004-08-04 19:16:54 +00002920 case IOHERE | IOXHERE:
2921 u = herein(iop->io_name, iop->io_flag & IOXHERE);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002922 cp = (char*)"here file";
Eric Andersenff9eee42001-06-29 04:57:14 +00002923 break;
2924
Eric Andersen8401eea2004-08-04 19:16:54 +00002925 case IOWRITE | IOCAT:
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00002926 u = open(cp, O_WRONLY);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002927 if (u >= 0) {
Denis Vlasenkoea620772006-10-14 02:23:43 +00002928 lseek(u, (long) 0, SEEK_END);
Eric Andersenff9eee42001-06-29 04:57:14 +00002929 break;
2930 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002931 /* fall through to creation if >>file doesn't exist */
2932
Eric Andersenff9eee42001-06-29 04:57:14 +00002933 case IOWRITE:
2934 u = creat(cp, 0666);
2935 break;
2936
2937 case IODUP:
Eric Andersen8401eea2004-08-04 19:16:54 +00002938 u = dup2(*cp - '0', iop->io_unit);
Eric Andersenff9eee42001-06-29 04:57:14 +00002939 break;
2940
2941 case IOCLOSE:
2942 close(iop->io_unit);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002943 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002944 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002945
Eric Andersenff9eee42001-06-29 04:57:14 +00002946 if (u < 0) {
2947 prs(cp);
2948 prs(": cannot ");
2949 warn(msg);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002950 return 1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002951 }
2952 if (u != iop->io_unit) {
2953 dup2(u, iop->io_unit);
2954 close(u);
Eric Andersenff9eee42001-06-29 04:57:14 +00002955 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002956 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002957}
2958
Eric Andersenff9eee42001-06-29 04:57:14 +00002959/*
2960 * Enter a new loop level (marked for break/continue).
2961 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002962static void brkset(struct brkcon *bc)
Eric Andersenff9eee42001-06-29 04:57:14 +00002963{
2964 bc->nextlev = brklist;
2965 brklist = bc;
2966}
2967
2968/*
2969 * Wait for the last process created.
2970 * Print a message for each process found
2971 * that was killed by a signal.
2972 * Ignore interrupt signals while waiting
2973 * unless `canintr' is true.
2974 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002975static int waitfor(int lastpid, int canintr)
Eric Andersenff9eee42001-06-29 04:57:14 +00002976{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002977 int pid, rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00002978 int s;
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002979 smallint oheedint = heedint;
Eric Andersenff9eee42001-06-29 04:57:14 +00002980
2981 heedint = 0;
2982 rv = 0;
2983 do {
2984 pid = wait(&s);
2985 if (pid == -1) {
2986 if (errno != EINTR || canintr)
2987 break;
2988 } else {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002989 rv = WAITSIG(s);
2990 if (rv != 0) {
Denis Vlasenko80b8b392007-06-25 10:55:35 +00002991 if (rv < ARRAY_SIZE(signame)) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002992 if (signame[rv] != NULL) {
2993 if (pid != lastpid) {
2994 prn(pid);
2995 prs(": ");
2996 }
2997 prs(signame[rv]);
2998 }
2999 } else {
3000 if (pid != lastpid) {
3001 prn(pid);
3002 prs(": ");
3003 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003004 prs("Signal ");
3005 prn(rv);
3006 prs(" ");
Eric Andersenff9eee42001-06-29 04:57:14 +00003007 }
3008 if (WAITCORE(s))
3009 prs(" - core dumped");
Denis Vlasenko80b8b392007-06-25 10:55:35 +00003010 if (rv >= ARRAY_SIZE(signame) || signame[rv])
Eric Andersenff9eee42001-06-29 04:57:14 +00003011 prs("\n");
3012 rv = -1;
3013 } else
3014 rv = WAITVAL(s);
3015 }
3016 } while (pid != lastpid);
3017 heedint = oheedint;
3018 if (intr) {
3019 if (interactive) {
3020 if (canintr)
3021 intr = 0;
3022 } else {
Eric Andersen8401eea2004-08-04 19:16:54 +00003023 if (exstat == 0)
3024 exstat = rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003025 onintr(0);
3026 }
3027 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003028 return rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003029}
3030
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003031static int setstatus(int s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003032{
3033 exstat = s;
3034 setval(lookup("?"), putn(s));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003035 return s;
Eric Andersenff9eee42001-06-29 04:57:14 +00003036}
3037
3038/*
3039 * PATH-searching interface to execve.
3040 * If getenv("PATH") were kept up-to-date,
3041 * execvp might be used.
3042 */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003043static const char *rexecve(char *c, char **v, char **envp)
Eric Andersenff9eee42001-06-29 04:57:14 +00003044{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003045 int i;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003046 const char *sp;
3047 char *tp;
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00003048 int asis = 0;
Eric Andersen1c039232001-07-07 00:05:55 +00003049 char *name = c;
Eric Andersen8401eea2004-08-04 19:16:54 +00003050
Denis Vlasenko80d14be2007-04-10 23:03:30 +00003051 if (ENABLE_FEATURE_SH_STANDALONE) {
Denis Vlasenko1aa7e472007-11-28 06:49:03 +00003052 if (find_applet_by_name(name) >= 0) {
Rob Landleya299efb2006-08-10 21:46:43 +00003053 /* We have to exec here since we vforked. Running
Denis Vlasenkoe4f2d062007-04-11 17:03:19 +00003054 * run_applet_and_exit() won't work and bad things
Rob Landleya299efb2006-08-10 21:46:43 +00003055 * will happen. */
Denis Vlasenkobdbbb7e2007-06-08 15:02:55 +00003056 execve(bb_busybox_exec_path, v, envp);
Rob Landleya299efb2006-08-10 21:46:43 +00003057 }
Eric Andersen1c039232001-07-07 00:05:55 +00003058 }
Eric Andersen1c039232001-07-07 00:05:55 +00003059
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003060 DBGPRINTF(("REXECVE: c=%p, v=%p, envp=%p\n", c, v, envp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003061
Eric Andersen8401eea2004-08-04 19:16:54 +00003062 sp = any('/', c) ? "" : path->value;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003063 asis = (*sp == '\0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003064 while (asis || *sp != '\0') {
3065 asis = 0;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003066 tp = global_env.linep;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003067 for (; *sp != '\0'; tp++) {
3068 *tp = *sp++;
3069 if (*tp == ':') {
3070 asis = (*sp == '\0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003071 break;
3072 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003073 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003074 if (tp != global_env.linep)
Eric Andersenff9eee42001-06-29 04:57:14 +00003075 *tp++ = '/';
Eric Andersen8401eea2004-08-04 19:16:54 +00003076 for (i = 0; (*tp++ = c[i++]) != '\0';);
Eric Andersen1c039232001-07-07 00:05:55 +00003077
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003078 DBGPRINTF3(("REXECVE: global_env.linep is %s\n", global_env.linep));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003079
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003080 execve(global_env.linep, v, envp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003081
Eric Andersenff9eee42001-06-29 04:57:14 +00003082 switch (errno) {
3083 case ENOEXEC:
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003084 *v = global_env.linep;
Eric Andersenff9eee42001-06-29 04:57:14 +00003085 tp = *--v;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003086 *v = global_env.linep;
Glenn L McGrathdc4e75e2003-09-02 02:36:18 +00003087 execve(DEFAULT_SHELL, v, envp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003088 *v = tp;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003089 return "no Shell";
Eric Andersenff9eee42001-06-29 04:57:14 +00003090
3091 case ENOMEM:
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003092 return (char *) bb_msg_memory_exhausted;
Eric Andersenff9eee42001-06-29 04:57:14 +00003093
3094 case E2BIG:
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003095 return "argument list too long";
Eric Andersenff9eee42001-06-29 04:57:14 +00003096 }
3097 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003098 return errno == ENOENT ? "not found" : "cannot execute";
Eric Andersenff9eee42001-06-29 04:57:14 +00003099}
3100
3101/*
3102 * Run the command produced by generator `f'
3103 * applied to stream `arg'.
3104 */
Eric Andersen8401eea2004-08-04 19:16:54 +00003105static int run(struct ioarg *argp, int (*f) (struct ioarg *))
Eric Andersenff9eee42001-06-29 04:57:14 +00003106{
3107 struct op *otree;
3108 struct wdblock *swdlist;
3109 struct wdblock *siolist;
3110 jmp_buf ev, rt;
3111 xint *ofail;
3112 int rv;
3113
3114#if __GNUC__
3115 /* Avoid longjmp clobbering */
3116 (void) &rv;
3117#endif
3118
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003119 DBGPRINTF(("RUN: enter, areanum %d, outtree %p, failpt %p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00003120 areanum, outtree, failpt));
3121
Eric Andersenff9eee42001-06-29 04:57:14 +00003122 areanum++;
3123 swdlist = wdlist;
3124 siolist = iolist;
3125 otree = outtree;
3126 ofail = failpt;
3127 rv = -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003128
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003129 errpt = ev;
3130 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003131 wdlist = 0;
3132 iolist = 0;
3133 pushio(argp, f);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003134 global_env.iobase = global_env.iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00003135 yynerrs = 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003136 failpt = rt;
3137 if (setjmp(failpt) == 0 && yyparse() == 0)
Denis Vlasenko7e497522008-02-12 09:51:03 +00003138 rv = execute(outtree, NOPIPE, NOPIPE, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003139 quitenv();
Eric Andersen12de6cf2004-08-04 19:19:10 +00003140 } else {
3141 DBGPRINTF(("RUN: error from newenv()!\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00003142 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00003143
Eric Andersenff9eee42001-06-29 04:57:14 +00003144 wdlist = swdlist;
3145 iolist = siolist;
3146 failpt = ofail;
3147 outtree = otree;
3148 freearea(areanum--);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003149
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003150 return rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003151}
3152
3153/* -------- do.c -------- */
3154
3155/*
3156 * built-in commands: doX
3157 */
3158
Eric Andersen8401eea2004-08-04 19:16:54 +00003159static int dohelp(struct op *t)
Eric Andersen1c039232001-07-07 00:05:55 +00003160{
3161 int col;
3162 const struct builtincmd *x;
3163
Denis Vlasenko0ee39992006-12-24 15:23:28 +00003164 puts("\nBuilt-in commands:\n"
3165 "-------------------");
Eric Andersen1c039232001-07-07 00:05:55 +00003166
Denis Vlasenko95cb3262007-04-09 03:06:34 +00003167 col = 0;
3168 x = builtincmds;
3169 while (x->name) {
3170 col += printf("%c%s", ((col == 0) ? '\t' : ' '), x->name);
Eric Andersen1c039232001-07-07 00:05:55 +00003171 if (col > 60) {
Denis Vlasenko4daad902007-09-27 10:20:47 +00003172 bb_putchar('\n');
Eric Andersen1c039232001-07-07 00:05:55 +00003173 col = 0;
3174 }
Denis Vlasenko95cb3262007-04-09 03:06:34 +00003175 x++;
Eric Andersen1c039232001-07-07 00:05:55 +00003176 }
Denis Vlasenko80d14be2007-04-10 23:03:30 +00003177#if ENABLE_FEATURE_SH_STANDALONE
Eric Andersen1c039232001-07-07 00:05:55 +00003178 {
Denis Vlasenko1aa7e472007-11-28 06:49:03 +00003179 const char *applet = applet_names;
Eric Andersen1c039232001-07-07 00:05:55 +00003180
Denis Vlasenko1aa7e472007-11-28 06:49:03 +00003181 while (*applet) {
3182 col += printf("%c%s", ((col == 0) ? '\t' : ' '), applet);
Eric Andersen1c039232001-07-07 00:05:55 +00003183 if (col > 60) {
Denis Vlasenko4daad902007-09-27 10:20:47 +00003184 bb_putchar('\n');
Eric Andersen1c039232001-07-07 00:05:55 +00003185 col = 0;
3186 }
Denis Vlasenko1aa7e472007-11-28 06:49:03 +00003187 applet += strlen(applet) + 1;
Eric Andersen1c039232001-07-07 00:05:55 +00003188 }
3189 }
3190#endif
Denis Vlasenko0ee39992006-12-24 15:23:28 +00003191 puts("\n");
Eric Andersen1c039232001-07-07 00:05:55 +00003192 return EXIT_SUCCESS;
3193}
3194
Eric Andersen8401eea2004-08-04 19:16:54 +00003195static int dolabel(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003196{
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003197 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003198}
3199
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003200static int dochdir(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003201{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003202 const char *cp, *er;
Eric Andersenff9eee42001-06-29 04:57:14 +00003203
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003204 cp = t->words[1];
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003205 if (cp == NULL) {
3206 cp = homedir->value;
Denis Vlasenkod244c5e2007-02-09 17:30:14 +00003207 if (cp != NULL)
3208 goto do_cd;
3209 er = ": no home directory";
3210 } else {
3211 do_cd:
3212 if (chdir(cp) >= 0)
3213 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003214 er = ": bad directory";
Denis Vlasenkod244c5e2007-02-09 17:30:14 +00003215 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003216 prs(cp != NULL ? cp : "cd");
Eric Andersenff9eee42001-06-29 04:57:14 +00003217 err(er);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003218 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003219}
3220
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003221static int doshift(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003222{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003223 int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003224
Eric Andersen8401eea2004-08-04 19:16:54 +00003225 n = t->words[1] ? getn(t->words[1]) : 1;
3226 if (dolc < n) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003227 err("nothing to shift");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003228 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003229 }
3230 dolv[n] = dolv[0];
3231 dolv += n;
3232 dolc -= n;
3233 setval(lookup("#"), putn(dolc));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003234 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003235}
3236
3237/*
3238 * execute login and newgrp directly
3239 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003240static int dologin(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003241{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003242 const char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003243
3244 if (interactive) {
3245 signal(SIGINT, SIG_DFL);
3246 signal(SIGQUIT, SIG_DFL);
3247 }
Eric Andersenfd7a4c82004-09-02 23:13:10 +00003248 cp = rexecve(t->words[0], t->words, makenv(0, NULL));
Eric Andersen8401eea2004-08-04 19:16:54 +00003249 prs(t->words[0]);
3250 prs(": ");
3251 err(cp);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003252 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003253}
3254
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003255static int doumask(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003256{
Denis Vlasenko7e497522008-02-12 09:51:03 +00003257 int i;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003258 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003259
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003260 cp = t->words[1];
3261 if (cp == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003262 i = umask(0);
3263 umask(i);
Denis Vlasenko7e497522008-02-12 09:51:03 +00003264 printf("%04o\n", i);
Eric Andersenff9eee42001-06-29 04:57:14 +00003265 } else {
Denis Vlasenko7e497522008-02-12 09:51:03 +00003266 i = bb_strtou(cp, NULL, 8);
3267 if (errno) {
3268 err("umask: bad octal number");
3269 return 1;
3270 }
3271 umask(i);
Eric Andersenff9eee42001-06-29 04:57:14 +00003272 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003273 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003274}
3275
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003276static int doexec(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003277{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003278 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00003279 jmp_buf ex;
3280 xint *ofail;
3281
3282 t->ioact = NULL;
Denis Vlasenko7e497522008-02-12 09:51:03 +00003283 for (i = 0; (t->words[i] = t->words[i + 1]) != NULL; i++)
3284 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00003285 if (i == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003286 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003287 execflg = 1;
3288 ofail = failpt;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003289 failpt = ex;
3290 if (setjmp(failpt) == 0)
Denis Vlasenko7e497522008-02-12 09:51:03 +00003291 execute(t, NOPIPE, NOPIPE, /* no_fork: */ 1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003292 failpt = ofail;
3293 execflg = 0;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003294 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003295}
3296
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003297static int dodot(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003298{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003299 int i;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003300 const char *sp;
3301 char *tp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003302 char *cp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003303 int maltmp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003304
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003305 DBGPRINTF(("DODOT: enter, t=%p, tleft %p, tright %p, global_env.linep is %s\n",
3306 t, t->left, t->right, ((global_env.linep == NULL) ? "NULL" : global_env.linep)));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003307
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003308 cp = t->words[1];
3309 if (cp == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00003310 DBGPRINTF(("DODOT: bad args, ret 0\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003311 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003312 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003313 DBGPRINTF(("DODOT: cp is %s\n", cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003314
Eric Andersen8401eea2004-08-04 19:16:54 +00003315 sp = any('/', cp) ? ":" : path->value;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003316
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003317 DBGPRINTF(("DODOT: sp is %s, global_env.linep is %s\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00003318 ((sp == NULL) ? "NULL" : sp),
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003319 ((global_env.linep == NULL) ? "NULL" : global_env.linep)));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003320
Eric Andersenff9eee42001-06-29 04:57:14 +00003321 while (*sp) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003322 tp = global_env.linep;
Eric Andersenff9eee42001-06-29 04:57:14 +00003323 while (*sp && (*tp = *sp++) != ':')
3324 tp++;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003325 if (tp != global_env.linep)
Eric Andersenff9eee42001-06-29 04:57:14 +00003326 *tp++ = '/';
Eric Andersen12de6cf2004-08-04 19:19:10 +00003327
Eric Andersen8401eea2004-08-04 19:16:54 +00003328 for (i = 0; (*tp++ = cp[i++]) != '\0';);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003329
3330 /* Original code */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003331 i = open(global_env.linep, O_RDONLY);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003332 if (i >= 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003333 exstat = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003334 maltmp = remap(i);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003335 DBGPRINTF(("DODOT: remap=%d, exstat=%d, global_env.iofd %d, i %d, global_env.linep is %s\n",
3336 maltmp, exstat, global_env.iofd, i, global_env.linep));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003337
3338 next(maltmp); /* Basically a PUSHIO */
3339
3340 DBGPRINTF(("DODOT: returning exstat=%d\n", exstat));
3341
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003342 return exstat;
Eric Andersenff9eee42001-06-29 04:57:14 +00003343 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003344 } /* while */
Eric Andersen12de6cf2004-08-04 19:19:10 +00003345
Eric Andersenff9eee42001-06-29 04:57:14 +00003346 prs(cp);
3347 err(": not found");
Eric Andersen12de6cf2004-08-04 19:19:10 +00003348
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003349 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003350}
3351
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003352static int dowait(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003353{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003354 int i;
3355 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003356
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003357 cp = t->words[1];
3358 if (cp != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003359 i = getn(cp);
3360 if (i == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003361 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003362 } else
3363 i = -1;
3364 setstatus(waitfor(i, 1));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003365 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003366}
3367
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003368static int doread(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003369{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003370 char *cp, **wp;
3371 int nb = 0;
3372 int nl = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003373
3374 if (t->words[1] == NULL) {
3375 err("Usage: read name ...");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003376 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003377 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003378 for (wp = t->words + 1; *wp; wp++) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003379 for (cp = global_env.linep; !nl && cp < elinep - 1; cp++) {
Denis Vlasenkoe376d452008-02-20 22:23:24 +00003380 nb = nonblock_safe_read(0, cp, sizeof(*cp));
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003381 if (nb != sizeof(*cp))
Eric Andersenff9eee42001-06-29 04:57:14 +00003382 break;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003383 nl = (*cp == '\n');
3384 if (nl || (wp[1] && any(*cp, ifs->value)))
3385 break;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003386 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003387 *cp = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00003388 if (nb <= 0)
3389 break;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003390 setval(lookup(*wp), global_env.linep);
Eric Andersenff9eee42001-06-29 04:57:14 +00003391 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003392 return nb <= 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003393}
3394
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003395static int doeval(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003396{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003397 return RUN(awordlist, t->words + 1, wdchar);
Eric Andersenff9eee42001-06-29 04:57:14 +00003398}
3399
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003400static int dotrap(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003401{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003402 int n, i;
3403 int resetsig;
Eric Andersenff9eee42001-06-29 04:57:14 +00003404
3405 if (t->words[1] == NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00003406 for (i = 0; i <= _NSIG; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00003407 if (trap[i]) {
3408 prn(i);
3409 prs(": ");
3410 prs(trap[i]);
3411 prs("\n");
3412 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003413 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003414 }
3415 resetsig = isdigit(*t->words[1]);
3416 for (i = resetsig ? 1 : 2; t->words[i] != NULL; ++i) {
3417 n = getsig(t->words[i]);
3418 freecell(trap[n]);
3419 trap[n] = 0;
3420 if (!resetsig) {
3421 if (*t->words[1] != '\0') {
3422 trap[n] = strsave(t->words[1], 0);
3423 setsig(n, sig);
3424 } else
3425 setsig(n, SIG_IGN);
3426 } else {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00003427 if (interactive) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003428 if (n == SIGINT)
3429 setsig(n, onintr);
3430 else
Eric Andersen8401eea2004-08-04 19:16:54 +00003431 setsig(n, n == SIGQUIT ? SIG_IGN : SIG_DFL);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00003432 } else
Eric Andersenff9eee42001-06-29 04:57:14 +00003433 setsig(n, SIG_DFL);
3434 }
3435 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003436 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003437}
3438
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003439static int getsig(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003440{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003441 int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003442
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003443 n = getn(s);
3444 if (n < 0 || n > _NSIG) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003445 err("trap: bad signal number");
3446 n = 0;
3447 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003448 return n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003449}
3450
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003451static void setsig(int n, sighandler_t f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003452{
3453 if (n == 0)
3454 return;
3455 if (signal(n, SIG_IGN) != SIG_IGN || ourtrap[n]) {
3456 ourtrap[n] = 1;
3457 signal(n, f);
3458 }
3459}
3460
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003461static int getn(char *as)
Eric Andersenff9eee42001-06-29 04:57:14 +00003462{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003463 char *s;
3464 int n, m;
Eric Andersenff9eee42001-06-29 04:57:14 +00003465
3466 s = as;
3467 m = 1;
3468 if (*s == '-') {
3469 m = -1;
3470 s++;
3471 }
3472 for (n = 0; isdigit(*s); s++)
Eric Andersen8401eea2004-08-04 19:16:54 +00003473 n = (n * 10) + (*s - '0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003474 if (*s) {
3475 prs(as);
3476 err(": bad number");
3477 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003478 return n * m;
Eric Andersenff9eee42001-06-29 04:57:14 +00003479}
3480
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003481static int dobreak(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003482{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003483 return brkcontin(t->words[1], 1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003484}
3485
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003486static int docontinue(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003487{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003488 return brkcontin(t->words[1], 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003489}
3490
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003491static int brkcontin(char *cp, int val)
Eric Andersenff9eee42001-06-29 04:57:14 +00003492{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003493 struct brkcon *bc;
3494 int nl;
Eric Andersenff9eee42001-06-29 04:57:14 +00003495
Eric Andersen8401eea2004-08-04 19:16:54 +00003496 nl = cp == NULL ? 1 : getn(cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003497 if (nl <= 0)
3498 nl = 999;
3499 do {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003500 bc = brklist;
3501 if (bc == NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00003502 break;
3503 brklist = bc->nextlev;
3504 } while (--nl);
3505 if (nl) {
3506 err("bad break/continue level");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003507 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003508 }
Denis Vlasenko648b44f2008-02-12 06:04:06 +00003509 isbreak = (val != 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003510 longjmp(bc->brkpt, 1);
3511 /* NOTREACHED */
3512}
3513
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003514static int doexit(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003515{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003516 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003517
3518 execflg = 0;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003519 cp = t->words[1];
3520 if (cp != NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00003521 setstatus(getn(cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003522
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003523 DBGPRINTF(("DOEXIT: calling leave(), t=%p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003524
Eric Andersenff9eee42001-06-29 04:57:14 +00003525 leave();
3526 /* NOTREACHED */
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003527 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003528}
3529
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003530static int doexport(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003531{
Eric Andersen8401eea2004-08-04 19:16:54 +00003532 rdexp(t->words + 1, export, EXPORT);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003533 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003534}
3535
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003536static int doreadonly(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003537{
Eric Andersen8401eea2004-08-04 19:16:54 +00003538 rdexp(t->words + 1, ronly, RONLY);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003539 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003540}
3541
Eric Andersen8401eea2004-08-04 19:16:54 +00003542static void rdexp(char **wp, void (*f) (struct var *), int key)
Eric Andersenff9eee42001-06-29 04:57:14 +00003543{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003544 DBGPRINTF6(("RDEXP: enter, wp=%p, func=%p, key=%d\n", wp, f, key));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003545 DBGPRINTF6(("RDEXP: *wp=%s\n", *wp));
3546
Eric Andersenff9eee42001-06-29 04:57:14 +00003547 if (*wp != NULL) {
Matt Kraaif69bfc72001-07-12 19:39:59 +00003548 for (; *wp != NULL; wp++) {
3549 if (isassign(*wp)) {
3550 char *cp;
Eric Andersen8401eea2004-08-04 19:16:54 +00003551
Matt Kraaif69bfc72001-07-12 19:39:59 +00003552 assign(*wp, COPYV);
Eric Andersen8401eea2004-08-04 19:16:54 +00003553 for (cp = *wp; *cp != '='; cp++);
Matt Kraaif69bfc72001-07-12 19:39:59 +00003554 *cp = '\0';
3555 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003556 if (checkname(*wp))
Eric Andersen8401eea2004-08-04 19:16:54 +00003557 (*f) (lookup(*wp));
Eric Andersenff9eee42001-06-29 04:57:14 +00003558 else
3559 badid(*wp);
Matt Kraaif69bfc72001-07-12 19:39:59 +00003560 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003561 } else
3562 putvlist(key, 1);
3563}
3564
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003565static void badid(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003566{
3567 prs(s);
3568 err(": bad identifier");
3569}
3570
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003571static int doset(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003572{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003573 struct var *vp;
3574 char *cp;
3575 int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003576
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003577 cp = t->words[1];
3578 if (cp == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003579 for (vp = vlist; vp; vp = vp->next)
3580 varput(vp->name, 1);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003581 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003582 }
3583 if (*cp == '-') {
3584 /* bad: t->words++; */
Eric Andersen8401eea2004-08-04 19:16:54 +00003585 for (n = 0; (t->words[n] = t->words[n + 1]) != NULL; n++);
Eric Andersenff9eee42001-06-29 04:57:14 +00003586 if (*++cp == 0)
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003587 FLAG['x'] = FLAG['v'] = 0;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003588 else {
3589 for (; *cp; cp++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003590 switch (*cp) {
3591 case 'e':
3592 if (!interactive)
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003593 FLAG['e']++;
Eric Andersenff9eee42001-06-29 04:57:14 +00003594 break;
3595
3596 default:
Eric Andersen8401eea2004-08-04 19:16:54 +00003597 if (*cp >= 'a' && *cp <= 'z')
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003598 FLAG[(int) *cp]++;
Eric Andersenff9eee42001-06-29 04:57:14 +00003599 break;
3600 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003601 }
3602 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003603 setdash();
3604 }
3605 if (t->words[1]) {
3606 t->words[0] = dolv[0];
Eric Andersen8401eea2004-08-04 19:16:54 +00003607 for (n = 1; t->words[n]; n++)
3608 setarea((char *) t->words[n], 0);
3609 dolc = n - 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003610 dolv = t->words;
3611 setval(lookup("#"), putn(dolc));
Eric Andersen8401eea2004-08-04 19:16:54 +00003612 setarea((char *) (dolv - 1), 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003613 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003614 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003615}
3616
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003617static void varput(char *s, int out)
Eric Andersenff9eee42001-06-29 04:57:14 +00003618{
Matt Kraai69edfec2001-08-06 14:14:18 +00003619 if (isalnum(*s) || *s == '_') {
Eric Andersenff9eee42001-06-29 04:57:14 +00003620 write(out, s, strlen(s));
3621 write(out, "\n", 1);
3622 }
3623}
3624
3625
3626/*
3627 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
3628 * This file contains code for the times builtin.
Eric Andersenff9eee42001-06-29 04:57:14 +00003629 */
Eric Andersen8401eea2004-08-04 19:16:54 +00003630static int dotimes(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003631{
3632 struct tms buf;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003633 long clk_tck = sysconf(_SC_CLK_TCK);
Eric Andersenff9eee42001-06-29 04:57:14 +00003634
3635 times(&buf);
3636 printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
Eric Andersen8401eea2004-08-04 19:16:54 +00003637 (int) (buf.tms_utime / clk_tck / 60),
3638 ((double) buf.tms_utime) / clk_tck,
3639 (int) (buf.tms_stime / clk_tck / 60),
3640 ((double) buf.tms_stime) / clk_tck,
3641 (int) (buf.tms_cutime / clk_tck / 60),
3642 ((double) buf.tms_cutime) / clk_tck,
3643 (int) (buf.tms_cstime / clk_tck / 60),
3644 ((double) buf.tms_cstime) / clk_tck);
Eric Andersenff9eee42001-06-29 04:57:14 +00003645 return 0;
3646}
3647
3648
Eric Andersenff9eee42001-06-29 04:57:14 +00003649/* -------- eval.c -------- */
3650
3651/*
3652 * ${}
3653 * `command`
3654 * blank interpretation
3655 * quoting
3656 * glob
3657 */
3658
Eric Andersen8401eea2004-08-04 19:16:54 +00003659static char **eval(char **ap, int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003660{
3661 struct wdblock *wb;
3662 char **wp;
3663 char **wf;
3664 jmp_buf ev;
3665
3666#if __GNUC__
3667 /* Avoid longjmp clobbering */
3668 (void) &wp;
3669 (void) &ap;
3670#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00003671
3672 DBGPRINTF4(("EVAL: enter, f=%d\n", f));
3673
Eric Andersenff9eee42001-06-29 04:57:14 +00003674 wp = NULL;
3675 wb = NULL;
3676 wf = NULL;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003677 errpt = ev;
3678 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003679 while (*ap && isassign(*ap))
3680 expand(*ap++, &wb, f & ~DOGLOB);
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003681 if (FLAG['k']) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003682 for (wf = ap; *wf; wf++) {
3683 if (isassign(*wf))
3684 expand(*wf, &wb, f & ~DOGLOB);
3685 }
3686 }
Denis Vlasenko648b44f2008-02-12 06:04:06 +00003687 for (wb = addword((char *) NULL, wb); *ap; ap++) {
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003688 if (!FLAG['k'] || !isassign(*ap))
Eric Andersenff9eee42001-06-29 04:57:14 +00003689 expand(*ap, &wb, f & ~DOKEY);
3690 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003691 wb = addword((char *) 0, wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00003692 wp = getwords(wb);
3693 quitenv();
3694 } else
3695 gflg = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003696
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003697 return gflg ? (char **) NULL : wp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003698}
3699
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003700
Eric Andersenff9eee42001-06-29 04:57:14 +00003701/*
3702 * Make the exported environment from the exported
3703 * names in the dictionary. Keyword assignments
3704 * will already have been done.
3705 */
Eric Andersenfd7a4c82004-09-02 23:13:10 +00003706static char **makenv(int all, struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00003707{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003708 struct var *vp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003709
3710 DBGPRINTF5(("MAKENV: enter, all=%d\n", all));
Eric Andersenff9eee42001-06-29 04:57:14 +00003711
Eric Andersenff9eee42001-06-29 04:57:14 +00003712 for (vp = vlist; vp; vp = vp->next)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003713 if (all || vp->status & EXPORT)
Eric Andersenff9eee42001-06-29 04:57:14 +00003714 wb = addword(vp->name, wb);
Eric Andersen8401eea2004-08-04 19:16:54 +00003715 wb = addword((char *) 0, wb);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003716 return getwords(wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00003717}
3718
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003719static int expand(const char *cp, struct wdblock **wbp, int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003720{
3721 jmp_buf ev;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003722 char *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003723
3724#if __GNUC__
3725 /* Avoid longjmp clobbering */
3726 (void) &cp;
3727#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00003728
3729 DBGPRINTF3(("EXPAND: enter, f=%d\n", f));
3730
Eric Andersenff9eee42001-06-29 04:57:14 +00003731 gflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003732
Eric Andersenff9eee42001-06-29 04:57:14 +00003733 if (cp == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003734 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003735
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003736 if (!anys("$`'\"", cp) && !anys(ifs->value, cp)
3737 && ((f & DOGLOB) == 0 || !anys("[*?", cp))
3738 ) {
3739 xp = strsave(cp, areanum);
Eric Andersenff9eee42001-06-29 04:57:14 +00003740 if (f & DOTRIM)
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003741 unquote(xp);
3742 *wbp = addword(xp, *wbp);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003743 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003744 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003745 errpt = ev;
3746 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003747 PUSHIO(aword, cp, strchar);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003748 global_env.iobase = global_env.iop;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003749 while ((xp = blank(f)) && gflg == 0) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003750 global_env.linep = xp;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003751 xp = strsave(xp, areanum);
Eric Andersen8401eea2004-08-04 19:16:54 +00003752 if ((f & DOGLOB) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003753 if (f & DOTRIM)
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003754 unquote(xp);
3755 *wbp = addword(xp, *wbp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003756 } else
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003757 *wbp = glob(xp, *wbp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003758 }
3759 quitenv();
3760 } else
3761 gflg = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003762 return gflg == 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003763}
3764
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003765static char *evalstr(char *cp, int f)
3766{
3767 struct wdblock *wb;
3768
3769 DBGPRINTF6(("EVALSTR: enter, cp=%p, f=%d\n", cp, f));
3770
3771 wb = NULL;
3772 if (expand(cp, &wb, f)) {
3773 if (wb == NULL || wb->w_nword == 0
3774 || (cp = wb->w_words[0]) == NULL
3775 ) {
Denis Vlasenko8e858e22007-03-07 09:35:43 +00003776// TODO: I suspect that
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003777// char *evalstr(char *cp, int f) is actually
3778// const char *evalstr(const char *cp, int f)!
3779 cp = (char*)"";
3780 }
3781 DELETE(wb);
3782 } else
3783 cp = NULL;
3784 return cp;
3785}
3786
3787
Eric Andersenff9eee42001-06-29 04:57:14 +00003788/*
3789 * Blank interpretation and quoting
3790 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003791static char *blank(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003792{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003793 int c, c1;
3794 char *sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003795 int scanequals, foundequals;
3796
Eric Andersen12de6cf2004-08-04 19:19:10 +00003797 DBGPRINTF3(("BLANK: enter, f=%d\n", f));
3798
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003799 sp = global_env.linep;
Eric Andersenff9eee42001-06-29 04:57:14 +00003800 scanequals = f & DOKEY;
3801 foundequals = 0;
3802
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003803 loop:
3804 c = subgetc('"', foundequals);
3805 switch (c) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003806 case 0:
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003807 if (sp == global_env.linep)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003808 return 0;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003809 *global_env.linep++ = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003810 return sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003811
3812 default:
3813 if (f & DOBLANK && any(c, ifs->value))
3814 goto loop;
3815 break;
3816
3817 case '"':
3818 case '\'':
3819 scanequals = 0;
3820 if (INSUB())
3821 break;
3822 for (c1 = c; (c = subgetc(c1, 1)) != c1;) {
3823 if (c == 0)
3824 break;
3825 if (c == '\'' || !any(c, "$`\""))
3826 c |= QUOTE;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003827 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003828 }
3829 c = 0;
3830 }
3831 unget(c);
Matt Kraai69edfec2001-08-06 14:14:18 +00003832 if (!isalpha(c) && c != '_')
Eric Andersenff9eee42001-06-29 04:57:14 +00003833 scanequals = 0;
3834 for (;;) {
3835 c = subgetc('"', foundequals);
3836 if (c == 0 ||
Eric Andersen8401eea2004-08-04 19:16:54 +00003837 f & (DOBLANK && any(c, ifs->value)) ||
3838 (!INSUB() && any(c, "\"'"))) {
3839 scanequals = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003840 unget(c);
3841 if (any(c, "\"'"))
3842 goto loop;
3843 break;
3844 }
3845 if (scanequals) {
3846 if (c == '=') {
3847 foundequals = 1;
Eric Andersen8401eea2004-08-04 19:16:54 +00003848 scanequals = 0;
3849 } else if (!isalnum(c) && c != '_')
Eric Andersenff9eee42001-06-29 04:57:14 +00003850 scanequals = 0;
3851 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003852 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003853 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003854 *global_env.linep++ = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003855 return sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003856}
3857
3858/*
3859 * Get characters, substituting for ` and $
3860 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003861static int subgetc(char ec, int quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00003862{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003863 char c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003864
3865 DBGPRINTF3(("SUBGETC: enter, quoted=%d\n", quoted));
Eric Andersenff9eee42001-06-29 04:57:14 +00003866
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003867 again:
Eric Andersenff9eee42001-06-29 04:57:14 +00003868 c = my_getc(ec);
3869 if (!INSUB() && ec != '\'') {
3870 if (c == '`') {
3871 if (grave(quoted) == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003872 return 0;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003873 global_env.iop->task = XGRAVE;
Eric Andersenff9eee42001-06-29 04:57:14 +00003874 goto again;
3875 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003876 if (c == '$') {
3877 c = dollar(quoted);
3878 if (c == 0) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003879 global_env.iop->task = XDOLL;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003880 goto again;
3881 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003882 }
3883 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003884 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003885}
3886
3887/*
3888 * Prepare to generate the string returned by ${} substitution.
3889 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003890static int dollar(int quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00003891{
3892 int otask;
3893 struct io *oiop;
3894 char *dolp;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003895 char *s, c, *cp = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00003896 struct var *vp;
3897
Eric Andersen12de6cf2004-08-04 19:19:10 +00003898 DBGPRINTF3(("DOLLAR: enter, quoted=%d\n", quoted));
3899
Eric Andersenff9eee42001-06-29 04:57:14 +00003900 c = readc();
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003901 s = global_env.linep;
Eric Andersenff9eee42001-06-29 04:57:14 +00003902 if (c != '{') {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003903 *global_env.linep++ = c;
Matt Kraai69edfec2001-08-06 14:14:18 +00003904 if (isalpha(c) || c == '_') {
Eric Andersen8401eea2004-08-04 19:16:54 +00003905 while ((c = readc()) != 0 && (isalnum(c) || c == '_'))
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003906 if (global_env.linep < elinep)
3907 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003908 unget(c);
3909 }
3910 c = 0;
3911 } else {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003912 oiop = global_env.iop;
3913 otask = global_env.iop->task;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003914
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003915 global_env.iop->task = XOTHER;
Eric Andersen8401eea2004-08-04 19:16:54 +00003916 while ((c = subgetc('"', 0)) != 0 && c != '}' && c != '\n')
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003917 if (global_env.linep < elinep)
3918 *global_env.linep++ = c;
3919 if (oiop == global_env.iop)
3920 global_env.iop->task = otask;
Eric Andersenff9eee42001-06-29 04:57:14 +00003921 if (c != '}') {
3922 err("unclosed ${");
Denis Vlasenko648b44f2008-02-12 06:04:06 +00003923 gflg = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003924 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003925 }
3926 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003927 if (global_env.linep >= elinep) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003928 err("string in ${} too long");
Denis Vlasenko648b44f2008-02-12 06:04:06 +00003929 gflg = 1;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003930 global_env.linep -= 10;
Eric Andersenff9eee42001-06-29 04:57:14 +00003931 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003932 *global_env.linep = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003933 if (*s)
Eric Andersen8401eea2004-08-04 19:16:54 +00003934 for (cp = s + 1; *cp; cp++)
Eric Andersenff9eee42001-06-29 04:57:14 +00003935 if (any(*cp, "=-+?")) {
3936 c = *cp;
3937 *cp++ = 0;
3938 break;
3939 }
3940 if (s[1] == 0 && (*s == '*' || *s == '@')) {
3941 if (dolc > 1) {
3942 /* currently this does not distinguish $* and $@ */
3943 /* should check dollar */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003944 global_env.linep = s;
Eric Andersen8401eea2004-08-04 19:16:54 +00003945 PUSHIO(awordlist, dolv + 1, dolchar);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003946 return 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00003947 } else { /* trap the nasty ${=} */
Eric Andersenff9eee42001-06-29 04:57:14 +00003948 s[0] = '1';
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003949 s[1] = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00003950 }
3951 }
3952 vp = lookup(s);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003953 dolp = vp->value;
3954 if (dolp == null) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003955 switch (c) {
3956 case '=':
3957 if (isdigit(*s)) {
3958 err("cannot use ${...=...} with $n");
Denis Vlasenko648b44f2008-02-12 06:04:06 +00003959 gflg = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003960 break;
3961 }
3962 setval(vp, cp);
3963 dolp = vp->value;
3964 break;
3965
3966 case '-':
3967 dolp = strsave(cp, areanum);
3968 break;
3969
3970 case '?':
3971 if (*cp == 0) {
3972 prs("missing value for ");
3973 err(s);
3974 } else
3975 err(cp);
Denis Vlasenko648b44f2008-02-12 06:04:06 +00003976 gflg = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003977 break;
3978 }
3979 } else if (c == '+')
3980 dolp = strsave(cp, areanum);
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003981 if (FLAG['u'] && dolp == null) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003982 prs("unset variable: ");
3983 err(s);
Denis Vlasenko648b44f2008-02-12 06:04:06 +00003984 gflg = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003985 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003986 global_env.linep = s;
Eric Andersenff9eee42001-06-29 04:57:14 +00003987 PUSHIO(aword, dolp, quoted ? qstrchar : strchar);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003988 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003989}
3990
3991/*
3992 * Run the command in `...` and read its output.
3993 */
Eric Andersen737f5fb2003-03-14 16:05:59 +00003994
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003995static int grave(int quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00003996{
Denis Vlasenko55f30b02007-03-24 22:42:29 +00003997 /* moved to G: static char child_cmd[LINELIM]; */
3998
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003999 const char *cp;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004000 int i;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004001 int j;
Eric Andersenff9eee42001-06-29 04:57:14 +00004002 int pf[2];
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004003 const char *src;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004004 char *dest;
4005 int count;
4006 int ignore;
4007 int ignore_once;
4008 char *argument_list[4];
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004009 struct wdblock *wb = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004010
4011#if __GNUC__
4012 /* Avoid longjmp clobbering */
4013 (void) &cp;
4014#endif
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004015
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004016 for (cp = global_env.iop->argp->aword; *cp != '`'; cp++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004017 if (*cp == 0) {
4018 err("no closing `");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004019 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004020 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004021 }
Eric Andersen737f5fb2003-03-14 16:05:59 +00004022
4023 /* string copy with dollar expansion */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004024 src = global_env.iop->argp->aword;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004025 dest = child_cmd;
4026 count = 0;
4027 ignore = 0;
4028 ignore_once = 0;
4029 while ((*src != '`') && (count < LINELIM)) {
4030 if (*src == '\'')
4031 ignore = !ignore;
4032 if (*src == '\\')
4033 ignore_once = 1;
4034 if (*src == '$' && !ignore && !ignore_once) {
4035 struct var *vp;
Denis Vlasenkoab801872007-12-02 08:35:37 +00004036 /* moved to G to reduce stack usage
Eric Andersen737f5fb2003-03-14 16:05:59 +00004037 char var_name[LINELIM];
4038 char alt_value[LINELIM];
Denis Vlasenkoab801872007-12-02 08:35:37 +00004039 */
4040#define var_name (G.grave__var_name)
4041#define alt_value (G.grave__alt_value)
Eric Andersen737f5fb2003-03-14 16:05:59 +00004042 int var_index = 0;
4043 int alt_index = 0;
4044 char operator = 0;
4045 int braces = 0;
4046 char *value;
4047
4048 src++;
4049 if (*src == '{') {
4050 braces = 1;
4051 src++;
4052 }
4053
4054 var_name[var_index++] = *src++;
Paul Fox54690dc2005-07-20 18:33:12 +00004055 while (isalnum(*src) || *src=='_')
Eric Andersen737f5fb2003-03-14 16:05:59 +00004056 var_name[var_index++] = *src++;
4057 var_name[var_index] = 0;
4058
4059 if (braces) {
4060 switch (*src) {
4061 case '}':
4062 break;
4063 case '-':
4064 case '=':
4065 case '+':
4066 case '?':
Eric Andersen8401eea2004-08-04 19:16:54 +00004067 operator = * src;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004068 break;
4069 default:
4070 err("unclosed ${\n");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004071 return 0;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004072 }
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004073 if (operator) {
Eric Andersen737f5fb2003-03-14 16:05:59 +00004074 src++;
4075 while (*src && (*src != '}')) {
4076 alt_value[alt_index++] = *src++;
4077 }
4078 alt_value[alt_index] = 0;
4079 if (*src != '}') {
4080 err("unclosed ${\n");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004081 return 0;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004082 }
4083 }
4084 src++;
4085 }
4086
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004087 if (isalpha(*var_name)) {
4088 /* let subshell handle it instead */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004089
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004090 char *namep = var_name;
4091
4092 *dest++ = '$';
4093 if (braces)
4094 *dest++ = '{';
4095 while (*namep)
4096 *dest++ = *namep++;
4097 if (operator) {
4098 char *altp = alt_value;
4099 *dest++ = operator;
4100 while (*altp)
4101 *dest++ = *altp++;
4102 }
4103 if (braces)
4104 *dest++ = '}';
4105
4106 wb = addword(lookup(var_name)->name, wb);
4107 } else {
4108 /* expand */
4109
4110 vp = lookup(var_name);
4111 if (vp->value != null)
4112 value = (operator == '+') ?
4113 alt_value : vp->value;
4114 else if (operator == '?') {
4115 err(alt_value);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004116 return 0;
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004117 } else if (alt_index && (operator != '+')) {
4118 value = alt_value;
4119 if (operator == '=')
4120 setval(vp, value);
4121 } else
4122 continue;
4123
4124 while (*value && (count < LINELIM)) {
4125 *dest++ = *value++;
4126 count++;
4127 }
Eric Andersen737f5fb2003-03-14 16:05:59 +00004128 }
Denis Vlasenkoab801872007-12-02 08:35:37 +00004129#undef var_name
4130#undef alt_value
Eric Andersen737f5fb2003-03-14 16:05:59 +00004131 } else {
4132 *dest++ = *src++;
4133 count++;
4134 ignore_once = 0;
4135 }
4136 }
4137 *dest = '\0';
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004138
Eric Andersenff9eee42001-06-29 04:57:14 +00004139 if (openpipe(pf) < 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004140 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004141
Eric Andersen8401eea2004-08-04 19:16:54 +00004142 while ((i = vfork()) == -1 && errno == EAGAIN);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004143
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004144 DBGPRINTF3(("GRAVE: i is %p\n", io));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004145
Eric Andersen737f5fb2003-03-14 16:05:59 +00004146 if (i < 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004147 closepipe(pf);
Eric Andersen8401eea2004-08-04 19:16:54 +00004148 err((char *) bb_msg_memory_exhausted);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004149 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004150 }
4151 if (i != 0) {
Denis Vlasenkofb0eba72008-01-02 19:55:04 +00004152 waitpid(i, NULL, 0); // safe_waitpid?
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004153 global_env.iop->argp->aword = ++cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004154 close(pf[1]);
Eric Andersen8401eea2004-08-04 19:16:54 +00004155 PUSHIO(afile, remap(pf[0]),
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004156 (int (*)(struct ioarg *)) ((quoted) ? qgravechar : gravechar));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004157 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004158 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004159 /* allow trapped signals */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004160 /* XXX - Maybe this signal stuff should go as well? */
Eric Andersen8401eea2004-08-04 19:16:54 +00004161 for (j = 0; j <= _NSIG; j++)
Eric Andersen737f5fb2003-03-14 16:05:59 +00004162 if (ourtrap[j] && signal(j, SIG_IGN) != SIG_IGN)
4163 signal(j, SIG_DFL);
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004164
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00004165 /* Testcase where below checks are needed:
4166 * close stdout & run this script:
4167 * files=`ls`
4168 * echo "$files" >zz
4169 */
4170 xmove_fd(pf[1], 1);
Denis Vlasenko847fa772008-01-28 22:45:43 +00004171 if (pf[0] != 1)
4172 close(pf[0]);
Eric Andersen737f5fb2003-03-14 16:05:59 +00004173
Eric Andersen8401eea2004-08-04 19:16:54 +00004174 argument_list[0] = (char *) DEFAULT_SHELL;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004175 argument_list[1] = (char *) "-c";
Eric Andersen737f5fb2003-03-14 16:05:59 +00004176 argument_list[2] = child_cmd;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004177 argument_list[3] = NULL;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004178
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004179 cp = rexecve(argument_list[0], argument_list, makenv(1, wb));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004180 prs(argument_list[0]);
4181 prs(": ");
4182 err(cp);
Eric Andersen737f5fb2003-03-14 16:05:59 +00004183 _exit(1);
Eric Andersenff9eee42001-06-29 04:57:14 +00004184}
4185
Eric Andersen737f5fb2003-03-14 16:05:59 +00004186
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004187static char *unquote(char *as)
Eric Andersenff9eee42001-06-29 04:57:14 +00004188{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004189 char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00004190
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004191 s = as;
4192 if (s != NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00004193 while (*s)
4194 *s++ &= ~QUOTE;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004195 return as;
Eric Andersenff9eee42001-06-29 04:57:14 +00004196}
4197
4198/* -------- glob.c -------- */
4199
4200/*
4201 * glob
4202 */
4203
4204#define scopy(x) strsave((x), areanum)
4205#define BLKSIZ 512
4206#define NDENT ((BLKSIZ+sizeof(struct dirent)-1)/sizeof(struct dirent))
4207
Eric Andersen8401eea2004-08-04 19:16:54 +00004208static struct wdblock *cl, *nl;
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00004209static const char spcl[] ALIGN1= "[?*";
Eric Andersenff9eee42001-06-29 04:57:14 +00004210
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004211static struct wdblock *glob(char *cp, struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004212{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004213 int i;
4214 char *pp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004215
4216 if (cp == 0)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004217 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004218 i = 0;
4219 for (pp = cp; *pp; pp++)
4220 if (any(*pp, spcl))
4221 i++;
4222 else if (!any(*pp & ~QUOTE, spcl))
4223 *pp &= ~QUOTE;
4224 if (i != 0) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004225 for (cl = addword(scopy(cp), NULL); anyspcl(cl); cl = nl) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004226 nl = newword(cl->w_nword * 2);
4227 for (i = 0; i < cl->w_nword; i++) { /* for each argument */
Eric Andersenff9eee42001-06-29 04:57:14 +00004228 for (pp = cl->w_words[i]; *pp; pp++)
4229 if (any(*pp, spcl)) {
4230 globname(cl->w_words[i], pp);
4231 break;
4232 }
4233 if (*pp == '\0')
4234 nl = addword(scopy(cl->w_words[i]), nl);
4235 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004236 for (i = 0; i < cl->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004237 DELETE(cl->w_words[i]);
4238 DELETE(cl);
4239 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004240 for (i = 0; i < cl->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004241 unquote(cl->w_words[i]);
Eric Andersen8401eea2004-08-04 19:16:54 +00004242 glob0((char *) cl->w_words, cl->w_nword, sizeof(char *), xstrcmp);
Eric Andersenff9eee42001-06-29 04:57:14 +00004243 if (cl->w_nword) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004244 for (i = 0; i < cl->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004245 wb = addword(cl->w_words[i], wb);
4246 DELETE(cl);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004247 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004248 }
4249 }
4250 wb = addword(unquote(cp), wb);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004251 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004252}
4253
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004254static void globname(char *we, char *pp)
Eric Andersenff9eee42001-06-29 04:57:14 +00004255{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004256 char *np, *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004257 char *name, *gp, *dp;
4258 int k;
4259 DIR *dirp;
4260 struct dirent *de;
Eric Andersen8401eea2004-08-04 19:16:54 +00004261 char dname[NAME_MAX + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00004262 struct stat dbuf;
4263
4264 for (np = we; np != pp; pp--)
4265 if (pp[-1] == '/')
4266 break;
Eric Andersen8401eea2004-08-04 19:16:54 +00004267 for (dp = cp = space((int) (pp - np) + 3); np < pp;)
Eric Andersenff9eee42001-06-29 04:57:14 +00004268 *cp++ = *np++;
4269 *cp++ = '.';
4270 *cp = '\0';
Eric Andersen8401eea2004-08-04 19:16:54 +00004271 for (gp = cp = space(strlen(pp) + 1); *np && *np != '/';)
Eric Andersenff9eee42001-06-29 04:57:14 +00004272 *cp++ = *np++;
4273 *cp = '\0';
4274 dirp = opendir(dp);
4275 if (dirp == 0) {
4276 DELETE(dp);
4277 DELETE(gp);
4278 return;
4279 }
4280 dname[NAME_MAX] = '\0';
Eric Andersen8401eea2004-08-04 19:16:54 +00004281 while ((de = readdir(dirp)) != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004282 /* XXX Hmmm... What this could be? (abial) */
4283 /*
Eric Andersen8401eea2004-08-04 19:16:54 +00004284 if (ent[j].d_ino == 0)
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004285 continue;
Eric Andersen8401eea2004-08-04 19:16:54 +00004286 */
Eric Andersenff9eee42001-06-29 04:57:14 +00004287 strncpy(dname, de->d_name, NAME_MAX);
Eric Andersen8401eea2004-08-04 19:16:54 +00004288 if (dname[0] == '.')
4289 if (*gp != '.')
4290 continue;
4291 for (k = 0; k < NAME_MAX; k++)
4292 if (any(dname[k], spcl))
4293 dname[k] |= QUOTE;
4294 if (gmatch(dname, gp)) {
4295 name = generate(we, pp, dname, np);
4296 if (*np && !anys(np, spcl)) {
4297 if (stat(name, &dbuf)) {
4298 DELETE(name);
Eric Andersenff9eee42001-06-29 04:57:14 +00004299 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00004300 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004301 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004302 nl = addword(name, nl);
4303 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004304 }
4305 closedir(dirp);
4306 DELETE(dp);
4307 DELETE(gp);
4308}
4309
4310/*
4311 * generate a pathname as below.
4312 * start..end1 / middle end
4313 * the slashes come for free
4314 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004315static char *generate(char *start1, char *end1, char *middle, char *end)
Eric Andersenff9eee42001-06-29 04:57:14 +00004316{
4317 char *p;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004318 char *op, *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004319
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004320 p = op = space((int)(end1 - start1) + strlen(middle) + strlen(end) + 2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004321 for (xp = start1; xp != end1;)
4322 *op++ = *xp++;
Eric Andersen8401eea2004-08-04 19:16:54 +00004323 for (xp = middle; (*op++ = *xp++) != '\0';);
Eric Andersenff9eee42001-06-29 04:57:14 +00004324 op--;
Eric Andersen8401eea2004-08-04 19:16:54 +00004325 for (xp = end; (*op++ = *xp++) != '\0';);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004326 return p;
Eric Andersenff9eee42001-06-29 04:57:14 +00004327}
4328
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004329static int anyspcl(struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004330{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004331 int i;
4332 char **wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004333
4334 wd = wb->w_words;
Eric Andersen8401eea2004-08-04 19:16:54 +00004335 for (i = 0; i < wb->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004336 if (anys(spcl, *wd++))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004337 return 1;
4338 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004339}
4340
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004341static int xstrcmp(char *p1, char *p2)
Eric Andersenff9eee42001-06-29 04:57:14 +00004342{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004343 return strcmp(*(char **) p1, *(char **) p2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004344}
4345
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004346
Eric Andersenff9eee42001-06-29 04:57:14 +00004347/* -------- word.c -------- */
4348
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004349static struct wdblock *newword(int nw)
Eric Andersenff9eee42001-06-29 04:57:14 +00004350{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004351 struct wdblock *wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004352
Eric Andersen8401eea2004-08-04 19:16:54 +00004353 wb = (struct wdblock *) space(sizeof(*wb) + nw * sizeof(char *));
Eric Andersenff9eee42001-06-29 04:57:14 +00004354 wb->w_bsize = nw;
4355 wb->w_nword = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004356 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004357}
4358
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004359static struct wdblock *addword(char *wd, struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004360{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004361 struct wdblock *wb2;
4362 int nw;
Eric Andersenff9eee42001-06-29 04:57:14 +00004363
4364 if (wb == NULL)
4365 wb = newword(NSTART);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004366 nw = wb->w_nword;
4367 if (nw >= wb->w_bsize) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004368 wb2 = newword(nw * 2);
Eric Andersen8401eea2004-08-04 19:16:54 +00004369 memcpy((char *) wb2->w_words, (char *) wb->w_words,
4370 nw * sizeof(char *));
Eric Andersenff9eee42001-06-29 04:57:14 +00004371 wb2->w_nword = nw;
4372 DELETE(wb);
4373 wb = wb2;
4374 }
4375 wb->w_words[wb->w_nword++] = wd;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004376 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004377}
Eric Andersen8401eea2004-08-04 19:16:54 +00004378
Denis Vlasenkoe4712752007-04-14 15:08:41 +00004379static char **getwords(struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004380{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004381 char **wd;
4382 int nb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004383
4384 if (wb == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004385 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004386 if (wb->w_nword == 0) {
4387 DELETE(wb);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004388 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004389 }
4390 wd = (char **) space(nb = sizeof(*wd) * wb->w_nword);
Eric Andersen8401eea2004-08-04 19:16:54 +00004391 memcpy((char *) wd, (char *) wb->w_words, nb);
4392 DELETE(wb); /* perhaps should done by caller */
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004393 return wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004394}
4395
"Vladimir N. Oleynik"ac973172005-09-22 14:38:17 +00004396static int (*func) (char *, char *);
4397static int globv;
Eric Andersenff9eee42001-06-29 04:57:14 +00004398
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004399static void glob3(char *i, char *j, char *k)
Eric Andersenff9eee42001-06-29 04:57:14 +00004400{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004401 char *index1, *index2, *index3;
4402 int c;
4403 int m;
4404
4405 m = globv;
4406 index1 = i;
4407 index2 = j;
4408 index3 = k;
4409 do {
4410 c = *index1;
4411 *index1++ = *index3;
4412 *index3++ = *index2;
4413 *index2++ = c;
4414 } while (--m);
4415}
4416
4417static void glob2(char *i, char *j)
4418{
4419 char *index1, *index2, c;
4420 int m;
4421
4422 m = globv;
4423 index1 = i;
4424 index2 = j;
4425 do {
4426 c = *index1;
4427 *index1++ = *index2;
4428 *index2++ = c;
4429 } while (--m);
Eric Andersenff9eee42001-06-29 04:57:14 +00004430}
4431
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004432static void glob1(char *base, char *lim)
Eric Andersenff9eee42001-06-29 04:57:14 +00004433{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004434 char *i, *j;
Eric Andersenff9eee42001-06-29 04:57:14 +00004435 int v2;
4436 char *lptr, *hptr;
4437 int c;
4438 unsigned n;
4439
Eric Andersenff9eee42001-06-29 04:57:14 +00004440 v2 = globv;
4441
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004442 top:
4443 n = (int) (lim - base);
4444 if (n <= v2)
Eric Andersenff9eee42001-06-29 04:57:14 +00004445 return;
Eric Andersen8401eea2004-08-04 19:16:54 +00004446 n = v2 * (n / (2 * v2));
4447 hptr = lptr = base + n;
Eric Andersenff9eee42001-06-29 04:57:14 +00004448 i = base;
Eric Andersen8401eea2004-08-04 19:16:54 +00004449 j = lim - v2;
4450 for (;;) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004451 if (i < lptr) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004452 c = (*func) (i, lptr);
4453 if (c == 0) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004454 lptr -= v2;
4455 glob2(i, lptr);
Eric Andersenff9eee42001-06-29 04:57:14 +00004456 continue;
4457 }
4458 if (c < 0) {
4459 i += v2;
4460 continue;
4461 }
4462 }
4463
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004464 begin:
Eric Andersenff9eee42001-06-29 04:57:14 +00004465 if (j > hptr) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004466 c = (*func) (hptr, j);
4467 if (c == 0) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004468 hptr += v2;
4469 glob2(hptr, j);
Eric Andersenff9eee42001-06-29 04:57:14 +00004470 goto begin;
4471 }
4472 if (c > 0) {
4473 if (i == lptr) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004474 hptr += v2;
4475 glob3(i, hptr, j);
4476 i = (lptr += v2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004477 goto begin;
4478 }
4479 glob2(i, j);
4480 j -= v2;
4481 i += v2;
4482 continue;
4483 }
4484 j -= v2;
4485 goto begin;
4486 }
4487
4488
4489 if (i == lptr) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004490 if (lptr - base >= lim - hptr) {
4491 glob1(hptr + v2, lim);
Eric Andersenff9eee42001-06-29 04:57:14 +00004492 lim = lptr;
4493 } else {
4494 glob1(base, lptr);
Eric Andersen8401eea2004-08-04 19:16:54 +00004495 base = hptr + v2;
Eric Andersenff9eee42001-06-29 04:57:14 +00004496 }
4497 goto top;
4498 }
4499
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004500 lptr -= v2;
4501 glob3(j, lptr, i);
4502 j = (hptr -= v2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004503 }
4504}
4505
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004506static void glob0(char *a0, unsigned a1, int a2, int (*a3) (char *, char *))
Eric Andersenff9eee42001-06-29 04:57:14 +00004507{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004508 func = a3;
4509 globv = a2;
4510 glob1(a0, a0 + a1 * a2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004511}
4512
Eric Andersenff9eee42001-06-29 04:57:14 +00004513
4514/* -------- io.c -------- */
4515
4516/*
4517 * shell IO
4518 */
4519
Eric Andersen8401eea2004-08-04 19:16:54 +00004520static int my_getc(int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00004521{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004522 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004523
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004524 if (global_env.linep > elinep) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004525 while ((c = readc()) != '\n' && c);
Eric Andersenff9eee42001-06-29 04:57:14 +00004526 err("input line too long");
Denis Vlasenko648b44f2008-02-12 06:04:06 +00004527 gflg = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004528 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004529 }
4530 c = readc();
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004531 if ((ec != '\'') && (ec != '`') && (global_env.iop->task != XGRAVE)) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004532 if (c == '\\') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004533 c = readc();
4534 if (c == '\n' && ec != '\"')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004535 return my_getc(ec);
Eric Andersenff9eee42001-06-29 04:57:14 +00004536 c |= QUOTE;
4537 }
4538 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004539 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004540}
4541
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004542static void unget(int c)
Eric Andersenff9eee42001-06-29 04:57:14 +00004543{
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004544 if (global_env.iop >= global_env.iobase)
4545 global_env.iop->peekc = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004546}
4547
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004548static int eofc(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00004549{
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004550 return global_env.iop < global_env.iobase || (global_env.iop->peekc == 0 && global_env.iop->prev == 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004551}
4552
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004553static int readc(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00004554{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004555 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004556
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004557 RCPRINTF(("READC: global_env.iop %p, global_env.iobase %p\n", global_env.iop, global_env.iobase));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004558
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004559 for (; global_env.iop >= global_env.iobase; global_env.iop--) {
4560 RCPRINTF(("READC: global_env.iop %p, peekc 0x%x\n", global_env.iop, global_env.iop->peekc));
4561 c = global_env.iop->peekc;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004562 if (c != '\0') {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004563 global_env.iop->peekc = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004564 return c;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004565 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004566 if (global_env.iop->prev != 0) {
4567 c = (*global_env.iop->iofn)(global_env.iop->argp, global_env.iop);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004568 if (c != '\0') {
4569 if (c == -1) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004570 global_env.iop++;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004571 continue;
Eric Andersen8401eea2004-08-04 19:16:54 +00004572 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004573 if (global_env.iop == iostack)
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004574 ioecho(c);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004575 global_env.iop->prev = c;
4576 return global_env.iop->prev;
Eric Andersenff9eee42001-06-29 04:57:14 +00004577 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004578 if (global_env.iop->task == XIO && global_env.iop->prev != '\n') {
4579 global_env.iop->prev = 0;
4580 if (global_env.iop == iostack)
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004581 ioecho('\n');
4582 return '\n';
Eric Andersen8401eea2004-08-04 19:16:54 +00004583 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004584 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004585 if (global_env.iop->task == XIO) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004586 if (multiline) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004587 global_env.iop->prev = 0;
4588 return global_env.iop->prev;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004589 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004590 if (interactive && global_env.iop == iostack + 1) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004591#if ENABLE_FEATURE_EDITING
4592 current_prompt = prompt->value;
4593#else
4594 prs(prompt->value);
4595#endif
4596 }
4597 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004598 } /* FOR */
4599
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004600 if (global_env.iop >= iostack) {
4601 RCPRINTF(("READC: return 0, global_env.iop %p\n", global_env.iop));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004602 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004603 }
4604
4605 DBGPRINTF(("READC: leave()...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00004606 leave();
4607 /* NOTREACHED */
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004608 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004609}
4610
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004611static void ioecho(char c)
Eric Andersenff9eee42001-06-29 04:57:14 +00004612{
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00004613 if (FLAG['v'])
Eric Andersenff9eee42001-06-29 04:57:14 +00004614 write(2, &c, sizeof c);
4615}
4616
Eric Andersen8401eea2004-08-04 19:16:54 +00004617static void pushio(struct ioarg *argp, int (*fn) (struct ioarg *))
Eric Andersenff9eee42001-06-29 04:57:14 +00004618{
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004619 DBGPRINTF(("PUSHIO: argp %p, argp->afid 0x%x, global_env.iop %p\n", argp,
4620 argp->afid, global_env.iop));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004621
4622 /* Set env ptr for io source to next array spot and check for array overflow */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004623 if (++global_env.iop >= &iostack[NPUSH]) {
4624 global_env.iop--;
Eric Andersenff9eee42001-06-29 04:57:14 +00004625 err("Shell input nested too deeply");
Denis Vlasenko648b44f2008-02-12 06:04:06 +00004626 gflg = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004627 return;
4628 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004629
4630 /* We did not overflow the NPUSH array spots so setup data structs */
4631
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004632 global_env.iop->iofn = (int (*)(struct ioarg *, struct io *)) fn; /* Store data source func ptr */
Eric Andersenff9eee42001-06-29 04:57:14 +00004633
4634 if (argp->afid != AFID_NOBUF)
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004635 global_env.iop->argp = argp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004636 else {
Eric Andersen12de6cf2004-08-04 19:19:10 +00004637
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004638 global_env.iop->argp = ioargstack + (global_env.iop - iostack); /* MAL - index into stack */
4639 *global_env.iop->argp = *argp; /* copy data from temp area into stack spot */
Eric Andersen12de6cf2004-08-04 19:19:10 +00004640
4641 /* MAL - mainbuf is for 1st data source (command line?) and all nested use a single shared buffer? */
4642
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004643 if (global_env.iop == &iostack[0])
4644 global_env.iop->argp->afbuf = &mainbuf;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004645 else
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004646 global_env.iop->argp->afbuf = &sharedbuf;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004647
4648 /* MAL - if not a termimal AND (commandline OR readable file) then give it a buffer id? */
4649 /* This line appears to be active when running scripts from command line */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004650 if ((isatty(global_env.iop->argp->afile) == 0)
4651 && (global_env.iop == &iostack[0]
4652 || lseek(global_env.iop->argp->afile, 0L, SEEK_CUR) != -1)) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00004653 if (++bufid == AFID_NOBUF) /* counter rollover check, AFID_NOBUF = 11111111 */
4654 bufid = AFID_ID; /* AFID_ID = 0 */
4655
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004656 global_env.iop->argp->afid = bufid; /* assign buffer id */
Eric Andersen8401eea2004-08-04 19:16:54 +00004657 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004658
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004659 DBGPRINTF(("PUSHIO: iostack %p, global_env.iop %p, afbuf %p\n",
4660 iostack, global_env.iop, global_env.iop->argp->afbuf));
4661 DBGPRINTF(("PUSHIO: mbuf %p, sbuf %p, bid %d, global_env.iop %p\n",
4662 &mainbuf, &sharedbuf, bufid, global_env.iop));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004663
Eric Andersenff9eee42001-06-29 04:57:14 +00004664 }
4665
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004666 global_env.iop->prev = ~'\n';
4667 global_env.iop->peekc = 0;
4668 global_env.iop->xchar = 0;
4669 global_env.iop->nlcount = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004670
Eric Andersenff9eee42001-06-29 04:57:14 +00004671 if (fn == filechar || fn == linechar)
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004672 global_env.iop->task = XIO;
Eric Andersen8401eea2004-08-04 19:16:54 +00004673 else if (fn == (int (*)(struct ioarg *)) gravechar
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004674 || fn == (int (*)(struct ioarg *)) qgravechar)
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004675 global_env.iop->task = XGRAVE;
Eric Andersenff9eee42001-06-29 04:57:14 +00004676 else
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004677 global_env.iop->task = XOTHER;
Eric Andersenff9eee42001-06-29 04:57:14 +00004678}
4679
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004680static struct io *setbase(struct io *ip)
Eric Andersenff9eee42001-06-29 04:57:14 +00004681{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004682 struct io *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004683
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004684 xp = global_env.iobase;
4685 global_env.iobase = ip;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004686 return xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004687}
4688
4689/*
4690 * Input generating functions
4691 */
4692
4693/*
4694 * Produce the characters of a string, then a newline, then EOF.
4695 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004696static int nlchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004697{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004698 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004699
4700 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004701 return 0;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004702 c = *ap->aword++;
4703 if (c == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004704 ap->aword = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004705 return '\n';
Eric Andersenff9eee42001-06-29 04:57:14 +00004706 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004707 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004708}
4709
4710/*
4711 * Given a list of words, produce the characters
4712 * in them, with a space after each word.
4713 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004714static int wdchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004715{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004716 char c;
4717 char **wl;
Eric Andersenff9eee42001-06-29 04:57:14 +00004718
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004719 wl = ap->awordlist;
4720 if (wl == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004721 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004722 if (*wl != NULL) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004723 c = *(*wl)++;
4724 if (c != 0)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004725 return c & 0177;
Eric Andersenff9eee42001-06-29 04:57:14 +00004726 ap->awordlist++;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004727 return ' ';
Eric Andersenff9eee42001-06-29 04:57:14 +00004728 }
4729 ap->awordlist = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004730 return '\n';
Eric Andersenff9eee42001-06-29 04:57:14 +00004731}
4732
4733/*
4734 * Return the characters of a list of words,
4735 * producing a space between them.
4736 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004737static int dolchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004738{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004739 char *wp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004740
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004741 wp = *ap->awordlist++;
4742 if (wp != NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004743 PUSHIO(aword, wp, *ap->awordlist == NULL ? strchar : xxchar);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004744 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004745 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004746 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004747}
4748
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004749static int xxchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004750{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004751 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004752
4753 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004754 return 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004755 c = *ap->aword++;
4756 if (c == '\0') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004757 ap->aword = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004758 return ' ';
Eric Andersenff9eee42001-06-29 04:57:14 +00004759 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004760 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004761}
4762
4763/*
4764 * Produce the characters from a single word (string).
4765 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004766static int strchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004767{
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004768 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004769 return 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004770 return *ap->aword++;
Eric Andersenff9eee42001-06-29 04:57:14 +00004771}
4772
4773/*
4774 * Produce quoted characters from a single word (string).
4775 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004776static int qstrchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004777{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004778 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004779
Denis Vlasenkob2abef32007-01-01 18:18:04 +00004780 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004781 return 0;
Denis Vlasenkob2abef32007-01-01 18:18:04 +00004782 c = *ap->aword++;
4783 if (c)
4784 c |= QUOTE;
4785 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004786}
4787
4788/*
4789 * Return the characters from a file.
4790 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004791static int filechar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004792{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004793 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004794 char c;
4795 struct iobuf *bp = ap->afbuf;
4796
4797 if (ap->afid != AFID_NOBUF) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004798 i = (ap->afid != bp->id);
4799 if (i || bp->bufp == bp->ebufp) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004800 if (i)
Denis Vlasenkoea620772006-10-14 02:23:43 +00004801 lseek(ap->afile, ap->afpos, SEEK_SET);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004802
Denis Vlasenkoe376d452008-02-20 22:23:24 +00004803 i = nonblock_safe_read(ap->afile, bp->buf, sizeof(bp->buf));
Eric Andersen8401eea2004-08-04 19:16:54 +00004804 if (i <= 0) {
4805 closef(ap->afile);
4806 return 0;
4807 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004808
Eric Andersen8401eea2004-08-04 19:16:54 +00004809 bp->id = ap->afid;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004810 bp->bufp = bp->buf;
4811 bp->ebufp = bp->bufp + i;
Eric Andersen8401eea2004-08-04 19:16:54 +00004812 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004813
Eric Andersen8401eea2004-08-04 19:16:54 +00004814 ap->afpos++;
4815 return *bp->bufp++ & 0177;
Eric Andersenff9eee42001-06-29 04:57:14 +00004816 }
Denis Vlasenko38f63192007-01-22 09:03:07 +00004817#if ENABLE_FEATURE_EDITING
Eric Andersen737f5fb2003-03-14 16:05:59 +00004818 if (interactive && isatty(ap->afile)) {
Denis Vlasenko55f30b02007-03-24 22:42:29 +00004819 /* moved to G: static char filechar_cmdbuf[BUFSIZ]; */
Eric Andersen8401eea2004-08-04 19:16:54 +00004820 static int position = 0, size = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004821
Eric Andersen8401eea2004-08-04 19:16:54 +00004822 while (size == 0 || position >= size) {
Denis Vlasenko6e602c42008-02-02 18:50:50 +00004823 size = read_line_input(current_prompt, filechar_cmdbuf, BUFSIZ, line_input_state);
4824 if (size < 0) /* Error/EOF */
4825 exit(0);
Eric Andersen8401eea2004-08-04 19:16:54 +00004826 position = 0;
Denis Vlasenko6e602c42008-02-02 18:50:50 +00004827 /* if Ctrl-C, size == 0 and loop will repeat */
Eric Andersen8401eea2004-08-04 19:16:54 +00004828 }
Denis Vlasenko55f30b02007-03-24 22:42:29 +00004829 c = filechar_cmdbuf[position];
Eric Andersen8401eea2004-08-04 19:16:54 +00004830 position++;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004831 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004832 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004833#endif
Denis Vlasenkoe376d452008-02-20 22:23:24 +00004834 i = nonblock_safe_read(ap->afile, &c, sizeof(c));
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004835 return i == sizeof(c) ? (c & 0x7f) : (closef(ap->afile), 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004836}
4837
4838/*
4839 * Return the characters from a here temp file.
4840 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004841static int herechar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004842{
4843 char c;
4844
Denis Vlasenkoe376d452008-02-20 22:23:24 +00004845 if (nonblock_safe_read(ap->afile, &c, sizeof(c)) != sizeof(c)) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004846 close(ap->afile);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004847 c = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00004848 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004849 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004850}
4851
4852/*
4853 * Return the characters produced by a process (`...`).
4854 * Quote them if required, and remove any trailing newline characters.
4855 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004856static int gravechar(struct ioarg *ap, struct io *iop)
Eric Andersenff9eee42001-06-29 04:57:14 +00004857{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004858 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004859
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004860 c = qgravechar(ap, iop) & ~QUOTE;
4861 if (c == '\n')
Eric Andersenff9eee42001-06-29 04:57:14 +00004862 c = ' ';
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004863 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004864}
4865
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004866static int qgravechar(struct ioarg *ap, struct io *iop)
Eric Andersenff9eee42001-06-29 04:57:14 +00004867{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004868 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004869
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004870 DBGPRINTF3(("QGRAVECHAR: enter, ap=%p, iop=%p\n", ap, iop));
Eric Andersenff9eee42001-06-29 04:57:14 +00004871
4872 if (iop->xchar) {
4873 if (iop->nlcount) {
4874 iop->nlcount--;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004875 return '\n' | QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00004876 }
4877 c = iop->xchar;
4878 iop->xchar = 0;
4879 } else if ((c = filechar(ap)) == '\n') {
4880 iop->nlcount = 1;
4881 while ((c = filechar(ap)) == '\n')
4882 iop->nlcount++;
4883 iop->xchar = c;
4884 if (c == 0)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004885 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004886 iop->nlcount--;
4887 c = '\n';
4888 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004889 return c != 0 ? c | QUOTE : 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004890}
4891
4892/*
4893 * Return a single command (usually the first line) from a file.
4894 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004895static int linechar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004896{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004897 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004898
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004899 c = filechar(ap);
4900 if (c == '\n') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004901 if (!multiline) {
4902 closef(ap->afile);
Eric Andersen8401eea2004-08-04 19:16:54 +00004903 ap->afile = -1; /* illegal value */
Eric Andersenff9eee42001-06-29 04:57:14 +00004904 }
4905 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004906 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004907}
4908
Eric Andersenff9eee42001-06-29 04:57:14 +00004909/*
4910 * remap fd into Shell's fd space
4911 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004912static int remap(int fd)
Eric Andersenff9eee42001-06-29 04:57:14 +00004913{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004914 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004915 int map[NOFILE];
Eric Andersen12de6cf2004-08-04 19:19:10 +00004916 int newfd;
4917
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004918 DBGPRINTF(("REMAP: fd=%d, global_env.iofd=%d\n", fd, global_env.iofd));
Eric Andersenff9eee42001-06-29 04:57:14 +00004919
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004920 if (fd < global_env.iofd) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004921 for (i = 0; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004922 map[i] = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004923
Eric Andersenff9eee42001-06-29 04:57:14 +00004924 do {
4925 map[fd] = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004926 newfd = dup(fd);
4927 fd = newfd;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004928 } while (fd >= 0 && fd < global_env.iofd);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004929
Eric Andersen8401eea2004-08-04 19:16:54 +00004930 for (i = 0; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004931 if (map[i])
4932 close(i);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004933
Eric Andersenff9eee42001-06-29 04:57:14 +00004934 if (fd < 0)
4935 err("too many files open in shell");
4936 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004937
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004938 return fd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004939}
4940
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004941static int openpipe(int *pv)
Eric Andersenff9eee42001-06-29 04:57:14 +00004942{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004943 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004944
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004945 i = pipe(pv);
4946 if (i < 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00004947 err("can't create pipe - try again");
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004948 return i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004949}
4950
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004951static void closepipe(int *pv)
Eric Andersenff9eee42001-06-29 04:57:14 +00004952{
4953 if (pv != NULL) {
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00004954 close(pv[0]);
4955 close(pv[1]);
Eric Andersenff9eee42001-06-29 04:57:14 +00004956 }
4957}
4958
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004959
Eric Andersenff9eee42001-06-29 04:57:14 +00004960/* -------- here.c -------- */
4961
4962/*
4963 * here documents
4964 */
4965
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004966static void markhere(char *s, struct ioword *iop)
Eric Andersenff9eee42001-06-29 04:57:14 +00004967{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004968 struct here *h, *lh;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004969
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004970 DBGPRINTF7(("MARKHERE: enter, s=%p\n", s));
Eric Andersenff9eee42001-06-29 04:57:14 +00004971
4972 h = (struct here *) space(sizeof(struct here));
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004973 if (h == NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00004974 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004975
Eric Andersenff9eee42001-06-29 04:57:14 +00004976 h->h_tag = evalstr(s, DOSUB);
4977 if (h->h_tag == 0)
4978 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004979
Eric Andersenff9eee42001-06-29 04:57:14 +00004980 h->h_iop = iop;
4981 iop->io_name = 0;
4982 h->h_next = NULL;
4983 if (inhere == 0)
4984 inhere = h;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004985 else {
4986 for (lh = inhere; lh != NULL; lh = lh->h_next) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004987 if (lh->h_next == 0) {
4988 lh->h_next = h;
4989 break;
4990 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004991 }
4992 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004993 iop->io_flag |= IOHERE | IOXHERE;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004994 for (s = h->h_tag; *s; s++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004995 if (*s & QUOTE) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004996 iop->io_flag &= ~IOXHERE;
4997 *s &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00004998 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004999 }
Denis Vlasenko648b44f2008-02-12 06:04:06 +00005000 h->h_dosub = ((iop->io_flag & IOXHERE) ? '\0' : '\'');
Eric Andersenff9eee42001-06-29 04:57:14 +00005001}
5002
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005003static void gethere(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00005004{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005005 struct here *h, *hp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005006
5007 DBGPRINTF7(("GETHERE: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00005008
5009 /* Scan here files first leaving inhere list in place */
5010 for (hp = h = inhere; h != NULL; hp = h, h = h->h_next)
Denis Vlasenko648b44f2008-02-12 06:04:06 +00005011 readhere(&h->h_iop->io_name, h->h_tag, h->h_dosub /* NUL or ' */);
Eric Andersenff9eee42001-06-29 04:57:14 +00005012
5013 /* Make inhere list active - keep list intact for scraphere */
5014 if (hp != NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005015 hp->h_next = acthere;
5016 acthere = inhere;
5017 inhere = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00005018 }
5019}
5020
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005021static void readhere(char **name, char *s, int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00005022{
5023 int tf;
5024 char tname[30] = ".msh_XXXXXX";
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005025 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00005026 jmp_buf ev;
Eric Andersen8401eea2004-08-04 19:16:54 +00005027 char myline[LINELIM + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00005028 char *thenext;
5029
Mike Frysinger02d8fa42006-05-05 20:32:31 +00005030 DBGPRINTF7(("READHERE: enter, name=%p, s=%p\n", name, s));
Eric Andersen12de6cf2004-08-04 19:19:10 +00005031
Eric Andersenff9eee42001-06-29 04:57:14 +00005032 tf = mkstemp(tname);
5033 if (tf < 0)
5034 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005035
Eric Andersenff9eee42001-06-29 04:57:14 +00005036 *name = strsave(tname, areanum);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00005037 errpt = ev;
5038 if (newenv(setjmp(errpt)) != 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00005039 unlink(tname);
5040 else {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005041 pushio(global_env.iop->argp, (int (*)(struct ioarg *)) global_env.iop->iofn);
5042 global_env.iobase = global_env.iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00005043 for (;;) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005044 if (interactive && global_env.iop <= iostack) {
Denis Vlasenko38f63192007-01-22 09:03:07 +00005045#if ENABLE_FEATURE_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00005046 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00005047#else
Eric Andersen8401eea2004-08-04 19:16:54 +00005048 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00005049#endif
5050 }
5051 thenext = myline;
5052 while ((c = my_getc(ec)) != '\n' && c) {
5053 if (ec == '\'')
Eric Andersen8401eea2004-08-04 19:16:54 +00005054 c &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00005055 if (thenext >= &myline[LINELIM]) {
5056 c = 0;
5057 break;
5058 }
5059 *thenext++ = c;
5060 }
5061 *thenext = 0;
5062 if (strcmp(s, myline) == 0 || c == 0)
5063 break;
5064 *thenext++ = '\n';
Eric Andersen8401eea2004-08-04 19:16:54 +00005065 write(tf, myline, (int) (thenext - myline));
Eric Andersenff9eee42001-06-29 04:57:14 +00005066 }
5067 if (c == 0) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005068 prs("here document `");
5069 prs(s);
5070 err("' unclosed");
Eric Andersenff9eee42001-06-29 04:57:14 +00005071 }
5072 quitenv();
5073 }
5074 close(tf);
5075}
5076
5077/*
5078 * open here temp file.
5079 * if unquoted here, expand here temp file into second temp file.
5080 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005081static int herein(char *hname, int xdoll)
Eric Andersenff9eee42001-06-29 04:57:14 +00005082{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005083 int hf;
Eric Andersenff9eee42001-06-29 04:57:14 +00005084 int tf;
5085
5086#if __GNUC__
5087 /* Avoid longjmp clobbering */
5088 (void) &tf;
5089#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00005090 if (hname == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00005091 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005092
5093 DBGPRINTF7(("HEREIN: hname is %s, xdoll=%d\n", hname, xdoll));
5094
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005095 hf = open(hname, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00005096 if (hf < 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00005097 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005098
Eric Andersenff9eee42001-06-29 04:57:14 +00005099 if (xdoll) {
5100 char c;
5101 char tname[30] = ".msh_XXXXXX";
5102 jmp_buf ev;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005103
Eric Andersenff9eee42001-06-29 04:57:14 +00005104 tf = mkstemp(tname);
5105 if (tf < 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00005106 return -1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00005107 errpt = ev;
5108 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00005109 PUSHIO(afile, hf, herechar);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005110 setbase(global_env.iop);
Eric Andersenff9eee42001-06-29 04:57:14 +00005111 while ((c = subgetc(0, 0)) != 0) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005112 c &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00005113 write(tf, &c, sizeof c);
5114 }
5115 quitenv();
5116 } else
5117 unlink(tname);
5118 close(tf);
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005119 tf = open(tname, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00005120 unlink(tname);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00005121 return tf;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00005122 }
5123 return hf;
Eric Andersenff9eee42001-06-29 04:57:14 +00005124}
5125
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005126static void scraphere(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00005127{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005128 struct here *h;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005129
5130 DBGPRINTF7(("SCRAPHERE: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00005131
5132 for (h = inhere; h != NULL; h = h->h_next) {
5133 if (h->h_iop && h->h_iop->io_name)
Eric Andersen8401eea2004-08-04 19:16:54 +00005134 unlink(h->h_iop->io_name);
Eric Andersenff9eee42001-06-29 04:57:14 +00005135 }
5136 inhere = NULL;
5137}
5138
5139/* unlink here temp files before a freearea(area) */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005140static void freehere(int area)
Eric Andersenff9eee42001-06-29 04:57:14 +00005141{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005142 struct here *h, *hl;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005143
5144 DBGPRINTF6(("FREEHERE: enter, area=%d\n", area));
Eric Andersenff9eee42001-06-29 04:57:14 +00005145
5146 hl = NULL;
5147 for (h = acthere; h != NULL; h = h->h_next)
5148 if (getarea((char *) h) >= area) {
5149 if (h->h_iop->io_name != NULL)
5150 unlink(h->h_iop->io_name);
5151 if (hl == NULL)
5152 acthere = h->h_next;
5153 else
5154 hl->h_next = h->h_next;
5155 } else
5156 hl = h;
5157}
5158
5159
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005160/* -------- sh.c -------- */
5161/*
5162 * shell
5163 */
5164
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00005165int msh_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005166int msh_main(int argc, char **argv)
5167{
5168 int f;
5169 char *s;
5170 int cflag;
5171 char *name, **ap;
5172 int (*iof) (struct ioarg *);
5173
Denis Vlasenkoab801872007-12-02 08:35:37 +00005174 INIT_G();
5175
Denis Vlasenko55f30b02007-03-24 22:42:29 +00005176 sharedbuf.id = AFID_NOBUF;
5177 mainbuf.id = AFID_NOBUF;
Denis Vlasenko55f30b02007-03-24 22:42:29 +00005178 elinep = line + sizeof(line) - 5;
5179
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005180#if ENABLE_FEATURE_EDITING
5181 line_input_state = new_line_input_t(FOR_SHELL);
5182#endif
5183
5184 DBGPRINTF(("MSH_MAIN: argc %d, environ %p\n", argc, environ));
5185
5186 initarea();
5187 ap = environ;
5188 if (ap != NULL) {
5189 while (*ap)
5190 assign(*ap++, !COPYV);
5191 for (ap = environ; *ap;)
5192 export(lookup(*ap++));
5193 }
5194 closeall();
5195 areanum = 1;
5196
5197 shell = lookup("SHELL");
5198 if (shell->value == null)
5199 setval(shell, (char *)DEFAULT_SHELL);
5200 export(shell);
5201
5202 homedir = lookup("HOME");
5203 if (homedir->value == null)
5204 setval(homedir, "/");
5205 export(homedir);
5206
5207 setval(lookup("$"), putn(getpid()));
5208
5209 path = lookup("PATH");
5210 if (path->value == null) {
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005211 /* Can be merged with same string elsewhere in bbox */
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005212 if (geteuid() == 0)
Denis Vlasenkof5f75c52007-06-12 22:35:19 +00005213 setval(path, bb_default_root_path);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005214 else
Denis Vlasenkof5f75c52007-06-12 22:35:19 +00005215 setval(path, bb_default_path);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005216 }
5217 export(path);
5218
5219 ifs = lookup("IFS");
5220 if (ifs->value == null)
5221 setval(ifs, " \t\n");
5222
5223#ifdef MSHDEBUG
5224 mshdbg_var = lookup("MSHDEBUG");
5225 if (mshdbg_var->value == null)
5226 setval(mshdbg_var, "0");
5227#endif
5228
5229 prompt = lookup("PS1");
5230#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
5231 if (prompt->value == null)
5232#endif
5233 setval(prompt, DEFAULT_USER_PROMPT);
5234 if (geteuid() == 0) {
5235 setval(prompt, DEFAULT_ROOT_PROMPT);
5236 prompt->status &= ~EXPORT;
5237 }
5238 cprompt = lookup("PS2");
5239#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
5240 if (cprompt->value == null)
5241#endif
5242 setval(cprompt, "> ");
5243
5244 iof = filechar;
5245 cflag = 0;
5246 name = *argv++;
5247 if (--argc >= 1) {
5248 if (argv[0][0] == '-' && argv[0][1] != '\0') {
5249 for (s = argv[0] + 1; *s; s++)
5250 switch (*s) {
5251 case 'c':
5252 prompt->status &= ~EXPORT;
5253 cprompt->status &= ~EXPORT;
5254 setval(prompt, "");
5255 setval(cprompt, "");
5256 cflag = 1;
5257 if (--argc > 0)
5258 PUSHIO(aword, *++argv, iof = nlchar);
5259 break;
5260
5261 case 'q':
5262 qflag = SIG_DFL;
5263 break;
5264
5265 case 's':
5266 /* standard input */
5267 break;
5268
5269 case 't':
5270 prompt->status &= ~EXPORT;
5271 setval(prompt, "");
5272 iof = linechar;
5273 break;
5274
5275 case 'i':
Denis Vlasenko648b44f2008-02-12 06:04:06 +00005276 interactive = 1;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005277 default:
5278 if (*s >= 'a' && *s <= 'z')
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00005279 FLAG[(int) *s]++;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005280 }
5281 } else {
5282 argv--;
5283 argc++;
5284 }
5285
5286 if (iof == filechar && --argc > 0) {
5287 setval(prompt, "");
5288 setval(cprompt, "");
5289 prompt->status &= ~EXPORT;
5290 cprompt->status &= ~EXPORT;
5291
5292/* Shell is non-interactive, activate printf-based debug */
5293#ifdef MSHDEBUG
5294 mshdbg = (int) (((char) (mshdbg_var->value[0])) - '0');
5295 if (mshdbg < 0)
5296 mshdbg = 0;
5297#endif
5298 DBGPRINTF(("MSH_MAIN: calling newfile()\n"));
5299
5300 name = *++argv;
5301 if (newfile(name))
5302 exit(1); /* Exit on error */
5303 }
5304 }
5305
5306 setdash();
5307
5308 /* This won't be true if PUSHIO has been called, say from newfile() above */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005309 if (global_env.iop < iostack) {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005310 PUSHIO(afile, 0, iof);
5311 if (isatty(0) && isatty(1) && !cflag) {
Denis Vlasenko648b44f2008-02-12 06:04:06 +00005312 interactive = 1;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005313#if !ENABLE_FEATURE_SH_EXTRA_QUIET
5314#ifdef MSHDEBUG
Denis Vlasenkoca525b42007-06-13 12:27:17 +00005315 printf("\n\n%s built-in shell (msh with debug)\n", bb_banner);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005316#else
Denis Vlasenkoca525b42007-06-13 12:27:17 +00005317 printf("\n\n%s built-in shell (msh)\n", bb_banner);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005318#endif
5319 printf("Enter 'help' for a list of built-in commands.\n\n");
5320#endif
5321 }
5322 }
5323
5324 signal(SIGQUIT, qflag);
5325 if (name && name[0] == '-') {
Denis Vlasenko648b44f2008-02-12 06:04:06 +00005326 interactive = 1;
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005327 f = open(".profile", O_RDONLY);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005328 if (f >= 0)
5329 next(remap(f));
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005330 f = open("/etc/profile", O_RDONLY);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005331 if (f >= 0)
5332 next(remap(f));
5333 }
5334 if (interactive)
5335 signal(SIGTERM, sig);
5336
5337 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
5338 signal(SIGINT, onintr);
Denis Vlasenkofee2d0c2008-02-12 10:12:18 +00005339
5340/* Handle "msh SCRIPT VAR=val params..." */
5341/* Disabled: bash does not do it! */
5342#if 0
5343 argv++;
5344 /* skip leading args of the form VAR=val */
5345 while (*argv && assign(*argv, !COPYV)) {
5346 argc--;
5347 argv++;
5348 }
5349 argv--;
5350#endif
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005351 dolv = argv;
5352 dolc = argc;
5353 dolv[0] = name;
Denis Vlasenkofee2d0c2008-02-12 10:12:18 +00005354
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005355 setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc));
5356
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005357 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 +00005358
5359 for (;;) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005360 if (interactive && global_env.iop <= iostack) {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005361#if ENABLE_FEATURE_EDITING
5362 current_prompt = prompt->value;
5363#else
5364 prs(prompt->value);
5365#endif
5366 }
5367 onecommand();
5368 /* Ensure that getenv("PATH") stays current */
5369 setenv("PATH", path->value, 1);
5370 }
5371
5372 DBGPRINTF(("MSH_MAIN: returning.\n"));
5373}
5374
5375
Eric Andersenff9eee42001-06-29 04:57:14 +00005376/*
5377 * Copyright (c) 1987,1997, Prentice Hall
5378 * All rights reserved.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005379 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005380 * Redistribution and use of the MINIX operating system in source and
5381 * binary forms, with or without modification, are permitted provided
5382 * that the following conditions are met:
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005383 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005384 * Redistributions of source code must retain the above copyright
5385 * notice, this list of conditions and the following disclaimer.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005386 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005387 * Redistributions in binary form must reproduce the above
5388 * copyright notice, this list of conditions and the following
5389 * disclaimer in the documentation and/or other materials provided
5390 * with the distribution.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005391 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005392 * Neither the name of Prentice Hall nor the names of the software
5393 * authors or contributors may be used to endorse or promote
5394 * products derived from this software without specific prior
5395 * written permission.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005396 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005397 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND
5398 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
5399 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
5400 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
5401 * IN NO EVENT SHALL PRENTICE HALL OR ANY AUTHORS OR CONTRIBUTORS BE
5402 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
5403 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
5404 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
5405 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
5406 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
5407 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
5408 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5409 *
5410 */