blob: 2328e0734c1cc5b72b2d7d823c8da14a5fce2d2d [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__))
48static char *find_applet_by_name(const char *applet)
49{
50 return NULL;
51}
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
Mike Frysinger67a32ad2007-03-09 08:25:24 +000086# include "busybox.h"
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
Eric Andersen8401eea2004-08-04 19:16:54 +0000205#define TCOM 1 /* command */
206#define TPAREN 2 /* (c-list) */
207#define TPIPE 3 /* a | b */
208#define TLIST 4 /* a [&;] b */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000209#define TOR 5 /* || */
Eric Andersen8401eea2004-08-04 19:16:54 +0000210#define TAND 6 /* && */
Eric Andersenff9eee42001-06-29 04:57:14 +0000211#define TFOR 7
Eric Andersen12de6cf2004-08-04 19:19:10 +0000212#define TDO 8
Eric Andersenff9eee42001-06-29 04:57:14 +0000213#define TCASE 9
Eric Andersen12de6cf2004-08-04 19:19:10 +0000214#define TIF 10
Eric Andersenff9eee42001-06-29 04:57:14 +0000215#define TWHILE 11
216#define TUNTIL 12
217#define TELIF 13
Eric Andersen8401eea2004-08-04 19:16:54 +0000218#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 */
222#define TDOT 17
223
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 Andersenff9eee42001-06-29 04:57:14 +0000273/*
Eric Andersenff9eee42001-06-29 04:57:14 +0000274 * flags:
275 * -e: quit on error
276 * -k: look for name=value everywhere on command line
277 * -n: no execution
278 * -t: exit after reading and executing one command
279 * -v: echo as read
280 * -x: trace
281 * -u: unset variables net diagnostic
282 */
Mike Frysinger3672fe92006-11-15 21:52:10 +0000283static char flags['z' - 'a' + 1];
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +0000284/* this looks weird, but is OK ... we index FLAG with 'a'...'z' */
285#define FLAG (flags - 'a')
Eric Andersenff9eee42001-06-29 04:57:14 +0000286
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000287/* moved to G: static char *trap[_NSIG + 1]; */
288/* moved to G: static char ourtrap[_NSIG + 1]; */
Eric Andersen8401eea2004-08-04 19:16:54 +0000289static int trapset; /* trap pending */
Eric Andersenff9eee42001-06-29 04:57:14 +0000290
Eric Andersen8401eea2004-08-04 19:16:54 +0000291static int yynerrs; /* yacc */
Eric Andersenff9eee42001-06-29 04:57:14 +0000292
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000293/* moved to G: static char line[LINELIM]; */
Eric Andersenff9eee42001-06-29 04:57:14 +0000294
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000295#if ENABLE_FEATURE_EDITING
296static char *current_prompt;
297static line_input_t *line_input_state;
298#endif
299
Eric Andersen12de6cf2004-08-04 19:19:10 +0000300
Eric Andersenff9eee42001-06-29 04:57:14 +0000301/*
302 * other functions
303 */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000304static const char *rexecve(char *c, char **v, char **envp);
Eric Andersen8401eea2004-08-04 19:16:54 +0000305static char *evalstr(char *cp, int f);
306static char *putn(int n);
Eric Andersen8401eea2004-08-04 19:16:54 +0000307static char *unquote(char *as);
Eric Andersen8401eea2004-08-04 19:16:54 +0000308static int rlookup(char *n);
309static struct wdblock *glob(char *cp, struct wdblock *wb);
310static int my_getc(int ec);
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +0000311static int subgetc(char ec, int quoted);
Eric Andersenfd7a4c82004-09-02 23:13:10 +0000312static char **makenv(int all, struct wdblock *wb);
Eric Andersen8401eea2004-08-04 19:16:54 +0000313static char **eval(char **ap, int f);
314static int setstatus(int s);
315static int waitfor(int lastpid, int canintr);
Eric Andersenff9eee42001-06-29 04:57:14 +0000316
Eric Andersen8401eea2004-08-04 19:16:54 +0000317static void onintr(int s); /* SIGINT handler */
Eric Andersenff9eee42001-06-29 04:57:14 +0000318
Eric Andersen8401eea2004-08-04 19:16:54 +0000319static int newenv(int f);
320static void quitenv(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000321static void next(int f);
322static void setdash(void);
323static void onecommand(void);
324static void runtrap(int i);
Eric Andersenff9eee42001-06-29 04:57:14 +0000325
Eric Andersen12de6cf2004-08-04 19:19:10 +0000326
Eric Andersenff9eee42001-06-29 04:57:14 +0000327/* -------- area stuff -------- */
328
Denis Vlasenko5f9468e2007-04-14 13:22:09 +0000329#define REGSIZE sizeof(struct region)
330#define GROWBY (256)
331/* #define SHRINKBY (64) */
332#undef SHRINKBY
333#define FREE (32767)
334#define BUSY (0)
335#define ALIGN (sizeof(int)-1)
Eric Andersenff9eee42001-06-29 04:57:14 +0000336
337
338struct region {
Eric Andersen8401eea2004-08-04 19:16:54 +0000339 struct region *next;
340 int area;
Eric Andersenff9eee42001-06-29 04:57:14 +0000341};
342
343
Eric Andersenff9eee42001-06-29 04:57:14 +0000344/* -------- grammar stuff -------- */
345typedef union {
Eric Andersen8401eea2004-08-04 19:16:54 +0000346 char *cp;
347 char **wp;
348 int i;
349 struct op *o;
Eric Andersenff9eee42001-06-29 04:57:14 +0000350} YYSTYPE;
Eric Andersen8401eea2004-08-04 19:16:54 +0000351
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000352#define WORD 256
353#define LOGAND 257
354#define LOGOR 258
355#define BREAK 259
356#define IF 260
357#define THEN 261
358#define ELSE 262
359#define ELIF 263
360#define FI 264
361#define CASE 265
362#define ESAC 266
363#define FOR 267
364#define WHILE 268
365#define UNTIL 269
366#define DO 270
367#define DONE 271
368#define IN 272
Eric Andersen12de6cf2004-08-04 19:19:10 +0000369/* Added for "." file expansion */
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000370#define DOT 273
Eric Andersen12de6cf2004-08-04 19:19:10 +0000371
Eric Andersenff9eee42001-06-29 04:57:14 +0000372#define YYERRCODE 300
373
374/* flags to yylex */
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000375#define CONTIN 01 /* skip new lines to complete command */
Eric Andersenff9eee42001-06-29 04:57:14 +0000376
Eric Andersen8401eea2004-08-04 19:16:54 +0000377static struct op *pipeline(int cf);
Eric Andersenff9eee42001-06-29 04:57:14 +0000378static struct op *andor(void);
379static struct op *c_list(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000380static int synio(int cf);
381static void musthave(int c, int cf);
Eric Andersenff9eee42001-06-29 04:57:14 +0000382static struct op *simple(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000383static struct op *nested(int type, int mark);
384static struct op *command(int cf);
385static struct op *dogroup(int onlydone);
Eric Andersenff9eee42001-06-29 04:57:14 +0000386static struct op *thenpart(void);
387static struct op *elsepart(void);
388static struct op *caselist(void);
389static struct op *casepart(void);
390static char **pattern(void);
391static char **wordlist(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000392static struct op *list(struct op *t1, struct op *t2);
393static struct op *block(int type, struct op *t1, struct op *t2, char **wp);
Eric Andersenff9eee42001-06-29 04:57:14 +0000394static struct op *newtp(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000395static struct op *namelist(struct op *t);
Eric Andersenff9eee42001-06-29 04:57:14 +0000396static char **copyw(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000397static void word(char *cp);
Eric Andersenff9eee42001-06-29 04:57:14 +0000398static struct ioword **copyio(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000399static struct ioword *io(int u, int f, char *cp);
Eric Andersen8401eea2004-08-04 19:16:54 +0000400static int yylex(int cf);
401static int collect(int c, int c1);
402static int dual(int c);
403static void diag(int ec);
404static char *tree(unsigned size);
Eric Andersenff9eee42001-06-29 04:57:14 +0000405
406/* -------- var.h -------- */
407
Eric Andersen8401eea2004-08-04 19:16:54 +0000408struct var {
409 char *value;
410 char *name;
411 struct var *next;
412 char status;
Eric Andersenff9eee42001-06-29 04:57:14 +0000413};
Eric Andersenff9eee42001-06-29 04:57:14 +0000414
Eric Andersen8401eea2004-08-04 19:16:54 +0000415#define COPYV 1 /* flag to setval, suggesting copy */
416#define RONLY 01 /* variable is read-only */
417#define EXPORT 02 /* variable is to be exported */
418#define GETCELL 04 /* name & value space was got with getcell */
Eric Andersenff9eee42001-06-29 04:57:14 +0000419
Eric Andersen8401eea2004-08-04 19:16:54 +0000420static int yyparse(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000421
422static int execute(struct op *t, int *pin, int *pout, int act);
Eric Andersenff9eee42001-06-29 04:57:14 +0000423
Eric Andersen12de6cf2004-08-04 19:19:10 +0000424
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000425#define AFID_NOBUF (~0)
426#define AFID_ID 0
427
428
Eric Andersenff9eee42001-06-29 04:57:14 +0000429/* -------- io.h -------- */
430/* io buffer */
431struct iobuf {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000432 unsigned id; /* buffer id */
433 char buf[512]; /* buffer */
434 char *bufp; /* pointer into buffer */
435 char *ebufp; /* pointer to end of buffer */
Eric Andersenff9eee42001-06-29 04:57:14 +0000436};
437
438/* possible arguments to an IO function */
439struct ioarg {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000440 const char *aword;
Eric Andersen8401eea2004-08-04 19:16:54 +0000441 char **awordlist;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000442 int afile; /* file descriptor */
443 unsigned afid; /* buffer id */
444 long afpos; /* file position */
445 struct iobuf *afbuf; /* buffer for this file */
Eric Andersenff9eee42001-06-29 04:57:14 +0000446};
Eric Andersen8401eea2004-08-04 19:16:54 +0000447
Eric Andersenff9eee42001-06-29 04:57:14 +0000448/* an input generator's state */
Eric Andersen8401eea2004-08-04 19:16:54 +0000449struct io {
450 int (*iofn) (struct ioarg *, struct io *);
451 struct ioarg *argp;
452 int peekc;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000453 char prev; /* previous character read by readc() */
454 char nlcount; /* for `'s */
455 char xchar; /* for `'s */
456 char task; /* reason for pushed IO */
Eric Andersenff9eee42001-06-29 04:57:14 +0000457};
Eric Andersen8401eea2004-08-04 19:16:54 +0000458
Eric Andersen8401eea2004-08-04 19:16:54 +0000459#define XOTHER 0 /* none of the below */
460#define XDOLL 1 /* expanding ${} */
461#define XGRAVE 2 /* expanding `'s */
Denis Vlasenkoe27f1562007-01-01 06:00:38 +0000462#define XIO 3 /* file IO */
Eric Andersenff9eee42001-06-29 04:57:14 +0000463
464/* in substitution */
465#define INSUB() (e.iop->task == XGRAVE || e.iop->task == XDOLL)
466
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000467static struct ioarg temparg = { 0, 0, 0, AFID_NOBUF, 0 }; /* temporary for PUSHIO */
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000468/* moved to G: static struct ioarg ioargstack[NPUSH]; */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000469static struct io iostack[NPUSH];
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000470/* moved to G: static struct iobuf sharedbuf = { AFID_NOBUF }; */
471/* moved to G: static struct iobuf mainbuf = { AFID_NOBUF }; */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000472static unsigned bufid = AFID_ID; /* buffer id counter */
473
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000474#define RUN(what,arg,gen) ((temparg.what = (arg)), run(&temparg,(gen)))
475
476
477/*
Eric Andersenff9eee42001-06-29 04:57:14 +0000478 * input generators for IO structure
479 */
Eric Andersen8401eea2004-08-04 19:16:54 +0000480static int nlchar(struct ioarg *ap);
481static int strchar(struct ioarg *ap);
482static int qstrchar(struct ioarg *ap);
483static int filechar(struct ioarg *ap);
484static int herechar(struct ioarg *ap);
485static int linechar(struct ioarg *ap);
486static int gravechar(struct ioarg *ap, struct io *iop);
487static int qgravechar(struct ioarg *ap, struct io *iop);
488static int dolchar(struct ioarg *ap);
489static int wdchar(struct ioarg *ap);
490static void scraphere(void);
491static void freehere(int area);
492static void gethere(void);
493static void markhere(char *s, struct ioword *iop);
494static int herein(char *hname, int xdoll);
495static int run(struct ioarg *argp, int (*f) (struct ioarg *));
Eric Andersenff9eee42001-06-29 04:57:14 +0000496
Eric Andersen12de6cf2004-08-04 19:19:10 +0000497
Eric Andersen8401eea2004-08-04 19:16:54 +0000498static int eofc(void);
499static int readc(void);
500static void unget(int c);
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +0000501static void ioecho(char c);
Eric Andersenff9eee42001-06-29 04:57:14 +0000502
Eric Andersen12de6cf2004-08-04 19:19:10 +0000503
Eric Andersenff9eee42001-06-29 04:57:14 +0000504/*
505 * IO control
506 */
Eric Andersen8401eea2004-08-04 19:16:54 +0000507static void pushio(struct ioarg *argp, int (*f) (struct ioarg *));
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000508#define PUSHIO(what,arg,gen) ((temparg.what = (arg)), pushio(&temparg,(gen)))
Eric Andersen8401eea2004-08-04 19:16:54 +0000509static int remap(int fd);
510static int openpipe(int *pv);
511static void closepipe(int *pv);
512static struct io *setbase(struct io *ip);
Eric Andersenff9eee42001-06-29 04:57:14 +0000513
Eric Andersenff9eee42001-06-29 04:57:14 +0000514/* -------- word.h -------- */
515
Eric Andersen8401eea2004-08-04 19:16:54 +0000516#define NSTART 16 /* default number of words to allow for initially */
Eric Andersenff9eee42001-06-29 04:57:14 +0000517
Eric Andersen8401eea2004-08-04 19:16:54 +0000518struct wdblock {
519 short w_bsize;
520 short w_nword;
Eric Andersenff9eee42001-06-29 04:57:14 +0000521 /* bounds are arbitrary */
Eric Andersen8401eea2004-08-04 19:16:54 +0000522 char *w_words[1];
Eric Andersenff9eee42001-06-29 04:57:14 +0000523};
524
Eric Andersen8401eea2004-08-04 19:16:54 +0000525static struct wdblock *addword(char *wd, struct wdblock *wb);
526static struct wdblock *newword(int nw);
527static char **getwords(struct wdblock *wb);
Eric Andersenff9eee42001-06-29 04:57:14 +0000528
Eric Andersenff9eee42001-06-29 04:57:14 +0000529/* -------- misc stuff -------- */
530
Eric Andersen12de6cf2004-08-04 19:19:10 +0000531static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp);
Eric Andersen8401eea2004-08-04 19:16:54 +0000532static int iosetup(struct ioword *iop, int pipein, int pipeout);
Eric Andersen8401eea2004-08-04 19:16:54 +0000533static void brkset(struct brkcon *bc);
534static int dolabel(struct op *t);
535static int dohelp(struct op *t);
536static int dochdir(struct op *t);
537static int doshift(struct op *t);
538static int dologin(struct op *t);
539static int doumask(struct op *t);
540static int doexec(struct op *t);
541static int dodot(struct op *t);
542static int dowait(struct op *t);
543static int doread(struct op *t);
544static int doeval(struct op *t);
545static int dotrap(struct op *t);
546static int getsig(char *s);
547static void setsig(int n, sighandler_t f);
548static int getn(char *as);
549static int dobreak(struct op *t);
550static int docontinue(struct op *t);
551static int brkcontin(char *cp, int val);
552static int doexit(struct op *t);
553static int doexport(struct op *t);
554static int doreadonly(struct op *t);
555static void rdexp(char **wp, void (*f) (struct var *), int key);
556static void badid(char *s);
557static int doset(struct op *t);
558static void varput(char *s, int out);
559static int dotimes(struct op *t);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000560static int expand(const char *cp, struct wdblock **wbp, int f);
Eric Andersen8401eea2004-08-04 19:16:54 +0000561static char *blank(int f);
562static int dollar(int quoted);
563static int grave(int quoted);
564static void globname(char *we, char *pp);
565static char *generate(char *start1, char *end1, char *middle, char *end);
566static int anyspcl(struct wdblock *wb);
567static int xstrcmp(char *p1, char *p2);
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000568static void glob0(char *a0, unsigned a1, int a2,
Eric Andersen8401eea2004-08-04 19:16:54 +0000569 int (*a3) (char *, char *));
Eric Andersen8401eea2004-08-04 19:16:54 +0000570static void readhere(char **name, char *s, int ec);
Eric Andersen8401eea2004-08-04 19:16:54 +0000571static int xxchar(struct ioarg *ap);
Eric Andersenff9eee42001-06-29 04:57:14 +0000572
Eric Andersen8401eea2004-08-04 19:16:54 +0000573struct here {
574 char *h_tag;
575 int h_dosub;
576 struct ioword *h_iop;
577 struct here *h_next;
Eric Andersenff9eee42001-06-29 04:57:14 +0000578};
579
"Vladimir N. Oleynik"485d7cb2005-10-17 09:48:57 +0000580static const char * const signame[] = {
Eric Andersenff9eee42001-06-29 04:57:14 +0000581 "Signal 0",
582 "Hangup",
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000583 NULL, /* interrupt */
Eric Andersenff9eee42001-06-29 04:57:14 +0000584 "Quit",
585 "Illegal instruction",
586 "Trace/BPT trap",
587 "Abort",
588 "Bus error",
589 "Floating Point Exception",
590 "Killed",
591 "SIGUSR1",
592 "SIGSEGV",
593 "SIGUSR2",
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000594 NULL, /* broken pipe */
Eric Andersenff9eee42001-06-29 04:57:14 +0000595 "Alarm clock",
596 "Terminated",
597};
Eric Andersen8401eea2004-08-04 19:16:54 +0000598
Eric Andersenff9eee42001-06-29 04:57:14 +0000599#define NSIGNAL (sizeof(signame)/sizeof(signame[0]))
600
601struct res {
"Vladimir N. Oleynik"485d7cb2005-10-17 09:48:57 +0000602 const char *r_name;
Eric Andersen8401eea2004-08-04 19:16:54 +0000603 int r_val;
Eric Andersenff9eee42001-06-29 04:57:14 +0000604};
"Vladimir N. Oleynik"485d7cb2005-10-17 09:48:57 +0000605static const struct res restab[] = {
Denis Vlasenko95cb3262007-04-09 03:06:34 +0000606 { "for" , FOR },
607 { "case" , CASE },
608 { "esac" , ESAC },
609 { "while", WHILE },
610 { "do" , DO },
611 { "done" , DONE },
612 { "if" , IF },
613 { "in" , IN },
614 { "then" , THEN },
615 { "else" , ELSE },
616 { "elif" , ELIF },
617 { "until", UNTIL },
618 { "fi" , FI },
619 { ";;" , BREAK },
620 { "||" , LOGOR },
621 { "&&" , LOGAND },
622 { "{" , '{' },
623 { "}" , '}' },
624 { "." , DOT },
625 { NULL , 0 },
Eric Andersenff9eee42001-06-29 04:57:14 +0000626};
627
Eric Andersen1c039232001-07-07 00:05:55 +0000628struct builtincmd {
629 const char *name;
Denis Vlasenko95cb3262007-04-09 03:06:34 +0000630 int (*builtinfunc)(struct op *t);
Eric Andersenff9eee42001-06-29 04:57:14 +0000631};
Eric Andersen8401eea2004-08-04 19:16:54 +0000632static const struct builtincmd builtincmds[] = {
Denis Vlasenko95cb3262007-04-09 03:06:34 +0000633 { "." , dodot },
634 { ":" , dolabel },
635 { "break" , dobreak },
636 { "cd" , dochdir },
637 { "continue", docontinue },
638 { "eval" , doeval },
639 { "exec" , doexec },
640 { "exit" , doexit },
641 { "export" , doexport },
642 { "help" , dohelp },
643 { "login" , dologin },
644 { "newgrp" , dologin },
645 { "read" , doread },
646 { "readonly", doreadonly },
647 { "set" , doset },
648 { "shift" , doshift },
649 { "times" , dotimes },
650 { "trap" , dotrap },
651 { "umask" , doumask },
652 { "wait" , dowait },
653 { NULL , NULL },
Eric Andersenff9eee42001-06-29 04:57:14 +0000654};
655
"Vladimir N. Oleynik"ac973172005-09-22 14:38:17 +0000656static struct op *scantree(struct op *);
Eric Andersen12de6cf2004-08-04 19:19:10 +0000657static struct op *dowholefile(int, int);
658
Eric Andersen12de6cf2004-08-04 19:19:10 +0000659
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000660/* Globals */
Eric Andersen8401eea2004-08-04 19:16:54 +0000661static char **dolv;
662static int dolc;
663static int exstat;
664static char gflg;
"Vladimir N. Oleynik"485d7cb2005-10-17 09:48:57 +0000665static int interactive; /* Is this an interactive shell */
Eric Andersen8401eea2004-08-04 19:16:54 +0000666static int execflg;
667static int multiline; /* \n changed to ; */
668static struct op *outtree; /* result from parser */
669static xint *failpt;
670static xint *errpt;
671static struct brkcon *brklist;
672static int isbreak;
673static struct wdblock *wdlist;
674static struct wdblock *iolist;
Eric Andersen12de6cf2004-08-04 19:19:10 +0000675
676#ifdef MSHDEBUG
677static struct var *mshdbg_var;
678#endif
Eric Andersen8401eea2004-08-04 19:16:54 +0000679static struct var *vlist; /* dictionary */
680static struct var *homedir; /* home directory */
681static struct var *prompt; /* main prompt */
682static struct var *cprompt; /* continuation prompt */
683static struct var *path; /* search path for commands */
684static struct var *shell; /* shell to interpret command files */
685static struct var *ifs; /* field separators */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000686
Denis Vlasenko95cb3262007-04-09 03:06:34 +0000687static int areanum; /* current allocation area */
688static int intr; /* interrupt pending */
Eric Andersen8401eea2004-08-04 19:16:54 +0000689static int inparse;
Denis Vlasenko95cb3262007-04-09 03:06:34 +0000690static char *null = (char*)""; /* null value for variable */
691static int heedint = 1; /* heed interrupt signals */
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +0000692static void (*qflag)(int) = SIG_IGN;
Eric Andersen8401eea2004-08-04 19:16:54 +0000693static int startl;
694static int peeksym;
695static int nlseen;
696static int iounit = IODEFAULT;
697static YYSTYPE yylval;
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000698static char *elinep; /* done in main(): = line + sizeof(line) - 5 */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000699
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000700static struct here *inhere; /* list of hear docs while parsing */
701static struct here *acthere; /* list of active here documents */
702static struct region *areabot; /* bottom of area */
703static struct region *areatop; /* top of area */
704static struct region *areanxt; /* starting point of scan */
Eric Andersen8401eea2004-08-04 19:16:54 +0000705static void *brktop;
706static void *brkaddr;
Eric Andersenff9eee42001-06-29 04:57:14 +0000707
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000708/*
709 * parsing & execution environment
710 */
711struct env {
712 char *linep;
713 struct io *iobase;
714 struct io *iop;
715 xint *errpt; /* void * */
716 int iofd;
717 struct env *oenv;
718};
719
Eric Andersen12de6cf2004-08-04 19:19:10 +0000720static struct env e = {
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000721 NULL /* set to line in main() */, /* linep: char ptr */
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000722 iostack, /* iobase: struct io ptr */
723 iostack - 1, /* iop: struct io ptr */
724 (xint *) NULL, /* errpt: void ptr for errors? */
725 FDBASE, /* iofd: file desc */
726 (struct env *) NULL /* oenv: struct env ptr */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000727};
728
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000729
730struct globals {
731 char ourtrap[_NSIG + 1];
732 char *trap[_NSIG + 1];
733 struct iobuf sharedbuf; /* in main(): set to { AFID_NOBUF } */
734 struct iobuf mainbuf; /* in main(): set to { AFID_NOBUF } */
735 struct ioarg ioargstack[NPUSH];
736 char filechar_cmdbuf[BUFSIZ];
737 char line[LINELIM];
738 char child_cmd[LINELIM];
739};
740
741#define G (*ptr_to_globals)
742#define ourtrap (G.ourtrap )
743#define trap (G.trap )
744#define sharedbuf (G.sharedbuf )
745#define mainbuf (G.mainbuf )
746#define ioargstack (G.ioargstack )
747#define filechar_cmdbuf (G.filechar_cmdbuf)
748#define line (G.line )
749#define child_cmd (G.child_cmd )
750
751
Eric Andersen12de6cf2004-08-04 19:19:10 +0000752#ifdef MSHDEBUG
753void print_t(struct op *t)
754{
Mike Frysinger02d8fa42006-05-05 20:32:31 +0000755 DBGPRINTF(("T: t=%p, type %s, words=%p, IOword=%p\n", t,
756 T_CMD_NAMES[t->type], t->words, t->ioact));
Eric Andersen12de6cf2004-08-04 19:19:10 +0000757
758 if (t->words) {
759 DBGPRINTF(("T: W1: %s", t->words[0]));
760 }
Eric Andersen12de6cf2004-08-04 19:19:10 +0000761}
762
763void print_tree(struct op *head)
764{
765 if (head == NULL) {
766 DBGPRINTF(("PRINT_TREE: no tree\n"));
767 return;
768 }
769
Mike Frysinger02d8fa42006-05-05 20:32:31 +0000770 DBGPRINTF(("NODE: %p, left %p, right %p\n", head, head->left,
Eric Andersen12de6cf2004-08-04 19:19:10 +0000771 head->right));
772
773 if (head->left)
774 print_tree(head->left);
775
776 if (head->right)
777 print_tree(head->right);
Eric Andersen12de6cf2004-08-04 19:19:10 +0000778}
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000779#endif /* MSHDEBUG */
780
781
782/*
783 * IO functions
784 */
785static void prs(const char *s)
786{
787 if (*s)
788 write(2, s, strlen(s));
789}
790
791static void prn(unsigned u)
792{
793 prs(itoa(u));
794}
795
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000796static void echo(char **wp)
797{
798 int i;
799
800 prs("+");
801 for (i = 0; wp[i]; i++) {
802 if (i)
803 prs(" ");
804 prs(wp[i]);
805 }
806 prs("\n");
807}
808
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000809static void closef(int i)
810{
811 if (i > 2)
812 close(i);
813}
814
815static void closeall(void)
816{
817 int u;
818
819 for (u = NUFILE; u < NOFILE;)
820 close(u++);
821}
Eric Andersen12de6cf2004-08-04 19:19:10 +0000822
Eric Andersenff9eee42001-06-29 04:57:14 +0000823
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000824/* fail but return to process next command */
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000825static void fail(void) ATTRIBUTE_NORETURN;
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000826static void fail(void)
827{
828 longjmp(failpt, 1);
829 /* NOTREACHED */
830}
Eric Andersenff9eee42001-06-29 04:57:14 +0000831
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000832/* abort shell (or fail in subshell) */
833static void leave(void) ATTRIBUTE_NORETURN;
834static void leave(void)
835{
836 DBGPRINTF(("LEAVE: leave called!\n"));
837
838 if (execflg)
839 fail();
840 scraphere();
841 freehere(1);
842 runtrap(0);
843 _exit(exstat);
844 /* NOTREACHED */
845}
846
847static void warn(const char *s)
848{
849 if (*s) {
850 prs(s);
851 exstat = -1;
852 }
853 prs("\n");
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +0000854 if (FLAG['e'])
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000855 leave();
856}
857
858static void err(const char *s)
859{
860 warn(s);
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +0000861 if (FLAG['n'])
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000862 return;
863 if (!interactive)
864 leave();
865 if (e.errpt)
866 longjmp(e.errpt, 1);
867 closeall();
868 e.iop = e.iobase = iostack;
869}
870
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000871
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000872/* -------- area.c -------- */
873
Eric Andersenff9eee42001-06-29 04:57:14 +0000874/*
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000875 * All memory between (char *)areabot and (char *)(areatop+1) is
876 * exclusively administered by the area management routines.
877 * It is assumed that sbrk() and brk() manipulate the high end.
Eric Andersenff9eee42001-06-29 04:57:14 +0000878 */
879
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000880#define sbrk(X) ({ \
881 void * __q = (void *)-1; \
882 if (brkaddr + (int)(X) < brktop) { \
883 __q = brkaddr; \
884 brkaddr += (int)(X); \
885 } \
886 __q; \
887})
Eric Andersenff9eee42001-06-29 04:57:14 +0000888
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000889static void initarea(void)
Eric Andersenff9eee42001-06-29 04:57:14 +0000890{
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000891 brkaddr = xmalloc(AREASIZE);
892 brktop = brkaddr + AREASIZE;
Eric Andersenff9eee42001-06-29 04:57:14 +0000893
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000894 while ((long) sbrk(0) & ALIGN)
895 sbrk(1);
896 areabot = (struct region *) sbrk(REGSIZE);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +0000897
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000898 areabot->next = areabot;
899 areabot->area = BUSY;
900 areatop = areabot;
901 areanxt = areabot;
Eric Andersenff9eee42001-06-29 04:57:14 +0000902}
903
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000904static char *getcell(unsigned nbytes)
905{
906 int nregio;
907 struct region *p, *q;
908 int i;
909
910 if (nbytes == 0) {
911 puts("getcell(0)");
912 abort();
913 }
914 /* silly and defeats the algorithm */
915 /*
916 * round upwards and add administration area
917 */
918 nregio = (nbytes + (REGSIZE - 1)) / REGSIZE + 1;
919 p = areanxt;
920 for (;;) {
921 if (p->area > areanum) {
922 /*
923 * merge free cells
924 */
925 while ((q = p->next)->area > areanum && q != areanxt)
926 p->next = q->next;
927 /*
928 * exit loop if cell big enough
929 */
930 if (q >= p + nregio)
931 goto found;
932 }
933 p = p->next;
934 if (p == areanxt)
935 break;
936 }
937 i = nregio >= GROWBY ? nregio : GROWBY;
938 p = (struct region *) sbrk(i * REGSIZE);
939 if (p == (struct region *) -1)
940 return NULL;
941 p--;
942 if (p != areatop) {
943 puts("not contig");
944 abort(); /* allocated areas are contiguous */
945 }
946 q = p + i;
947 p->next = q;
948 p->area = FREE;
949 q->next = areabot;
950 q->area = BUSY;
951 areatop = q;
952 found:
953 /*
954 * we found a FREE area big enough, pointed to by 'p', and up to 'q'
955 */
956 areanxt = p + nregio;
957 if (areanxt < q) {
958 /*
959 * split into requested area and rest
960 */
961 if (areanxt + 1 > q) {
962 puts("OOM");
963 abort(); /* insufficient space left for admin */
964 }
965 areanxt->next = q;
966 areanxt->area = FREE;
967 p->next = areanxt;
968 }
969 p->area = areanum;
970 return (char *) (p + 1);
971}
972
973static void freecell(char *cp)
974{
975 struct region *p;
976
977 p = (struct region *) cp;
978 if (p != NULL) {
979 p--;
980 if (p < areanxt)
981 areanxt = p;
982 p->area = FREE;
983 }
984}
985#define DELETE(obj) freecell((char *)obj)
986
987static void freearea(int a)
988{
989 struct region *p, *top;
990
991 top = areatop;
992 for (p = areabot; p != top; p = p->next)
993 if (p->area >= a)
994 p->area = FREE;
995}
996
997static void setarea(char *cp, int a)
998{
999 struct region *p;
1000
1001 p = (struct region *) cp;
1002 if (p != NULL)
1003 (p - 1)->area = a;
1004}
1005
1006static int getarea(char *cp)
1007{
1008 return ((struct region *) cp - 1)->area;
1009}
1010
1011static void garbage(void)
1012{
1013 struct region *p, *q, *top;
1014
1015 top = areatop;
1016 for (p = areabot; p != top; p = p->next) {
1017 if (p->area > areanum) {
1018 while ((q = p->next)->area > areanum)
1019 p->next = q->next;
1020 areanxt = p;
1021 }
1022 }
1023#ifdef SHRINKBY
1024 if (areatop >= q + SHRINKBY && q->area > areanum) {
1025 brk((char *) (q + 1));
1026 q->next = areabot;
1027 q->area = BUSY;
1028 areatop = q;
1029 }
1030#endif
1031}
1032
1033static char *space(int n)
1034{
1035 char *cp;
1036
1037 cp = getcell(n);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001038 if (cp == NULL)
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001039 err("out of string space");
1040 return cp;
1041}
1042
1043static char *strsave(const char *s, int a)
1044{
1045 char *cp;
1046
1047 cp = space(strlen(s) + 1);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001048 if (cp == NULL) {
1049// FIXME: I highly doubt this is good.
1050 return (char*)"";
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001051 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001052 setarea(cp, a);
1053 strcpy(cp, s);
1054 return cp;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001055}
1056
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001057
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001058/* -------- var.c -------- */
1059
1060static int eqname(const char *n1, const char *n2)
1061{
1062 for (; *n1 != '=' && *n1 != '\0'; n1++)
1063 if (*n2++ != *n1)
1064 return 0;
1065 return *n2 == '\0' || *n2 == '=';
1066}
1067
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001068static const char *findeq(const char *cp)
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001069{
1070 while (*cp != '\0' && *cp != '=')
1071 cp++;
1072 return cp;
1073}
1074
1075/*
1076 * Find the given name in the dictionary
1077 * and return its value. If the name was
1078 * not previously there, enter it now and
1079 * return a null value.
1080 */
1081static struct var *lookup(const char *n)
1082{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001083// FIXME: dirty hack
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001084 static struct var dummy;
1085
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001086 struct var *vp;
1087 const char *cp;
1088 char *xp;
1089 int c;
1090
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001091 if (isdigit(*n)) {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001092 dummy.name = (char*)n;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001093 for (c = 0; isdigit(*n) && c < 1000; n++)
1094 c = c * 10 + *n - '0';
1095 dummy.status = RONLY;
1096 dummy.value = (c <= dolc ? dolv[c] : null);
1097 return &dummy;
1098 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001099
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001100 for (vp = vlist; vp; vp = vp->next)
1101 if (eqname(vp->name, n))
1102 return vp;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001103
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001104 cp = findeq(n);
1105 vp = (struct var *) space(sizeof(*vp));
1106 if (vp == 0 || (vp->name = space((int) (cp - n) + 2)) == 0) {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001107 dummy.name = dummy.value = (char*)"";
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001108 return &dummy;
1109 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001110
1111 xp = vp->name;
1112 while ((*xp = *n++) != '\0' && *xp != '=')
1113 xp++;
1114 *xp++ = '=';
1115 *xp = '\0';
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001116 setarea((char *) vp, 0);
1117 setarea((char *) vp->name, 0);
1118 vp->value = null;
1119 vp->next = vlist;
1120 vp->status = GETCELL;
1121 vlist = vp;
1122 return vp;
1123}
1124
1125/*
1126 * if name is not NULL, it must be
1127 * a prefix of the space `val',
1128 * and end with `='.
1129 * this is all so that exporting
1130 * values is reasonably painless.
1131 */
1132static void nameval(struct var *vp, const char *val, const char *name)
1133{
1134 const char *cp;
1135 char *xp;
1136 int fl;
1137
1138 if (vp->status & RONLY) {
1139 xp = vp->name;
1140 while (*xp && *xp != '=')
1141 putc(*xp++, stderr);
1142 err(" is read-only");
1143 return;
1144 }
1145 fl = 0;
1146 if (name == NULL) {
1147 xp = space(strlen(vp->name) + strlen(val) + 2);
1148 if (xp == NULL)
1149 return;
1150 /* make string: name=value */
1151 setarea(xp, 0);
1152 name = xp;
1153 cp = vp->name;
1154 while ((*xp = *cp++) != '\0' && *xp != '=')
1155 xp++;
1156 *xp++ = '=';
1157 strcpy(xp, val);
1158 val = xp;
1159 fl = GETCELL;
1160 }
1161 if (vp->status & GETCELL)
1162 freecell(vp->name); /* form new string `name=value' */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001163 vp->name = (char*)name;
1164 vp->value = (char*)val;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001165 vp->status |= fl;
1166}
1167
1168/*
1169 * give variable at `vp' the value `val'.
1170 */
1171static void setval(struct var *vp, const char *val)
1172{
1173 nameval(vp, val, NULL);
1174}
1175
1176static void export(struct var *vp)
1177{
1178 vp->status |= EXPORT;
1179}
1180
1181static void ronly(struct var *vp)
1182{
1183 if (isalpha(vp->name[0]) || vp->name[0] == '_') /* not an internal symbol */
1184 vp->status |= RONLY;
1185}
1186
1187static int isassign(const char *s)
1188{
1189 unsigned char c;
1190 DBGPRINTF7(("ISASSIGN: enter, s=%s\n", s));
1191
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001192 c = *s;
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001193 /* no isalpha() - we shouldn't use locale */
1194 /* c | 0x20 - lowercase (Latin) letters */
1195 if (c != '_' && (unsigned)((c|0x20) - 'a') > 25)
1196 /* not letter */
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001197 return 0;
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001198
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001199 while (1) {
1200 c = *++s;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001201 if (c == '=')
1202 return 1;
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001203 if (c == '\0')
1204 return 0;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001205 if (c != '_'
1206 && (unsigned)(c - '0') > 9 /* not number */
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001207 && (unsigned)((c|0x20) - 'a') > 25 /* not letter */
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001208 ) {
1209 return 0;
1210 }
1211 }
1212}
1213
1214static int assign(const char *s, int cf)
1215{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001216 const char *cp;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001217 struct var *vp;
1218
1219 DBGPRINTF7(("ASSIGN: enter, s=%s, cf=%d\n", s, cf));
1220
1221 if (!isalpha(*s) && *s != '_')
1222 return 0;
1223 for (cp = s; *cp != '='; cp++)
1224 if (*cp == '\0' || (!isalnum(*cp) && *cp != '_'))
1225 return 0;
1226 vp = lookup(s);
1227 nameval(vp, ++cp, cf == COPYV ? NULL : s);
1228 if (cf != COPYV)
1229 vp->status &= ~GETCELL;
1230 return 1;
1231}
1232
1233static int checkname(char *cp)
1234{
1235 DBGPRINTF7(("CHECKNAME: enter, cp=%s\n", cp));
1236
1237 if (!isalpha(*cp++) && *(cp - 1) != '_')
1238 return 0;
1239 while (*cp)
1240 if (!isalnum(*cp++) && *(cp - 1) != '_')
1241 return 0;
1242 return 1;
1243}
1244
1245static void putvlist(int f, int out)
1246{
1247 struct var *vp;
1248
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001249 for (vp = vlist; vp; vp = vp->next) {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001250 if (vp->status & f && (isalpha(*vp->name) || *vp->name == '_')) {
1251 if (vp->status & EXPORT)
1252 write(out, "export ", 7);
1253 if (vp->status & RONLY)
1254 write(out, "readonly ", 9);
1255 write(out, vp->name, (int) (findeq(vp->name) - vp->name));
1256 write(out, "\n", 1);
1257 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001258 }
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001259}
1260
1261
1262/*
1263 * trap handling
1264 */
1265static void sig(int i)
1266{
1267 trapset = i;
1268 signal(i, sig);
1269}
1270
1271static void runtrap(int i)
1272{
1273 char *trapstr;
1274
1275 trapstr = trap[i];
1276 if (trapstr == NULL)
1277 return;
1278
1279 if (i == 0)
1280 trap[i] = NULL;
1281
1282 RUN(aword, trapstr, nlchar);
1283}
1284
1285
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001286static void setdash(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001287{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001288 char *cp;
1289 int c;
Eric Andersen8401eea2004-08-04 19:16:54 +00001290 char m['z' - 'a' + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00001291
1292 cp = m;
Eric Andersen8401eea2004-08-04 19:16:54 +00001293 for (c = 'a'; c <= 'z'; c++)
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00001294 if (FLAG[c])
Eric Andersenff9eee42001-06-29 04:57:14 +00001295 *cp++ = c;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001296 *cp = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00001297 setval(lookup("-"), m);
1298}
1299
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001300static int newfile(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00001301{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001302 int f;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001303
1304 DBGPRINTF7(("NEWFILE: opening %s\n", s));
Eric Andersenff9eee42001-06-29 04:57:14 +00001305
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001306 f = 0;
Denis Vlasenko9f739442006-12-16 23:49:13 +00001307 if (NOT_LONE_DASH(s)) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001308 DBGPRINTF(("NEWFILE: s is %s\n", s));
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00001309 f = open(s, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00001310 if (f < 0) {
1311 prs(s);
1312 err(": cannot open");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001313 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001314 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001315 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001316
Eric Andersenff9eee42001-06-29 04:57:14 +00001317 next(remap(f));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001318 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001319}
1320
Eric Andersen12de6cf2004-08-04 19:19:10 +00001321
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001322struct op *scantree(struct op *head)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001323{
1324 struct op *dotnode;
1325
1326 if (head == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001327 return NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001328
1329 if (head->left != NULL) {
1330 dotnode = scantree(head->left);
1331 if (dotnode)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001332 return dotnode;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001333 }
1334
1335 if (head->right != NULL) {
1336 dotnode = scantree(head->right);
1337 if (dotnode)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001338 return dotnode;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001339 }
1340
1341 if (head->words == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001342 return NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001343
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001344 DBGPRINTF5(("SCANTREE: checking node %p\n", head));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001345
Denis Vlasenkocf787cf2007-02-04 17:11:25 +00001346 if ((head->type != TDOT) && LONE_CHAR(head->words[0], '.')) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001347 DBGPRINTF5(("SCANTREE: dot found in node %p\n", head));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001348 return head;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001349 }
1350
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001351 return NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001352}
1353
1354
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001355static void onecommand(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001356{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001357 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00001358 jmp_buf m1;
1359
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001360 DBGPRINTF(("ONECOMMAND: enter, outtree=%p\n", outtree));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001361
Eric Andersenff9eee42001-06-29 04:57:14 +00001362 while (e.oenv)
1363 quitenv();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001364
Eric Andersenff9eee42001-06-29 04:57:14 +00001365 areanum = 1;
1366 freehere(areanum);
1367 freearea(areanum);
1368 garbage();
1369 wdlist = 0;
1370 iolist = 0;
1371 e.errpt = 0;
1372 e.linep = line;
1373 yynerrs = 0;
1374 multiline = 0;
1375 inparse = 1;
1376 intr = 0;
1377 execflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001378
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001379 failpt = m1;
1380 setjmp(failpt); /* Bruce Evans' fix */
1381 failpt = m1;
1382 if (setjmp(failpt) || yyparse() || intr) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001383 DBGPRINTF(("ONECOMMAND: this is not good.\n"));
1384
Eric Andersenff9eee42001-06-29 04:57:14 +00001385 while (e.oenv)
1386 quitenv();
1387 scraphere();
1388 if (!interactive && intr)
1389 leave();
1390 inparse = 0;
1391 intr = 0;
1392 return;
1393 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001394
Eric Andersenff9eee42001-06-29 04:57:14 +00001395 inparse = 0;
1396 brklist = 0;
1397 intr = 0;
1398 execflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001399
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00001400 if (!FLAG['n']) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001401 DBGPRINTF(("ONECOMMAND: calling execute, t=outtree=%p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00001402 outtree));
Eric Andersenff9eee42001-06-29 04:57:14 +00001403 execute(outtree, NOPIPE, NOPIPE, 0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001404 }
1405
Eric Andersenff9eee42001-06-29 04:57:14 +00001406 if (!interactive && intr) {
1407 execflg = 0;
1408 leave();
1409 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001410
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001411 i = trapset;
1412 if (i != 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001413 trapset = 0;
1414 runtrap(i);
1415 }
1416}
1417
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001418static int newenv(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00001419{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001420 struct env *ep;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001421
1422 DBGPRINTF(("NEWENV: f=%d (indicates quitenv and return)\n", f));
Eric Andersenff9eee42001-06-29 04:57:14 +00001423
1424 if (f) {
1425 quitenv();
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001426 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001427 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001428
Eric Andersenff9eee42001-06-29 04:57:14 +00001429 ep = (struct env *) space(sizeof(*ep));
1430 if (ep == NULL) {
1431 while (e.oenv)
1432 quitenv();
1433 fail();
1434 }
1435 *ep = e;
1436 e.oenv = ep;
1437 e.errpt = errpt;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001438
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001439 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001440}
1441
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001442static void quitenv(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001443{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001444 struct env *ep;
1445 int fd;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001446
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001447 DBGPRINTF(("QUITENV: e.oenv=%p\n", e.oenv));
Eric Andersenff9eee42001-06-29 04:57:14 +00001448
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001449 ep = e.oenv;
1450 if (ep != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001451 fd = e.iofd;
1452 e = *ep;
1453 /* should close `'d files */
1454 DELETE(ep);
1455 while (--fd >= e.iofd)
1456 close(fd);
1457 }
1458}
1459
1460/*
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001461 * Is character c in s?
Eric Andersenff9eee42001-06-29 04:57:14 +00001462 */
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001463static int any(int c, const char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00001464{
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001465 while (*s)
1466 if (*s++ == c)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001467 return 1;
1468 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001469}
1470
1471/*
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001472 * Is any character from s1 in s2?
Eric Andersenff9eee42001-06-29 04:57:14 +00001473 */
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001474static int anys(const char *s1, const char *s2)
Eric Andersenff9eee42001-06-29 04:57:14 +00001475{
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001476 while (*s1)
1477 if (any(*s1++, s2))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001478 return 1;
1479 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001480}
1481
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001482static char *putn(int n)
Eric Andersenff9eee42001-06-29 04:57:14 +00001483{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001484 return itoa(n);
Eric Andersenff9eee42001-06-29 04:57:14 +00001485}
1486
Eric Andersen8401eea2004-08-04 19:16:54 +00001487static void next(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00001488{
1489 PUSHIO(afile, f, filechar);
1490}
1491
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001492static void onintr(int s) /* ANSI C requires a parameter */
Eric Andersenff9eee42001-06-29 04:57:14 +00001493{
1494 signal(SIGINT, onintr);
1495 intr = 1;
1496 if (interactive) {
1497 if (inparse) {
1498 prs("\n");
1499 fail();
1500 }
Eric Andersen8401eea2004-08-04 19:16:54 +00001501 } else if (heedint) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001502 execflg = 0;
1503 leave();
1504 }
1505}
1506
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001507
Eric Andersenff9eee42001-06-29 04:57:14 +00001508/* -------- gmatch.c -------- */
1509/*
1510 * int gmatch(string, pattern)
1511 * char *string, *pattern;
1512 *
1513 * Match a pattern as in sh(1).
1514 */
1515
1516#define CMASK 0377
1517#define QUOTE 0200
Denis Vlasenko55f30b02007-03-24 22:42:29 +00001518#define QMASK (CMASK & ~QUOTE)
Eric Andersen8401eea2004-08-04 19:16:54 +00001519#define NOT '!' /* might use ^ */
Eric Andersenff9eee42001-06-29 04:57:14 +00001520
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001521static const char *cclass(const char *p, int sub)
1522{
1523 int c, d, not, found;
1524
1525 not = (*p == NOT);
1526 if (not != 0)
1527 p++;
1528 found = not;
1529 do {
1530 if (*p == '\0')
1531 return NULL;
1532 c = *p & CMASK;
1533 if (p[1] == '-' && p[2] != ']') {
1534 d = p[2] & CMASK;
1535 p++;
1536 } else
1537 d = c;
1538 if (c == sub || (c <= sub && sub <= d))
1539 found = !not;
1540 } while (*++p != ']');
1541 return found ? p + 1 : NULL;
1542}
1543
1544static int gmatch(const char *s, const char *p)
Eric Andersenff9eee42001-06-29 04:57:14 +00001545{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001546 int sc, pc;
Eric Andersenff9eee42001-06-29 04:57:14 +00001547
1548 if (s == NULL || p == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001549 return 0;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001550
Eric Andersenff9eee42001-06-29 04:57:14 +00001551 while ((pc = *p++ & CMASK) != '\0') {
1552 sc = *s++ & QMASK;
1553 switch (pc) {
1554 case '[':
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001555 p = cclass(p, sc);
1556 if (p == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001557 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001558 break;
1559
1560 case '?':
1561 if (sc == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001562 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001563 break;
1564
1565 case '*':
1566 s--;
1567 do {
1568 if (*p == '\0' || gmatch(s, p))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001569 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001570 } while (*s++ != '\0');
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001571 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001572
1573 default:
Eric Andersen8401eea2004-08-04 19:16:54 +00001574 if (sc != (pc & ~QUOTE))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001575 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001576 }
1577 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001578 return *s == '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00001579}
1580
Eric Andersenff9eee42001-06-29 04:57:14 +00001581
Eric Andersenff9eee42001-06-29 04:57:14 +00001582/* -------- csyn.c -------- */
1583/*
1584 * shell: syntax (C version)
1585 */
1586
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001587static void yyerror(const char *s) ATTRIBUTE_NORETURN;
1588static void yyerror(const char *s)
1589{
1590 yynerrs++;
1591 if (interactive && e.iop <= iostack) {
1592 multiline = 0;
1593 while (eofc() == 0 && yylex(0) != '\n');
1594 }
1595 err(s);
1596 fail();
1597}
1598
1599static void zzerr(void) ATTRIBUTE_NORETURN;
1600static void zzerr(void)
1601{
1602 yyerror("syntax error");
1603}
1604
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001605int yyparse(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001606{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001607 DBGPRINTF7(("YYPARSE: enter...\n"));
1608
Eric Andersen8401eea2004-08-04 19:16:54 +00001609 startl = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001610 peeksym = 0;
1611 yynerrs = 0;
1612 outtree = c_list();
1613 musthave('\n', 0);
Eric Andersen8401eea2004-08-04 19:16:54 +00001614 return (yynerrs != 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001615}
1616
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001617static struct op *pipeline(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001618{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001619 struct op *t, *p;
1620 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001621
1622 DBGPRINTF7(("PIPELINE: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001623
1624 t = command(cf);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001625
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001626 DBGPRINTF9(("PIPELINE: t=%p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001627
Eric Andersenff9eee42001-06-29 04:57:14 +00001628 if (t != NULL) {
1629 while ((c = yylex(0)) == '|') {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001630 p = command(CONTIN);
1631 if (p == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001632 DBGPRINTF8(("PIPELINE: error!\n"));
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001633 zzerr();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001634 }
1635
Eric Andersenff9eee42001-06-29 04:57:14 +00001636 if (t->type != TPAREN && t->type != TCOM) {
1637 /* shell statement */
1638 t = block(TPAREN, t, NOBLOCK, NOWORDS);
1639 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001640
Eric Andersenff9eee42001-06-29 04:57:14 +00001641 t = block(TPIPE, t, p, NOWORDS);
1642 }
1643 peeksym = c;
1644 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001645
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001646 DBGPRINTF7(("PIPELINE: returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001647 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001648}
1649
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001650static struct op *andor(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001651{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001652 struct op *t, *p;
1653 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001654
1655 DBGPRINTF7(("ANDOR: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001656
1657 t = pipeline(0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001658
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001659 DBGPRINTF9(("ANDOR: t=%p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001660
Eric Andersenff9eee42001-06-29 04:57:14 +00001661 if (t != NULL) {
1662 while ((c = yylex(0)) == LOGAND || c == LOGOR) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001663 p = pipeline(CONTIN);
1664 if (p == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001665 DBGPRINTF8(("ANDOR: error!\n"));
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001666 zzerr();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001667 }
1668
Eric Andersen8401eea2004-08-04 19:16:54 +00001669 t = block(c == LOGAND ? TAND : TOR, t, p, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001670 } /* WHILE */
1671
Eric Andersenff9eee42001-06-29 04:57:14 +00001672 peeksym = c;
1673 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001674
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001675 DBGPRINTF7(("ANDOR: returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001676 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001677}
1678
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001679static struct op *c_list(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001680{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001681 struct op *t, *p;
1682 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001683
1684 DBGPRINTF7(("C_LIST: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001685
1686 t = andor();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001687
Eric Andersenff9eee42001-06-29 04:57:14 +00001688 if (t != NULL) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001689 peeksym = yylex(0);
1690 if (peeksym == '&')
Eric Andersenff9eee42001-06-29 04:57:14 +00001691 t = block(TASYNC, t, NOBLOCK, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001692
Eric Andersen8401eea2004-08-04 19:16:54 +00001693 while ((c = yylex(0)) == ';' || c == '&'
1694 || (multiline && c == '\n')) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001695
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001696 p = andor();
1697 if (p== NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001698 return t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001699
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001700 peeksym = yylex(0);
1701 if (peeksym == '&')
Eric Andersenff9eee42001-06-29 04:57:14 +00001702 p = block(TASYNC, p, NOBLOCK, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001703
Eric Andersenff9eee42001-06-29 04:57:14 +00001704 t = list(t, p);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001705 } /* WHILE */
1706
Eric Andersenff9eee42001-06-29 04:57:14 +00001707 peeksym = c;
1708 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001709 /* IF */
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001710 DBGPRINTF7(("C_LIST: returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001711 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001712}
1713
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001714static int synio(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001715{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001716 struct ioword *iop;
1717 int i;
1718 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001719
1720 DBGPRINTF7(("SYNIO: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001721
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001722 c = yylex(cf);
1723 if (c != '<' && c != '>') {
Eric Andersenff9eee42001-06-29 04:57:14 +00001724 peeksym = c;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001725 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001726 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001727
Eric Andersenff9eee42001-06-29 04:57:14 +00001728 i = yylval.i;
1729 musthave(WORD, 0);
1730 iop = io(iounit, i, yylval.cp);
1731 iounit = IODEFAULT;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001732
Eric Andersenff9eee42001-06-29 04:57:14 +00001733 if (i & IOHERE)
1734 markhere(yylval.cp, iop);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001735
1736 DBGPRINTF7(("SYNIO: returning 1\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001737 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001738}
1739
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001740static void musthave(int c, int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001741{
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001742 peeksym = yylex(cf);
1743 if (peeksym != c) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001744 DBGPRINTF7(("MUSTHAVE: error!\n"));
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001745 zzerr();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001746 }
1747
Eric Andersenff9eee42001-06-29 04:57:14 +00001748 peeksym = 0;
1749}
1750
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001751static struct op *simple(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001752{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001753 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001754
1755 t = NULL;
1756 for (;;) {
1757 switch (peeksym = yylex(0)) {
1758 case '<':
1759 case '>':
1760 (void) synio(0);
1761 break;
1762
1763 case WORD:
1764 if (t == NULL) {
1765 t = newtp();
1766 t->type = TCOM;
1767 }
1768 peeksym = 0;
1769 word(yylval.cp);
1770 break;
1771
1772 default:
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001773 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001774 }
1775 }
1776}
1777
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001778static struct op *nested(int type, int mark)
Eric Andersenff9eee42001-06-29 04:57:14 +00001779{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001780 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001781
1782 DBGPRINTF3(("NESTED: enter, type=%d, mark=%d\n", type, mark));
Eric Andersenff9eee42001-06-29 04:57:14 +00001783
1784 multiline++;
1785 t = c_list();
1786 musthave(mark, 0);
1787 multiline--;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001788 return block(type, t, NOBLOCK, NOWORDS);
Eric Andersenff9eee42001-06-29 04:57:14 +00001789}
1790
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001791static struct op *command(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001792{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001793 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001794 struct wdblock *iosave;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001795 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001796
1797 DBGPRINTF(("COMMAND: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001798
1799 iosave = iolist;
1800 iolist = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001801
Eric Andersenff9eee42001-06-29 04:57:14 +00001802 if (multiline)
1803 cf |= CONTIN;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001804
Eric Andersenff9eee42001-06-29 04:57:14 +00001805 while (synio(cf))
1806 cf = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001807
1808 c = yylex(cf);
1809
1810 switch (c) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001811 default:
1812 peeksym = c;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001813 t = simple();
1814 if (t == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001815 if (iolist == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001816 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001817 t = newtp();
1818 t->type = TCOM;
1819 }
1820 break;
1821
1822 case '(':
1823 t = nested(TPAREN, ')');
1824 break;
1825
1826 case '{':
1827 t = nested(TBRACE, '}');
1828 break;
1829
1830 case FOR:
1831 t = newtp();
1832 t->type = TFOR;
1833 musthave(WORD, 0);
1834 startl = 1;
1835 t->str = yylval.cp;
1836 multiline++;
1837 t->words = wordlist();
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001838 c = yylex(0);
1839 if (c != '\n' && c != ';')
Eric Andersenff9eee42001-06-29 04:57:14 +00001840 peeksym = c;
1841 t->left = dogroup(0);
1842 multiline--;
1843 break;
1844
1845 case WHILE:
1846 case UNTIL:
1847 multiline++;
1848 t = newtp();
Eric Andersen8401eea2004-08-04 19:16:54 +00001849 t->type = c == WHILE ? TWHILE : TUNTIL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001850 t->left = c_list();
1851 t->right = dogroup(1);
1852 t->words = NULL;
1853 multiline--;
1854 break;
1855
1856 case CASE:
1857 t = newtp();
1858 t->type = TCASE;
1859 musthave(WORD, 0);
1860 t->str = yylval.cp;
1861 startl++;
1862 multiline++;
1863 musthave(IN, CONTIN);
1864 startl++;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001865
Eric Andersenff9eee42001-06-29 04:57:14 +00001866 t->left = caselist();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001867
Eric Andersenff9eee42001-06-29 04:57:14 +00001868 musthave(ESAC, 0);
1869 multiline--;
1870 break;
1871
1872 case IF:
1873 multiline++;
1874 t = newtp();
1875 t->type = TIF;
1876 t->left = c_list();
1877 t->right = thenpart();
1878 musthave(FI, 0);
1879 multiline--;
1880 break;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001881
1882 case DOT:
1883 t = newtp();
1884 t->type = TDOT;
1885
1886 musthave(WORD, 0); /* gets name of file */
1887 DBGPRINTF7(("COMMAND: DOT clause, yylval.cp is %s\n", yylval.cp));
1888
1889 word(yylval.cp); /* add word to wdlist */
1890 word(NOWORD); /* terminate wdlist */
1891 t->words = copyw(); /* dup wdlist */
1892 break;
1893
Eric Andersenff9eee42001-06-29 04:57:14 +00001894 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001895
Eric Andersen8401eea2004-08-04 19:16:54 +00001896 while (synio(0));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001897
Eric Andersenff9eee42001-06-29 04:57:14 +00001898 t = namelist(t);
1899 iolist = iosave;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001900
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001901 DBGPRINTF(("COMMAND: returning %p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001902
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001903 return t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001904}
1905
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001906static struct op *dowholefile(int type, int mark)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001907{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001908 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001909
1910 DBGPRINTF(("DOWHOLEFILE: enter, type=%d, mark=%d\n", type, mark));
1911
1912 multiline++;
1913 t = c_list();
1914 multiline--;
1915 t = block(type, t, NOBLOCK, NOWORDS);
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001916 DBGPRINTF(("DOWHOLEFILE: return t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001917 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001918}
1919
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001920static struct op *dogroup(int onlydone)
Eric Andersenff9eee42001-06-29 04:57:14 +00001921{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001922 int c;
1923 struct op *mylist;
Eric Andersenff9eee42001-06-29 04:57:14 +00001924
1925 c = yylex(CONTIN);
1926 if (c == DONE && onlydone)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001927 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001928 if (c != DO)
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001929 zzerr();
Eric Andersenff9eee42001-06-29 04:57:14 +00001930 mylist = c_list();
1931 musthave(DONE, 0);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001932 return mylist;
Eric Andersenff9eee42001-06-29 04:57:14 +00001933}
1934
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001935static struct op *thenpart(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001936{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001937 int c;
1938 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001939
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001940 c = yylex(0);
1941 if (c != THEN) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001942 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001943 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001944 }
1945 t = newtp();
1946 t->type = 0;
1947 t->left = c_list();
1948 if (t->left == NULL)
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001949 zzerr();
Eric Andersenff9eee42001-06-29 04:57:14 +00001950 t->right = elsepart();
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001951 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001952}
1953
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001954static struct op *elsepart(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001955{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001956 int c;
1957 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001958
1959 switch (c = yylex(0)) {
1960 case ELSE:
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001961 t = c_list();
1962 if (t == NULL)
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001963 zzerr();
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001964 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001965
1966 case ELIF:
1967 t = newtp();
1968 t->type = TELIF;
1969 t->left = c_list();
1970 t->right = thenpart();
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001971 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001972
1973 default:
1974 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001975 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001976 }
1977}
1978
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001979static struct op *caselist(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001980{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001981 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001982
1983 t = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001984 while ((peeksym = yylex(CONTIN)) != ESAC) {
1985 DBGPRINTF(("CASELIST, doing yylex, peeksym=%d\n", peeksym));
Eric Andersenff9eee42001-06-29 04:57:14 +00001986 t = list(t, casepart());
Eric Andersen12de6cf2004-08-04 19:19:10 +00001987 }
1988
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001989 DBGPRINTF(("CASELIST, returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001990 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001991}
1992
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001993static struct op *casepart(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001994{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001995 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001996
1997 DBGPRINTF7(("CASEPART: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001998
1999 t = newtp();
2000 t->type = TPAT;
2001 t->words = pattern();
2002 musthave(')', 0);
2003 t->left = c_list();
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002004 peeksym = yylex(CONTIN);
2005 if (peeksym != ESAC)
Eric Andersenff9eee42001-06-29 04:57:14 +00002006 musthave(BREAK, CONTIN);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002007
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002008 DBGPRINTF7(("CASEPART: made newtp(TPAT, t=%p)\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002009
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002010 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002011}
2012
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002013static char **pattern(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002014{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002015 int c, cf;
Eric Andersenff9eee42001-06-29 04:57:14 +00002016
2017 cf = CONTIN;
2018 do {
2019 musthave(WORD, cf);
2020 word(yylval.cp);
2021 cf = 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002022 c = yylex(0);
2023 } while (c == '|');
Eric Andersenff9eee42001-06-29 04:57:14 +00002024 peeksym = c;
2025 word(NOWORD);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002026
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002027 return copyw();
Eric Andersenff9eee42001-06-29 04:57:14 +00002028}
2029
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002030static char **wordlist(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002031{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002032 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002033
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002034 c = yylex(0);
2035 if (c != IN) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002036 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002037 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00002038 }
2039 startl = 0;
2040 while ((c = yylex(0)) == WORD)
2041 word(yylval.cp);
2042 word(NOWORD);
2043 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002044 return copyw();
Eric Andersenff9eee42001-06-29 04:57:14 +00002045}
2046
2047/*
2048 * supporting functions
2049 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002050static struct op *list(struct op *t1, struct op *t2)
Eric Andersenff9eee42001-06-29 04:57:14 +00002051{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002052 DBGPRINTF7(("LIST: enter, t1=%p, t2=%p\n", t1, t2));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002053
Eric Andersenff9eee42001-06-29 04:57:14 +00002054 if (t1 == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002055 return t2;
Eric Andersenff9eee42001-06-29 04:57:14 +00002056 if (t2 == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002057 return t1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002058
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002059 return block(TLIST, t1, t2, NOWORDS);
Eric Andersenff9eee42001-06-29 04:57:14 +00002060}
2061
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002062static struct op *block(int type, struct op *t1, struct op *t2, char **wp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002063{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002064 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002065
2066 DBGPRINTF7(("BLOCK: enter, type=%d (%s)\n", type, T_CMD_NAMES[type]));
Eric Andersenff9eee42001-06-29 04:57:14 +00002067
2068 t = newtp();
2069 t->type = type;
2070 t->left = t1;
2071 t->right = t2;
2072 t->words = wp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002073
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002074 DBGPRINTF7(("BLOCK: inserted %p between %p and %p\n", t, t1,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002075 t2));
2076
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002077 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002078}
2079
Eric Andersen12de6cf2004-08-04 19:19:10 +00002080/* See if given string is a shell multiline (FOR, IF, etc) */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002081static int rlookup(char *n)
Eric Andersenff9eee42001-06-29 04:57:14 +00002082{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002083 const struct res *rp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002084
2085 DBGPRINTF7(("RLOOKUP: enter, n is %s\n", n));
Eric Andersenff9eee42001-06-29 04:57:14 +00002086
2087 for (rp = restab; rp->r_name; rp++)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002088 if (strcmp(rp->r_name, n) == 0) {
2089 DBGPRINTF7(("RLOOKUP: match, returning %d\n", rp->r_val));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002090 return rp->r_val; /* Return numeric code for shell multiline */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002091 }
2092
2093 DBGPRINTF7(("RLOOKUP: NO match, returning 0\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002094 return 0; /* Not a shell multiline */
Eric Andersenff9eee42001-06-29 04:57:14 +00002095}
2096
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002097static struct op *newtp(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002098{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002099 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002100
Eric Andersen8401eea2004-08-04 19:16:54 +00002101 t = (struct op *) tree(sizeof(*t));
Eric Andersenff9eee42001-06-29 04:57:14 +00002102 t->type = 0;
2103 t->words = NULL;
2104 t->ioact = NULL;
2105 t->left = NULL;
2106 t->right = NULL;
2107 t->str = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002108
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002109 DBGPRINTF3(("NEWTP: allocated %p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002110
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002111 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002112}
2113
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002114static struct op *namelist(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00002115{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002116 DBGPRINTF7(("NAMELIST: enter, t=%p, type %s, iolist=%p\n", t,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002117 T_CMD_NAMES[t->type], iolist));
2118
Eric Andersenff9eee42001-06-29 04:57:14 +00002119 if (iolist) {
Eric Andersen8401eea2004-08-04 19:16:54 +00002120 iolist = addword((char *) NULL, iolist);
Eric Andersenff9eee42001-06-29 04:57:14 +00002121 t->ioact = copyio();
2122 } else
2123 t->ioact = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002124
Eric Andersenff9eee42001-06-29 04:57:14 +00002125 if (t->type != TCOM) {
2126 if (t->type != TPAREN && t->ioact != NULL) {
2127 t = block(TPAREN, t, NOBLOCK, NOWORDS);
2128 t->ioact = t->left->ioact;
2129 t->left->ioact = NULL;
2130 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002131 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002132 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002133
Eric Andersenff9eee42001-06-29 04:57:14 +00002134 word(NOWORD);
2135 t->words = copyw();
Eric Andersen12de6cf2004-08-04 19:19:10 +00002136
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002137 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002138}
2139
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002140static char **copyw(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002141{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002142 char **wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00002143
2144 wd = getwords(wdlist);
2145 wdlist = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002146 return wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00002147}
2148
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002149static void word(char *cp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002150{
2151 wdlist = addword(cp, wdlist);
2152}
2153
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002154static struct ioword **copyio(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002155{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002156 struct ioword **iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002157
2158 iop = (struct ioword **) getwords(iolist);
2159 iolist = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002160 return iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002161}
2162
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002163static struct ioword *io(int u, int f, char *cp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002164{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002165 struct ioword *iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002166
2167 iop = (struct ioword *) tree(sizeof(*iop));
2168 iop->io_unit = u;
2169 iop->io_flag = f;
2170 iop->io_name = cp;
Eric Andersen8401eea2004-08-04 19:16:54 +00002171 iolist = addword((char *) iop, iolist);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002172 return iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002173}
2174
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002175static int yylex(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00002176{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002177 int c, c1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002178 int atstart;
2179
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002180 c = peeksym;
2181 if (c > 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002182 peeksym = 0;
2183 if (c == '\n')
2184 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002185 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002186 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002187
Eric Andersenff9eee42001-06-29 04:57:14 +00002188 nlseen = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002189 atstart = startl;
2190 startl = 0;
2191 yylval.i = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002192 e.linep = line;
2193
2194/* MALAMO */
2195 line[LINELIM - 1] = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00002196
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002197 loop:
Eric Andersen12de6cf2004-08-04 19:19:10 +00002198 while ((c = my_getc(0)) == ' ' || c == '\t') /* Skip whitespace */
2199 ;
2200
Eric Andersenff9eee42001-06-29 04:57:14 +00002201 switch (c) {
2202 default:
2203 if (any(c, "0123456789")) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002204 c1 = my_getc(0);
2205 unget(c1);
Eric Andersenff9eee42001-06-29 04:57:14 +00002206 if (c1 == '<' || c1 == '>') {
2207 iounit = c - '0';
2208 goto loop;
2209 }
2210 *e.linep++ = c;
2211 c = c1;
2212 }
2213 break;
2214
Eric Andersen12de6cf2004-08-04 19:19:10 +00002215 case '#': /* Comment, skip to next newline or End-of-string */
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002216 while ((c = my_getc(0)) != '\0' && c != '\n');
Eric Andersenff9eee42001-06-29 04:57:14 +00002217 unget(c);
2218 goto loop;
2219
2220 case 0:
Eric Andersen12de6cf2004-08-04 19:19:10 +00002221 DBGPRINTF5(("YYLEX: return 0, c=%d\n", c));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002222 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002223
2224 case '$':
Eric Andersen12de6cf2004-08-04 19:19:10 +00002225 DBGPRINTF9(("YYLEX: found $\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00002226 *e.linep++ = c;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002227 c = my_getc(0);
2228 if (c == '{') {
2229 c = collect(c, '}');
2230 if (c != '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002231 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002232 goto pack;
2233 }
2234 break;
2235
2236 case '`':
2237 case '\'':
2238 case '"':
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002239 c = collect(c, c);
2240 if (c != '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002241 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002242 goto pack;
2243
2244 case '|':
2245 case '&':
2246 case ';':
Eric Andersenff9eee42001-06-29 04:57:14 +00002247 startl = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002248 /* If more chars process them, else return NULL char */
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002249 c1 = dual(c);
2250 if (c1 != '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002251 return c1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002252 return c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002253
Eric Andersenff9eee42001-06-29 04:57:14 +00002254 case '^':
2255 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002256 return '|';
Eric Andersenff9eee42001-06-29 04:57:14 +00002257 case '>':
2258 case '<':
2259 diag(c);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002260 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002261
2262 case '\n':
2263 nlseen++;
2264 gethere();
2265 startl = 1;
2266 if (multiline || cf & CONTIN) {
2267 if (interactive && e.iop <= iostack) {
Denis Vlasenko38f63192007-01-22 09:03:07 +00002268#if ENABLE_FEATURE_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00002269 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00002270#else
Eric Andersen8401eea2004-08-04 19:16:54 +00002271 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00002272#endif
2273 }
2274 if (cf & CONTIN)
2275 goto loop;
2276 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002277 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002278
2279 case '(':
2280 case ')':
2281 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002282 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002283 }
2284
2285 unget(c);
2286
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002287 pack:
2288 while ((c = my_getc(0)) != '\0' && !any(c, "`$ '\"\t;&<>()|^\n")) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002289 if (e.linep >= elinep)
2290 err("word too long");
2291 else
2292 *e.linep++ = c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002293 };
2294
Eric Andersenff9eee42001-06-29 04:57:14 +00002295 unget(c);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002296
Eric Andersen8401eea2004-08-04 19:16:54 +00002297 if (any(c, "\"'`$"))
Eric Andersenff9eee42001-06-29 04:57:14 +00002298 goto loop;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002299
Eric Andersenff9eee42001-06-29 04:57:14 +00002300 *e.linep++ = '\0';
Eric Andersen12de6cf2004-08-04 19:19:10 +00002301
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002302 if (atstart) {
2303 c = rlookup(line);
2304 if (c != 0) {
2305 startl = 1;
2306 return c;
2307 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002308 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002309
Eric Andersenff9eee42001-06-29 04:57:14 +00002310 yylval.cp = strsave(line, areanum);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002311 return WORD;
Eric Andersenff9eee42001-06-29 04:57:14 +00002312}
2313
Eric Andersen12de6cf2004-08-04 19:19:10 +00002314
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002315static int collect(int c, int c1)
Eric Andersenff9eee42001-06-29 04:57:14 +00002316{
2317 char s[2];
2318
Eric Andersen12de6cf2004-08-04 19:19:10 +00002319 DBGPRINTF8(("COLLECT: enter, c=%d, c1=%d\n", c, c1));
2320
Eric Andersenff9eee42001-06-29 04:57:14 +00002321 *e.linep++ = c;
2322 while ((c = my_getc(c1)) != c1) {
2323 if (c == 0) {
2324 unget(c);
2325 s[0] = c1;
2326 s[1] = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00002327 prs("no closing ");
2328 yyerror(s);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002329 return YYERRCODE;
Eric Andersenff9eee42001-06-29 04:57:14 +00002330 }
2331 if (interactive && c == '\n' && e.iop <= iostack) {
Denis Vlasenko38f63192007-01-22 09:03:07 +00002332#if ENABLE_FEATURE_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00002333 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00002334#else
Eric Andersen8401eea2004-08-04 19:16:54 +00002335 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00002336#endif
2337 }
2338 *e.linep++ = c;
2339 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002340
Eric Andersenff9eee42001-06-29 04:57:14 +00002341 *e.linep++ = c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002342
2343 DBGPRINTF8(("COLLECT: return 0, line is %s\n", line));
2344
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002345 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002346}
2347
Eric Andersen12de6cf2004-08-04 19:19:10 +00002348/* "multiline commands" helper func */
2349/* see if next 2 chars form a shell multiline */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002350static int dual(int c)
Eric Andersenff9eee42001-06-29 04:57:14 +00002351{
2352 char s[3];
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002353 char *cp = s;
Eric Andersenff9eee42001-06-29 04:57:14 +00002354
Eric Andersen12de6cf2004-08-04 19:19:10 +00002355 DBGPRINTF8(("DUAL: enter, c=%d\n", c));
2356
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002357 *cp++ = c; /* c is the given "peek" char */
2358 *cp++ = my_getc(0); /* get next char of input */
2359 *cp = '\0'; /* add EOS marker */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002360
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002361 c = rlookup(s); /* see if 2 chars form a shell multiline */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002362 if (c == 0)
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002363 unget(*--cp); /* String is not a shell multiline, put peek char back */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002364
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002365 return c; /* String is multiline, return numeric multiline (restab) code */
Eric Andersenff9eee42001-06-29 04:57:14 +00002366}
2367
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002368static void diag(int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00002369{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002370 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002371
2372 DBGPRINTF8(("DIAG: enter, ec=%d\n", ec));
Eric Andersenff9eee42001-06-29 04:57:14 +00002373
2374 c = my_getc(0);
2375 if (c == '>' || c == '<') {
2376 if (c != ec)
2377 zzerr();
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002378 yylval.i = (ec == '>' ? IOWRITE | IOCAT : IOHERE);
Eric Andersenff9eee42001-06-29 04:57:14 +00002379 c = my_getc(0);
2380 } else
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002381 yylval.i = (ec == '>' ? IOWRITE : IOREAD);
Eric Andersenff9eee42001-06-29 04:57:14 +00002382 if (c != '&' || yylval.i == IOHERE)
2383 unget(c);
2384 else
2385 yylval.i |= IODUP;
2386}
2387
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002388static char *tree(unsigned size)
Eric Andersenff9eee42001-06-29 04:57:14 +00002389{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002390 char *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002391
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002392 t = getcell(size);
2393 if (t == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002394 DBGPRINTF2(("TREE: getcell(%d) failed!\n", size));
Eric Andersenff9eee42001-06-29 04:57:14 +00002395 prs("command line too complicated\n");
2396 fail();
2397 /* NOTREACHED */
2398 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002399 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002400}
2401
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002402
Eric Andersenff9eee42001-06-29 04:57:14 +00002403/* VARARGS1 */
2404/* ARGSUSED */
2405
2406/* -------- exec.c -------- */
2407
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002408static struct op **find1case(struct op *t, const char *w)
2409{
2410 struct op *t1;
2411 struct op **tp;
2412 char **wp;
2413 char *cp;
2414
2415 if (t == NULL) {
2416 DBGPRINTF3(("FIND1CASE: enter, t==NULL, returning.\n"));
2417 return NULL;
2418 }
2419
2420 DBGPRINTF3(("FIND1CASE: enter, t->type=%d (%s)\n", t->type,
2421 T_CMD_NAMES[t->type]));
2422
2423 if (t->type == TLIST) {
2424 tp = find1case(t->left, w);
2425 if (tp != NULL) {
2426 DBGPRINTF3(("FIND1CASE: found one to the left, returning tp=%p\n", tp));
2427 return tp;
2428 }
2429 t1 = t->right; /* TPAT */
2430 } else
2431 t1 = t;
2432
2433 for (wp = t1->words; *wp;) {
2434 cp = evalstr(*wp++, DOSUB);
2435 if (cp && gmatch(w, cp)) {
2436 DBGPRINTF3(("FIND1CASE: returning &t1->left= %p.\n",
2437 &t1->left));
2438 return &t1->left;
2439 }
2440 }
2441
2442 DBGPRINTF(("FIND1CASE: returning NULL\n"));
2443 return NULL;
2444}
2445
2446static struct op *findcase(struct op *t, const char *w)
2447{
2448 struct op **tp;
2449
2450 tp = find1case(t, w);
2451 return tp != NULL ? *tp : NULL;
2452}
2453
Eric Andersenff9eee42001-06-29 04:57:14 +00002454/*
2455 * execute tree
2456 */
2457
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002458static int execute(struct op *t, int *pin, int *pout, int act)
Eric Andersenff9eee42001-06-29 04:57:14 +00002459{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002460 struct op *t1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002461 volatile int i, rv, a;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002462 const char *cp;
2463 char **wp, **wp2;
Eric Andersenff9eee42001-06-29 04:57:14 +00002464 struct var *vp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002465 struct op *outtree_save;
Eric Andersenff9eee42001-06-29 04:57:14 +00002466 struct brkcon bc;
2467
2468#if __GNUC__
2469 /* Avoid longjmp clobbering */
2470 (void) &wp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002471#endif
Eric Andersenff9eee42001-06-29 04:57:14 +00002472
Eric Andersen12de6cf2004-08-04 19:19:10 +00002473 if (t == NULL) {
2474 DBGPRINTF4(("EXECUTE: enter, t==null, returning.\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002475 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002476 }
2477
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002478 DBGPRINTF(("EXECUTE: t=%p, t->type=%d (%s), t->words is %s\n", t,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002479 t->type, T_CMD_NAMES[t->type],
2480 ((t->words == NULL) ? "NULL" : t->words[0])));
2481
Eric Andersenff9eee42001-06-29 04:57:14 +00002482 rv = 0;
2483 a = areanum++;
2484 wp = (wp2 = t->words) != NULL
Eric Andersen8401eea2004-08-04 19:16:54 +00002485 ? eval(wp2, t->type == TCOM ? DOALL : DOALL & ~DOKEY)
2486 : NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00002487
Eric Andersen8401eea2004-08-04 19:16:54 +00002488 switch (t->type) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002489 case TDOT:
2490 DBGPRINTF3(("EXECUTE: TDOT\n"));
2491
2492 outtree_save = outtree;
2493
2494 newfile(evalstr(t->words[0], DOALL));
2495
2496 t->left = dowholefile(TLIST, 0);
2497 t->right = NULL;
2498
2499 outtree = outtree_save;
2500
2501 if (t->left)
2502 rv = execute(t->left, pin, pout, 0);
2503 if (t->right)
2504 rv = execute(t->right, pin, pout, 0);
2505 break;
2506
Eric Andersenff9eee42001-06-29 04:57:14 +00002507 case TPAREN:
Eric Andersen737f5fb2003-03-14 16:05:59 +00002508 rv = execute(t->left, pin, pout, 0);
2509 break;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002510
Eric Andersenff9eee42001-06-29 04:57:14 +00002511 case TCOM:
Denis Vlasenko489f93e2007-02-01 01:43:16 +00002512 rv = forkexec(t, pin, pout, act, wp);
Eric Andersenff9eee42001-06-29 04:57:14 +00002513 break;
2514
2515 case TPIPE:
2516 {
Eric Andersen8401eea2004-08-04 19:16:54 +00002517 int pv[2];
2518
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002519 rv = openpipe(pv);
2520 if (rv < 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00002521 break;
2522 pv[0] = remap(pv[0]);
2523 pv[1] = remap(pv[1]);
2524 (void) execute(t->left, pin, pv, 0);
2525 rv = execute(t->right, pv, pout, 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002526 }
2527 break;
2528
2529 case TLIST:
2530 (void) execute(t->left, pin, pout, 0);
2531 rv = execute(t->right, pin, pout, 0);
2532 break;
2533
2534 case TASYNC:
Eric Andersen8401eea2004-08-04 19:16:54 +00002535 {
2536 int hinteractive = interactive;
Eric Andersenff9eee42001-06-29 04:57:14 +00002537
Eric Andersen12de6cf2004-08-04 19:19:10 +00002538 DBGPRINTF7(("EXECUTE: TASYNC clause, calling vfork()...\n"));
2539
Eric Andersen8401eea2004-08-04 19:16:54 +00002540 i = vfork();
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002541 if (i == 0) { /* child */
Eric Andersen8401eea2004-08-04 19:16:54 +00002542 signal(SIGINT, SIG_IGN);
2543 signal(SIGQUIT, SIG_IGN);
2544 if (interactive)
2545 signal(SIGTERM, SIG_DFL);
2546 interactive = 0;
2547 if (pin == NULL) {
2548 close(0);
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00002549 xopen(bb_dev_null, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00002550 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002551 _exit(execute(t->left, pin, pout, FEXEC));
Eric Andersenff9eee42001-06-29 04:57:14 +00002552 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002553 interactive = hinteractive;
2554 if (i != -1) {
2555 setval(lookup("!"), putn(i));
2556 if (pin != NULL)
2557 closepipe(pin);
2558 if (interactive) {
2559 prs(putn(i));
2560 prs("\n");
2561 }
2562 } else
2563 rv = -1;
2564 setstatus(rv);
Eric Andersenff9eee42001-06-29 04:57:14 +00002565 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002566 break;
2567
2568 case TOR:
2569 case TAND:
2570 rv = execute(t->left, pin, pout, 0);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002571 t1 = t->right;
2572 if (t1 != NULL && (rv == 0) == (t->type == TAND))
Eric Andersenff9eee42001-06-29 04:57:14 +00002573 rv = execute(t1, pin, pout, 0);
2574 break;
2575
2576 case TFOR:
2577 if (wp == NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00002578 wp = dolv + 1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002579 i = dolc;
2580 if (i < 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00002581 i = 0;
2582 } else {
2583 i = -1;
Eric Andersen8401eea2004-08-04 19:16:54 +00002584 while (*wp++ != NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00002585 }
2586 vp = lookup(t->str);
2587 while (setjmp(bc.brkpt))
2588 if (isbreak)
2589 goto broken;
2590 brkset(&bc);
2591 for (t1 = t->left; i-- && *wp != NULL;) {
2592 setval(vp, *wp++);
2593 rv = execute(t1, pin, pout, 0);
2594 }
2595 brklist = brklist->nextlev;
2596 break;
2597
2598 case TWHILE:
2599 case TUNTIL:
2600 while (setjmp(bc.brkpt))
2601 if (isbreak)
2602 goto broken;
2603 brkset(&bc);
2604 t1 = t->left;
2605 while ((execute(t1, pin, pout, 0) == 0) == (t->type == TWHILE))
2606 rv = execute(t->right, pin, pout, 0);
2607 brklist = brklist->nextlev;
2608 break;
2609
2610 case TIF:
2611 case TELIF:
Eric Andersen8401eea2004-08-04 19:16:54 +00002612 if (t->right != NULL) {
2613 rv = !execute(t->left, pin, pout, 0) ?
2614 execute(t->right->left, pin, pout, 0) :
2615 execute(t->right->right, pin, pout, 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002616 }
2617 break;
2618
2619 case TCASE:
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002620 cp = evalstr(t->str, DOSUB | DOTRIM);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002621 if (cp == NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00002622 cp = "";
Eric Andersen12de6cf2004-08-04 19:19:10 +00002623
2624 DBGPRINTF7(("EXECUTE: TCASE, t->str is %s, cp is %s\n",
2625 ((t->str == NULL) ? "NULL" : t->str),
2626 ((cp == NULL) ? "NULL" : cp)));
2627
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002628 t1 = findcase(t->left, cp);
2629 if (t1 != NULL) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002630 DBGPRINTF7(("EXECUTE: TCASE, calling execute(t=%p, t1=%p)...\n", t, t1));
Eric Andersenff9eee42001-06-29 04:57:14 +00002631 rv = execute(t1, pin, pout, 0);
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002632 DBGPRINTF7(("EXECUTE: TCASE, back from execute(t=%p, t1=%p)...\n", t, t1));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002633 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002634 break;
2635
2636 case TBRACE:
2637/*
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002638 iopp = t->ioact;
2639 if (i)
Eric Andersenff9eee42001-06-29 04:57:14 +00002640 while (*iopp)
2641 if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) {
2642 rv = -1;
2643 break;
2644 }
2645*/
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002646 if (rv >= 0) {
2647 t1 = t->left;
2648 if (t1) {
2649 rv = execute(t1, pin, pout, 0);
2650 }
2651 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002652 break;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002653
2654 };
Eric Andersenff9eee42001-06-29 04:57:14 +00002655
Denis Vlasenkoe4712752007-04-14 15:08:41 +00002656 broken:
Eric Andersenff9eee42001-06-29 04:57:14 +00002657 t->words = wp2;
2658 isbreak = 0;
2659 freehere(areanum);
2660 freearea(areanum);
2661 areanum = a;
2662 if (interactive && intr) {
2663 closeall();
2664 fail();
2665 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002666
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002667 i = trapset;
2668 if (i != 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002669 trapset = 0;
2670 runtrap(i);
2671 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002672
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002673 DBGPRINTF(("EXECUTE: returning from t=%p, rv=%d\n", t, rv));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002674 return rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00002675}
2676
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002677typedef int (*builtin_func_ptr)(struct op *);
2678
Denis Vlasenkoe4712752007-04-14 15:08:41 +00002679static builtin_func_ptr inbuilt(const char *s)
2680{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002681 const struct builtincmd *bp;
2682
Denis Vlasenko95cb3262007-04-09 03:06:34 +00002683 for (bp = builtincmds; bp->name; bp++)
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002684 if (strcmp(bp->name, s) == 0)
2685 return bp->builtinfunc;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002686 return NULL;
2687}
2688
2689static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002690{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002691 pid_t newpid;
Eric Andersenff9eee42001-06-29 04:57:14 +00002692 int i, rv;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002693 builtin_func_ptr shcom = NULL;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002694 int f;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002695 const char *cp = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00002696 struct ioword **iopp;
2697 int resetsig;
2698 char **owp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002699 int forked = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002700
2701 int *hpin = pin;
2702 int *hpout = pout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002703 char *hwp;
2704 int hinteractive;
2705 int hintr;
Eric Andersen8401eea2004-08-04 19:16:54 +00002706 struct brkcon *hbrklist;
Eric Andersenff9eee42001-06-29 04:57:14 +00002707 int hexecflg;
2708
2709#if __GNUC__
2710 /* Avoid longjmp clobbering */
2711 (void) &pin;
2712 (void) &pout;
2713 (void) &wp;
2714 (void) &shcom;
2715 (void) &cp;
2716 (void) &resetsig;
2717 (void) &owp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002718#endif
Eric Andersenff9eee42001-06-29 04:57:14 +00002719
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002720 DBGPRINTF(("FORKEXEC: t=%p, pin %p, pout %p, act %d\n", t, pin,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002721 pout, act));
2722 DBGPRINTF7(("FORKEXEC: t->words is %s\n",
2723 ((t->words == NULL) ? "NULL" : t->words[0])));
2724
Eric Andersenff9eee42001-06-29 04:57:14 +00002725 owp = wp;
2726 resetsig = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00002727 rv = -1; /* system-detected error */
Eric Andersenff9eee42001-06-29 04:57:14 +00002728 if (t->type == TCOM) {
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00002729 while (*wp++ != NULL)
2730 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00002731 cp = *wp;
2732
2733 /* strip all initial assignments */
2734 /* not correct wrt PATH=yyy command etc */
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00002735 if (FLAG['x']) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002736 DBGPRINTF9(("FORKEXEC: echo'ing, cp=%p, wp=%p, owp=%p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00002737 cp, wp, owp));
Eric Andersen8401eea2004-08-04 19:16:54 +00002738 echo(cp ? wp : owp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002739 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002740
Eric Andersenff9eee42001-06-29 04:57:14 +00002741 if (cp == NULL && t->ioact == NULL) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002742 while ((cp = *owp++) != NULL && assign(cp, COPYV))
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00002743 continue;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002744 DBGPRINTF(("FORKEXEC: returning setstatus()\n"));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002745 return setstatus(0);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002746 }
2747 if (cp != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002748 shcom = inbuilt(cp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002749 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002750 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002751
Eric Andersenff9eee42001-06-29 04:57:14 +00002752 t->words = wp;
2753 f = act;
Eric Andersenff9eee42001-06-29 04:57:14 +00002754
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002755 DBGPRINTF(("FORKEXEC: shcom %p, f&FEXEC 0x%x, owp %p\n", shcom,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002756 f & FEXEC, owp));
2757
2758 if (shcom == NULL && (f & FEXEC) == 0) {
2759 /* Save values in case the child process alters them */
Eric Andersenff9eee42001-06-29 04:57:14 +00002760 hpin = pin;
2761 hpout = pout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002762 hwp = *wp;
2763 hinteractive = interactive;
2764 hintr = intr;
2765 hbrklist = brklist;
2766 hexecflg = execflg;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002767
Eric Andersen12de6cf2004-08-04 19:19:10 +00002768 DBGPRINTF3(("FORKEXEC: calling vfork()...\n"));
2769
2770 newpid = vfork();
2771
2772 if (newpid == -1) {
Denis Vlasenko89f0b342006-11-18 22:04:09 +00002773 DBGPRINTF(("FORKEXEC: ERROR, cannot vfork()!\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002774 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002775 }
2776
Denis Vlasenko489f93e2007-02-01 01:43:16 +00002777 if (newpid > 0) { /* Parent */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002778 /* Restore values */
Eric Andersenff9eee42001-06-29 04:57:14 +00002779 pin = hpin;
2780 pout = hpout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002781 *wp = hwp;
2782 interactive = hinteractive;
2783 intr = hintr;
2784 brklist = hbrklist;
2785 execflg = hexecflg;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002786/* moved up
Eric Andersenff9eee42001-06-29 04:57:14 +00002787 if (i == -1)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002788 return rv;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002789*/
Eric Andersenff9eee42001-06-29 04:57:14 +00002790 if (pin != NULL)
2791 closepipe(pin);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002792
2793 return (pout == NULL ? setstatus(waitfor(newpid, 0)) : 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002794 }
2795
Eric Andersen12de6cf2004-08-04 19:19:10 +00002796 /* Must be the child process, pid should be 0 */
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002797 DBGPRINTF(("FORKEXEC: child process, shcom=%p\n", shcom));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002798
Eric Andersenff9eee42001-06-29 04:57:14 +00002799 if (interactive) {
2800 signal(SIGINT, SIG_IGN);
2801 signal(SIGQUIT, SIG_IGN);
2802 resetsig = 1;
2803 }
2804 interactive = 0;
2805 intr = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002806 forked = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002807 brklist = 0;
2808 execflg = 0;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002809 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002810
Eric Andersenff9eee42001-06-29 04:57:14 +00002811 if (owp != NULL)
2812 while ((cp = *owp++) != NULL && assign(cp, COPYV))
2813 if (shcom == NULL)
2814 export(lookup(cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002815
Eric Andersenff9eee42001-06-29 04:57:14 +00002816#ifdef COMPIPE
2817 if ((pin != NULL || pout != NULL) && shcom != NULL && shcom != doexec) {
2818 err("piping to/from shell builtins not yet done");
Eric Andersen12de6cf2004-08-04 19:19:10 +00002819 if (forked)
2820 _exit(-1);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002821 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002822 }
2823#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00002824
Eric Andersenff9eee42001-06-29 04:57:14 +00002825 if (pin != NULL) {
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00002826 xmove_fd(pin[0], 0);
2827 if (pin[1] != 0) close(pin[1]);
Eric Andersenff9eee42001-06-29 04:57:14 +00002828 }
2829 if (pout != NULL) {
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00002830 xmove_fd(pout[1], 1);
2831 if (pout[1] != 1) close(pout[0]);
Eric Andersenff9eee42001-06-29 04:57:14 +00002832 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002833
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002834 iopp = t->ioact;
2835 if (iopp != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002836 if (shcom != NULL && shcom != doexec) {
2837 prs(cp);
2838 err(": cannot redirect shell command");
Eric Andersen12de6cf2004-08-04 19:19:10 +00002839 if (forked)
2840 _exit(-1);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002841 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002842 }
2843 while (*iopp)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002844 if (iosetup(*iopp++, pin != NULL, pout != NULL)) {
2845 if (forked)
2846 _exit(rv);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002847 return rv;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002848 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002849 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002850
2851 if (shcom) {
2852 i = setstatus((*shcom) (t));
2853 if (forked)
2854 _exit(i);
2855 DBGPRINTF(("FORKEXEC: returning i=%d\n", i));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002856 return i;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002857 }
2858
Eric Andersenff9eee42001-06-29 04:57:14 +00002859 /* should use FIOCEXCL */
Eric Andersen8401eea2004-08-04 19:16:54 +00002860 for (i = FDBASE; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00002861 close(i);
2862 if (resetsig) {
2863 signal(SIGINT, SIG_DFL);
2864 signal(SIGQUIT, SIG_DFL);
2865 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002866
Eric Andersen12de6cf2004-08-04 19:19:10 +00002867 if (t->type == TPAREN)
2868 _exit(execute(t->left, NOPIPE, NOPIPE, FEXEC));
2869 if (wp[0] == NULL)
2870 _exit(0);
2871
Eric Andersenfd7a4c82004-09-02 23:13:10 +00002872 cp = rexecve(wp[0], wp, makenv(0, NULL));
Eric Andersen8401eea2004-08-04 19:16:54 +00002873 prs(wp[0]);
2874 prs(": ");
Eric Andersen12de6cf2004-08-04 19:19:10 +00002875 err(cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00002876 if (!execflg)
2877 trap[0] = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002878
2879 DBGPRINTF(("FORKEXEC: calling leave(), pid=%d\n", newpid));
2880
Eric Andersenff9eee42001-06-29 04:57:14 +00002881 leave();
2882 /* NOTREACHED */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002883 _exit(1);
Eric Andersenff9eee42001-06-29 04:57:14 +00002884}
2885
2886/*
2887 * 0< 1> are ignored as required
2888 * within pipelines.
2889 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002890static int iosetup(struct ioword *iop, int pipein, int pipeout)
Eric Andersenff9eee42001-06-29 04:57:14 +00002891{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002892 int u = -1;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002893 char *cp = NULL;
2894 const char *msg;
Eric Andersenff9eee42001-06-29 04:57:14 +00002895
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002896 DBGPRINTF(("IOSETUP: iop %p, pipein %i, pipeout %i\n", iop,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002897 pipein, pipeout));
2898
Eric Andersenff9eee42001-06-29 04:57:14 +00002899 if (iop->io_unit == IODEFAULT) /* take default */
Eric Andersen8401eea2004-08-04 19:16:54 +00002900 iop->io_unit = iop->io_flag & (IOREAD | IOHERE) ? 0 : 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002901
Eric Andersenff9eee42001-06-29 04:57:14 +00002902 if (pipein && iop->io_unit == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002903 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002904
Eric Andersenff9eee42001-06-29 04:57:14 +00002905 if (pipeout && iop->io_unit == 1)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002906 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002907
Eric Andersen8401eea2004-08-04 19:16:54 +00002908 msg = iop->io_flag & (IOREAD | IOHERE) ? "open" : "create";
Eric Andersenff9eee42001-06-29 04:57:14 +00002909 if ((iop->io_flag & IOHERE) == 0) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002910 cp = iop->io_name; /* huh?? */
2911 cp = evalstr(cp, DOSUB | DOTRIM);
2912 if (cp == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002913 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002914 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002915
Eric Andersenff9eee42001-06-29 04:57:14 +00002916 if (iop->io_flag & IODUP) {
2917 if (cp[1] || (!isdigit(*cp) && *cp != '-')) {
2918 prs(cp);
2919 err(": illegal >& argument");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002920 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002921 }
2922 if (*cp == '-')
2923 iop->io_flag = IOCLOSE;
Eric Andersen8401eea2004-08-04 19:16:54 +00002924 iop->io_flag &= ~(IOREAD | IOWRITE);
Eric Andersenff9eee42001-06-29 04:57:14 +00002925 }
2926 switch (iop->io_flag) {
2927 case IOREAD:
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00002928 u = open(cp, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00002929 break;
2930
2931 case IOHERE:
Eric Andersen8401eea2004-08-04 19:16:54 +00002932 case IOHERE | IOXHERE:
2933 u = herein(iop->io_name, iop->io_flag & IOXHERE);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002934 cp = (char*)"here file";
Eric Andersenff9eee42001-06-29 04:57:14 +00002935 break;
2936
Eric Andersen8401eea2004-08-04 19:16:54 +00002937 case IOWRITE | IOCAT:
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00002938 u = open(cp, O_WRONLY);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002939 if (u >= 0) {
Denis Vlasenkoea620772006-10-14 02:23:43 +00002940 lseek(u, (long) 0, SEEK_END);
Eric Andersenff9eee42001-06-29 04:57:14 +00002941 break;
2942 }
2943 case IOWRITE:
2944 u = creat(cp, 0666);
2945 break;
2946
2947 case IODUP:
Eric Andersen8401eea2004-08-04 19:16:54 +00002948 u = dup2(*cp - '0', iop->io_unit);
Eric Andersenff9eee42001-06-29 04:57:14 +00002949 break;
2950
2951 case IOCLOSE:
2952 close(iop->io_unit);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002953 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002954 }
2955 if (u < 0) {
2956 prs(cp);
2957 prs(": cannot ");
2958 warn(msg);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002959 return 1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002960 }
2961 if (u != iop->io_unit) {
2962 dup2(u, iop->io_unit);
2963 close(u);
Eric Andersenff9eee42001-06-29 04:57:14 +00002964 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002965 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002966}
2967
Eric Andersenff9eee42001-06-29 04:57:14 +00002968/*
2969 * Enter a new loop level (marked for break/continue).
2970 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002971static void brkset(struct brkcon *bc)
Eric Andersenff9eee42001-06-29 04:57:14 +00002972{
2973 bc->nextlev = brklist;
2974 brklist = bc;
2975}
2976
2977/*
2978 * Wait for the last process created.
2979 * Print a message for each process found
2980 * that was killed by a signal.
2981 * Ignore interrupt signals while waiting
2982 * unless `canintr' is true.
2983 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002984static int waitfor(int lastpid, int canintr)
Eric Andersenff9eee42001-06-29 04:57:14 +00002985{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002986 int pid, rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00002987 int s;
2988 int oheedint = heedint;
2989
2990 heedint = 0;
2991 rv = 0;
2992 do {
2993 pid = wait(&s);
2994 if (pid == -1) {
2995 if (errno != EINTR || canintr)
2996 break;
2997 } else {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002998 rv = WAITSIG(s);
2999 if (rv != 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003000 if (rv < NSIGNAL) {
3001 if (signame[rv] != NULL) {
3002 if (pid != lastpid) {
3003 prn(pid);
3004 prs(": ");
3005 }
3006 prs(signame[rv]);
3007 }
3008 } else {
3009 if (pid != lastpid) {
3010 prn(pid);
3011 prs(": ");
3012 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003013 prs("Signal ");
3014 prn(rv);
3015 prs(" ");
Eric Andersenff9eee42001-06-29 04:57:14 +00003016 }
3017 if (WAITCORE(s))
3018 prs(" - core dumped");
3019 if (rv >= NSIGNAL || signame[rv])
3020 prs("\n");
3021 rv = -1;
3022 } else
3023 rv = WAITVAL(s);
3024 }
3025 } while (pid != lastpid);
3026 heedint = oheedint;
3027 if (intr) {
3028 if (interactive) {
3029 if (canintr)
3030 intr = 0;
3031 } else {
Eric Andersen8401eea2004-08-04 19:16:54 +00003032 if (exstat == 0)
3033 exstat = rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003034 onintr(0);
3035 }
3036 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003037 return rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003038}
3039
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003040static int setstatus(int s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003041{
3042 exstat = s;
3043 setval(lookup("?"), putn(s));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003044 return s;
Eric Andersenff9eee42001-06-29 04:57:14 +00003045}
3046
3047/*
3048 * PATH-searching interface to execve.
3049 * If getenv("PATH") were kept up-to-date,
3050 * execvp might be used.
3051 */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003052static const char *rexecve(char *c, char **v, char **envp)
Eric Andersenff9eee42001-06-29 04:57:14 +00003053{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003054 int i;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003055 const char *sp;
3056 char *tp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003057 int eacces = 0, asis = 0;
Eric Andersen1c039232001-07-07 00:05:55 +00003058 char *name = c;
Eric Andersen8401eea2004-08-04 19:16:54 +00003059
Denis Vlasenko80d14be2007-04-10 23:03:30 +00003060 if (ENABLE_FEATURE_SH_STANDALONE) {
Rob Landleya299efb2006-08-10 21:46:43 +00003061 if (find_applet_by_name(name)) {
3062 /* We have to exec here since we vforked. Running
Denis Vlasenkoe4f2d062007-04-11 17:03:19 +00003063 * run_applet_and_exit() won't work and bad things
Rob Landleya299efb2006-08-10 21:46:43 +00003064 * will happen. */
Denis Vlasenkobdbbb7e2007-06-08 15:02:55 +00003065 execve(bb_busybox_exec_path, v, envp);
Rob Landleya299efb2006-08-10 21:46:43 +00003066 }
Eric Andersen1c039232001-07-07 00:05:55 +00003067 }
Eric Andersen1c039232001-07-07 00:05:55 +00003068
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003069 DBGPRINTF(("REXECVE: c=%p, v=%p, envp=%p\n", c, v, envp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003070
Eric Andersen8401eea2004-08-04 19:16:54 +00003071 sp = any('/', c) ? "" : path->value;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003072 asis = (*sp == '\0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003073 while (asis || *sp != '\0') {
3074 asis = 0;
3075 tp = e.linep;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003076 for (; *sp != '\0'; tp++) {
3077 *tp = *sp++;
3078 if (*tp == ':') {
3079 asis = (*sp == '\0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003080 break;
3081 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003082 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003083 if (tp != e.linep)
3084 *tp++ = '/';
Eric Andersen8401eea2004-08-04 19:16:54 +00003085 for (i = 0; (*tp++ = c[i++]) != '\0';);
Eric Andersen1c039232001-07-07 00:05:55 +00003086
Eric Andersen12de6cf2004-08-04 19:19:10 +00003087 DBGPRINTF3(("REXECVE: e.linep is %s\n", e.linep));
3088
Eric Andersenff9eee42001-06-29 04:57:14 +00003089 execve(e.linep, v, envp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003090
Eric Andersenff9eee42001-06-29 04:57:14 +00003091 switch (errno) {
3092 case ENOEXEC:
3093 *v = e.linep;
3094 tp = *--v;
3095 *v = e.linep;
Glenn L McGrathdc4e75e2003-09-02 02:36:18 +00003096 execve(DEFAULT_SHELL, v, envp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003097 *v = tp;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003098 return "no Shell";
Eric Andersenff9eee42001-06-29 04:57:14 +00003099
3100 case ENOMEM:
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003101 return (char *) bb_msg_memory_exhausted;
Eric Andersenff9eee42001-06-29 04:57:14 +00003102
3103 case E2BIG:
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003104 return "argument list too long";
Eric Andersenff9eee42001-06-29 04:57:14 +00003105
3106 case EACCES:
3107 eacces++;
3108 break;
3109 }
3110 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003111 return errno == ENOENT ? "not found" : "cannot execute";
Eric Andersenff9eee42001-06-29 04:57:14 +00003112}
3113
3114/*
3115 * Run the command produced by generator `f'
3116 * applied to stream `arg'.
3117 */
Eric Andersen8401eea2004-08-04 19:16:54 +00003118static int run(struct ioarg *argp, int (*f) (struct ioarg *))
Eric Andersenff9eee42001-06-29 04:57:14 +00003119{
3120 struct op *otree;
3121 struct wdblock *swdlist;
3122 struct wdblock *siolist;
3123 jmp_buf ev, rt;
3124 xint *ofail;
3125 int rv;
3126
3127#if __GNUC__
3128 /* Avoid longjmp clobbering */
3129 (void) &rv;
3130#endif
3131
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003132 DBGPRINTF(("RUN: enter, areanum %d, outtree %p, failpt %p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00003133 areanum, outtree, failpt));
3134
Eric Andersenff9eee42001-06-29 04:57:14 +00003135 areanum++;
3136 swdlist = wdlist;
3137 siolist = iolist;
3138 otree = outtree;
3139 ofail = failpt;
3140 rv = -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003141
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003142 errpt = ev;
3143 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003144 wdlist = 0;
3145 iolist = 0;
3146 pushio(argp, f);
3147 e.iobase = e.iop;
3148 yynerrs = 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003149 failpt = rt;
3150 if (setjmp(failpt) == 0 && yyparse() == 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00003151 rv = execute(outtree, NOPIPE, NOPIPE, 0);
3152 quitenv();
Eric Andersen12de6cf2004-08-04 19:19:10 +00003153 } else {
3154 DBGPRINTF(("RUN: error from newenv()!\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00003155 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00003156
Eric Andersenff9eee42001-06-29 04:57:14 +00003157 wdlist = swdlist;
3158 iolist = siolist;
3159 failpt = ofail;
3160 outtree = otree;
3161 freearea(areanum--);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003162
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003163 return rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003164}
3165
3166/* -------- do.c -------- */
3167
3168/*
3169 * built-in commands: doX
3170 */
3171
Eric Andersen8401eea2004-08-04 19:16:54 +00003172static int dohelp(struct op *t)
Eric Andersen1c039232001-07-07 00:05:55 +00003173{
3174 int col;
3175 const struct builtincmd *x;
3176
Denis Vlasenko0ee39992006-12-24 15:23:28 +00003177 puts("\nBuilt-in commands:\n"
3178 "-------------------");
Eric Andersen1c039232001-07-07 00:05:55 +00003179
Denis Vlasenko95cb3262007-04-09 03:06:34 +00003180 col = 0;
3181 x = builtincmds;
3182 while (x->name) {
3183 col += printf("%c%s", ((col == 0) ? '\t' : ' '), x->name);
Eric Andersen1c039232001-07-07 00:05:55 +00003184 if (col > 60) {
Denis Vlasenkoc6f188d2006-10-26 00:37:00 +00003185 puts("");
Eric Andersen1c039232001-07-07 00:05:55 +00003186 col = 0;
3187 }
Denis Vlasenko95cb3262007-04-09 03:06:34 +00003188 x++;
Eric Andersen1c039232001-07-07 00:05:55 +00003189 }
Denis Vlasenko80d14be2007-04-10 23:03:30 +00003190#if ENABLE_FEATURE_SH_STANDALONE
Eric Andersen1c039232001-07-07 00:05:55 +00003191 {
Denis Vlasenko335b63d2007-04-10 21:38:30 +00003192 const struct bb_applet *applet = applets;
Eric Andersen1c039232001-07-07 00:05:55 +00003193
Denis Vlasenko95cb3262007-04-09 03:06:34 +00003194 while (applet->name) {
3195 col += printf("%c%s", ((col == 0) ? '\t' : ' '), applet->name);
Eric Andersen1c039232001-07-07 00:05:55 +00003196 if (col > 60) {
Denis Vlasenkoc6f188d2006-10-26 00:37:00 +00003197 puts("");
Eric Andersen1c039232001-07-07 00:05:55 +00003198 col = 0;
3199 }
Denis Vlasenko95cb3262007-04-09 03:06:34 +00003200 applet++;
Eric Andersen1c039232001-07-07 00:05:55 +00003201 }
3202 }
3203#endif
Denis Vlasenko0ee39992006-12-24 15:23:28 +00003204 puts("\n");
Eric Andersen1c039232001-07-07 00:05:55 +00003205 return EXIT_SUCCESS;
3206}
3207
Eric Andersen8401eea2004-08-04 19:16:54 +00003208static int dolabel(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003209{
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003210 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003211}
3212
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003213static int dochdir(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003214{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003215 const char *cp, *er;
Eric Andersenff9eee42001-06-29 04:57:14 +00003216
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003217 cp = t->words[1];
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003218 if (cp == NULL) {
3219 cp = homedir->value;
Denis Vlasenkod244c5e2007-02-09 17:30:14 +00003220 if (cp != NULL)
3221 goto do_cd;
3222 er = ": no home directory";
3223 } else {
3224 do_cd:
3225 if (chdir(cp) >= 0)
3226 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003227 er = ": bad directory";
Denis Vlasenkod244c5e2007-02-09 17:30:14 +00003228 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003229 prs(cp != NULL ? cp : "cd");
Eric Andersenff9eee42001-06-29 04:57:14 +00003230 err(er);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003231 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003232}
3233
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003234static int doshift(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003235{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003236 int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003237
Eric Andersen8401eea2004-08-04 19:16:54 +00003238 n = t->words[1] ? getn(t->words[1]) : 1;
3239 if (dolc < n) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003240 err("nothing to shift");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003241 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003242 }
3243 dolv[n] = dolv[0];
3244 dolv += n;
3245 dolc -= n;
3246 setval(lookup("#"), putn(dolc));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003247 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003248}
3249
3250/*
3251 * execute login and newgrp directly
3252 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003253static int dologin(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003254{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003255 const char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003256
3257 if (interactive) {
3258 signal(SIGINT, SIG_DFL);
3259 signal(SIGQUIT, SIG_DFL);
3260 }
Eric Andersenfd7a4c82004-09-02 23:13:10 +00003261 cp = rexecve(t->words[0], t->words, makenv(0, NULL));
Eric Andersen8401eea2004-08-04 19:16:54 +00003262 prs(t->words[0]);
3263 prs(": ");
3264 err(cp);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003265 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003266}
3267
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003268static int doumask(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003269{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003270 int i, n;
3271 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003272
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003273 cp = t->words[1];
3274 if (cp == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003275 i = umask(0);
3276 umask(i);
Eric Andersen8401eea2004-08-04 19:16:54 +00003277 for (n = 3 * 4; (n -= 3) >= 0;)
3278 putc('0' + ((i >> n) & 07), stderr);
Eric Andersenff9eee42001-06-29 04:57:14 +00003279 putc('\n', stderr);
3280 } else {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003281/* huh??? '8','9' are not allowed! */
Eric Andersen8401eea2004-08-04 19:16:54 +00003282 for (n = 0; *cp >= '0' && *cp <= '9'; cp++)
3283 n = n * 8 + (*cp - '0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003284 umask(n);
3285 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003286 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003287}
3288
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003289static int doexec(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003290{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003291 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00003292 jmp_buf ex;
3293 xint *ofail;
3294
3295 t->ioact = NULL;
Eric Andersen8401eea2004-08-04 19:16:54 +00003296 for (i = 0; (t->words[i] = t->words[i + 1]) != NULL; i++);
Eric Andersenff9eee42001-06-29 04:57:14 +00003297 if (i == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003298 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003299 execflg = 1;
3300 ofail = failpt;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003301 failpt = ex;
3302 if (setjmp(failpt) == 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00003303 execute(t, NOPIPE, NOPIPE, FEXEC);
3304 failpt = ofail;
3305 execflg = 0;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003306 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003307}
3308
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003309static int dodot(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003310{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003311 int i;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003312 const char *sp;
3313 char *tp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003314 char *cp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003315 int maltmp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003316
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003317 DBGPRINTF(("DODOT: enter, t=%p, tleft %p, tright %p, e.linep is %s\n", t, t->left, t->right, ((e.linep == NULL) ? "NULL" : e.linep)));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003318
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003319 cp = t->words[1];
3320 if (cp == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00003321 DBGPRINTF(("DODOT: bad args, ret 0\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003322 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003323 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003324 DBGPRINTF(("DODOT: cp is %s\n", cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003325
Eric Andersen8401eea2004-08-04 19:16:54 +00003326 sp = any('/', cp) ? ":" : path->value;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003327
3328 DBGPRINTF(("DODOT: sp is %s, e.linep is %s\n",
3329 ((sp == NULL) ? "NULL" : sp),
3330 ((e.linep == NULL) ? "NULL" : e.linep)));
3331
Eric Andersenff9eee42001-06-29 04:57:14 +00003332 while (*sp) {
3333 tp = e.linep;
3334 while (*sp && (*tp = *sp++) != ':')
3335 tp++;
3336 if (tp != e.linep)
3337 *tp++ = '/';
Eric Andersen12de6cf2004-08-04 19:19:10 +00003338
Eric Andersen8401eea2004-08-04 19:16:54 +00003339 for (i = 0; (*tp++ = cp[i++]) != '\0';);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003340
3341 /* Original code */
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00003342 i = open(e.linep, O_RDONLY);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003343 if (i >= 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003344 exstat = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003345 maltmp = remap(i);
3346 DBGPRINTF(("DODOT: remap=%d, exstat=%d, e.iofd %d, i %d, e.linep is %s\n", maltmp, exstat, e.iofd, i, e.linep));
3347
3348 next(maltmp); /* Basically a PUSHIO */
3349
3350 DBGPRINTF(("DODOT: returning exstat=%d\n", exstat));
3351
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003352 return exstat;
Eric Andersenff9eee42001-06-29 04:57:14 +00003353 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003354 } /* while */
Eric Andersen12de6cf2004-08-04 19:19:10 +00003355
Eric Andersenff9eee42001-06-29 04:57:14 +00003356 prs(cp);
3357 err(": not found");
Eric Andersen12de6cf2004-08-04 19:19:10 +00003358
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003359 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003360}
3361
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003362static int dowait(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003363{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003364 int i;
3365 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003366
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003367 cp = t->words[1];
3368 if (cp != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003369 i = getn(cp);
3370 if (i == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003371 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003372 } else
3373 i = -1;
3374 setstatus(waitfor(i, 1));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003375 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003376}
3377
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003378static int doread(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003379{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003380 char *cp, **wp;
3381 int nb = 0;
3382 int nl = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003383
3384 if (t->words[1] == NULL) {
3385 err("Usage: read name ...");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003386 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003387 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003388 for (wp = t->words + 1; *wp; wp++) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003389 for (cp = e.linep; !nl && cp < elinep - 1; cp++) {
3390 nb = read(0, cp, sizeof(*cp));
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003391 if (nb != sizeof(*cp))
Eric Andersenff9eee42001-06-29 04:57:14 +00003392 break;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003393 nl = (*cp == '\n');
3394 if (nl || (wp[1] && any(*cp, ifs->value)))
3395 break;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003396 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003397 *cp = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00003398 if (nb <= 0)
3399 break;
3400 setval(lookup(*wp), e.linep);
3401 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003402 return nb <= 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003403}
3404
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003405static int doeval(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003406{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003407 return RUN(awordlist, t->words + 1, wdchar);
Eric Andersenff9eee42001-06-29 04:57:14 +00003408}
3409
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003410static int dotrap(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003411{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003412 int n, i;
3413 int resetsig;
Eric Andersenff9eee42001-06-29 04:57:14 +00003414
3415 if (t->words[1] == NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00003416 for (i = 0; i <= _NSIG; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00003417 if (trap[i]) {
3418 prn(i);
3419 prs(": ");
3420 prs(trap[i]);
3421 prs("\n");
3422 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003423 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003424 }
3425 resetsig = isdigit(*t->words[1]);
3426 for (i = resetsig ? 1 : 2; t->words[i] != NULL; ++i) {
3427 n = getsig(t->words[i]);
3428 freecell(trap[n]);
3429 trap[n] = 0;
3430 if (!resetsig) {
3431 if (*t->words[1] != '\0') {
3432 trap[n] = strsave(t->words[1], 0);
3433 setsig(n, sig);
3434 } else
3435 setsig(n, SIG_IGN);
3436 } else {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00003437 if (interactive) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003438 if (n == SIGINT)
3439 setsig(n, onintr);
3440 else
Eric Andersen8401eea2004-08-04 19:16:54 +00003441 setsig(n, n == SIGQUIT ? SIG_IGN : SIG_DFL);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00003442 } else
Eric Andersenff9eee42001-06-29 04:57:14 +00003443 setsig(n, SIG_DFL);
3444 }
3445 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003446 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003447}
3448
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003449static int getsig(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003450{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003451 int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003452
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003453 n = getn(s);
3454 if (n < 0 || n > _NSIG) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003455 err("trap: bad signal number");
3456 n = 0;
3457 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003458 return n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003459}
3460
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003461static void setsig(int n, sighandler_t f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003462{
3463 if (n == 0)
3464 return;
3465 if (signal(n, SIG_IGN) != SIG_IGN || ourtrap[n]) {
3466 ourtrap[n] = 1;
3467 signal(n, f);
3468 }
3469}
3470
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003471static int getn(char *as)
Eric Andersenff9eee42001-06-29 04:57:14 +00003472{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003473 char *s;
3474 int n, m;
Eric Andersenff9eee42001-06-29 04:57:14 +00003475
3476 s = as;
3477 m = 1;
3478 if (*s == '-') {
3479 m = -1;
3480 s++;
3481 }
3482 for (n = 0; isdigit(*s); s++)
Eric Andersen8401eea2004-08-04 19:16:54 +00003483 n = (n * 10) + (*s - '0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003484 if (*s) {
3485 prs(as);
3486 err(": bad number");
3487 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003488 return n * m;
Eric Andersenff9eee42001-06-29 04:57:14 +00003489}
3490
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003491static int dobreak(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003492{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003493 return brkcontin(t->words[1], 1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003494}
3495
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003496static int docontinue(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003497{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003498 return brkcontin(t->words[1], 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003499}
3500
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003501static int brkcontin(char *cp, int val)
Eric Andersenff9eee42001-06-29 04:57:14 +00003502{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003503 struct brkcon *bc;
3504 int nl;
Eric Andersenff9eee42001-06-29 04:57:14 +00003505
Eric Andersen8401eea2004-08-04 19:16:54 +00003506 nl = cp == NULL ? 1 : getn(cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003507 if (nl <= 0)
3508 nl = 999;
3509 do {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003510 bc = brklist;
3511 if (bc == NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00003512 break;
3513 brklist = bc->nextlev;
3514 } while (--nl);
3515 if (nl) {
3516 err("bad break/continue level");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003517 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003518 }
3519 isbreak = val;
3520 longjmp(bc->brkpt, 1);
3521 /* NOTREACHED */
3522}
3523
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003524static int doexit(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003525{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003526 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003527
3528 execflg = 0;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003529 cp = t->words[1];
3530 if (cp != NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00003531 setstatus(getn(cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003532
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003533 DBGPRINTF(("DOEXIT: calling leave(), t=%p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003534
Eric Andersenff9eee42001-06-29 04:57:14 +00003535 leave();
3536 /* NOTREACHED */
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003537 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003538}
3539
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003540static int doexport(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003541{
Eric Andersen8401eea2004-08-04 19:16:54 +00003542 rdexp(t->words + 1, export, EXPORT);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003543 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003544}
3545
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003546static int doreadonly(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003547{
Eric Andersen8401eea2004-08-04 19:16:54 +00003548 rdexp(t->words + 1, ronly, RONLY);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003549 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003550}
3551
Eric Andersen8401eea2004-08-04 19:16:54 +00003552static void rdexp(char **wp, void (*f) (struct var *), int key)
Eric Andersenff9eee42001-06-29 04:57:14 +00003553{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003554 DBGPRINTF6(("RDEXP: enter, wp=%p, func=%p, key=%d\n", wp, f, key));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003555 DBGPRINTF6(("RDEXP: *wp=%s\n", *wp));
3556
Eric Andersenff9eee42001-06-29 04:57:14 +00003557 if (*wp != NULL) {
Matt Kraaif69bfc72001-07-12 19:39:59 +00003558 for (; *wp != NULL; wp++) {
3559 if (isassign(*wp)) {
3560 char *cp;
Eric Andersen8401eea2004-08-04 19:16:54 +00003561
Matt Kraaif69bfc72001-07-12 19:39:59 +00003562 assign(*wp, COPYV);
Eric Andersen8401eea2004-08-04 19:16:54 +00003563 for (cp = *wp; *cp != '='; cp++);
Matt Kraaif69bfc72001-07-12 19:39:59 +00003564 *cp = '\0';
3565 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003566 if (checkname(*wp))
Eric Andersen8401eea2004-08-04 19:16:54 +00003567 (*f) (lookup(*wp));
Eric Andersenff9eee42001-06-29 04:57:14 +00003568 else
3569 badid(*wp);
Matt Kraaif69bfc72001-07-12 19:39:59 +00003570 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003571 } else
3572 putvlist(key, 1);
3573}
3574
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003575static void badid(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003576{
3577 prs(s);
3578 err(": bad identifier");
3579}
3580
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003581static int doset(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003582{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003583 struct var *vp;
3584 char *cp;
3585 int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003586
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003587 cp = t->words[1];
3588 if (cp == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003589 for (vp = vlist; vp; vp = vp->next)
3590 varput(vp->name, 1);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003591 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003592 }
3593 if (*cp == '-') {
3594 /* bad: t->words++; */
Eric Andersen8401eea2004-08-04 19:16:54 +00003595 for (n = 0; (t->words[n] = t->words[n + 1]) != NULL; n++);
Eric Andersenff9eee42001-06-29 04:57:14 +00003596 if (*++cp == 0)
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003597 FLAG['x'] = FLAG['v'] = 0;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003598 else {
3599 for (; *cp; cp++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003600 switch (*cp) {
3601 case 'e':
3602 if (!interactive)
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003603 FLAG['e']++;
Eric Andersenff9eee42001-06-29 04:57:14 +00003604 break;
3605
3606 default:
Eric Andersen8401eea2004-08-04 19:16:54 +00003607 if (*cp >= 'a' && *cp <= 'z')
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003608 FLAG[(int) *cp]++;
Eric Andersenff9eee42001-06-29 04:57:14 +00003609 break;
3610 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003611 }
3612 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003613 setdash();
3614 }
3615 if (t->words[1]) {
3616 t->words[0] = dolv[0];
Eric Andersen8401eea2004-08-04 19:16:54 +00003617 for (n = 1; t->words[n]; n++)
3618 setarea((char *) t->words[n], 0);
3619 dolc = n - 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003620 dolv = t->words;
3621 setval(lookup("#"), putn(dolc));
Eric Andersen8401eea2004-08-04 19:16:54 +00003622 setarea((char *) (dolv - 1), 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003623 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003624 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003625}
3626
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003627static void varput(char *s, int out)
Eric Andersenff9eee42001-06-29 04:57:14 +00003628{
Matt Kraai69edfec2001-08-06 14:14:18 +00003629 if (isalnum(*s) || *s == '_') {
Eric Andersenff9eee42001-06-29 04:57:14 +00003630 write(out, s, strlen(s));
3631 write(out, "\n", 1);
3632 }
3633}
3634
3635
3636/*
3637 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
3638 * This file contains code for the times builtin.
Eric Andersenff9eee42001-06-29 04:57:14 +00003639 */
Eric Andersen8401eea2004-08-04 19:16:54 +00003640static int dotimes(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003641{
3642 struct tms buf;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003643 long clk_tck = sysconf(_SC_CLK_TCK);
Eric Andersenff9eee42001-06-29 04:57:14 +00003644
3645 times(&buf);
3646 printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
Eric Andersen8401eea2004-08-04 19:16:54 +00003647 (int) (buf.tms_utime / clk_tck / 60),
3648 ((double) buf.tms_utime) / clk_tck,
3649 (int) (buf.tms_stime / clk_tck / 60),
3650 ((double) buf.tms_stime) / clk_tck,
3651 (int) (buf.tms_cutime / clk_tck / 60),
3652 ((double) buf.tms_cutime) / clk_tck,
3653 (int) (buf.tms_cstime / clk_tck / 60),
3654 ((double) buf.tms_cstime) / clk_tck);
Eric Andersenff9eee42001-06-29 04:57:14 +00003655 return 0;
3656}
3657
3658
Eric Andersenff9eee42001-06-29 04:57:14 +00003659/* -------- eval.c -------- */
3660
3661/*
3662 * ${}
3663 * `command`
3664 * blank interpretation
3665 * quoting
3666 * glob
3667 */
3668
Eric Andersen8401eea2004-08-04 19:16:54 +00003669static char **eval(char **ap, int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003670{
3671 struct wdblock *wb;
3672 char **wp;
3673 char **wf;
3674 jmp_buf ev;
3675
3676#if __GNUC__
3677 /* Avoid longjmp clobbering */
3678 (void) &wp;
3679 (void) &ap;
3680#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00003681
3682 DBGPRINTF4(("EVAL: enter, f=%d\n", f));
3683
Eric Andersenff9eee42001-06-29 04:57:14 +00003684 wp = NULL;
3685 wb = NULL;
3686 wf = NULL;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003687 errpt = ev;
3688 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003689 while (*ap && isassign(*ap))
3690 expand(*ap++, &wb, f & ~DOGLOB);
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003691 if (FLAG['k']) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003692 for (wf = ap; *wf; wf++) {
3693 if (isassign(*wf))
3694 expand(*wf, &wb, f & ~DOGLOB);
3695 }
3696 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003697 for (wb = addword((char *) 0, wb); *ap; ap++) {
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003698 if (!FLAG['k'] || !isassign(*ap))
Eric Andersenff9eee42001-06-29 04:57:14 +00003699 expand(*ap, &wb, f & ~DOKEY);
3700 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003701 wb = addword((char *) 0, wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00003702 wp = getwords(wb);
3703 quitenv();
3704 } else
3705 gflg = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003706
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003707 return gflg ? (char **) NULL : wp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003708}
3709
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003710
Eric Andersenff9eee42001-06-29 04:57:14 +00003711/*
3712 * Make the exported environment from the exported
3713 * names in the dictionary. Keyword assignments
3714 * will already have been done.
3715 */
Eric Andersenfd7a4c82004-09-02 23:13:10 +00003716static char **makenv(int all, struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00003717{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003718 struct var *vp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003719
3720 DBGPRINTF5(("MAKENV: enter, all=%d\n", all));
Eric Andersenff9eee42001-06-29 04:57:14 +00003721
Eric Andersenff9eee42001-06-29 04:57:14 +00003722 for (vp = vlist; vp; vp = vp->next)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003723 if (all || vp->status & EXPORT)
Eric Andersenff9eee42001-06-29 04:57:14 +00003724 wb = addword(vp->name, wb);
Eric Andersen8401eea2004-08-04 19:16:54 +00003725 wb = addword((char *) 0, wb);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003726 return getwords(wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00003727}
3728
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003729static int expand(const char *cp, struct wdblock **wbp, int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003730{
3731 jmp_buf ev;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003732 char *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003733
3734#if __GNUC__
3735 /* Avoid longjmp clobbering */
3736 (void) &cp;
3737#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00003738
3739 DBGPRINTF3(("EXPAND: enter, f=%d\n", f));
3740
Eric Andersenff9eee42001-06-29 04:57:14 +00003741 gflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003742
Eric Andersenff9eee42001-06-29 04:57:14 +00003743 if (cp == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003744 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003745
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003746 if (!anys("$`'\"", cp) && !anys(ifs->value, cp)
3747 && ((f & DOGLOB) == 0 || !anys("[*?", cp))
3748 ) {
3749 xp = strsave(cp, areanum);
Eric Andersenff9eee42001-06-29 04:57:14 +00003750 if (f & DOTRIM)
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003751 unquote(xp);
3752 *wbp = addword(xp, *wbp);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003753 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003754 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003755 errpt = ev;
3756 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003757 PUSHIO(aword, cp, strchar);
3758 e.iobase = e.iop;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003759 while ((xp = blank(f)) && gflg == 0) {
3760 e.linep = xp;
3761 xp = strsave(xp, areanum);
Eric Andersen8401eea2004-08-04 19:16:54 +00003762 if ((f & DOGLOB) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003763 if (f & DOTRIM)
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003764 unquote(xp);
3765 *wbp = addword(xp, *wbp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003766 } else
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003767 *wbp = glob(xp, *wbp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003768 }
3769 quitenv();
3770 } else
3771 gflg = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003772 return gflg == 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003773}
3774
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003775static char *evalstr(char *cp, int f)
3776{
3777 struct wdblock *wb;
3778
3779 DBGPRINTF6(("EVALSTR: enter, cp=%p, f=%d\n", cp, f));
3780
3781 wb = NULL;
3782 if (expand(cp, &wb, f)) {
3783 if (wb == NULL || wb->w_nword == 0
3784 || (cp = wb->w_words[0]) == NULL
3785 ) {
Denis Vlasenko8e858e22007-03-07 09:35:43 +00003786// TODO: I suspect that
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003787// char *evalstr(char *cp, int f) is actually
3788// const char *evalstr(const char *cp, int f)!
3789 cp = (char*)"";
3790 }
3791 DELETE(wb);
3792 } else
3793 cp = NULL;
3794 return cp;
3795}
3796
3797
Eric Andersenff9eee42001-06-29 04:57:14 +00003798/*
3799 * Blank interpretation and quoting
3800 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003801static char *blank(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003802{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003803 int c, c1;
3804 char *sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003805 int scanequals, foundequals;
3806
Eric Andersen12de6cf2004-08-04 19:19:10 +00003807 DBGPRINTF3(("BLANK: enter, f=%d\n", f));
3808
Eric Andersenff9eee42001-06-29 04:57:14 +00003809 sp = e.linep;
3810 scanequals = f & DOKEY;
3811 foundequals = 0;
3812
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003813 loop:
3814 c = subgetc('"', foundequals);
3815 switch (c) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003816 case 0:
3817 if (sp == e.linep)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003818 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003819 *e.linep++ = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003820 return sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003821
3822 default:
3823 if (f & DOBLANK && any(c, ifs->value))
3824 goto loop;
3825 break;
3826
3827 case '"':
3828 case '\'':
3829 scanequals = 0;
3830 if (INSUB())
3831 break;
3832 for (c1 = c; (c = subgetc(c1, 1)) != c1;) {
3833 if (c == 0)
3834 break;
3835 if (c == '\'' || !any(c, "$`\""))
3836 c |= QUOTE;
3837 *e.linep++ = c;
3838 }
3839 c = 0;
3840 }
3841 unget(c);
Matt Kraai69edfec2001-08-06 14:14:18 +00003842 if (!isalpha(c) && c != '_')
Eric Andersenff9eee42001-06-29 04:57:14 +00003843 scanequals = 0;
3844 for (;;) {
3845 c = subgetc('"', foundequals);
3846 if (c == 0 ||
Eric Andersen8401eea2004-08-04 19:16:54 +00003847 f & (DOBLANK && any(c, ifs->value)) ||
3848 (!INSUB() && any(c, "\"'"))) {
3849 scanequals = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003850 unget(c);
3851 if (any(c, "\"'"))
3852 goto loop;
3853 break;
3854 }
3855 if (scanequals) {
3856 if (c == '=') {
3857 foundequals = 1;
Eric Andersen8401eea2004-08-04 19:16:54 +00003858 scanequals = 0;
3859 } else if (!isalnum(c) && c != '_')
Eric Andersenff9eee42001-06-29 04:57:14 +00003860 scanequals = 0;
3861 }
3862 *e.linep++ = c;
3863 }
3864 *e.linep++ = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003865 return sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003866}
3867
3868/*
3869 * Get characters, substituting for ` and $
3870 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003871static int subgetc(char ec, int quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00003872{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003873 char c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003874
3875 DBGPRINTF3(("SUBGETC: enter, quoted=%d\n", quoted));
Eric Andersenff9eee42001-06-29 04:57:14 +00003876
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003877 again:
Eric Andersenff9eee42001-06-29 04:57:14 +00003878 c = my_getc(ec);
3879 if (!INSUB() && ec != '\'') {
3880 if (c == '`') {
3881 if (grave(quoted) == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003882 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003883 e.iop->task = XGRAVE;
3884 goto again;
3885 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003886 if (c == '$') {
3887 c = dollar(quoted);
3888 if (c == 0) {
3889 e.iop->task = XDOLL;
3890 goto again;
3891 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003892 }
3893 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003894 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003895}
3896
3897/*
3898 * Prepare to generate the string returned by ${} substitution.
3899 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003900static int dollar(int quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00003901{
3902 int otask;
3903 struct io *oiop;
3904 char *dolp;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003905 char *s, c, *cp = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00003906 struct var *vp;
3907
Eric Andersen12de6cf2004-08-04 19:19:10 +00003908 DBGPRINTF3(("DOLLAR: enter, quoted=%d\n", quoted));
3909
Eric Andersenff9eee42001-06-29 04:57:14 +00003910 c = readc();
3911 s = e.linep;
3912 if (c != '{') {
3913 *e.linep++ = c;
Matt Kraai69edfec2001-08-06 14:14:18 +00003914 if (isalpha(c) || c == '_') {
Eric Andersen8401eea2004-08-04 19:16:54 +00003915 while ((c = readc()) != 0 && (isalnum(c) || c == '_'))
Eric Andersenff9eee42001-06-29 04:57:14 +00003916 if (e.linep < elinep)
3917 *e.linep++ = c;
3918 unget(c);
3919 }
3920 c = 0;
3921 } else {
3922 oiop = e.iop;
3923 otask = e.iop->task;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003924
Eric Andersenff9eee42001-06-29 04:57:14 +00003925 e.iop->task = XOTHER;
Eric Andersen8401eea2004-08-04 19:16:54 +00003926 while ((c = subgetc('"', 0)) != 0 && c != '}' && c != '\n')
Eric Andersenff9eee42001-06-29 04:57:14 +00003927 if (e.linep < elinep)
3928 *e.linep++ = c;
3929 if (oiop == e.iop)
3930 e.iop->task = otask;
3931 if (c != '}') {
3932 err("unclosed ${");
3933 gflg++;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003934 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003935 }
3936 }
3937 if (e.linep >= elinep) {
3938 err("string in ${} too long");
3939 gflg++;
3940 e.linep -= 10;
3941 }
3942 *e.linep = 0;
3943 if (*s)
Eric Andersen8401eea2004-08-04 19:16:54 +00003944 for (cp = s + 1; *cp; cp++)
Eric Andersenff9eee42001-06-29 04:57:14 +00003945 if (any(*cp, "=-+?")) {
3946 c = *cp;
3947 *cp++ = 0;
3948 break;
3949 }
3950 if (s[1] == 0 && (*s == '*' || *s == '@')) {
3951 if (dolc > 1) {
3952 /* currently this does not distinguish $* and $@ */
3953 /* should check dollar */
3954 e.linep = s;
Eric Andersen8401eea2004-08-04 19:16:54 +00003955 PUSHIO(awordlist, dolv + 1, dolchar);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003956 return 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00003957 } else { /* trap the nasty ${=} */
Eric Andersenff9eee42001-06-29 04:57:14 +00003958 s[0] = '1';
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003959 s[1] = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00003960 }
3961 }
3962 vp = lookup(s);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003963 dolp = vp->value;
3964 if (dolp == null) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003965 switch (c) {
3966 case '=':
3967 if (isdigit(*s)) {
3968 err("cannot use ${...=...} with $n");
3969 gflg++;
3970 break;
3971 }
3972 setval(vp, cp);
3973 dolp = vp->value;
3974 break;
3975
3976 case '-':
3977 dolp = strsave(cp, areanum);
3978 break;
3979
3980 case '?':
3981 if (*cp == 0) {
3982 prs("missing value for ");
3983 err(s);
3984 } else
3985 err(cp);
3986 gflg++;
3987 break;
3988 }
3989 } else if (c == '+')
3990 dolp = strsave(cp, areanum);
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003991 if (FLAG['u'] && dolp == null) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003992 prs("unset variable: ");
3993 err(s);
3994 gflg++;
3995 }
3996 e.linep = s;
3997 PUSHIO(aword, dolp, quoted ? qstrchar : strchar);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003998 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003999}
4000
4001/*
4002 * Run the command in `...` and read its output.
4003 */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004004
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004005static int grave(int quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00004006{
Denis Vlasenko55f30b02007-03-24 22:42:29 +00004007 /* moved to G: static char child_cmd[LINELIM]; */
4008
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004009 const char *cp;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004010 int i;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004011 int j;
Eric Andersenff9eee42001-06-29 04:57:14 +00004012 int pf[2];
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004013 const char *src;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004014 char *dest;
4015 int count;
4016 int ignore;
4017 int ignore_once;
4018 char *argument_list[4];
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004019 struct wdblock *wb = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004020
4021#if __GNUC__
4022 /* Avoid longjmp clobbering */
4023 (void) &cp;
4024#endif
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004025
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004026 for (cp = e.iop->argp->aword; *cp != '`'; cp++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004027 if (*cp == 0) {
4028 err("no closing `");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004029 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004030 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004031 }
Eric Andersen737f5fb2003-03-14 16:05:59 +00004032
4033 /* string copy with dollar expansion */
4034 src = e.iop->argp->aword;
4035 dest = child_cmd;
4036 count = 0;
4037 ignore = 0;
4038 ignore_once = 0;
4039 while ((*src != '`') && (count < LINELIM)) {
4040 if (*src == '\'')
4041 ignore = !ignore;
4042 if (*src == '\\')
4043 ignore_once = 1;
4044 if (*src == '$' && !ignore && !ignore_once) {
4045 struct var *vp;
4046 char var_name[LINELIM];
4047 char alt_value[LINELIM];
4048 int var_index = 0;
4049 int alt_index = 0;
4050 char operator = 0;
4051 int braces = 0;
4052 char *value;
4053
4054 src++;
4055 if (*src == '{') {
4056 braces = 1;
4057 src++;
4058 }
4059
4060 var_name[var_index++] = *src++;
Paul Fox54690dc2005-07-20 18:33:12 +00004061 while (isalnum(*src) || *src=='_')
Eric Andersen737f5fb2003-03-14 16:05:59 +00004062 var_name[var_index++] = *src++;
4063 var_name[var_index] = 0;
4064
4065 if (braces) {
4066 switch (*src) {
4067 case '}':
4068 break;
4069 case '-':
4070 case '=':
4071 case '+':
4072 case '?':
Eric Andersen8401eea2004-08-04 19:16:54 +00004073 operator = * src;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004074 break;
4075 default:
4076 err("unclosed ${\n");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004077 return 0;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004078 }
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004079 if (operator) {
Eric Andersen737f5fb2003-03-14 16:05:59 +00004080 src++;
4081 while (*src && (*src != '}')) {
4082 alt_value[alt_index++] = *src++;
4083 }
4084 alt_value[alt_index] = 0;
4085 if (*src != '}') {
4086 err("unclosed ${\n");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004087 return 0;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004088 }
4089 }
4090 src++;
4091 }
4092
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004093 if (isalpha(*var_name)) {
4094 /* let subshell handle it instead */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004095
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004096 char *namep = var_name;
4097
4098 *dest++ = '$';
4099 if (braces)
4100 *dest++ = '{';
4101 while (*namep)
4102 *dest++ = *namep++;
4103 if (operator) {
4104 char *altp = alt_value;
4105 *dest++ = operator;
4106 while (*altp)
4107 *dest++ = *altp++;
4108 }
4109 if (braces)
4110 *dest++ = '}';
4111
4112 wb = addword(lookup(var_name)->name, wb);
4113 } else {
4114 /* expand */
4115
4116 vp = lookup(var_name);
4117 if (vp->value != null)
4118 value = (operator == '+') ?
4119 alt_value : vp->value;
4120 else if (operator == '?') {
4121 err(alt_value);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004122 return 0;
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004123 } else if (alt_index && (operator != '+')) {
4124 value = alt_value;
4125 if (operator == '=')
4126 setval(vp, value);
4127 } else
4128 continue;
4129
4130 while (*value && (count < LINELIM)) {
4131 *dest++ = *value++;
4132 count++;
4133 }
Eric Andersen737f5fb2003-03-14 16:05:59 +00004134 }
4135 } else {
4136 *dest++ = *src++;
4137 count++;
4138 ignore_once = 0;
4139 }
4140 }
4141 *dest = '\0';
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004142
Eric Andersenff9eee42001-06-29 04:57:14 +00004143 if (openpipe(pf) < 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004144 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004145
Eric Andersen8401eea2004-08-04 19:16:54 +00004146 while ((i = vfork()) == -1 && errno == EAGAIN);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004147
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004148 DBGPRINTF3(("GRAVE: i is %p\n", io));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004149
Eric Andersen737f5fb2003-03-14 16:05:59 +00004150 if (i < 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004151 closepipe(pf);
Eric Andersen8401eea2004-08-04 19:16:54 +00004152 err((char *) bb_msg_memory_exhausted);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004153 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004154 }
4155 if (i != 0) {
Eric Andersen737f5fb2003-03-14 16:05:59 +00004156 waitpid(i, NULL, 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004157 e.iop->argp->aword = ++cp;
4158 close(pf[1]);
Eric Andersen8401eea2004-08-04 19:16:54 +00004159 PUSHIO(afile, remap(pf[0]),
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004160 (int (*)(struct ioarg *)) ((quoted) ? qgravechar : gravechar));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004161 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004162 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004163 /* allow trapped signals */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004164 /* XXX - Maybe this signal stuff should go as well? */
Eric Andersen8401eea2004-08-04 19:16:54 +00004165 for (j = 0; j <= _NSIG; j++)
Eric Andersen737f5fb2003-03-14 16:05:59 +00004166 if (ourtrap[j] && signal(j, SIG_IGN) != SIG_IGN)
4167 signal(j, SIG_DFL);
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004168
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00004169 /* Testcase where below checks are needed:
4170 * close stdout & run this script:
4171 * files=`ls`
4172 * echo "$files" >zz
4173 */
4174 xmove_fd(pf[1], 1);
4175 if (pf[0] != 1) close(pf[0]);
Eric Andersen737f5fb2003-03-14 16:05:59 +00004176
Eric Andersen8401eea2004-08-04 19:16:54 +00004177 argument_list[0] = (char *) DEFAULT_SHELL;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004178 argument_list[1] = (char *) "-c";
Eric Andersen737f5fb2003-03-14 16:05:59 +00004179 argument_list[2] = child_cmd;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004180 argument_list[3] = NULL;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004181
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004182 cp = rexecve(argument_list[0], argument_list, makenv(1, wb));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004183 prs(argument_list[0]);
4184 prs(": ");
4185 err(cp);
Eric Andersen737f5fb2003-03-14 16:05:59 +00004186 _exit(1);
Eric Andersenff9eee42001-06-29 04:57:14 +00004187}
4188
Eric Andersen737f5fb2003-03-14 16:05:59 +00004189
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004190static char *unquote(char *as)
Eric Andersenff9eee42001-06-29 04:57:14 +00004191{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004192 char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00004193
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004194 s = as;
4195 if (s != NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00004196 while (*s)
4197 *s++ &= ~QUOTE;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004198 return as;
Eric Andersenff9eee42001-06-29 04:57:14 +00004199}
4200
4201/* -------- glob.c -------- */
4202
4203/*
4204 * glob
4205 */
4206
4207#define scopy(x) strsave((x), areanum)
4208#define BLKSIZ 512
4209#define NDENT ((BLKSIZ+sizeof(struct dirent)-1)/sizeof(struct dirent))
4210
Eric Andersen8401eea2004-08-04 19:16:54 +00004211static struct wdblock *cl, *nl;
4212static char spcl[] = "[?*";
Eric Andersenff9eee42001-06-29 04:57:14 +00004213
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004214static struct wdblock *glob(char *cp, struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004215{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004216 int i;
4217 char *pp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004218
4219 if (cp == 0)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004220 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004221 i = 0;
4222 for (pp = cp; *pp; pp++)
4223 if (any(*pp, spcl))
4224 i++;
4225 else if (!any(*pp & ~QUOTE, spcl))
4226 *pp &= ~QUOTE;
4227 if (i != 0) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004228 for (cl = addword(scopy(cp), NULL); anyspcl(cl); cl = nl) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004229 nl = newword(cl->w_nword * 2);
4230 for (i = 0; i < cl->w_nword; i++) { /* for each argument */
Eric Andersenff9eee42001-06-29 04:57:14 +00004231 for (pp = cl->w_words[i]; *pp; pp++)
4232 if (any(*pp, spcl)) {
4233 globname(cl->w_words[i], pp);
4234 break;
4235 }
4236 if (*pp == '\0')
4237 nl = addword(scopy(cl->w_words[i]), nl);
4238 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004239 for (i = 0; i < cl->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004240 DELETE(cl->w_words[i]);
4241 DELETE(cl);
4242 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004243 for (i = 0; i < cl->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004244 unquote(cl->w_words[i]);
Eric Andersen8401eea2004-08-04 19:16:54 +00004245 glob0((char *) cl->w_words, cl->w_nword, sizeof(char *), xstrcmp);
Eric Andersenff9eee42001-06-29 04:57:14 +00004246 if (cl->w_nword) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004247 for (i = 0; i < cl->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004248 wb = addword(cl->w_words[i], wb);
4249 DELETE(cl);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004250 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004251 }
4252 }
4253 wb = addword(unquote(cp), wb);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004254 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004255}
4256
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004257static void globname(char *we, char *pp)
Eric Andersenff9eee42001-06-29 04:57:14 +00004258{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004259 char *np, *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004260 char *name, *gp, *dp;
4261 int k;
4262 DIR *dirp;
4263 struct dirent *de;
Eric Andersen8401eea2004-08-04 19:16:54 +00004264 char dname[NAME_MAX + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00004265 struct stat dbuf;
4266
4267 for (np = we; np != pp; pp--)
4268 if (pp[-1] == '/')
4269 break;
Eric Andersen8401eea2004-08-04 19:16:54 +00004270 for (dp = cp = space((int) (pp - np) + 3); np < pp;)
Eric Andersenff9eee42001-06-29 04:57:14 +00004271 *cp++ = *np++;
4272 *cp++ = '.';
4273 *cp = '\0';
Eric Andersen8401eea2004-08-04 19:16:54 +00004274 for (gp = cp = space(strlen(pp) + 1); *np && *np != '/';)
Eric Andersenff9eee42001-06-29 04:57:14 +00004275 *cp++ = *np++;
4276 *cp = '\0';
4277 dirp = opendir(dp);
4278 if (dirp == 0) {
4279 DELETE(dp);
4280 DELETE(gp);
4281 return;
4282 }
4283 dname[NAME_MAX] = '\0';
Eric Andersen8401eea2004-08-04 19:16:54 +00004284 while ((de = readdir(dirp)) != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004285 /* XXX Hmmm... What this could be? (abial) */
4286 /*
Eric Andersen8401eea2004-08-04 19:16:54 +00004287 if (ent[j].d_ino == 0)
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004288 continue;
Eric Andersen8401eea2004-08-04 19:16:54 +00004289 */
Eric Andersenff9eee42001-06-29 04:57:14 +00004290 strncpy(dname, de->d_name, NAME_MAX);
Eric Andersen8401eea2004-08-04 19:16:54 +00004291 if (dname[0] == '.')
4292 if (*gp != '.')
4293 continue;
4294 for (k = 0; k < NAME_MAX; k++)
4295 if (any(dname[k], spcl))
4296 dname[k] |= QUOTE;
4297 if (gmatch(dname, gp)) {
4298 name = generate(we, pp, dname, np);
4299 if (*np && !anys(np, spcl)) {
4300 if (stat(name, &dbuf)) {
4301 DELETE(name);
Eric Andersenff9eee42001-06-29 04:57:14 +00004302 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00004303 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004304 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004305 nl = addword(name, nl);
4306 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004307 }
4308 closedir(dirp);
4309 DELETE(dp);
4310 DELETE(gp);
4311}
4312
4313/*
4314 * generate a pathname as below.
4315 * start..end1 / middle end
4316 * the slashes come for free
4317 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004318static char *generate(char *start1, char *end1, char *middle, char *end)
Eric Andersenff9eee42001-06-29 04:57:14 +00004319{
4320 char *p;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004321 char *op, *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004322
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004323 p = op = space((int)(end1 - start1) + strlen(middle) + strlen(end) + 2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004324 for (xp = start1; xp != end1;)
4325 *op++ = *xp++;
Eric Andersen8401eea2004-08-04 19:16:54 +00004326 for (xp = middle; (*op++ = *xp++) != '\0';);
Eric Andersenff9eee42001-06-29 04:57:14 +00004327 op--;
Eric Andersen8401eea2004-08-04 19:16:54 +00004328 for (xp = end; (*op++ = *xp++) != '\0';);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004329 return p;
Eric Andersenff9eee42001-06-29 04:57:14 +00004330}
4331
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004332static int anyspcl(struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004333{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004334 int i;
4335 char **wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004336
4337 wd = wb->w_words;
Eric Andersen8401eea2004-08-04 19:16:54 +00004338 for (i = 0; i < wb->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004339 if (anys(spcl, *wd++))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004340 return 1;
4341 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004342}
4343
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004344static int xstrcmp(char *p1, char *p2)
Eric Andersenff9eee42001-06-29 04:57:14 +00004345{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004346 return strcmp(*(char **) p1, *(char **) p2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004347}
4348
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004349
Eric Andersenff9eee42001-06-29 04:57:14 +00004350/* -------- word.c -------- */
4351
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004352static struct wdblock *newword(int nw)
Eric Andersenff9eee42001-06-29 04:57:14 +00004353{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004354 struct wdblock *wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004355
Eric Andersen8401eea2004-08-04 19:16:54 +00004356 wb = (struct wdblock *) space(sizeof(*wb) + nw * sizeof(char *));
Eric Andersenff9eee42001-06-29 04:57:14 +00004357 wb->w_bsize = nw;
4358 wb->w_nword = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004359 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004360}
4361
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004362static struct wdblock *addword(char *wd, struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004363{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004364 struct wdblock *wb2;
4365 int nw;
Eric Andersenff9eee42001-06-29 04:57:14 +00004366
4367 if (wb == NULL)
4368 wb = newword(NSTART);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004369 nw = wb->w_nword;
4370 if (nw >= wb->w_bsize) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004371 wb2 = newword(nw * 2);
Eric Andersen8401eea2004-08-04 19:16:54 +00004372 memcpy((char *) wb2->w_words, (char *) wb->w_words,
4373 nw * sizeof(char *));
Eric Andersenff9eee42001-06-29 04:57:14 +00004374 wb2->w_nword = nw;
4375 DELETE(wb);
4376 wb = wb2;
4377 }
4378 wb->w_words[wb->w_nword++] = wd;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004379 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004380}
Eric Andersen8401eea2004-08-04 19:16:54 +00004381
Denis Vlasenkoe4712752007-04-14 15:08:41 +00004382static char **getwords(struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004383{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004384 char **wd;
4385 int nb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004386
4387 if (wb == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004388 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004389 if (wb->w_nword == 0) {
4390 DELETE(wb);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004391 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004392 }
4393 wd = (char **) space(nb = sizeof(*wd) * wb->w_nword);
Eric Andersen8401eea2004-08-04 19:16:54 +00004394 memcpy((char *) wd, (char *) wb->w_words, nb);
4395 DELETE(wb); /* perhaps should done by caller */
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004396 return wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004397}
4398
"Vladimir N. Oleynik"ac973172005-09-22 14:38:17 +00004399static int (*func) (char *, char *);
4400static int globv;
Eric Andersenff9eee42001-06-29 04:57:14 +00004401
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004402static void glob3(char *i, char *j, char *k)
Eric Andersenff9eee42001-06-29 04:57:14 +00004403{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004404 char *index1, *index2, *index3;
4405 int c;
4406 int m;
4407
4408 m = globv;
4409 index1 = i;
4410 index2 = j;
4411 index3 = k;
4412 do {
4413 c = *index1;
4414 *index1++ = *index3;
4415 *index3++ = *index2;
4416 *index2++ = c;
4417 } while (--m);
4418}
4419
4420static void glob2(char *i, char *j)
4421{
4422 char *index1, *index2, c;
4423 int m;
4424
4425 m = globv;
4426 index1 = i;
4427 index2 = j;
4428 do {
4429 c = *index1;
4430 *index1++ = *index2;
4431 *index2++ = c;
4432 } while (--m);
Eric Andersenff9eee42001-06-29 04:57:14 +00004433}
4434
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004435static void glob1(char *base, char *lim)
Eric Andersenff9eee42001-06-29 04:57:14 +00004436{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004437 char *i, *j;
Eric Andersenff9eee42001-06-29 04:57:14 +00004438 int v2;
4439 char *lptr, *hptr;
4440 int c;
4441 unsigned n;
4442
Eric Andersenff9eee42001-06-29 04:57:14 +00004443 v2 = globv;
4444
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004445 top:
4446 n = (int) (lim - base);
4447 if (n <= v2)
Eric Andersenff9eee42001-06-29 04:57:14 +00004448 return;
Eric Andersen8401eea2004-08-04 19:16:54 +00004449 n = v2 * (n / (2 * v2));
4450 hptr = lptr = base + n;
Eric Andersenff9eee42001-06-29 04:57:14 +00004451 i = base;
Eric Andersen8401eea2004-08-04 19:16:54 +00004452 j = lim - v2;
4453 for (;;) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004454 if (i < lptr) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004455 c = (*func) (i, lptr);
4456 if (c == 0) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004457 lptr -= v2;
4458 glob2(i, lptr);
Eric Andersenff9eee42001-06-29 04:57:14 +00004459 continue;
4460 }
4461 if (c < 0) {
4462 i += v2;
4463 continue;
4464 }
4465 }
4466
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004467 begin:
Eric Andersenff9eee42001-06-29 04:57:14 +00004468 if (j > hptr) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004469 c = (*func) (hptr, j);
4470 if (c == 0) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004471 hptr += v2;
4472 glob2(hptr, j);
Eric Andersenff9eee42001-06-29 04:57:14 +00004473 goto begin;
4474 }
4475 if (c > 0) {
4476 if (i == lptr) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004477 hptr += v2;
4478 glob3(i, hptr, j);
4479 i = (lptr += v2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004480 goto begin;
4481 }
4482 glob2(i, j);
4483 j -= v2;
4484 i += v2;
4485 continue;
4486 }
4487 j -= v2;
4488 goto begin;
4489 }
4490
4491
4492 if (i == lptr) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004493 if (lptr - base >= lim - hptr) {
4494 glob1(hptr + v2, lim);
Eric Andersenff9eee42001-06-29 04:57:14 +00004495 lim = lptr;
4496 } else {
4497 glob1(base, lptr);
Eric Andersen8401eea2004-08-04 19:16:54 +00004498 base = hptr + v2;
Eric Andersenff9eee42001-06-29 04:57:14 +00004499 }
4500 goto top;
4501 }
4502
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004503 lptr -= v2;
4504 glob3(j, lptr, i);
4505 j = (hptr -= v2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004506 }
4507}
4508
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004509static void glob0(char *a0, unsigned a1, int a2, int (*a3) (char *, char *))
Eric Andersenff9eee42001-06-29 04:57:14 +00004510{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004511 func = a3;
4512 globv = a2;
4513 glob1(a0, a0 + a1 * a2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004514}
4515
Eric Andersenff9eee42001-06-29 04:57:14 +00004516
4517/* -------- io.c -------- */
4518
4519/*
4520 * shell IO
4521 */
4522
Eric Andersen8401eea2004-08-04 19:16:54 +00004523static int my_getc(int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00004524{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004525 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004526
Eric Andersen8401eea2004-08-04 19:16:54 +00004527 if (e.linep > elinep) {
4528 while ((c = readc()) != '\n' && c);
Eric Andersenff9eee42001-06-29 04:57:14 +00004529 err("input line too long");
4530 gflg++;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004531 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004532 }
4533 c = readc();
Eric Andersen737f5fb2003-03-14 16:05:59 +00004534 if ((ec != '\'') && (ec != '`') && (e.iop->task != XGRAVE)) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004535 if (c == '\\') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004536 c = readc();
4537 if (c == '\n' && ec != '\"')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004538 return my_getc(ec);
Eric Andersenff9eee42001-06-29 04:57:14 +00004539 c |= QUOTE;
4540 }
4541 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004542 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004543}
4544
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004545static void unget(int c)
Eric Andersenff9eee42001-06-29 04:57:14 +00004546{
4547 if (e.iop >= e.iobase)
4548 e.iop->peekc = c;
4549}
4550
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004551static int eofc(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00004552{
Eric Andersen8401eea2004-08-04 19:16:54 +00004553 return e.iop < e.iobase || (e.iop->peekc == 0 && e.iop->prev == 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004554}
4555
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004556static int readc(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00004557{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004558 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004559
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004560 RCPRINTF(("READC: e.iop %p, e.iobase %p\n", e.iop, e.iobase));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004561
4562 for (; e.iop >= e.iobase; e.iop--) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004563 RCPRINTF(("READC: e.iop %p, peekc 0x%x\n", e.iop, e.iop->peekc));
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004564 c = e.iop->peekc;
4565 if (c != '\0') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004566 e.iop->peekc = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004567 return c;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004568 }
4569 if (e.iop->prev != 0) {
4570 c = (*e.iop->iofn)(e.iop->argp, e.iop);
4571 if (c != '\0') {
4572 if (c == -1) {
4573 e.iop++;
4574 continue;
Eric Andersen8401eea2004-08-04 19:16:54 +00004575 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004576 if (e.iop == iostack)
4577 ioecho(c);
4578 e.iop->prev = c;
4579 return e.iop->prev;
Eric Andersenff9eee42001-06-29 04:57:14 +00004580 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004581 if (e.iop->task == XIO && e.iop->prev != '\n') {
4582 e.iop->prev = 0;
4583 if (e.iop == iostack)
4584 ioecho('\n');
4585 return '\n';
Eric Andersen8401eea2004-08-04 19:16:54 +00004586 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004587 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004588 if (e.iop->task == XIO) {
4589 if (multiline) {
4590 e.iop->prev = 0;
4591 return e.iop->prev;
4592 }
4593 if (interactive && e.iop == iostack + 1) {
4594#if ENABLE_FEATURE_EDITING
4595 current_prompt = prompt->value;
4596#else
4597 prs(prompt->value);
4598#endif
4599 }
4600 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004601 } /* FOR */
4602
4603 if (e.iop >= iostack) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004604 RCPRINTF(("READC: return 0, e.iop %p\n", e.iop));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004605 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004606 }
4607
4608 DBGPRINTF(("READC: leave()...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00004609 leave();
Eric Andersen12de6cf2004-08-04 19:19:10 +00004610
Eric Andersenff9eee42001-06-29 04:57:14 +00004611 /* NOTREACHED */
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004612 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004613}
4614
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004615static void ioecho(char c)
Eric Andersenff9eee42001-06-29 04:57:14 +00004616{
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00004617 if (FLAG['v'])
Eric Andersenff9eee42001-06-29 04:57:14 +00004618 write(2, &c, sizeof c);
4619}
4620
Eric Andersen12de6cf2004-08-04 19:19:10 +00004621
Eric Andersen8401eea2004-08-04 19:16:54 +00004622static void pushio(struct ioarg *argp, int (*fn) (struct ioarg *))
Eric Andersenff9eee42001-06-29 04:57:14 +00004623{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004624 DBGPRINTF(("PUSHIO: argp %p, argp->afid 0x%x, e.iop %p\n", argp,
Eric Andersen12de6cf2004-08-04 19:19:10 +00004625 argp->afid, e.iop));
4626
4627 /* Set env ptr for io source to next array spot and check for array overflow */
Eric Andersenff9eee42001-06-29 04:57:14 +00004628 if (++e.iop >= &iostack[NPUSH]) {
4629 e.iop--;
4630 err("Shell input nested too deeply");
4631 gflg++;
4632 return;
4633 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004634
4635 /* We did not overflow the NPUSH array spots so setup data structs */
4636
4637 e.iop->iofn = (int (*)(struct ioarg *, struct io *)) fn; /* Store data source func ptr */
Eric Andersenff9eee42001-06-29 04:57:14 +00004638
4639 if (argp->afid != AFID_NOBUF)
Eric Andersen8401eea2004-08-04 19:16:54 +00004640 e.iop->argp = argp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004641 else {
Eric Andersen12de6cf2004-08-04 19:19:10 +00004642
4643 e.iop->argp = ioargstack + (e.iop - iostack); /* MAL - index into stack */
4644 *e.iop->argp = *argp; /* copy data from temp area into stack spot */
4645
4646 /* MAL - mainbuf is for 1st data source (command line?) and all nested use a single shared buffer? */
4647
4648 if (e.iop == &iostack[0])
4649 e.iop->argp->afbuf = &mainbuf;
4650 else
4651 e.iop->argp->afbuf = &sharedbuf;
4652
4653 /* MAL - if not a termimal AND (commandline OR readable file) then give it a buffer id? */
4654 /* This line appears to be active when running scripts from command line */
4655 if ((isatty(e.iop->argp->afile) == 0)
4656 && (e.iop == &iostack[0]
Denis Vlasenkoea620772006-10-14 02:23:43 +00004657 || lseek(e.iop->argp->afile, 0L, SEEK_CUR) != -1)) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00004658 if (++bufid == AFID_NOBUF) /* counter rollover check, AFID_NOBUF = 11111111 */
4659 bufid = AFID_ID; /* AFID_ID = 0 */
4660
4661 e.iop->argp->afid = bufid; /* assign buffer id */
Eric Andersen8401eea2004-08-04 19:16:54 +00004662 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004663
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004664 DBGPRINTF(("PUSHIO: iostack %p, e.iop %p, afbuf %p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00004665 iostack, e.iop, e.iop->argp->afbuf));
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004666 DBGPRINTF(("PUSHIO: mbuf %p, sbuf %p, bid %d, e.iop %p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00004667 &mainbuf, &sharedbuf, bufid, e.iop));
4668
Eric Andersenff9eee42001-06-29 04:57:14 +00004669 }
4670
Eric Andersen8401eea2004-08-04 19:16:54 +00004671 e.iop->prev = ~'\n';
Eric Andersenff9eee42001-06-29 04:57:14 +00004672 e.iop->peekc = 0;
4673 e.iop->xchar = 0;
4674 e.iop->nlcount = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004675
Eric Andersenff9eee42001-06-29 04:57:14 +00004676 if (fn == filechar || fn == linechar)
4677 e.iop->task = XIO;
Eric Andersen8401eea2004-08-04 19:16:54 +00004678 else if (fn == (int (*)(struct ioarg *)) gravechar
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004679 || fn == (int (*)(struct ioarg *)) qgravechar)
Eric Andersenff9eee42001-06-29 04:57:14 +00004680 e.iop->task = XGRAVE;
4681 else
4682 e.iop->task = XOTHER;
4683}
4684
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004685static struct io *setbase(struct io *ip)
Eric Andersenff9eee42001-06-29 04:57:14 +00004686{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004687 struct io *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004688
4689 xp = e.iobase;
4690 e.iobase = ip;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004691 return xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004692}
4693
4694/*
4695 * Input generating functions
4696 */
4697
4698/*
4699 * Produce the characters of a string, then a newline, then EOF.
4700 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004701static int nlchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004702{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004703 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004704
4705 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004706 return 0;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004707 c = *ap->aword++;
4708 if (c == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004709 ap->aword = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004710 return '\n';
Eric Andersenff9eee42001-06-29 04:57:14 +00004711 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004712 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004713}
4714
4715/*
4716 * Given a list of words, produce the characters
4717 * in them, with a space after each word.
4718 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004719static int wdchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004720{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004721 char c;
4722 char **wl;
Eric Andersenff9eee42001-06-29 04:57:14 +00004723
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004724 wl = ap->awordlist;
4725 if (wl == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004726 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004727 if (*wl != NULL) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004728 c = *(*wl)++;
4729 if (c != 0)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004730 return c & 0177;
Eric Andersenff9eee42001-06-29 04:57:14 +00004731 ap->awordlist++;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004732 return ' ';
Eric Andersenff9eee42001-06-29 04:57:14 +00004733 }
4734 ap->awordlist = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004735 return '\n';
Eric Andersenff9eee42001-06-29 04:57:14 +00004736}
4737
4738/*
4739 * Return the characters of a list of words,
4740 * producing a space between them.
4741 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004742static int dolchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004743{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004744 char *wp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004745
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004746 wp = *ap->awordlist++;
4747 if (wp != NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004748 PUSHIO(aword, wp, *ap->awordlist == NULL ? strchar : xxchar);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004749 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004750 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004751 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004752}
4753
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004754static int xxchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004755{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004756 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004757
4758 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004759 return 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004760 c = *ap->aword++;
4761 if (c == '\0') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004762 ap->aword = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004763 return ' ';
Eric Andersenff9eee42001-06-29 04:57:14 +00004764 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004765 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004766}
4767
4768/*
4769 * Produce the characters from a single word (string).
4770 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004771static int strchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004772{
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004773 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004774 return 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004775 return *ap->aword++;
Eric Andersenff9eee42001-06-29 04:57:14 +00004776}
4777
4778/*
4779 * Produce quoted characters from a single word (string).
4780 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004781static int qstrchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004782{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004783 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004784
Denis Vlasenkob2abef32007-01-01 18:18:04 +00004785 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004786 return 0;
Denis Vlasenkob2abef32007-01-01 18:18:04 +00004787 c = *ap->aword++;
4788 if (c)
4789 c |= QUOTE;
4790 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004791}
4792
4793/*
4794 * Return the characters from a file.
4795 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004796static int filechar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004797{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004798 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004799 char c;
4800 struct iobuf *bp = ap->afbuf;
4801
4802 if (ap->afid != AFID_NOBUF) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004803 i = (ap->afid != bp->id);
4804 if (i || bp->bufp == bp->ebufp) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004805 if (i)
Denis Vlasenkoea620772006-10-14 02:23:43 +00004806 lseek(ap->afile, ap->afpos, SEEK_SET);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004807
Eric Andersen8401eea2004-08-04 19:16:54 +00004808 i = safe_read(ap->afile, bp->buf, sizeof(bp->buf));
4809 if (i <= 0) {
4810 closef(ap->afile);
4811 return 0;
4812 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004813
Eric Andersen8401eea2004-08-04 19:16:54 +00004814 bp->id = ap->afid;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004815 bp->bufp = bp->buf;
4816 bp->ebufp = bp->bufp + i;
Eric Andersen8401eea2004-08-04 19:16:54 +00004817 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004818
Eric Andersen8401eea2004-08-04 19:16:54 +00004819 ap->afpos++;
4820 return *bp->bufp++ & 0177;
Eric Andersenff9eee42001-06-29 04:57:14 +00004821 }
Denis Vlasenko38f63192007-01-22 09:03:07 +00004822#if ENABLE_FEATURE_EDITING
Eric Andersen737f5fb2003-03-14 16:05:59 +00004823 if (interactive && isatty(ap->afile)) {
Denis Vlasenko55f30b02007-03-24 22:42:29 +00004824 /* moved to G: static char filechar_cmdbuf[BUFSIZ]; */
Eric Andersen8401eea2004-08-04 19:16:54 +00004825 static int position = 0, size = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004826
Eric Andersen8401eea2004-08-04 19:16:54 +00004827 while (size == 0 || position >= size) {
Denis Vlasenko55f30b02007-03-24 22:42:29 +00004828 read_line_input(current_prompt, filechar_cmdbuf, BUFSIZ, line_input_state);
4829 size = strlen(filechar_cmdbuf);
Eric Andersen8401eea2004-08-04 19:16:54 +00004830 position = 0;
4831 }
Denis Vlasenko55f30b02007-03-24 22:42:29 +00004832 c = filechar_cmdbuf[position];
Eric Andersen8401eea2004-08-04 19:16:54 +00004833 position++;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004834 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004835 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004836#endif
4837 i = safe_read(ap->afile, &c, sizeof(c));
4838 return i == sizeof(c) ? (c & 0x7f) : (closef(ap->afile), 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004839}
4840
4841/*
4842 * Return the characters from a here temp file.
4843 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004844static int herechar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004845{
4846 char c;
4847
Eric Andersenff9eee42001-06-29 04:57:14 +00004848 if (read(ap->afile, &c, sizeof(c)) != sizeof(c)) {
4849 close(ap->afile);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004850 c = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00004851 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004852 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004853}
4854
4855/*
4856 * Return the characters produced by a process (`...`).
4857 * Quote them if required, and remove any trailing newline characters.
4858 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004859static int gravechar(struct ioarg *ap, struct io *iop)
Eric Andersenff9eee42001-06-29 04:57:14 +00004860{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004861 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004862
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004863 c = qgravechar(ap, iop) & ~QUOTE;
4864 if (c == '\n')
Eric Andersenff9eee42001-06-29 04:57:14 +00004865 c = ' ';
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004866 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004867}
4868
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004869static int qgravechar(struct ioarg *ap, struct io *iop)
Eric Andersenff9eee42001-06-29 04:57:14 +00004870{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004871 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004872
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004873 DBGPRINTF3(("QGRAVECHAR: enter, ap=%p, iop=%p\n", ap, iop));
Eric Andersenff9eee42001-06-29 04:57:14 +00004874
4875 if (iop->xchar) {
4876 if (iop->nlcount) {
4877 iop->nlcount--;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004878 return '\n' | QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00004879 }
4880 c = iop->xchar;
4881 iop->xchar = 0;
4882 } else if ((c = filechar(ap)) == '\n') {
4883 iop->nlcount = 1;
4884 while ((c = filechar(ap)) == '\n')
4885 iop->nlcount++;
4886 iop->xchar = c;
4887 if (c == 0)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004888 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004889 iop->nlcount--;
4890 c = '\n';
4891 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004892 return c != 0 ? c | QUOTE : 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004893}
4894
4895/*
4896 * Return a single command (usually the first line) from a file.
4897 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004898static int linechar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004899{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004900 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004901
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004902 c = filechar(ap);
4903 if (c == '\n') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004904 if (!multiline) {
4905 closef(ap->afile);
Eric Andersen8401eea2004-08-04 19:16:54 +00004906 ap->afile = -1; /* illegal value */
Eric Andersenff9eee42001-06-29 04:57:14 +00004907 }
4908 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004909 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004910}
4911
Eric Andersenff9eee42001-06-29 04:57:14 +00004912/*
4913 * remap fd into Shell's fd space
4914 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004915static int remap(int fd)
Eric Andersenff9eee42001-06-29 04:57:14 +00004916{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004917 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004918 int map[NOFILE];
Eric Andersen12de6cf2004-08-04 19:19:10 +00004919 int newfd;
4920
Eric Andersen12de6cf2004-08-04 19:19:10 +00004921 DBGPRINTF(("REMAP: fd=%d, e.iofd=%d\n", fd, e.iofd));
Eric Andersenff9eee42001-06-29 04:57:14 +00004922
4923 if (fd < e.iofd) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004924 for (i = 0; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004925 map[i] = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004926
Eric Andersenff9eee42001-06-29 04:57:14 +00004927 do {
4928 map[fd] = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004929 newfd = dup(fd);
4930 fd = newfd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004931 } while (fd >= 0 && fd < e.iofd);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004932
Eric Andersen8401eea2004-08-04 19:16:54 +00004933 for (i = 0; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004934 if (map[i])
4935 close(i);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004936
Eric Andersenff9eee42001-06-29 04:57:14 +00004937 if (fd < 0)
4938 err("too many files open in shell");
4939 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004940
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004941 return fd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004942}
4943
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004944static int openpipe(int *pv)
Eric Andersenff9eee42001-06-29 04:57:14 +00004945{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004946 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004947
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004948 i = pipe(pv);
4949 if (i < 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00004950 err("can't create pipe - try again");
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004951 return i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004952}
4953
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004954static void closepipe(int *pv)
Eric Andersenff9eee42001-06-29 04:57:14 +00004955{
4956 if (pv != NULL) {
4957 close(*pv++);
4958 close(*pv);
4959 }
4960}
4961
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004962
Eric Andersenff9eee42001-06-29 04:57:14 +00004963/* -------- here.c -------- */
4964
4965/*
4966 * here documents
4967 */
4968
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004969static void markhere(char *s, struct ioword *iop)
Eric Andersenff9eee42001-06-29 04:57:14 +00004970{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004971 struct here *h, *lh;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004972
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004973 DBGPRINTF7(("MARKHERE: enter, s=%p\n", s));
Eric Andersenff9eee42001-06-29 04:57:14 +00004974
4975 h = (struct here *) space(sizeof(struct here));
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004976 if (h == NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00004977 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004978
Eric Andersenff9eee42001-06-29 04:57:14 +00004979 h->h_tag = evalstr(s, DOSUB);
4980 if (h->h_tag == 0)
4981 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004982
Eric Andersenff9eee42001-06-29 04:57:14 +00004983 h->h_iop = iop;
4984 iop->io_name = 0;
4985 h->h_next = NULL;
4986 if (inhere == 0)
4987 inhere = h;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004988 else {
4989 for (lh = inhere; lh != NULL; lh = lh->h_next) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004990 if (lh->h_next == 0) {
4991 lh->h_next = h;
4992 break;
4993 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004994 }
4995 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004996 iop->io_flag |= IOHERE | IOXHERE;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004997 for (s = h->h_tag; *s; s++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004998 if (*s & QUOTE) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004999 iop->io_flag &= ~IOXHERE;
5000 *s &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00005001 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00005002 }
Eric Andersenff9eee42001-06-29 04:57:14 +00005003 h->h_dosub = iop->io_flag & IOXHERE;
5004}
5005
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005006static void gethere(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00005007{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005008 struct here *h, *hp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005009
5010 DBGPRINTF7(("GETHERE: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00005011
5012 /* Scan here files first leaving inhere list in place */
5013 for (hp = h = inhere; h != NULL; hp = h, h = h->h_next)
Eric Andersen8401eea2004-08-04 19:16:54 +00005014 readhere(&h->h_iop->io_name, h->h_tag, h->h_dosub ? 0 : '\'');
Eric Andersenff9eee42001-06-29 04:57:14 +00005015
5016 /* Make inhere list active - keep list intact for scraphere */
5017 if (hp != NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005018 hp->h_next = acthere;
5019 acthere = inhere;
5020 inhere = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00005021 }
5022}
5023
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005024static void readhere(char **name, char *s, int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00005025{
5026 int tf;
5027 char tname[30] = ".msh_XXXXXX";
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005028 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00005029 jmp_buf ev;
Eric Andersen8401eea2004-08-04 19:16:54 +00005030 char myline[LINELIM + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00005031 char *thenext;
5032
Mike Frysinger02d8fa42006-05-05 20:32:31 +00005033 DBGPRINTF7(("READHERE: enter, name=%p, s=%p\n", name, s));
Eric Andersen12de6cf2004-08-04 19:19:10 +00005034
Eric Andersenff9eee42001-06-29 04:57:14 +00005035 tf = mkstemp(tname);
5036 if (tf < 0)
5037 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005038
Eric Andersenff9eee42001-06-29 04:57:14 +00005039 *name = strsave(tname, areanum);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00005040 errpt = ev;
5041 if (newenv(setjmp(errpt)) != 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00005042 unlink(tname);
5043 else {
Eric Andersen8401eea2004-08-04 19:16:54 +00005044 pushio(e.iop->argp, (int (*)(struct ioarg *)) e.iop->iofn);
Eric Andersenff9eee42001-06-29 04:57:14 +00005045 e.iobase = e.iop;
5046 for (;;) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005047 if (interactive && e.iop <= iostack) {
Denis Vlasenko38f63192007-01-22 09:03:07 +00005048#if ENABLE_FEATURE_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00005049 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00005050#else
Eric Andersen8401eea2004-08-04 19:16:54 +00005051 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00005052#endif
5053 }
5054 thenext = myline;
5055 while ((c = my_getc(ec)) != '\n' && c) {
5056 if (ec == '\'')
Eric Andersen8401eea2004-08-04 19:16:54 +00005057 c &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00005058 if (thenext >= &myline[LINELIM]) {
5059 c = 0;
5060 break;
5061 }
5062 *thenext++ = c;
5063 }
5064 *thenext = 0;
5065 if (strcmp(s, myline) == 0 || c == 0)
5066 break;
5067 *thenext++ = '\n';
Eric Andersen8401eea2004-08-04 19:16:54 +00005068 write(tf, myline, (int) (thenext - myline));
Eric Andersenff9eee42001-06-29 04:57:14 +00005069 }
5070 if (c == 0) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005071 prs("here document `");
5072 prs(s);
5073 err("' unclosed");
Eric Andersenff9eee42001-06-29 04:57:14 +00005074 }
5075 quitenv();
5076 }
5077 close(tf);
5078}
5079
5080/*
5081 * open here temp file.
5082 * if unquoted here, expand here temp file into second temp file.
5083 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005084static int herein(char *hname, int xdoll)
Eric Andersenff9eee42001-06-29 04:57:14 +00005085{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005086 int hf;
Eric Andersenff9eee42001-06-29 04:57:14 +00005087 int tf;
5088
5089#if __GNUC__
5090 /* Avoid longjmp clobbering */
5091 (void) &tf;
5092#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00005093 if (hname == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00005094 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005095
5096 DBGPRINTF7(("HEREIN: hname is %s, xdoll=%d\n", hname, xdoll));
5097
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005098 hf = open(hname, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00005099 if (hf < 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00005100 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005101
Eric Andersenff9eee42001-06-29 04:57:14 +00005102 if (xdoll) {
5103 char c;
5104 char tname[30] = ".msh_XXXXXX";
5105 jmp_buf ev;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005106
Eric Andersenff9eee42001-06-29 04:57:14 +00005107 tf = mkstemp(tname);
5108 if (tf < 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00005109 return -1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00005110 errpt = ev;
5111 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00005112 PUSHIO(afile, hf, herechar);
5113 setbase(e.iop);
5114 while ((c = subgetc(0, 0)) != 0) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005115 c &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00005116 write(tf, &c, sizeof c);
5117 }
5118 quitenv();
5119 } else
5120 unlink(tname);
5121 close(tf);
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005122 tf = open(tname, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00005123 unlink(tname);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00005124 return tf;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00005125 }
5126 return hf;
Eric Andersenff9eee42001-06-29 04:57:14 +00005127}
5128
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005129static void scraphere(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00005130{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005131 struct here *h;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005132
5133 DBGPRINTF7(("SCRAPHERE: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00005134
5135 for (h = inhere; h != NULL; h = h->h_next) {
5136 if (h->h_iop && h->h_iop->io_name)
Eric Andersen8401eea2004-08-04 19:16:54 +00005137 unlink(h->h_iop->io_name);
Eric Andersenff9eee42001-06-29 04:57:14 +00005138 }
5139 inhere = NULL;
5140}
5141
5142/* unlink here temp files before a freearea(area) */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005143static void freehere(int area)
Eric Andersenff9eee42001-06-29 04:57:14 +00005144{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005145 struct here *h, *hl;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005146
5147 DBGPRINTF6(("FREEHERE: enter, area=%d\n", area));
Eric Andersenff9eee42001-06-29 04:57:14 +00005148
5149 hl = NULL;
5150 for (h = acthere; h != NULL; h = h->h_next)
5151 if (getarea((char *) h) >= area) {
5152 if (h->h_iop->io_name != NULL)
5153 unlink(h->h_iop->io_name);
5154 if (hl == NULL)
5155 acthere = h->h_next;
5156 else
5157 hl->h_next = h->h_next;
5158 } else
5159 hl = h;
5160}
5161
5162
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005163/* -------- sh.c -------- */
5164/*
5165 * shell
5166 */
5167
Denis Vlasenko06af2162007-02-03 17:28:39 +00005168int msh_main(int argc, char **argv);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005169int msh_main(int argc, char **argv)
5170{
5171 int f;
5172 char *s;
5173 int cflag;
5174 char *name, **ap;
5175 int (*iof) (struct ioarg *);
5176
Denis Vlasenko55f30b02007-03-24 22:42:29 +00005177 PTR_TO_GLOBALS = xzalloc(sizeof(G));
5178 sharedbuf.id = AFID_NOBUF;
5179 mainbuf.id = AFID_NOBUF;
5180 e.linep = line;
5181 elinep = line + sizeof(line) - 5;
5182
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005183#if ENABLE_FEATURE_EDITING
5184 line_input_state = new_line_input_t(FOR_SHELL);
5185#endif
5186
5187 DBGPRINTF(("MSH_MAIN: argc %d, environ %p\n", argc, environ));
5188
5189 initarea();
5190 ap = environ;
5191 if (ap != NULL) {
5192 while (*ap)
5193 assign(*ap++, !COPYV);
5194 for (ap = environ; *ap;)
5195 export(lookup(*ap++));
5196 }
5197 closeall();
5198 areanum = 1;
5199
5200 shell = lookup("SHELL");
5201 if (shell->value == null)
5202 setval(shell, (char *)DEFAULT_SHELL);
5203 export(shell);
5204
5205 homedir = lookup("HOME");
5206 if (homedir->value == null)
5207 setval(homedir, "/");
5208 export(homedir);
5209
5210 setval(lookup("$"), putn(getpid()));
5211
5212 path = lookup("PATH");
5213 if (path->value == null) {
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005214 /* Can be merged with same string elsewhere in bbox */
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005215 if (geteuid() == 0)
Denis Vlasenkof5f75c52007-06-12 22:35:19 +00005216 setval(path, bb_default_root_path);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005217 else
Denis Vlasenkof5f75c52007-06-12 22:35:19 +00005218 setval(path, bb_default_path);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005219 }
5220 export(path);
5221
5222 ifs = lookup("IFS");
5223 if (ifs->value == null)
5224 setval(ifs, " \t\n");
5225
5226#ifdef MSHDEBUG
5227 mshdbg_var = lookup("MSHDEBUG");
5228 if (mshdbg_var->value == null)
5229 setval(mshdbg_var, "0");
5230#endif
5231
5232 prompt = lookup("PS1");
5233#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
5234 if (prompt->value == null)
5235#endif
5236 setval(prompt, DEFAULT_USER_PROMPT);
5237 if (geteuid() == 0) {
5238 setval(prompt, DEFAULT_ROOT_PROMPT);
5239 prompt->status &= ~EXPORT;
5240 }
5241 cprompt = lookup("PS2");
5242#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
5243 if (cprompt->value == null)
5244#endif
5245 setval(cprompt, "> ");
5246
5247 iof = filechar;
5248 cflag = 0;
5249 name = *argv++;
5250 if (--argc >= 1) {
5251 if (argv[0][0] == '-' && argv[0][1] != '\0') {
5252 for (s = argv[0] + 1; *s; s++)
5253 switch (*s) {
5254 case 'c':
5255 prompt->status &= ~EXPORT;
5256 cprompt->status &= ~EXPORT;
5257 setval(prompt, "");
5258 setval(cprompt, "");
5259 cflag = 1;
5260 if (--argc > 0)
5261 PUSHIO(aword, *++argv, iof = nlchar);
5262 break;
5263
5264 case 'q':
5265 qflag = SIG_DFL;
5266 break;
5267
5268 case 's':
5269 /* standard input */
5270 break;
5271
5272 case 't':
5273 prompt->status &= ~EXPORT;
5274 setval(prompt, "");
5275 iof = linechar;
5276 break;
5277
5278 case 'i':
5279 interactive++;
5280 default:
5281 if (*s >= 'a' && *s <= 'z')
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00005282 FLAG[(int) *s]++;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005283 }
5284 } else {
5285 argv--;
5286 argc++;
5287 }
5288
5289 if (iof == filechar && --argc > 0) {
5290 setval(prompt, "");
5291 setval(cprompt, "");
5292 prompt->status &= ~EXPORT;
5293 cprompt->status &= ~EXPORT;
5294
5295/* Shell is non-interactive, activate printf-based debug */
5296#ifdef MSHDEBUG
5297 mshdbg = (int) (((char) (mshdbg_var->value[0])) - '0');
5298 if (mshdbg < 0)
5299 mshdbg = 0;
5300#endif
5301 DBGPRINTF(("MSH_MAIN: calling newfile()\n"));
5302
5303 name = *++argv;
5304 if (newfile(name))
5305 exit(1); /* Exit on error */
5306 }
5307 }
5308
5309 setdash();
5310
5311 /* This won't be true if PUSHIO has been called, say from newfile() above */
5312 if (e.iop < iostack) {
5313 PUSHIO(afile, 0, iof);
5314 if (isatty(0) && isatty(1) && !cflag) {
5315 interactive++;
5316#if !ENABLE_FEATURE_SH_EXTRA_QUIET
5317#ifdef MSHDEBUG
Denis Vlasenkoca525b42007-06-13 12:27:17 +00005318 printf("\n\n%s built-in shell (msh with debug)\n", bb_banner);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005319#else
Denis Vlasenkoca525b42007-06-13 12:27:17 +00005320 printf("\n\n%s built-in shell (msh)\n", bb_banner);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005321#endif
5322 printf("Enter 'help' for a list of built-in commands.\n\n");
5323#endif
5324 }
5325 }
5326
5327 signal(SIGQUIT, qflag);
5328 if (name && name[0] == '-') {
5329 interactive++;
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005330 f = open(".profile", O_RDONLY);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005331 if (f >= 0)
5332 next(remap(f));
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005333 f = open("/etc/profile", O_RDONLY);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005334 if (f >= 0)
5335 next(remap(f));
5336 }
5337 if (interactive)
5338 signal(SIGTERM, sig);
5339
5340 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
5341 signal(SIGINT, onintr);
5342 dolv = argv;
5343 dolc = argc;
5344 dolv[0] = name;
5345 if (dolc > 1) {
5346 for (ap = ++argv; --argc > 0;) {
5347 *ap = *argv++;
5348 if (assign(*ap, !COPYV)) {
5349 dolc--; /* keyword */
5350 } else {
5351 ap++;
5352 }
5353 }
5354 }
5355 setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc));
5356
5357 DBGPRINTF(("MSH_MAIN: begin FOR loop, interactive %d, e.iop %p, iostack %p\n", interactive, e.iop, iostack));
5358
5359 for (;;) {
5360 if (interactive && e.iop <= iostack) {
5361#if ENABLE_FEATURE_EDITING
5362 current_prompt = prompt->value;
5363#else
5364 prs(prompt->value);
5365#endif
5366 }
5367 onecommand();
5368 /* Ensure that getenv("PATH") stays current */
5369 setenv("PATH", path->value, 1);
5370 }
5371
5372 DBGPRINTF(("MSH_MAIN: returning.\n"));
5373}
5374
5375
Eric Andersenff9eee42001-06-29 04:57:14 +00005376/*
5377 * Copyright (c) 1987,1997, Prentice Hall
5378 * All rights reserved.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005379 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005380 * Redistribution and use of the MINIX operating system in source and
5381 * binary forms, with or without modification, are permitted provided
5382 * that the following conditions are met:
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005383 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005384 * Redistributions of source code must retain the above copyright
5385 * notice, this list of conditions and the following disclaimer.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005386 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005387 * Redistributions in binary form must reproduce the above
5388 * copyright notice, this list of conditions and the following
5389 * disclaimer in the documentation and/or other materials provided
5390 * with the distribution.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005391 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005392 * Neither the name of Prentice Hall nor the names of the software
5393 * authors or contributors may be used to endorse or promote
5394 * products derived from this software without specific prior
5395 * written permission.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005396 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005397 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND
5398 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
5399 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
5400 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
5401 * IN NO EVENT SHALL PRENTICE HALL OR ANY AUTHORS OR CONTRIBUTORS BE
5402 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
5403 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
5404 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
5405 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
5406 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
5407 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
5408 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5409 *
5410 */