blob: 7371120cab73acc06fac65eabc547b3648981343 [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)
45# define NOT_LONE_DASH(s) ((s)[0] != '-' || (s)[1])
46# define LONE_CHAR(s,c) ((s)[0] == (c) && !(s)[1])
47# define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__))
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000048static int find_applet_by_name(const char *applet)
Mike Frysinger67a32ad2007-03-09 08:25:24 +000049{
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000050 return -1;
Mike Frysinger67a32ad2007-03-09 08:25:24 +000051}
Denis Vlasenko10457b92007-03-27 22:01:31 +000052static char *utoa_to_buf(unsigned n, char *buf, unsigned buflen)
Mike Frysinger67a32ad2007-03-09 08:25:24 +000053{
Denis Vlasenkoc86e0522007-03-20 11:30:28 +000054 unsigned i, out, res;
55 assert(sizeof(unsigned) == 4);
56 if (buflen) {
57 out = 0;
58 for (i = 1000000000; i; i /= 10) {
59 res = n / i;
60 if (res || out || i == 1) {
Denis Vlasenko4b924f32007-05-30 00:29:55 +000061 if (!--buflen) break;
62 out++;
63 n -= res*i;
64 *buf++ = '0' + res;
Denis Vlasenkoc86e0522007-03-20 11:30:28 +000065 }
66 }
Denis Vlasenkoc86e0522007-03-20 11:30:28 +000067 }
Denis Vlasenko10457b92007-03-27 22:01:31 +000068 return buf;
Mike Frysinger67a32ad2007-03-09 08:25:24 +000069}
Denis Vlasenko10457b92007-03-27 22:01:31 +000070static char *itoa_to_buf(int n, char *buf, unsigned buflen)
Mike Frysinger67a32ad2007-03-09 08:25:24 +000071{
Denis Vlasenkoc86e0522007-03-20 11:30:28 +000072 if (buflen && n < 0) {
73 n = -n;
74 *buf++ = '-';
75 buflen--;
76 }
Denis Vlasenko10457b92007-03-27 22:01:31 +000077 return utoa_to_buf((unsigned)n, buf, buflen);
Mike Frysinger67a32ad2007-03-09 08:25:24 +000078}
79static char local_buf[12];
80static char *itoa(int n)
81{
Denis Vlasenko10457b92007-03-27 22:01:31 +000082 *(itoa_to_buf(n, local_buf, sizeof(local_buf))) = '\0';
Denis Vlasenkoc86e0522007-03-20 11:30:28 +000083 return local_buf;
Mike Frysinger67a32ad2007-03-09 08:25:24 +000084}
85#else
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000086# include "busybox.h" /* for applet_names */
Mike Frysinger67a32ad2007-03-09 08:25:24 +000087#endif
Eric Andersenff9eee42001-06-29 04:57:14 +000088
Mike Frysinger17811882006-05-05 20:33:07 +000089/*#define MSHDEBUG 1*/
Eric Andersen12de6cf2004-08-04 19:19:10 +000090
91#ifdef MSHDEBUG
Mike Frysinger14ff19b2006-06-20 20:37:01 +000092int mshdbg = MSHDEBUG;
Eric Andersen12de6cf2004-08-04 19:19:10 +000093
Denis Vlasenko51742f42007-04-12 00:32:05 +000094#define DBGPRINTF(x) if (mshdbg>0) printf x
95#define DBGPRINTF0(x) if (mshdbg>0) printf x
96#define DBGPRINTF1(x) if (mshdbg>1) printf x
97#define DBGPRINTF2(x) if (mshdbg>2) printf x
98#define DBGPRINTF3(x) if (mshdbg>3) printf x
99#define DBGPRINTF4(x) if (mshdbg>4) printf x
100#define DBGPRINTF5(x) if (mshdbg>5) printf x
101#define DBGPRINTF6(x) if (mshdbg>6) printf x
102#define DBGPRINTF7(x) if (mshdbg>7) printf x
103#define DBGPRINTF8(x) if (mshdbg>8) printf x
104#define DBGPRINTF9(x) if (mshdbg>9) printf x
Eric Andersen12de6cf2004-08-04 19:19:10 +0000105
106int mshdbg_rc = 0;
107
Denis Vlasenko51742f42007-04-12 00:32:05 +0000108#define RCPRINTF(x) if (mshdbg_rc) printf x
Eric Andersen12de6cf2004-08-04 19:19:10 +0000109
110#else
111
112#define DBGPRINTF(x)
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000113#define DBGPRINTF0(x) ((void)0)
114#define DBGPRINTF1(x) ((void)0)
115#define DBGPRINTF2(x) ((void)0)
116#define DBGPRINTF3(x) ((void)0)
117#define DBGPRINTF4(x) ((void)0)
118#define DBGPRINTF5(x) ((void)0)
119#define DBGPRINTF6(x) ((void)0)
120#define DBGPRINTF7(x) ((void)0)
121#define DBGPRINTF8(x) ((void)0)
122#define DBGPRINTF9(x) ((void)0)
Eric Andersen12de6cf2004-08-04 19:19:10 +0000123
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000124#define RCPRINTF(x) ((void)0)
Eric Andersen12de6cf2004-08-04 19:19:10 +0000125
126#endif /* MSHDEBUG */
127
128
Denis Vlasenko38f63192007-01-22 09:03:07 +0000129#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
Mike Frysinger2a131752006-06-06 06:26:12 +0000130# define DEFAULT_ROOT_PROMPT "\\u:\\w> "
131# define DEFAULT_USER_PROMPT "\\u:\\w$ "
132#else
133# define DEFAULT_ROOT_PROMPT "# "
134# define DEFAULT_USER_PROMPT "$ "
135#endif
136
137
Eric Andersenff9eee42001-06-29 04:57:14 +0000138/* -------- sh.h -------- */
139/*
140 * shell
141 */
142
Eric Andersen12de6cf2004-08-04 19:19:10 +0000143#define LINELIM 2100
144#define NPUSH 8 /* limit to input nesting */
Eric Andersenff9eee42001-06-29 04:57:14 +0000145
Eric Andersen392947c2002-12-11 07:42:46 +0000146#undef NOFILE
Eric Andersen12de6cf2004-08-04 19:19:10 +0000147#define NOFILE 20 /* Number of open files */
148#define NUFILE 10 /* Number of user-accessible files */
149#define FDBASE 10 /* First file usable by Shell */
Eric Andersenff9eee42001-06-29 04:57:14 +0000150
151/*
152 * values returned by wait
153 */
Denis Vlasenko5f9468e2007-04-14 13:22:09 +0000154#define WAITSIG(s) ((s) & 0177)
155#define WAITVAL(s) (((s) >> 8) & 0377)
156#define WAITCORE(s) (((s) & 0200) != 0)
Eric Andersenff9eee42001-06-29 04:57:14 +0000157
158/*
Eric Andersenaff114c2004-04-14 17:51:38 +0000159 * library and system definitions
Eric Andersenff9eee42001-06-29 04:57:14 +0000160 */
Eric Andersen8401eea2004-08-04 19:16:54 +0000161typedef void xint; /* base type of jmp_buf, for not broken compilers */
Eric Andersenff9eee42001-06-29 04:57:14 +0000162
163/*
164 * shell components
165 */
Eric Andersenff9eee42001-06-29 04:57:14 +0000166#define NOBLOCK ((struct op *)NULL)
167#define NOWORD ((char *)NULL)
168#define NOWORDS ((char **)NULL)
169#define NOPIPE ((int *)NULL)
170
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000171/*
172 * redirection
173 */
174struct ioword {
175 short io_unit; /* unit affected */
176 short io_flag; /* action (below) */
177 char *io_name; /* file name */
178};
179
180#define IOREAD 1 /* < */
181#define IOHERE 2 /* << (here file) */
182#define IOWRITE 4 /* > */
183#define IOCAT 8 /* >> */
184#define IOXHERE 16 /* ${}, ` in << */
185#define IODUP 32 /* >&digit */
186#define IOCLOSE 64 /* >&- */
187
188#define IODEFAULT (-1) /* token for default IO unit */
189
190
Eric Andersenff9eee42001-06-29 04:57:14 +0000191/*
192 * Description of a command or an operation on commands.
193 * Might eventually use a union.
194 */
195struct op {
Eric Andersen8401eea2004-08-04 19:16:54 +0000196 int type; /* operation type, see below */
197 char **words; /* arguments to a command */
198 struct ioword **ioact; /* IO actions (eg, < > >>) */
Eric Andersenff9eee42001-06-29 04:57:14 +0000199 struct op *left;
200 struct op *right;
Eric Andersen8401eea2004-08-04 19:16:54 +0000201 char *str; /* identifier for case and for */
Eric Andersenff9eee42001-06-29 04:57:14 +0000202};
203
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000204#define TCOM 1 /* command */
205#define TPAREN 2 /* (c-list) */
206#define TPIPE 3 /* a | b */
207#define TLIST 4 /* a [&;] b */
208#define TOR 5 /* || */
209#define TAND 6 /* && */
210#define TFOR 7
211#define TDO 8
212#define TCASE 9
213#define TIF 10
214#define TWHILE 11
215#define TUNTIL 12
216#define TELIF 13
217#define TPAT 14 /* pattern in case */
218#define TBRACE 15 /* {c-list} */
219#define TASYNC 16 /* c & */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000220/* Added to support "." file expansion */
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000221#define TDOT 17
Eric Andersen12de6cf2004-08-04 19:19:10 +0000222
223/* Strings for names to make debug easier */
"Vladimir N. Oleynik"ac973172005-09-22 14:38:17 +0000224#ifdef MSHDEBUG
Denis Vlasenkoe27f1562007-01-01 06:00:38 +0000225static const char *const T_CMD_NAMES[] = {
Eric Andersen12de6cf2004-08-04 19:19:10 +0000226 "PLACEHOLDER",
227 "TCOM",
228 "TPAREN",
229 "TPIPE",
230 "TLIST",
231 "TOR",
232 "TAND",
233 "TFOR",
234 "TDO",
235 "TCASE",
236 "TIF",
237 "TWHILE",
238 "TUNTIL",
239 "TELIF",
240 "TPAT",
241 "TBRACE",
242 "TASYNC",
243 "TDOT",
244};
"Vladimir N. Oleynik"ac973172005-09-22 14:38:17 +0000245#endif
Eric Andersenff9eee42001-06-29 04:57:14 +0000246
247/*
248 * actions determining the environment of a process
249 */
Denis Vlasenko5f9468e2007-04-14 13:22:09 +0000250#define FEXEC 1 /* execute without forking */
Eric Andersenff9eee42001-06-29 04:57:14 +0000251
Denis Vlasenko5f9468e2007-04-14 13:22:09 +0000252#define AREASIZE (90000)
Eric Andersen12de6cf2004-08-04 19:19:10 +0000253
Eric Andersenff9eee42001-06-29 04:57:14 +0000254/*
255 * flags to control evaluation of words
256 */
Denis Vlasenko5f9468e2007-04-14 13:22:09 +0000257#define DOSUB 1 /* interpret $, `, and quotes */
258#define DOBLANK 2 /* perform blank interpretation */
259#define DOGLOB 4 /* interpret [?* */
260#define DOKEY 8 /* move words with `=' to 2nd arg. list */
261#define DOTRIM 16 /* trim resulting string */
Eric Andersenff9eee42001-06-29 04:57:14 +0000262
Denis Vlasenko5f9468e2007-04-14 13:22:09 +0000263#define DOALL (DOSUB|DOBLANK|DOGLOB|DOKEY|DOTRIM)
Eric Andersenff9eee42001-06-29 04:57:14 +0000264
Eric Andersenff9eee42001-06-29 04:57:14 +0000265
Eric Andersen8401eea2004-08-04 19:16:54 +0000266struct brkcon {
267 jmp_buf brkpt;
268 struct brkcon *nextlev;
269};
Eric Andersenff9eee42001-06-29 04:57:14 +0000270
Eric Andersen12de6cf2004-08-04 19:19:10 +0000271
Eric Andersen8401eea2004-08-04 19:16:54 +0000272static int trapset; /* trap pending */
Eric Andersenff9eee42001-06-29 04:57:14 +0000273
Eric Andersen8401eea2004-08-04 19:16:54 +0000274static int yynerrs; /* yacc */
Eric Andersenff9eee42001-06-29 04:57:14 +0000275
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000276/* moved to G: static char line[LINELIM]; */
Eric Andersenff9eee42001-06-29 04:57:14 +0000277
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000278#if ENABLE_FEATURE_EDITING
279static char *current_prompt;
280static line_input_t *line_input_state;
281#endif
282
Eric Andersen12de6cf2004-08-04 19:19:10 +0000283
Eric Andersenff9eee42001-06-29 04:57:14 +0000284/*
285 * other functions
286 */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000287static const char *rexecve(char *c, char **v, char **envp);
Eric Andersen8401eea2004-08-04 19:16:54 +0000288static char *evalstr(char *cp, int f);
289static char *putn(int n);
Eric Andersen8401eea2004-08-04 19:16:54 +0000290static char *unquote(char *as);
Eric Andersen8401eea2004-08-04 19:16:54 +0000291static int rlookup(char *n);
292static struct wdblock *glob(char *cp, struct wdblock *wb);
293static int my_getc(int ec);
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +0000294static int subgetc(char ec, int quoted);
Eric Andersenfd7a4c82004-09-02 23:13:10 +0000295static char **makenv(int all, struct wdblock *wb);
Eric Andersen8401eea2004-08-04 19:16:54 +0000296static char **eval(char **ap, int f);
297static int setstatus(int s);
298static int waitfor(int lastpid, int canintr);
Eric Andersenff9eee42001-06-29 04:57:14 +0000299
Eric Andersen8401eea2004-08-04 19:16:54 +0000300static void onintr(int s); /* SIGINT handler */
Eric Andersenff9eee42001-06-29 04:57:14 +0000301
Eric Andersen8401eea2004-08-04 19:16:54 +0000302static int newenv(int f);
303static void quitenv(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000304static void next(int f);
305static void setdash(void);
306static void onecommand(void);
307static void runtrap(int i);
Eric Andersenff9eee42001-06-29 04:57:14 +0000308
Eric Andersen12de6cf2004-08-04 19:19:10 +0000309
Eric Andersenff9eee42001-06-29 04:57:14 +0000310/* -------- area stuff -------- */
311
Denis Vlasenko5f9468e2007-04-14 13:22:09 +0000312#define REGSIZE sizeof(struct region)
313#define GROWBY (256)
314/* #define SHRINKBY (64) */
315#undef SHRINKBY
316#define FREE (32767)
317#define BUSY (0)
318#define ALIGN (sizeof(int)-1)
Eric Andersenff9eee42001-06-29 04:57:14 +0000319
320
321struct region {
Eric Andersen8401eea2004-08-04 19:16:54 +0000322 struct region *next;
323 int area;
Eric Andersenff9eee42001-06-29 04:57:14 +0000324};
325
326
Eric Andersenff9eee42001-06-29 04:57:14 +0000327/* -------- grammar stuff -------- */
328typedef union {
Eric Andersen8401eea2004-08-04 19:16:54 +0000329 char *cp;
330 char **wp;
331 int i;
332 struct op *o;
Eric Andersenff9eee42001-06-29 04:57:14 +0000333} YYSTYPE;
Eric Andersen8401eea2004-08-04 19:16:54 +0000334
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000335#define WORD 256
336#define LOGAND 257
337#define LOGOR 258
338#define BREAK 259
339#define IF 260
340#define THEN 261
341#define ELSE 262
342#define ELIF 263
343#define FI 264
344#define CASE 265
345#define ESAC 266
346#define FOR 267
347#define WHILE 268
348#define UNTIL 269
349#define DO 270
350#define DONE 271
351#define IN 272
Eric Andersen12de6cf2004-08-04 19:19:10 +0000352/* Added for "." file expansion */
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000353#define DOT 273
Eric Andersen12de6cf2004-08-04 19:19:10 +0000354
Eric Andersenff9eee42001-06-29 04:57:14 +0000355#define YYERRCODE 300
356
357/* flags to yylex */
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000358#define CONTIN 01 /* skip new lines to complete command */
Eric Andersenff9eee42001-06-29 04:57:14 +0000359
Eric Andersen8401eea2004-08-04 19:16:54 +0000360static struct op *pipeline(int cf);
Eric Andersenff9eee42001-06-29 04:57:14 +0000361static struct op *andor(void);
362static struct op *c_list(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000363static int synio(int cf);
364static void musthave(int c, int cf);
Eric Andersenff9eee42001-06-29 04:57:14 +0000365static struct op *simple(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000366static struct op *nested(int type, int mark);
367static struct op *command(int cf);
368static struct op *dogroup(int onlydone);
Eric Andersenff9eee42001-06-29 04:57:14 +0000369static struct op *thenpart(void);
370static struct op *elsepart(void);
371static struct op *caselist(void);
372static struct op *casepart(void);
373static char **pattern(void);
374static char **wordlist(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000375static struct op *list(struct op *t1, struct op *t2);
376static struct op *block(int type, struct op *t1, struct op *t2, char **wp);
Eric Andersenff9eee42001-06-29 04:57:14 +0000377static struct op *newtp(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000378static struct op *namelist(struct op *t);
Eric Andersenff9eee42001-06-29 04:57:14 +0000379static char **copyw(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000380static void word(char *cp);
Eric Andersenff9eee42001-06-29 04:57:14 +0000381static struct ioword **copyio(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000382static struct ioword *io(int u, int f, char *cp);
Eric Andersen8401eea2004-08-04 19:16:54 +0000383static int yylex(int cf);
384static int collect(int c, int c1);
385static int dual(int c);
386static void diag(int ec);
387static char *tree(unsigned size);
Eric Andersenff9eee42001-06-29 04:57:14 +0000388
389/* -------- var.h -------- */
390
Eric Andersen8401eea2004-08-04 19:16:54 +0000391struct var {
392 char *value;
393 char *name;
394 struct var *next;
395 char status;
Eric Andersenff9eee42001-06-29 04:57:14 +0000396};
Eric Andersenff9eee42001-06-29 04:57:14 +0000397
Eric Andersen8401eea2004-08-04 19:16:54 +0000398#define COPYV 1 /* flag to setval, suggesting copy */
399#define RONLY 01 /* variable is read-only */
400#define EXPORT 02 /* variable is to be exported */
401#define GETCELL 04 /* name & value space was got with getcell */
Eric Andersenff9eee42001-06-29 04:57:14 +0000402
Eric Andersen8401eea2004-08-04 19:16:54 +0000403static int yyparse(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000404
405static int execute(struct op *t, int *pin, int *pout, int act);
Eric Andersenff9eee42001-06-29 04:57:14 +0000406
Eric Andersen12de6cf2004-08-04 19:19:10 +0000407
Eric Andersenff9eee42001-06-29 04:57:14 +0000408/* -------- io.h -------- */
409/* io buffer */
410struct iobuf {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000411 unsigned id; /* buffer id */
412 char buf[512]; /* buffer */
413 char *bufp; /* pointer into buffer */
414 char *ebufp; /* pointer to end of buffer */
Eric Andersenff9eee42001-06-29 04:57:14 +0000415};
416
417/* possible arguments to an IO function */
418struct ioarg {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000419 const char *aword;
Eric Andersen8401eea2004-08-04 19:16:54 +0000420 char **awordlist;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000421 int afile; /* file descriptor */
422 unsigned afid; /* buffer id */
423 long afpos; /* file position */
424 struct iobuf *afbuf; /* buffer for this file */
Eric Andersenff9eee42001-06-29 04:57:14 +0000425};
Eric Andersen8401eea2004-08-04 19:16:54 +0000426
Eric Andersenff9eee42001-06-29 04:57:14 +0000427/* an input generator's state */
Eric Andersen8401eea2004-08-04 19:16:54 +0000428struct io {
429 int (*iofn) (struct ioarg *, struct io *);
430 struct ioarg *argp;
431 int peekc;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000432 char prev; /* previous character read by readc() */
433 char nlcount; /* for `'s */
434 char xchar; /* for `'s */
435 char task; /* reason for pushed IO */
Eric Andersenff9eee42001-06-29 04:57:14 +0000436};
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000437/* ->task: */
438#define XOTHER 0 /* none of the below */
439#define XDOLL 1 /* expanding ${} */
440#define XGRAVE 2 /* expanding `'s */
441#define XIO 3 /* file IO */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000442
443
444/*
Eric Andersenff9eee42001-06-29 04:57:14 +0000445 * input generators for IO structure
446 */
Eric Andersen8401eea2004-08-04 19:16:54 +0000447static int nlchar(struct ioarg *ap);
448static int strchar(struct ioarg *ap);
449static int qstrchar(struct ioarg *ap);
450static int filechar(struct ioarg *ap);
451static int herechar(struct ioarg *ap);
452static int linechar(struct ioarg *ap);
453static int gravechar(struct ioarg *ap, struct io *iop);
454static int qgravechar(struct ioarg *ap, struct io *iop);
455static int dolchar(struct ioarg *ap);
456static int wdchar(struct ioarg *ap);
457static void scraphere(void);
458static void freehere(int area);
459static void gethere(void);
460static void markhere(char *s, struct ioword *iop);
461static int herein(char *hname, int xdoll);
462static int run(struct ioarg *argp, int (*f) (struct ioarg *));
Eric Andersenff9eee42001-06-29 04:57:14 +0000463
Eric Andersen12de6cf2004-08-04 19:19:10 +0000464
Eric Andersen8401eea2004-08-04 19:16:54 +0000465static int eofc(void);
466static int readc(void);
467static void unget(int c);
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +0000468static void ioecho(char c);
Eric Andersenff9eee42001-06-29 04:57:14 +0000469
Eric Andersen12de6cf2004-08-04 19:19:10 +0000470
Eric Andersenff9eee42001-06-29 04:57:14 +0000471/*
472 * IO control
473 */
Eric Andersen8401eea2004-08-04 19:16:54 +0000474static void pushio(struct ioarg *argp, int (*f) (struct ioarg *));
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000475#define PUSHIO(what,arg,gen) ((temparg.what = (arg)), pushio(&temparg,(gen)))
Eric Andersen8401eea2004-08-04 19:16:54 +0000476static int remap(int fd);
477static int openpipe(int *pv);
478static void closepipe(int *pv);
479static struct io *setbase(struct io *ip);
Eric Andersenff9eee42001-06-29 04:57:14 +0000480
Eric Andersenff9eee42001-06-29 04:57:14 +0000481/* -------- word.h -------- */
482
Eric Andersen8401eea2004-08-04 19:16:54 +0000483#define NSTART 16 /* default number of words to allow for initially */
Eric Andersenff9eee42001-06-29 04:57:14 +0000484
Eric Andersen8401eea2004-08-04 19:16:54 +0000485struct wdblock {
486 short w_bsize;
487 short w_nword;
Eric Andersenff9eee42001-06-29 04:57:14 +0000488 /* bounds are arbitrary */
Eric Andersen8401eea2004-08-04 19:16:54 +0000489 char *w_words[1];
Eric Andersenff9eee42001-06-29 04:57:14 +0000490};
491
Eric Andersen8401eea2004-08-04 19:16:54 +0000492static struct wdblock *addword(char *wd, struct wdblock *wb);
493static struct wdblock *newword(int nw);
494static char **getwords(struct wdblock *wb);
Eric Andersenff9eee42001-06-29 04:57:14 +0000495
Eric Andersenff9eee42001-06-29 04:57:14 +0000496/* -------- misc stuff -------- */
497
Eric Andersen12de6cf2004-08-04 19:19:10 +0000498static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp);
Eric Andersen8401eea2004-08-04 19:16:54 +0000499static int iosetup(struct ioword *iop, int pipein, int pipeout);
Eric Andersen8401eea2004-08-04 19:16:54 +0000500static void brkset(struct brkcon *bc);
501static int dolabel(struct op *t);
502static int dohelp(struct op *t);
503static int dochdir(struct op *t);
504static int doshift(struct op *t);
505static int dologin(struct op *t);
506static int doumask(struct op *t);
507static int doexec(struct op *t);
508static int dodot(struct op *t);
509static int dowait(struct op *t);
510static int doread(struct op *t);
511static int doeval(struct op *t);
512static int dotrap(struct op *t);
513static int getsig(char *s);
514static void setsig(int n, sighandler_t f);
515static int getn(char *as);
516static int dobreak(struct op *t);
517static int docontinue(struct op *t);
518static int brkcontin(char *cp, int val);
519static int doexit(struct op *t);
520static int doexport(struct op *t);
521static int doreadonly(struct op *t);
522static void rdexp(char **wp, void (*f) (struct var *), int key);
523static void badid(char *s);
524static int doset(struct op *t);
525static void varput(char *s, int out);
526static int dotimes(struct op *t);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000527static int expand(const char *cp, struct wdblock **wbp, int f);
Eric Andersen8401eea2004-08-04 19:16:54 +0000528static char *blank(int f);
529static int dollar(int quoted);
530static int grave(int quoted);
531static void globname(char *we, char *pp);
532static char *generate(char *start1, char *end1, char *middle, char *end);
533static int anyspcl(struct wdblock *wb);
534static int xstrcmp(char *p1, char *p2);
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000535static void glob0(char *a0, unsigned a1, int a2,
Eric Andersen8401eea2004-08-04 19:16:54 +0000536 int (*a3) (char *, char *));
Eric Andersen8401eea2004-08-04 19:16:54 +0000537static void readhere(char **name, char *s, int ec);
Eric Andersen8401eea2004-08-04 19:16:54 +0000538static int xxchar(struct ioarg *ap);
Eric Andersenff9eee42001-06-29 04:57:14 +0000539
Eric Andersen8401eea2004-08-04 19:16:54 +0000540struct here {
541 char *h_tag;
542 int h_dosub;
543 struct ioword *h_iop;
544 struct here *h_next;
Eric Andersenff9eee42001-06-29 04:57:14 +0000545};
546
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000547static const char *const signame[] = {
Eric Andersenff9eee42001-06-29 04:57:14 +0000548 "Signal 0",
549 "Hangup",
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000550 NULL, /* interrupt */
Eric Andersenff9eee42001-06-29 04:57:14 +0000551 "Quit",
552 "Illegal instruction",
553 "Trace/BPT trap",
554 "Abort",
555 "Bus error",
556 "Floating Point Exception",
557 "Killed",
558 "SIGUSR1",
559 "SIGSEGV",
560 "SIGUSR2",
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000561 NULL, /* broken pipe */
Eric Andersenff9eee42001-06-29 04:57:14 +0000562 "Alarm clock",
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000563 "Terminated"
Eric Andersenff9eee42001-06-29 04:57:14 +0000564};
Eric Andersen8401eea2004-08-04 19:16:54 +0000565
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000566
Eric Andersen1c039232001-07-07 00:05:55 +0000567struct builtincmd {
568 const char *name;
Denis Vlasenko95cb3262007-04-09 03:06:34 +0000569 int (*builtinfunc)(struct op *t);
Eric Andersenff9eee42001-06-29 04:57:14 +0000570};
Eric Andersen8401eea2004-08-04 19:16:54 +0000571static const struct builtincmd builtincmds[] = {
Denis Vlasenko95cb3262007-04-09 03:06:34 +0000572 { "." , dodot },
573 { ":" , dolabel },
574 { "break" , dobreak },
575 { "cd" , dochdir },
576 { "continue", docontinue },
577 { "eval" , doeval },
578 { "exec" , doexec },
579 { "exit" , doexit },
580 { "export" , doexport },
581 { "help" , dohelp },
582 { "login" , dologin },
583 { "newgrp" , dologin },
584 { "read" , doread },
585 { "readonly", doreadonly },
586 { "set" , doset },
587 { "shift" , doshift },
588 { "times" , dotimes },
589 { "trap" , dotrap },
590 { "umask" , doumask },
591 { "wait" , dowait },
592 { NULL , NULL },
Eric Andersenff9eee42001-06-29 04:57:14 +0000593};
594
"Vladimir N. Oleynik"ac973172005-09-22 14:38:17 +0000595static struct op *scantree(struct op *);
Eric Andersen12de6cf2004-08-04 19:19:10 +0000596static struct op *dowholefile(int, int);
597
Eric Andersen12de6cf2004-08-04 19:19:10 +0000598
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000599/* Globals */
Eric Andersen8401eea2004-08-04 19:16:54 +0000600static char **dolv;
601static int dolc;
602static int exstat;
603static char gflg;
"Vladimir N. Oleynik"485d7cb2005-10-17 09:48:57 +0000604static int interactive; /* Is this an interactive shell */
Eric Andersen8401eea2004-08-04 19:16:54 +0000605static int execflg;
606static int multiline; /* \n changed to ; */
607static struct op *outtree; /* result from parser */
608static xint *failpt;
609static xint *errpt;
610static struct brkcon *brklist;
611static int isbreak;
612static struct wdblock *wdlist;
613static struct wdblock *iolist;
Eric Andersen12de6cf2004-08-04 19:19:10 +0000614
615#ifdef MSHDEBUG
616static struct var *mshdbg_var;
617#endif
Eric Andersen8401eea2004-08-04 19:16:54 +0000618static struct var *vlist; /* dictionary */
619static struct var *homedir; /* home directory */
620static struct var *prompt; /* main prompt */
621static struct var *cprompt; /* continuation prompt */
622static struct var *path; /* search path for commands */
623static struct var *shell; /* shell to interpret command files */
624static struct var *ifs; /* field separators */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000625
Denis Vlasenko95cb3262007-04-09 03:06:34 +0000626static int areanum; /* current allocation area */
627static int intr; /* interrupt pending */
Eric Andersen8401eea2004-08-04 19:16:54 +0000628static int inparse;
Denis Vlasenko95cb3262007-04-09 03:06:34 +0000629static char *null = (char*)""; /* null value for variable */
630static int heedint = 1; /* heed interrupt signals */
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +0000631static void (*qflag)(int) = SIG_IGN;
Eric Andersen8401eea2004-08-04 19:16:54 +0000632static int startl;
633static int peeksym;
634static int nlseen;
635static int iounit = IODEFAULT;
636static YYSTYPE yylval;
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000637static char *elinep; /* done in main(): = line + sizeof(line) - 5 */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000638
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000639static struct here *inhere; /* list of hear docs while parsing */
640static struct here *acthere; /* list of active here documents */
641static struct region *areabot; /* bottom of area */
642static struct region *areatop; /* top of area */
643static struct region *areanxt; /* starting point of scan */
Eric Andersen8401eea2004-08-04 19:16:54 +0000644static void *brktop;
645static void *brkaddr;
Eric Andersenff9eee42001-06-29 04:57:14 +0000646
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000647#define AFID_NOBUF (~0)
648#define AFID_ID 0
649
650
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000651/*
652 * parsing & execution environment
653 */
654struct env {
655 char *linep;
656 struct io *iobase;
657 struct io *iop;
658 xint *errpt; /* void * */
659 int iofd;
660 struct env *oenv;
661};
662
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000663
664struct globals {
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000665 struct env global_env;
666 struct ioarg temparg; // = { .afid = AFID_NOBUF }; /* temporary for PUSHIO */
667 unsigned bufid; // = AFID_ID; /* buffer id counter */
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000668 char ourtrap[_NSIG + 1];
669 char *trap[_NSIG + 1];
670 struct iobuf sharedbuf; /* in main(): set to { AFID_NOBUF } */
671 struct iobuf mainbuf; /* in main(): set to { AFID_NOBUF } */
672 struct ioarg ioargstack[NPUSH];
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000673 /*
674 * flags:
675 * -e: quit on error
676 * -k: look for name=value everywhere on command line
677 * -n: no execution
678 * -t: exit after reading and executing one command
679 * -v: echo as read
680 * -x: trace
681 * -u: unset variables net diagnostic
682 */
683 char flags['z' - 'a' + 1];
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000684 char filechar_cmdbuf[BUFSIZ];
685 char line[LINELIM];
686 char child_cmd[LINELIM];
Denis Vlasenkoab801872007-12-02 08:35:37 +0000687
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000688 struct io iostack[NPUSH];
689
Denis Vlasenkoab801872007-12-02 08:35:37 +0000690 char grave__var_name[LINELIM];
691 char grave__alt_value[LINELIM];
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000692};
693
694#define G (*ptr_to_globals)
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000695#define global_env (G.global_env )
696#define temparg (G.temparg )
697#define bufid (G.bufid )
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000698#define ourtrap (G.ourtrap )
699#define trap (G.trap )
700#define sharedbuf (G.sharedbuf )
701#define mainbuf (G.mainbuf )
702#define ioargstack (G.ioargstack )
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000703/* this looks weird, but is OK ... we index FLAG with 'a'...'z' */
704#define FLAG (G.flags - 'a' )
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000705#define filechar_cmdbuf (G.filechar_cmdbuf)
706#define line (G.line )
707#define child_cmd (G.child_cmd )
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000708#define iostack (G.iostack )
Denis Vlasenkoab801872007-12-02 08:35:37 +0000709#define INIT_G() do { \
710 PTR_TO_GLOBALS = xzalloc(sizeof(G)); \
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000711 global_env.linep = line; \
712 global_env.iobase = iostack; \
713 global_env.iop = iostack - 1; \
714 global_env.iofd = FDBASE; \
715 temparg.afid = AFID_NOBUF; \
716 bufid = AFID_ID; \
Denis Vlasenkoab801872007-12-02 08:35:37 +0000717} while (0)
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000718
719
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000720/* in substitution */
721#define INSUB() (global_env.iop->task == XGRAVE || global_env.iop->task == XDOLL)
722
723#define RUN(what, arg, gen) ((temparg.what = (arg)), run(&temparg, (gen)))
724
Eric Andersen12de6cf2004-08-04 19:19:10 +0000725#ifdef MSHDEBUG
726void print_t(struct op *t)
727{
Mike Frysinger02d8fa42006-05-05 20:32:31 +0000728 DBGPRINTF(("T: t=%p, type %s, words=%p, IOword=%p\n", t,
729 T_CMD_NAMES[t->type], t->words, t->ioact));
Eric Andersen12de6cf2004-08-04 19:19:10 +0000730
731 if (t->words) {
732 DBGPRINTF(("T: W1: %s", t->words[0]));
733 }
Eric Andersen12de6cf2004-08-04 19:19:10 +0000734}
735
736void print_tree(struct op *head)
737{
738 if (head == NULL) {
739 DBGPRINTF(("PRINT_TREE: no tree\n"));
740 return;
741 }
742
Mike Frysinger02d8fa42006-05-05 20:32:31 +0000743 DBGPRINTF(("NODE: %p, left %p, right %p\n", head, head->left,
Eric Andersen12de6cf2004-08-04 19:19:10 +0000744 head->right));
745
746 if (head->left)
747 print_tree(head->left);
748
749 if (head->right)
750 print_tree(head->right);
Eric Andersen12de6cf2004-08-04 19:19:10 +0000751}
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000752#endif /* MSHDEBUG */
753
754
755/*
756 * IO functions
757 */
758static void prs(const char *s)
759{
760 if (*s)
761 write(2, s, strlen(s));
762}
763
764static void prn(unsigned u)
765{
766 prs(itoa(u));
767}
768
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000769static void echo(char **wp)
770{
771 int i;
772
773 prs("+");
774 for (i = 0; wp[i]; i++) {
775 if (i)
776 prs(" ");
777 prs(wp[i]);
778 }
779 prs("\n");
780}
781
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000782static void closef(int i)
783{
784 if (i > 2)
785 close(i);
786}
787
788static void closeall(void)
789{
790 int u;
791
792 for (u = NUFILE; u < NOFILE;)
793 close(u++);
794}
Eric Andersen12de6cf2004-08-04 19:19:10 +0000795
Eric Andersenff9eee42001-06-29 04:57:14 +0000796
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000797/* fail but return to process next command */
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000798static void fail(void) ATTRIBUTE_NORETURN;
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000799static void fail(void)
800{
801 longjmp(failpt, 1);
802 /* NOTREACHED */
803}
Eric Andersenff9eee42001-06-29 04:57:14 +0000804
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000805/* abort shell (or fail in subshell) */
806static void leave(void) ATTRIBUTE_NORETURN;
807static void leave(void)
808{
809 DBGPRINTF(("LEAVE: leave called!\n"));
810
811 if (execflg)
812 fail();
813 scraphere();
814 freehere(1);
815 runtrap(0);
816 _exit(exstat);
817 /* NOTREACHED */
818}
819
820static void warn(const char *s)
821{
822 if (*s) {
823 prs(s);
824 exstat = -1;
825 }
826 prs("\n");
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +0000827 if (FLAG['e'])
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000828 leave();
829}
830
831static void err(const char *s)
832{
833 warn(s);
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +0000834 if (FLAG['n'])
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000835 return;
836 if (!interactive)
837 leave();
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000838 if (global_env.errpt)
839 longjmp(global_env.errpt, 1);
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000840 closeall();
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000841 global_env.iop = global_env.iobase = iostack;
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000842}
843
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000844
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000845/* -------- area.c -------- */
846
Eric Andersenff9eee42001-06-29 04:57:14 +0000847/*
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000848 * All memory between (char *)areabot and (char *)(areatop+1) is
849 * exclusively administered by the area management routines.
850 * It is assumed that sbrk() and brk() manipulate the high end.
Eric Andersenff9eee42001-06-29 04:57:14 +0000851 */
852
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000853#define sbrk(X) ({ \
854 void * __q = (void *)-1; \
855 if (brkaddr + (int)(X) < brktop) { \
856 __q = brkaddr; \
857 brkaddr += (int)(X); \
858 } \
859 __q; \
860})
Eric Andersenff9eee42001-06-29 04:57:14 +0000861
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000862static void initarea(void)
Eric Andersenff9eee42001-06-29 04:57:14 +0000863{
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000864 brkaddr = xmalloc(AREASIZE);
865 brktop = brkaddr + AREASIZE;
Eric Andersenff9eee42001-06-29 04:57:14 +0000866
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000867 while ((long) sbrk(0) & ALIGN)
868 sbrk(1);
869 areabot = (struct region *) sbrk(REGSIZE);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +0000870
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000871 areabot->next = areabot;
872 areabot->area = BUSY;
873 areatop = areabot;
874 areanxt = areabot;
Eric Andersenff9eee42001-06-29 04:57:14 +0000875}
876
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000877static char *getcell(unsigned nbytes)
878{
879 int nregio;
880 struct region *p, *q;
881 int i;
882
883 if (nbytes == 0) {
884 puts("getcell(0)");
885 abort();
886 }
887 /* silly and defeats the algorithm */
888 /*
889 * round upwards and add administration area
890 */
891 nregio = (nbytes + (REGSIZE - 1)) / REGSIZE + 1;
892 p = areanxt;
893 for (;;) {
894 if (p->area > areanum) {
895 /*
896 * merge free cells
897 */
898 while ((q = p->next)->area > areanum && q != areanxt)
899 p->next = q->next;
900 /*
901 * exit loop if cell big enough
902 */
903 if (q >= p + nregio)
904 goto found;
905 }
906 p = p->next;
907 if (p == areanxt)
908 break;
909 }
910 i = nregio >= GROWBY ? nregio : GROWBY;
911 p = (struct region *) sbrk(i * REGSIZE);
912 if (p == (struct region *) -1)
913 return NULL;
914 p--;
915 if (p != areatop) {
916 puts("not contig");
917 abort(); /* allocated areas are contiguous */
918 }
919 q = p + i;
920 p->next = q;
921 p->area = FREE;
922 q->next = areabot;
923 q->area = BUSY;
924 areatop = q;
925 found:
926 /*
927 * we found a FREE area big enough, pointed to by 'p', and up to 'q'
928 */
929 areanxt = p + nregio;
930 if (areanxt < q) {
931 /*
932 * split into requested area and rest
933 */
934 if (areanxt + 1 > q) {
935 puts("OOM");
936 abort(); /* insufficient space left for admin */
937 }
938 areanxt->next = q;
939 areanxt->area = FREE;
940 p->next = areanxt;
941 }
942 p->area = areanum;
943 return (char *) (p + 1);
944}
945
946static void freecell(char *cp)
947{
948 struct region *p;
949
950 p = (struct region *) cp;
951 if (p != NULL) {
952 p--;
953 if (p < areanxt)
954 areanxt = p;
955 p->area = FREE;
956 }
957}
958#define DELETE(obj) freecell((char *)obj)
959
960static void freearea(int a)
961{
962 struct region *p, *top;
963
964 top = areatop;
965 for (p = areabot; p != top; p = p->next)
966 if (p->area >= a)
967 p->area = FREE;
968}
969
970static void setarea(char *cp, int a)
971{
972 struct region *p;
973
974 p = (struct region *) cp;
975 if (p != NULL)
976 (p - 1)->area = a;
977}
978
979static int getarea(char *cp)
980{
981 return ((struct region *) cp - 1)->area;
982}
983
984static void garbage(void)
985{
986 struct region *p, *q, *top;
987
988 top = areatop;
989 for (p = areabot; p != top; p = p->next) {
990 if (p->area > areanum) {
991 while ((q = p->next)->area > areanum)
992 p->next = q->next;
993 areanxt = p;
994 }
995 }
996#ifdef SHRINKBY
997 if (areatop >= q + SHRINKBY && q->area > areanum) {
998 brk((char *) (q + 1));
999 q->next = areabot;
1000 q->area = BUSY;
1001 areatop = q;
1002 }
1003#endif
1004}
1005
1006static char *space(int n)
1007{
1008 char *cp;
1009
1010 cp = getcell(n);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001011 if (cp == NULL)
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001012 err("out of string space");
1013 return cp;
1014}
1015
1016static char *strsave(const char *s, int a)
1017{
1018 char *cp;
1019
1020 cp = space(strlen(s) + 1);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001021 if (cp == NULL) {
1022// FIXME: I highly doubt this is good.
1023 return (char*)"";
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001024 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001025 setarea(cp, a);
1026 strcpy(cp, s);
1027 return cp;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001028}
1029
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001030
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001031/* -------- var.c -------- */
1032
1033static int eqname(const char *n1, const char *n2)
1034{
1035 for (; *n1 != '=' && *n1 != '\0'; n1++)
1036 if (*n2++ != *n1)
1037 return 0;
1038 return *n2 == '\0' || *n2 == '=';
1039}
1040
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001041static const char *findeq(const char *cp)
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001042{
1043 while (*cp != '\0' && *cp != '=')
1044 cp++;
1045 return cp;
1046}
1047
1048/*
1049 * Find the given name in the dictionary
1050 * and return its value. If the name was
1051 * not previously there, enter it now and
1052 * return a null value.
1053 */
1054static struct var *lookup(const char *n)
1055{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001056// FIXME: dirty hack
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001057 static struct var dummy;
1058
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001059 struct var *vp;
1060 const char *cp;
1061 char *xp;
1062 int c;
1063
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001064 if (isdigit(*n)) {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001065 dummy.name = (char*)n;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001066 for (c = 0; isdigit(*n) && c < 1000; n++)
1067 c = c * 10 + *n - '0';
1068 dummy.status = RONLY;
1069 dummy.value = (c <= dolc ? dolv[c] : null);
1070 return &dummy;
1071 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001072
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001073 for (vp = vlist; vp; vp = vp->next)
1074 if (eqname(vp->name, n))
1075 return vp;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001076
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001077 cp = findeq(n);
1078 vp = (struct var *) space(sizeof(*vp));
1079 if (vp == 0 || (vp->name = space((int) (cp - n) + 2)) == 0) {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001080 dummy.name = dummy.value = (char*)"";
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001081 return &dummy;
1082 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001083
1084 xp = vp->name;
1085 while ((*xp = *n++) != '\0' && *xp != '=')
1086 xp++;
1087 *xp++ = '=';
1088 *xp = '\0';
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001089 setarea((char *) vp, 0);
1090 setarea((char *) vp->name, 0);
1091 vp->value = null;
1092 vp->next = vlist;
1093 vp->status = GETCELL;
1094 vlist = vp;
1095 return vp;
1096}
1097
1098/*
1099 * if name is not NULL, it must be
1100 * a prefix of the space `val',
1101 * and end with `='.
1102 * this is all so that exporting
1103 * values is reasonably painless.
1104 */
1105static void nameval(struct var *vp, const char *val, const char *name)
1106{
1107 const char *cp;
1108 char *xp;
1109 int fl;
1110
1111 if (vp->status & RONLY) {
1112 xp = vp->name;
1113 while (*xp && *xp != '=')
Denis Vlasenko4daad902007-09-27 10:20:47 +00001114 fputc(*xp++, stderr);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001115 err(" is read-only");
1116 return;
1117 }
1118 fl = 0;
1119 if (name == NULL) {
1120 xp = space(strlen(vp->name) + strlen(val) + 2);
1121 if (xp == NULL)
1122 return;
1123 /* make string: name=value */
1124 setarea(xp, 0);
1125 name = xp;
1126 cp = vp->name;
1127 while ((*xp = *cp++) != '\0' && *xp != '=')
1128 xp++;
1129 *xp++ = '=';
1130 strcpy(xp, val);
1131 val = xp;
1132 fl = GETCELL;
1133 }
1134 if (vp->status & GETCELL)
1135 freecell(vp->name); /* form new string `name=value' */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001136 vp->name = (char*)name;
1137 vp->value = (char*)val;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001138 vp->status |= fl;
1139}
1140
1141/*
1142 * give variable at `vp' the value `val'.
1143 */
1144static void setval(struct var *vp, const char *val)
1145{
1146 nameval(vp, val, NULL);
1147}
1148
1149static void export(struct var *vp)
1150{
1151 vp->status |= EXPORT;
1152}
1153
1154static void ronly(struct var *vp)
1155{
1156 if (isalpha(vp->name[0]) || vp->name[0] == '_') /* not an internal symbol */
1157 vp->status |= RONLY;
1158}
1159
1160static int isassign(const char *s)
1161{
1162 unsigned char c;
1163 DBGPRINTF7(("ISASSIGN: enter, s=%s\n", s));
1164
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001165 c = *s;
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001166 /* no isalpha() - we shouldn't use locale */
1167 /* c | 0x20 - lowercase (Latin) letters */
1168 if (c != '_' && (unsigned)((c|0x20) - 'a') > 25)
1169 /* not letter */
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001170 return 0;
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001171
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001172 while (1) {
1173 c = *++s;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001174 if (c == '=')
1175 return 1;
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001176 if (c == '\0')
1177 return 0;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001178 if (c != '_'
1179 && (unsigned)(c - '0') > 9 /* not number */
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001180 && (unsigned)((c|0x20) - 'a') > 25 /* not letter */
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001181 ) {
1182 return 0;
1183 }
1184 }
1185}
1186
1187static int assign(const char *s, int cf)
1188{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001189 const char *cp;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001190 struct var *vp;
1191
1192 DBGPRINTF7(("ASSIGN: enter, s=%s, cf=%d\n", s, cf));
1193
1194 if (!isalpha(*s) && *s != '_')
1195 return 0;
1196 for (cp = s; *cp != '='; cp++)
1197 if (*cp == '\0' || (!isalnum(*cp) && *cp != '_'))
1198 return 0;
1199 vp = lookup(s);
1200 nameval(vp, ++cp, cf == COPYV ? NULL : s);
1201 if (cf != COPYV)
1202 vp->status &= ~GETCELL;
1203 return 1;
1204}
1205
1206static int checkname(char *cp)
1207{
1208 DBGPRINTF7(("CHECKNAME: enter, cp=%s\n", cp));
1209
1210 if (!isalpha(*cp++) && *(cp - 1) != '_')
1211 return 0;
1212 while (*cp)
1213 if (!isalnum(*cp++) && *(cp - 1) != '_')
1214 return 0;
1215 return 1;
1216}
1217
1218static void putvlist(int f, int out)
1219{
1220 struct var *vp;
1221
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001222 for (vp = vlist; vp; vp = vp->next) {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001223 if (vp->status & f && (isalpha(*vp->name) || *vp->name == '_')) {
1224 if (vp->status & EXPORT)
1225 write(out, "export ", 7);
1226 if (vp->status & RONLY)
1227 write(out, "readonly ", 9);
1228 write(out, vp->name, (int) (findeq(vp->name) - vp->name));
1229 write(out, "\n", 1);
1230 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001231 }
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001232}
1233
1234
1235/*
1236 * trap handling
1237 */
1238static void sig(int i)
1239{
1240 trapset = i;
1241 signal(i, sig);
1242}
1243
1244static void runtrap(int i)
1245{
1246 char *trapstr;
1247
1248 trapstr = trap[i];
1249 if (trapstr == NULL)
1250 return;
1251
1252 if (i == 0)
1253 trap[i] = NULL;
1254
1255 RUN(aword, trapstr, nlchar);
1256}
1257
1258
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001259static void setdash(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001260{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001261 char *cp;
1262 int c;
Eric Andersen8401eea2004-08-04 19:16:54 +00001263 char m['z' - 'a' + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00001264
1265 cp = m;
Eric Andersen8401eea2004-08-04 19:16:54 +00001266 for (c = 'a'; c <= 'z'; c++)
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00001267 if (FLAG[c])
Eric Andersenff9eee42001-06-29 04:57:14 +00001268 *cp++ = c;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001269 *cp = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00001270 setval(lookup("-"), m);
1271}
1272
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001273static int newfile(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00001274{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001275 int f;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001276
1277 DBGPRINTF7(("NEWFILE: opening %s\n", s));
Eric Andersenff9eee42001-06-29 04:57:14 +00001278
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001279 f = 0;
Denis Vlasenko9f739442006-12-16 23:49:13 +00001280 if (NOT_LONE_DASH(s)) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001281 DBGPRINTF(("NEWFILE: s is %s\n", s));
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00001282 f = open(s, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00001283 if (f < 0) {
1284 prs(s);
1285 err(": cannot open");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001286 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001287 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001288 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001289
Eric Andersenff9eee42001-06-29 04:57:14 +00001290 next(remap(f));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001291 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001292}
1293
Eric Andersen12de6cf2004-08-04 19:19:10 +00001294
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001295struct op *scantree(struct op *head)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001296{
1297 struct op *dotnode;
1298
1299 if (head == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001300 return NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001301
1302 if (head->left != NULL) {
1303 dotnode = scantree(head->left);
1304 if (dotnode)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001305 return dotnode;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001306 }
1307
1308 if (head->right != NULL) {
1309 dotnode = scantree(head->right);
1310 if (dotnode)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001311 return dotnode;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001312 }
1313
1314 if (head->words == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001315 return NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001316
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001317 DBGPRINTF5(("SCANTREE: checking node %p\n", head));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001318
Denis Vlasenkocf787cf2007-02-04 17:11:25 +00001319 if ((head->type != TDOT) && LONE_CHAR(head->words[0], '.')) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001320 DBGPRINTF5(("SCANTREE: dot found in node %p\n", head));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001321 return head;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001322 }
1323
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001324 return NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001325}
1326
1327
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001328static void onecommand(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001329{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001330 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00001331 jmp_buf m1;
1332
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001333 DBGPRINTF(("ONECOMMAND: enter, outtree=%p\n", outtree));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001334
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001335 while (global_env.oenv)
Eric Andersenff9eee42001-06-29 04:57:14 +00001336 quitenv();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001337
Eric Andersenff9eee42001-06-29 04:57:14 +00001338 areanum = 1;
1339 freehere(areanum);
1340 freearea(areanum);
1341 garbage();
1342 wdlist = 0;
1343 iolist = 0;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001344 global_env.errpt = 0;
1345 global_env.linep = line;
Eric Andersenff9eee42001-06-29 04:57:14 +00001346 yynerrs = 0;
1347 multiline = 0;
1348 inparse = 1;
1349 intr = 0;
1350 execflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001351
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001352 failpt = m1;
1353 setjmp(failpt); /* Bruce Evans' fix */
1354 failpt = m1;
1355 if (setjmp(failpt) || yyparse() || intr) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001356 DBGPRINTF(("ONECOMMAND: this is not good.\n"));
1357
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001358 while (global_env.oenv)
Eric Andersenff9eee42001-06-29 04:57:14 +00001359 quitenv();
1360 scraphere();
1361 if (!interactive && intr)
1362 leave();
1363 inparse = 0;
1364 intr = 0;
1365 return;
1366 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001367
Eric Andersenff9eee42001-06-29 04:57:14 +00001368 inparse = 0;
1369 brklist = 0;
1370 intr = 0;
1371 execflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001372
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00001373 if (!FLAG['n']) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001374 DBGPRINTF(("ONECOMMAND: calling execute, t=outtree=%p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00001375 outtree));
Eric Andersenff9eee42001-06-29 04:57:14 +00001376 execute(outtree, NOPIPE, NOPIPE, 0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001377 }
1378
Eric Andersenff9eee42001-06-29 04:57:14 +00001379 if (!interactive && intr) {
1380 execflg = 0;
1381 leave();
1382 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001383
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001384 i = trapset;
1385 if (i != 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001386 trapset = 0;
1387 runtrap(i);
1388 }
1389}
1390
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001391static int newenv(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00001392{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001393 struct env *ep;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001394
1395 DBGPRINTF(("NEWENV: f=%d (indicates quitenv and return)\n", f));
Eric Andersenff9eee42001-06-29 04:57:14 +00001396
1397 if (f) {
1398 quitenv();
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001399 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001400 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001401
Eric Andersenff9eee42001-06-29 04:57:14 +00001402 ep = (struct env *) space(sizeof(*ep));
1403 if (ep == NULL) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001404 while (global_env.oenv)
Eric Andersenff9eee42001-06-29 04:57:14 +00001405 quitenv();
1406 fail();
1407 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001408 *ep = global_env;
1409 global_env.oenv = ep;
1410 global_env.errpt = errpt;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001411
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001412 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001413}
1414
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001415static void quitenv(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001416{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001417 struct env *ep;
1418 int fd;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001419
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001420 DBGPRINTF(("QUITENV: global_env.oenv=%p\n", global_env.oenv));
Eric Andersenff9eee42001-06-29 04:57:14 +00001421
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001422 ep = global_env.oenv;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001423 if (ep != NULL) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001424 fd = global_env.iofd;
1425 global_env = *ep;
Eric Andersenff9eee42001-06-29 04:57:14 +00001426 /* should close `'d files */
1427 DELETE(ep);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001428 while (--fd >= global_env.iofd)
Eric Andersenff9eee42001-06-29 04:57:14 +00001429 close(fd);
1430 }
1431}
1432
1433/*
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001434 * Is character c in s?
Eric Andersenff9eee42001-06-29 04:57:14 +00001435 */
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001436static int any(int c, const char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00001437{
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001438 while (*s)
1439 if (*s++ == c)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001440 return 1;
1441 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001442}
1443
1444/*
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001445 * Is any character from s1 in s2?
Eric Andersenff9eee42001-06-29 04:57:14 +00001446 */
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001447static int anys(const char *s1, const char *s2)
Eric Andersenff9eee42001-06-29 04:57:14 +00001448{
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001449 while (*s1)
1450 if (any(*s1++, s2))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001451 return 1;
1452 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001453}
1454
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001455static char *putn(int n)
Eric Andersenff9eee42001-06-29 04:57:14 +00001456{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001457 return itoa(n);
Eric Andersenff9eee42001-06-29 04:57:14 +00001458}
1459
Eric Andersen8401eea2004-08-04 19:16:54 +00001460static void next(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00001461{
1462 PUSHIO(afile, f, filechar);
1463}
1464
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001465static void onintr(int s) /* ANSI C requires a parameter */
Eric Andersenff9eee42001-06-29 04:57:14 +00001466{
1467 signal(SIGINT, onintr);
1468 intr = 1;
1469 if (interactive) {
1470 if (inparse) {
1471 prs("\n");
1472 fail();
1473 }
Eric Andersen8401eea2004-08-04 19:16:54 +00001474 } else if (heedint) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001475 execflg = 0;
1476 leave();
1477 }
1478}
1479
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001480
Eric Andersenff9eee42001-06-29 04:57:14 +00001481/* -------- gmatch.c -------- */
1482/*
1483 * int gmatch(string, pattern)
1484 * char *string, *pattern;
1485 *
1486 * Match a pattern as in sh(1).
1487 */
1488
1489#define CMASK 0377
1490#define QUOTE 0200
Denis Vlasenko55f30b02007-03-24 22:42:29 +00001491#define QMASK (CMASK & ~QUOTE)
Eric Andersen8401eea2004-08-04 19:16:54 +00001492#define NOT '!' /* might use ^ */
Eric Andersenff9eee42001-06-29 04:57:14 +00001493
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001494static const char *cclass(const char *p, int sub)
1495{
1496 int c, d, not, found;
1497
1498 not = (*p == NOT);
1499 if (not != 0)
1500 p++;
1501 found = not;
1502 do {
1503 if (*p == '\0')
1504 return NULL;
1505 c = *p & CMASK;
1506 if (p[1] == '-' && p[2] != ']') {
1507 d = p[2] & CMASK;
1508 p++;
1509 } else
1510 d = c;
1511 if (c == sub || (c <= sub && sub <= d))
1512 found = !not;
1513 } while (*++p != ']');
1514 return found ? p + 1 : NULL;
1515}
1516
1517static int gmatch(const char *s, const char *p)
Eric Andersenff9eee42001-06-29 04:57:14 +00001518{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001519 int sc, pc;
Eric Andersenff9eee42001-06-29 04:57:14 +00001520
1521 if (s == NULL || p == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001522 return 0;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001523
Eric Andersenff9eee42001-06-29 04:57:14 +00001524 while ((pc = *p++ & CMASK) != '\0') {
1525 sc = *s++ & QMASK;
1526 switch (pc) {
1527 case '[':
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001528 p = cclass(p, sc);
1529 if (p == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001530 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001531 break;
1532
1533 case '?':
1534 if (sc == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001535 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001536 break;
1537
1538 case '*':
1539 s--;
1540 do {
1541 if (*p == '\0' || gmatch(s, p))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001542 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001543 } while (*s++ != '\0');
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001544 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001545
1546 default:
Eric Andersen8401eea2004-08-04 19:16:54 +00001547 if (sc != (pc & ~QUOTE))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001548 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001549 }
1550 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001551 return *s == '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00001552}
1553
Eric Andersenff9eee42001-06-29 04:57:14 +00001554
Eric Andersenff9eee42001-06-29 04:57:14 +00001555/* -------- csyn.c -------- */
1556/*
1557 * shell: syntax (C version)
1558 */
1559
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001560static void yyerror(const char *s) ATTRIBUTE_NORETURN;
1561static void yyerror(const char *s)
1562{
1563 yynerrs++;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001564 if (interactive && global_env.iop <= iostack) {
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001565 multiline = 0;
1566 while (eofc() == 0 && yylex(0) != '\n');
1567 }
1568 err(s);
1569 fail();
1570}
1571
1572static void zzerr(void) ATTRIBUTE_NORETURN;
1573static void zzerr(void)
1574{
1575 yyerror("syntax error");
1576}
1577
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001578int yyparse(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001579{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001580 DBGPRINTF7(("YYPARSE: enter...\n"));
1581
Eric Andersen8401eea2004-08-04 19:16:54 +00001582 startl = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001583 peeksym = 0;
1584 yynerrs = 0;
1585 outtree = c_list();
1586 musthave('\n', 0);
Eric Andersen8401eea2004-08-04 19:16:54 +00001587 return (yynerrs != 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001588}
1589
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001590static struct op *pipeline(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001591{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001592 struct op *t, *p;
1593 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001594
1595 DBGPRINTF7(("PIPELINE: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001596
1597 t = command(cf);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001598
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001599 DBGPRINTF9(("PIPELINE: t=%p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001600
Eric Andersenff9eee42001-06-29 04:57:14 +00001601 if (t != NULL) {
1602 while ((c = yylex(0)) == '|') {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001603 p = command(CONTIN);
1604 if (p == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001605 DBGPRINTF8(("PIPELINE: error!\n"));
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001606 zzerr();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001607 }
1608
Eric Andersenff9eee42001-06-29 04:57:14 +00001609 if (t->type != TPAREN && t->type != TCOM) {
1610 /* shell statement */
1611 t = block(TPAREN, t, NOBLOCK, NOWORDS);
1612 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001613
Eric Andersenff9eee42001-06-29 04:57:14 +00001614 t = block(TPIPE, t, p, NOWORDS);
1615 }
1616 peeksym = c;
1617 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001618
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001619 DBGPRINTF7(("PIPELINE: returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001620 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001621}
1622
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001623static struct op *andor(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001624{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001625 struct op *t, *p;
1626 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001627
1628 DBGPRINTF7(("ANDOR: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001629
1630 t = pipeline(0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001631
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001632 DBGPRINTF9(("ANDOR: t=%p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001633
Eric Andersenff9eee42001-06-29 04:57:14 +00001634 if (t != NULL) {
1635 while ((c = yylex(0)) == LOGAND || c == LOGOR) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001636 p = pipeline(CONTIN);
1637 if (p == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001638 DBGPRINTF8(("ANDOR: error!\n"));
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001639 zzerr();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001640 }
1641
Eric Andersen8401eea2004-08-04 19:16:54 +00001642 t = block(c == LOGAND ? TAND : TOR, t, p, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001643 } /* WHILE */
1644
Eric Andersenff9eee42001-06-29 04:57:14 +00001645 peeksym = c;
1646 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001647
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001648 DBGPRINTF7(("ANDOR: returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001649 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001650}
1651
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001652static struct op *c_list(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001653{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001654 struct op *t, *p;
1655 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001656
1657 DBGPRINTF7(("C_LIST: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001658
1659 t = andor();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001660
Eric Andersenff9eee42001-06-29 04:57:14 +00001661 if (t != NULL) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001662 peeksym = yylex(0);
1663 if (peeksym == '&')
Eric Andersenff9eee42001-06-29 04:57:14 +00001664 t = block(TASYNC, t, NOBLOCK, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001665
Eric Andersen8401eea2004-08-04 19:16:54 +00001666 while ((c = yylex(0)) == ';' || c == '&'
1667 || (multiline && c == '\n')) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001668
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001669 p = andor();
1670 if (p== NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001671 return t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001672
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001673 peeksym = yylex(0);
1674 if (peeksym == '&')
Eric Andersenff9eee42001-06-29 04:57:14 +00001675 p = block(TASYNC, p, NOBLOCK, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001676
Eric Andersenff9eee42001-06-29 04:57:14 +00001677 t = list(t, p);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001678 } /* WHILE */
1679
Eric Andersenff9eee42001-06-29 04:57:14 +00001680 peeksym = c;
1681 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001682 /* IF */
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001683 DBGPRINTF7(("C_LIST: returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001684 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001685}
1686
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001687static int synio(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001688{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001689 struct ioword *iop;
1690 int i;
1691 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001692
1693 DBGPRINTF7(("SYNIO: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001694
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001695 c = yylex(cf);
1696 if (c != '<' && c != '>') {
Eric Andersenff9eee42001-06-29 04:57:14 +00001697 peeksym = c;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001698 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001699 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001700
Eric Andersenff9eee42001-06-29 04:57:14 +00001701 i = yylval.i;
1702 musthave(WORD, 0);
1703 iop = io(iounit, i, yylval.cp);
1704 iounit = IODEFAULT;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001705
Eric Andersenff9eee42001-06-29 04:57:14 +00001706 if (i & IOHERE)
1707 markhere(yylval.cp, iop);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001708
1709 DBGPRINTF7(("SYNIO: returning 1\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001710 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001711}
1712
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001713static void musthave(int c, int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001714{
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001715 peeksym = yylex(cf);
1716 if (peeksym != c) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001717 DBGPRINTF7(("MUSTHAVE: error!\n"));
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001718 zzerr();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001719 }
1720
Eric Andersenff9eee42001-06-29 04:57:14 +00001721 peeksym = 0;
1722}
1723
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001724static struct op *simple(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001725{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001726 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001727
1728 t = NULL;
1729 for (;;) {
1730 switch (peeksym = yylex(0)) {
1731 case '<':
1732 case '>':
1733 (void) synio(0);
1734 break;
1735
1736 case WORD:
1737 if (t == NULL) {
1738 t = newtp();
1739 t->type = TCOM;
1740 }
1741 peeksym = 0;
1742 word(yylval.cp);
1743 break;
1744
1745 default:
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001746 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001747 }
1748 }
1749}
1750
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001751static struct op *nested(int type, int mark)
Eric Andersenff9eee42001-06-29 04:57:14 +00001752{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001753 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001754
1755 DBGPRINTF3(("NESTED: enter, type=%d, mark=%d\n", type, mark));
Eric Andersenff9eee42001-06-29 04:57:14 +00001756
1757 multiline++;
1758 t = c_list();
1759 musthave(mark, 0);
1760 multiline--;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001761 return block(type, t, NOBLOCK, NOWORDS);
Eric Andersenff9eee42001-06-29 04:57:14 +00001762}
1763
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001764static struct op *command(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001765{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001766 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001767 struct wdblock *iosave;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001768 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001769
1770 DBGPRINTF(("COMMAND: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001771
1772 iosave = iolist;
1773 iolist = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001774
Eric Andersenff9eee42001-06-29 04:57:14 +00001775 if (multiline)
1776 cf |= CONTIN;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001777
Eric Andersenff9eee42001-06-29 04:57:14 +00001778 while (synio(cf))
1779 cf = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001780
1781 c = yylex(cf);
1782
1783 switch (c) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001784 default:
1785 peeksym = c;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001786 t = simple();
1787 if (t == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001788 if (iolist == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001789 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001790 t = newtp();
1791 t->type = TCOM;
1792 }
1793 break;
1794
1795 case '(':
1796 t = nested(TPAREN, ')');
1797 break;
1798
1799 case '{':
1800 t = nested(TBRACE, '}');
1801 break;
1802
1803 case FOR:
1804 t = newtp();
1805 t->type = TFOR;
1806 musthave(WORD, 0);
1807 startl = 1;
1808 t->str = yylval.cp;
1809 multiline++;
1810 t->words = wordlist();
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001811 c = yylex(0);
1812 if (c != '\n' && c != ';')
Eric Andersenff9eee42001-06-29 04:57:14 +00001813 peeksym = c;
1814 t->left = dogroup(0);
1815 multiline--;
1816 break;
1817
1818 case WHILE:
1819 case UNTIL:
1820 multiline++;
1821 t = newtp();
Eric Andersen8401eea2004-08-04 19:16:54 +00001822 t->type = c == WHILE ? TWHILE : TUNTIL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001823 t->left = c_list();
1824 t->right = dogroup(1);
1825 t->words = NULL;
1826 multiline--;
1827 break;
1828
1829 case CASE:
1830 t = newtp();
1831 t->type = TCASE;
1832 musthave(WORD, 0);
1833 t->str = yylval.cp;
1834 startl++;
1835 multiline++;
1836 musthave(IN, CONTIN);
1837 startl++;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001838
Eric Andersenff9eee42001-06-29 04:57:14 +00001839 t->left = caselist();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001840
Eric Andersenff9eee42001-06-29 04:57:14 +00001841 musthave(ESAC, 0);
1842 multiline--;
1843 break;
1844
1845 case IF:
1846 multiline++;
1847 t = newtp();
1848 t->type = TIF;
1849 t->left = c_list();
1850 t->right = thenpart();
1851 musthave(FI, 0);
1852 multiline--;
1853 break;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001854
1855 case DOT:
1856 t = newtp();
1857 t->type = TDOT;
1858
1859 musthave(WORD, 0); /* gets name of file */
1860 DBGPRINTF7(("COMMAND: DOT clause, yylval.cp is %s\n", yylval.cp));
1861
1862 word(yylval.cp); /* add word to wdlist */
1863 word(NOWORD); /* terminate wdlist */
1864 t->words = copyw(); /* dup wdlist */
1865 break;
1866
Eric Andersenff9eee42001-06-29 04:57:14 +00001867 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001868
Eric Andersen8401eea2004-08-04 19:16:54 +00001869 while (synio(0));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001870
Eric Andersenff9eee42001-06-29 04:57:14 +00001871 t = namelist(t);
1872 iolist = iosave;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001873
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001874 DBGPRINTF(("COMMAND: returning %p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001875
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001876 return t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001877}
1878
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001879static struct op *dowholefile(int type, int mark)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001880{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001881 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001882
1883 DBGPRINTF(("DOWHOLEFILE: enter, type=%d, mark=%d\n", type, mark));
1884
1885 multiline++;
1886 t = c_list();
1887 multiline--;
1888 t = block(type, t, NOBLOCK, NOWORDS);
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001889 DBGPRINTF(("DOWHOLEFILE: return t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001890 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001891}
1892
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001893static struct op *dogroup(int onlydone)
Eric Andersenff9eee42001-06-29 04:57:14 +00001894{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001895 int c;
1896 struct op *mylist;
Eric Andersenff9eee42001-06-29 04:57:14 +00001897
1898 c = yylex(CONTIN);
1899 if (c == DONE && onlydone)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001900 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001901 if (c != DO)
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001902 zzerr();
Eric Andersenff9eee42001-06-29 04:57:14 +00001903 mylist = c_list();
1904 musthave(DONE, 0);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001905 return mylist;
Eric Andersenff9eee42001-06-29 04:57:14 +00001906}
1907
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001908static struct op *thenpart(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001909{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001910 int c;
1911 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001912
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001913 c = yylex(0);
1914 if (c != THEN) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001915 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001916 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001917 }
1918 t = newtp();
1919 t->type = 0;
1920 t->left = c_list();
1921 if (t->left == NULL)
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001922 zzerr();
Eric Andersenff9eee42001-06-29 04:57:14 +00001923 t->right = elsepart();
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001924 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001925}
1926
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001927static struct op *elsepart(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001928{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001929 int c;
1930 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001931
1932 switch (c = yylex(0)) {
1933 case ELSE:
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001934 t = c_list();
1935 if (t == NULL)
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001936 zzerr();
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001937 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001938
1939 case ELIF:
1940 t = newtp();
1941 t->type = TELIF;
1942 t->left = c_list();
1943 t->right = thenpart();
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001944 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001945
1946 default:
1947 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001948 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001949 }
1950}
1951
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001952static struct op *caselist(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001953{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001954 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001955
1956 t = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001957 while ((peeksym = yylex(CONTIN)) != ESAC) {
1958 DBGPRINTF(("CASELIST, doing yylex, peeksym=%d\n", peeksym));
Eric Andersenff9eee42001-06-29 04:57:14 +00001959 t = list(t, casepart());
Eric Andersen12de6cf2004-08-04 19:19:10 +00001960 }
1961
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001962 DBGPRINTF(("CASELIST, returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001963 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001964}
1965
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001966static struct op *casepart(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001967{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001968 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001969
1970 DBGPRINTF7(("CASEPART: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001971
1972 t = newtp();
1973 t->type = TPAT;
1974 t->words = pattern();
1975 musthave(')', 0);
1976 t->left = c_list();
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001977 peeksym = yylex(CONTIN);
1978 if (peeksym != ESAC)
Eric Andersenff9eee42001-06-29 04:57:14 +00001979 musthave(BREAK, CONTIN);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001980
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001981 DBGPRINTF7(("CASEPART: made newtp(TPAT, t=%p)\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001982
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001983 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001984}
1985
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001986static char **pattern(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001987{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001988 int c, cf;
Eric Andersenff9eee42001-06-29 04:57:14 +00001989
1990 cf = CONTIN;
1991 do {
1992 musthave(WORD, cf);
1993 word(yylval.cp);
1994 cf = 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001995 c = yylex(0);
1996 } while (c == '|');
Eric Andersenff9eee42001-06-29 04:57:14 +00001997 peeksym = c;
1998 word(NOWORD);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001999
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002000 return copyw();
Eric Andersenff9eee42001-06-29 04:57:14 +00002001}
2002
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002003static char **wordlist(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002004{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002005 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002006
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002007 c = yylex(0);
2008 if (c != IN) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002009 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002010 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00002011 }
2012 startl = 0;
2013 while ((c = yylex(0)) == WORD)
2014 word(yylval.cp);
2015 word(NOWORD);
2016 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002017 return copyw();
Eric Andersenff9eee42001-06-29 04:57:14 +00002018}
2019
2020/*
2021 * supporting functions
2022 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002023static struct op *list(struct op *t1, struct op *t2)
Eric Andersenff9eee42001-06-29 04:57:14 +00002024{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002025 DBGPRINTF7(("LIST: enter, t1=%p, t2=%p\n", t1, t2));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002026
Eric Andersenff9eee42001-06-29 04:57:14 +00002027 if (t1 == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002028 return t2;
Eric Andersenff9eee42001-06-29 04:57:14 +00002029 if (t2 == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002030 return t1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002031
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002032 return block(TLIST, t1, t2, NOWORDS);
Eric Andersenff9eee42001-06-29 04:57:14 +00002033}
2034
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002035static struct op *block(int type, struct op *t1, struct op *t2, char **wp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002036{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002037 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002038
2039 DBGPRINTF7(("BLOCK: enter, type=%d (%s)\n", type, T_CMD_NAMES[type]));
Eric Andersenff9eee42001-06-29 04:57:14 +00002040
2041 t = newtp();
2042 t->type = type;
2043 t->left = t1;
2044 t->right = t2;
2045 t->words = wp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002046
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002047 DBGPRINTF7(("BLOCK: inserted %p between %p and %p\n", t, t1,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002048 t2));
2049
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002050 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002051}
2052
Eric Andersen12de6cf2004-08-04 19:19:10 +00002053/* See if given string is a shell multiline (FOR, IF, etc) */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002054static int rlookup(char *n)
Eric Andersenff9eee42001-06-29 04:57:14 +00002055{
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002056 struct res {
2057 char r_name[6];
2058 int16_t r_val;
2059 };
2060 static const struct res restab[] = {
2061 { "for" , FOR },
2062 { "case" , CASE },
2063 { "esac" , ESAC },
2064 { "while", WHILE },
2065 { "do" , DO },
2066 { "done" , DONE },
2067 { "if" , IF },
2068 { "in" , IN },
2069 { "then" , THEN },
2070 { "else" , ELSE },
2071 { "elif" , ELIF },
2072 { "until", UNTIL },
2073 { "fi" , FI },
2074 { ";;" , BREAK },
2075 { "||" , LOGOR },
2076 { "&&" , LOGAND },
2077 { "{" , '{' },
2078 { "}" , '}' },
2079 { "." , DOT },
2080 { },
2081 };
2082
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002083 const struct res *rp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002084
2085 DBGPRINTF7(("RLOOKUP: enter, n is %s\n", n));
Eric Andersenff9eee42001-06-29 04:57:14 +00002086
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002087 for (rp = restab; rp->r_name[0]; rp++)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002088 if (strcmp(rp->r_name, n) == 0) {
2089 DBGPRINTF7(("RLOOKUP: match, returning %d\n", rp->r_val));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002090 return rp->r_val; /* Return numeric code for shell multiline */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002091 }
2092
2093 DBGPRINTF7(("RLOOKUP: NO match, returning 0\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002094 return 0; /* Not a shell multiline */
Eric Andersenff9eee42001-06-29 04:57:14 +00002095}
2096
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002097static struct op *newtp(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002098{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002099 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002100
Eric Andersen8401eea2004-08-04 19:16:54 +00002101 t = (struct op *) tree(sizeof(*t));
Eric Andersenff9eee42001-06-29 04:57:14 +00002102 t->type = 0;
2103 t->words = NULL;
2104 t->ioact = NULL;
2105 t->left = NULL;
2106 t->right = NULL;
2107 t->str = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002108
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002109 DBGPRINTF3(("NEWTP: allocated %p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002110
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002111 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002112}
2113
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002114static struct op *namelist(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00002115{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002116 DBGPRINTF7(("NAMELIST: enter, t=%p, type %s, iolist=%p\n", t,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002117 T_CMD_NAMES[t->type], iolist));
2118
Eric Andersenff9eee42001-06-29 04:57:14 +00002119 if (iolist) {
Eric Andersen8401eea2004-08-04 19:16:54 +00002120 iolist = addword((char *) NULL, iolist);
Eric Andersenff9eee42001-06-29 04:57:14 +00002121 t->ioact = copyio();
2122 } else
2123 t->ioact = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002124
Eric Andersenff9eee42001-06-29 04:57:14 +00002125 if (t->type != TCOM) {
2126 if (t->type != TPAREN && t->ioact != NULL) {
2127 t = block(TPAREN, t, NOBLOCK, NOWORDS);
2128 t->ioact = t->left->ioact;
2129 t->left->ioact = NULL;
2130 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002131 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002132 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002133
Eric Andersenff9eee42001-06-29 04:57:14 +00002134 word(NOWORD);
2135 t->words = copyw();
Eric Andersen12de6cf2004-08-04 19:19:10 +00002136
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002137 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002138}
2139
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002140static char **copyw(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002141{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002142 char **wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00002143
2144 wd = getwords(wdlist);
2145 wdlist = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002146 return wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00002147}
2148
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002149static void word(char *cp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002150{
2151 wdlist = addword(cp, wdlist);
2152}
2153
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002154static struct ioword **copyio(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002155{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002156 struct ioword **iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002157
2158 iop = (struct ioword **) getwords(iolist);
2159 iolist = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002160 return iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002161}
2162
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002163static struct ioword *io(int u, int f, char *cp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002164{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002165 struct ioword *iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002166
2167 iop = (struct ioword *) tree(sizeof(*iop));
2168 iop->io_unit = u;
2169 iop->io_flag = f;
2170 iop->io_name = cp;
Eric Andersen8401eea2004-08-04 19:16:54 +00002171 iolist = addword((char *) iop, iolist);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002172 return iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002173}
2174
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002175static int yylex(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00002176{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002177 int c, c1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002178 int atstart;
2179
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002180 c = peeksym;
2181 if (c > 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002182 peeksym = 0;
2183 if (c == '\n')
2184 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002185 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002186 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002187
Eric Andersenff9eee42001-06-29 04:57:14 +00002188 nlseen = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002189 atstart = startl;
2190 startl = 0;
2191 yylval.i = 0;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002192 global_env.linep = line;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002193
2194/* MALAMO */
2195 line[LINELIM - 1] = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00002196
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002197 loop:
Eric Andersen12de6cf2004-08-04 19:19:10 +00002198 while ((c = my_getc(0)) == ' ' || c == '\t') /* Skip whitespace */
2199 ;
2200
Eric Andersenff9eee42001-06-29 04:57:14 +00002201 switch (c) {
2202 default:
2203 if (any(c, "0123456789")) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002204 c1 = my_getc(0);
2205 unget(c1);
Eric Andersenff9eee42001-06-29 04:57:14 +00002206 if (c1 == '<' || c1 == '>') {
2207 iounit = c - '0';
2208 goto loop;
2209 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002210 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002211 c = c1;
2212 }
2213 break;
2214
Eric Andersen12de6cf2004-08-04 19:19:10 +00002215 case '#': /* Comment, skip to next newline or End-of-string */
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002216 while ((c = my_getc(0)) != '\0' && c != '\n');
Eric Andersenff9eee42001-06-29 04:57:14 +00002217 unget(c);
2218 goto loop;
2219
2220 case 0:
Eric Andersen12de6cf2004-08-04 19:19:10 +00002221 DBGPRINTF5(("YYLEX: return 0, c=%d\n", c));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002222 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002223
2224 case '$':
Eric Andersen12de6cf2004-08-04 19:19:10 +00002225 DBGPRINTF9(("YYLEX: found $\n"));
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002226 *global_env.linep++ = c;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002227 c = my_getc(0);
2228 if (c == '{') {
2229 c = collect(c, '}');
2230 if (c != '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002231 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002232 goto pack;
2233 }
2234 break;
2235
2236 case '`':
2237 case '\'':
2238 case '"':
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002239 c = collect(c, c);
2240 if (c != '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002241 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002242 goto pack;
2243
2244 case '|':
2245 case '&':
2246 case ';':
Eric Andersenff9eee42001-06-29 04:57:14 +00002247 startl = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002248 /* If more chars process them, else return NULL char */
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002249 c1 = dual(c);
2250 if (c1 != '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002251 return c1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002252 return c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002253
Eric Andersenff9eee42001-06-29 04:57:14 +00002254 case '^':
2255 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002256 return '|';
Eric Andersenff9eee42001-06-29 04:57:14 +00002257 case '>':
2258 case '<':
2259 diag(c);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002260 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002261
2262 case '\n':
2263 nlseen++;
2264 gethere();
2265 startl = 1;
2266 if (multiline || cf & CONTIN) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002267 if (interactive && global_env.iop <= iostack) {
Denis Vlasenko38f63192007-01-22 09:03:07 +00002268#if ENABLE_FEATURE_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00002269 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00002270#else
Eric Andersen8401eea2004-08-04 19:16:54 +00002271 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00002272#endif
2273 }
2274 if (cf & CONTIN)
2275 goto loop;
2276 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002277 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002278
2279 case '(':
2280 case ')':
2281 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002282 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002283 }
2284
2285 unget(c);
2286
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002287 pack:
2288 while ((c = my_getc(0)) != '\0' && !any(c, "`$ '\"\t;&<>()|^\n")) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002289 if (global_env.linep >= elinep)
Eric Andersenff9eee42001-06-29 04:57:14 +00002290 err("word too long");
2291 else
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002292 *global_env.linep++ = c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002293 };
2294
Eric Andersenff9eee42001-06-29 04:57:14 +00002295 unget(c);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002296
Eric Andersen8401eea2004-08-04 19:16:54 +00002297 if (any(c, "\"'`$"))
Eric Andersenff9eee42001-06-29 04:57:14 +00002298 goto loop;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002299
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002300 *global_env.linep++ = '\0';
Eric Andersen12de6cf2004-08-04 19:19:10 +00002301
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002302 if (atstart) {
2303 c = rlookup(line);
2304 if (c != 0) {
2305 startl = 1;
2306 return c;
2307 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002308 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002309
Eric Andersenff9eee42001-06-29 04:57:14 +00002310 yylval.cp = strsave(line, areanum);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002311 return WORD;
Eric Andersenff9eee42001-06-29 04:57:14 +00002312}
2313
Eric Andersen12de6cf2004-08-04 19:19:10 +00002314
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002315static int collect(int c, int c1)
Eric Andersenff9eee42001-06-29 04:57:14 +00002316{
2317 char s[2];
2318
Eric Andersen12de6cf2004-08-04 19:19:10 +00002319 DBGPRINTF8(("COLLECT: enter, c=%d, c1=%d\n", c, c1));
2320
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002321 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002322 while ((c = my_getc(c1)) != c1) {
2323 if (c == 0) {
2324 unget(c);
2325 s[0] = c1;
2326 s[1] = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00002327 prs("no closing ");
2328 yyerror(s);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002329 return YYERRCODE;
Eric Andersenff9eee42001-06-29 04:57:14 +00002330 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002331 if (interactive && c == '\n' && global_env.iop <= iostack) {
Denis Vlasenko38f63192007-01-22 09:03:07 +00002332#if ENABLE_FEATURE_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00002333 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00002334#else
Eric Andersen8401eea2004-08-04 19:16:54 +00002335 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00002336#endif
2337 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002338 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002339 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002340
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002341 *global_env.linep++ = c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002342
2343 DBGPRINTF8(("COLLECT: return 0, line is %s\n", line));
2344
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002345 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002346}
2347
Eric Andersen12de6cf2004-08-04 19:19:10 +00002348/* "multiline commands" helper func */
2349/* see if next 2 chars form a shell multiline */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002350static int dual(int c)
Eric Andersenff9eee42001-06-29 04:57:14 +00002351{
2352 char s[3];
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002353 char *cp = s;
Eric Andersenff9eee42001-06-29 04:57:14 +00002354
Eric Andersen12de6cf2004-08-04 19:19:10 +00002355 DBGPRINTF8(("DUAL: enter, c=%d\n", c));
2356
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002357 *cp++ = c; /* c is the given "peek" char */
2358 *cp++ = my_getc(0); /* get next char of input */
2359 *cp = '\0'; /* add EOS marker */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002360
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002361 c = rlookup(s); /* see if 2 chars form a shell multiline */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002362 if (c == 0)
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002363 unget(*--cp); /* String is not a shell multiline, put peek char back */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002364
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002365 return c; /* String is multiline, return numeric multiline (restab) code */
Eric Andersenff9eee42001-06-29 04:57:14 +00002366}
2367
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002368static void diag(int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00002369{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002370 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002371
2372 DBGPRINTF8(("DIAG: enter, ec=%d\n", ec));
Eric Andersenff9eee42001-06-29 04:57:14 +00002373
2374 c = my_getc(0);
2375 if (c == '>' || c == '<') {
2376 if (c != ec)
2377 zzerr();
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002378 yylval.i = (ec == '>' ? IOWRITE | IOCAT : IOHERE);
Eric Andersenff9eee42001-06-29 04:57:14 +00002379 c = my_getc(0);
2380 } else
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002381 yylval.i = (ec == '>' ? IOWRITE : IOREAD);
Eric Andersenff9eee42001-06-29 04:57:14 +00002382 if (c != '&' || yylval.i == IOHERE)
2383 unget(c);
2384 else
2385 yylval.i |= IODUP;
2386}
2387
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002388static char *tree(unsigned size)
Eric Andersenff9eee42001-06-29 04:57:14 +00002389{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002390 char *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002391
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002392 t = getcell(size);
2393 if (t == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002394 DBGPRINTF2(("TREE: getcell(%d) failed!\n", size));
Eric Andersenff9eee42001-06-29 04:57:14 +00002395 prs("command line too complicated\n");
2396 fail();
2397 /* NOTREACHED */
2398 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002399 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002400}
2401
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002402
Eric Andersenff9eee42001-06-29 04:57:14 +00002403/* VARARGS1 */
2404/* ARGSUSED */
2405
2406/* -------- exec.c -------- */
2407
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002408static struct op **find1case(struct op *t, const char *w)
2409{
2410 struct op *t1;
2411 struct op **tp;
2412 char **wp;
2413 char *cp;
2414
2415 if (t == NULL) {
2416 DBGPRINTF3(("FIND1CASE: enter, t==NULL, returning.\n"));
2417 return NULL;
2418 }
2419
2420 DBGPRINTF3(("FIND1CASE: enter, t->type=%d (%s)\n", t->type,
2421 T_CMD_NAMES[t->type]));
2422
2423 if (t->type == TLIST) {
2424 tp = find1case(t->left, w);
2425 if (tp != NULL) {
2426 DBGPRINTF3(("FIND1CASE: found one to the left, returning tp=%p\n", tp));
2427 return tp;
2428 }
2429 t1 = t->right; /* TPAT */
2430 } else
2431 t1 = t;
2432
2433 for (wp = t1->words; *wp;) {
2434 cp = evalstr(*wp++, DOSUB);
2435 if (cp && gmatch(w, cp)) {
2436 DBGPRINTF3(("FIND1CASE: returning &t1->left= %p.\n",
2437 &t1->left));
2438 return &t1->left;
2439 }
2440 }
2441
2442 DBGPRINTF(("FIND1CASE: returning NULL\n"));
2443 return NULL;
2444}
2445
2446static struct op *findcase(struct op *t, const char *w)
2447{
2448 struct op **tp;
2449
2450 tp = find1case(t, w);
2451 return tp != NULL ? *tp : NULL;
2452}
2453
Eric Andersenff9eee42001-06-29 04:57:14 +00002454/*
2455 * execute tree
2456 */
2457
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002458static int execute(struct op *t, int *pin, int *pout, int act)
Eric Andersenff9eee42001-06-29 04:57:14 +00002459{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002460 struct op *t1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002461 volatile int i, rv, a;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002462 const char *cp;
2463 char **wp, **wp2;
Eric Andersenff9eee42001-06-29 04:57:14 +00002464 struct var *vp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002465 struct op *outtree_save;
Eric Andersenff9eee42001-06-29 04:57:14 +00002466 struct brkcon bc;
2467
2468#if __GNUC__
2469 /* Avoid longjmp clobbering */
2470 (void) &wp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002471#endif
Eric Andersenff9eee42001-06-29 04:57:14 +00002472
Eric Andersen12de6cf2004-08-04 19:19:10 +00002473 if (t == NULL) {
2474 DBGPRINTF4(("EXECUTE: enter, t==null, returning.\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002475 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002476 }
2477
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002478 DBGPRINTF(("EXECUTE: t=%p, t->type=%d (%s), t->words is %s\n", t,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002479 t->type, T_CMD_NAMES[t->type],
2480 ((t->words == NULL) ? "NULL" : t->words[0])));
2481
Eric Andersenff9eee42001-06-29 04:57:14 +00002482 rv = 0;
2483 a = areanum++;
2484 wp = (wp2 = t->words) != NULL
Eric Andersen8401eea2004-08-04 19:16:54 +00002485 ? eval(wp2, t->type == TCOM ? DOALL : DOALL & ~DOKEY)
2486 : NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00002487
Eric Andersen8401eea2004-08-04 19:16:54 +00002488 switch (t->type) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002489 case TDOT:
2490 DBGPRINTF3(("EXECUTE: TDOT\n"));
2491
2492 outtree_save = outtree;
2493
2494 newfile(evalstr(t->words[0], DOALL));
2495
2496 t->left = dowholefile(TLIST, 0);
2497 t->right = NULL;
2498
2499 outtree = outtree_save;
2500
2501 if (t->left)
2502 rv = execute(t->left, pin, pout, 0);
2503 if (t->right)
2504 rv = execute(t->right, pin, pout, 0);
2505 break;
2506
Eric Andersenff9eee42001-06-29 04:57:14 +00002507 case TPAREN:
Eric Andersen737f5fb2003-03-14 16:05:59 +00002508 rv = execute(t->left, pin, pout, 0);
2509 break;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002510
Eric Andersenff9eee42001-06-29 04:57:14 +00002511 case TCOM:
Denis Vlasenko489f93e2007-02-01 01:43:16 +00002512 rv = forkexec(t, pin, pout, act, wp);
Eric Andersenff9eee42001-06-29 04:57:14 +00002513 break;
2514
2515 case TPIPE:
2516 {
Eric Andersen8401eea2004-08-04 19:16:54 +00002517 int pv[2];
2518
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002519 rv = openpipe(pv);
2520 if (rv < 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00002521 break;
2522 pv[0] = remap(pv[0]);
2523 pv[1] = remap(pv[1]);
2524 (void) execute(t->left, pin, pv, 0);
2525 rv = execute(t->right, pv, pout, 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002526 }
2527 break;
2528
2529 case TLIST:
2530 (void) execute(t->left, pin, pout, 0);
2531 rv = execute(t->right, pin, pout, 0);
2532 break;
2533
2534 case TASYNC:
Eric Andersen8401eea2004-08-04 19:16:54 +00002535 {
2536 int hinteractive = interactive;
Eric Andersenff9eee42001-06-29 04:57:14 +00002537
Eric Andersen12de6cf2004-08-04 19:19:10 +00002538 DBGPRINTF7(("EXECUTE: TASYNC clause, calling vfork()...\n"));
2539
Eric Andersen8401eea2004-08-04 19:16:54 +00002540 i = vfork();
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002541 if (i == 0) { /* child */
Eric Andersen8401eea2004-08-04 19:16:54 +00002542 signal(SIGINT, SIG_IGN);
2543 signal(SIGQUIT, SIG_IGN);
2544 if (interactive)
2545 signal(SIGTERM, SIG_DFL);
2546 interactive = 0;
2547 if (pin == NULL) {
2548 close(0);
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00002549 xopen(bb_dev_null, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00002550 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002551 _exit(execute(t->left, pin, pout, FEXEC));
Eric Andersenff9eee42001-06-29 04:57:14 +00002552 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002553 interactive = hinteractive;
2554 if (i != -1) {
2555 setval(lookup("!"), putn(i));
2556 if (pin != NULL)
2557 closepipe(pin);
2558 if (interactive) {
2559 prs(putn(i));
2560 prs("\n");
2561 }
2562 } else
2563 rv = -1;
2564 setstatus(rv);
Eric Andersenff9eee42001-06-29 04:57:14 +00002565 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002566 break;
2567
2568 case TOR:
2569 case TAND:
2570 rv = execute(t->left, pin, pout, 0);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002571 t1 = t->right;
2572 if (t1 != NULL && (rv == 0) == (t->type == TAND))
Eric Andersenff9eee42001-06-29 04:57:14 +00002573 rv = execute(t1, pin, pout, 0);
2574 break;
2575
2576 case TFOR:
2577 if (wp == NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00002578 wp = dolv + 1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002579 i = dolc;
2580 if (i < 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00002581 i = 0;
2582 } else {
2583 i = -1;
Eric Andersen8401eea2004-08-04 19:16:54 +00002584 while (*wp++ != NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00002585 }
2586 vp = lookup(t->str);
2587 while (setjmp(bc.brkpt))
2588 if (isbreak)
2589 goto broken;
2590 brkset(&bc);
2591 for (t1 = t->left; i-- && *wp != NULL;) {
2592 setval(vp, *wp++);
2593 rv = execute(t1, pin, pout, 0);
2594 }
2595 brklist = brklist->nextlev;
2596 break;
2597
2598 case TWHILE:
2599 case TUNTIL:
2600 while (setjmp(bc.brkpt))
2601 if (isbreak)
2602 goto broken;
2603 brkset(&bc);
2604 t1 = t->left;
2605 while ((execute(t1, pin, pout, 0) == 0) == (t->type == TWHILE))
2606 rv = execute(t->right, pin, pout, 0);
2607 brklist = brklist->nextlev;
2608 break;
2609
2610 case TIF:
2611 case TELIF:
Eric Andersen8401eea2004-08-04 19:16:54 +00002612 if (t->right != NULL) {
2613 rv = !execute(t->left, pin, pout, 0) ?
2614 execute(t->right->left, pin, pout, 0) :
2615 execute(t->right->right, pin, pout, 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002616 }
2617 break;
2618
2619 case TCASE:
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002620 cp = evalstr(t->str, DOSUB | DOTRIM);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002621 if (cp == NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00002622 cp = "";
Eric Andersen12de6cf2004-08-04 19:19:10 +00002623
2624 DBGPRINTF7(("EXECUTE: TCASE, t->str is %s, cp is %s\n",
2625 ((t->str == NULL) ? "NULL" : t->str),
2626 ((cp == NULL) ? "NULL" : cp)));
2627
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002628 t1 = findcase(t->left, cp);
2629 if (t1 != NULL) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002630 DBGPRINTF7(("EXECUTE: TCASE, calling execute(t=%p, t1=%p)...\n", t, t1));
Eric Andersenff9eee42001-06-29 04:57:14 +00002631 rv = execute(t1, pin, pout, 0);
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002632 DBGPRINTF7(("EXECUTE: TCASE, back from execute(t=%p, t1=%p)...\n", t, t1));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002633 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002634 break;
2635
2636 case TBRACE:
2637/*
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002638 iopp = t->ioact;
2639 if (i)
Eric Andersenff9eee42001-06-29 04:57:14 +00002640 while (*iopp)
2641 if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) {
2642 rv = -1;
2643 break;
2644 }
2645*/
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002646 if (rv >= 0) {
2647 t1 = t->left;
2648 if (t1) {
2649 rv = execute(t1, pin, pout, 0);
2650 }
2651 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002652 break;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002653
2654 };
Eric Andersenff9eee42001-06-29 04:57:14 +00002655
Denis Vlasenkoe4712752007-04-14 15:08:41 +00002656 broken:
Eric Andersenff9eee42001-06-29 04:57:14 +00002657 t->words = wp2;
2658 isbreak = 0;
2659 freehere(areanum);
2660 freearea(areanum);
2661 areanum = a;
2662 if (interactive && intr) {
2663 closeall();
2664 fail();
2665 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002666
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002667 i = trapset;
2668 if (i != 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002669 trapset = 0;
2670 runtrap(i);
2671 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002672
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002673 DBGPRINTF(("EXECUTE: returning from t=%p, rv=%d\n", t, rv));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002674 return rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00002675}
2676
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002677typedef int (*builtin_func_ptr)(struct op *);
2678
Denis Vlasenkoe4712752007-04-14 15:08:41 +00002679static builtin_func_ptr inbuilt(const char *s)
2680{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002681 const struct builtincmd *bp;
2682
Denis Vlasenko95cb3262007-04-09 03:06:34 +00002683 for (bp = builtincmds; bp->name; bp++)
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002684 if (strcmp(bp->name, s) == 0)
2685 return bp->builtinfunc;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002686 return NULL;
2687}
2688
2689static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002690{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002691 pid_t newpid;
Eric Andersenff9eee42001-06-29 04:57:14 +00002692 int i, rv;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002693 builtin_func_ptr shcom = NULL;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002694 int f;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002695 const char *cp = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00002696 struct ioword **iopp;
2697 int resetsig;
2698 char **owp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002699 int forked = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002700
2701 int *hpin = pin;
2702 int *hpout = pout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002703 char *hwp;
2704 int hinteractive;
2705 int hintr;
Eric Andersen8401eea2004-08-04 19:16:54 +00002706 struct brkcon *hbrklist;
Eric Andersenff9eee42001-06-29 04:57:14 +00002707 int hexecflg;
2708
2709#if __GNUC__
2710 /* Avoid longjmp clobbering */
2711 (void) &pin;
2712 (void) &pout;
2713 (void) &wp;
2714 (void) &shcom;
2715 (void) &cp;
2716 (void) &resetsig;
2717 (void) &owp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002718#endif
Eric Andersenff9eee42001-06-29 04:57:14 +00002719
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002720 DBGPRINTF(("FORKEXEC: t=%p, pin %p, pout %p, act %d\n", t, pin,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002721 pout, act));
2722 DBGPRINTF7(("FORKEXEC: t->words is %s\n",
2723 ((t->words == NULL) ? "NULL" : t->words[0])));
2724
Eric Andersenff9eee42001-06-29 04:57:14 +00002725 owp = wp;
2726 resetsig = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00002727 rv = -1; /* system-detected error */
Eric Andersenff9eee42001-06-29 04:57:14 +00002728 if (t->type == TCOM) {
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00002729 while (*wp++ != NULL)
2730 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00002731 cp = *wp;
2732
2733 /* strip all initial assignments */
2734 /* not correct wrt PATH=yyy command etc */
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00002735 if (FLAG['x']) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002736 DBGPRINTF9(("FORKEXEC: echo'ing, cp=%p, wp=%p, owp=%p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00002737 cp, wp, owp));
Eric Andersen8401eea2004-08-04 19:16:54 +00002738 echo(cp ? wp : owp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002739 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002740
Eric Andersenff9eee42001-06-29 04:57:14 +00002741 if (cp == NULL && t->ioact == NULL) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002742 while ((cp = *owp++) != NULL && assign(cp, COPYV))
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00002743 continue;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002744 DBGPRINTF(("FORKEXEC: returning setstatus()\n"));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002745 return setstatus(0);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002746 }
2747 if (cp != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002748 shcom = inbuilt(cp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002749 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002750 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002751
Eric Andersenff9eee42001-06-29 04:57:14 +00002752 t->words = wp;
2753 f = act;
Eric Andersenff9eee42001-06-29 04:57:14 +00002754
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002755 DBGPRINTF(("FORKEXEC: shcom %p, f&FEXEC 0x%x, owp %p\n", shcom,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002756 f & FEXEC, owp));
2757
2758 if (shcom == NULL && (f & FEXEC) == 0) {
2759 /* Save values in case the child process alters them */
Eric Andersenff9eee42001-06-29 04:57:14 +00002760 hpin = pin;
2761 hpout = pout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002762 hwp = *wp;
2763 hinteractive = interactive;
2764 hintr = intr;
2765 hbrklist = brklist;
2766 hexecflg = execflg;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002767
Eric Andersen12de6cf2004-08-04 19:19:10 +00002768 DBGPRINTF3(("FORKEXEC: calling vfork()...\n"));
2769
2770 newpid = vfork();
2771
2772 if (newpid == -1) {
Denis Vlasenko89f0b342006-11-18 22:04:09 +00002773 DBGPRINTF(("FORKEXEC: ERROR, cannot vfork()!\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002774 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002775 }
2776
Denis Vlasenko489f93e2007-02-01 01:43:16 +00002777 if (newpid > 0) { /* Parent */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002778 /* Restore values */
Eric Andersenff9eee42001-06-29 04:57:14 +00002779 pin = hpin;
2780 pout = hpout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002781 *wp = hwp;
2782 interactive = hinteractive;
2783 intr = hintr;
2784 brklist = hbrklist;
2785 execflg = hexecflg;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002786/* moved up
Eric Andersenff9eee42001-06-29 04:57:14 +00002787 if (i == -1)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002788 return rv;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002789*/
Eric Andersenff9eee42001-06-29 04:57:14 +00002790 if (pin != NULL)
2791 closepipe(pin);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002792
2793 return (pout == NULL ? setstatus(waitfor(newpid, 0)) : 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002794 }
2795
Eric Andersen12de6cf2004-08-04 19:19:10 +00002796 /* Must be the child process, pid should be 0 */
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002797 DBGPRINTF(("FORKEXEC: child process, shcom=%p\n", shcom));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002798
Eric Andersenff9eee42001-06-29 04:57:14 +00002799 if (interactive) {
2800 signal(SIGINT, SIG_IGN);
2801 signal(SIGQUIT, SIG_IGN);
2802 resetsig = 1;
2803 }
2804 interactive = 0;
2805 intr = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002806 forked = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002807 brklist = 0;
2808 execflg = 0;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002809 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002810
Eric Andersenff9eee42001-06-29 04:57:14 +00002811 if (owp != NULL)
2812 while ((cp = *owp++) != NULL && assign(cp, COPYV))
2813 if (shcom == NULL)
2814 export(lookup(cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002815
Eric Andersenff9eee42001-06-29 04:57:14 +00002816#ifdef COMPIPE
2817 if ((pin != NULL || pout != NULL) && shcom != NULL && shcom != doexec) {
2818 err("piping to/from shell builtins not yet done");
Eric Andersen12de6cf2004-08-04 19:19:10 +00002819 if (forked)
2820 _exit(-1);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002821 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002822 }
2823#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00002824
Eric Andersenff9eee42001-06-29 04:57:14 +00002825 if (pin != NULL) {
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00002826 xmove_fd(pin[0], 0);
Denis Vlasenko847fa772008-01-28 22:45:43 +00002827 if (pin[1] != 0)
2828 close(pin[1]);
Eric Andersenff9eee42001-06-29 04:57:14 +00002829 }
2830 if (pout != NULL) {
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00002831 xmove_fd(pout[1], 1);
Denis Vlasenko847fa772008-01-28 22:45:43 +00002832 if (pout[1] != 1)
2833 close(pout[0]);
Eric Andersenff9eee42001-06-29 04:57:14 +00002834 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002835
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002836 iopp = t->ioact;
2837 if (iopp != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002838 if (shcom != NULL && shcom != doexec) {
2839 prs(cp);
2840 err(": cannot redirect shell command");
Eric Andersen12de6cf2004-08-04 19:19:10 +00002841 if (forked)
2842 _exit(-1);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002843 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002844 }
2845 while (*iopp)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002846 if (iosetup(*iopp++, pin != NULL, pout != NULL)) {
2847 if (forked)
2848 _exit(rv);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002849 return rv;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002850 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002851 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002852
2853 if (shcom) {
2854 i = setstatus((*shcom) (t));
2855 if (forked)
2856 _exit(i);
2857 DBGPRINTF(("FORKEXEC: returning i=%d\n", i));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002858 return i;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002859 }
2860
Eric Andersenff9eee42001-06-29 04:57:14 +00002861 /* should use FIOCEXCL */
Eric Andersen8401eea2004-08-04 19:16:54 +00002862 for (i = FDBASE; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00002863 close(i);
2864 if (resetsig) {
2865 signal(SIGINT, SIG_DFL);
2866 signal(SIGQUIT, SIG_DFL);
2867 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002868
Eric Andersen12de6cf2004-08-04 19:19:10 +00002869 if (t->type == TPAREN)
2870 _exit(execute(t->left, NOPIPE, NOPIPE, FEXEC));
2871 if (wp[0] == NULL)
2872 _exit(0);
2873
Eric Andersenfd7a4c82004-09-02 23:13:10 +00002874 cp = rexecve(wp[0], wp, makenv(0, NULL));
Eric Andersen8401eea2004-08-04 19:16:54 +00002875 prs(wp[0]);
2876 prs(": ");
Eric Andersen12de6cf2004-08-04 19:19:10 +00002877 err(cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00002878 if (!execflg)
2879 trap[0] = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002880
2881 DBGPRINTF(("FORKEXEC: calling leave(), pid=%d\n", newpid));
2882
Eric Andersenff9eee42001-06-29 04:57:14 +00002883 leave();
2884 /* NOTREACHED */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002885 _exit(1);
Eric Andersenff9eee42001-06-29 04:57:14 +00002886}
2887
2888/*
2889 * 0< 1> are ignored as required
2890 * within pipelines.
2891 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002892static int iosetup(struct ioword *iop, int pipein, int pipeout)
Eric Andersenff9eee42001-06-29 04:57:14 +00002893{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002894 int u = -1;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002895 char *cp = NULL;
2896 const char *msg;
Eric Andersenff9eee42001-06-29 04:57:14 +00002897
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002898 DBGPRINTF(("IOSETUP: iop %p, pipein %i, pipeout %i\n", iop,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002899 pipein, pipeout));
2900
Eric Andersenff9eee42001-06-29 04:57:14 +00002901 if (iop->io_unit == IODEFAULT) /* take default */
Eric Andersen8401eea2004-08-04 19:16:54 +00002902 iop->io_unit = iop->io_flag & (IOREAD | IOHERE) ? 0 : 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002903
Eric Andersenff9eee42001-06-29 04:57:14 +00002904 if (pipein && iop->io_unit == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002905 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002906
Eric Andersenff9eee42001-06-29 04:57:14 +00002907 if (pipeout && iop->io_unit == 1)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002908 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002909
Eric Andersen8401eea2004-08-04 19:16:54 +00002910 msg = iop->io_flag & (IOREAD | IOHERE) ? "open" : "create";
Eric Andersenff9eee42001-06-29 04:57:14 +00002911 if ((iop->io_flag & IOHERE) == 0) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002912 cp = iop->io_name; /* huh?? */
2913 cp = evalstr(cp, DOSUB | DOTRIM);
2914 if (cp == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002915 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002916 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002917
Eric Andersenff9eee42001-06-29 04:57:14 +00002918 if (iop->io_flag & IODUP) {
2919 if (cp[1] || (!isdigit(*cp) && *cp != '-')) {
2920 prs(cp);
2921 err(": illegal >& argument");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002922 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002923 }
2924 if (*cp == '-')
2925 iop->io_flag = IOCLOSE;
Eric Andersen8401eea2004-08-04 19:16:54 +00002926 iop->io_flag &= ~(IOREAD | IOWRITE);
Eric Andersenff9eee42001-06-29 04:57:14 +00002927 }
2928 switch (iop->io_flag) {
2929 case IOREAD:
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00002930 u = open(cp, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00002931 break;
2932
2933 case IOHERE:
Eric Andersen8401eea2004-08-04 19:16:54 +00002934 case IOHERE | IOXHERE:
2935 u = herein(iop->io_name, iop->io_flag & IOXHERE);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002936 cp = (char*)"here file";
Eric Andersenff9eee42001-06-29 04:57:14 +00002937 break;
2938
Eric Andersen8401eea2004-08-04 19:16:54 +00002939 case IOWRITE | IOCAT:
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00002940 u = open(cp, O_WRONLY);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002941 if (u >= 0) {
Denis Vlasenkoea620772006-10-14 02:23:43 +00002942 lseek(u, (long) 0, SEEK_END);
Eric Andersenff9eee42001-06-29 04:57:14 +00002943 break;
2944 }
2945 case IOWRITE:
2946 u = creat(cp, 0666);
2947 break;
2948
2949 case IODUP:
Eric Andersen8401eea2004-08-04 19:16:54 +00002950 u = dup2(*cp - '0', iop->io_unit);
Eric Andersenff9eee42001-06-29 04:57:14 +00002951 break;
2952
2953 case IOCLOSE:
2954 close(iop->io_unit);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002955 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002956 }
2957 if (u < 0) {
2958 prs(cp);
2959 prs(": cannot ");
2960 warn(msg);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002961 return 1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002962 }
2963 if (u != iop->io_unit) {
2964 dup2(u, iop->io_unit);
2965 close(u);
Eric Andersenff9eee42001-06-29 04:57:14 +00002966 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002967 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002968}
2969
Eric Andersenff9eee42001-06-29 04:57:14 +00002970/*
2971 * Enter a new loop level (marked for break/continue).
2972 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002973static void brkset(struct brkcon *bc)
Eric Andersenff9eee42001-06-29 04:57:14 +00002974{
2975 bc->nextlev = brklist;
2976 brklist = bc;
2977}
2978
2979/*
2980 * Wait for the last process created.
2981 * Print a message for each process found
2982 * that was killed by a signal.
2983 * Ignore interrupt signals while waiting
2984 * unless `canintr' is true.
2985 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002986static int waitfor(int lastpid, int canintr)
Eric Andersenff9eee42001-06-29 04:57:14 +00002987{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002988 int pid, rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00002989 int s;
2990 int oheedint = heedint;
2991
2992 heedint = 0;
2993 rv = 0;
2994 do {
2995 pid = wait(&s);
2996 if (pid == -1) {
2997 if (errno != EINTR || canintr)
2998 break;
2999 } else {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003000 rv = WAITSIG(s);
3001 if (rv != 0) {
Denis Vlasenko80b8b392007-06-25 10:55:35 +00003002 if (rv < ARRAY_SIZE(signame)) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003003 if (signame[rv] != NULL) {
3004 if (pid != lastpid) {
3005 prn(pid);
3006 prs(": ");
3007 }
3008 prs(signame[rv]);
3009 }
3010 } else {
3011 if (pid != lastpid) {
3012 prn(pid);
3013 prs(": ");
3014 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003015 prs("Signal ");
3016 prn(rv);
3017 prs(" ");
Eric Andersenff9eee42001-06-29 04:57:14 +00003018 }
3019 if (WAITCORE(s))
3020 prs(" - core dumped");
Denis Vlasenko80b8b392007-06-25 10:55:35 +00003021 if (rv >= ARRAY_SIZE(signame) || signame[rv])
Eric Andersenff9eee42001-06-29 04:57:14 +00003022 prs("\n");
3023 rv = -1;
3024 } else
3025 rv = WAITVAL(s);
3026 }
3027 } while (pid != lastpid);
3028 heedint = oheedint;
3029 if (intr) {
3030 if (interactive) {
3031 if (canintr)
3032 intr = 0;
3033 } else {
Eric Andersen8401eea2004-08-04 19:16:54 +00003034 if (exstat == 0)
3035 exstat = rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003036 onintr(0);
3037 }
3038 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003039 return rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003040}
3041
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003042static int setstatus(int s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003043{
3044 exstat = s;
3045 setval(lookup("?"), putn(s));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003046 return s;
Eric Andersenff9eee42001-06-29 04:57:14 +00003047}
3048
3049/*
3050 * PATH-searching interface to execve.
3051 * If getenv("PATH") were kept up-to-date,
3052 * execvp might be used.
3053 */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003054static const char *rexecve(char *c, char **v, char **envp)
Eric Andersenff9eee42001-06-29 04:57:14 +00003055{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003056 int i;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003057 const char *sp;
3058 char *tp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003059 int eacces = 0, asis = 0;
Eric Andersen1c039232001-07-07 00:05:55 +00003060 char *name = c;
Eric Andersen8401eea2004-08-04 19:16:54 +00003061
Denis Vlasenko80d14be2007-04-10 23:03:30 +00003062 if (ENABLE_FEATURE_SH_STANDALONE) {
Denis Vlasenko1aa7e472007-11-28 06:49:03 +00003063 if (find_applet_by_name(name) >= 0) {
Rob Landleya299efb2006-08-10 21:46:43 +00003064 /* We have to exec here since we vforked. Running
Denis Vlasenkoe4f2d062007-04-11 17:03:19 +00003065 * run_applet_and_exit() won't work and bad things
Rob Landleya299efb2006-08-10 21:46:43 +00003066 * will happen. */
Denis Vlasenkobdbbb7e2007-06-08 15:02:55 +00003067 execve(bb_busybox_exec_path, v, envp);
Rob Landleya299efb2006-08-10 21:46:43 +00003068 }
Eric Andersen1c039232001-07-07 00:05:55 +00003069 }
Eric Andersen1c039232001-07-07 00:05:55 +00003070
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003071 DBGPRINTF(("REXECVE: c=%p, v=%p, envp=%p\n", c, v, envp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003072
Eric Andersen8401eea2004-08-04 19:16:54 +00003073 sp = any('/', c) ? "" : path->value;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003074 asis = (*sp == '\0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003075 while (asis || *sp != '\0') {
3076 asis = 0;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003077 tp = global_env.linep;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003078 for (; *sp != '\0'; tp++) {
3079 *tp = *sp++;
3080 if (*tp == ':') {
3081 asis = (*sp == '\0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003082 break;
3083 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003084 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003085 if (tp != global_env.linep)
Eric Andersenff9eee42001-06-29 04:57:14 +00003086 *tp++ = '/';
Eric Andersen8401eea2004-08-04 19:16:54 +00003087 for (i = 0; (*tp++ = c[i++]) != '\0';);
Eric Andersen1c039232001-07-07 00:05:55 +00003088
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003089 DBGPRINTF3(("REXECVE: global_env.linep is %s\n", global_env.linep));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003090
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003091 execve(global_env.linep, v, envp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003092
Eric Andersenff9eee42001-06-29 04:57:14 +00003093 switch (errno) {
3094 case ENOEXEC:
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003095 *v = global_env.linep;
Eric Andersenff9eee42001-06-29 04:57:14 +00003096 tp = *--v;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003097 *v = global_env.linep;
Glenn L McGrathdc4e75e2003-09-02 02:36:18 +00003098 execve(DEFAULT_SHELL, v, envp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003099 *v = tp;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003100 return "no Shell";
Eric Andersenff9eee42001-06-29 04:57:14 +00003101
3102 case ENOMEM:
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003103 return (char *) bb_msg_memory_exhausted;
Eric Andersenff9eee42001-06-29 04:57:14 +00003104
3105 case E2BIG:
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003106 return "argument list too long";
Eric Andersenff9eee42001-06-29 04:57:14 +00003107
3108 case EACCES:
3109 eacces++;
3110 break;
3111 }
3112 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003113 return errno == ENOENT ? "not found" : "cannot execute";
Eric Andersenff9eee42001-06-29 04:57:14 +00003114}
3115
3116/*
3117 * Run the command produced by generator `f'
3118 * applied to stream `arg'.
3119 */
Eric Andersen8401eea2004-08-04 19:16:54 +00003120static int run(struct ioarg *argp, int (*f) (struct ioarg *))
Eric Andersenff9eee42001-06-29 04:57:14 +00003121{
3122 struct op *otree;
3123 struct wdblock *swdlist;
3124 struct wdblock *siolist;
3125 jmp_buf ev, rt;
3126 xint *ofail;
3127 int rv;
3128
3129#if __GNUC__
3130 /* Avoid longjmp clobbering */
3131 (void) &rv;
3132#endif
3133
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003134 DBGPRINTF(("RUN: enter, areanum %d, outtree %p, failpt %p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00003135 areanum, outtree, failpt));
3136
Eric Andersenff9eee42001-06-29 04:57:14 +00003137 areanum++;
3138 swdlist = wdlist;
3139 siolist = iolist;
3140 otree = outtree;
3141 ofail = failpt;
3142 rv = -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003143
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003144 errpt = ev;
3145 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003146 wdlist = 0;
3147 iolist = 0;
3148 pushio(argp, f);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003149 global_env.iobase = global_env.iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00003150 yynerrs = 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003151 failpt = rt;
3152 if (setjmp(failpt) == 0 && yyparse() == 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00003153 rv = execute(outtree, NOPIPE, NOPIPE, 0);
3154 quitenv();
Eric Andersen12de6cf2004-08-04 19:19:10 +00003155 } else {
3156 DBGPRINTF(("RUN: error from newenv()!\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00003157 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00003158
Eric Andersenff9eee42001-06-29 04:57:14 +00003159 wdlist = swdlist;
3160 iolist = siolist;
3161 failpt = ofail;
3162 outtree = otree;
3163 freearea(areanum--);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003164
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003165 return rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003166}
3167
3168/* -------- do.c -------- */
3169
3170/*
3171 * built-in commands: doX
3172 */
3173
Eric Andersen8401eea2004-08-04 19:16:54 +00003174static int dohelp(struct op *t)
Eric Andersen1c039232001-07-07 00:05:55 +00003175{
3176 int col;
3177 const struct builtincmd *x;
3178
Denis Vlasenko0ee39992006-12-24 15:23:28 +00003179 puts("\nBuilt-in commands:\n"
3180 "-------------------");
Eric Andersen1c039232001-07-07 00:05:55 +00003181
Denis Vlasenko95cb3262007-04-09 03:06:34 +00003182 col = 0;
3183 x = builtincmds;
3184 while (x->name) {
3185 col += printf("%c%s", ((col == 0) ? '\t' : ' '), x->name);
Eric Andersen1c039232001-07-07 00:05:55 +00003186 if (col > 60) {
Denis Vlasenko4daad902007-09-27 10:20:47 +00003187 bb_putchar('\n');
Eric Andersen1c039232001-07-07 00:05:55 +00003188 col = 0;
3189 }
Denis Vlasenko95cb3262007-04-09 03:06:34 +00003190 x++;
Eric Andersen1c039232001-07-07 00:05:55 +00003191 }
Denis Vlasenko80d14be2007-04-10 23:03:30 +00003192#if ENABLE_FEATURE_SH_STANDALONE
Eric Andersen1c039232001-07-07 00:05:55 +00003193 {
Denis Vlasenko1aa7e472007-11-28 06:49:03 +00003194 const char *applet = applet_names;
Eric Andersen1c039232001-07-07 00:05:55 +00003195
Denis Vlasenko1aa7e472007-11-28 06:49:03 +00003196 while (*applet) {
3197 col += printf("%c%s", ((col == 0) ? '\t' : ' '), applet);
Eric Andersen1c039232001-07-07 00:05:55 +00003198 if (col > 60) {
Denis Vlasenko4daad902007-09-27 10:20:47 +00003199 bb_putchar('\n');
Eric Andersen1c039232001-07-07 00:05:55 +00003200 col = 0;
3201 }
Denis Vlasenko1aa7e472007-11-28 06:49:03 +00003202 applet += strlen(applet) + 1;
Eric Andersen1c039232001-07-07 00:05:55 +00003203 }
3204 }
3205#endif
Denis Vlasenko0ee39992006-12-24 15:23:28 +00003206 puts("\n");
Eric Andersen1c039232001-07-07 00:05:55 +00003207 return EXIT_SUCCESS;
3208}
3209
Eric Andersen8401eea2004-08-04 19:16:54 +00003210static int dolabel(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003211{
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003212 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003213}
3214
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003215static int dochdir(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003216{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003217 const char *cp, *er;
Eric Andersenff9eee42001-06-29 04:57:14 +00003218
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003219 cp = t->words[1];
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003220 if (cp == NULL) {
3221 cp = homedir->value;
Denis Vlasenkod244c5e2007-02-09 17:30:14 +00003222 if (cp != NULL)
3223 goto do_cd;
3224 er = ": no home directory";
3225 } else {
3226 do_cd:
3227 if (chdir(cp) >= 0)
3228 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003229 er = ": bad directory";
Denis Vlasenkod244c5e2007-02-09 17:30:14 +00003230 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003231 prs(cp != NULL ? cp : "cd");
Eric Andersenff9eee42001-06-29 04:57:14 +00003232 err(er);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003233 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003234}
3235
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003236static int doshift(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003237{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003238 int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003239
Eric Andersen8401eea2004-08-04 19:16:54 +00003240 n = t->words[1] ? getn(t->words[1]) : 1;
3241 if (dolc < n) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003242 err("nothing to shift");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003243 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003244 }
3245 dolv[n] = dolv[0];
3246 dolv += n;
3247 dolc -= n;
3248 setval(lookup("#"), putn(dolc));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003249 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003250}
3251
3252/*
3253 * execute login and newgrp directly
3254 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003255static int dologin(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003256{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003257 const char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003258
3259 if (interactive) {
3260 signal(SIGINT, SIG_DFL);
3261 signal(SIGQUIT, SIG_DFL);
3262 }
Eric Andersenfd7a4c82004-09-02 23:13:10 +00003263 cp = rexecve(t->words[0], t->words, makenv(0, NULL));
Eric Andersen8401eea2004-08-04 19:16:54 +00003264 prs(t->words[0]);
3265 prs(": ");
3266 err(cp);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003267 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003268}
3269
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003270static int doumask(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003271{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003272 int i, n;
3273 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003274
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003275 cp = t->words[1];
3276 if (cp == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003277 i = umask(0);
3278 umask(i);
Eric Andersen8401eea2004-08-04 19:16:54 +00003279 for (n = 3 * 4; (n -= 3) >= 0;)
Denis Vlasenko4daad902007-09-27 10:20:47 +00003280 fputc('0' + ((i >> n) & 07), stderr);
3281 fputc('\n', stderr);
Eric Andersenff9eee42001-06-29 04:57:14 +00003282 } else {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003283/* huh??? '8','9' are not allowed! */
Eric Andersen8401eea2004-08-04 19:16:54 +00003284 for (n = 0; *cp >= '0' && *cp <= '9'; cp++)
3285 n = n * 8 + (*cp - '0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003286 umask(n);
3287 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003288 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003289}
3290
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003291static int doexec(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003292{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003293 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00003294 jmp_buf ex;
3295 xint *ofail;
3296
3297 t->ioact = NULL;
Eric Andersen8401eea2004-08-04 19:16:54 +00003298 for (i = 0; (t->words[i] = t->words[i + 1]) != NULL; i++);
Eric Andersenff9eee42001-06-29 04:57:14 +00003299 if (i == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003300 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003301 execflg = 1;
3302 ofail = failpt;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003303 failpt = ex;
3304 if (setjmp(failpt) == 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00003305 execute(t, NOPIPE, NOPIPE, FEXEC);
3306 failpt = ofail;
3307 execflg = 0;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003308 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003309}
3310
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003311static int dodot(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003312{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003313 int i;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003314 const char *sp;
3315 char *tp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003316 char *cp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003317 int maltmp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003318
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003319 DBGPRINTF(("DODOT: enter, t=%p, tleft %p, tright %p, global_env.linep is %s\n",
3320 t, t->left, t->right, ((global_env.linep == NULL) ? "NULL" : global_env.linep)));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003321
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003322 cp = t->words[1];
3323 if (cp == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00003324 DBGPRINTF(("DODOT: bad args, ret 0\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003325 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003326 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003327 DBGPRINTF(("DODOT: cp is %s\n", cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003328
Eric Andersen8401eea2004-08-04 19:16:54 +00003329 sp = any('/', cp) ? ":" : path->value;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003330
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003331 DBGPRINTF(("DODOT: sp is %s, global_env.linep is %s\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00003332 ((sp == NULL) ? "NULL" : sp),
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003333 ((global_env.linep == NULL) ? "NULL" : global_env.linep)));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003334
Eric Andersenff9eee42001-06-29 04:57:14 +00003335 while (*sp) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003336 tp = global_env.linep;
Eric Andersenff9eee42001-06-29 04:57:14 +00003337 while (*sp && (*tp = *sp++) != ':')
3338 tp++;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003339 if (tp != global_env.linep)
Eric Andersenff9eee42001-06-29 04:57:14 +00003340 *tp++ = '/';
Eric Andersen12de6cf2004-08-04 19:19:10 +00003341
Eric Andersen8401eea2004-08-04 19:16:54 +00003342 for (i = 0; (*tp++ = cp[i++]) != '\0';);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003343
3344 /* Original code */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003345 i = open(global_env.linep, O_RDONLY);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003346 if (i >= 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003347 exstat = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003348 maltmp = remap(i);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003349 DBGPRINTF(("DODOT: remap=%d, exstat=%d, global_env.iofd %d, i %d, global_env.linep is %s\n",
3350 maltmp, exstat, global_env.iofd, i, global_env.linep));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003351
3352 next(maltmp); /* Basically a PUSHIO */
3353
3354 DBGPRINTF(("DODOT: returning exstat=%d\n", exstat));
3355
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003356 return exstat;
Eric Andersenff9eee42001-06-29 04:57:14 +00003357 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003358 } /* while */
Eric Andersen12de6cf2004-08-04 19:19:10 +00003359
Eric Andersenff9eee42001-06-29 04:57:14 +00003360 prs(cp);
3361 err(": not found");
Eric Andersen12de6cf2004-08-04 19:19:10 +00003362
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003363 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003364}
3365
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003366static int dowait(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003367{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003368 int i;
3369 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003370
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003371 cp = t->words[1];
3372 if (cp != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003373 i = getn(cp);
3374 if (i == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003375 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003376 } else
3377 i = -1;
3378 setstatus(waitfor(i, 1));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003379 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003380}
3381
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003382static int doread(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003383{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003384 char *cp, **wp;
3385 int nb = 0;
3386 int nl = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003387
3388 if (t->words[1] == NULL) {
3389 err("Usage: read name ...");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003390 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003391 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003392 for (wp = t->words + 1; *wp; wp++) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003393 for (cp = global_env.linep; !nl && cp < elinep - 1; cp++) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003394 nb = read(0, cp, sizeof(*cp));
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003395 if (nb != sizeof(*cp))
Eric Andersenff9eee42001-06-29 04:57:14 +00003396 break;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003397 nl = (*cp == '\n');
3398 if (nl || (wp[1] && any(*cp, ifs->value)))
3399 break;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003400 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003401 *cp = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00003402 if (nb <= 0)
3403 break;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003404 setval(lookup(*wp), global_env.linep);
Eric Andersenff9eee42001-06-29 04:57:14 +00003405 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003406 return nb <= 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003407}
3408
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003409static int doeval(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003410{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003411 return RUN(awordlist, t->words + 1, wdchar);
Eric Andersenff9eee42001-06-29 04:57:14 +00003412}
3413
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003414static int dotrap(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003415{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003416 int n, i;
3417 int resetsig;
Eric Andersenff9eee42001-06-29 04:57:14 +00003418
3419 if (t->words[1] == NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00003420 for (i = 0; i <= _NSIG; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00003421 if (trap[i]) {
3422 prn(i);
3423 prs(": ");
3424 prs(trap[i]);
3425 prs("\n");
3426 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003427 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003428 }
3429 resetsig = isdigit(*t->words[1]);
3430 for (i = resetsig ? 1 : 2; t->words[i] != NULL; ++i) {
3431 n = getsig(t->words[i]);
3432 freecell(trap[n]);
3433 trap[n] = 0;
3434 if (!resetsig) {
3435 if (*t->words[1] != '\0') {
3436 trap[n] = strsave(t->words[1], 0);
3437 setsig(n, sig);
3438 } else
3439 setsig(n, SIG_IGN);
3440 } else {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00003441 if (interactive) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003442 if (n == SIGINT)
3443 setsig(n, onintr);
3444 else
Eric Andersen8401eea2004-08-04 19:16:54 +00003445 setsig(n, n == SIGQUIT ? SIG_IGN : SIG_DFL);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00003446 } else
Eric Andersenff9eee42001-06-29 04:57:14 +00003447 setsig(n, SIG_DFL);
3448 }
3449 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003450 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003451}
3452
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003453static int getsig(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003454{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003455 int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003456
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003457 n = getn(s);
3458 if (n < 0 || n > _NSIG) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003459 err("trap: bad signal number");
3460 n = 0;
3461 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003462 return n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003463}
3464
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003465static void setsig(int n, sighandler_t f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003466{
3467 if (n == 0)
3468 return;
3469 if (signal(n, SIG_IGN) != SIG_IGN || ourtrap[n]) {
3470 ourtrap[n] = 1;
3471 signal(n, f);
3472 }
3473}
3474
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003475static int getn(char *as)
Eric Andersenff9eee42001-06-29 04:57:14 +00003476{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003477 char *s;
3478 int n, m;
Eric Andersenff9eee42001-06-29 04:57:14 +00003479
3480 s = as;
3481 m = 1;
3482 if (*s == '-') {
3483 m = -1;
3484 s++;
3485 }
3486 for (n = 0; isdigit(*s); s++)
Eric Andersen8401eea2004-08-04 19:16:54 +00003487 n = (n * 10) + (*s - '0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003488 if (*s) {
3489 prs(as);
3490 err(": bad number");
3491 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003492 return n * m;
Eric Andersenff9eee42001-06-29 04:57:14 +00003493}
3494
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003495static int dobreak(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003496{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003497 return brkcontin(t->words[1], 1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003498}
3499
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003500static int docontinue(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003501{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003502 return brkcontin(t->words[1], 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003503}
3504
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003505static int brkcontin(char *cp, int val)
Eric Andersenff9eee42001-06-29 04:57:14 +00003506{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003507 struct brkcon *bc;
3508 int nl;
Eric Andersenff9eee42001-06-29 04:57:14 +00003509
Eric Andersen8401eea2004-08-04 19:16:54 +00003510 nl = cp == NULL ? 1 : getn(cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003511 if (nl <= 0)
3512 nl = 999;
3513 do {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003514 bc = brklist;
3515 if (bc == NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00003516 break;
3517 brklist = bc->nextlev;
3518 } while (--nl);
3519 if (nl) {
3520 err("bad break/continue level");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003521 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003522 }
3523 isbreak = val;
3524 longjmp(bc->brkpt, 1);
3525 /* NOTREACHED */
3526}
3527
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003528static int doexit(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003529{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003530 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003531
3532 execflg = 0;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003533 cp = t->words[1];
3534 if (cp != NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00003535 setstatus(getn(cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003536
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003537 DBGPRINTF(("DOEXIT: calling leave(), t=%p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003538
Eric Andersenff9eee42001-06-29 04:57:14 +00003539 leave();
3540 /* NOTREACHED */
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003541 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003542}
3543
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003544static int doexport(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003545{
Eric Andersen8401eea2004-08-04 19:16:54 +00003546 rdexp(t->words + 1, export, EXPORT);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003547 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003548}
3549
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003550static int doreadonly(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003551{
Eric Andersen8401eea2004-08-04 19:16:54 +00003552 rdexp(t->words + 1, ronly, RONLY);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003553 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003554}
3555
Eric Andersen8401eea2004-08-04 19:16:54 +00003556static void rdexp(char **wp, void (*f) (struct var *), int key)
Eric Andersenff9eee42001-06-29 04:57:14 +00003557{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003558 DBGPRINTF6(("RDEXP: enter, wp=%p, func=%p, key=%d\n", wp, f, key));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003559 DBGPRINTF6(("RDEXP: *wp=%s\n", *wp));
3560
Eric Andersenff9eee42001-06-29 04:57:14 +00003561 if (*wp != NULL) {
Matt Kraaif69bfc72001-07-12 19:39:59 +00003562 for (; *wp != NULL; wp++) {
3563 if (isassign(*wp)) {
3564 char *cp;
Eric Andersen8401eea2004-08-04 19:16:54 +00003565
Matt Kraaif69bfc72001-07-12 19:39:59 +00003566 assign(*wp, COPYV);
Eric Andersen8401eea2004-08-04 19:16:54 +00003567 for (cp = *wp; *cp != '='; cp++);
Matt Kraaif69bfc72001-07-12 19:39:59 +00003568 *cp = '\0';
3569 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003570 if (checkname(*wp))
Eric Andersen8401eea2004-08-04 19:16:54 +00003571 (*f) (lookup(*wp));
Eric Andersenff9eee42001-06-29 04:57:14 +00003572 else
3573 badid(*wp);
Matt Kraaif69bfc72001-07-12 19:39:59 +00003574 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003575 } else
3576 putvlist(key, 1);
3577}
3578
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003579static void badid(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003580{
3581 prs(s);
3582 err(": bad identifier");
3583}
3584
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003585static int doset(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003586{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003587 struct var *vp;
3588 char *cp;
3589 int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003590
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003591 cp = t->words[1];
3592 if (cp == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003593 for (vp = vlist; vp; vp = vp->next)
3594 varput(vp->name, 1);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003595 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003596 }
3597 if (*cp == '-') {
3598 /* bad: t->words++; */
Eric Andersen8401eea2004-08-04 19:16:54 +00003599 for (n = 0; (t->words[n] = t->words[n + 1]) != NULL; n++);
Eric Andersenff9eee42001-06-29 04:57:14 +00003600 if (*++cp == 0)
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003601 FLAG['x'] = FLAG['v'] = 0;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003602 else {
3603 for (; *cp; cp++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003604 switch (*cp) {
3605 case 'e':
3606 if (!interactive)
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003607 FLAG['e']++;
Eric Andersenff9eee42001-06-29 04:57:14 +00003608 break;
3609
3610 default:
Eric Andersen8401eea2004-08-04 19:16:54 +00003611 if (*cp >= 'a' && *cp <= 'z')
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003612 FLAG[(int) *cp]++;
Eric Andersenff9eee42001-06-29 04:57:14 +00003613 break;
3614 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003615 }
3616 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003617 setdash();
3618 }
3619 if (t->words[1]) {
3620 t->words[0] = dolv[0];
Eric Andersen8401eea2004-08-04 19:16:54 +00003621 for (n = 1; t->words[n]; n++)
3622 setarea((char *) t->words[n], 0);
3623 dolc = n - 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003624 dolv = t->words;
3625 setval(lookup("#"), putn(dolc));
Eric Andersen8401eea2004-08-04 19:16:54 +00003626 setarea((char *) (dolv - 1), 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003627 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003628 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003629}
3630
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003631static void varput(char *s, int out)
Eric Andersenff9eee42001-06-29 04:57:14 +00003632{
Matt Kraai69edfec2001-08-06 14:14:18 +00003633 if (isalnum(*s) || *s == '_') {
Eric Andersenff9eee42001-06-29 04:57:14 +00003634 write(out, s, strlen(s));
3635 write(out, "\n", 1);
3636 }
3637}
3638
3639
3640/*
3641 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
3642 * This file contains code for the times builtin.
Eric Andersenff9eee42001-06-29 04:57:14 +00003643 */
Eric Andersen8401eea2004-08-04 19:16:54 +00003644static int dotimes(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003645{
3646 struct tms buf;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003647 long clk_tck = sysconf(_SC_CLK_TCK);
Eric Andersenff9eee42001-06-29 04:57:14 +00003648
3649 times(&buf);
3650 printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
Eric Andersen8401eea2004-08-04 19:16:54 +00003651 (int) (buf.tms_utime / clk_tck / 60),
3652 ((double) buf.tms_utime) / clk_tck,
3653 (int) (buf.tms_stime / clk_tck / 60),
3654 ((double) buf.tms_stime) / clk_tck,
3655 (int) (buf.tms_cutime / clk_tck / 60),
3656 ((double) buf.tms_cutime) / clk_tck,
3657 (int) (buf.tms_cstime / clk_tck / 60),
3658 ((double) buf.tms_cstime) / clk_tck);
Eric Andersenff9eee42001-06-29 04:57:14 +00003659 return 0;
3660}
3661
3662
Eric Andersenff9eee42001-06-29 04:57:14 +00003663/* -------- eval.c -------- */
3664
3665/*
3666 * ${}
3667 * `command`
3668 * blank interpretation
3669 * quoting
3670 * glob
3671 */
3672
Eric Andersen8401eea2004-08-04 19:16:54 +00003673static char **eval(char **ap, int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003674{
3675 struct wdblock *wb;
3676 char **wp;
3677 char **wf;
3678 jmp_buf ev;
3679
3680#if __GNUC__
3681 /* Avoid longjmp clobbering */
3682 (void) &wp;
3683 (void) &ap;
3684#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00003685
3686 DBGPRINTF4(("EVAL: enter, f=%d\n", f));
3687
Eric Andersenff9eee42001-06-29 04:57:14 +00003688 wp = NULL;
3689 wb = NULL;
3690 wf = NULL;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003691 errpt = ev;
3692 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003693 while (*ap && isassign(*ap))
3694 expand(*ap++, &wb, f & ~DOGLOB);
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003695 if (FLAG['k']) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003696 for (wf = ap; *wf; wf++) {
3697 if (isassign(*wf))
3698 expand(*wf, &wb, f & ~DOGLOB);
3699 }
3700 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003701 for (wb = addword((char *) 0, wb); *ap; ap++) {
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003702 if (!FLAG['k'] || !isassign(*ap))
Eric Andersenff9eee42001-06-29 04:57:14 +00003703 expand(*ap, &wb, f & ~DOKEY);
3704 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003705 wb = addword((char *) 0, wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00003706 wp = getwords(wb);
3707 quitenv();
3708 } else
3709 gflg = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003710
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003711 return gflg ? (char **) NULL : wp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003712}
3713
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003714
Eric Andersenff9eee42001-06-29 04:57:14 +00003715/*
3716 * Make the exported environment from the exported
3717 * names in the dictionary. Keyword assignments
3718 * will already have been done.
3719 */
Eric Andersenfd7a4c82004-09-02 23:13:10 +00003720static char **makenv(int all, struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00003721{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003722 struct var *vp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003723
3724 DBGPRINTF5(("MAKENV: enter, all=%d\n", all));
Eric Andersenff9eee42001-06-29 04:57:14 +00003725
Eric Andersenff9eee42001-06-29 04:57:14 +00003726 for (vp = vlist; vp; vp = vp->next)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003727 if (all || vp->status & EXPORT)
Eric Andersenff9eee42001-06-29 04:57:14 +00003728 wb = addword(vp->name, wb);
Eric Andersen8401eea2004-08-04 19:16:54 +00003729 wb = addword((char *) 0, wb);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003730 return getwords(wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00003731}
3732
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003733static int expand(const char *cp, struct wdblock **wbp, int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003734{
3735 jmp_buf ev;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003736 char *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003737
3738#if __GNUC__
3739 /* Avoid longjmp clobbering */
3740 (void) &cp;
3741#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00003742
3743 DBGPRINTF3(("EXPAND: enter, f=%d\n", f));
3744
Eric Andersenff9eee42001-06-29 04:57:14 +00003745 gflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003746
Eric Andersenff9eee42001-06-29 04:57:14 +00003747 if (cp == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003748 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003749
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003750 if (!anys("$`'\"", cp) && !anys(ifs->value, cp)
3751 && ((f & DOGLOB) == 0 || !anys("[*?", cp))
3752 ) {
3753 xp = strsave(cp, areanum);
Eric Andersenff9eee42001-06-29 04:57:14 +00003754 if (f & DOTRIM)
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003755 unquote(xp);
3756 *wbp = addword(xp, *wbp);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003757 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003758 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003759 errpt = ev;
3760 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003761 PUSHIO(aword, cp, strchar);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003762 global_env.iobase = global_env.iop;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003763 while ((xp = blank(f)) && gflg == 0) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003764 global_env.linep = xp;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003765 xp = strsave(xp, areanum);
Eric Andersen8401eea2004-08-04 19:16:54 +00003766 if ((f & DOGLOB) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003767 if (f & DOTRIM)
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003768 unquote(xp);
3769 *wbp = addword(xp, *wbp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003770 } else
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003771 *wbp = glob(xp, *wbp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003772 }
3773 quitenv();
3774 } else
3775 gflg = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003776 return gflg == 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003777}
3778
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003779static char *evalstr(char *cp, int f)
3780{
3781 struct wdblock *wb;
3782
3783 DBGPRINTF6(("EVALSTR: enter, cp=%p, f=%d\n", cp, f));
3784
3785 wb = NULL;
3786 if (expand(cp, &wb, f)) {
3787 if (wb == NULL || wb->w_nword == 0
3788 || (cp = wb->w_words[0]) == NULL
3789 ) {
Denis Vlasenko8e858e22007-03-07 09:35:43 +00003790// TODO: I suspect that
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003791// char *evalstr(char *cp, int f) is actually
3792// const char *evalstr(const char *cp, int f)!
3793 cp = (char*)"";
3794 }
3795 DELETE(wb);
3796 } else
3797 cp = NULL;
3798 return cp;
3799}
3800
3801
Eric Andersenff9eee42001-06-29 04:57:14 +00003802/*
3803 * Blank interpretation and quoting
3804 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003805static char *blank(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003806{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003807 int c, c1;
3808 char *sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003809 int scanequals, foundequals;
3810
Eric Andersen12de6cf2004-08-04 19:19:10 +00003811 DBGPRINTF3(("BLANK: enter, f=%d\n", f));
3812
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003813 sp = global_env.linep;
Eric Andersenff9eee42001-06-29 04:57:14 +00003814 scanequals = f & DOKEY;
3815 foundequals = 0;
3816
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003817 loop:
3818 c = subgetc('"', foundequals);
3819 switch (c) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003820 case 0:
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003821 if (sp == global_env.linep)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003822 return 0;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003823 *global_env.linep++ = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003824 return sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003825
3826 default:
3827 if (f & DOBLANK && any(c, ifs->value))
3828 goto loop;
3829 break;
3830
3831 case '"':
3832 case '\'':
3833 scanequals = 0;
3834 if (INSUB())
3835 break;
3836 for (c1 = c; (c = subgetc(c1, 1)) != c1;) {
3837 if (c == 0)
3838 break;
3839 if (c == '\'' || !any(c, "$`\""))
3840 c |= QUOTE;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003841 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003842 }
3843 c = 0;
3844 }
3845 unget(c);
Matt Kraai69edfec2001-08-06 14:14:18 +00003846 if (!isalpha(c) && c != '_')
Eric Andersenff9eee42001-06-29 04:57:14 +00003847 scanequals = 0;
3848 for (;;) {
3849 c = subgetc('"', foundequals);
3850 if (c == 0 ||
Eric Andersen8401eea2004-08-04 19:16:54 +00003851 f & (DOBLANK && any(c, ifs->value)) ||
3852 (!INSUB() && any(c, "\"'"))) {
3853 scanequals = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003854 unget(c);
3855 if (any(c, "\"'"))
3856 goto loop;
3857 break;
3858 }
3859 if (scanequals) {
3860 if (c == '=') {
3861 foundequals = 1;
Eric Andersen8401eea2004-08-04 19:16:54 +00003862 scanequals = 0;
3863 } else if (!isalnum(c) && c != '_')
Eric Andersenff9eee42001-06-29 04:57:14 +00003864 scanequals = 0;
3865 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003866 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003867 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003868 *global_env.linep++ = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003869 return sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003870}
3871
3872/*
3873 * Get characters, substituting for ` and $
3874 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003875static int subgetc(char ec, int quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00003876{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003877 char c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003878
3879 DBGPRINTF3(("SUBGETC: enter, quoted=%d\n", quoted));
Eric Andersenff9eee42001-06-29 04:57:14 +00003880
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003881 again:
Eric Andersenff9eee42001-06-29 04:57:14 +00003882 c = my_getc(ec);
3883 if (!INSUB() && ec != '\'') {
3884 if (c == '`') {
3885 if (grave(quoted) == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003886 return 0;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003887 global_env.iop->task = XGRAVE;
Eric Andersenff9eee42001-06-29 04:57:14 +00003888 goto again;
3889 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003890 if (c == '$') {
3891 c = dollar(quoted);
3892 if (c == 0) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003893 global_env.iop->task = XDOLL;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003894 goto again;
3895 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003896 }
3897 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003898 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003899}
3900
3901/*
3902 * Prepare to generate the string returned by ${} substitution.
3903 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003904static int dollar(int quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00003905{
3906 int otask;
3907 struct io *oiop;
3908 char *dolp;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003909 char *s, c, *cp = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00003910 struct var *vp;
3911
Eric Andersen12de6cf2004-08-04 19:19:10 +00003912 DBGPRINTF3(("DOLLAR: enter, quoted=%d\n", quoted));
3913
Eric Andersenff9eee42001-06-29 04:57:14 +00003914 c = readc();
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003915 s = global_env.linep;
Eric Andersenff9eee42001-06-29 04:57:14 +00003916 if (c != '{') {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003917 *global_env.linep++ = c;
Matt Kraai69edfec2001-08-06 14:14:18 +00003918 if (isalpha(c) || c == '_') {
Eric Andersen8401eea2004-08-04 19:16:54 +00003919 while ((c = readc()) != 0 && (isalnum(c) || c == '_'))
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003920 if (global_env.linep < elinep)
3921 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003922 unget(c);
3923 }
3924 c = 0;
3925 } else {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003926 oiop = global_env.iop;
3927 otask = global_env.iop->task;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003928
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003929 global_env.iop->task = XOTHER;
Eric Andersen8401eea2004-08-04 19:16:54 +00003930 while ((c = subgetc('"', 0)) != 0 && c != '}' && c != '\n')
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003931 if (global_env.linep < elinep)
3932 *global_env.linep++ = c;
3933 if (oiop == global_env.iop)
3934 global_env.iop->task = otask;
Eric Andersenff9eee42001-06-29 04:57:14 +00003935 if (c != '}') {
3936 err("unclosed ${");
3937 gflg++;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003938 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003939 }
3940 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003941 if (global_env.linep >= elinep) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003942 err("string in ${} too long");
3943 gflg++;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003944 global_env.linep -= 10;
Eric Andersenff9eee42001-06-29 04:57:14 +00003945 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003946 *global_env.linep = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003947 if (*s)
Eric Andersen8401eea2004-08-04 19:16:54 +00003948 for (cp = s + 1; *cp; cp++)
Eric Andersenff9eee42001-06-29 04:57:14 +00003949 if (any(*cp, "=-+?")) {
3950 c = *cp;
3951 *cp++ = 0;
3952 break;
3953 }
3954 if (s[1] == 0 && (*s == '*' || *s == '@')) {
3955 if (dolc > 1) {
3956 /* currently this does not distinguish $* and $@ */
3957 /* should check dollar */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003958 global_env.linep = s;
Eric Andersen8401eea2004-08-04 19:16:54 +00003959 PUSHIO(awordlist, dolv + 1, dolchar);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003960 return 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00003961 } else { /* trap the nasty ${=} */
Eric Andersenff9eee42001-06-29 04:57:14 +00003962 s[0] = '1';
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003963 s[1] = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00003964 }
3965 }
3966 vp = lookup(s);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003967 dolp = vp->value;
3968 if (dolp == null) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003969 switch (c) {
3970 case '=':
3971 if (isdigit(*s)) {
3972 err("cannot use ${...=...} with $n");
3973 gflg++;
3974 break;
3975 }
3976 setval(vp, cp);
3977 dolp = vp->value;
3978 break;
3979
3980 case '-':
3981 dolp = strsave(cp, areanum);
3982 break;
3983
3984 case '?':
3985 if (*cp == 0) {
3986 prs("missing value for ");
3987 err(s);
3988 } else
3989 err(cp);
3990 gflg++;
3991 break;
3992 }
3993 } else if (c == '+')
3994 dolp = strsave(cp, areanum);
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003995 if (FLAG['u'] && dolp == null) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003996 prs("unset variable: ");
3997 err(s);
3998 gflg++;
3999 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004000 global_env.linep = s;
Eric Andersenff9eee42001-06-29 04:57:14 +00004001 PUSHIO(aword, dolp, quoted ? qstrchar : strchar);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004002 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004003}
4004
4005/*
4006 * Run the command in `...` and read its output.
4007 */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004008
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004009static int grave(int quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00004010{
Denis Vlasenko55f30b02007-03-24 22:42:29 +00004011 /* moved to G: static char child_cmd[LINELIM]; */
4012
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004013 const char *cp;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004014 int i;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004015 int j;
Eric Andersenff9eee42001-06-29 04:57:14 +00004016 int pf[2];
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004017 const char *src;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004018 char *dest;
4019 int count;
4020 int ignore;
4021 int ignore_once;
4022 char *argument_list[4];
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004023 struct wdblock *wb = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004024
4025#if __GNUC__
4026 /* Avoid longjmp clobbering */
4027 (void) &cp;
4028#endif
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004029
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004030 for (cp = global_env.iop->argp->aword; *cp != '`'; cp++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004031 if (*cp == 0) {
4032 err("no closing `");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004033 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004034 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004035 }
Eric Andersen737f5fb2003-03-14 16:05:59 +00004036
4037 /* string copy with dollar expansion */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004038 src = global_env.iop->argp->aword;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004039 dest = child_cmd;
4040 count = 0;
4041 ignore = 0;
4042 ignore_once = 0;
4043 while ((*src != '`') && (count < LINELIM)) {
4044 if (*src == '\'')
4045 ignore = !ignore;
4046 if (*src == '\\')
4047 ignore_once = 1;
4048 if (*src == '$' && !ignore && !ignore_once) {
4049 struct var *vp;
Denis Vlasenkoab801872007-12-02 08:35:37 +00004050 /* moved to G to reduce stack usage
Eric Andersen737f5fb2003-03-14 16:05:59 +00004051 char var_name[LINELIM];
4052 char alt_value[LINELIM];
Denis Vlasenkoab801872007-12-02 08:35:37 +00004053 */
4054#define var_name (G.grave__var_name)
4055#define alt_value (G.grave__alt_value)
Eric Andersen737f5fb2003-03-14 16:05:59 +00004056 int var_index = 0;
4057 int alt_index = 0;
4058 char operator = 0;
4059 int braces = 0;
4060 char *value;
4061
4062 src++;
4063 if (*src == '{') {
4064 braces = 1;
4065 src++;
4066 }
4067
4068 var_name[var_index++] = *src++;
Paul Fox54690dc2005-07-20 18:33:12 +00004069 while (isalnum(*src) || *src=='_')
Eric Andersen737f5fb2003-03-14 16:05:59 +00004070 var_name[var_index++] = *src++;
4071 var_name[var_index] = 0;
4072
4073 if (braces) {
4074 switch (*src) {
4075 case '}':
4076 break;
4077 case '-':
4078 case '=':
4079 case '+':
4080 case '?':
Eric Andersen8401eea2004-08-04 19:16:54 +00004081 operator = * src;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004082 break;
4083 default:
4084 err("unclosed ${\n");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004085 return 0;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004086 }
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004087 if (operator) {
Eric Andersen737f5fb2003-03-14 16:05:59 +00004088 src++;
4089 while (*src && (*src != '}')) {
4090 alt_value[alt_index++] = *src++;
4091 }
4092 alt_value[alt_index] = 0;
4093 if (*src != '}') {
4094 err("unclosed ${\n");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004095 return 0;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004096 }
4097 }
4098 src++;
4099 }
4100
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004101 if (isalpha(*var_name)) {
4102 /* let subshell handle it instead */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004103
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004104 char *namep = var_name;
4105
4106 *dest++ = '$';
4107 if (braces)
4108 *dest++ = '{';
4109 while (*namep)
4110 *dest++ = *namep++;
4111 if (operator) {
4112 char *altp = alt_value;
4113 *dest++ = operator;
4114 while (*altp)
4115 *dest++ = *altp++;
4116 }
4117 if (braces)
4118 *dest++ = '}';
4119
4120 wb = addword(lookup(var_name)->name, wb);
4121 } else {
4122 /* expand */
4123
4124 vp = lookup(var_name);
4125 if (vp->value != null)
4126 value = (operator == '+') ?
4127 alt_value : vp->value;
4128 else if (operator == '?') {
4129 err(alt_value);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004130 return 0;
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004131 } else if (alt_index && (operator != '+')) {
4132 value = alt_value;
4133 if (operator == '=')
4134 setval(vp, value);
4135 } else
4136 continue;
4137
4138 while (*value && (count < LINELIM)) {
4139 *dest++ = *value++;
4140 count++;
4141 }
Eric Andersen737f5fb2003-03-14 16:05:59 +00004142 }
Denis Vlasenkoab801872007-12-02 08:35:37 +00004143#undef var_name
4144#undef alt_value
Eric Andersen737f5fb2003-03-14 16:05:59 +00004145 } else {
4146 *dest++ = *src++;
4147 count++;
4148 ignore_once = 0;
4149 }
4150 }
4151 *dest = '\0';
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004152
Eric Andersenff9eee42001-06-29 04:57:14 +00004153 if (openpipe(pf) < 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004154 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004155
Eric Andersen8401eea2004-08-04 19:16:54 +00004156 while ((i = vfork()) == -1 && errno == EAGAIN);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004157
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004158 DBGPRINTF3(("GRAVE: i is %p\n", io));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004159
Eric Andersen737f5fb2003-03-14 16:05:59 +00004160 if (i < 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004161 closepipe(pf);
Eric Andersen8401eea2004-08-04 19:16:54 +00004162 err((char *) bb_msg_memory_exhausted);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004163 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004164 }
4165 if (i != 0) {
Denis Vlasenkofb0eba72008-01-02 19:55:04 +00004166 waitpid(i, NULL, 0); // safe_waitpid?
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004167 global_env.iop->argp->aword = ++cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004168 close(pf[1]);
Eric Andersen8401eea2004-08-04 19:16:54 +00004169 PUSHIO(afile, remap(pf[0]),
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004170 (int (*)(struct ioarg *)) ((quoted) ? qgravechar : gravechar));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004171 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004172 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004173 /* allow trapped signals */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004174 /* XXX - Maybe this signal stuff should go as well? */
Eric Andersen8401eea2004-08-04 19:16:54 +00004175 for (j = 0; j <= _NSIG; j++)
Eric Andersen737f5fb2003-03-14 16:05:59 +00004176 if (ourtrap[j] && signal(j, SIG_IGN) != SIG_IGN)
4177 signal(j, SIG_DFL);
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004178
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00004179 /* Testcase where below checks are needed:
4180 * close stdout & run this script:
4181 * files=`ls`
4182 * echo "$files" >zz
4183 */
4184 xmove_fd(pf[1], 1);
Denis Vlasenko847fa772008-01-28 22:45:43 +00004185 if (pf[0] != 1)
4186 close(pf[0]);
Eric Andersen737f5fb2003-03-14 16:05:59 +00004187
Eric Andersen8401eea2004-08-04 19:16:54 +00004188 argument_list[0] = (char *) DEFAULT_SHELL;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004189 argument_list[1] = (char *) "-c";
Eric Andersen737f5fb2003-03-14 16:05:59 +00004190 argument_list[2] = child_cmd;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004191 argument_list[3] = NULL;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004192
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004193 cp = rexecve(argument_list[0], argument_list, makenv(1, wb));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004194 prs(argument_list[0]);
4195 prs(": ");
4196 err(cp);
Eric Andersen737f5fb2003-03-14 16:05:59 +00004197 _exit(1);
Eric Andersenff9eee42001-06-29 04:57:14 +00004198}
4199
Eric Andersen737f5fb2003-03-14 16:05:59 +00004200
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004201static char *unquote(char *as)
Eric Andersenff9eee42001-06-29 04:57:14 +00004202{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004203 char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00004204
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004205 s = as;
4206 if (s != NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00004207 while (*s)
4208 *s++ &= ~QUOTE;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004209 return as;
Eric Andersenff9eee42001-06-29 04:57:14 +00004210}
4211
4212/* -------- glob.c -------- */
4213
4214/*
4215 * glob
4216 */
4217
4218#define scopy(x) strsave((x), areanum)
4219#define BLKSIZ 512
4220#define NDENT ((BLKSIZ+sizeof(struct dirent)-1)/sizeof(struct dirent))
4221
Eric Andersen8401eea2004-08-04 19:16:54 +00004222static struct wdblock *cl, *nl;
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00004223static const char spcl[] ALIGN1= "[?*";
Eric Andersenff9eee42001-06-29 04:57:14 +00004224
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004225static struct wdblock *glob(char *cp, struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004226{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004227 int i;
4228 char *pp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004229
4230 if (cp == 0)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004231 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004232 i = 0;
4233 for (pp = cp; *pp; pp++)
4234 if (any(*pp, spcl))
4235 i++;
4236 else if (!any(*pp & ~QUOTE, spcl))
4237 *pp &= ~QUOTE;
4238 if (i != 0) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004239 for (cl = addword(scopy(cp), NULL); anyspcl(cl); cl = nl) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004240 nl = newword(cl->w_nword * 2);
4241 for (i = 0; i < cl->w_nword; i++) { /* for each argument */
Eric Andersenff9eee42001-06-29 04:57:14 +00004242 for (pp = cl->w_words[i]; *pp; pp++)
4243 if (any(*pp, spcl)) {
4244 globname(cl->w_words[i], pp);
4245 break;
4246 }
4247 if (*pp == '\0')
4248 nl = addword(scopy(cl->w_words[i]), nl);
4249 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004250 for (i = 0; i < cl->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004251 DELETE(cl->w_words[i]);
4252 DELETE(cl);
4253 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004254 for (i = 0; i < cl->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004255 unquote(cl->w_words[i]);
Eric Andersen8401eea2004-08-04 19:16:54 +00004256 glob0((char *) cl->w_words, cl->w_nword, sizeof(char *), xstrcmp);
Eric Andersenff9eee42001-06-29 04:57:14 +00004257 if (cl->w_nword) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004258 for (i = 0; i < cl->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004259 wb = addword(cl->w_words[i], wb);
4260 DELETE(cl);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004261 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004262 }
4263 }
4264 wb = addword(unquote(cp), wb);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004265 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004266}
4267
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004268static void globname(char *we, char *pp)
Eric Andersenff9eee42001-06-29 04:57:14 +00004269{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004270 char *np, *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004271 char *name, *gp, *dp;
4272 int k;
4273 DIR *dirp;
4274 struct dirent *de;
Eric Andersen8401eea2004-08-04 19:16:54 +00004275 char dname[NAME_MAX + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00004276 struct stat dbuf;
4277
4278 for (np = we; np != pp; pp--)
4279 if (pp[-1] == '/')
4280 break;
Eric Andersen8401eea2004-08-04 19:16:54 +00004281 for (dp = cp = space((int) (pp - np) + 3); np < pp;)
Eric Andersenff9eee42001-06-29 04:57:14 +00004282 *cp++ = *np++;
4283 *cp++ = '.';
4284 *cp = '\0';
Eric Andersen8401eea2004-08-04 19:16:54 +00004285 for (gp = cp = space(strlen(pp) + 1); *np && *np != '/';)
Eric Andersenff9eee42001-06-29 04:57:14 +00004286 *cp++ = *np++;
4287 *cp = '\0';
4288 dirp = opendir(dp);
4289 if (dirp == 0) {
4290 DELETE(dp);
4291 DELETE(gp);
4292 return;
4293 }
4294 dname[NAME_MAX] = '\0';
Eric Andersen8401eea2004-08-04 19:16:54 +00004295 while ((de = readdir(dirp)) != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004296 /* XXX Hmmm... What this could be? (abial) */
4297 /*
Eric Andersen8401eea2004-08-04 19:16:54 +00004298 if (ent[j].d_ino == 0)
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004299 continue;
Eric Andersen8401eea2004-08-04 19:16:54 +00004300 */
Eric Andersenff9eee42001-06-29 04:57:14 +00004301 strncpy(dname, de->d_name, NAME_MAX);
Eric Andersen8401eea2004-08-04 19:16:54 +00004302 if (dname[0] == '.')
4303 if (*gp != '.')
4304 continue;
4305 for (k = 0; k < NAME_MAX; k++)
4306 if (any(dname[k], spcl))
4307 dname[k] |= QUOTE;
4308 if (gmatch(dname, gp)) {
4309 name = generate(we, pp, dname, np);
4310 if (*np && !anys(np, spcl)) {
4311 if (stat(name, &dbuf)) {
4312 DELETE(name);
Eric Andersenff9eee42001-06-29 04:57:14 +00004313 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00004314 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004315 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004316 nl = addword(name, nl);
4317 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004318 }
4319 closedir(dirp);
4320 DELETE(dp);
4321 DELETE(gp);
4322}
4323
4324/*
4325 * generate a pathname as below.
4326 * start..end1 / middle end
4327 * the slashes come for free
4328 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004329static char *generate(char *start1, char *end1, char *middle, char *end)
Eric Andersenff9eee42001-06-29 04:57:14 +00004330{
4331 char *p;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004332 char *op, *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004333
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004334 p = op = space((int)(end1 - start1) + strlen(middle) + strlen(end) + 2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004335 for (xp = start1; xp != end1;)
4336 *op++ = *xp++;
Eric Andersen8401eea2004-08-04 19:16:54 +00004337 for (xp = middle; (*op++ = *xp++) != '\0';);
Eric Andersenff9eee42001-06-29 04:57:14 +00004338 op--;
Eric Andersen8401eea2004-08-04 19:16:54 +00004339 for (xp = end; (*op++ = *xp++) != '\0';);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004340 return p;
Eric Andersenff9eee42001-06-29 04:57:14 +00004341}
4342
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004343static int anyspcl(struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004344{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004345 int i;
4346 char **wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004347
4348 wd = wb->w_words;
Eric Andersen8401eea2004-08-04 19:16:54 +00004349 for (i = 0; i < wb->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004350 if (anys(spcl, *wd++))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004351 return 1;
4352 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004353}
4354
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004355static int xstrcmp(char *p1, char *p2)
Eric Andersenff9eee42001-06-29 04:57:14 +00004356{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004357 return strcmp(*(char **) p1, *(char **) p2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004358}
4359
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004360
Eric Andersenff9eee42001-06-29 04:57:14 +00004361/* -------- word.c -------- */
4362
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004363static struct wdblock *newword(int nw)
Eric Andersenff9eee42001-06-29 04:57:14 +00004364{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004365 struct wdblock *wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004366
Eric Andersen8401eea2004-08-04 19:16:54 +00004367 wb = (struct wdblock *) space(sizeof(*wb) + nw * sizeof(char *));
Eric Andersenff9eee42001-06-29 04:57:14 +00004368 wb->w_bsize = nw;
4369 wb->w_nword = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004370 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004371}
4372
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004373static struct wdblock *addword(char *wd, struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004374{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004375 struct wdblock *wb2;
4376 int nw;
Eric Andersenff9eee42001-06-29 04:57:14 +00004377
4378 if (wb == NULL)
4379 wb = newword(NSTART);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004380 nw = wb->w_nword;
4381 if (nw >= wb->w_bsize) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004382 wb2 = newword(nw * 2);
Eric Andersen8401eea2004-08-04 19:16:54 +00004383 memcpy((char *) wb2->w_words, (char *) wb->w_words,
4384 nw * sizeof(char *));
Eric Andersenff9eee42001-06-29 04:57:14 +00004385 wb2->w_nword = nw;
4386 DELETE(wb);
4387 wb = wb2;
4388 }
4389 wb->w_words[wb->w_nword++] = wd;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004390 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004391}
Eric Andersen8401eea2004-08-04 19:16:54 +00004392
Denis Vlasenkoe4712752007-04-14 15:08:41 +00004393static char **getwords(struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004394{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004395 char **wd;
4396 int nb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004397
4398 if (wb == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004399 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004400 if (wb->w_nword == 0) {
4401 DELETE(wb);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004402 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004403 }
4404 wd = (char **) space(nb = sizeof(*wd) * wb->w_nword);
Eric Andersen8401eea2004-08-04 19:16:54 +00004405 memcpy((char *) wd, (char *) wb->w_words, nb);
4406 DELETE(wb); /* perhaps should done by caller */
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004407 return wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004408}
4409
"Vladimir N. Oleynik"ac973172005-09-22 14:38:17 +00004410static int (*func) (char *, char *);
4411static int globv;
Eric Andersenff9eee42001-06-29 04:57:14 +00004412
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004413static void glob3(char *i, char *j, char *k)
Eric Andersenff9eee42001-06-29 04:57:14 +00004414{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004415 char *index1, *index2, *index3;
4416 int c;
4417 int m;
4418
4419 m = globv;
4420 index1 = i;
4421 index2 = j;
4422 index3 = k;
4423 do {
4424 c = *index1;
4425 *index1++ = *index3;
4426 *index3++ = *index2;
4427 *index2++ = c;
4428 } while (--m);
4429}
4430
4431static void glob2(char *i, char *j)
4432{
4433 char *index1, *index2, c;
4434 int m;
4435
4436 m = globv;
4437 index1 = i;
4438 index2 = j;
4439 do {
4440 c = *index1;
4441 *index1++ = *index2;
4442 *index2++ = c;
4443 } while (--m);
Eric Andersenff9eee42001-06-29 04:57:14 +00004444}
4445
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004446static void glob1(char *base, char *lim)
Eric Andersenff9eee42001-06-29 04:57:14 +00004447{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004448 char *i, *j;
Eric Andersenff9eee42001-06-29 04:57:14 +00004449 int v2;
4450 char *lptr, *hptr;
4451 int c;
4452 unsigned n;
4453
Eric Andersenff9eee42001-06-29 04:57:14 +00004454 v2 = globv;
4455
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004456 top:
4457 n = (int) (lim - base);
4458 if (n <= v2)
Eric Andersenff9eee42001-06-29 04:57:14 +00004459 return;
Eric Andersen8401eea2004-08-04 19:16:54 +00004460 n = v2 * (n / (2 * v2));
4461 hptr = lptr = base + n;
Eric Andersenff9eee42001-06-29 04:57:14 +00004462 i = base;
Eric Andersen8401eea2004-08-04 19:16:54 +00004463 j = lim - v2;
4464 for (;;) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004465 if (i < lptr) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004466 c = (*func) (i, lptr);
4467 if (c == 0) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004468 lptr -= v2;
4469 glob2(i, lptr);
Eric Andersenff9eee42001-06-29 04:57:14 +00004470 continue;
4471 }
4472 if (c < 0) {
4473 i += v2;
4474 continue;
4475 }
4476 }
4477
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004478 begin:
Eric Andersenff9eee42001-06-29 04:57:14 +00004479 if (j > hptr) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004480 c = (*func) (hptr, j);
4481 if (c == 0) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004482 hptr += v2;
4483 glob2(hptr, j);
Eric Andersenff9eee42001-06-29 04:57:14 +00004484 goto begin;
4485 }
4486 if (c > 0) {
4487 if (i == lptr) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004488 hptr += v2;
4489 glob3(i, hptr, j);
4490 i = (lptr += v2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004491 goto begin;
4492 }
4493 glob2(i, j);
4494 j -= v2;
4495 i += v2;
4496 continue;
4497 }
4498 j -= v2;
4499 goto begin;
4500 }
4501
4502
4503 if (i == lptr) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004504 if (lptr - base >= lim - hptr) {
4505 glob1(hptr + v2, lim);
Eric Andersenff9eee42001-06-29 04:57:14 +00004506 lim = lptr;
4507 } else {
4508 glob1(base, lptr);
Eric Andersen8401eea2004-08-04 19:16:54 +00004509 base = hptr + v2;
Eric Andersenff9eee42001-06-29 04:57:14 +00004510 }
4511 goto top;
4512 }
4513
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004514 lptr -= v2;
4515 glob3(j, lptr, i);
4516 j = (hptr -= v2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004517 }
4518}
4519
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004520static void glob0(char *a0, unsigned a1, int a2, int (*a3) (char *, char *))
Eric Andersenff9eee42001-06-29 04:57:14 +00004521{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004522 func = a3;
4523 globv = a2;
4524 glob1(a0, a0 + a1 * a2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004525}
4526
Eric Andersenff9eee42001-06-29 04:57:14 +00004527
4528/* -------- io.c -------- */
4529
4530/*
4531 * shell IO
4532 */
4533
Eric Andersen8401eea2004-08-04 19:16:54 +00004534static int my_getc(int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00004535{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004536 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004537
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004538 if (global_env.linep > elinep) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004539 while ((c = readc()) != '\n' && c);
Eric Andersenff9eee42001-06-29 04:57:14 +00004540 err("input line too long");
4541 gflg++;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004542 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004543 }
4544 c = readc();
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004545 if ((ec != '\'') && (ec != '`') && (global_env.iop->task != XGRAVE)) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004546 if (c == '\\') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004547 c = readc();
4548 if (c == '\n' && ec != '\"')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004549 return my_getc(ec);
Eric Andersenff9eee42001-06-29 04:57:14 +00004550 c |= QUOTE;
4551 }
4552 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004553 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004554}
4555
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004556static void unget(int c)
Eric Andersenff9eee42001-06-29 04:57:14 +00004557{
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004558 if (global_env.iop >= global_env.iobase)
4559 global_env.iop->peekc = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004560}
4561
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004562static int eofc(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00004563{
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004564 return global_env.iop < global_env.iobase || (global_env.iop->peekc == 0 && global_env.iop->prev == 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004565}
4566
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004567static int readc(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00004568{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004569 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004570
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004571 RCPRINTF(("READC: global_env.iop %p, global_env.iobase %p\n", global_env.iop, global_env.iobase));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004572
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004573 for (; global_env.iop >= global_env.iobase; global_env.iop--) {
4574 RCPRINTF(("READC: global_env.iop %p, peekc 0x%x\n", global_env.iop, global_env.iop->peekc));
4575 c = global_env.iop->peekc;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004576 if (c != '\0') {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004577 global_env.iop->peekc = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004578 return c;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004579 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004580 if (global_env.iop->prev != 0) {
4581 c = (*global_env.iop->iofn)(global_env.iop->argp, global_env.iop);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004582 if (c != '\0') {
4583 if (c == -1) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004584 global_env.iop++;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004585 continue;
Eric Andersen8401eea2004-08-04 19:16:54 +00004586 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004587 if (global_env.iop == iostack)
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004588 ioecho(c);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004589 global_env.iop->prev = c;
4590 return global_env.iop->prev;
Eric Andersenff9eee42001-06-29 04:57:14 +00004591 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004592 if (global_env.iop->task == XIO && global_env.iop->prev != '\n') {
4593 global_env.iop->prev = 0;
4594 if (global_env.iop == iostack)
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004595 ioecho('\n');
4596 return '\n';
Eric Andersen8401eea2004-08-04 19:16:54 +00004597 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004598 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004599 if (global_env.iop->task == XIO) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004600 if (multiline) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004601 global_env.iop->prev = 0;
4602 return global_env.iop->prev;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004603 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004604 if (interactive && global_env.iop == iostack + 1) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004605#if ENABLE_FEATURE_EDITING
4606 current_prompt = prompt->value;
4607#else
4608 prs(prompt->value);
4609#endif
4610 }
4611 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004612 } /* FOR */
4613
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004614 if (global_env.iop >= iostack) {
4615 RCPRINTF(("READC: return 0, global_env.iop %p\n", global_env.iop));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004616 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004617 }
4618
4619 DBGPRINTF(("READC: leave()...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00004620 leave();
Eric Andersen12de6cf2004-08-04 19:19:10 +00004621
Eric Andersenff9eee42001-06-29 04:57:14 +00004622 /* NOTREACHED */
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004623 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004624}
4625
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004626static void ioecho(char c)
Eric Andersenff9eee42001-06-29 04:57:14 +00004627{
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00004628 if (FLAG['v'])
Eric Andersenff9eee42001-06-29 04:57:14 +00004629 write(2, &c, sizeof c);
4630}
4631
Eric Andersen12de6cf2004-08-04 19:19:10 +00004632
Eric Andersen8401eea2004-08-04 19:16:54 +00004633static void pushio(struct ioarg *argp, int (*fn) (struct ioarg *))
Eric Andersenff9eee42001-06-29 04:57:14 +00004634{
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004635 DBGPRINTF(("PUSHIO: argp %p, argp->afid 0x%x, global_env.iop %p\n", argp,
4636 argp->afid, global_env.iop));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004637
4638 /* Set env ptr for io source to next array spot and check for array overflow */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004639 if (++global_env.iop >= &iostack[NPUSH]) {
4640 global_env.iop--;
Eric Andersenff9eee42001-06-29 04:57:14 +00004641 err("Shell input nested too deeply");
4642 gflg++;
4643 return;
4644 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004645
4646 /* We did not overflow the NPUSH array spots so setup data structs */
4647
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004648 global_env.iop->iofn = (int (*)(struct ioarg *, struct io *)) fn; /* Store data source func ptr */
Eric Andersenff9eee42001-06-29 04:57:14 +00004649
4650 if (argp->afid != AFID_NOBUF)
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004651 global_env.iop->argp = argp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004652 else {
Eric Andersen12de6cf2004-08-04 19:19:10 +00004653
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004654 global_env.iop->argp = ioargstack + (global_env.iop - iostack); /* MAL - index into stack */
4655 *global_env.iop->argp = *argp; /* copy data from temp area into stack spot */
Eric Andersen12de6cf2004-08-04 19:19:10 +00004656
4657 /* MAL - mainbuf is for 1st data source (command line?) and all nested use a single shared buffer? */
4658
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004659 if (global_env.iop == &iostack[0])
4660 global_env.iop->argp->afbuf = &mainbuf;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004661 else
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004662 global_env.iop->argp->afbuf = &sharedbuf;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004663
4664 /* MAL - if not a termimal AND (commandline OR readable file) then give it a buffer id? */
4665 /* This line appears to be active when running scripts from command line */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004666 if ((isatty(global_env.iop->argp->afile) == 0)
4667 && (global_env.iop == &iostack[0]
4668 || lseek(global_env.iop->argp->afile, 0L, SEEK_CUR) != -1)) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00004669 if (++bufid == AFID_NOBUF) /* counter rollover check, AFID_NOBUF = 11111111 */
4670 bufid = AFID_ID; /* AFID_ID = 0 */
4671
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004672 global_env.iop->argp->afid = bufid; /* assign buffer id */
Eric Andersen8401eea2004-08-04 19:16:54 +00004673 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004674
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004675 DBGPRINTF(("PUSHIO: iostack %p, global_env.iop %p, afbuf %p\n",
4676 iostack, global_env.iop, global_env.iop->argp->afbuf));
4677 DBGPRINTF(("PUSHIO: mbuf %p, sbuf %p, bid %d, global_env.iop %p\n",
4678 &mainbuf, &sharedbuf, bufid, global_env.iop));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004679
Eric Andersenff9eee42001-06-29 04:57:14 +00004680 }
4681
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004682 global_env.iop->prev = ~'\n';
4683 global_env.iop->peekc = 0;
4684 global_env.iop->xchar = 0;
4685 global_env.iop->nlcount = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004686
Eric Andersenff9eee42001-06-29 04:57:14 +00004687 if (fn == filechar || fn == linechar)
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004688 global_env.iop->task = XIO;
Eric Andersen8401eea2004-08-04 19:16:54 +00004689 else if (fn == (int (*)(struct ioarg *)) gravechar
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004690 || fn == (int (*)(struct ioarg *)) qgravechar)
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004691 global_env.iop->task = XGRAVE;
Eric Andersenff9eee42001-06-29 04:57:14 +00004692 else
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004693 global_env.iop->task = XOTHER;
Eric Andersenff9eee42001-06-29 04:57:14 +00004694}
4695
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004696static struct io *setbase(struct io *ip)
Eric Andersenff9eee42001-06-29 04:57:14 +00004697{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004698 struct io *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004699
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004700 xp = global_env.iobase;
4701 global_env.iobase = ip;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004702 return xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004703}
4704
4705/*
4706 * Input generating functions
4707 */
4708
4709/*
4710 * Produce the characters of a string, then a newline, then EOF.
4711 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004712static int nlchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004713{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004714 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004715
4716 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004717 return 0;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004718 c = *ap->aword++;
4719 if (c == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004720 ap->aword = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004721 return '\n';
Eric Andersenff9eee42001-06-29 04:57:14 +00004722 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004723 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004724}
4725
4726/*
4727 * Given a list of words, produce the characters
4728 * in them, with a space after each word.
4729 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004730static int wdchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004731{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004732 char c;
4733 char **wl;
Eric Andersenff9eee42001-06-29 04:57:14 +00004734
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004735 wl = ap->awordlist;
4736 if (wl == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004737 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004738 if (*wl != NULL) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004739 c = *(*wl)++;
4740 if (c != 0)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004741 return c & 0177;
Eric Andersenff9eee42001-06-29 04:57:14 +00004742 ap->awordlist++;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004743 return ' ';
Eric Andersenff9eee42001-06-29 04:57:14 +00004744 }
4745 ap->awordlist = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004746 return '\n';
Eric Andersenff9eee42001-06-29 04:57:14 +00004747}
4748
4749/*
4750 * Return the characters of a list of words,
4751 * producing a space between them.
4752 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004753static int dolchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004754{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004755 char *wp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004756
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004757 wp = *ap->awordlist++;
4758 if (wp != NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004759 PUSHIO(aword, wp, *ap->awordlist == NULL ? strchar : xxchar);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004760 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004761 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004762 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004763}
4764
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004765static int xxchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004766{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004767 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004768
4769 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004770 return 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004771 c = *ap->aword++;
4772 if (c == '\0') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004773 ap->aword = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004774 return ' ';
Eric Andersenff9eee42001-06-29 04:57:14 +00004775 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004776 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004777}
4778
4779/*
4780 * Produce the characters from a single word (string).
4781 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004782static int strchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004783{
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004784 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004785 return 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004786 return *ap->aword++;
Eric Andersenff9eee42001-06-29 04:57:14 +00004787}
4788
4789/*
4790 * Produce quoted characters from a single word (string).
4791 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004792static int qstrchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004793{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004794 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004795
Denis Vlasenkob2abef32007-01-01 18:18:04 +00004796 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004797 return 0;
Denis Vlasenkob2abef32007-01-01 18:18:04 +00004798 c = *ap->aword++;
4799 if (c)
4800 c |= QUOTE;
4801 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004802}
4803
4804/*
4805 * Return the characters from a file.
4806 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004807static int filechar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004808{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004809 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004810 char c;
4811 struct iobuf *bp = ap->afbuf;
4812
4813 if (ap->afid != AFID_NOBUF) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004814 i = (ap->afid != bp->id);
4815 if (i || bp->bufp == bp->ebufp) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004816 if (i)
Denis Vlasenkoea620772006-10-14 02:23:43 +00004817 lseek(ap->afile, ap->afpos, SEEK_SET);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004818
Eric Andersen8401eea2004-08-04 19:16:54 +00004819 i = safe_read(ap->afile, bp->buf, sizeof(bp->buf));
4820 if (i <= 0) {
4821 closef(ap->afile);
4822 return 0;
4823 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004824
Eric Andersen8401eea2004-08-04 19:16:54 +00004825 bp->id = ap->afid;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004826 bp->bufp = bp->buf;
4827 bp->ebufp = bp->bufp + i;
Eric Andersen8401eea2004-08-04 19:16:54 +00004828 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004829
Eric Andersen8401eea2004-08-04 19:16:54 +00004830 ap->afpos++;
4831 return *bp->bufp++ & 0177;
Eric Andersenff9eee42001-06-29 04:57:14 +00004832 }
Denis Vlasenko38f63192007-01-22 09:03:07 +00004833#if ENABLE_FEATURE_EDITING
Eric Andersen737f5fb2003-03-14 16:05:59 +00004834 if (interactive && isatty(ap->afile)) {
Denis Vlasenko55f30b02007-03-24 22:42:29 +00004835 /* moved to G: static char filechar_cmdbuf[BUFSIZ]; */
Eric Andersen8401eea2004-08-04 19:16:54 +00004836 static int position = 0, size = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004837
Eric Andersen8401eea2004-08-04 19:16:54 +00004838 while (size == 0 || position >= size) {
Denis Vlasenko55f30b02007-03-24 22:42:29 +00004839 read_line_input(current_prompt, filechar_cmdbuf, BUFSIZ, line_input_state);
4840 size = strlen(filechar_cmdbuf);
Eric Andersen8401eea2004-08-04 19:16:54 +00004841 position = 0;
4842 }
Denis Vlasenko55f30b02007-03-24 22:42:29 +00004843 c = filechar_cmdbuf[position];
Eric Andersen8401eea2004-08-04 19:16:54 +00004844 position++;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004845 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004846 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004847#endif
4848 i = safe_read(ap->afile, &c, sizeof(c));
4849 return i == sizeof(c) ? (c & 0x7f) : (closef(ap->afile), 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004850}
4851
4852/*
4853 * Return the characters from a here temp file.
4854 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004855static int herechar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004856{
4857 char c;
4858
Eric Andersenff9eee42001-06-29 04:57:14 +00004859 if (read(ap->afile, &c, sizeof(c)) != sizeof(c)) {
4860 close(ap->afile);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004861 c = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00004862 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004863 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004864}
4865
4866/*
4867 * Return the characters produced by a process (`...`).
4868 * Quote them if required, and remove any trailing newline characters.
4869 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004870static int gravechar(struct ioarg *ap, struct io *iop)
Eric Andersenff9eee42001-06-29 04:57:14 +00004871{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004872 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004873
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004874 c = qgravechar(ap, iop) & ~QUOTE;
4875 if (c == '\n')
Eric Andersenff9eee42001-06-29 04:57:14 +00004876 c = ' ';
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004877 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004878}
4879
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004880static int qgravechar(struct ioarg *ap, struct io *iop)
Eric Andersenff9eee42001-06-29 04:57:14 +00004881{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004882 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004883
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004884 DBGPRINTF3(("QGRAVECHAR: enter, ap=%p, iop=%p\n", ap, iop));
Eric Andersenff9eee42001-06-29 04:57:14 +00004885
4886 if (iop->xchar) {
4887 if (iop->nlcount) {
4888 iop->nlcount--;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004889 return '\n' | QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00004890 }
4891 c = iop->xchar;
4892 iop->xchar = 0;
4893 } else if ((c = filechar(ap)) == '\n') {
4894 iop->nlcount = 1;
4895 while ((c = filechar(ap)) == '\n')
4896 iop->nlcount++;
4897 iop->xchar = c;
4898 if (c == 0)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004899 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004900 iop->nlcount--;
4901 c = '\n';
4902 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004903 return c != 0 ? c | QUOTE : 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004904}
4905
4906/*
4907 * Return a single command (usually the first line) from a file.
4908 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004909static int linechar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004910{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004911 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004912
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004913 c = filechar(ap);
4914 if (c == '\n') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004915 if (!multiline) {
4916 closef(ap->afile);
Eric Andersen8401eea2004-08-04 19:16:54 +00004917 ap->afile = -1; /* illegal value */
Eric Andersenff9eee42001-06-29 04:57:14 +00004918 }
4919 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004920 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004921}
4922
Eric Andersenff9eee42001-06-29 04:57:14 +00004923/*
4924 * remap fd into Shell's fd space
4925 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004926static int remap(int fd)
Eric Andersenff9eee42001-06-29 04:57:14 +00004927{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004928 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004929 int map[NOFILE];
Eric Andersen12de6cf2004-08-04 19:19:10 +00004930 int newfd;
4931
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004932 DBGPRINTF(("REMAP: fd=%d, global_env.iofd=%d\n", fd, global_env.iofd));
Eric Andersenff9eee42001-06-29 04:57:14 +00004933
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004934 if (fd < global_env.iofd) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004935 for (i = 0; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004936 map[i] = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004937
Eric Andersenff9eee42001-06-29 04:57:14 +00004938 do {
4939 map[fd] = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004940 newfd = dup(fd);
4941 fd = newfd;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004942 } while (fd >= 0 && fd < global_env.iofd);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004943
Eric Andersen8401eea2004-08-04 19:16:54 +00004944 for (i = 0; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004945 if (map[i])
4946 close(i);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004947
Eric Andersenff9eee42001-06-29 04:57:14 +00004948 if (fd < 0)
4949 err("too many files open in shell");
4950 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004951
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004952 return fd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004953}
4954
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004955static int openpipe(int *pv)
Eric Andersenff9eee42001-06-29 04:57:14 +00004956{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004957 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004958
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004959 i = pipe(pv);
4960 if (i < 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00004961 err("can't create pipe - try again");
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004962 return i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004963}
4964
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004965static void closepipe(int *pv)
Eric Andersenff9eee42001-06-29 04:57:14 +00004966{
4967 if (pv != NULL) {
4968 close(*pv++);
4969 close(*pv);
4970 }
4971}
4972
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004973
Eric Andersenff9eee42001-06-29 04:57:14 +00004974/* -------- here.c -------- */
4975
4976/*
4977 * here documents
4978 */
4979
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004980static void markhere(char *s, struct ioword *iop)
Eric Andersenff9eee42001-06-29 04:57:14 +00004981{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004982 struct here *h, *lh;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004983
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004984 DBGPRINTF7(("MARKHERE: enter, s=%p\n", s));
Eric Andersenff9eee42001-06-29 04:57:14 +00004985
4986 h = (struct here *) space(sizeof(struct here));
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004987 if (h == NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00004988 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004989
Eric Andersenff9eee42001-06-29 04:57:14 +00004990 h->h_tag = evalstr(s, DOSUB);
4991 if (h->h_tag == 0)
4992 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004993
Eric Andersenff9eee42001-06-29 04:57:14 +00004994 h->h_iop = iop;
4995 iop->io_name = 0;
4996 h->h_next = NULL;
4997 if (inhere == 0)
4998 inhere = h;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004999 else {
5000 for (lh = inhere; lh != NULL; lh = lh->h_next) {
Eric Andersenff9eee42001-06-29 04:57:14 +00005001 if (lh->h_next == 0) {
5002 lh->h_next = h;
5003 break;
5004 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00005005 }
5006 }
Eric Andersen8401eea2004-08-04 19:16:54 +00005007 iop->io_flag |= IOHERE | IOXHERE;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00005008 for (s = h->h_tag; *s; s++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00005009 if (*s & QUOTE) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005010 iop->io_flag &= ~IOXHERE;
5011 *s &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00005012 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00005013 }
Eric Andersenff9eee42001-06-29 04:57:14 +00005014 h->h_dosub = iop->io_flag & IOXHERE;
5015}
5016
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005017static void gethere(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00005018{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005019 struct here *h, *hp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005020
5021 DBGPRINTF7(("GETHERE: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00005022
5023 /* Scan here files first leaving inhere list in place */
5024 for (hp = h = inhere; h != NULL; hp = h, h = h->h_next)
Eric Andersen8401eea2004-08-04 19:16:54 +00005025 readhere(&h->h_iop->io_name, h->h_tag, h->h_dosub ? 0 : '\'');
Eric Andersenff9eee42001-06-29 04:57:14 +00005026
5027 /* Make inhere list active - keep list intact for scraphere */
5028 if (hp != NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005029 hp->h_next = acthere;
5030 acthere = inhere;
5031 inhere = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00005032 }
5033}
5034
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005035static void readhere(char **name, char *s, int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00005036{
5037 int tf;
5038 char tname[30] = ".msh_XXXXXX";
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005039 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00005040 jmp_buf ev;
Eric Andersen8401eea2004-08-04 19:16:54 +00005041 char myline[LINELIM + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00005042 char *thenext;
5043
Mike Frysinger02d8fa42006-05-05 20:32:31 +00005044 DBGPRINTF7(("READHERE: enter, name=%p, s=%p\n", name, s));
Eric Andersen12de6cf2004-08-04 19:19:10 +00005045
Eric Andersenff9eee42001-06-29 04:57:14 +00005046 tf = mkstemp(tname);
5047 if (tf < 0)
5048 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005049
Eric Andersenff9eee42001-06-29 04:57:14 +00005050 *name = strsave(tname, areanum);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00005051 errpt = ev;
5052 if (newenv(setjmp(errpt)) != 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00005053 unlink(tname);
5054 else {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005055 pushio(global_env.iop->argp, (int (*)(struct ioarg *)) global_env.iop->iofn);
5056 global_env.iobase = global_env.iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00005057 for (;;) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005058 if (interactive && global_env.iop <= iostack) {
Denis Vlasenko38f63192007-01-22 09:03:07 +00005059#if ENABLE_FEATURE_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00005060 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00005061#else
Eric Andersen8401eea2004-08-04 19:16:54 +00005062 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00005063#endif
5064 }
5065 thenext = myline;
5066 while ((c = my_getc(ec)) != '\n' && c) {
5067 if (ec == '\'')
Eric Andersen8401eea2004-08-04 19:16:54 +00005068 c &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00005069 if (thenext >= &myline[LINELIM]) {
5070 c = 0;
5071 break;
5072 }
5073 *thenext++ = c;
5074 }
5075 *thenext = 0;
5076 if (strcmp(s, myline) == 0 || c == 0)
5077 break;
5078 *thenext++ = '\n';
Eric Andersen8401eea2004-08-04 19:16:54 +00005079 write(tf, myline, (int) (thenext - myline));
Eric Andersenff9eee42001-06-29 04:57:14 +00005080 }
5081 if (c == 0) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005082 prs("here document `");
5083 prs(s);
5084 err("' unclosed");
Eric Andersenff9eee42001-06-29 04:57:14 +00005085 }
5086 quitenv();
5087 }
5088 close(tf);
5089}
5090
5091/*
5092 * open here temp file.
5093 * if unquoted here, expand here temp file into second temp file.
5094 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005095static int herein(char *hname, int xdoll)
Eric Andersenff9eee42001-06-29 04:57:14 +00005096{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005097 int hf;
Eric Andersenff9eee42001-06-29 04:57:14 +00005098 int tf;
5099
5100#if __GNUC__
5101 /* Avoid longjmp clobbering */
5102 (void) &tf;
5103#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00005104 if (hname == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00005105 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005106
5107 DBGPRINTF7(("HEREIN: hname is %s, xdoll=%d\n", hname, xdoll));
5108
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005109 hf = open(hname, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00005110 if (hf < 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00005111 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005112
Eric Andersenff9eee42001-06-29 04:57:14 +00005113 if (xdoll) {
5114 char c;
5115 char tname[30] = ".msh_XXXXXX";
5116 jmp_buf ev;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005117
Eric Andersenff9eee42001-06-29 04:57:14 +00005118 tf = mkstemp(tname);
5119 if (tf < 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00005120 return -1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00005121 errpt = ev;
5122 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00005123 PUSHIO(afile, hf, herechar);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005124 setbase(global_env.iop);
Eric Andersenff9eee42001-06-29 04:57:14 +00005125 while ((c = subgetc(0, 0)) != 0) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005126 c &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00005127 write(tf, &c, sizeof c);
5128 }
5129 quitenv();
5130 } else
5131 unlink(tname);
5132 close(tf);
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005133 tf = open(tname, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00005134 unlink(tname);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00005135 return tf;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00005136 }
5137 return hf;
Eric Andersenff9eee42001-06-29 04:57:14 +00005138}
5139
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005140static void scraphere(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00005141{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005142 struct here *h;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005143
5144 DBGPRINTF7(("SCRAPHERE: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00005145
5146 for (h = inhere; h != NULL; h = h->h_next) {
5147 if (h->h_iop && h->h_iop->io_name)
Eric Andersen8401eea2004-08-04 19:16:54 +00005148 unlink(h->h_iop->io_name);
Eric Andersenff9eee42001-06-29 04:57:14 +00005149 }
5150 inhere = NULL;
5151}
5152
5153/* unlink here temp files before a freearea(area) */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005154static void freehere(int area)
Eric Andersenff9eee42001-06-29 04:57:14 +00005155{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005156 struct here *h, *hl;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005157
5158 DBGPRINTF6(("FREEHERE: enter, area=%d\n", area));
Eric Andersenff9eee42001-06-29 04:57:14 +00005159
5160 hl = NULL;
5161 for (h = acthere; h != NULL; h = h->h_next)
5162 if (getarea((char *) h) >= area) {
5163 if (h->h_iop->io_name != NULL)
5164 unlink(h->h_iop->io_name);
5165 if (hl == NULL)
5166 acthere = h->h_next;
5167 else
5168 hl->h_next = h->h_next;
5169 } else
5170 hl = h;
5171}
5172
5173
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005174/* -------- sh.c -------- */
5175/*
5176 * shell
5177 */
5178
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00005179int msh_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005180int msh_main(int argc, char **argv)
5181{
5182 int f;
5183 char *s;
5184 int cflag;
5185 char *name, **ap;
5186 int (*iof) (struct ioarg *);
5187
Denis Vlasenkoab801872007-12-02 08:35:37 +00005188 INIT_G();
5189
Denis Vlasenko55f30b02007-03-24 22:42:29 +00005190 sharedbuf.id = AFID_NOBUF;
5191 mainbuf.id = AFID_NOBUF;
Denis Vlasenko55f30b02007-03-24 22:42:29 +00005192 elinep = line + sizeof(line) - 5;
5193
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005194#if ENABLE_FEATURE_EDITING
5195 line_input_state = new_line_input_t(FOR_SHELL);
5196#endif
5197
5198 DBGPRINTF(("MSH_MAIN: argc %d, environ %p\n", argc, environ));
5199
5200 initarea();
5201 ap = environ;
5202 if (ap != NULL) {
5203 while (*ap)
5204 assign(*ap++, !COPYV);
5205 for (ap = environ; *ap;)
5206 export(lookup(*ap++));
5207 }
5208 closeall();
5209 areanum = 1;
5210
5211 shell = lookup("SHELL");
5212 if (shell->value == null)
5213 setval(shell, (char *)DEFAULT_SHELL);
5214 export(shell);
5215
5216 homedir = lookup("HOME");
5217 if (homedir->value == null)
5218 setval(homedir, "/");
5219 export(homedir);
5220
5221 setval(lookup("$"), putn(getpid()));
5222
5223 path = lookup("PATH");
5224 if (path->value == null) {
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005225 /* Can be merged with same string elsewhere in bbox */
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005226 if (geteuid() == 0)
Denis Vlasenkof5f75c52007-06-12 22:35:19 +00005227 setval(path, bb_default_root_path);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005228 else
Denis Vlasenkof5f75c52007-06-12 22:35:19 +00005229 setval(path, bb_default_path);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005230 }
5231 export(path);
5232
5233 ifs = lookup("IFS");
5234 if (ifs->value == null)
5235 setval(ifs, " \t\n");
5236
5237#ifdef MSHDEBUG
5238 mshdbg_var = lookup("MSHDEBUG");
5239 if (mshdbg_var->value == null)
5240 setval(mshdbg_var, "0");
5241#endif
5242
5243 prompt = lookup("PS1");
5244#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
5245 if (prompt->value == null)
5246#endif
5247 setval(prompt, DEFAULT_USER_PROMPT);
5248 if (geteuid() == 0) {
5249 setval(prompt, DEFAULT_ROOT_PROMPT);
5250 prompt->status &= ~EXPORT;
5251 }
5252 cprompt = lookup("PS2");
5253#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
5254 if (cprompt->value == null)
5255#endif
5256 setval(cprompt, "> ");
5257
5258 iof = filechar;
5259 cflag = 0;
5260 name = *argv++;
5261 if (--argc >= 1) {
5262 if (argv[0][0] == '-' && argv[0][1] != '\0') {
5263 for (s = argv[0] + 1; *s; s++)
5264 switch (*s) {
5265 case 'c':
5266 prompt->status &= ~EXPORT;
5267 cprompt->status &= ~EXPORT;
5268 setval(prompt, "");
5269 setval(cprompt, "");
5270 cflag = 1;
5271 if (--argc > 0)
5272 PUSHIO(aword, *++argv, iof = nlchar);
5273 break;
5274
5275 case 'q':
5276 qflag = SIG_DFL;
5277 break;
5278
5279 case 's':
5280 /* standard input */
5281 break;
5282
5283 case 't':
5284 prompt->status &= ~EXPORT;
5285 setval(prompt, "");
5286 iof = linechar;
5287 break;
5288
5289 case 'i':
5290 interactive++;
5291 default:
5292 if (*s >= 'a' && *s <= 'z')
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00005293 FLAG[(int) *s]++;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005294 }
5295 } else {
5296 argv--;
5297 argc++;
5298 }
5299
5300 if (iof == filechar && --argc > 0) {
5301 setval(prompt, "");
5302 setval(cprompt, "");
5303 prompt->status &= ~EXPORT;
5304 cprompt->status &= ~EXPORT;
5305
5306/* Shell is non-interactive, activate printf-based debug */
5307#ifdef MSHDEBUG
5308 mshdbg = (int) (((char) (mshdbg_var->value[0])) - '0');
5309 if (mshdbg < 0)
5310 mshdbg = 0;
5311#endif
5312 DBGPRINTF(("MSH_MAIN: calling newfile()\n"));
5313
5314 name = *++argv;
5315 if (newfile(name))
5316 exit(1); /* Exit on error */
5317 }
5318 }
5319
5320 setdash();
5321
5322 /* This won't be true if PUSHIO has been called, say from newfile() above */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005323 if (global_env.iop < iostack) {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005324 PUSHIO(afile, 0, iof);
5325 if (isatty(0) && isatty(1) && !cflag) {
5326 interactive++;
5327#if !ENABLE_FEATURE_SH_EXTRA_QUIET
5328#ifdef MSHDEBUG
Denis Vlasenkoca525b42007-06-13 12:27:17 +00005329 printf("\n\n%s built-in shell (msh with debug)\n", bb_banner);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005330#else
Denis Vlasenkoca525b42007-06-13 12:27:17 +00005331 printf("\n\n%s built-in shell (msh)\n", bb_banner);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005332#endif
5333 printf("Enter 'help' for a list of built-in commands.\n\n");
5334#endif
5335 }
5336 }
5337
5338 signal(SIGQUIT, qflag);
5339 if (name && name[0] == '-') {
5340 interactive++;
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005341 f = open(".profile", O_RDONLY);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005342 if (f >= 0)
5343 next(remap(f));
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005344 f = open("/etc/profile", O_RDONLY);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005345 if (f >= 0)
5346 next(remap(f));
5347 }
5348 if (interactive)
5349 signal(SIGTERM, sig);
5350
5351 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
5352 signal(SIGINT, onintr);
5353 dolv = argv;
5354 dolc = argc;
5355 dolv[0] = name;
5356 if (dolc > 1) {
5357 for (ap = ++argv; --argc > 0;) {
5358 *ap = *argv++;
5359 if (assign(*ap, !COPYV)) {
5360 dolc--; /* keyword */
5361 } else {
5362 ap++;
5363 }
5364 }
5365 }
5366 setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc));
5367
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005368 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 +00005369
5370 for (;;) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005371 if (interactive && global_env.iop <= iostack) {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005372#if ENABLE_FEATURE_EDITING
5373 current_prompt = prompt->value;
5374#else
5375 prs(prompt->value);
5376#endif
5377 }
5378 onecommand();
5379 /* Ensure that getenv("PATH") stays current */
5380 setenv("PATH", path->value, 1);
5381 }
5382
5383 DBGPRINTF(("MSH_MAIN: returning.\n"));
5384}
5385
5386
Eric Andersenff9eee42001-06-29 04:57:14 +00005387/*
5388 * Copyright (c) 1987,1997, Prentice Hall
5389 * All rights reserved.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005390 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005391 * Redistribution and use of the MINIX operating system in source and
5392 * binary forms, with or without modification, are permitted provided
5393 * that the following conditions are met:
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005394 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005395 * Redistributions of source code must retain the above copyright
5396 * notice, this list of conditions and the following disclaimer.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005397 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005398 * Redistributions in binary form must reproduce the above
5399 * copyright notice, this list of conditions and the following
5400 * disclaimer in the documentation and/or other materials provided
5401 * with the distribution.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005402 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005403 * Neither the name of Prentice Hall nor the names of the software
5404 * authors or contributors may be used to endorse or promote
5405 * products derived from this software without specific prior
5406 * written permission.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005407 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005408 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND
5409 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
5410 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
5411 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
5412 * IN NO EVENT SHALL PRENTICE HALL OR ANY AUTHORS OR CONTRIBUTORS BE
5413 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
5414 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
5415 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
5416 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
5417 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
5418 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
5419 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5420 *
5421 */