blob: 9edf793ab094baf513685c88abdc5917efcadfd8 [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 */
Denis Vlasenko489f93e2007-02-01 01:43:16 +000087extern char **environ;
Mike Frysinger67a32ad2007-03-09 08:25:24 +000088#endif
Eric Andersenff9eee42001-06-29 04:57:14 +000089
Mike Frysinger17811882006-05-05 20:33:07 +000090/*#define MSHDEBUG 1*/
Eric Andersen12de6cf2004-08-04 19:19:10 +000091
92#ifdef MSHDEBUG
Mike Frysinger14ff19b2006-06-20 20:37:01 +000093int mshdbg = MSHDEBUG;
Eric Andersen12de6cf2004-08-04 19:19:10 +000094
Denis Vlasenko51742f42007-04-12 00:32:05 +000095#define DBGPRINTF(x) if (mshdbg>0) printf x
96#define DBGPRINTF0(x) if (mshdbg>0) printf x
97#define DBGPRINTF1(x) if (mshdbg>1) printf x
98#define DBGPRINTF2(x) if (mshdbg>2) printf x
99#define DBGPRINTF3(x) if (mshdbg>3) printf x
100#define DBGPRINTF4(x) if (mshdbg>4) printf x
101#define DBGPRINTF5(x) if (mshdbg>5) printf x
102#define DBGPRINTF6(x) if (mshdbg>6) printf x
103#define DBGPRINTF7(x) if (mshdbg>7) printf x
104#define DBGPRINTF8(x) if (mshdbg>8) printf x
105#define DBGPRINTF9(x) if (mshdbg>9) printf x
Eric Andersen12de6cf2004-08-04 19:19:10 +0000106
107int mshdbg_rc = 0;
108
Denis Vlasenko51742f42007-04-12 00:32:05 +0000109#define RCPRINTF(x) if (mshdbg_rc) printf x
Eric Andersen12de6cf2004-08-04 19:19:10 +0000110
111#else
112
113#define DBGPRINTF(x)
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000114#define DBGPRINTF0(x) ((void)0)
115#define DBGPRINTF1(x) ((void)0)
116#define DBGPRINTF2(x) ((void)0)
117#define DBGPRINTF3(x) ((void)0)
118#define DBGPRINTF4(x) ((void)0)
119#define DBGPRINTF5(x) ((void)0)
120#define DBGPRINTF6(x) ((void)0)
121#define DBGPRINTF7(x) ((void)0)
122#define DBGPRINTF8(x) ((void)0)
123#define DBGPRINTF9(x) ((void)0)
Eric Andersen12de6cf2004-08-04 19:19:10 +0000124
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000125#define RCPRINTF(x) ((void)0)
Eric Andersen12de6cf2004-08-04 19:19:10 +0000126
127#endif /* MSHDEBUG */
128
129
Denis Vlasenko38f63192007-01-22 09:03:07 +0000130#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
Mike Frysinger2a131752006-06-06 06:26:12 +0000131# define DEFAULT_ROOT_PROMPT "\\u:\\w> "
132# define DEFAULT_USER_PROMPT "\\u:\\w$ "
133#else
134# define DEFAULT_ROOT_PROMPT "# "
135# define DEFAULT_USER_PROMPT "$ "
136#endif
137
138
Eric Andersenff9eee42001-06-29 04:57:14 +0000139/* -------- sh.h -------- */
140/*
141 * shell
142 */
143
Eric Andersen12de6cf2004-08-04 19:19:10 +0000144#define LINELIM 2100
145#define NPUSH 8 /* limit to input nesting */
Eric Andersenff9eee42001-06-29 04:57:14 +0000146
Eric Andersen392947c2002-12-11 07:42:46 +0000147#undef NOFILE
Eric Andersen12de6cf2004-08-04 19:19:10 +0000148#define NOFILE 20 /* Number of open files */
149#define NUFILE 10 /* Number of user-accessible files */
150#define FDBASE 10 /* First file usable by Shell */
Eric Andersenff9eee42001-06-29 04:57:14 +0000151
152/*
153 * values returned by wait
154 */
Denis Vlasenko5f9468e2007-04-14 13:22:09 +0000155#define WAITSIG(s) ((s) & 0177)
156#define WAITVAL(s) (((s) >> 8) & 0377)
157#define WAITCORE(s) (((s) & 0200) != 0)
Eric Andersenff9eee42001-06-29 04:57:14 +0000158
159/*
Eric Andersenaff114c2004-04-14 17:51:38 +0000160 * library and system definitions
Eric Andersenff9eee42001-06-29 04:57:14 +0000161 */
Eric Andersen8401eea2004-08-04 19:16:54 +0000162typedef void xint; /* base type of jmp_buf, for not broken compilers */
Eric Andersenff9eee42001-06-29 04:57:14 +0000163
164/*
165 * shell components
166 */
Eric Andersenff9eee42001-06-29 04:57:14 +0000167#define NOBLOCK ((struct op *)NULL)
168#define NOWORD ((char *)NULL)
169#define NOWORDS ((char **)NULL)
170#define NOPIPE ((int *)NULL)
171
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000172/*
173 * redirection
174 */
175struct ioword {
176 short io_unit; /* unit affected */
177 short io_flag; /* action (below) */
178 char *io_name; /* file name */
179};
180
181#define IOREAD 1 /* < */
182#define IOHERE 2 /* << (here file) */
183#define IOWRITE 4 /* > */
184#define IOCAT 8 /* >> */
185#define IOXHERE 16 /* ${}, ` in << */
186#define IODUP 32 /* >&digit */
187#define IOCLOSE 64 /* >&- */
188
189#define IODEFAULT (-1) /* token for default IO unit */
190
191
Eric Andersenff9eee42001-06-29 04:57:14 +0000192/*
193 * Description of a command or an operation on commands.
194 * Might eventually use a union.
195 */
196struct op {
Eric Andersen8401eea2004-08-04 19:16:54 +0000197 int type; /* operation type, see below */
198 char **words; /* arguments to a command */
199 struct ioword **ioact; /* IO actions (eg, < > >>) */
Eric Andersenff9eee42001-06-29 04:57:14 +0000200 struct op *left;
201 struct op *right;
Eric Andersen8401eea2004-08-04 19:16:54 +0000202 char *str; /* identifier for case and for */
Eric Andersenff9eee42001-06-29 04:57:14 +0000203};
204
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000205#define TCOM 1 /* command */
206#define TPAREN 2 /* (c-list) */
207#define TPIPE 3 /* a | b */
208#define TLIST 4 /* a [&;] b */
209#define TOR 5 /* || */
210#define TAND 6 /* && */
211#define TFOR 7
212#define TDO 8
213#define TCASE 9
214#define TIF 10
215#define TWHILE 11
216#define TUNTIL 12
217#define TELIF 13
218#define TPAT 14 /* pattern in case */
219#define TBRACE 15 /* {c-list} */
220#define TASYNC 16 /* c & */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000221/* Added to support "." file expansion */
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000222#define TDOT 17
Eric Andersen12de6cf2004-08-04 19:19:10 +0000223
224/* Strings for names to make debug easier */
"Vladimir N. Oleynik"ac973172005-09-22 14:38:17 +0000225#ifdef MSHDEBUG
Denis Vlasenkoe27f1562007-01-01 06:00:38 +0000226static const char *const T_CMD_NAMES[] = {
Eric Andersen12de6cf2004-08-04 19:19:10 +0000227 "PLACEHOLDER",
228 "TCOM",
229 "TPAREN",
230 "TPIPE",
231 "TLIST",
232 "TOR",
233 "TAND",
234 "TFOR",
235 "TDO",
236 "TCASE",
237 "TIF",
238 "TWHILE",
239 "TUNTIL",
240 "TELIF",
241 "TPAT",
242 "TBRACE",
243 "TASYNC",
244 "TDOT",
245};
"Vladimir N. Oleynik"ac973172005-09-22 14:38:17 +0000246#endif
Eric Andersenff9eee42001-06-29 04:57:14 +0000247
248/*
249 * actions determining the environment of a process
250 */
Denis Vlasenko5f9468e2007-04-14 13:22:09 +0000251#define FEXEC 1 /* execute without forking */
Eric Andersenff9eee42001-06-29 04:57:14 +0000252
Denis Vlasenko5f9468e2007-04-14 13:22:09 +0000253#define AREASIZE (90000)
Eric Andersen12de6cf2004-08-04 19:19:10 +0000254
Eric Andersenff9eee42001-06-29 04:57:14 +0000255/*
256 * flags to control evaluation of words
257 */
Denis Vlasenko5f9468e2007-04-14 13:22:09 +0000258#define DOSUB 1 /* interpret $, `, and quotes */
259#define DOBLANK 2 /* perform blank interpretation */
260#define DOGLOB 4 /* interpret [?* */
261#define DOKEY 8 /* move words with `=' to 2nd arg. list */
262#define DOTRIM 16 /* trim resulting string */
Eric Andersenff9eee42001-06-29 04:57:14 +0000263
Denis Vlasenko5f9468e2007-04-14 13:22:09 +0000264#define DOALL (DOSUB|DOBLANK|DOGLOB|DOKEY|DOTRIM)
Eric Andersenff9eee42001-06-29 04:57:14 +0000265
Eric Andersenff9eee42001-06-29 04:57:14 +0000266
Eric Andersen8401eea2004-08-04 19:16:54 +0000267struct brkcon {
268 jmp_buf brkpt;
269 struct brkcon *nextlev;
270};
Eric Andersenff9eee42001-06-29 04:57:14 +0000271
Eric Andersen12de6cf2004-08-04 19:19:10 +0000272
Eric Andersen8401eea2004-08-04 19:16:54 +0000273static int trapset; /* trap pending */
Eric Andersenff9eee42001-06-29 04:57:14 +0000274
Eric Andersen8401eea2004-08-04 19:16:54 +0000275static int yynerrs; /* yacc */
Eric Andersenff9eee42001-06-29 04:57:14 +0000276
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000277/* moved to G: static char line[LINELIM]; */
Eric Andersenff9eee42001-06-29 04:57:14 +0000278
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000279#if ENABLE_FEATURE_EDITING
280static char *current_prompt;
281static line_input_t *line_input_state;
282#endif
283
Eric Andersen12de6cf2004-08-04 19:19:10 +0000284
Eric Andersenff9eee42001-06-29 04:57:14 +0000285/*
286 * other functions
287 */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000288static const char *rexecve(char *c, char **v, char **envp);
Eric Andersen8401eea2004-08-04 19:16:54 +0000289static char *evalstr(char *cp, int f);
290static char *putn(int n);
Eric Andersen8401eea2004-08-04 19:16:54 +0000291static char *unquote(char *as);
Eric Andersen8401eea2004-08-04 19:16:54 +0000292static int rlookup(char *n);
293static struct wdblock *glob(char *cp, struct wdblock *wb);
294static int my_getc(int ec);
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +0000295static int subgetc(char ec, int quoted);
Eric Andersenfd7a4c82004-09-02 23:13:10 +0000296static char **makenv(int all, struct wdblock *wb);
Eric Andersen8401eea2004-08-04 19:16:54 +0000297static char **eval(char **ap, int f);
298static int setstatus(int s);
299static int waitfor(int lastpid, int canintr);
Eric Andersenff9eee42001-06-29 04:57:14 +0000300
Eric Andersen8401eea2004-08-04 19:16:54 +0000301static void onintr(int s); /* SIGINT handler */
Eric Andersenff9eee42001-06-29 04:57:14 +0000302
Eric Andersen8401eea2004-08-04 19:16:54 +0000303static int newenv(int f);
304static void quitenv(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000305static void next(int f);
306static void setdash(void);
307static void onecommand(void);
308static void runtrap(int i);
Eric Andersenff9eee42001-06-29 04:57:14 +0000309
Eric Andersen12de6cf2004-08-04 19:19:10 +0000310
Eric Andersenff9eee42001-06-29 04:57:14 +0000311/* -------- area stuff -------- */
312
Denis Vlasenko5f9468e2007-04-14 13:22:09 +0000313#define REGSIZE sizeof(struct region)
314#define GROWBY (256)
315/* #define SHRINKBY (64) */
316#undef SHRINKBY
317#define FREE (32767)
318#define BUSY (0)
319#define ALIGN (sizeof(int)-1)
Eric Andersenff9eee42001-06-29 04:57:14 +0000320
321
322struct region {
Eric Andersen8401eea2004-08-04 19:16:54 +0000323 struct region *next;
324 int area;
Eric Andersenff9eee42001-06-29 04:57:14 +0000325};
326
327
Eric Andersenff9eee42001-06-29 04:57:14 +0000328/* -------- grammar stuff -------- */
329typedef union {
Eric Andersen8401eea2004-08-04 19:16:54 +0000330 char *cp;
331 char **wp;
332 int i;
333 struct op *o;
Eric Andersenff9eee42001-06-29 04:57:14 +0000334} YYSTYPE;
Eric Andersen8401eea2004-08-04 19:16:54 +0000335
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000336#define WORD 256
337#define LOGAND 257
338#define LOGOR 258
339#define BREAK 259
340#define IF 260
341#define THEN 261
342#define ELSE 262
343#define ELIF 263
344#define FI 264
345#define CASE 265
346#define ESAC 266
347#define FOR 267
348#define WHILE 268
349#define UNTIL 269
350#define DO 270
351#define DONE 271
352#define IN 272
Eric Andersen12de6cf2004-08-04 19:19:10 +0000353/* Added for "." file expansion */
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000354#define DOT 273
Eric Andersen12de6cf2004-08-04 19:19:10 +0000355
Eric Andersenff9eee42001-06-29 04:57:14 +0000356#define YYERRCODE 300
357
358/* flags to yylex */
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000359#define CONTIN 01 /* skip new lines to complete command */
Eric Andersenff9eee42001-06-29 04:57:14 +0000360
Eric Andersen8401eea2004-08-04 19:16:54 +0000361static struct op *pipeline(int cf);
Eric Andersenff9eee42001-06-29 04:57:14 +0000362static struct op *andor(void);
363static struct op *c_list(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000364static int synio(int cf);
365static void musthave(int c, int cf);
Eric Andersenff9eee42001-06-29 04:57:14 +0000366static struct op *simple(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000367static struct op *nested(int type, int mark);
368static struct op *command(int cf);
369static struct op *dogroup(int onlydone);
Eric Andersenff9eee42001-06-29 04:57:14 +0000370static struct op *thenpart(void);
371static struct op *elsepart(void);
372static struct op *caselist(void);
373static struct op *casepart(void);
374static char **pattern(void);
375static char **wordlist(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000376static struct op *list(struct op *t1, struct op *t2);
377static struct op *block(int type, struct op *t1, struct op *t2, char **wp);
Eric Andersenff9eee42001-06-29 04:57:14 +0000378static struct op *newtp(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000379static struct op *namelist(struct op *t);
Eric Andersenff9eee42001-06-29 04:57:14 +0000380static char **copyw(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000381static void word(char *cp);
Eric Andersenff9eee42001-06-29 04:57:14 +0000382static struct ioword **copyio(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000383static struct ioword *io(int u, int f, char *cp);
Eric Andersen8401eea2004-08-04 19:16:54 +0000384static int yylex(int cf);
385static int collect(int c, int c1);
386static int dual(int c);
387static void diag(int ec);
388static char *tree(unsigned size);
Eric Andersenff9eee42001-06-29 04:57:14 +0000389
390/* -------- var.h -------- */
391
Eric Andersen8401eea2004-08-04 19:16:54 +0000392struct var {
393 char *value;
394 char *name;
395 struct var *next;
396 char status;
Eric Andersenff9eee42001-06-29 04:57:14 +0000397};
Eric Andersenff9eee42001-06-29 04:57:14 +0000398
Eric Andersen8401eea2004-08-04 19:16:54 +0000399#define COPYV 1 /* flag to setval, suggesting copy */
400#define RONLY 01 /* variable is read-only */
401#define EXPORT 02 /* variable is to be exported */
402#define GETCELL 04 /* name & value space was got with getcell */
Eric Andersenff9eee42001-06-29 04:57:14 +0000403
Eric Andersen8401eea2004-08-04 19:16:54 +0000404static int yyparse(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000405
406static int execute(struct op *t, int *pin, int *pout, int act);
Eric Andersenff9eee42001-06-29 04:57:14 +0000407
Eric Andersen12de6cf2004-08-04 19:19:10 +0000408
Eric Andersenff9eee42001-06-29 04:57:14 +0000409/* -------- io.h -------- */
410/* io buffer */
411struct iobuf {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000412 unsigned id; /* buffer id */
413 char buf[512]; /* buffer */
414 char *bufp; /* pointer into buffer */
415 char *ebufp; /* pointer to end of buffer */
Eric Andersenff9eee42001-06-29 04:57:14 +0000416};
417
418/* possible arguments to an IO function */
419struct ioarg {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000420 const char *aword;
Eric Andersen8401eea2004-08-04 19:16:54 +0000421 char **awordlist;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000422 int afile; /* file descriptor */
423 unsigned afid; /* buffer id */
424 long afpos; /* file position */
425 struct iobuf *afbuf; /* buffer for this file */
Eric Andersenff9eee42001-06-29 04:57:14 +0000426};
Eric Andersen8401eea2004-08-04 19:16:54 +0000427
Eric Andersenff9eee42001-06-29 04:57:14 +0000428/* an input generator's state */
Eric Andersen8401eea2004-08-04 19:16:54 +0000429struct io {
430 int (*iofn) (struct ioarg *, struct io *);
431 struct ioarg *argp;
432 int peekc;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000433 char prev; /* previous character read by readc() */
434 char nlcount; /* for `'s */
435 char xchar; /* for `'s */
436 char task; /* reason for pushed IO */
Eric Andersenff9eee42001-06-29 04:57:14 +0000437};
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000438/* ->task: */
439#define XOTHER 0 /* none of the below */
440#define XDOLL 1 /* expanding ${} */
441#define XGRAVE 2 /* expanding `'s */
442#define XIO 3 /* file IO */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000443
444
445/*
Eric Andersenff9eee42001-06-29 04:57:14 +0000446 * input generators for IO structure
447 */
Eric Andersen8401eea2004-08-04 19:16:54 +0000448static int nlchar(struct ioarg *ap);
449static int strchar(struct ioarg *ap);
450static int qstrchar(struct ioarg *ap);
451static int filechar(struct ioarg *ap);
452static int herechar(struct ioarg *ap);
453static int linechar(struct ioarg *ap);
454static int gravechar(struct ioarg *ap, struct io *iop);
455static int qgravechar(struct ioarg *ap, struct io *iop);
456static int dolchar(struct ioarg *ap);
457static int wdchar(struct ioarg *ap);
458static void scraphere(void);
459static void freehere(int area);
460static void gethere(void);
461static void markhere(char *s, struct ioword *iop);
462static int herein(char *hname, int xdoll);
463static int run(struct ioarg *argp, int (*f) (struct ioarg *));
Eric Andersenff9eee42001-06-29 04:57:14 +0000464
Eric Andersen12de6cf2004-08-04 19:19:10 +0000465
Eric Andersen8401eea2004-08-04 19:16:54 +0000466static int eofc(void);
467static int readc(void);
468static void unget(int c);
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +0000469static void ioecho(char c);
Eric Andersenff9eee42001-06-29 04:57:14 +0000470
Eric Andersen12de6cf2004-08-04 19:19:10 +0000471
Eric Andersenff9eee42001-06-29 04:57:14 +0000472/*
473 * IO control
474 */
Eric Andersen8401eea2004-08-04 19:16:54 +0000475static void pushio(struct ioarg *argp, int (*f) (struct ioarg *));
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000476#define PUSHIO(what,arg,gen) ((temparg.what = (arg)), pushio(&temparg,(gen)))
Eric Andersen8401eea2004-08-04 19:16:54 +0000477static int remap(int fd);
478static int openpipe(int *pv);
479static void closepipe(int *pv);
480static struct io *setbase(struct io *ip);
Eric Andersenff9eee42001-06-29 04:57:14 +0000481
Eric Andersenff9eee42001-06-29 04:57:14 +0000482/* -------- word.h -------- */
483
Eric Andersen8401eea2004-08-04 19:16:54 +0000484#define NSTART 16 /* default number of words to allow for initially */
Eric Andersenff9eee42001-06-29 04:57:14 +0000485
Eric Andersen8401eea2004-08-04 19:16:54 +0000486struct wdblock {
487 short w_bsize;
488 short w_nword;
Eric Andersenff9eee42001-06-29 04:57:14 +0000489 /* bounds are arbitrary */
Eric Andersen8401eea2004-08-04 19:16:54 +0000490 char *w_words[1];
Eric Andersenff9eee42001-06-29 04:57:14 +0000491};
492
Eric Andersen8401eea2004-08-04 19:16:54 +0000493static struct wdblock *addword(char *wd, struct wdblock *wb);
494static struct wdblock *newword(int nw);
495static char **getwords(struct wdblock *wb);
Eric Andersenff9eee42001-06-29 04:57:14 +0000496
Eric Andersenff9eee42001-06-29 04:57:14 +0000497/* -------- misc stuff -------- */
498
Eric Andersen12de6cf2004-08-04 19:19:10 +0000499static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp);
Eric Andersen8401eea2004-08-04 19:16:54 +0000500static int iosetup(struct ioword *iop, int pipein, int pipeout);
Eric Andersen8401eea2004-08-04 19:16:54 +0000501static void brkset(struct brkcon *bc);
502static int dolabel(struct op *t);
503static int dohelp(struct op *t);
504static int dochdir(struct op *t);
505static int doshift(struct op *t);
506static int dologin(struct op *t);
507static int doumask(struct op *t);
508static int doexec(struct op *t);
509static int dodot(struct op *t);
510static int dowait(struct op *t);
511static int doread(struct op *t);
512static int doeval(struct op *t);
513static int dotrap(struct op *t);
514static int getsig(char *s);
515static void setsig(int n, sighandler_t f);
516static int getn(char *as);
517static int dobreak(struct op *t);
518static int docontinue(struct op *t);
519static int brkcontin(char *cp, int val);
520static int doexit(struct op *t);
521static int doexport(struct op *t);
522static int doreadonly(struct op *t);
523static void rdexp(char **wp, void (*f) (struct var *), int key);
524static void badid(char *s);
525static int doset(struct op *t);
526static void varput(char *s, int out);
527static int dotimes(struct op *t);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000528static int expand(const char *cp, struct wdblock **wbp, int f);
Eric Andersen8401eea2004-08-04 19:16:54 +0000529static char *blank(int f);
530static int dollar(int quoted);
531static int grave(int quoted);
532static void globname(char *we, char *pp);
533static char *generate(char *start1, char *end1, char *middle, char *end);
534static int anyspcl(struct wdblock *wb);
535static int xstrcmp(char *p1, char *p2);
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000536static void glob0(char *a0, unsigned a1, int a2,
Eric Andersen8401eea2004-08-04 19:16:54 +0000537 int (*a3) (char *, char *));
Eric Andersen8401eea2004-08-04 19:16:54 +0000538static void readhere(char **name, char *s, int ec);
Eric Andersen8401eea2004-08-04 19:16:54 +0000539static int xxchar(struct ioarg *ap);
Eric Andersenff9eee42001-06-29 04:57:14 +0000540
Eric Andersen8401eea2004-08-04 19:16:54 +0000541struct here {
542 char *h_tag;
543 int h_dosub;
544 struct ioword *h_iop;
545 struct here *h_next;
Eric Andersenff9eee42001-06-29 04:57:14 +0000546};
547
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000548static const char *const signame[] = {
Eric Andersenff9eee42001-06-29 04:57:14 +0000549 "Signal 0",
550 "Hangup",
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000551 NULL, /* interrupt */
Eric Andersenff9eee42001-06-29 04:57:14 +0000552 "Quit",
553 "Illegal instruction",
554 "Trace/BPT trap",
555 "Abort",
556 "Bus error",
557 "Floating Point Exception",
558 "Killed",
559 "SIGUSR1",
560 "SIGSEGV",
561 "SIGUSR2",
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000562 NULL, /* broken pipe */
Eric Andersenff9eee42001-06-29 04:57:14 +0000563 "Alarm clock",
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000564 "Terminated"
Eric Andersenff9eee42001-06-29 04:57:14 +0000565};
Eric Andersen8401eea2004-08-04 19:16:54 +0000566
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000567
Eric Andersen1c039232001-07-07 00:05:55 +0000568struct builtincmd {
569 const char *name;
Denis Vlasenko95cb3262007-04-09 03:06:34 +0000570 int (*builtinfunc)(struct op *t);
Eric Andersenff9eee42001-06-29 04:57:14 +0000571};
Eric Andersen8401eea2004-08-04 19:16:54 +0000572static const struct builtincmd builtincmds[] = {
Denis Vlasenko95cb3262007-04-09 03:06:34 +0000573 { "." , dodot },
574 { ":" , dolabel },
575 { "break" , dobreak },
576 { "cd" , dochdir },
577 { "continue", docontinue },
578 { "eval" , doeval },
579 { "exec" , doexec },
580 { "exit" , doexit },
581 { "export" , doexport },
582 { "help" , dohelp },
583 { "login" , dologin },
584 { "newgrp" , dologin },
585 { "read" , doread },
586 { "readonly", doreadonly },
587 { "set" , doset },
588 { "shift" , doshift },
589 { "times" , dotimes },
590 { "trap" , dotrap },
591 { "umask" , doumask },
592 { "wait" , dowait },
593 { NULL , NULL },
Eric Andersenff9eee42001-06-29 04:57:14 +0000594};
595
"Vladimir N. Oleynik"ac973172005-09-22 14:38:17 +0000596static struct op *scantree(struct op *);
Eric Andersen12de6cf2004-08-04 19:19:10 +0000597static struct op *dowholefile(int, int);
598
Eric Andersen12de6cf2004-08-04 19:19:10 +0000599
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000600/* Globals */
Eric Andersen8401eea2004-08-04 19:16:54 +0000601static char **dolv;
602static int dolc;
603static int exstat;
604static char gflg;
"Vladimir N. Oleynik"485d7cb2005-10-17 09:48:57 +0000605static int interactive; /* Is this an interactive shell */
Eric Andersen8401eea2004-08-04 19:16:54 +0000606static int execflg;
607static int multiline; /* \n changed to ; */
608static struct op *outtree; /* result from parser */
609static xint *failpt;
610static xint *errpt;
611static struct brkcon *brklist;
612static int isbreak;
613static struct wdblock *wdlist;
614static struct wdblock *iolist;
Eric Andersen12de6cf2004-08-04 19:19:10 +0000615
616#ifdef MSHDEBUG
617static struct var *mshdbg_var;
618#endif
Eric Andersen8401eea2004-08-04 19:16:54 +0000619static struct var *vlist; /* dictionary */
620static struct var *homedir; /* home directory */
621static struct var *prompt; /* main prompt */
622static struct var *cprompt; /* continuation prompt */
623static struct var *path; /* search path for commands */
624static struct var *shell; /* shell to interpret command files */
625static struct var *ifs; /* field separators */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000626
Denis Vlasenko95cb3262007-04-09 03:06:34 +0000627static int areanum; /* current allocation area */
628static int intr; /* interrupt pending */
Eric Andersen8401eea2004-08-04 19:16:54 +0000629static int inparse;
Denis Vlasenko95cb3262007-04-09 03:06:34 +0000630static char *null = (char*)""; /* null value for variable */
631static int heedint = 1; /* heed interrupt signals */
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +0000632static void (*qflag)(int) = SIG_IGN;
Eric Andersen8401eea2004-08-04 19:16:54 +0000633static int startl;
634static int peeksym;
635static int nlseen;
636static int iounit = IODEFAULT;
637static YYSTYPE yylval;
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000638static char *elinep; /* done in main(): = line + sizeof(line) - 5 */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000639
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000640static struct here *inhere; /* list of hear docs while parsing */
641static struct here *acthere; /* list of active here documents */
642static struct region *areabot; /* bottom of area */
643static struct region *areatop; /* top of area */
644static struct region *areanxt; /* starting point of scan */
Eric Andersen8401eea2004-08-04 19:16:54 +0000645static void *brktop;
646static void *brkaddr;
Eric Andersenff9eee42001-06-29 04:57:14 +0000647
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000648#define AFID_NOBUF (~0)
649#define AFID_ID 0
650
651
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000652/*
653 * parsing & execution environment
654 */
655struct env {
656 char *linep;
657 struct io *iobase;
658 struct io *iop;
659 xint *errpt; /* void * */
660 int iofd;
661 struct env *oenv;
662};
663
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000664
665struct globals {
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000666 struct env global_env;
667 struct ioarg temparg; // = { .afid = AFID_NOBUF }; /* temporary for PUSHIO */
668 unsigned bufid; // = AFID_ID; /* buffer id counter */
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000669 char ourtrap[_NSIG + 1];
670 char *trap[_NSIG + 1];
671 struct iobuf sharedbuf; /* in main(): set to { AFID_NOBUF } */
672 struct iobuf mainbuf; /* in main(): set to { AFID_NOBUF } */
673 struct ioarg ioargstack[NPUSH];
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000674 /*
675 * flags:
676 * -e: quit on error
677 * -k: look for name=value everywhere on command line
678 * -n: no execution
679 * -t: exit after reading and executing one command
680 * -v: echo as read
681 * -x: trace
682 * -u: unset variables net diagnostic
683 */
684 char flags['z' - 'a' + 1];
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000685 char filechar_cmdbuf[BUFSIZ];
686 char line[LINELIM];
687 char child_cmd[LINELIM];
Denis Vlasenkoab801872007-12-02 08:35:37 +0000688
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000689 struct io iostack[NPUSH];
690
Denis Vlasenkoab801872007-12-02 08:35:37 +0000691 char grave__var_name[LINELIM];
692 char grave__alt_value[LINELIM];
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000693};
694
695#define G (*ptr_to_globals)
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000696#define global_env (G.global_env )
697#define temparg (G.temparg )
698#define bufid (G.bufid )
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000699#define ourtrap (G.ourtrap )
700#define trap (G.trap )
701#define sharedbuf (G.sharedbuf )
702#define mainbuf (G.mainbuf )
703#define ioargstack (G.ioargstack )
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000704/* this looks weird, but is OK ... we index FLAG with 'a'...'z' */
705#define FLAG (G.flags - 'a' )
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000706#define filechar_cmdbuf (G.filechar_cmdbuf)
707#define line (G.line )
708#define child_cmd (G.child_cmd )
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000709#define iostack (G.iostack )
Denis Vlasenkoab801872007-12-02 08:35:37 +0000710#define INIT_G() do { \
711 PTR_TO_GLOBALS = xzalloc(sizeof(G)); \
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000712 global_env.linep = line; \
713 global_env.iobase = iostack; \
714 global_env.iop = iostack - 1; \
715 global_env.iofd = FDBASE; \
716 temparg.afid = AFID_NOBUF; \
717 bufid = AFID_ID; \
Denis Vlasenkoab801872007-12-02 08:35:37 +0000718} while (0)
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000719
720
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000721/* in substitution */
722#define INSUB() (global_env.iop->task == XGRAVE || global_env.iop->task == XDOLL)
723
724#define RUN(what, arg, gen) ((temparg.what = (arg)), run(&temparg, (gen)))
725
Eric Andersen12de6cf2004-08-04 19:19:10 +0000726#ifdef MSHDEBUG
727void print_t(struct op *t)
728{
Mike Frysinger02d8fa42006-05-05 20:32:31 +0000729 DBGPRINTF(("T: t=%p, type %s, words=%p, IOword=%p\n", t,
730 T_CMD_NAMES[t->type], t->words, t->ioact));
Eric Andersen12de6cf2004-08-04 19:19:10 +0000731
732 if (t->words) {
733 DBGPRINTF(("T: W1: %s", t->words[0]));
734 }
Eric Andersen12de6cf2004-08-04 19:19:10 +0000735}
736
737void print_tree(struct op *head)
738{
739 if (head == NULL) {
740 DBGPRINTF(("PRINT_TREE: no tree\n"));
741 return;
742 }
743
Mike Frysinger02d8fa42006-05-05 20:32:31 +0000744 DBGPRINTF(("NODE: %p, left %p, right %p\n", head, head->left,
Eric Andersen12de6cf2004-08-04 19:19:10 +0000745 head->right));
746
747 if (head->left)
748 print_tree(head->left);
749
750 if (head->right)
751 print_tree(head->right);
Eric Andersen12de6cf2004-08-04 19:19:10 +0000752}
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000753#endif /* MSHDEBUG */
754
755
756/*
757 * IO functions
758 */
759static void prs(const char *s)
760{
761 if (*s)
762 write(2, s, strlen(s));
763}
764
765static void prn(unsigned u)
766{
767 prs(itoa(u));
768}
769
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000770static void echo(char **wp)
771{
772 int i;
773
774 prs("+");
775 for (i = 0; wp[i]; i++) {
776 if (i)
777 prs(" ");
778 prs(wp[i]);
779 }
780 prs("\n");
781}
782
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000783static void closef(int i)
784{
785 if (i > 2)
786 close(i);
787}
788
789static void closeall(void)
790{
791 int u;
792
793 for (u = NUFILE; u < NOFILE;)
794 close(u++);
795}
Eric Andersen12de6cf2004-08-04 19:19:10 +0000796
Eric Andersenff9eee42001-06-29 04:57:14 +0000797
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000798/* fail but return to process next command */
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000799static void fail(void) ATTRIBUTE_NORETURN;
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000800static void fail(void)
801{
802 longjmp(failpt, 1);
803 /* NOTREACHED */
804}
Eric Andersenff9eee42001-06-29 04:57:14 +0000805
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000806/* abort shell (or fail in subshell) */
807static void leave(void) ATTRIBUTE_NORETURN;
808static void leave(void)
809{
810 DBGPRINTF(("LEAVE: leave called!\n"));
811
812 if (execflg)
813 fail();
814 scraphere();
815 freehere(1);
816 runtrap(0);
817 _exit(exstat);
818 /* NOTREACHED */
819}
820
821static void warn(const char *s)
822{
823 if (*s) {
824 prs(s);
825 exstat = -1;
826 }
827 prs("\n");
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +0000828 if (FLAG['e'])
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000829 leave();
830}
831
832static void err(const char *s)
833{
834 warn(s);
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +0000835 if (FLAG['n'])
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000836 return;
837 if (!interactive)
838 leave();
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000839 if (global_env.errpt)
840 longjmp(global_env.errpt, 1);
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000841 closeall();
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000842 global_env.iop = global_env.iobase = iostack;
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000843}
844
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000845
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000846/* -------- area.c -------- */
847
Eric Andersenff9eee42001-06-29 04:57:14 +0000848/*
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000849 * All memory between (char *)areabot and (char *)(areatop+1) is
850 * exclusively administered by the area management routines.
851 * It is assumed that sbrk() and brk() manipulate the high end.
Eric Andersenff9eee42001-06-29 04:57:14 +0000852 */
853
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000854#define sbrk(X) ({ \
855 void * __q = (void *)-1; \
856 if (brkaddr + (int)(X) < brktop) { \
857 __q = brkaddr; \
858 brkaddr += (int)(X); \
859 } \
860 __q; \
861})
Eric Andersenff9eee42001-06-29 04:57:14 +0000862
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000863static void initarea(void)
Eric Andersenff9eee42001-06-29 04:57:14 +0000864{
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000865 brkaddr = xmalloc(AREASIZE);
866 brktop = brkaddr + AREASIZE;
Eric Andersenff9eee42001-06-29 04:57:14 +0000867
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000868 while ((long) sbrk(0) & ALIGN)
869 sbrk(1);
870 areabot = (struct region *) sbrk(REGSIZE);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +0000871
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000872 areabot->next = areabot;
873 areabot->area = BUSY;
874 areatop = areabot;
875 areanxt = areabot;
Eric Andersenff9eee42001-06-29 04:57:14 +0000876}
877
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000878static char *getcell(unsigned nbytes)
879{
880 int nregio;
881 struct region *p, *q;
882 int i;
883
884 if (nbytes == 0) {
885 puts("getcell(0)");
886 abort();
887 }
888 /* silly and defeats the algorithm */
889 /*
890 * round upwards and add administration area
891 */
892 nregio = (nbytes + (REGSIZE - 1)) / REGSIZE + 1;
893 p = areanxt;
894 for (;;) {
895 if (p->area > areanum) {
896 /*
897 * merge free cells
898 */
899 while ((q = p->next)->area > areanum && q != areanxt)
900 p->next = q->next;
901 /*
902 * exit loop if cell big enough
903 */
904 if (q >= p + nregio)
905 goto found;
906 }
907 p = p->next;
908 if (p == areanxt)
909 break;
910 }
911 i = nregio >= GROWBY ? nregio : GROWBY;
912 p = (struct region *) sbrk(i * REGSIZE);
913 if (p == (struct region *) -1)
914 return NULL;
915 p--;
916 if (p != areatop) {
917 puts("not contig");
918 abort(); /* allocated areas are contiguous */
919 }
920 q = p + i;
921 p->next = q;
922 p->area = FREE;
923 q->next = areabot;
924 q->area = BUSY;
925 areatop = q;
926 found:
927 /*
928 * we found a FREE area big enough, pointed to by 'p', and up to 'q'
929 */
930 areanxt = p + nregio;
931 if (areanxt < q) {
932 /*
933 * split into requested area and rest
934 */
935 if (areanxt + 1 > q) {
936 puts("OOM");
937 abort(); /* insufficient space left for admin */
938 }
939 areanxt->next = q;
940 areanxt->area = FREE;
941 p->next = areanxt;
942 }
943 p->area = areanum;
944 return (char *) (p + 1);
945}
946
947static void freecell(char *cp)
948{
949 struct region *p;
950
951 p = (struct region *) cp;
952 if (p != NULL) {
953 p--;
954 if (p < areanxt)
955 areanxt = p;
956 p->area = FREE;
957 }
958}
959#define DELETE(obj) freecell((char *)obj)
960
961static void freearea(int a)
962{
963 struct region *p, *top;
964
965 top = areatop;
966 for (p = areabot; p != top; p = p->next)
967 if (p->area >= a)
968 p->area = FREE;
969}
970
971static void setarea(char *cp, int a)
972{
973 struct region *p;
974
975 p = (struct region *) cp;
976 if (p != NULL)
977 (p - 1)->area = a;
978}
979
980static int getarea(char *cp)
981{
982 return ((struct region *) cp - 1)->area;
983}
984
985static void garbage(void)
986{
987 struct region *p, *q, *top;
988
989 top = areatop;
990 for (p = areabot; p != top; p = p->next) {
991 if (p->area > areanum) {
992 while ((q = p->next)->area > areanum)
993 p->next = q->next;
994 areanxt = p;
995 }
996 }
997#ifdef SHRINKBY
998 if (areatop >= q + SHRINKBY && q->area > areanum) {
999 brk((char *) (q + 1));
1000 q->next = areabot;
1001 q->area = BUSY;
1002 areatop = q;
1003 }
1004#endif
1005}
1006
1007static char *space(int n)
1008{
1009 char *cp;
1010
1011 cp = getcell(n);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001012 if (cp == NULL)
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001013 err("out of string space");
1014 return cp;
1015}
1016
1017static char *strsave(const char *s, int a)
1018{
1019 char *cp;
1020
1021 cp = space(strlen(s) + 1);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001022 if (cp == NULL) {
1023// FIXME: I highly doubt this is good.
1024 return (char*)"";
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001025 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001026 setarea(cp, a);
1027 strcpy(cp, s);
1028 return cp;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001029}
1030
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001031
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001032/* -------- var.c -------- */
1033
1034static int eqname(const char *n1, const char *n2)
1035{
1036 for (; *n1 != '=' && *n1 != '\0'; n1++)
1037 if (*n2++ != *n1)
1038 return 0;
1039 return *n2 == '\0' || *n2 == '=';
1040}
1041
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001042static const char *findeq(const char *cp)
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001043{
1044 while (*cp != '\0' && *cp != '=')
1045 cp++;
1046 return cp;
1047}
1048
1049/*
1050 * Find the given name in the dictionary
1051 * and return its value. If the name was
1052 * not previously there, enter it now and
1053 * return a null value.
1054 */
1055static struct var *lookup(const char *n)
1056{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001057// FIXME: dirty hack
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001058 static struct var dummy;
1059
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001060 struct var *vp;
1061 const char *cp;
1062 char *xp;
1063 int c;
1064
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001065 if (isdigit(*n)) {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001066 dummy.name = (char*)n;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001067 for (c = 0; isdigit(*n) && c < 1000; n++)
1068 c = c * 10 + *n - '0';
1069 dummy.status = RONLY;
1070 dummy.value = (c <= dolc ? dolv[c] : null);
1071 return &dummy;
1072 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001073
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001074 for (vp = vlist; vp; vp = vp->next)
1075 if (eqname(vp->name, n))
1076 return vp;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001077
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001078 cp = findeq(n);
1079 vp = (struct var *) space(sizeof(*vp));
1080 if (vp == 0 || (vp->name = space((int) (cp - n) + 2)) == 0) {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001081 dummy.name = dummy.value = (char*)"";
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001082 return &dummy;
1083 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001084
1085 xp = vp->name;
1086 while ((*xp = *n++) != '\0' && *xp != '=')
1087 xp++;
1088 *xp++ = '=';
1089 *xp = '\0';
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001090 setarea((char *) vp, 0);
1091 setarea((char *) vp->name, 0);
1092 vp->value = null;
1093 vp->next = vlist;
1094 vp->status = GETCELL;
1095 vlist = vp;
1096 return vp;
1097}
1098
1099/*
1100 * if name is not NULL, it must be
1101 * a prefix of the space `val',
1102 * and end with `='.
1103 * this is all so that exporting
1104 * values is reasonably painless.
1105 */
1106static void nameval(struct var *vp, const char *val, const char *name)
1107{
1108 const char *cp;
1109 char *xp;
1110 int fl;
1111
1112 if (vp->status & RONLY) {
1113 xp = vp->name;
1114 while (*xp && *xp != '=')
Denis Vlasenko4daad902007-09-27 10:20:47 +00001115 fputc(*xp++, stderr);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001116 err(" is read-only");
1117 return;
1118 }
1119 fl = 0;
1120 if (name == NULL) {
1121 xp = space(strlen(vp->name) + strlen(val) + 2);
1122 if (xp == NULL)
1123 return;
1124 /* make string: name=value */
1125 setarea(xp, 0);
1126 name = xp;
1127 cp = vp->name;
1128 while ((*xp = *cp++) != '\0' && *xp != '=')
1129 xp++;
1130 *xp++ = '=';
1131 strcpy(xp, val);
1132 val = xp;
1133 fl = GETCELL;
1134 }
1135 if (vp->status & GETCELL)
1136 freecell(vp->name); /* form new string `name=value' */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001137 vp->name = (char*)name;
1138 vp->value = (char*)val;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001139 vp->status |= fl;
1140}
1141
1142/*
1143 * give variable at `vp' the value `val'.
1144 */
1145static void setval(struct var *vp, const char *val)
1146{
1147 nameval(vp, val, NULL);
1148}
1149
1150static void export(struct var *vp)
1151{
1152 vp->status |= EXPORT;
1153}
1154
1155static void ronly(struct var *vp)
1156{
1157 if (isalpha(vp->name[0]) || vp->name[0] == '_') /* not an internal symbol */
1158 vp->status |= RONLY;
1159}
1160
1161static int isassign(const char *s)
1162{
1163 unsigned char c;
1164 DBGPRINTF7(("ISASSIGN: enter, s=%s\n", s));
1165
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001166 c = *s;
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001167 /* no isalpha() - we shouldn't use locale */
1168 /* c | 0x20 - lowercase (Latin) letters */
1169 if (c != '_' && (unsigned)((c|0x20) - 'a') > 25)
1170 /* not letter */
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001171 return 0;
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001172
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001173 while (1) {
1174 c = *++s;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001175 if (c == '=')
1176 return 1;
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001177 if (c == '\0')
1178 return 0;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001179 if (c != '_'
1180 && (unsigned)(c - '0') > 9 /* not number */
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001181 && (unsigned)((c|0x20) - 'a') > 25 /* not letter */
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001182 ) {
1183 return 0;
1184 }
1185 }
1186}
1187
1188static int assign(const char *s, int cf)
1189{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001190 const char *cp;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001191 struct var *vp;
1192
1193 DBGPRINTF7(("ASSIGN: enter, s=%s, cf=%d\n", s, cf));
1194
1195 if (!isalpha(*s) && *s != '_')
1196 return 0;
1197 for (cp = s; *cp != '='; cp++)
1198 if (*cp == '\0' || (!isalnum(*cp) && *cp != '_'))
1199 return 0;
1200 vp = lookup(s);
1201 nameval(vp, ++cp, cf == COPYV ? NULL : s);
1202 if (cf != COPYV)
1203 vp->status &= ~GETCELL;
1204 return 1;
1205}
1206
1207static int checkname(char *cp)
1208{
1209 DBGPRINTF7(("CHECKNAME: enter, cp=%s\n", cp));
1210
1211 if (!isalpha(*cp++) && *(cp - 1) != '_')
1212 return 0;
1213 while (*cp)
1214 if (!isalnum(*cp++) && *(cp - 1) != '_')
1215 return 0;
1216 return 1;
1217}
1218
1219static void putvlist(int f, int out)
1220{
1221 struct var *vp;
1222
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001223 for (vp = vlist; vp; vp = vp->next) {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001224 if (vp->status & f && (isalpha(*vp->name) || *vp->name == '_')) {
1225 if (vp->status & EXPORT)
1226 write(out, "export ", 7);
1227 if (vp->status & RONLY)
1228 write(out, "readonly ", 9);
1229 write(out, vp->name, (int) (findeq(vp->name) - vp->name));
1230 write(out, "\n", 1);
1231 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001232 }
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001233}
1234
1235
1236/*
1237 * trap handling
1238 */
1239static void sig(int i)
1240{
1241 trapset = i;
1242 signal(i, sig);
1243}
1244
1245static void runtrap(int i)
1246{
1247 char *trapstr;
1248
1249 trapstr = trap[i];
1250 if (trapstr == NULL)
1251 return;
1252
1253 if (i == 0)
1254 trap[i] = NULL;
1255
1256 RUN(aword, trapstr, nlchar);
1257}
1258
1259
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001260static void setdash(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001261{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001262 char *cp;
1263 int c;
Eric Andersen8401eea2004-08-04 19:16:54 +00001264 char m['z' - 'a' + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00001265
1266 cp = m;
Eric Andersen8401eea2004-08-04 19:16:54 +00001267 for (c = 'a'; c <= 'z'; c++)
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00001268 if (FLAG[c])
Eric Andersenff9eee42001-06-29 04:57:14 +00001269 *cp++ = c;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001270 *cp = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00001271 setval(lookup("-"), m);
1272}
1273
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001274static int newfile(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00001275{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001276 int f;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001277
1278 DBGPRINTF7(("NEWFILE: opening %s\n", s));
Eric Andersenff9eee42001-06-29 04:57:14 +00001279
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001280 f = 0;
Denis Vlasenko9f739442006-12-16 23:49:13 +00001281 if (NOT_LONE_DASH(s)) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001282 DBGPRINTF(("NEWFILE: s is %s\n", s));
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00001283 f = open(s, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00001284 if (f < 0) {
1285 prs(s);
1286 err(": cannot open");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001287 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001288 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001289 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001290
Eric Andersenff9eee42001-06-29 04:57:14 +00001291 next(remap(f));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001292 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001293}
1294
Eric Andersen12de6cf2004-08-04 19:19:10 +00001295
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001296struct op *scantree(struct op *head)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001297{
1298 struct op *dotnode;
1299
1300 if (head == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001301 return NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001302
1303 if (head->left != NULL) {
1304 dotnode = scantree(head->left);
1305 if (dotnode)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001306 return dotnode;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001307 }
1308
1309 if (head->right != NULL) {
1310 dotnode = scantree(head->right);
1311 if (dotnode)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001312 return dotnode;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001313 }
1314
1315 if (head->words == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001316 return NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001317
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001318 DBGPRINTF5(("SCANTREE: checking node %p\n", head));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001319
Denis Vlasenkocf787cf2007-02-04 17:11:25 +00001320 if ((head->type != TDOT) && LONE_CHAR(head->words[0], '.')) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001321 DBGPRINTF5(("SCANTREE: dot found in node %p\n", head));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001322 return head;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001323 }
1324
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001325 return NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001326}
1327
1328
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001329static void onecommand(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001330{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001331 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00001332 jmp_buf m1;
1333
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001334 DBGPRINTF(("ONECOMMAND: enter, outtree=%p\n", outtree));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001335
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001336 while (global_env.oenv)
Eric Andersenff9eee42001-06-29 04:57:14 +00001337 quitenv();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001338
Eric Andersenff9eee42001-06-29 04:57:14 +00001339 areanum = 1;
1340 freehere(areanum);
1341 freearea(areanum);
1342 garbage();
1343 wdlist = 0;
1344 iolist = 0;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001345 global_env.errpt = 0;
1346 global_env.linep = line;
Eric Andersenff9eee42001-06-29 04:57:14 +00001347 yynerrs = 0;
1348 multiline = 0;
1349 inparse = 1;
1350 intr = 0;
1351 execflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001352
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001353 failpt = m1;
1354 setjmp(failpt); /* Bruce Evans' fix */
1355 failpt = m1;
1356 if (setjmp(failpt) || yyparse() || intr) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001357 DBGPRINTF(("ONECOMMAND: this is not good.\n"));
1358
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001359 while (global_env.oenv)
Eric Andersenff9eee42001-06-29 04:57:14 +00001360 quitenv();
1361 scraphere();
1362 if (!interactive && intr)
1363 leave();
1364 inparse = 0;
1365 intr = 0;
1366 return;
1367 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001368
Eric Andersenff9eee42001-06-29 04:57:14 +00001369 inparse = 0;
1370 brklist = 0;
1371 intr = 0;
1372 execflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001373
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00001374 if (!FLAG['n']) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001375 DBGPRINTF(("ONECOMMAND: calling execute, t=outtree=%p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00001376 outtree));
Eric Andersenff9eee42001-06-29 04:57:14 +00001377 execute(outtree, NOPIPE, NOPIPE, 0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001378 }
1379
Eric Andersenff9eee42001-06-29 04:57:14 +00001380 if (!interactive && intr) {
1381 execflg = 0;
1382 leave();
1383 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001384
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001385 i = trapset;
1386 if (i != 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001387 trapset = 0;
1388 runtrap(i);
1389 }
1390}
1391
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001392static int newenv(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00001393{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001394 struct env *ep;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001395
1396 DBGPRINTF(("NEWENV: f=%d (indicates quitenv and return)\n", f));
Eric Andersenff9eee42001-06-29 04:57:14 +00001397
1398 if (f) {
1399 quitenv();
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001400 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001401 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001402
Eric Andersenff9eee42001-06-29 04:57:14 +00001403 ep = (struct env *) space(sizeof(*ep));
1404 if (ep == NULL) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001405 while (global_env.oenv)
Eric Andersenff9eee42001-06-29 04:57:14 +00001406 quitenv();
1407 fail();
1408 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001409 *ep = global_env;
1410 global_env.oenv = ep;
1411 global_env.errpt = errpt;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001412
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001413 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001414}
1415
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001416static void quitenv(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001417{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001418 struct env *ep;
1419 int fd;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001420
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001421 DBGPRINTF(("QUITENV: global_env.oenv=%p\n", global_env.oenv));
Eric Andersenff9eee42001-06-29 04:57:14 +00001422
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001423 ep = global_env.oenv;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001424 if (ep != NULL) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001425 fd = global_env.iofd;
1426 global_env = *ep;
Eric Andersenff9eee42001-06-29 04:57:14 +00001427 /* should close `'d files */
1428 DELETE(ep);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001429 while (--fd >= global_env.iofd)
Eric Andersenff9eee42001-06-29 04:57:14 +00001430 close(fd);
1431 }
1432}
1433
1434/*
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001435 * Is character c in s?
Eric Andersenff9eee42001-06-29 04:57:14 +00001436 */
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001437static int any(int c, const char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00001438{
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001439 while (*s)
1440 if (*s++ == c)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001441 return 1;
1442 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001443}
1444
1445/*
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001446 * Is any character from s1 in s2?
Eric Andersenff9eee42001-06-29 04:57:14 +00001447 */
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001448static int anys(const char *s1, const char *s2)
Eric Andersenff9eee42001-06-29 04:57:14 +00001449{
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001450 while (*s1)
1451 if (any(*s1++, s2))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001452 return 1;
1453 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001454}
1455
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001456static char *putn(int n)
Eric Andersenff9eee42001-06-29 04:57:14 +00001457{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001458 return itoa(n);
Eric Andersenff9eee42001-06-29 04:57:14 +00001459}
1460
Eric Andersen8401eea2004-08-04 19:16:54 +00001461static void next(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00001462{
1463 PUSHIO(afile, f, filechar);
1464}
1465
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001466static void onintr(int s) /* ANSI C requires a parameter */
Eric Andersenff9eee42001-06-29 04:57:14 +00001467{
1468 signal(SIGINT, onintr);
1469 intr = 1;
1470 if (interactive) {
1471 if (inparse) {
1472 prs("\n");
1473 fail();
1474 }
Eric Andersen8401eea2004-08-04 19:16:54 +00001475 } else if (heedint) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001476 execflg = 0;
1477 leave();
1478 }
1479}
1480
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001481
Eric Andersenff9eee42001-06-29 04:57:14 +00001482/* -------- gmatch.c -------- */
1483/*
1484 * int gmatch(string, pattern)
1485 * char *string, *pattern;
1486 *
1487 * Match a pattern as in sh(1).
1488 */
1489
1490#define CMASK 0377
1491#define QUOTE 0200
Denis Vlasenko55f30b02007-03-24 22:42:29 +00001492#define QMASK (CMASK & ~QUOTE)
Eric Andersen8401eea2004-08-04 19:16:54 +00001493#define NOT '!' /* might use ^ */
Eric Andersenff9eee42001-06-29 04:57:14 +00001494
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001495static const char *cclass(const char *p, int sub)
1496{
1497 int c, d, not, found;
1498
1499 not = (*p == NOT);
1500 if (not != 0)
1501 p++;
1502 found = not;
1503 do {
1504 if (*p == '\0')
1505 return NULL;
1506 c = *p & CMASK;
1507 if (p[1] == '-' && p[2] != ']') {
1508 d = p[2] & CMASK;
1509 p++;
1510 } else
1511 d = c;
1512 if (c == sub || (c <= sub && sub <= d))
1513 found = !not;
1514 } while (*++p != ']');
1515 return found ? p + 1 : NULL;
1516}
1517
1518static int gmatch(const char *s, const char *p)
Eric Andersenff9eee42001-06-29 04:57:14 +00001519{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001520 int sc, pc;
Eric Andersenff9eee42001-06-29 04:57:14 +00001521
1522 if (s == NULL || p == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001523 return 0;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001524
Eric Andersenff9eee42001-06-29 04:57:14 +00001525 while ((pc = *p++ & CMASK) != '\0') {
1526 sc = *s++ & QMASK;
1527 switch (pc) {
1528 case '[':
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001529 p = cclass(p, sc);
1530 if (p == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001531 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001532 break;
1533
1534 case '?':
1535 if (sc == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001536 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001537 break;
1538
1539 case '*':
1540 s--;
1541 do {
1542 if (*p == '\0' || gmatch(s, p))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001543 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001544 } while (*s++ != '\0');
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001545 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001546
1547 default:
Eric Andersen8401eea2004-08-04 19:16:54 +00001548 if (sc != (pc & ~QUOTE))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001549 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001550 }
1551 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001552 return *s == '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00001553}
1554
Eric Andersenff9eee42001-06-29 04:57:14 +00001555
Eric Andersenff9eee42001-06-29 04:57:14 +00001556/* -------- csyn.c -------- */
1557/*
1558 * shell: syntax (C version)
1559 */
1560
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001561static void yyerror(const char *s) ATTRIBUTE_NORETURN;
1562static void yyerror(const char *s)
1563{
1564 yynerrs++;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001565 if (interactive && global_env.iop <= iostack) {
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001566 multiline = 0;
1567 while (eofc() == 0 && yylex(0) != '\n');
1568 }
1569 err(s);
1570 fail();
1571}
1572
1573static void zzerr(void) ATTRIBUTE_NORETURN;
1574static void zzerr(void)
1575{
1576 yyerror("syntax error");
1577}
1578
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001579int yyparse(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001580{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001581 DBGPRINTF7(("YYPARSE: enter...\n"));
1582
Eric Andersen8401eea2004-08-04 19:16:54 +00001583 startl = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001584 peeksym = 0;
1585 yynerrs = 0;
1586 outtree = c_list();
1587 musthave('\n', 0);
Eric Andersen8401eea2004-08-04 19:16:54 +00001588 return (yynerrs != 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001589}
1590
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001591static struct op *pipeline(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001592{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001593 struct op *t, *p;
1594 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001595
1596 DBGPRINTF7(("PIPELINE: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001597
1598 t = command(cf);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001599
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001600 DBGPRINTF9(("PIPELINE: t=%p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001601
Eric Andersenff9eee42001-06-29 04:57:14 +00001602 if (t != NULL) {
1603 while ((c = yylex(0)) == '|') {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001604 p = command(CONTIN);
1605 if (p == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001606 DBGPRINTF8(("PIPELINE: error!\n"));
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001607 zzerr();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001608 }
1609
Eric Andersenff9eee42001-06-29 04:57:14 +00001610 if (t->type != TPAREN && t->type != TCOM) {
1611 /* shell statement */
1612 t = block(TPAREN, t, NOBLOCK, NOWORDS);
1613 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001614
Eric Andersenff9eee42001-06-29 04:57:14 +00001615 t = block(TPIPE, t, p, NOWORDS);
1616 }
1617 peeksym = c;
1618 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001619
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001620 DBGPRINTF7(("PIPELINE: returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001621 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001622}
1623
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001624static struct op *andor(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001625{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001626 struct op *t, *p;
1627 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001628
1629 DBGPRINTF7(("ANDOR: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001630
1631 t = pipeline(0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001632
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001633 DBGPRINTF9(("ANDOR: t=%p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001634
Eric Andersenff9eee42001-06-29 04:57:14 +00001635 if (t != NULL) {
1636 while ((c = yylex(0)) == LOGAND || c == LOGOR) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001637 p = pipeline(CONTIN);
1638 if (p == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001639 DBGPRINTF8(("ANDOR: error!\n"));
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001640 zzerr();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001641 }
1642
Eric Andersen8401eea2004-08-04 19:16:54 +00001643 t = block(c == LOGAND ? TAND : TOR, t, p, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001644 } /* WHILE */
1645
Eric Andersenff9eee42001-06-29 04:57:14 +00001646 peeksym = c;
1647 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001648
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001649 DBGPRINTF7(("ANDOR: returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001650 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001651}
1652
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001653static struct op *c_list(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001654{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001655 struct op *t, *p;
1656 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001657
1658 DBGPRINTF7(("C_LIST: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001659
1660 t = andor();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001661
Eric Andersenff9eee42001-06-29 04:57:14 +00001662 if (t != NULL) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001663 peeksym = yylex(0);
1664 if (peeksym == '&')
Eric Andersenff9eee42001-06-29 04:57:14 +00001665 t = block(TASYNC, t, NOBLOCK, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001666
Eric Andersen8401eea2004-08-04 19:16:54 +00001667 while ((c = yylex(0)) == ';' || c == '&'
1668 || (multiline && c == '\n')) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001669
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001670 p = andor();
1671 if (p== NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001672 return t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001673
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001674 peeksym = yylex(0);
1675 if (peeksym == '&')
Eric Andersenff9eee42001-06-29 04:57:14 +00001676 p = block(TASYNC, p, NOBLOCK, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001677
Eric Andersenff9eee42001-06-29 04:57:14 +00001678 t = list(t, p);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001679 } /* WHILE */
1680
Eric Andersenff9eee42001-06-29 04:57:14 +00001681 peeksym = c;
1682 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001683 /* IF */
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001684 DBGPRINTF7(("C_LIST: returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001685 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001686}
1687
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001688static int synio(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001689{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001690 struct ioword *iop;
1691 int i;
1692 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001693
1694 DBGPRINTF7(("SYNIO: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001695
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001696 c = yylex(cf);
1697 if (c != '<' && c != '>') {
Eric Andersenff9eee42001-06-29 04:57:14 +00001698 peeksym = c;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001699 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001700 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001701
Eric Andersenff9eee42001-06-29 04:57:14 +00001702 i = yylval.i;
1703 musthave(WORD, 0);
1704 iop = io(iounit, i, yylval.cp);
1705 iounit = IODEFAULT;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001706
Eric Andersenff9eee42001-06-29 04:57:14 +00001707 if (i & IOHERE)
1708 markhere(yylval.cp, iop);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001709
1710 DBGPRINTF7(("SYNIO: returning 1\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001711 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001712}
1713
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001714static void musthave(int c, int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001715{
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001716 peeksym = yylex(cf);
1717 if (peeksym != c) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001718 DBGPRINTF7(("MUSTHAVE: error!\n"));
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001719 zzerr();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001720 }
1721
Eric Andersenff9eee42001-06-29 04:57:14 +00001722 peeksym = 0;
1723}
1724
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001725static struct op *simple(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001726{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001727 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001728
1729 t = NULL;
1730 for (;;) {
1731 switch (peeksym = yylex(0)) {
1732 case '<':
1733 case '>':
1734 (void) synio(0);
1735 break;
1736
1737 case WORD:
1738 if (t == NULL) {
1739 t = newtp();
1740 t->type = TCOM;
1741 }
1742 peeksym = 0;
1743 word(yylval.cp);
1744 break;
1745
1746 default:
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001747 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001748 }
1749 }
1750}
1751
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001752static struct op *nested(int type, int mark)
Eric Andersenff9eee42001-06-29 04:57:14 +00001753{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001754 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001755
1756 DBGPRINTF3(("NESTED: enter, type=%d, mark=%d\n", type, mark));
Eric Andersenff9eee42001-06-29 04:57:14 +00001757
1758 multiline++;
1759 t = c_list();
1760 musthave(mark, 0);
1761 multiline--;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001762 return block(type, t, NOBLOCK, NOWORDS);
Eric Andersenff9eee42001-06-29 04:57:14 +00001763}
1764
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001765static struct op *command(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001766{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001767 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001768 struct wdblock *iosave;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001769 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001770
1771 DBGPRINTF(("COMMAND: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001772
1773 iosave = iolist;
1774 iolist = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001775
Eric Andersenff9eee42001-06-29 04:57:14 +00001776 if (multiline)
1777 cf |= CONTIN;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001778
Eric Andersenff9eee42001-06-29 04:57:14 +00001779 while (synio(cf))
1780 cf = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001781
1782 c = yylex(cf);
1783
1784 switch (c) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001785 default:
1786 peeksym = c;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001787 t = simple();
1788 if (t == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001789 if (iolist == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001790 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001791 t = newtp();
1792 t->type = TCOM;
1793 }
1794 break;
1795
1796 case '(':
1797 t = nested(TPAREN, ')');
1798 break;
1799
1800 case '{':
1801 t = nested(TBRACE, '}');
1802 break;
1803
1804 case FOR:
1805 t = newtp();
1806 t->type = TFOR;
1807 musthave(WORD, 0);
1808 startl = 1;
1809 t->str = yylval.cp;
1810 multiline++;
1811 t->words = wordlist();
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001812 c = yylex(0);
1813 if (c != '\n' && c != ';')
Eric Andersenff9eee42001-06-29 04:57:14 +00001814 peeksym = c;
1815 t->left = dogroup(0);
1816 multiline--;
1817 break;
1818
1819 case WHILE:
1820 case UNTIL:
1821 multiline++;
1822 t = newtp();
Eric Andersen8401eea2004-08-04 19:16:54 +00001823 t->type = c == WHILE ? TWHILE : TUNTIL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001824 t->left = c_list();
1825 t->right = dogroup(1);
1826 t->words = NULL;
1827 multiline--;
1828 break;
1829
1830 case CASE:
1831 t = newtp();
1832 t->type = TCASE;
1833 musthave(WORD, 0);
1834 t->str = yylval.cp;
1835 startl++;
1836 multiline++;
1837 musthave(IN, CONTIN);
1838 startl++;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001839
Eric Andersenff9eee42001-06-29 04:57:14 +00001840 t->left = caselist();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001841
Eric Andersenff9eee42001-06-29 04:57:14 +00001842 musthave(ESAC, 0);
1843 multiline--;
1844 break;
1845
1846 case IF:
1847 multiline++;
1848 t = newtp();
1849 t->type = TIF;
1850 t->left = c_list();
1851 t->right = thenpart();
1852 musthave(FI, 0);
1853 multiline--;
1854 break;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001855
1856 case DOT:
1857 t = newtp();
1858 t->type = TDOT;
1859
1860 musthave(WORD, 0); /* gets name of file */
1861 DBGPRINTF7(("COMMAND: DOT clause, yylval.cp is %s\n", yylval.cp));
1862
1863 word(yylval.cp); /* add word to wdlist */
1864 word(NOWORD); /* terminate wdlist */
1865 t->words = copyw(); /* dup wdlist */
1866 break;
1867
Eric Andersenff9eee42001-06-29 04:57:14 +00001868 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001869
Eric Andersen8401eea2004-08-04 19:16:54 +00001870 while (synio(0));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001871
Eric Andersenff9eee42001-06-29 04:57:14 +00001872 t = namelist(t);
1873 iolist = iosave;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001874
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001875 DBGPRINTF(("COMMAND: returning %p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001876
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001877 return t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001878}
1879
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001880static struct op *dowholefile(int type, int mark)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001881{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001882 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001883
1884 DBGPRINTF(("DOWHOLEFILE: enter, type=%d, mark=%d\n", type, mark));
1885
1886 multiline++;
1887 t = c_list();
1888 multiline--;
1889 t = block(type, t, NOBLOCK, NOWORDS);
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001890 DBGPRINTF(("DOWHOLEFILE: return t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001891 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001892}
1893
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001894static struct op *dogroup(int onlydone)
Eric Andersenff9eee42001-06-29 04:57:14 +00001895{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001896 int c;
1897 struct op *mylist;
Eric Andersenff9eee42001-06-29 04:57:14 +00001898
1899 c = yylex(CONTIN);
1900 if (c == DONE && onlydone)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001901 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001902 if (c != DO)
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001903 zzerr();
Eric Andersenff9eee42001-06-29 04:57:14 +00001904 mylist = c_list();
1905 musthave(DONE, 0);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001906 return mylist;
Eric Andersenff9eee42001-06-29 04:57:14 +00001907}
1908
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001909static struct op *thenpart(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001910{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001911 int c;
1912 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001913
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001914 c = yylex(0);
1915 if (c != THEN) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001916 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001917 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001918 }
1919 t = newtp();
1920 t->type = 0;
1921 t->left = c_list();
1922 if (t->left == NULL)
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001923 zzerr();
Eric Andersenff9eee42001-06-29 04:57:14 +00001924 t->right = elsepart();
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001925 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001926}
1927
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001928static struct op *elsepart(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001929{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001930 int c;
1931 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001932
1933 switch (c = yylex(0)) {
1934 case ELSE:
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001935 t = c_list();
1936 if (t == NULL)
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001937 zzerr();
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001938 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001939
1940 case ELIF:
1941 t = newtp();
1942 t->type = TELIF;
1943 t->left = c_list();
1944 t->right = thenpart();
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001945 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001946
1947 default:
1948 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001949 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001950 }
1951}
1952
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001953static struct op *caselist(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001954{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001955 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001956
1957 t = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001958 while ((peeksym = yylex(CONTIN)) != ESAC) {
1959 DBGPRINTF(("CASELIST, doing yylex, peeksym=%d\n", peeksym));
Eric Andersenff9eee42001-06-29 04:57:14 +00001960 t = list(t, casepart());
Eric Andersen12de6cf2004-08-04 19:19:10 +00001961 }
1962
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001963 DBGPRINTF(("CASELIST, returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001964 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001965}
1966
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001967static struct op *casepart(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001968{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001969 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001970
1971 DBGPRINTF7(("CASEPART: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001972
1973 t = newtp();
1974 t->type = TPAT;
1975 t->words = pattern();
1976 musthave(')', 0);
1977 t->left = c_list();
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001978 peeksym = yylex(CONTIN);
1979 if (peeksym != ESAC)
Eric Andersenff9eee42001-06-29 04:57:14 +00001980 musthave(BREAK, CONTIN);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001981
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001982 DBGPRINTF7(("CASEPART: made newtp(TPAT, t=%p)\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001983
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001984 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001985}
1986
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001987static char **pattern(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001988{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001989 int c, cf;
Eric Andersenff9eee42001-06-29 04:57:14 +00001990
1991 cf = CONTIN;
1992 do {
1993 musthave(WORD, cf);
1994 word(yylval.cp);
1995 cf = 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001996 c = yylex(0);
1997 } while (c == '|');
Eric Andersenff9eee42001-06-29 04:57:14 +00001998 peeksym = c;
1999 word(NOWORD);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002000
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002001 return copyw();
Eric Andersenff9eee42001-06-29 04:57:14 +00002002}
2003
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002004static char **wordlist(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002005{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002006 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002007
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002008 c = yylex(0);
2009 if (c != IN) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002010 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002011 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00002012 }
2013 startl = 0;
2014 while ((c = yylex(0)) == WORD)
2015 word(yylval.cp);
2016 word(NOWORD);
2017 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002018 return copyw();
Eric Andersenff9eee42001-06-29 04:57:14 +00002019}
2020
2021/*
2022 * supporting functions
2023 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002024static struct op *list(struct op *t1, struct op *t2)
Eric Andersenff9eee42001-06-29 04:57:14 +00002025{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002026 DBGPRINTF7(("LIST: enter, t1=%p, t2=%p\n", t1, t2));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002027
Eric Andersenff9eee42001-06-29 04:57:14 +00002028 if (t1 == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002029 return t2;
Eric Andersenff9eee42001-06-29 04:57:14 +00002030 if (t2 == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002031 return t1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002032
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002033 return block(TLIST, t1, t2, NOWORDS);
Eric Andersenff9eee42001-06-29 04:57:14 +00002034}
2035
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002036static struct op *block(int type, struct op *t1, struct op *t2, char **wp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002037{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002038 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002039
2040 DBGPRINTF7(("BLOCK: enter, type=%d (%s)\n", type, T_CMD_NAMES[type]));
Eric Andersenff9eee42001-06-29 04:57:14 +00002041
2042 t = newtp();
2043 t->type = type;
2044 t->left = t1;
2045 t->right = t2;
2046 t->words = wp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002047
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002048 DBGPRINTF7(("BLOCK: inserted %p between %p and %p\n", t, t1,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002049 t2));
2050
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002051 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002052}
2053
Eric Andersen12de6cf2004-08-04 19:19:10 +00002054/* See if given string is a shell multiline (FOR, IF, etc) */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002055static int rlookup(char *n)
Eric Andersenff9eee42001-06-29 04:57:14 +00002056{
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002057 struct res {
2058 char r_name[6];
2059 int16_t r_val;
2060 };
2061 static const struct res restab[] = {
2062 { "for" , FOR },
2063 { "case" , CASE },
2064 { "esac" , ESAC },
2065 { "while", WHILE },
2066 { "do" , DO },
2067 { "done" , DONE },
2068 { "if" , IF },
2069 { "in" , IN },
2070 { "then" , THEN },
2071 { "else" , ELSE },
2072 { "elif" , ELIF },
2073 { "until", UNTIL },
2074 { "fi" , FI },
2075 { ";;" , BREAK },
2076 { "||" , LOGOR },
2077 { "&&" , LOGAND },
2078 { "{" , '{' },
2079 { "}" , '}' },
2080 { "." , DOT },
2081 { },
2082 };
2083
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002084 const struct res *rp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002085
2086 DBGPRINTF7(("RLOOKUP: enter, n is %s\n", n));
Eric Andersenff9eee42001-06-29 04:57:14 +00002087
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002088 for (rp = restab; rp->r_name[0]; rp++)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002089 if (strcmp(rp->r_name, n) == 0) {
2090 DBGPRINTF7(("RLOOKUP: match, returning %d\n", rp->r_val));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002091 return rp->r_val; /* Return numeric code for shell multiline */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002092 }
2093
2094 DBGPRINTF7(("RLOOKUP: NO match, returning 0\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002095 return 0; /* Not a shell multiline */
Eric Andersenff9eee42001-06-29 04:57:14 +00002096}
2097
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002098static struct op *newtp(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002099{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002100 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002101
Eric Andersen8401eea2004-08-04 19:16:54 +00002102 t = (struct op *) tree(sizeof(*t));
Eric Andersenff9eee42001-06-29 04:57:14 +00002103 t->type = 0;
2104 t->words = NULL;
2105 t->ioact = NULL;
2106 t->left = NULL;
2107 t->right = NULL;
2108 t->str = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002109
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002110 DBGPRINTF3(("NEWTP: allocated %p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002111
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002112 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002113}
2114
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002115static struct op *namelist(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00002116{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002117 DBGPRINTF7(("NAMELIST: enter, t=%p, type %s, iolist=%p\n", t,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002118 T_CMD_NAMES[t->type], iolist));
2119
Eric Andersenff9eee42001-06-29 04:57:14 +00002120 if (iolist) {
Eric Andersen8401eea2004-08-04 19:16:54 +00002121 iolist = addword((char *) NULL, iolist);
Eric Andersenff9eee42001-06-29 04:57:14 +00002122 t->ioact = copyio();
2123 } else
2124 t->ioact = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002125
Eric Andersenff9eee42001-06-29 04:57:14 +00002126 if (t->type != TCOM) {
2127 if (t->type != TPAREN && t->ioact != NULL) {
2128 t = block(TPAREN, t, NOBLOCK, NOWORDS);
2129 t->ioact = t->left->ioact;
2130 t->left->ioact = NULL;
2131 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002132 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002133 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002134
Eric Andersenff9eee42001-06-29 04:57:14 +00002135 word(NOWORD);
2136 t->words = copyw();
Eric Andersen12de6cf2004-08-04 19:19:10 +00002137
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002138 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002139}
2140
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002141static char **copyw(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002142{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002143 char **wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00002144
2145 wd = getwords(wdlist);
2146 wdlist = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002147 return wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00002148}
2149
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002150static void word(char *cp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002151{
2152 wdlist = addword(cp, wdlist);
2153}
2154
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002155static struct ioword **copyio(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002156{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002157 struct ioword **iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002158
2159 iop = (struct ioword **) getwords(iolist);
2160 iolist = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002161 return iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002162}
2163
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002164static struct ioword *io(int u, int f, char *cp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002165{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002166 struct ioword *iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002167
2168 iop = (struct ioword *) tree(sizeof(*iop));
2169 iop->io_unit = u;
2170 iop->io_flag = f;
2171 iop->io_name = cp;
Eric Andersen8401eea2004-08-04 19:16:54 +00002172 iolist = addword((char *) iop, iolist);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002173 return iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002174}
2175
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002176static int yylex(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00002177{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002178 int c, c1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002179 int atstart;
2180
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002181 c = peeksym;
2182 if (c > 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002183 peeksym = 0;
2184 if (c == '\n')
2185 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002186 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002187 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002188
Eric Andersenff9eee42001-06-29 04:57:14 +00002189 nlseen = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002190 atstart = startl;
2191 startl = 0;
2192 yylval.i = 0;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002193 global_env.linep = line;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002194
2195/* MALAMO */
2196 line[LINELIM - 1] = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00002197
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002198 loop:
Eric Andersen12de6cf2004-08-04 19:19:10 +00002199 while ((c = my_getc(0)) == ' ' || c == '\t') /* Skip whitespace */
2200 ;
2201
Eric Andersenff9eee42001-06-29 04:57:14 +00002202 switch (c) {
2203 default:
2204 if (any(c, "0123456789")) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002205 c1 = my_getc(0);
2206 unget(c1);
Eric Andersenff9eee42001-06-29 04:57:14 +00002207 if (c1 == '<' || c1 == '>') {
2208 iounit = c - '0';
2209 goto loop;
2210 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002211 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002212 c = c1;
2213 }
2214 break;
2215
Eric Andersen12de6cf2004-08-04 19:19:10 +00002216 case '#': /* Comment, skip to next newline or End-of-string */
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002217 while ((c = my_getc(0)) != '\0' && c != '\n');
Eric Andersenff9eee42001-06-29 04:57:14 +00002218 unget(c);
2219 goto loop;
2220
2221 case 0:
Eric Andersen12de6cf2004-08-04 19:19:10 +00002222 DBGPRINTF5(("YYLEX: return 0, c=%d\n", c));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002223 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002224
2225 case '$':
Eric Andersen12de6cf2004-08-04 19:19:10 +00002226 DBGPRINTF9(("YYLEX: found $\n"));
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002227 *global_env.linep++ = c;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002228 c = my_getc(0);
2229 if (c == '{') {
2230 c = collect(c, '}');
2231 if (c != '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002232 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002233 goto pack;
2234 }
2235 break;
2236
2237 case '`':
2238 case '\'':
2239 case '"':
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002240 c = collect(c, c);
2241 if (c != '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002242 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002243 goto pack;
2244
2245 case '|':
2246 case '&':
2247 case ';':
Eric Andersenff9eee42001-06-29 04:57:14 +00002248 startl = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002249 /* If more chars process them, else return NULL char */
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002250 c1 = dual(c);
2251 if (c1 != '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002252 return c1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002253 return c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002254
Eric Andersenff9eee42001-06-29 04:57:14 +00002255 case '^':
2256 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002257 return '|';
Eric Andersenff9eee42001-06-29 04:57:14 +00002258 case '>':
2259 case '<':
2260 diag(c);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002261 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002262
2263 case '\n':
2264 nlseen++;
2265 gethere();
2266 startl = 1;
2267 if (multiline || cf & CONTIN) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002268 if (interactive && global_env.iop <= iostack) {
Denis Vlasenko38f63192007-01-22 09:03:07 +00002269#if ENABLE_FEATURE_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00002270 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00002271#else
Eric Andersen8401eea2004-08-04 19:16:54 +00002272 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00002273#endif
2274 }
2275 if (cf & CONTIN)
2276 goto loop;
2277 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002278 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002279
2280 case '(':
2281 case ')':
2282 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002283 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002284 }
2285
2286 unget(c);
2287
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002288 pack:
2289 while ((c = my_getc(0)) != '\0' && !any(c, "`$ '\"\t;&<>()|^\n")) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002290 if (global_env.linep >= elinep)
Eric Andersenff9eee42001-06-29 04:57:14 +00002291 err("word too long");
2292 else
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002293 *global_env.linep++ = c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002294 };
2295
Eric Andersenff9eee42001-06-29 04:57:14 +00002296 unget(c);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002297
Eric Andersen8401eea2004-08-04 19:16:54 +00002298 if (any(c, "\"'`$"))
Eric Andersenff9eee42001-06-29 04:57:14 +00002299 goto loop;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002300
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002301 *global_env.linep++ = '\0';
Eric Andersen12de6cf2004-08-04 19:19:10 +00002302
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002303 if (atstart) {
2304 c = rlookup(line);
2305 if (c != 0) {
2306 startl = 1;
2307 return c;
2308 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002309 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002310
Eric Andersenff9eee42001-06-29 04:57:14 +00002311 yylval.cp = strsave(line, areanum);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002312 return WORD;
Eric Andersenff9eee42001-06-29 04:57:14 +00002313}
2314
Eric Andersen12de6cf2004-08-04 19:19:10 +00002315
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002316static int collect(int c, int c1)
Eric Andersenff9eee42001-06-29 04:57:14 +00002317{
2318 char s[2];
2319
Eric Andersen12de6cf2004-08-04 19:19:10 +00002320 DBGPRINTF8(("COLLECT: enter, c=%d, c1=%d\n", c, c1));
2321
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002322 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002323 while ((c = my_getc(c1)) != c1) {
2324 if (c == 0) {
2325 unget(c);
2326 s[0] = c1;
2327 s[1] = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00002328 prs("no closing ");
2329 yyerror(s);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002330 return YYERRCODE;
Eric Andersenff9eee42001-06-29 04:57:14 +00002331 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002332 if (interactive && c == '\n' && global_env.iop <= iostack) {
Denis Vlasenko38f63192007-01-22 09:03:07 +00002333#if ENABLE_FEATURE_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00002334 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00002335#else
Eric Andersen8401eea2004-08-04 19:16:54 +00002336 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00002337#endif
2338 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002339 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002340 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002341
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002342 *global_env.linep++ = c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002343
2344 DBGPRINTF8(("COLLECT: return 0, line is %s\n", line));
2345
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002346 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002347}
2348
Eric Andersen12de6cf2004-08-04 19:19:10 +00002349/* "multiline commands" helper func */
2350/* see if next 2 chars form a shell multiline */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002351static int dual(int c)
Eric Andersenff9eee42001-06-29 04:57:14 +00002352{
2353 char s[3];
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002354 char *cp = s;
Eric Andersenff9eee42001-06-29 04:57:14 +00002355
Eric Andersen12de6cf2004-08-04 19:19:10 +00002356 DBGPRINTF8(("DUAL: enter, c=%d\n", c));
2357
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002358 *cp++ = c; /* c is the given "peek" char */
2359 *cp++ = my_getc(0); /* get next char of input */
2360 *cp = '\0'; /* add EOS marker */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002361
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002362 c = rlookup(s); /* see if 2 chars form a shell multiline */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002363 if (c == 0)
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002364 unget(*--cp); /* String is not a shell multiline, put peek char back */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002365
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002366 return c; /* String is multiline, return numeric multiline (restab) code */
Eric Andersenff9eee42001-06-29 04:57:14 +00002367}
2368
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002369static void diag(int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00002370{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002371 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002372
2373 DBGPRINTF8(("DIAG: enter, ec=%d\n", ec));
Eric Andersenff9eee42001-06-29 04:57:14 +00002374
2375 c = my_getc(0);
2376 if (c == '>' || c == '<') {
2377 if (c != ec)
2378 zzerr();
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002379 yylval.i = (ec == '>' ? IOWRITE | IOCAT : IOHERE);
Eric Andersenff9eee42001-06-29 04:57:14 +00002380 c = my_getc(0);
2381 } else
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002382 yylval.i = (ec == '>' ? IOWRITE : IOREAD);
Eric Andersenff9eee42001-06-29 04:57:14 +00002383 if (c != '&' || yylval.i == IOHERE)
2384 unget(c);
2385 else
2386 yylval.i |= IODUP;
2387}
2388
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002389static char *tree(unsigned size)
Eric Andersenff9eee42001-06-29 04:57:14 +00002390{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002391 char *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002392
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002393 t = getcell(size);
2394 if (t == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002395 DBGPRINTF2(("TREE: getcell(%d) failed!\n", size));
Eric Andersenff9eee42001-06-29 04:57:14 +00002396 prs("command line too complicated\n");
2397 fail();
2398 /* NOTREACHED */
2399 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002400 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002401}
2402
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002403
Eric Andersenff9eee42001-06-29 04:57:14 +00002404/* VARARGS1 */
2405/* ARGSUSED */
2406
2407/* -------- exec.c -------- */
2408
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002409static struct op **find1case(struct op *t, const char *w)
2410{
2411 struct op *t1;
2412 struct op **tp;
2413 char **wp;
2414 char *cp;
2415
2416 if (t == NULL) {
2417 DBGPRINTF3(("FIND1CASE: enter, t==NULL, returning.\n"));
2418 return NULL;
2419 }
2420
2421 DBGPRINTF3(("FIND1CASE: enter, t->type=%d (%s)\n", t->type,
2422 T_CMD_NAMES[t->type]));
2423
2424 if (t->type == TLIST) {
2425 tp = find1case(t->left, w);
2426 if (tp != NULL) {
2427 DBGPRINTF3(("FIND1CASE: found one to the left, returning tp=%p\n", tp));
2428 return tp;
2429 }
2430 t1 = t->right; /* TPAT */
2431 } else
2432 t1 = t;
2433
2434 for (wp = t1->words; *wp;) {
2435 cp = evalstr(*wp++, DOSUB);
2436 if (cp && gmatch(w, cp)) {
2437 DBGPRINTF3(("FIND1CASE: returning &t1->left= %p.\n",
2438 &t1->left));
2439 return &t1->left;
2440 }
2441 }
2442
2443 DBGPRINTF(("FIND1CASE: returning NULL\n"));
2444 return NULL;
2445}
2446
2447static struct op *findcase(struct op *t, const char *w)
2448{
2449 struct op **tp;
2450
2451 tp = find1case(t, w);
2452 return tp != NULL ? *tp : NULL;
2453}
2454
Eric Andersenff9eee42001-06-29 04:57:14 +00002455/*
2456 * execute tree
2457 */
2458
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002459static int execute(struct op *t, int *pin, int *pout, int act)
Eric Andersenff9eee42001-06-29 04:57:14 +00002460{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002461 struct op *t1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002462 volatile int i, rv, a;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002463 const char *cp;
2464 char **wp, **wp2;
Eric Andersenff9eee42001-06-29 04:57:14 +00002465 struct var *vp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002466 struct op *outtree_save;
Eric Andersenff9eee42001-06-29 04:57:14 +00002467 struct brkcon bc;
2468
2469#if __GNUC__
2470 /* Avoid longjmp clobbering */
2471 (void) &wp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002472#endif
Eric Andersenff9eee42001-06-29 04:57:14 +00002473
Eric Andersen12de6cf2004-08-04 19:19:10 +00002474 if (t == NULL) {
2475 DBGPRINTF4(("EXECUTE: enter, t==null, returning.\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002476 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002477 }
2478
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002479 DBGPRINTF(("EXECUTE: t=%p, t->type=%d (%s), t->words is %s\n", t,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002480 t->type, T_CMD_NAMES[t->type],
2481 ((t->words == NULL) ? "NULL" : t->words[0])));
2482
Eric Andersenff9eee42001-06-29 04:57:14 +00002483 rv = 0;
2484 a = areanum++;
2485 wp = (wp2 = t->words) != NULL
Eric Andersen8401eea2004-08-04 19:16:54 +00002486 ? eval(wp2, t->type == TCOM ? DOALL : DOALL & ~DOKEY)
2487 : NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00002488
Eric Andersen8401eea2004-08-04 19:16:54 +00002489 switch (t->type) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002490 case TDOT:
2491 DBGPRINTF3(("EXECUTE: TDOT\n"));
2492
2493 outtree_save = outtree;
2494
2495 newfile(evalstr(t->words[0], DOALL));
2496
2497 t->left = dowholefile(TLIST, 0);
2498 t->right = NULL;
2499
2500 outtree = outtree_save;
2501
2502 if (t->left)
2503 rv = execute(t->left, pin, pout, 0);
2504 if (t->right)
2505 rv = execute(t->right, pin, pout, 0);
2506 break;
2507
Eric Andersenff9eee42001-06-29 04:57:14 +00002508 case TPAREN:
Eric Andersen737f5fb2003-03-14 16:05:59 +00002509 rv = execute(t->left, pin, pout, 0);
2510 break;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002511
Eric Andersenff9eee42001-06-29 04:57:14 +00002512 case TCOM:
Denis Vlasenko489f93e2007-02-01 01:43:16 +00002513 rv = forkexec(t, pin, pout, act, wp);
Eric Andersenff9eee42001-06-29 04:57:14 +00002514 break;
2515
2516 case TPIPE:
2517 {
Eric Andersen8401eea2004-08-04 19:16:54 +00002518 int pv[2];
2519
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002520 rv = openpipe(pv);
2521 if (rv < 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00002522 break;
2523 pv[0] = remap(pv[0]);
2524 pv[1] = remap(pv[1]);
2525 (void) execute(t->left, pin, pv, 0);
2526 rv = execute(t->right, pv, pout, 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002527 }
2528 break;
2529
2530 case TLIST:
2531 (void) execute(t->left, pin, pout, 0);
2532 rv = execute(t->right, pin, pout, 0);
2533 break;
2534
2535 case TASYNC:
Eric Andersen8401eea2004-08-04 19:16:54 +00002536 {
2537 int hinteractive = interactive;
Eric Andersenff9eee42001-06-29 04:57:14 +00002538
Eric Andersen12de6cf2004-08-04 19:19:10 +00002539 DBGPRINTF7(("EXECUTE: TASYNC clause, calling vfork()...\n"));
2540
Eric Andersen8401eea2004-08-04 19:16:54 +00002541 i = vfork();
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002542 if (i == 0) { /* child */
Eric Andersen8401eea2004-08-04 19:16:54 +00002543 signal(SIGINT, SIG_IGN);
2544 signal(SIGQUIT, SIG_IGN);
2545 if (interactive)
2546 signal(SIGTERM, SIG_DFL);
2547 interactive = 0;
2548 if (pin == NULL) {
2549 close(0);
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00002550 xopen(bb_dev_null, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00002551 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002552 _exit(execute(t->left, pin, pout, FEXEC));
Eric Andersenff9eee42001-06-29 04:57:14 +00002553 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002554 interactive = hinteractive;
2555 if (i != -1) {
2556 setval(lookup("!"), putn(i));
2557 if (pin != NULL)
2558 closepipe(pin);
2559 if (interactive) {
2560 prs(putn(i));
2561 prs("\n");
2562 }
2563 } else
2564 rv = -1;
2565 setstatus(rv);
Eric Andersenff9eee42001-06-29 04:57:14 +00002566 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002567 break;
2568
2569 case TOR:
2570 case TAND:
2571 rv = execute(t->left, pin, pout, 0);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002572 t1 = t->right;
2573 if (t1 != NULL && (rv == 0) == (t->type == TAND))
Eric Andersenff9eee42001-06-29 04:57:14 +00002574 rv = execute(t1, pin, pout, 0);
2575 break;
2576
2577 case TFOR:
2578 if (wp == NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00002579 wp = dolv + 1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002580 i = dolc;
2581 if (i < 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00002582 i = 0;
2583 } else {
2584 i = -1;
Eric Andersen8401eea2004-08-04 19:16:54 +00002585 while (*wp++ != NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00002586 }
2587 vp = lookup(t->str);
2588 while (setjmp(bc.brkpt))
2589 if (isbreak)
2590 goto broken;
2591 brkset(&bc);
2592 for (t1 = t->left; i-- && *wp != NULL;) {
2593 setval(vp, *wp++);
2594 rv = execute(t1, pin, pout, 0);
2595 }
2596 brklist = brklist->nextlev;
2597 break;
2598
2599 case TWHILE:
2600 case TUNTIL:
2601 while (setjmp(bc.brkpt))
2602 if (isbreak)
2603 goto broken;
2604 brkset(&bc);
2605 t1 = t->left;
2606 while ((execute(t1, pin, pout, 0) == 0) == (t->type == TWHILE))
2607 rv = execute(t->right, pin, pout, 0);
2608 brklist = brklist->nextlev;
2609 break;
2610
2611 case TIF:
2612 case TELIF:
Eric Andersen8401eea2004-08-04 19:16:54 +00002613 if (t->right != NULL) {
2614 rv = !execute(t->left, pin, pout, 0) ?
2615 execute(t->right->left, pin, pout, 0) :
2616 execute(t->right->right, pin, pout, 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002617 }
2618 break;
2619
2620 case TCASE:
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002621 cp = evalstr(t->str, DOSUB | DOTRIM);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002622 if (cp == NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00002623 cp = "";
Eric Andersen12de6cf2004-08-04 19:19:10 +00002624
2625 DBGPRINTF7(("EXECUTE: TCASE, t->str is %s, cp is %s\n",
2626 ((t->str == NULL) ? "NULL" : t->str),
2627 ((cp == NULL) ? "NULL" : cp)));
2628
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002629 t1 = findcase(t->left, cp);
2630 if (t1 != NULL) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002631 DBGPRINTF7(("EXECUTE: TCASE, calling execute(t=%p, t1=%p)...\n", t, t1));
Eric Andersenff9eee42001-06-29 04:57:14 +00002632 rv = execute(t1, pin, pout, 0);
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002633 DBGPRINTF7(("EXECUTE: TCASE, back from execute(t=%p, t1=%p)...\n", t, t1));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002634 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002635 break;
2636
2637 case TBRACE:
2638/*
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002639 iopp = t->ioact;
2640 if (i)
Eric Andersenff9eee42001-06-29 04:57:14 +00002641 while (*iopp)
2642 if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) {
2643 rv = -1;
2644 break;
2645 }
2646*/
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002647 if (rv >= 0) {
2648 t1 = t->left;
2649 if (t1) {
2650 rv = execute(t1, pin, pout, 0);
2651 }
2652 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002653 break;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002654
2655 };
Eric Andersenff9eee42001-06-29 04:57:14 +00002656
Denis Vlasenkoe4712752007-04-14 15:08:41 +00002657 broken:
Eric Andersenff9eee42001-06-29 04:57:14 +00002658 t->words = wp2;
2659 isbreak = 0;
2660 freehere(areanum);
2661 freearea(areanum);
2662 areanum = a;
2663 if (interactive && intr) {
2664 closeall();
2665 fail();
2666 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002667
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002668 i = trapset;
2669 if (i != 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002670 trapset = 0;
2671 runtrap(i);
2672 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002673
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002674 DBGPRINTF(("EXECUTE: returning from t=%p, rv=%d\n", t, rv));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002675 return rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00002676}
2677
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002678typedef int (*builtin_func_ptr)(struct op *);
2679
Denis Vlasenkoe4712752007-04-14 15:08:41 +00002680static builtin_func_ptr inbuilt(const char *s)
2681{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002682 const struct builtincmd *bp;
2683
Denis Vlasenko95cb3262007-04-09 03:06:34 +00002684 for (bp = builtincmds; bp->name; bp++)
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002685 if (strcmp(bp->name, s) == 0)
2686 return bp->builtinfunc;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002687 return NULL;
2688}
2689
2690static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002691{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002692 pid_t newpid;
Eric Andersenff9eee42001-06-29 04:57:14 +00002693 int i, rv;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002694 builtin_func_ptr shcom = NULL;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002695 int f;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002696 const char *cp = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00002697 struct ioword **iopp;
2698 int resetsig;
2699 char **owp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002700 int forked = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002701
2702 int *hpin = pin;
2703 int *hpout = pout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002704 char *hwp;
2705 int hinteractive;
2706 int hintr;
Eric Andersen8401eea2004-08-04 19:16:54 +00002707 struct brkcon *hbrklist;
Eric Andersenff9eee42001-06-29 04:57:14 +00002708 int hexecflg;
2709
2710#if __GNUC__
2711 /* Avoid longjmp clobbering */
2712 (void) &pin;
2713 (void) &pout;
2714 (void) &wp;
2715 (void) &shcom;
2716 (void) &cp;
2717 (void) &resetsig;
2718 (void) &owp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002719#endif
Eric Andersenff9eee42001-06-29 04:57:14 +00002720
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002721 DBGPRINTF(("FORKEXEC: t=%p, pin %p, pout %p, act %d\n", t, pin,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002722 pout, act));
2723 DBGPRINTF7(("FORKEXEC: t->words is %s\n",
2724 ((t->words == NULL) ? "NULL" : t->words[0])));
2725
Eric Andersenff9eee42001-06-29 04:57:14 +00002726 owp = wp;
2727 resetsig = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00002728 rv = -1; /* system-detected error */
Eric Andersenff9eee42001-06-29 04:57:14 +00002729 if (t->type == TCOM) {
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00002730 while (*wp++ != NULL)
2731 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00002732 cp = *wp;
2733
2734 /* strip all initial assignments */
2735 /* not correct wrt PATH=yyy command etc */
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00002736 if (FLAG['x']) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002737 DBGPRINTF9(("FORKEXEC: echo'ing, cp=%p, wp=%p, owp=%p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00002738 cp, wp, owp));
Eric Andersen8401eea2004-08-04 19:16:54 +00002739 echo(cp ? wp : owp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002740 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002741
Eric Andersenff9eee42001-06-29 04:57:14 +00002742 if (cp == NULL && t->ioact == NULL) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002743 while ((cp = *owp++) != NULL && assign(cp, COPYV))
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00002744 continue;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002745 DBGPRINTF(("FORKEXEC: returning setstatus()\n"));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002746 return setstatus(0);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002747 }
2748 if (cp != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002749 shcom = inbuilt(cp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002750 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002751 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002752
Eric Andersenff9eee42001-06-29 04:57:14 +00002753 t->words = wp;
2754 f = act;
Eric Andersenff9eee42001-06-29 04:57:14 +00002755
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002756 DBGPRINTF(("FORKEXEC: shcom %p, f&FEXEC 0x%x, owp %p\n", shcom,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002757 f & FEXEC, owp));
2758
2759 if (shcom == NULL && (f & FEXEC) == 0) {
2760 /* Save values in case the child process alters them */
Eric Andersenff9eee42001-06-29 04:57:14 +00002761 hpin = pin;
2762 hpout = pout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002763 hwp = *wp;
2764 hinteractive = interactive;
2765 hintr = intr;
2766 hbrklist = brklist;
2767 hexecflg = execflg;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002768
Eric Andersen12de6cf2004-08-04 19:19:10 +00002769 DBGPRINTF3(("FORKEXEC: calling vfork()...\n"));
2770
2771 newpid = vfork();
2772
2773 if (newpid == -1) {
Denis Vlasenko89f0b342006-11-18 22:04:09 +00002774 DBGPRINTF(("FORKEXEC: ERROR, cannot vfork()!\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002775 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002776 }
2777
Denis Vlasenko489f93e2007-02-01 01:43:16 +00002778 if (newpid > 0) { /* Parent */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002779 /* Restore values */
Eric Andersenff9eee42001-06-29 04:57:14 +00002780 pin = hpin;
2781 pout = hpout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002782 *wp = hwp;
2783 interactive = hinteractive;
2784 intr = hintr;
2785 brklist = hbrklist;
2786 execflg = hexecflg;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002787/* moved up
Eric Andersenff9eee42001-06-29 04:57:14 +00002788 if (i == -1)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002789 return rv;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002790*/
Eric Andersenff9eee42001-06-29 04:57:14 +00002791 if (pin != NULL)
2792 closepipe(pin);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002793
2794 return (pout == NULL ? setstatus(waitfor(newpid, 0)) : 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002795 }
2796
Eric Andersen12de6cf2004-08-04 19:19:10 +00002797 /* Must be the child process, pid should be 0 */
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002798 DBGPRINTF(("FORKEXEC: child process, shcom=%p\n", shcom));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002799
Eric Andersenff9eee42001-06-29 04:57:14 +00002800 if (interactive) {
2801 signal(SIGINT, SIG_IGN);
2802 signal(SIGQUIT, SIG_IGN);
2803 resetsig = 1;
2804 }
2805 interactive = 0;
2806 intr = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002807 forked = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002808 brklist = 0;
2809 execflg = 0;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002810 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002811
Eric Andersenff9eee42001-06-29 04:57:14 +00002812 if (owp != NULL)
2813 while ((cp = *owp++) != NULL && assign(cp, COPYV))
2814 if (shcom == NULL)
2815 export(lookup(cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002816
Eric Andersenff9eee42001-06-29 04:57:14 +00002817#ifdef COMPIPE
2818 if ((pin != NULL || pout != NULL) && shcom != NULL && shcom != doexec) {
2819 err("piping to/from shell builtins not yet done");
Eric Andersen12de6cf2004-08-04 19:19:10 +00002820 if (forked)
2821 _exit(-1);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002822 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002823 }
2824#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00002825
Eric Andersenff9eee42001-06-29 04:57:14 +00002826 if (pin != NULL) {
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00002827 xmove_fd(pin[0], 0);
2828 if (pin[1] != 0) 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);
2832 if (pout[1] != 1) close(pout[0]);
Eric Andersenff9eee42001-06-29 04:57:14 +00002833 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002834
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002835 iopp = t->ioact;
2836 if (iopp != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002837 if (shcom != NULL && shcom != doexec) {
2838 prs(cp);
2839 err(": cannot redirect shell command");
Eric Andersen12de6cf2004-08-04 19:19:10 +00002840 if (forked)
2841 _exit(-1);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002842 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002843 }
2844 while (*iopp)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002845 if (iosetup(*iopp++, pin != NULL, pout != NULL)) {
2846 if (forked)
2847 _exit(rv);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002848 return rv;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002849 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002850 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002851
2852 if (shcom) {
2853 i = setstatus((*shcom) (t));
2854 if (forked)
2855 _exit(i);
2856 DBGPRINTF(("FORKEXEC: returning i=%d\n", i));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002857 return i;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002858 }
2859
Eric Andersenff9eee42001-06-29 04:57:14 +00002860 /* should use FIOCEXCL */
Eric Andersen8401eea2004-08-04 19:16:54 +00002861 for (i = FDBASE; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00002862 close(i);
2863 if (resetsig) {
2864 signal(SIGINT, SIG_DFL);
2865 signal(SIGQUIT, SIG_DFL);
2866 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002867
Eric Andersen12de6cf2004-08-04 19:19:10 +00002868 if (t->type == TPAREN)
2869 _exit(execute(t->left, NOPIPE, NOPIPE, FEXEC));
2870 if (wp[0] == NULL)
2871 _exit(0);
2872
Eric Andersenfd7a4c82004-09-02 23:13:10 +00002873 cp = rexecve(wp[0], wp, makenv(0, NULL));
Eric Andersen8401eea2004-08-04 19:16:54 +00002874 prs(wp[0]);
2875 prs(": ");
Eric Andersen12de6cf2004-08-04 19:19:10 +00002876 err(cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00002877 if (!execflg)
2878 trap[0] = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002879
2880 DBGPRINTF(("FORKEXEC: calling leave(), pid=%d\n", newpid));
2881
Eric Andersenff9eee42001-06-29 04:57:14 +00002882 leave();
2883 /* NOTREACHED */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002884 _exit(1);
Eric Andersenff9eee42001-06-29 04:57:14 +00002885}
2886
2887/*
2888 * 0< 1> are ignored as required
2889 * within pipelines.
2890 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002891static int iosetup(struct ioword *iop, int pipein, int pipeout)
Eric Andersenff9eee42001-06-29 04:57:14 +00002892{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002893 int u = -1;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002894 char *cp = NULL;
2895 const char *msg;
Eric Andersenff9eee42001-06-29 04:57:14 +00002896
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002897 DBGPRINTF(("IOSETUP: iop %p, pipein %i, pipeout %i\n", iop,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002898 pipein, pipeout));
2899
Eric Andersenff9eee42001-06-29 04:57:14 +00002900 if (iop->io_unit == IODEFAULT) /* take default */
Eric Andersen8401eea2004-08-04 19:16:54 +00002901 iop->io_unit = iop->io_flag & (IOREAD | IOHERE) ? 0 : 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002902
Eric Andersenff9eee42001-06-29 04:57:14 +00002903 if (pipein && iop->io_unit == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002904 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002905
Eric Andersenff9eee42001-06-29 04:57:14 +00002906 if (pipeout && iop->io_unit == 1)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002907 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002908
Eric Andersen8401eea2004-08-04 19:16:54 +00002909 msg = iop->io_flag & (IOREAD | IOHERE) ? "open" : "create";
Eric Andersenff9eee42001-06-29 04:57:14 +00002910 if ((iop->io_flag & IOHERE) == 0) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002911 cp = iop->io_name; /* huh?? */
2912 cp = evalstr(cp, DOSUB | DOTRIM);
2913 if (cp == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002914 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002915 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002916
Eric Andersenff9eee42001-06-29 04:57:14 +00002917 if (iop->io_flag & IODUP) {
2918 if (cp[1] || (!isdigit(*cp) && *cp != '-')) {
2919 prs(cp);
2920 err(": illegal >& argument");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002921 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002922 }
2923 if (*cp == '-')
2924 iop->io_flag = IOCLOSE;
Eric Andersen8401eea2004-08-04 19:16:54 +00002925 iop->io_flag &= ~(IOREAD | IOWRITE);
Eric Andersenff9eee42001-06-29 04:57:14 +00002926 }
2927 switch (iop->io_flag) {
2928 case IOREAD:
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00002929 u = open(cp, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00002930 break;
2931
2932 case IOHERE:
Eric Andersen8401eea2004-08-04 19:16:54 +00002933 case IOHERE | IOXHERE:
2934 u = herein(iop->io_name, iop->io_flag & IOXHERE);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002935 cp = (char*)"here file";
Eric Andersenff9eee42001-06-29 04:57:14 +00002936 break;
2937
Eric Andersen8401eea2004-08-04 19:16:54 +00002938 case IOWRITE | IOCAT:
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00002939 u = open(cp, O_WRONLY);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002940 if (u >= 0) {
Denis Vlasenkoea620772006-10-14 02:23:43 +00002941 lseek(u, (long) 0, SEEK_END);
Eric Andersenff9eee42001-06-29 04:57:14 +00002942 break;
2943 }
2944 case IOWRITE:
2945 u = creat(cp, 0666);
2946 break;
2947
2948 case IODUP:
Eric Andersen8401eea2004-08-04 19:16:54 +00002949 u = dup2(*cp - '0', iop->io_unit);
Eric Andersenff9eee42001-06-29 04:57:14 +00002950 break;
2951
2952 case IOCLOSE:
2953 close(iop->io_unit);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002954 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002955 }
2956 if (u < 0) {
2957 prs(cp);
2958 prs(": cannot ");
2959 warn(msg);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002960 return 1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002961 }
2962 if (u != iop->io_unit) {
2963 dup2(u, iop->io_unit);
2964 close(u);
Eric Andersenff9eee42001-06-29 04:57:14 +00002965 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002966 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002967}
2968
Eric Andersenff9eee42001-06-29 04:57:14 +00002969/*
2970 * Enter a new loop level (marked for break/continue).
2971 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002972static void brkset(struct brkcon *bc)
Eric Andersenff9eee42001-06-29 04:57:14 +00002973{
2974 bc->nextlev = brklist;
2975 brklist = bc;
2976}
2977
2978/*
2979 * Wait for the last process created.
2980 * Print a message for each process found
2981 * that was killed by a signal.
2982 * Ignore interrupt signals while waiting
2983 * unless `canintr' is true.
2984 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002985static int waitfor(int lastpid, int canintr)
Eric Andersenff9eee42001-06-29 04:57:14 +00002986{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002987 int pid, rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00002988 int s;
2989 int oheedint = heedint;
2990
2991 heedint = 0;
2992 rv = 0;
2993 do {
2994 pid = wait(&s);
2995 if (pid == -1) {
2996 if (errno != EINTR || canintr)
2997 break;
2998 } else {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002999 rv = WAITSIG(s);
3000 if (rv != 0) {
Denis Vlasenko80b8b392007-06-25 10:55:35 +00003001 if (rv < ARRAY_SIZE(signame)) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003002 if (signame[rv] != NULL) {
3003 if (pid != lastpid) {
3004 prn(pid);
3005 prs(": ");
3006 }
3007 prs(signame[rv]);
3008 }
3009 } else {
3010 if (pid != lastpid) {
3011 prn(pid);
3012 prs(": ");
3013 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003014 prs("Signal ");
3015 prn(rv);
3016 prs(" ");
Eric Andersenff9eee42001-06-29 04:57:14 +00003017 }
3018 if (WAITCORE(s))
3019 prs(" - core dumped");
Denis Vlasenko80b8b392007-06-25 10:55:35 +00003020 if (rv >= ARRAY_SIZE(signame) || signame[rv])
Eric Andersenff9eee42001-06-29 04:57:14 +00003021 prs("\n");
3022 rv = -1;
3023 } else
3024 rv = WAITVAL(s);
3025 }
3026 } while (pid != lastpid);
3027 heedint = oheedint;
3028 if (intr) {
3029 if (interactive) {
3030 if (canintr)
3031 intr = 0;
3032 } else {
Eric Andersen8401eea2004-08-04 19:16:54 +00003033 if (exstat == 0)
3034 exstat = rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003035 onintr(0);
3036 }
3037 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003038 return rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003039}
3040
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003041static int setstatus(int s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003042{
3043 exstat = s;
3044 setval(lookup("?"), putn(s));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003045 return s;
Eric Andersenff9eee42001-06-29 04:57:14 +00003046}
3047
3048/*
3049 * PATH-searching interface to execve.
3050 * If getenv("PATH") were kept up-to-date,
3051 * execvp might be used.
3052 */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003053static const char *rexecve(char *c, char **v, char **envp)
Eric Andersenff9eee42001-06-29 04:57:14 +00003054{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003055 int i;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003056 const char *sp;
3057 char *tp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003058 int eacces = 0, asis = 0;
Eric Andersen1c039232001-07-07 00:05:55 +00003059 char *name = c;
Eric Andersen8401eea2004-08-04 19:16:54 +00003060
Denis Vlasenko80d14be2007-04-10 23:03:30 +00003061 if (ENABLE_FEATURE_SH_STANDALONE) {
Denis Vlasenko1aa7e472007-11-28 06:49:03 +00003062 if (find_applet_by_name(name) >= 0) {
Rob Landleya299efb2006-08-10 21:46:43 +00003063 /* We have to exec here since we vforked. Running
Denis Vlasenkoe4f2d062007-04-11 17:03:19 +00003064 * run_applet_and_exit() won't work and bad things
Rob Landleya299efb2006-08-10 21:46:43 +00003065 * will happen. */
Denis Vlasenkobdbbb7e2007-06-08 15:02:55 +00003066 execve(bb_busybox_exec_path, v, envp);
Rob Landleya299efb2006-08-10 21:46:43 +00003067 }
Eric Andersen1c039232001-07-07 00:05:55 +00003068 }
Eric Andersen1c039232001-07-07 00:05:55 +00003069
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003070 DBGPRINTF(("REXECVE: c=%p, v=%p, envp=%p\n", c, v, envp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003071
Eric Andersen8401eea2004-08-04 19:16:54 +00003072 sp = any('/', c) ? "" : path->value;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003073 asis = (*sp == '\0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003074 while (asis || *sp != '\0') {
3075 asis = 0;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003076 tp = global_env.linep;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003077 for (; *sp != '\0'; tp++) {
3078 *tp = *sp++;
3079 if (*tp == ':') {
3080 asis = (*sp == '\0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003081 break;
3082 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003083 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003084 if (tp != global_env.linep)
Eric Andersenff9eee42001-06-29 04:57:14 +00003085 *tp++ = '/';
Eric Andersen8401eea2004-08-04 19:16:54 +00003086 for (i = 0; (*tp++ = c[i++]) != '\0';);
Eric Andersen1c039232001-07-07 00:05:55 +00003087
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003088 DBGPRINTF3(("REXECVE: global_env.linep is %s\n", global_env.linep));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003089
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003090 execve(global_env.linep, v, envp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003091
Eric Andersenff9eee42001-06-29 04:57:14 +00003092 switch (errno) {
3093 case ENOEXEC:
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003094 *v = global_env.linep;
Eric Andersenff9eee42001-06-29 04:57:14 +00003095 tp = *--v;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003096 *v = global_env.linep;
Glenn L McGrathdc4e75e2003-09-02 02:36:18 +00003097 execve(DEFAULT_SHELL, v, envp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003098 *v = tp;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003099 return "no Shell";
Eric Andersenff9eee42001-06-29 04:57:14 +00003100
3101 case ENOMEM:
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003102 return (char *) bb_msg_memory_exhausted;
Eric Andersenff9eee42001-06-29 04:57:14 +00003103
3104 case E2BIG:
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003105 return "argument list too long";
Eric Andersenff9eee42001-06-29 04:57:14 +00003106
3107 case EACCES:
3108 eacces++;
3109 break;
3110 }
3111 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003112 return errno == ENOENT ? "not found" : "cannot execute";
Eric Andersenff9eee42001-06-29 04:57:14 +00003113}
3114
3115/*
3116 * Run the command produced by generator `f'
3117 * applied to stream `arg'.
3118 */
Eric Andersen8401eea2004-08-04 19:16:54 +00003119static int run(struct ioarg *argp, int (*f) (struct ioarg *))
Eric Andersenff9eee42001-06-29 04:57:14 +00003120{
3121 struct op *otree;
3122 struct wdblock *swdlist;
3123 struct wdblock *siolist;
3124 jmp_buf ev, rt;
3125 xint *ofail;
3126 int rv;
3127
3128#if __GNUC__
3129 /* Avoid longjmp clobbering */
3130 (void) &rv;
3131#endif
3132
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003133 DBGPRINTF(("RUN: enter, areanum %d, outtree %p, failpt %p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00003134 areanum, outtree, failpt));
3135
Eric Andersenff9eee42001-06-29 04:57:14 +00003136 areanum++;
3137 swdlist = wdlist;
3138 siolist = iolist;
3139 otree = outtree;
3140 ofail = failpt;
3141 rv = -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003142
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003143 errpt = ev;
3144 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003145 wdlist = 0;
3146 iolist = 0;
3147 pushio(argp, f);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003148 global_env.iobase = global_env.iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00003149 yynerrs = 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003150 failpt = rt;
3151 if (setjmp(failpt) == 0 && yyparse() == 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00003152 rv = execute(outtree, NOPIPE, NOPIPE, 0);
3153 quitenv();
Eric Andersen12de6cf2004-08-04 19:19:10 +00003154 } else {
3155 DBGPRINTF(("RUN: error from newenv()!\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00003156 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00003157
Eric Andersenff9eee42001-06-29 04:57:14 +00003158 wdlist = swdlist;
3159 iolist = siolist;
3160 failpt = ofail;
3161 outtree = otree;
3162 freearea(areanum--);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003163
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003164 return rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003165}
3166
3167/* -------- do.c -------- */
3168
3169/*
3170 * built-in commands: doX
3171 */
3172
Eric Andersen8401eea2004-08-04 19:16:54 +00003173static int dohelp(struct op *t)
Eric Andersen1c039232001-07-07 00:05:55 +00003174{
3175 int col;
3176 const struct builtincmd *x;
3177
Denis Vlasenko0ee39992006-12-24 15:23:28 +00003178 puts("\nBuilt-in commands:\n"
3179 "-------------------");
Eric Andersen1c039232001-07-07 00:05:55 +00003180
Denis Vlasenko95cb3262007-04-09 03:06:34 +00003181 col = 0;
3182 x = builtincmds;
3183 while (x->name) {
3184 col += printf("%c%s", ((col == 0) ? '\t' : ' '), x->name);
Eric Andersen1c039232001-07-07 00:05:55 +00003185 if (col > 60) {
Denis Vlasenko4daad902007-09-27 10:20:47 +00003186 bb_putchar('\n');
Eric Andersen1c039232001-07-07 00:05:55 +00003187 col = 0;
3188 }
Denis Vlasenko95cb3262007-04-09 03:06:34 +00003189 x++;
Eric Andersen1c039232001-07-07 00:05:55 +00003190 }
Denis Vlasenko80d14be2007-04-10 23:03:30 +00003191#if ENABLE_FEATURE_SH_STANDALONE
Eric Andersen1c039232001-07-07 00:05:55 +00003192 {
Denis Vlasenko1aa7e472007-11-28 06:49:03 +00003193 const char *applet = applet_names;
Eric Andersen1c039232001-07-07 00:05:55 +00003194
Denis Vlasenko1aa7e472007-11-28 06:49:03 +00003195 while (*applet) {
3196 col += printf("%c%s", ((col == 0) ? '\t' : ' '), applet);
Eric Andersen1c039232001-07-07 00:05:55 +00003197 if (col > 60) {
Denis Vlasenko4daad902007-09-27 10:20:47 +00003198 bb_putchar('\n');
Eric Andersen1c039232001-07-07 00:05:55 +00003199 col = 0;
3200 }
Denis Vlasenko1aa7e472007-11-28 06:49:03 +00003201 applet += strlen(applet) + 1;
Eric Andersen1c039232001-07-07 00:05:55 +00003202 }
3203 }
3204#endif
Denis Vlasenko0ee39992006-12-24 15:23:28 +00003205 puts("\n");
Eric Andersen1c039232001-07-07 00:05:55 +00003206 return EXIT_SUCCESS;
3207}
3208
Eric Andersen8401eea2004-08-04 19:16:54 +00003209static int dolabel(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003210{
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003211 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003212}
3213
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003214static int dochdir(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003215{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003216 const char *cp, *er;
Eric Andersenff9eee42001-06-29 04:57:14 +00003217
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003218 cp = t->words[1];
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003219 if (cp == NULL) {
3220 cp = homedir->value;
Denis Vlasenkod244c5e2007-02-09 17:30:14 +00003221 if (cp != NULL)
3222 goto do_cd;
3223 er = ": no home directory";
3224 } else {
3225 do_cd:
3226 if (chdir(cp) >= 0)
3227 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003228 er = ": bad directory";
Denis Vlasenkod244c5e2007-02-09 17:30:14 +00003229 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003230 prs(cp != NULL ? cp : "cd");
Eric Andersenff9eee42001-06-29 04:57:14 +00003231 err(er);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003232 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003233}
3234
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003235static int doshift(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003236{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003237 int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003238
Eric Andersen8401eea2004-08-04 19:16:54 +00003239 n = t->words[1] ? getn(t->words[1]) : 1;
3240 if (dolc < n) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003241 err("nothing to shift");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003242 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003243 }
3244 dolv[n] = dolv[0];
3245 dolv += n;
3246 dolc -= n;
3247 setval(lookup("#"), putn(dolc));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003248 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003249}
3250
3251/*
3252 * execute login and newgrp directly
3253 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003254static int dologin(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003255{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003256 const char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003257
3258 if (interactive) {
3259 signal(SIGINT, SIG_DFL);
3260 signal(SIGQUIT, SIG_DFL);
3261 }
Eric Andersenfd7a4c82004-09-02 23:13:10 +00003262 cp = rexecve(t->words[0], t->words, makenv(0, NULL));
Eric Andersen8401eea2004-08-04 19:16:54 +00003263 prs(t->words[0]);
3264 prs(": ");
3265 err(cp);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003266 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003267}
3268
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003269static int doumask(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003270{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003271 int i, n;
3272 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003273
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003274 cp = t->words[1];
3275 if (cp == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003276 i = umask(0);
3277 umask(i);
Eric Andersen8401eea2004-08-04 19:16:54 +00003278 for (n = 3 * 4; (n -= 3) >= 0;)
Denis Vlasenko4daad902007-09-27 10:20:47 +00003279 fputc('0' + ((i >> n) & 07), stderr);
3280 fputc('\n', stderr);
Eric Andersenff9eee42001-06-29 04:57:14 +00003281 } else {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003282/* huh??? '8','9' are not allowed! */
Eric Andersen8401eea2004-08-04 19:16:54 +00003283 for (n = 0; *cp >= '0' && *cp <= '9'; cp++)
3284 n = n * 8 + (*cp - '0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003285 umask(n);
3286 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003287 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003288}
3289
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003290static int doexec(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003291{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003292 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00003293 jmp_buf ex;
3294 xint *ofail;
3295
3296 t->ioact = NULL;
Eric Andersen8401eea2004-08-04 19:16:54 +00003297 for (i = 0; (t->words[i] = t->words[i + 1]) != NULL; i++);
Eric Andersenff9eee42001-06-29 04:57:14 +00003298 if (i == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003299 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003300 execflg = 1;
3301 ofail = failpt;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003302 failpt = ex;
3303 if (setjmp(failpt) == 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00003304 execute(t, NOPIPE, NOPIPE, FEXEC);
3305 failpt = ofail;
3306 execflg = 0;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003307 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003308}
3309
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003310static int dodot(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003311{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003312 int i;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003313 const char *sp;
3314 char *tp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003315 char *cp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003316 int maltmp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003317
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003318 DBGPRINTF(("DODOT: enter, t=%p, tleft %p, tright %p, global_env.linep is %s\n",
3319 t, t->left, t->right, ((global_env.linep == NULL) ? "NULL" : global_env.linep)));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003320
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003321 cp = t->words[1];
3322 if (cp == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00003323 DBGPRINTF(("DODOT: bad args, ret 0\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003324 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003325 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003326 DBGPRINTF(("DODOT: cp is %s\n", cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003327
Eric Andersen8401eea2004-08-04 19:16:54 +00003328 sp = any('/', cp) ? ":" : path->value;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003329
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003330 DBGPRINTF(("DODOT: sp is %s, global_env.linep is %s\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00003331 ((sp == NULL) ? "NULL" : sp),
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003332 ((global_env.linep == NULL) ? "NULL" : global_env.linep)));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003333
Eric Andersenff9eee42001-06-29 04:57:14 +00003334 while (*sp) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003335 tp = global_env.linep;
Eric Andersenff9eee42001-06-29 04:57:14 +00003336 while (*sp && (*tp = *sp++) != ':')
3337 tp++;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003338 if (tp != global_env.linep)
Eric Andersenff9eee42001-06-29 04:57:14 +00003339 *tp++ = '/';
Eric Andersen12de6cf2004-08-04 19:19:10 +00003340
Eric Andersen8401eea2004-08-04 19:16:54 +00003341 for (i = 0; (*tp++ = cp[i++]) != '\0';);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003342
3343 /* Original code */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003344 i = open(global_env.linep, O_RDONLY);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003345 if (i >= 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003346 exstat = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003347 maltmp = remap(i);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003348 DBGPRINTF(("DODOT: remap=%d, exstat=%d, global_env.iofd %d, i %d, global_env.linep is %s\n",
3349 maltmp, exstat, global_env.iofd, i, global_env.linep));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003350
3351 next(maltmp); /* Basically a PUSHIO */
3352
3353 DBGPRINTF(("DODOT: returning exstat=%d\n", exstat));
3354
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003355 return exstat;
Eric Andersenff9eee42001-06-29 04:57:14 +00003356 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003357 } /* while */
Eric Andersen12de6cf2004-08-04 19:19:10 +00003358
Eric Andersenff9eee42001-06-29 04:57:14 +00003359 prs(cp);
3360 err(": not found");
Eric Andersen12de6cf2004-08-04 19:19:10 +00003361
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003362 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003363}
3364
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003365static int dowait(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003366{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003367 int i;
3368 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003369
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003370 cp = t->words[1];
3371 if (cp != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003372 i = getn(cp);
3373 if (i == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003374 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003375 } else
3376 i = -1;
3377 setstatus(waitfor(i, 1));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003378 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003379}
3380
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003381static int doread(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003382{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003383 char *cp, **wp;
3384 int nb = 0;
3385 int nl = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003386
3387 if (t->words[1] == NULL) {
3388 err("Usage: read name ...");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003389 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003390 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003391 for (wp = t->words + 1; *wp; wp++) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003392 for (cp = global_env.linep; !nl && cp < elinep - 1; cp++) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003393 nb = read(0, cp, sizeof(*cp));
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003394 if (nb != sizeof(*cp))
Eric Andersenff9eee42001-06-29 04:57:14 +00003395 break;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003396 nl = (*cp == '\n');
3397 if (nl || (wp[1] && any(*cp, ifs->value)))
3398 break;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003399 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003400 *cp = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00003401 if (nb <= 0)
3402 break;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003403 setval(lookup(*wp), global_env.linep);
Eric Andersenff9eee42001-06-29 04:57:14 +00003404 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003405 return nb <= 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003406}
3407
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003408static int doeval(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003409{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003410 return RUN(awordlist, t->words + 1, wdchar);
Eric Andersenff9eee42001-06-29 04:57:14 +00003411}
3412
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003413static int dotrap(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003414{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003415 int n, i;
3416 int resetsig;
Eric Andersenff9eee42001-06-29 04:57:14 +00003417
3418 if (t->words[1] == NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00003419 for (i = 0; i <= _NSIG; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00003420 if (trap[i]) {
3421 prn(i);
3422 prs(": ");
3423 prs(trap[i]);
3424 prs("\n");
3425 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003426 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003427 }
3428 resetsig = isdigit(*t->words[1]);
3429 for (i = resetsig ? 1 : 2; t->words[i] != NULL; ++i) {
3430 n = getsig(t->words[i]);
3431 freecell(trap[n]);
3432 trap[n] = 0;
3433 if (!resetsig) {
3434 if (*t->words[1] != '\0') {
3435 trap[n] = strsave(t->words[1], 0);
3436 setsig(n, sig);
3437 } else
3438 setsig(n, SIG_IGN);
3439 } else {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00003440 if (interactive) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003441 if (n == SIGINT)
3442 setsig(n, onintr);
3443 else
Eric Andersen8401eea2004-08-04 19:16:54 +00003444 setsig(n, n == SIGQUIT ? SIG_IGN : SIG_DFL);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00003445 } else
Eric Andersenff9eee42001-06-29 04:57:14 +00003446 setsig(n, SIG_DFL);
3447 }
3448 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003449 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003450}
3451
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003452static int getsig(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003453{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003454 int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003455
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003456 n = getn(s);
3457 if (n < 0 || n > _NSIG) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003458 err("trap: bad signal number");
3459 n = 0;
3460 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003461 return n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003462}
3463
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003464static void setsig(int n, sighandler_t f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003465{
3466 if (n == 0)
3467 return;
3468 if (signal(n, SIG_IGN) != SIG_IGN || ourtrap[n]) {
3469 ourtrap[n] = 1;
3470 signal(n, f);
3471 }
3472}
3473
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003474static int getn(char *as)
Eric Andersenff9eee42001-06-29 04:57:14 +00003475{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003476 char *s;
3477 int n, m;
Eric Andersenff9eee42001-06-29 04:57:14 +00003478
3479 s = as;
3480 m = 1;
3481 if (*s == '-') {
3482 m = -1;
3483 s++;
3484 }
3485 for (n = 0; isdigit(*s); s++)
Eric Andersen8401eea2004-08-04 19:16:54 +00003486 n = (n * 10) + (*s - '0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003487 if (*s) {
3488 prs(as);
3489 err(": bad number");
3490 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003491 return n * m;
Eric Andersenff9eee42001-06-29 04:57:14 +00003492}
3493
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003494static int dobreak(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003495{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003496 return brkcontin(t->words[1], 1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003497}
3498
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003499static int docontinue(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003500{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003501 return brkcontin(t->words[1], 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003502}
3503
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003504static int brkcontin(char *cp, int val)
Eric Andersenff9eee42001-06-29 04:57:14 +00003505{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003506 struct brkcon *bc;
3507 int nl;
Eric Andersenff9eee42001-06-29 04:57:14 +00003508
Eric Andersen8401eea2004-08-04 19:16:54 +00003509 nl = cp == NULL ? 1 : getn(cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003510 if (nl <= 0)
3511 nl = 999;
3512 do {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003513 bc = brklist;
3514 if (bc == NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00003515 break;
3516 brklist = bc->nextlev;
3517 } while (--nl);
3518 if (nl) {
3519 err("bad break/continue level");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003520 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003521 }
3522 isbreak = val;
3523 longjmp(bc->brkpt, 1);
3524 /* NOTREACHED */
3525}
3526
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003527static int doexit(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003528{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003529 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003530
3531 execflg = 0;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003532 cp = t->words[1];
3533 if (cp != NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00003534 setstatus(getn(cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003535
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003536 DBGPRINTF(("DOEXIT: calling leave(), t=%p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003537
Eric Andersenff9eee42001-06-29 04:57:14 +00003538 leave();
3539 /* NOTREACHED */
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003540 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003541}
3542
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003543static int doexport(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003544{
Eric Andersen8401eea2004-08-04 19:16:54 +00003545 rdexp(t->words + 1, export, EXPORT);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003546 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003547}
3548
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003549static int doreadonly(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003550{
Eric Andersen8401eea2004-08-04 19:16:54 +00003551 rdexp(t->words + 1, ronly, RONLY);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003552 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003553}
3554
Eric Andersen8401eea2004-08-04 19:16:54 +00003555static void rdexp(char **wp, void (*f) (struct var *), int key)
Eric Andersenff9eee42001-06-29 04:57:14 +00003556{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003557 DBGPRINTF6(("RDEXP: enter, wp=%p, func=%p, key=%d\n", wp, f, key));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003558 DBGPRINTF6(("RDEXP: *wp=%s\n", *wp));
3559
Eric Andersenff9eee42001-06-29 04:57:14 +00003560 if (*wp != NULL) {
Matt Kraaif69bfc72001-07-12 19:39:59 +00003561 for (; *wp != NULL; wp++) {
3562 if (isassign(*wp)) {
3563 char *cp;
Eric Andersen8401eea2004-08-04 19:16:54 +00003564
Matt Kraaif69bfc72001-07-12 19:39:59 +00003565 assign(*wp, COPYV);
Eric Andersen8401eea2004-08-04 19:16:54 +00003566 for (cp = *wp; *cp != '='; cp++);
Matt Kraaif69bfc72001-07-12 19:39:59 +00003567 *cp = '\0';
3568 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003569 if (checkname(*wp))
Eric Andersen8401eea2004-08-04 19:16:54 +00003570 (*f) (lookup(*wp));
Eric Andersenff9eee42001-06-29 04:57:14 +00003571 else
3572 badid(*wp);
Matt Kraaif69bfc72001-07-12 19:39:59 +00003573 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003574 } else
3575 putvlist(key, 1);
3576}
3577
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003578static void badid(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003579{
3580 prs(s);
3581 err(": bad identifier");
3582}
3583
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003584static int doset(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003585{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003586 struct var *vp;
3587 char *cp;
3588 int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003589
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003590 cp = t->words[1];
3591 if (cp == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003592 for (vp = vlist; vp; vp = vp->next)
3593 varput(vp->name, 1);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003594 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003595 }
3596 if (*cp == '-') {
3597 /* bad: t->words++; */
Eric Andersen8401eea2004-08-04 19:16:54 +00003598 for (n = 0; (t->words[n] = t->words[n + 1]) != NULL; n++);
Eric Andersenff9eee42001-06-29 04:57:14 +00003599 if (*++cp == 0)
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003600 FLAG['x'] = FLAG['v'] = 0;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003601 else {
3602 for (; *cp; cp++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003603 switch (*cp) {
3604 case 'e':
3605 if (!interactive)
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003606 FLAG['e']++;
Eric Andersenff9eee42001-06-29 04:57:14 +00003607 break;
3608
3609 default:
Eric Andersen8401eea2004-08-04 19:16:54 +00003610 if (*cp >= 'a' && *cp <= 'z')
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003611 FLAG[(int) *cp]++;
Eric Andersenff9eee42001-06-29 04:57:14 +00003612 break;
3613 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003614 }
3615 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003616 setdash();
3617 }
3618 if (t->words[1]) {
3619 t->words[0] = dolv[0];
Eric Andersen8401eea2004-08-04 19:16:54 +00003620 for (n = 1; t->words[n]; n++)
3621 setarea((char *) t->words[n], 0);
3622 dolc = n - 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003623 dolv = t->words;
3624 setval(lookup("#"), putn(dolc));
Eric Andersen8401eea2004-08-04 19:16:54 +00003625 setarea((char *) (dolv - 1), 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003626 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003627 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003628}
3629
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003630static void varput(char *s, int out)
Eric Andersenff9eee42001-06-29 04:57:14 +00003631{
Matt Kraai69edfec2001-08-06 14:14:18 +00003632 if (isalnum(*s) || *s == '_') {
Eric Andersenff9eee42001-06-29 04:57:14 +00003633 write(out, s, strlen(s));
3634 write(out, "\n", 1);
3635 }
3636}
3637
3638
3639/*
3640 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
3641 * This file contains code for the times builtin.
Eric Andersenff9eee42001-06-29 04:57:14 +00003642 */
Eric Andersen8401eea2004-08-04 19:16:54 +00003643static int dotimes(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003644{
3645 struct tms buf;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003646 long clk_tck = sysconf(_SC_CLK_TCK);
Eric Andersenff9eee42001-06-29 04:57:14 +00003647
3648 times(&buf);
3649 printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
Eric Andersen8401eea2004-08-04 19:16:54 +00003650 (int) (buf.tms_utime / clk_tck / 60),
3651 ((double) buf.tms_utime) / clk_tck,
3652 (int) (buf.tms_stime / clk_tck / 60),
3653 ((double) buf.tms_stime) / clk_tck,
3654 (int) (buf.tms_cutime / clk_tck / 60),
3655 ((double) buf.tms_cutime) / clk_tck,
3656 (int) (buf.tms_cstime / clk_tck / 60),
3657 ((double) buf.tms_cstime) / clk_tck);
Eric Andersenff9eee42001-06-29 04:57:14 +00003658 return 0;
3659}
3660
3661
Eric Andersenff9eee42001-06-29 04:57:14 +00003662/* -------- eval.c -------- */
3663
3664/*
3665 * ${}
3666 * `command`
3667 * blank interpretation
3668 * quoting
3669 * glob
3670 */
3671
Eric Andersen8401eea2004-08-04 19:16:54 +00003672static char **eval(char **ap, int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003673{
3674 struct wdblock *wb;
3675 char **wp;
3676 char **wf;
3677 jmp_buf ev;
3678
3679#if __GNUC__
3680 /* Avoid longjmp clobbering */
3681 (void) &wp;
3682 (void) &ap;
3683#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00003684
3685 DBGPRINTF4(("EVAL: enter, f=%d\n", f));
3686
Eric Andersenff9eee42001-06-29 04:57:14 +00003687 wp = NULL;
3688 wb = NULL;
3689 wf = NULL;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003690 errpt = ev;
3691 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003692 while (*ap && isassign(*ap))
3693 expand(*ap++, &wb, f & ~DOGLOB);
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003694 if (FLAG['k']) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003695 for (wf = ap; *wf; wf++) {
3696 if (isassign(*wf))
3697 expand(*wf, &wb, f & ~DOGLOB);
3698 }
3699 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003700 for (wb = addword((char *) 0, wb); *ap; ap++) {
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003701 if (!FLAG['k'] || !isassign(*ap))
Eric Andersenff9eee42001-06-29 04:57:14 +00003702 expand(*ap, &wb, f & ~DOKEY);
3703 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003704 wb = addword((char *) 0, wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00003705 wp = getwords(wb);
3706 quitenv();
3707 } else
3708 gflg = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003709
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003710 return gflg ? (char **) NULL : wp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003711}
3712
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003713
Eric Andersenff9eee42001-06-29 04:57:14 +00003714/*
3715 * Make the exported environment from the exported
3716 * names in the dictionary. Keyword assignments
3717 * will already have been done.
3718 */
Eric Andersenfd7a4c82004-09-02 23:13:10 +00003719static char **makenv(int all, struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00003720{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003721 struct var *vp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003722
3723 DBGPRINTF5(("MAKENV: enter, all=%d\n", all));
Eric Andersenff9eee42001-06-29 04:57:14 +00003724
Eric Andersenff9eee42001-06-29 04:57:14 +00003725 for (vp = vlist; vp; vp = vp->next)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003726 if (all || vp->status & EXPORT)
Eric Andersenff9eee42001-06-29 04:57:14 +00003727 wb = addword(vp->name, wb);
Eric Andersen8401eea2004-08-04 19:16:54 +00003728 wb = addword((char *) 0, wb);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003729 return getwords(wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00003730}
3731
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003732static int expand(const char *cp, struct wdblock **wbp, int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003733{
3734 jmp_buf ev;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003735 char *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003736
3737#if __GNUC__
3738 /* Avoid longjmp clobbering */
3739 (void) &cp;
3740#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00003741
3742 DBGPRINTF3(("EXPAND: enter, f=%d\n", f));
3743
Eric Andersenff9eee42001-06-29 04:57:14 +00003744 gflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003745
Eric Andersenff9eee42001-06-29 04:57:14 +00003746 if (cp == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003747 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003748
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003749 if (!anys("$`'\"", cp) && !anys(ifs->value, cp)
3750 && ((f & DOGLOB) == 0 || !anys("[*?", cp))
3751 ) {
3752 xp = strsave(cp, areanum);
Eric Andersenff9eee42001-06-29 04:57:14 +00003753 if (f & DOTRIM)
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003754 unquote(xp);
3755 *wbp = addword(xp, *wbp);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003756 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003757 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003758 errpt = ev;
3759 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003760 PUSHIO(aword, cp, strchar);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003761 global_env.iobase = global_env.iop;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003762 while ((xp = blank(f)) && gflg == 0) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003763 global_env.linep = xp;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003764 xp = strsave(xp, areanum);
Eric Andersen8401eea2004-08-04 19:16:54 +00003765 if ((f & DOGLOB) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003766 if (f & DOTRIM)
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003767 unquote(xp);
3768 *wbp = addword(xp, *wbp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003769 } else
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003770 *wbp = glob(xp, *wbp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003771 }
3772 quitenv();
3773 } else
3774 gflg = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003775 return gflg == 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003776}
3777
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003778static char *evalstr(char *cp, int f)
3779{
3780 struct wdblock *wb;
3781
3782 DBGPRINTF6(("EVALSTR: enter, cp=%p, f=%d\n", cp, f));
3783
3784 wb = NULL;
3785 if (expand(cp, &wb, f)) {
3786 if (wb == NULL || wb->w_nword == 0
3787 || (cp = wb->w_words[0]) == NULL
3788 ) {
Denis Vlasenko8e858e22007-03-07 09:35:43 +00003789// TODO: I suspect that
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003790// char *evalstr(char *cp, int f) is actually
3791// const char *evalstr(const char *cp, int f)!
3792 cp = (char*)"";
3793 }
3794 DELETE(wb);
3795 } else
3796 cp = NULL;
3797 return cp;
3798}
3799
3800
Eric Andersenff9eee42001-06-29 04:57:14 +00003801/*
3802 * Blank interpretation and quoting
3803 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003804static char *blank(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003805{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003806 int c, c1;
3807 char *sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003808 int scanequals, foundequals;
3809
Eric Andersen12de6cf2004-08-04 19:19:10 +00003810 DBGPRINTF3(("BLANK: enter, f=%d\n", f));
3811
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003812 sp = global_env.linep;
Eric Andersenff9eee42001-06-29 04:57:14 +00003813 scanequals = f & DOKEY;
3814 foundequals = 0;
3815
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003816 loop:
3817 c = subgetc('"', foundequals);
3818 switch (c) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003819 case 0:
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003820 if (sp == global_env.linep)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003821 return 0;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003822 *global_env.linep++ = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003823 return sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003824
3825 default:
3826 if (f & DOBLANK && any(c, ifs->value))
3827 goto loop;
3828 break;
3829
3830 case '"':
3831 case '\'':
3832 scanequals = 0;
3833 if (INSUB())
3834 break;
3835 for (c1 = c; (c = subgetc(c1, 1)) != c1;) {
3836 if (c == 0)
3837 break;
3838 if (c == '\'' || !any(c, "$`\""))
3839 c |= QUOTE;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003840 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003841 }
3842 c = 0;
3843 }
3844 unget(c);
Matt Kraai69edfec2001-08-06 14:14:18 +00003845 if (!isalpha(c) && c != '_')
Eric Andersenff9eee42001-06-29 04:57:14 +00003846 scanequals = 0;
3847 for (;;) {
3848 c = subgetc('"', foundequals);
3849 if (c == 0 ||
Eric Andersen8401eea2004-08-04 19:16:54 +00003850 f & (DOBLANK && any(c, ifs->value)) ||
3851 (!INSUB() && any(c, "\"'"))) {
3852 scanequals = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003853 unget(c);
3854 if (any(c, "\"'"))
3855 goto loop;
3856 break;
3857 }
3858 if (scanequals) {
3859 if (c == '=') {
3860 foundequals = 1;
Eric Andersen8401eea2004-08-04 19:16:54 +00003861 scanequals = 0;
3862 } else if (!isalnum(c) && c != '_')
Eric Andersenff9eee42001-06-29 04:57:14 +00003863 scanequals = 0;
3864 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003865 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003866 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003867 *global_env.linep++ = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003868 return sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003869}
3870
3871/*
3872 * Get characters, substituting for ` and $
3873 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003874static int subgetc(char ec, int quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00003875{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003876 char c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003877
3878 DBGPRINTF3(("SUBGETC: enter, quoted=%d\n", quoted));
Eric Andersenff9eee42001-06-29 04:57:14 +00003879
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003880 again:
Eric Andersenff9eee42001-06-29 04:57:14 +00003881 c = my_getc(ec);
3882 if (!INSUB() && ec != '\'') {
3883 if (c == '`') {
3884 if (grave(quoted) == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003885 return 0;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003886 global_env.iop->task = XGRAVE;
Eric Andersenff9eee42001-06-29 04:57:14 +00003887 goto again;
3888 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003889 if (c == '$') {
3890 c = dollar(quoted);
3891 if (c == 0) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003892 global_env.iop->task = XDOLL;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003893 goto again;
3894 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003895 }
3896 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003897 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003898}
3899
3900/*
3901 * Prepare to generate the string returned by ${} substitution.
3902 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003903static int dollar(int quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00003904{
3905 int otask;
3906 struct io *oiop;
3907 char *dolp;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003908 char *s, c, *cp = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00003909 struct var *vp;
3910
Eric Andersen12de6cf2004-08-04 19:19:10 +00003911 DBGPRINTF3(("DOLLAR: enter, quoted=%d\n", quoted));
3912
Eric Andersenff9eee42001-06-29 04:57:14 +00003913 c = readc();
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003914 s = global_env.linep;
Eric Andersenff9eee42001-06-29 04:57:14 +00003915 if (c != '{') {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003916 *global_env.linep++ = c;
Matt Kraai69edfec2001-08-06 14:14:18 +00003917 if (isalpha(c) || c == '_') {
Eric Andersen8401eea2004-08-04 19:16:54 +00003918 while ((c = readc()) != 0 && (isalnum(c) || c == '_'))
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003919 if (global_env.linep < elinep)
3920 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003921 unget(c);
3922 }
3923 c = 0;
3924 } else {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003925 oiop = global_env.iop;
3926 otask = global_env.iop->task;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003927
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003928 global_env.iop->task = XOTHER;
Eric Andersen8401eea2004-08-04 19:16:54 +00003929 while ((c = subgetc('"', 0)) != 0 && c != '}' && c != '\n')
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003930 if (global_env.linep < elinep)
3931 *global_env.linep++ = c;
3932 if (oiop == global_env.iop)
3933 global_env.iop->task = otask;
Eric Andersenff9eee42001-06-29 04:57:14 +00003934 if (c != '}') {
3935 err("unclosed ${");
3936 gflg++;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003937 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003938 }
3939 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003940 if (global_env.linep >= elinep) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003941 err("string in ${} too long");
3942 gflg++;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003943 global_env.linep -= 10;
Eric Andersenff9eee42001-06-29 04:57:14 +00003944 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003945 *global_env.linep = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003946 if (*s)
Eric Andersen8401eea2004-08-04 19:16:54 +00003947 for (cp = s + 1; *cp; cp++)
Eric Andersenff9eee42001-06-29 04:57:14 +00003948 if (any(*cp, "=-+?")) {
3949 c = *cp;
3950 *cp++ = 0;
3951 break;
3952 }
3953 if (s[1] == 0 && (*s == '*' || *s == '@')) {
3954 if (dolc > 1) {
3955 /* currently this does not distinguish $* and $@ */
3956 /* should check dollar */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003957 global_env.linep = s;
Eric Andersen8401eea2004-08-04 19:16:54 +00003958 PUSHIO(awordlist, dolv + 1, dolchar);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003959 return 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00003960 } else { /* trap the nasty ${=} */
Eric Andersenff9eee42001-06-29 04:57:14 +00003961 s[0] = '1';
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003962 s[1] = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00003963 }
3964 }
3965 vp = lookup(s);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003966 dolp = vp->value;
3967 if (dolp == null) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003968 switch (c) {
3969 case '=':
3970 if (isdigit(*s)) {
3971 err("cannot use ${...=...} with $n");
3972 gflg++;
3973 break;
3974 }
3975 setval(vp, cp);
3976 dolp = vp->value;
3977 break;
3978
3979 case '-':
3980 dolp = strsave(cp, areanum);
3981 break;
3982
3983 case '?':
3984 if (*cp == 0) {
3985 prs("missing value for ");
3986 err(s);
3987 } else
3988 err(cp);
3989 gflg++;
3990 break;
3991 }
3992 } else if (c == '+')
3993 dolp = strsave(cp, areanum);
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003994 if (FLAG['u'] && dolp == null) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003995 prs("unset variable: ");
3996 err(s);
3997 gflg++;
3998 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003999 global_env.linep = s;
Eric Andersenff9eee42001-06-29 04:57:14 +00004000 PUSHIO(aword, dolp, quoted ? qstrchar : strchar);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004001 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004002}
4003
4004/*
4005 * Run the command in `...` and read its output.
4006 */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004007
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004008static int grave(int quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00004009{
Denis Vlasenko55f30b02007-03-24 22:42:29 +00004010 /* moved to G: static char child_cmd[LINELIM]; */
4011
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004012 const char *cp;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004013 int i;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004014 int j;
Eric Andersenff9eee42001-06-29 04:57:14 +00004015 int pf[2];
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004016 const char *src;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004017 char *dest;
4018 int count;
4019 int ignore;
4020 int ignore_once;
4021 char *argument_list[4];
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004022 struct wdblock *wb = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004023
4024#if __GNUC__
4025 /* Avoid longjmp clobbering */
4026 (void) &cp;
4027#endif
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004028
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004029 for (cp = global_env.iop->argp->aword; *cp != '`'; cp++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004030 if (*cp == 0) {
4031 err("no closing `");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004032 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004033 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004034 }
Eric Andersen737f5fb2003-03-14 16:05:59 +00004035
4036 /* string copy with dollar expansion */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004037 src = global_env.iop->argp->aword;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004038 dest = child_cmd;
4039 count = 0;
4040 ignore = 0;
4041 ignore_once = 0;
4042 while ((*src != '`') && (count < LINELIM)) {
4043 if (*src == '\'')
4044 ignore = !ignore;
4045 if (*src == '\\')
4046 ignore_once = 1;
4047 if (*src == '$' && !ignore && !ignore_once) {
4048 struct var *vp;
Denis Vlasenkoab801872007-12-02 08:35:37 +00004049 /* moved to G to reduce stack usage
Eric Andersen737f5fb2003-03-14 16:05:59 +00004050 char var_name[LINELIM];
4051 char alt_value[LINELIM];
Denis Vlasenkoab801872007-12-02 08:35:37 +00004052 */
4053#define var_name (G.grave__var_name)
4054#define alt_value (G.grave__alt_value)
Eric Andersen737f5fb2003-03-14 16:05:59 +00004055 int var_index = 0;
4056 int alt_index = 0;
4057 char operator = 0;
4058 int braces = 0;
4059 char *value;
4060
4061 src++;
4062 if (*src == '{') {
4063 braces = 1;
4064 src++;
4065 }
4066
4067 var_name[var_index++] = *src++;
Paul Fox54690dc2005-07-20 18:33:12 +00004068 while (isalnum(*src) || *src=='_')
Eric Andersen737f5fb2003-03-14 16:05:59 +00004069 var_name[var_index++] = *src++;
4070 var_name[var_index] = 0;
4071
4072 if (braces) {
4073 switch (*src) {
4074 case '}':
4075 break;
4076 case '-':
4077 case '=':
4078 case '+':
4079 case '?':
Eric Andersen8401eea2004-08-04 19:16:54 +00004080 operator = * src;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004081 break;
4082 default:
4083 err("unclosed ${\n");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004084 return 0;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004085 }
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004086 if (operator) {
Eric Andersen737f5fb2003-03-14 16:05:59 +00004087 src++;
4088 while (*src && (*src != '}')) {
4089 alt_value[alt_index++] = *src++;
4090 }
4091 alt_value[alt_index] = 0;
4092 if (*src != '}') {
4093 err("unclosed ${\n");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004094 return 0;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004095 }
4096 }
4097 src++;
4098 }
4099
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004100 if (isalpha(*var_name)) {
4101 /* let subshell handle it instead */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004102
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004103 char *namep = var_name;
4104
4105 *dest++ = '$';
4106 if (braces)
4107 *dest++ = '{';
4108 while (*namep)
4109 *dest++ = *namep++;
4110 if (operator) {
4111 char *altp = alt_value;
4112 *dest++ = operator;
4113 while (*altp)
4114 *dest++ = *altp++;
4115 }
4116 if (braces)
4117 *dest++ = '}';
4118
4119 wb = addword(lookup(var_name)->name, wb);
4120 } else {
4121 /* expand */
4122
4123 vp = lookup(var_name);
4124 if (vp->value != null)
4125 value = (operator == '+') ?
4126 alt_value : vp->value;
4127 else if (operator == '?') {
4128 err(alt_value);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004129 return 0;
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004130 } else if (alt_index && (operator != '+')) {
4131 value = alt_value;
4132 if (operator == '=')
4133 setval(vp, value);
4134 } else
4135 continue;
4136
4137 while (*value && (count < LINELIM)) {
4138 *dest++ = *value++;
4139 count++;
4140 }
Eric Andersen737f5fb2003-03-14 16:05:59 +00004141 }
Denis Vlasenkoab801872007-12-02 08:35:37 +00004142#undef var_name
4143#undef alt_value
Eric Andersen737f5fb2003-03-14 16:05:59 +00004144 } else {
4145 *dest++ = *src++;
4146 count++;
4147 ignore_once = 0;
4148 }
4149 }
4150 *dest = '\0';
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004151
Eric Andersenff9eee42001-06-29 04:57:14 +00004152 if (openpipe(pf) < 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004153 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004154
Eric Andersen8401eea2004-08-04 19:16:54 +00004155 while ((i = vfork()) == -1 && errno == EAGAIN);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004156
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004157 DBGPRINTF3(("GRAVE: i is %p\n", io));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004158
Eric Andersen737f5fb2003-03-14 16:05:59 +00004159 if (i < 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004160 closepipe(pf);
Eric Andersen8401eea2004-08-04 19:16:54 +00004161 err((char *) bb_msg_memory_exhausted);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004162 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004163 }
4164 if (i != 0) {
Eric Andersen737f5fb2003-03-14 16:05:59 +00004165 waitpid(i, NULL, 0);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004166 global_env.iop->argp->aword = ++cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004167 close(pf[1]);
Eric Andersen8401eea2004-08-04 19:16:54 +00004168 PUSHIO(afile, remap(pf[0]),
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004169 (int (*)(struct ioarg *)) ((quoted) ? qgravechar : gravechar));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004170 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004171 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004172 /* allow trapped signals */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004173 /* XXX - Maybe this signal stuff should go as well? */
Eric Andersen8401eea2004-08-04 19:16:54 +00004174 for (j = 0; j <= _NSIG; j++)
Eric Andersen737f5fb2003-03-14 16:05:59 +00004175 if (ourtrap[j] && signal(j, SIG_IGN) != SIG_IGN)
4176 signal(j, SIG_DFL);
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004177
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00004178 /* Testcase where below checks are needed:
4179 * close stdout & run this script:
4180 * files=`ls`
4181 * echo "$files" >zz
4182 */
4183 xmove_fd(pf[1], 1);
4184 if (pf[0] != 1) close(pf[0]);
Eric Andersen737f5fb2003-03-14 16:05:59 +00004185
Eric Andersen8401eea2004-08-04 19:16:54 +00004186 argument_list[0] = (char *) DEFAULT_SHELL;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004187 argument_list[1] = (char *) "-c";
Eric Andersen737f5fb2003-03-14 16:05:59 +00004188 argument_list[2] = child_cmd;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004189 argument_list[3] = NULL;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004190
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004191 cp = rexecve(argument_list[0], argument_list, makenv(1, wb));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004192 prs(argument_list[0]);
4193 prs(": ");
4194 err(cp);
Eric Andersen737f5fb2003-03-14 16:05:59 +00004195 _exit(1);
Eric Andersenff9eee42001-06-29 04:57:14 +00004196}
4197
Eric Andersen737f5fb2003-03-14 16:05:59 +00004198
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004199static char *unquote(char *as)
Eric Andersenff9eee42001-06-29 04:57:14 +00004200{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004201 char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00004202
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004203 s = as;
4204 if (s != NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00004205 while (*s)
4206 *s++ &= ~QUOTE;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004207 return as;
Eric Andersenff9eee42001-06-29 04:57:14 +00004208}
4209
4210/* -------- glob.c -------- */
4211
4212/*
4213 * glob
4214 */
4215
4216#define scopy(x) strsave((x), areanum)
4217#define BLKSIZ 512
4218#define NDENT ((BLKSIZ+sizeof(struct dirent)-1)/sizeof(struct dirent))
4219
Eric Andersen8401eea2004-08-04 19:16:54 +00004220static struct wdblock *cl, *nl;
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00004221static const char spcl[] ALIGN1= "[?*";
Eric Andersenff9eee42001-06-29 04:57:14 +00004222
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004223static struct wdblock *glob(char *cp, struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004224{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004225 int i;
4226 char *pp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004227
4228 if (cp == 0)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004229 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004230 i = 0;
4231 for (pp = cp; *pp; pp++)
4232 if (any(*pp, spcl))
4233 i++;
4234 else if (!any(*pp & ~QUOTE, spcl))
4235 *pp &= ~QUOTE;
4236 if (i != 0) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004237 for (cl = addword(scopy(cp), NULL); anyspcl(cl); cl = nl) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004238 nl = newword(cl->w_nword * 2);
4239 for (i = 0; i < cl->w_nword; i++) { /* for each argument */
Eric Andersenff9eee42001-06-29 04:57:14 +00004240 for (pp = cl->w_words[i]; *pp; pp++)
4241 if (any(*pp, spcl)) {
4242 globname(cl->w_words[i], pp);
4243 break;
4244 }
4245 if (*pp == '\0')
4246 nl = addword(scopy(cl->w_words[i]), nl);
4247 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004248 for (i = 0; i < cl->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004249 DELETE(cl->w_words[i]);
4250 DELETE(cl);
4251 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004252 for (i = 0; i < cl->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004253 unquote(cl->w_words[i]);
Eric Andersen8401eea2004-08-04 19:16:54 +00004254 glob0((char *) cl->w_words, cl->w_nword, sizeof(char *), xstrcmp);
Eric Andersenff9eee42001-06-29 04:57:14 +00004255 if (cl->w_nword) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004256 for (i = 0; i < cl->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004257 wb = addword(cl->w_words[i], wb);
4258 DELETE(cl);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004259 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004260 }
4261 }
4262 wb = addword(unquote(cp), wb);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004263 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004264}
4265
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004266static void globname(char *we, char *pp)
Eric Andersenff9eee42001-06-29 04:57:14 +00004267{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004268 char *np, *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004269 char *name, *gp, *dp;
4270 int k;
4271 DIR *dirp;
4272 struct dirent *de;
Eric Andersen8401eea2004-08-04 19:16:54 +00004273 char dname[NAME_MAX + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00004274 struct stat dbuf;
4275
4276 for (np = we; np != pp; pp--)
4277 if (pp[-1] == '/')
4278 break;
Eric Andersen8401eea2004-08-04 19:16:54 +00004279 for (dp = cp = space((int) (pp - np) + 3); np < pp;)
Eric Andersenff9eee42001-06-29 04:57:14 +00004280 *cp++ = *np++;
4281 *cp++ = '.';
4282 *cp = '\0';
Eric Andersen8401eea2004-08-04 19:16:54 +00004283 for (gp = cp = space(strlen(pp) + 1); *np && *np != '/';)
Eric Andersenff9eee42001-06-29 04:57:14 +00004284 *cp++ = *np++;
4285 *cp = '\0';
4286 dirp = opendir(dp);
4287 if (dirp == 0) {
4288 DELETE(dp);
4289 DELETE(gp);
4290 return;
4291 }
4292 dname[NAME_MAX] = '\0';
Eric Andersen8401eea2004-08-04 19:16:54 +00004293 while ((de = readdir(dirp)) != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004294 /* XXX Hmmm... What this could be? (abial) */
4295 /*
Eric Andersen8401eea2004-08-04 19:16:54 +00004296 if (ent[j].d_ino == 0)
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004297 continue;
Eric Andersen8401eea2004-08-04 19:16:54 +00004298 */
Eric Andersenff9eee42001-06-29 04:57:14 +00004299 strncpy(dname, de->d_name, NAME_MAX);
Eric Andersen8401eea2004-08-04 19:16:54 +00004300 if (dname[0] == '.')
4301 if (*gp != '.')
4302 continue;
4303 for (k = 0; k < NAME_MAX; k++)
4304 if (any(dname[k], spcl))
4305 dname[k] |= QUOTE;
4306 if (gmatch(dname, gp)) {
4307 name = generate(we, pp, dname, np);
4308 if (*np && !anys(np, spcl)) {
4309 if (stat(name, &dbuf)) {
4310 DELETE(name);
Eric Andersenff9eee42001-06-29 04:57:14 +00004311 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00004312 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004313 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004314 nl = addword(name, nl);
4315 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004316 }
4317 closedir(dirp);
4318 DELETE(dp);
4319 DELETE(gp);
4320}
4321
4322/*
4323 * generate a pathname as below.
4324 * start..end1 / middle end
4325 * the slashes come for free
4326 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004327static char *generate(char *start1, char *end1, char *middle, char *end)
Eric Andersenff9eee42001-06-29 04:57:14 +00004328{
4329 char *p;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004330 char *op, *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004331
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004332 p = op = space((int)(end1 - start1) + strlen(middle) + strlen(end) + 2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004333 for (xp = start1; xp != end1;)
4334 *op++ = *xp++;
Eric Andersen8401eea2004-08-04 19:16:54 +00004335 for (xp = middle; (*op++ = *xp++) != '\0';);
Eric Andersenff9eee42001-06-29 04:57:14 +00004336 op--;
Eric Andersen8401eea2004-08-04 19:16:54 +00004337 for (xp = end; (*op++ = *xp++) != '\0';);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004338 return p;
Eric Andersenff9eee42001-06-29 04:57:14 +00004339}
4340
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004341static int anyspcl(struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004342{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004343 int i;
4344 char **wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004345
4346 wd = wb->w_words;
Eric Andersen8401eea2004-08-04 19:16:54 +00004347 for (i = 0; i < wb->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004348 if (anys(spcl, *wd++))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004349 return 1;
4350 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004351}
4352
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004353static int xstrcmp(char *p1, char *p2)
Eric Andersenff9eee42001-06-29 04:57:14 +00004354{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004355 return strcmp(*(char **) p1, *(char **) p2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004356}
4357
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004358
Eric Andersenff9eee42001-06-29 04:57:14 +00004359/* -------- word.c -------- */
4360
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004361static struct wdblock *newword(int nw)
Eric Andersenff9eee42001-06-29 04:57:14 +00004362{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004363 struct wdblock *wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004364
Eric Andersen8401eea2004-08-04 19:16:54 +00004365 wb = (struct wdblock *) space(sizeof(*wb) + nw * sizeof(char *));
Eric Andersenff9eee42001-06-29 04:57:14 +00004366 wb->w_bsize = nw;
4367 wb->w_nword = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004368 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004369}
4370
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004371static struct wdblock *addword(char *wd, struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004372{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004373 struct wdblock *wb2;
4374 int nw;
Eric Andersenff9eee42001-06-29 04:57:14 +00004375
4376 if (wb == NULL)
4377 wb = newword(NSTART);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004378 nw = wb->w_nword;
4379 if (nw >= wb->w_bsize) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004380 wb2 = newword(nw * 2);
Eric Andersen8401eea2004-08-04 19:16:54 +00004381 memcpy((char *) wb2->w_words, (char *) wb->w_words,
4382 nw * sizeof(char *));
Eric Andersenff9eee42001-06-29 04:57:14 +00004383 wb2->w_nword = nw;
4384 DELETE(wb);
4385 wb = wb2;
4386 }
4387 wb->w_words[wb->w_nword++] = wd;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004388 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004389}
Eric Andersen8401eea2004-08-04 19:16:54 +00004390
Denis Vlasenkoe4712752007-04-14 15:08:41 +00004391static char **getwords(struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004392{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004393 char **wd;
4394 int nb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004395
4396 if (wb == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004397 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004398 if (wb->w_nword == 0) {
4399 DELETE(wb);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004400 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004401 }
4402 wd = (char **) space(nb = sizeof(*wd) * wb->w_nword);
Eric Andersen8401eea2004-08-04 19:16:54 +00004403 memcpy((char *) wd, (char *) wb->w_words, nb);
4404 DELETE(wb); /* perhaps should done by caller */
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004405 return wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004406}
4407
"Vladimir N. Oleynik"ac973172005-09-22 14:38:17 +00004408static int (*func) (char *, char *);
4409static int globv;
Eric Andersenff9eee42001-06-29 04:57:14 +00004410
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004411static void glob3(char *i, char *j, char *k)
Eric Andersenff9eee42001-06-29 04:57:14 +00004412{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004413 char *index1, *index2, *index3;
4414 int c;
4415 int m;
4416
4417 m = globv;
4418 index1 = i;
4419 index2 = j;
4420 index3 = k;
4421 do {
4422 c = *index1;
4423 *index1++ = *index3;
4424 *index3++ = *index2;
4425 *index2++ = c;
4426 } while (--m);
4427}
4428
4429static void glob2(char *i, char *j)
4430{
4431 char *index1, *index2, c;
4432 int m;
4433
4434 m = globv;
4435 index1 = i;
4436 index2 = j;
4437 do {
4438 c = *index1;
4439 *index1++ = *index2;
4440 *index2++ = c;
4441 } while (--m);
Eric Andersenff9eee42001-06-29 04:57:14 +00004442}
4443
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004444static void glob1(char *base, char *lim)
Eric Andersenff9eee42001-06-29 04:57:14 +00004445{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004446 char *i, *j;
Eric Andersenff9eee42001-06-29 04:57:14 +00004447 int v2;
4448 char *lptr, *hptr;
4449 int c;
4450 unsigned n;
4451
Eric Andersenff9eee42001-06-29 04:57:14 +00004452 v2 = globv;
4453
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004454 top:
4455 n = (int) (lim - base);
4456 if (n <= v2)
Eric Andersenff9eee42001-06-29 04:57:14 +00004457 return;
Eric Andersen8401eea2004-08-04 19:16:54 +00004458 n = v2 * (n / (2 * v2));
4459 hptr = lptr = base + n;
Eric Andersenff9eee42001-06-29 04:57:14 +00004460 i = base;
Eric Andersen8401eea2004-08-04 19:16:54 +00004461 j = lim - v2;
4462 for (;;) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004463 if (i < lptr) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004464 c = (*func) (i, lptr);
4465 if (c == 0) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004466 lptr -= v2;
4467 glob2(i, lptr);
Eric Andersenff9eee42001-06-29 04:57:14 +00004468 continue;
4469 }
4470 if (c < 0) {
4471 i += v2;
4472 continue;
4473 }
4474 }
4475
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004476 begin:
Eric Andersenff9eee42001-06-29 04:57:14 +00004477 if (j > hptr) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004478 c = (*func) (hptr, j);
4479 if (c == 0) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004480 hptr += v2;
4481 glob2(hptr, j);
Eric Andersenff9eee42001-06-29 04:57:14 +00004482 goto begin;
4483 }
4484 if (c > 0) {
4485 if (i == lptr) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004486 hptr += v2;
4487 glob3(i, hptr, j);
4488 i = (lptr += v2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004489 goto begin;
4490 }
4491 glob2(i, j);
4492 j -= v2;
4493 i += v2;
4494 continue;
4495 }
4496 j -= v2;
4497 goto begin;
4498 }
4499
4500
4501 if (i == lptr) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004502 if (lptr - base >= lim - hptr) {
4503 glob1(hptr + v2, lim);
Eric Andersenff9eee42001-06-29 04:57:14 +00004504 lim = lptr;
4505 } else {
4506 glob1(base, lptr);
Eric Andersen8401eea2004-08-04 19:16:54 +00004507 base = hptr + v2;
Eric Andersenff9eee42001-06-29 04:57:14 +00004508 }
4509 goto top;
4510 }
4511
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004512 lptr -= v2;
4513 glob3(j, lptr, i);
4514 j = (hptr -= v2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004515 }
4516}
4517
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004518static void glob0(char *a0, unsigned a1, int a2, int (*a3) (char *, char *))
Eric Andersenff9eee42001-06-29 04:57:14 +00004519{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004520 func = a3;
4521 globv = a2;
4522 glob1(a0, a0 + a1 * a2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004523}
4524
Eric Andersenff9eee42001-06-29 04:57:14 +00004525
4526/* -------- io.c -------- */
4527
4528/*
4529 * shell IO
4530 */
4531
Eric Andersen8401eea2004-08-04 19:16:54 +00004532static int my_getc(int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00004533{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004534 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004535
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004536 if (global_env.linep > elinep) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004537 while ((c = readc()) != '\n' && c);
Eric Andersenff9eee42001-06-29 04:57:14 +00004538 err("input line too long");
4539 gflg++;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004540 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004541 }
4542 c = readc();
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004543 if ((ec != '\'') && (ec != '`') && (global_env.iop->task != XGRAVE)) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004544 if (c == '\\') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004545 c = readc();
4546 if (c == '\n' && ec != '\"')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004547 return my_getc(ec);
Eric Andersenff9eee42001-06-29 04:57:14 +00004548 c |= QUOTE;
4549 }
4550 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004551 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004552}
4553
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004554static void unget(int c)
Eric Andersenff9eee42001-06-29 04:57:14 +00004555{
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004556 if (global_env.iop >= global_env.iobase)
4557 global_env.iop->peekc = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004558}
4559
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004560static int eofc(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00004561{
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004562 return global_env.iop < global_env.iobase || (global_env.iop->peekc == 0 && global_env.iop->prev == 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004563}
4564
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004565static int readc(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00004566{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004567 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004568
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004569 RCPRINTF(("READC: global_env.iop %p, global_env.iobase %p\n", global_env.iop, global_env.iobase));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004570
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004571 for (; global_env.iop >= global_env.iobase; global_env.iop--) {
4572 RCPRINTF(("READC: global_env.iop %p, peekc 0x%x\n", global_env.iop, global_env.iop->peekc));
4573 c = global_env.iop->peekc;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004574 if (c != '\0') {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004575 global_env.iop->peekc = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004576 return c;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004577 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004578 if (global_env.iop->prev != 0) {
4579 c = (*global_env.iop->iofn)(global_env.iop->argp, global_env.iop);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004580 if (c != '\0') {
4581 if (c == -1) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004582 global_env.iop++;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004583 continue;
Eric Andersen8401eea2004-08-04 19:16:54 +00004584 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004585 if (global_env.iop == iostack)
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004586 ioecho(c);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004587 global_env.iop->prev = c;
4588 return global_env.iop->prev;
Eric Andersenff9eee42001-06-29 04:57:14 +00004589 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004590 if (global_env.iop->task == XIO && global_env.iop->prev != '\n') {
4591 global_env.iop->prev = 0;
4592 if (global_env.iop == iostack)
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004593 ioecho('\n');
4594 return '\n';
Eric Andersen8401eea2004-08-04 19:16:54 +00004595 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004596 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004597 if (global_env.iop->task == XIO) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004598 if (multiline) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004599 global_env.iop->prev = 0;
4600 return global_env.iop->prev;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004601 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004602 if (interactive && global_env.iop == iostack + 1) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004603#if ENABLE_FEATURE_EDITING
4604 current_prompt = prompt->value;
4605#else
4606 prs(prompt->value);
4607#endif
4608 }
4609 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004610 } /* FOR */
4611
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004612 if (global_env.iop >= iostack) {
4613 RCPRINTF(("READC: return 0, global_env.iop %p\n", global_env.iop));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004614 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004615 }
4616
4617 DBGPRINTF(("READC: leave()...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00004618 leave();
Eric Andersen12de6cf2004-08-04 19:19:10 +00004619
Eric Andersenff9eee42001-06-29 04:57:14 +00004620 /* NOTREACHED */
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004621 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004622}
4623
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004624static void ioecho(char c)
Eric Andersenff9eee42001-06-29 04:57:14 +00004625{
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00004626 if (FLAG['v'])
Eric Andersenff9eee42001-06-29 04:57:14 +00004627 write(2, &c, sizeof c);
4628}
4629
Eric Andersen12de6cf2004-08-04 19:19:10 +00004630
Eric Andersen8401eea2004-08-04 19:16:54 +00004631static void pushio(struct ioarg *argp, int (*fn) (struct ioarg *))
Eric Andersenff9eee42001-06-29 04:57:14 +00004632{
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004633 DBGPRINTF(("PUSHIO: argp %p, argp->afid 0x%x, global_env.iop %p\n", argp,
4634 argp->afid, global_env.iop));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004635
4636 /* Set env ptr for io source to next array spot and check for array overflow */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004637 if (++global_env.iop >= &iostack[NPUSH]) {
4638 global_env.iop--;
Eric Andersenff9eee42001-06-29 04:57:14 +00004639 err("Shell input nested too deeply");
4640 gflg++;
4641 return;
4642 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004643
4644 /* We did not overflow the NPUSH array spots so setup data structs */
4645
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004646 global_env.iop->iofn = (int (*)(struct ioarg *, struct io *)) fn; /* Store data source func ptr */
Eric Andersenff9eee42001-06-29 04:57:14 +00004647
4648 if (argp->afid != AFID_NOBUF)
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004649 global_env.iop->argp = argp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004650 else {
Eric Andersen12de6cf2004-08-04 19:19:10 +00004651
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004652 global_env.iop->argp = ioargstack + (global_env.iop - iostack); /* MAL - index into stack */
4653 *global_env.iop->argp = *argp; /* copy data from temp area into stack spot */
Eric Andersen12de6cf2004-08-04 19:19:10 +00004654
4655 /* MAL - mainbuf is for 1st data source (command line?) and all nested use a single shared buffer? */
4656
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004657 if (global_env.iop == &iostack[0])
4658 global_env.iop->argp->afbuf = &mainbuf;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004659 else
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004660 global_env.iop->argp->afbuf = &sharedbuf;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004661
4662 /* MAL - if not a termimal AND (commandline OR readable file) then give it a buffer id? */
4663 /* This line appears to be active when running scripts from command line */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004664 if ((isatty(global_env.iop->argp->afile) == 0)
4665 && (global_env.iop == &iostack[0]
4666 || lseek(global_env.iop->argp->afile, 0L, SEEK_CUR) != -1)) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00004667 if (++bufid == AFID_NOBUF) /* counter rollover check, AFID_NOBUF = 11111111 */
4668 bufid = AFID_ID; /* AFID_ID = 0 */
4669
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004670 global_env.iop->argp->afid = bufid; /* assign buffer id */
Eric Andersen8401eea2004-08-04 19:16:54 +00004671 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004672
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004673 DBGPRINTF(("PUSHIO: iostack %p, global_env.iop %p, afbuf %p\n",
4674 iostack, global_env.iop, global_env.iop->argp->afbuf));
4675 DBGPRINTF(("PUSHIO: mbuf %p, sbuf %p, bid %d, global_env.iop %p\n",
4676 &mainbuf, &sharedbuf, bufid, global_env.iop));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004677
Eric Andersenff9eee42001-06-29 04:57:14 +00004678 }
4679
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004680 global_env.iop->prev = ~'\n';
4681 global_env.iop->peekc = 0;
4682 global_env.iop->xchar = 0;
4683 global_env.iop->nlcount = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004684
Eric Andersenff9eee42001-06-29 04:57:14 +00004685 if (fn == filechar || fn == linechar)
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004686 global_env.iop->task = XIO;
Eric Andersen8401eea2004-08-04 19:16:54 +00004687 else if (fn == (int (*)(struct ioarg *)) gravechar
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004688 || fn == (int (*)(struct ioarg *)) qgravechar)
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004689 global_env.iop->task = XGRAVE;
Eric Andersenff9eee42001-06-29 04:57:14 +00004690 else
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004691 global_env.iop->task = XOTHER;
Eric Andersenff9eee42001-06-29 04:57:14 +00004692}
4693
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004694static struct io *setbase(struct io *ip)
Eric Andersenff9eee42001-06-29 04:57:14 +00004695{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004696 struct io *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004697
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004698 xp = global_env.iobase;
4699 global_env.iobase = ip;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004700 return xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004701}
4702
4703/*
4704 * Input generating functions
4705 */
4706
4707/*
4708 * Produce the characters of a string, then a newline, then EOF.
4709 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004710static int nlchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004711{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004712 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004713
4714 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004715 return 0;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004716 c = *ap->aword++;
4717 if (c == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004718 ap->aword = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004719 return '\n';
Eric Andersenff9eee42001-06-29 04:57:14 +00004720 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004721 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004722}
4723
4724/*
4725 * Given a list of words, produce the characters
4726 * in them, with a space after each word.
4727 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004728static int wdchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004729{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004730 char c;
4731 char **wl;
Eric Andersenff9eee42001-06-29 04:57:14 +00004732
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004733 wl = ap->awordlist;
4734 if (wl == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004735 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004736 if (*wl != NULL) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004737 c = *(*wl)++;
4738 if (c != 0)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004739 return c & 0177;
Eric Andersenff9eee42001-06-29 04:57:14 +00004740 ap->awordlist++;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004741 return ' ';
Eric Andersenff9eee42001-06-29 04:57:14 +00004742 }
4743 ap->awordlist = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004744 return '\n';
Eric Andersenff9eee42001-06-29 04:57:14 +00004745}
4746
4747/*
4748 * Return the characters of a list of words,
4749 * producing a space between them.
4750 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004751static int dolchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004752{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004753 char *wp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004754
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004755 wp = *ap->awordlist++;
4756 if (wp != NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004757 PUSHIO(aword, wp, *ap->awordlist == NULL ? strchar : xxchar);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004758 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004759 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004760 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004761}
4762
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004763static int xxchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004764{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004765 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004766
4767 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004768 return 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004769 c = *ap->aword++;
4770 if (c == '\0') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004771 ap->aword = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004772 return ' ';
Eric Andersenff9eee42001-06-29 04:57:14 +00004773 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004774 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004775}
4776
4777/*
4778 * Produce the characters from a single word (string).
4779 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004780static int strchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004781{
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004782 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004783 return 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004784 return *ap->aword++;
Eric Andersenff9eee42001-06-29 04:57:14 +00004785}
4786
4787/*
4788 * Produce quoted characters from a single word (string).
4789 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004790static int qstrchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004791{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004792 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004793
Denis Vlasenkob2abef32007-01-01 18:18:04 +00004794 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004795 return 0;
Denis Vlasenkob2abef32007-01-01 18:18:04 +00004796 c = *ap->aword++;
4797 if (c)
4798 c |= QUOTE;
4799 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004800}
4801
4802/*
4803 * Return the characters from a file.
4804 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004805static int filechar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004806{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004807 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004808 char c;
4809 struct iobuf *bp = ap->afbuf;
4810
4811 if (ap->afid != AFID_NOBUF) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004812 i = (ap->afid != bp->id);
4813 if (i || bp->bufp == bp->ebufp) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004814 if (i)
Denis Vlasenkoea620772006-10-14 02:23:43 +00004815 lseek(ap->afile, ap->afpos, SEEK_SET);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004816
Eric Andersen8401eea2004-08-04 19:16:54 +00004817 i = safe_read(ap->afile, bp->buf, sizeof(bp->buf));
4818 if (i <= 0) {
4819 closef(ap->afile);
4820 return 0;
4821 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004822
Eric Andersen8401eea2004-08-04 19:16:54 +00004823 bp->id = ap->afid;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004824 bp->bufp = bp->buf;
4825 bp->ebufp = bp->bufp + i;
Eric Andersen8401eea2004-08-04 19:16:54 +00004826 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004827
Eric Andersen8401eea2004-08-04 19:16:54 +00004828 ap->afpos++;
4829 return *bp->bufp++ & 0177;
Eric Andersenff9eee42001-06-29 04:57:14 +00004830 }
Denis Vlasenko38f63192007-01-22 09:03:07 +00004831#if ENABLE_FEATURE_EDITING
Eric Andersen737f5fb2003-03-14 16:05:59 +00004832 if (interactive && isatty(ap->afile)) {
Denis Vlasenko55f30b02007-03-24 22:42:29 +00004833 /* moved to G: static char filechar_cmdbuf[BUFSIZ]; */
Eric Andersen8401eea2004-08-04 19:16:54 +00004834 static int position = 0, size = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004835
Eric Andersen8401eea2004-08-04 19:16:54 +00004836 while (size == 0 || position >= size) {
Denis Vlasenko55f30b02007-03-24 22:42:29 +00004837 read_line_input(current_prompt, filechar_cmdbuf, BUFSIZ, line_input_state);
4838 size = strlen(filechar_cmdbuf);
Eric Andersen8401eea2004-08-04 19:16:54 +00004839 position = 0;
4840 }
Denis Vlasenko55f30b02007-03-24 22:42:29 +00004841 c = filechar_cmdbuf[position];
Eric Andersen8401eea2004-08-04 19:16:54 +00004842 position++;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004843 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004844 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004845#endif
4846 i = safe_read(ap->afile, &c, sizeof(c));
4847 return i == sizeof(c) ? (c & 0x7f) : (closef(ap->afile), 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004848}
4849
4850/*
4851 * Return the characters from a here temp file.
4852 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004853static int herechar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004854{
4855 char c;
4856
Eric Andersenff9eee42001-06-29 04:57:14 +00004857 if (read(ap->afile, &c, sizeof(c)) != sizeof(c)) {
4858 close(ap->afile);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004859 c = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00004860 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004861 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004862}
4863
4864/*
4865 * Return the characters produced by a process (`...`).
4866 * Quote them if required, and remove any trailing newline characters.
4867 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004868static int gravechar(struct ioarg *ap, struct io *iop)
Eric Andersenff9eee42001-06-29 04:57:14 +00004869{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004870 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004871
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004872 c = qgravechar(ap, iop) & ~QUOTE;
4873 if (c == '\n')
Eric Andersenff9eee42001-06-29 04:57:14 +00004874 c = ' ';
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004875 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004876}
4877
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004878static int qgravechar(struct ioarg *ap, struct io *iop)
Eric Andersenff9eee42001-06-29 04:57:14 +00004879{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004880 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004881
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004882 DBGPRINTF3(("QGRAVECHAR: enter, ap=%p, iop=%p\n", ap, iop));
Eric Andersenff9eee42001-06-29 04:57:14 +00004883
4884 if (iop->xchar) {
4885 if (iop->nlcount) {
4886 iop->nlcount--;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004887 return '\n' | QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00004888 }
4889 c = iop->xchar;
4890 iop->xchar = 0;
4891 } else if ((c = filechar(ap)) == '\n') {
4892 iop->nlcount = 1;
4893 while ((c = filechar(ap)) == '\n')
4894 iop->nlcount++;
4895 iop->xchar = c;
4896 if (c == 0)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004897 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004898 iop->nlcount--;
4899 c = '\n';
4900 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004901 return c != 0 ? c | QUOTE : 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004902}
4903
4904/*
4905 * Return a single command (usually the first line) from a file.
4906 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004907static int linechar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004908{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004909 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004910
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004911 c = filechar(ap);
4912 if (c == '\n') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004913 if (!multiline) {
4914 closef(ap->afile);
Eric Andersen8401eea2004-08-04 19:16:54 +00004915 ap->afile = -1; /* illegal value */
Eric Andersenff9eee42001-06-29 04:57:14 +00004916 }
4917 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004918 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004919}
4920
Eric Andersenff9eee42001-06-29 04:57:14 +00004921/*
4922 * remap fd into Shell's fd space
4923 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004924static int remap(int fd)
Eric Andersenff9eee42001-06-29 04:57:14 +00004925{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004926 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004927 int map[NOFILE];
Eric Andersen12de6cf2004-08-04 19:19:10 +00004928 int newfd;
4929
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004930 DBGPRINTF(("REMAP: fd=%d, global_env.iofd=%d\n", fd, global_env.iofd));
Eric Andersenff9eee42001-06-29 04:57:14 +00004931
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004932 if (fd < global_env.iofd) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004933 for (i = 0; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004934 map[i] = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004935
Eric Andersenff9eee42001-06-29 04:57:14 +00004936 do {
4937 map[fd] = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004938 newfd = dup(fd);
4939 fd = newfd;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004940 } while (fd >= 0 && fd < global_env.iofd);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004941
Eric Andersen8401eea2004-08-04 19:16:54 +00004942 for (i = 0; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004943 if (map[i])
4944 close(i);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004945
Eric Andersenff9eee42001-06-29 04:57:14 +00004946 if (fd < 0)
4947 err("too many files open in shell");
4948 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004949
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004950 return fd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004951}
4952
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004953static int openpipe(int *pv)
Eric Andersenff9eee42001-06-29 04:57:14 +00004954{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004955 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004956
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004957 i = pipe(pv);
4958 if (i < 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00004959 err("can't create pipe - try again");
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004960 return i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004961}
4962
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004963static void closepipe(int *pv)
Eric Andersenff9eee42001-06-29 04:57:14 +00004964{
4965 if (pv != NULL) {
4966 close(*pv++);
4967 close(*pv);
4968 }
4969}
4970
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004971
Eric Andersenff9eee42001-06-29 04:57:14 +00004972/* -------- here.c -------- */
4973
4974/*
4975 * here documents
4976 */
4977
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004978static void markhere(char *s, struct ioword *iop)
Eric Andersenff9eee42001-06-29 04:57:14 +00004979{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004980 struct here *h, *lh;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004981
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004982 DBGPRINTF7(("MARKHERE: enter, s=%p\n", s));
Eric Andersenff9eee42001-06-29 04:57:14 +00004983
4984 h = (struct here *) space(sizeof(struct here));
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004985 if (h == NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00004986 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004987
Eric Andersenff9eee42001-06-29 04:57:14 +00004988 h->h_tag = evalstr(s, DOSUB);
4989 if (h->h_tag == 0)
4990 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004991
Eric Andersenff9eee42001-06-29 04:57:14 +00004992 h->h_iop = iop;
4993 iop->io_name = 0;
4994 h->h_next = NULL;
4995 if (inhere == 0)
4996 inhere = h;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004997 else {
4998 for (lh = inhere; lh != NULL; lh = lh->h_next) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004999 if (lh->h_next == 0) {
5000 lh->h_next = h;
5001 break;
5002 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00005003 }
5004 }
Eric Andersen8401eea2004-08-04 19:16:54 +00005005 iop->io_flag |= IOHERE | IOXHERE;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00005006 for (s = h->h_tag; *s; s++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00005007 if (*s & QUOTE) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005008 iop->io_flag &= ~IOXHERE;
5009 *s &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00005010 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00005011 }
Eric Andersenff9eee42001-06-29 04:57:14 +00005012 h->h_dosub = iop->io_flag & IOXHERE;
5013}
5014
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005015static void gethere(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00005016{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005017 struct here *h, *hp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005018
5019 DBGPRINTF7(("GETHERE: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00005020
5021 /* Scan here files first leaving inhere list in place */
5022 for (hp = h = inhere; h != NULL; hp = h, h = h->h_next)
Eric Andersen8401eea2004-08-04 19:16:54 +00005023 readhere(&h->h_iop->io_name, h->h_tag, h->h_dosub ? 0 : '\'');
Eric Andersenff9eee42001-06-29 04:57:14 +00005024
5025 /* Make inhere list active - keep list intact for scraphere */
5026 if (hp != NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005027 hp->h_next = acthere;
5028 acthere = inhere;
5029 inhere = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00005030 }
5031}
5032
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005033static void readhere(char **name, char *s, int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00005034{
5035 int tf;
5036 char tname[30] = ".msh_XXXXXX";
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005037 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00005038 jmp_buf ev;
Eric Andersen8401eea2004-08-04 19:16:54 +00005039 char myline[LINELIM + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00005040 char *thenext;
5041
Mike Frysinger02d8fa42006-05-05 20:32:31 +00005042 DBGPRINTF7(("READHERE: enter, name=%p, s=%p\n", name, s));
Eric Andersen12de6cf2004-08-04 19:19:10 +00005043
Eric Andersenff9eee42001-06-29 04:57:14 +00005044 tf = mkstemp(tname);
5045 if (tf < 0)
5046 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005047
Eric Andersenff9eee42001-06-29 04:57:14 +00005048 *name = strsave(tname, areanum);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00005049 errpt = ev;
5050 if (newenv(setjmp(errpt)) != 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00005051 unlink(tname);
5052 else {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005053 pushio(global_env.iop->argp, (int (*)(struct ioarg *)) global_env.iop->iofn);
5054 global_env.iobase = global_env.iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00005055 for (;;) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005056 if (interactive && global_env.iop <= iostack) {
Denis Vlasenko38f63192007-01-22 09:03:07 +00005057#if ENABLE_FEATURE_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00005058 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00005059#else
Eric Andersen8401eea2004-08-04 19:16:54 +00005060 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00005061#endif
5062 }
5063 thenext = myline;
5064 while ((c = my_getc(ec)) != '\n' && c) {
5065 if (ec == '\'')
Eric Andersen8401eea2004-08-04 19:16:54 +00005066 c &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00005067 if (thenext >= &myline[LINELIM]) {
5068 c = 0;
5069 break;
5070 }
5071 *thenext++ = c;
5072 }
5073 *thenext = 0;
5074 if (strcmp(s, myline) == 0 || c == 0)
5075 break;
5076 *thenext++ = '\n';
Eric Andersen8401eea2004-08-04 19:16:54 +00005077 write(tf, myline, (int) (thenext - myline));
Eric Andersenff9eee42001-06-29 04:57:14 +00005078 }
5079 if (c == 0) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005080 prs("here document `");
5081 prs(s);
5082 err("' unclosed");
Eric Andersenff9eee42001-06-29 04:57:14 +00005083 }
5084 quitenv();
5085 }
5086 close(tf);
5087}
5088
5089/*
5090 * open here temp file.
5091 * if unquoted here, expand here temp file into second temp file.
5092 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005093static int herein(char *hname, int xdoll)
Eric Andersenff9eee42001-06-29 04:57:14 +00005094{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005095 int hf;
Eric Andersenff9eee42001-06-29 04:57:14 +00005096 int tf;
5097
5098#if __GNUC__
5099 /* Avoid longjmp clobbering */
5100 (void) &tf;
5101#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00005102 if (hname == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00005103 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005104
5105 DBGPRINTF7(("HEREIN: hname is %s, xdoll=%d\n", hname, xdoll));
5106
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005107 hf = open(hname, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00005108 if (hf < 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00005109 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005110
Eric Andersenff9eee42001-06-29 04:57:14 +00005111 if (xdoll) {
5112 char c;
5113 char tname[30] = ".msh_XXXXXX";
5114 jmp_buf ev;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005115
Eric Andersenff9eee42001-06-29 04:57:14 +00005116 tf = mkstemp(tname);
5117 if (tf < 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00005118 return -1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00005119 errpt = ev;
5120 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00005121 PUSHIO(afile, hf, herechar);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005122 setbase(global_env.iop);
Eric Andersenff9eee42001-06-29 04:57:14 +00005123 while ((c = subgetc(0, 0)) != 0) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005124 c &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00005125 write(tf, &c, sizeof c);
5126 }
5127 quitenv();
5128 } else
5129 unlink(tname);
5130 close(tf);
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005131 tf = open(tname, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00005132 unlink(tname);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00005133 return tf;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00005134 }
5135 return hf;
Eric Andersenff9eee42001-06-29 04:57:14 +00005136}
5137
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005138static void scraphere(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00005139{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005140 struct here *h;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005141
5142 DBGPRINTF7(("SCRAPHERE: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00005143
5144 for (h = inhere; h != NULL; h = h->h_next) {
5145 if (h->h_iop && h->h_iop->io_name)
Eric Andersen8401eea2004-08-04 19:16:54 +00005146 unlink(h->h_iop->io_name);
Eric Andersenff9eee42001-06-29 04:57:14 +00005147 }
5148 inhere = NULL;
5149}
5150
5151/* unlink here temp files before a freearea(area) */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005152static void freehere(int area)
Eric Andersenff9eee42001-06-29 04:57:14 +00005153{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005154 struct here *h, *hl;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005155
5156 DBGPRINTF6(("FREEHERE: enter, area=%d\n", area));
Eric Andersenff9eee42001-06-29 04:57:14 +00005157
5158 hl = NULL;
5159 for (h = acthere; h != NULL; h = h->h_next)
5160 if (getarea((char *) h) >= area) {
5161 if (h->h_iop->io_name != NULL)
5162 unlink(h->h_iop->io_name);
5163 if (hl == NULL)
5164 acthere = h->h_next;
5165 else
5166 hl->h_next = h->h_next;
5167 } else
5168 hl = h;
5169}
5170
5171
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005172/* -------- sh.c -------- */
5173/*
5174 * shell
5175 */
5176
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00005177int msh_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005178int msh_main(int argc, char **argv)
5179{
5180 int f;
5181 char *s;
5182 int cflag;
5183 char *name, **ap;
5184 int (*iof) (struct ioarg *);
5185
Denis Vlasenkoab801872007-12-02 08:35:37 +00005186 INIT_G();
5187
Denis Vlasenko55f30b02007-03-24 22:42:29 +00005188 sharedbuf.id = AFID_NOBUF;
5189 mainbuf.id = AFID_NOBUF;
Denis Vlasenko55f30b02007-03-24 22:42:29 +00005190 elinep = line + sizeof(line) - 5;
5191
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005192#if ENABLE_FEATURE_EDITING
5193 line_input_state = new_line_input_t(FOR_SHELL);
5194#endif
5195
5196 DBGPRINTF(("MSH_MAIN: argc %d, environ %p\n", argc, environ));
5197
5198 initarea();
5199 ap = environ;
5200 if (ap != NULL) {
5201 while (*ap)
5202 assign(*ap++, !COPYV);
5203 for (ap = environ; *ap;)
5204 export(lookup(*ap++));
5205 }
5206 closeall();
5207 areanum = 1;
5208
5209 shell = lookup("SHELL");
5210 if (shell->value == null)
5211 setval(shell, (char *)DEFAULT_SHELL);
5212 export(shell);
5213
5214 homedir = lookup("HOME");
5215 if (homedir->value == null)
5216 setval(homedir, "/");
5217 export(homedir);
5218
5219 setval(lookup("$"), putn(getpid()));
5220
5221 path = lookup("PATH");
5222 if (path->value == null) {
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005223 /* Can be merged with same string elsewhere in bbox */
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005224 if (geteuid() == 0)
Denis Vlasenkof5f75c52007-06-12 22:35:19 +00005225 setval(path, bb_default_root_path);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005226 else
Denis Vlasenkof5f75c52007-06-12 22:35:19 +00005227 setval(path, bb_default_path);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005228 }
5229 export(path);
5230
5231 ifs = lookup("IFS");
5232 if (ifs->value == null)
5233 setval(ifs, " \t\n");
5234
5235#ifdef MSHDEBUG
5236 mshdbg_var = lookup("MSHDEBUG");
5237 if (mshdbg_var->value == null)
5238 setval(mshdbg_var, "0");
5239#endif
5240
5241 prompt = lookup("PS1");
5242#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
5243 if (prompt->value == null)
5244#endif
5245 setval(prompt, DEFAULT_USER_PROMPT);
5246 if (geteuid() == 0) {
5247 setval(prompt, DEFAULT_ROOT_PROMPT);
5248 prompt->status &= ~EXPORT;
5249 }
5250 cprompt = lookup("PS2");
5251#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
5252 if (cprompt->value == null)
5253#endif
5254 setval(cprompt, "> ");
5255
5256 iof = filechar;
5257 cflag = 0;
5258 name = *argv++;
5259 if (--argc >= 1) {
5260 if (argv[0][0] == '-' && argv[0][1] != '\0') {
5261 for (s = argv[0] + 1; *s; s++)
5262 switch (*s) {
5263 case 'c':
5264 prompt->status &= ~EXPORT;
5265 cprompt->status &= ~EXPORT;
5266 setval(prompt, "");
5267 setval(cprompt, "");
5268 cflag = 1;
5269 if (--argc > 0)
5270 PUSHIO(aword, *++argv, iof = nlchar);
5271 break;
5272
5273 case 'q':
5274 qflag = SIG_DFL;
5275 break;
5276
5277 case 's':
5278 /* standard input */
5279 break;
5280
5281 case 't':
5282 prompt->status &= ~EXPORT;
5283 setval(prompt, "");
5284 iof = linechar;
5285 break;
5286
5287 case 'i':
5288 interactive++;
5289 default:
5290 if (*s >= 'a' && *s <= 'z')
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00005291 FLAG[(int) *s]++;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005292 }
5293 } else {
5294 argv--;
5295 argc++;
5296 }
5297
5298 if (iof == filechar && --argc > 0) {
5299 setval(prompt, "");
5300 setval(cprompt, "");
5301 prompt->status &= ~EXPORT;
5302 cprompt->status &= ~EXPORT;
5303
5304/* Shell is non-interactive, activate printf-based debug */
5305#ifdef MSHDEBUG
5306 mshdbg = (int) (((char) (mshdbg_var->value[0])) - '0');
5307 if (mshdbg < 0)
5308 mshdbg = 0;
5309#endif
5310 DBGPRINTF(("MSH_MAIN: calling newfile()\n"));
5311
5312 name = *++argv;
5313 if (newfile(name))
5314 exit(1); /* Exit on error */
5315 }
5316 }
5317
5318 setdash();
5319
5320 /* This won't be true if PUSHIO has been called, say from newfile() above */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005321 if (global_env.iop < iostack) {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005322 PUSHIO(afile, 0, iof);
5323 if (isatty(0) && isatty(1) && !cflag) {
5324 interactive++;
5325#if !ENABLE_FEATURE_SH_EXTRA_QUIET
5326#ifdef MSHDEBUG
Denis Vlasenkoca525b42007-06-13 12:27:17 +00005327 printf("\n\n%s built-in shell (msh with debug)\n", bb_banner);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005328#else
Denis Vlasenkoca525b42007-06-13 12:27:17 +00005329 printf("\n\n%s built-in shell (msh)\n", bb_banner);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005330#endif
5331 printf("Enter 'help' for a list of built-in commands.\n\n");
5332#endif
5333 }
5334 }
5335
5336 signal(SIGQUIT, qflag);
5337 if (name && name[0] == '-') {
5338 interactive++;
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005339 f = open(".profile", O_RDONLY);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005340 if (f >= 0)
5341 next(remap(f));
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005342 f = open("/etc/profile", O_RDONLY);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005343 if (f >= 0)
5344 next(remap(f));
5345 }
5346 if (interactive)
5347 signal(SIGTERM, sig);
5348
5349 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
5350 signal(SIGINT, onintr);
5351 dolv = argv;
5352 dolc = argc;
5353 dolv[0] = name;
5354 if (dolc > 1) {
5355 for (ap = ++argv; --argc > 0;) {
5356 *ap = *argv++;
5357 if (assign(*ap, !COPYV)) {
5358 dolc--; /* keyword */
5359 } else {
5360 ap++;
5361 }
5362 }
5363 }
5364 setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc));
5365
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005366 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 +00005367
5368 for (;;) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005369 if (interactive && global_env.iop <= iostack) {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005370#if ENABLE_FEATURE_EDITING
5371 current_prompt = prompt->value;
5372#else
5373 prs(prompt->value);
5374#endif
5375 }
5376 onecommand();
5377 /* Ensure that getenv("PATH") stays current */
5378 setenv("PATH", path->value, 1);
5379 }
5380
5381 DBGPRINTF(("MSH_MAIN: returning.\n"));
5382}
5383
5384
Eric Andersenff9eee42001-06-29 04:57:14 +00005385/*
5386 * Copyright (c) 1987,1997, Prentice Hall
5387 * All rights reserved.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005388 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005389 * Redistribution and use of the MINIX operating system in source and
5390 * binary forms, with or without modification, are permitted provided
5391 * that the following conditions are met:
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005392 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005393 * Redistributions of source code must retain the above copyright
5394 * notice, this list of conditions and the following disclaimer.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005395 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005396 * Redistributions in binary form must reproduce the above
5397 * copyright notice, this list of conditions and the following
5398 * disclaimer in the documentation and/or other materials provided
5399 * with the distribution.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005400 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005401 * Neither the name of Prentice Hall nor the names of the software
5402 * authors or contributors may be used to endorse or promote
5403 * products derived from this software without specific prior
5404 * written permission.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005405 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005406 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND
5407 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
5408 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
5409 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
5410 * IN NO EVENT SHALL PRENTICE HALL OR ANY AUTHORS OR CONTRIBUTORS BE
5411 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
5412 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
5413 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
5414 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
5415 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
5416 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
5417 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5418 *
5419 */