blob: f1b3f05254f8cbc2decc19408052be463a27b2c7 [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 */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000283static char flags['z' - 'a' + 1] ALIGN1;
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
Denis Vlasenko6ca409e2007-08-12 20:58:27 +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",
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000596 "Terminated"
Eric Andersenff9eee42001-06-29 04:57:14 +0000597};
Eric Andersen8401eea2004-08-04 19:16:54 +0000598
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000599
Eric Andersenff9eee42001-06-29 04:57:14 +0000600struct res {
"Vladimir N. Oleynik"485d7cb2005-10-17 09:48:57 +0000601 const char *r_name;
Eric Andersen8401eea2004-08-04 19:16:54 +0000602 int r_val;
Eric Andersenff9eee42001-06-29 04:57:14 +0000603};
"Vladimir N. Oleynik"485d7cb2005-10-17 09:48:57 +0000604static const struct res restab[] = {
Denis Vlasenko95cb3262007-04-09 03:06:34 +0000605 { "for" , FOR },
606 { "case" , CASE },
607 { "esac" , ESAC },
608 { "while", WHILE },
609 { "do" , DO },
610 { "done" , DONE },
611 { "if" , IF },
612 { "in" , IN },
613 { "then" , THEN },
614 { "else" , ELSE },
615 { "elif" , ELIF },
616 { "until", UNTIL },
617 { "fi" , FI },
618 { ";;" , BREAK },
619 { "||" , LOGOR },
620 { "&&" , LOGAND },
621 { "{" , '{' },
622 { "}" , '}' },
623 { "." , DOT },
624 { NULL , 0 },
Eric Andersenff9eee42001-06-29 04:57:14 +0000625};
626
Eric Andersen1c039232001-07-07 00:05:55 +0000627struct builtincmd {
628 const char *name;
Denis Vlasenko95cb3262007-04-09 03:06:34 +0000629 int (*builtinfunc)(struct op *t);
Eric Andersenff9eee42001-06-29 04:57:14 +0000630};
Eric Andersen8401eea2004-08-04 19:16:54 +0000631static const struct builtincmd builtincmds[] = {
Denis Vlasenko95cb3262007-04-09 03:06:34 +0000632 { "." , dodot },
633 { ":" , dolabel },
634 { "break" , dobreak },
635 { "cd" , dochdir },
636 { "continue", docontinue },
637 { "eval" , doeval },
638 { "exec" , doexec },
639 { "exit" , doexit },
640 { "export" , doexport },
641 { "help" , dohelp },
642 { "login" , dologin },
643 { "newgrp" , dologin },
644 { "read" , doread },
645 { "readonly", doreadonly },
646 { "set" , doset },
647 { "shift" , doshift },
648 { "times" , dotimes },
649 { "trap" , dotrap },
650 { "umask" , doumask },
651 { "wait" , dowait },
652 { NULL , NULL },
Eric Andersenff9eee42001-06-29 04:57:14 +0000653};
654
"Vladimir N. Oleynik"ac973172005-09-22 14:38:17 +0000655static struct op *scantree(struct op *);
Eric Andersen12de6cf2004-08-04 19:19:10 +0000656static struct op *dowholefile(int, int);
657
Eric Andersen12de6cf2004-08-04 19:19:10 +0000658
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000659/* Globals */
Eric Andersen8401eea2004-08-04 19:16:54 +0000660static char **dolv;
661static int dolc;
662static int exstat;
663static char gflg;
"Vladimir N. Oleynik"485d7cb2005-10-17 09:48:57 +0000664static int interactive; /* Is this an interactive shell */
Eric Andersen8401eea2004-08-04 19:16:54 +0000665static int execflg;
666static int multiline; /* \n changed to ; */
667static struct op *outtree; /* result from parser */
668static xint *failpt;
669static xint *errpt;
670static struct brkcon *brklist;
671static int isbreak;
672static struct wdblock *wdlist;
673static struct wdblock *iolist;
Eric Andersen12de6cf2004-08-04 19:19:10 +0000674
675#ifdef MSHDEBUG
676static struct var *mshdbg_var;
677#endif
Eric Andersen8401eea2004-08-04 19:16:54 +0000678static struct var *vlist; /* dictionary */
679static struct var *homedir; /* home directory */
680static struct var *prompt; /* main prompt */
681static struct var *cprompt; /* continuation prompt */
682static struct var *path; /* search path for commands */
683static struct var *shell; /* shell to interpret command files */
684static struct var *ifs; /* field separators */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000685
Denis Vlasenko95cb3262007-04-09 03:06:34 +0000686static int areanum; /* current allocation area */
687static int intr; /* interrupt pending */
Eric Andersen8401eea2004-08-04 19:16:54 +0000688static int inparse;
Denis Vlasenko95cb3262007-04-09 03:06:34 +0000689static char *null = (char*)""; /* null value for variable */
690static int heedint = 1; /* heed interrupt signals */
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +0000691static void (*qflag)(int) = SIG_IGN;
Eric Andersen8401eea2004-08-04 19:16:54 +0000692static int startl;
693static int peeksym;
694static int nlseen;
695static int iounit = IODEFAULT;
696static YYSTYPE yylval;
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000697static char *elinep; /* done in main(): = line + sizeof(line) - 5 */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000698
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000699static struct here *inhere; /* list of hear docs while parsing */
700static struct here *acthere; /* list of active here documents */
701static struct region *areabot; /* bottom of area */
702static struct region *areatop; /* top of area */
703static struct region *areanxt; /* starting point of scan */
Eric Andersen8401eea2004-08-04 19:16:54 +0000704static void *brktop;
705static void *brkaddr;
Eric Andersenff9eee42001-06-29 04:57:14 +0000706
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000707/*
708 * parsing & execution environment
709 */
710struct env {
711 char *linep;
712 struct io *iobase;
713 struct io *iop;
714 xint *errpt; /* void * */
715 int iofd;
716 struct env *oenv;
717};
718
Eric Andersen12de6cf2004-08-04 19:19:10 +0000719static struct env e = {
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000720 NULL /* set to line in main() */, /* linep: char ptr */
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000721 iostack, /* iobase: struct io ptr */
722 iostack - 1, /* iop: struct io ptr */
723 (xint *) NULL, /* errpt: void ptr for errors? */
724 FDBASE, /* iofd: file desc */
725 (struct env *) NULL /* oenv: struct env ptr */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000726};
727
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000728
729struct globals {
730 char ourtrap[_NSIG + 1];
731 char *trap[_NSIG + 1];
732 struct iobuf sharedbuf; /* in main(): set to { AFID_NOBUF } */
733 struct iobuf mainbuf; /* in main(): set to { AFID_NOBUF } */
734 struct ioarg ioargstack[NPUSH];
735 char filechar_cmdbuf[BUFSIZ];
736 char line[LINELIM];
737 char child_cmd[LINELIM];
738};
739
740#define G (*ptr_to_globals)
741#define ourtrap (G.ourtrap )
742#define trap (G.trap )
743#define sharedbuf (G.sharedbuf )
744#define mainbuf (G.mainbuf )
745#define ioargstack (G.ioargstack )
746#define filechar_cmdbuf (G.filechar_cmdbuf)
747#define line (G.line )
748#define child_cmd (G.child_cmd )
749
750
Eric Andersen12de6cf2004-08-04 19:19:10 +0000751#ifdef MSHDEBUG
752void print_t(struct op *t)
753{
Mike Frysinger02d8fa42006-05-05 20:32:31 +0000754 DBGPRINTF(("T: t=%p, type %s, words=%p, IOword=%p\n", t,
755 T_CMD_NAMES[t->type], t->words, t->ioact));
Eric Andersen12de6cf2004-08-04 19:19:10 +0000756
757 if (t->words) {
758 DBGPRINTF(("T: W1: %s", t->words[0]));
759 }
Eric Andersen12de6cf2004-08-04 19:19:10 +0000760}
761
762void print_tree(struct op *head)
763{
764 if (head == NULL) {
765 DBGPRINTF(("PRINT_TREE: no tree\n"));
766 return;
767 }
768
Mike Frysinger02d8fa42006-05-05 20:32:31 +0000769 DBGPRINTF(("NODE: %p, left %p, right %p\n", head, head->left,
Eric Andersen12de6cf2004-08-04 19:19:10 +0000770 head->right));
771
772 if (head->left)
773 print_tree(head->left);
774
775 if (head->right)
776 print_tree(head->right);
Eric Andersen12de6cf2004-08-04 19:19:10 +0000777}
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000778#endif /* MSHDEBUG */
779
780
781/*
782 * IO functions
783 */
784static void prs(const char *s)
785{
786 if (*s)
787 write(2, s, strlen(s));
788}
789
790static void prn(unsigned u)
791{
792 prs(itoa(u));
793}
794
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000795static void echo(char **wp)
796{
797 int i;
798
799 prs("+");
800 for (i = 0; wp[i]; i++) {
801 if (i)
802 prs(" ");
803 prs(wp[i]);
804 }
805 prs("\n");
806}
807
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000808static void closef(int i)
809{
810 if (i > 2)
811 close(i);
812}
813
814static void closeall(void)
815{
816 int u;
817
818 for (u = NUFILE; u < NOFILE;)
819 close(u++);
820}
Eric Andersen12de6cf2004-08-04 19:19:10 +0000821
Eric Andersenff9eee42001-06-29 04:57:14 +0000822
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000823/* fail but return to process next command */
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000824static void fail(void) ATTRIBUTE_NORETURN;
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000825static void fail(void)
826{
827 longjmp(failpt, 1);
828 /* NOTREACHED */
829}
Eric Andersenff9eee42001-06-29 04:57:14 +0000830
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000831/* abort shell (or fail in subshell) */
832static void leave(void) ATTRIBUTE_NORETURN;
833static void leave(void)
834{
835 DBGPRINTF(("LEAVE: leave called!\n"));
836
837 if (execflg)
838 fail();
839 scraphere();
840 freehere(1);
841 runtrap(0);
842 _exit(exstat);
843 /* NOTREACHED */
844}
845
846static void warn(const char *s)
847{
848 if (*s) {
849 prs(s);
850 exstat = -1;
851 }
852 prs("\n");
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +0000853 if (FLAG['e'])
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000854 leave();
855}
856
857static void err(const char *s)
858{
859 warn(s);
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +0000860 if (FLAG['n'])
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000861 return;
862 if (!interactive)
863 leave();
864 if (e.errpt)
865 longjmp(e.errpt, 1);
866 closeall();
867 e.iop = e.iobase = iostack;
868}
869
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000870
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000871/* -------- area.c -------- */
872
Eric Andersenff9eee42001-06-29 04:57:14 +0000873/*
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000874 * All memory between (char *)areabot and (char *)(areatop+1) is
875 * exclusively administered by the area management routines.
876 * It is assumed that sbrk() and brk() manipulate the high end.
Eric Andersenff9eee42001-06-29 04:57:14 +0000877 */
878
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000879#define sbrk(X) ({ \
880 void * __q = (void *)-1; \
881 if (brkaddr + (int)(X) < brktop) { \
882 __q = brkaddr; \
883 brkaddr += (int)(X); \
884 } \
885 __q; \
886})
Eric Andersenff9eee42001-06-29 04:57:14 +0000887
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000888static void initarea(void)
Eric Andersenff9eee42001-06-29 04:57:14 +0000889{
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000890 brkaddr = xmalloc(AREASIZE);
891 brktop = brkaddr + AREASIZE;
Eric Andersenff9eee42001-06-29 04:57:14 +0000892
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000893 while ((long) sbrk(0) & ALIGN)
894 sbrk(1);
895 areabot = (struct region *) sbrk(REGSIZE);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +0000896
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000897 areabot->next = areabot;
898 areabot->area = BUSY;
899 areatop = areabot;
900 areanxt = areabot;
Eric Andersenff9eee42001-06-29 04:57:14 +0000901}
902
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000903static char *getcell(unsigned nbytes)
904{
905 int nregio;
906 struct region *p, *q;
907 int i;
908
909 if (nbytes == 0) {
910 puts("getcell(0)");
911 abort();
912 }
913 /* silly and defeats the algorithm */
914 /*
915 * round upwards and add administration area
916 */
917 nregio = (nbytes + (REGSIZE - 1)) / REGSIZE + 1;
918 p = areanxt;
919 for (;;) {
920 if (p->area > areanum) {
921 /*
922 * merge free cells
923 */
924 while ((q = p->next)->area > areanum && q != areanxt)
925 p->next = q->next;
926 /*
927 * exit loop if cell big enough
928 */
929 if (q >= p + nregio)
930 goto found;
931 }
932 p = p->next;
933 if (p == areanxt)
934 break;
935 }
936 i = nregio >= GROWBY ? nregio : GROWBY;
937 p = (struct region *) sbrk(i * REGSIZE);
938 if (p == (struct region *) -1)
939 return NULL;
940 p--;
941 if (p != areatop) {
942 puts("not contig");
943 abort(); /* allocated areas are contiguous */
944 }
945 q = p + i;
946 p->next = q;
947 p->area = FREE;
948 q->next = areabot;
949 q->area = BUSY;
950 areatop = q;
951 found:
952 /*
953 * we found a FREE area big enough, pointed to by 'p', and up to 'q'
954 */
955 areanxt = p + nregio;
956 if (areanxt < q) {
957 /*
958 * split into requested area and rest
959 */
960 if (areanxt + 1 > q) {
961 puts("OOM");
962 abort(); /* insufficient space left for admin */
963 }
964 areanxt->next = q;
965 areanxt->area = FREE;
966 p->next = areanxt;
967 }
968 p->area = areanum;
969 return (char *) (p + 1);
970}
971
972static void freecell(char *cp)
973{
974 struct region *p;
975
976 p = (struct region *) cp;
977 if (p != NULL) {
978 p--;
979 if (p < areanxt)
980 areanxt = p;
981 p->area = FREE;
982 }
983}
984#define DELETE(obj) freecell((char *)obj)
985
986static void freearea(int a)
987{
988 struct region *p, *top;
989
990 top = areatop;
991 for (p = areabot; p != top; p = p->next)
992 if (p->area >= a)
993 p->area = FREE;
994}
995
996static void setarea(char *cp, int a)
997{
998 struct region *p;
999
1000 p = (struct region *) cp;
1001 if (p != NULL)
1002 (p - 1)->area = a;
1003}
1004
1005static int getarea(char *cp)
1006{
1007 return ((struct region *) cp - 1)->area;
1008}
1009
1010static void garbage(void)
1011{
1012 struct region *p, *q, *top;
1013
1014 top = areatop;
1015 for (p = areabot; p != top; p = p->next) {
1016 if (p->area > areanum) {
1017 while ((q = p->next)->area > areanum)
1018 p->next = q->next;
1019 areanxt = p;
1020 }
1021 }
1022#ifdef SHRINKBY
1023 if (areatop >= q + SHRINKBY && q->area > areanum) {
1024 brk((char *) (q + 1));
1025 q->next = areabot;
1026 q->area = BUSY;
1027 areatop = q;
1028 }
1029#endif
1030}
1031
1032static char *space(int n)
1033{
1034 char *cp;
1035
1036 cp = getcell(n);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001037 if (cp == NULL)
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001038 err("out of string space");
1039 return cp;
1040}
1041
1042static char *strsave(const char *s, int a)
1043{
1044 char *cp;
1045
1046 cp = space(strlen(s) + 1);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001047 if (cp == NULL) {
1048// FIXME: I highly doubt this is good.
1049 return (char*)"";
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001050 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001051 setarea(cp, a);
1052 strcpy(cp, s);
1053 return cp;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001054}
1055
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001056
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001057/* -------- var.c -------- */
1058
1059static int eqname(const char *n1, const char *n2)
1060{
1061 for (; *n1 != '=' && *n1 != '\0'; n1++)
1062 if (*n2++ != *n1)
1063 return 0;
1064 return *n2 == '\0' || *n2 == '=';
1065}
1066
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001067static const char *findeq(const char *cp)
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001068{
1069 while (*cp != '\0' && *cp != '=')
1070 cp++;
1071 return cp;
1072}
1073
1074/*
1075 * Find the given name in the dictionary
1076 * and return its value. If the name was
1077 * not previously there, enter it now and
1078 * return a null value.
1079 */
1080static struct var *lookup(const char *n)
1081{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001082// FIXME: dirty hack
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001083 static struct var dummy;
1084
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001085 struct var *vp;
1086 const char *cp;
1087 char *xp;
1088 int c;
1089
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001090 if (isdigit(*n)) {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001091 dummy.name = (char*)n;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001092 for (c = 0; isdigit(*n) && c < 1000; n++)
1093 c = c * 10 + *n - '0';
1094 dummy.status = RONLY;
1095 dummy.value = (c <= dolc ? dolv[c] : null);
1096 return &dummy;
1097 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001098
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001099 for (vp = vlist; vp; vp = vp->next)
1100 if (eqname(vp->name, n))
1101 return vp;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001102
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001103 cp = findeq(n);
1104 vp = (struct var *) space(sizeof(*vp));
1105 if (vp == 0 || (vp->name = space((int) (cp - n) + 2)) == 0) {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001106 dummy.name = dummy.value = (char*)"";
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001107 return &dummy;
1108 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001109
1110 xp = vp->name;
1111 while ((*xp = *n++) != '\0' && *xp != '=')
1112 xp++;
1113 *xp++ = '=';
1114 *xp = '\0';
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001115 setarea((char *) vp, 0);
1116 setarea((char *) vp->name, 0);
1117 vp->value = null;
1118 vp->next = vlist;
1119 vp->status = GETCELL;
1120 vlist = vp;
1121 return vp;
1122}
1123
1124/*
1125 * if name is not NULL, it must be
1126 * a prefix of the space `val',
1127 * and end with `='.
1128 * this is all so that exporting
1129 * values is reasonably painless.
1130 */
1131static void nameval(struct var *vp, const char *val, const char *name)
1132{
1133 const char *cp;
1134 char *xp;
1135 int fl;
1136
1137 if (vp->status & RONLY) {
1138 xp = vp->name;
1139 while (*xp && *xp != '=')
1140 putc(*xp++, stderr);
1141 err(" is read-only");
1142 return;
1143 }
1144 fl = 0;
1145 if (name == NULL) {
1146 xp = space(strlen(vp->name) + strlen(val) + 2);
1147 if (xp == NULL)
1148 return;
1149 /* make string: name=value */
1150 setarea(xp, 0);
1151 name = xp;
1152 cp = vp->name;
1153 while ((*xp = *cp++) != '\0' && *xp != '=')
1154 xp++;
1155 *xp++ = '=';
1156 strcpy(xp, val);
1157 val = xp;
1158 fl = GETCELL;
1159 }
1160 if (vp->status & GETCELL)
1161 freecell(vp->name); /* form new string `name=value' */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001162 vp->name = (char*)name;
1163 vp->value = (char*)val;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001164 vp->status |= fl;
1165}
1166
1167/*
1168 * give variable at `vp' the value `val'.
1169 */
1170static void setval(struct var *vp, const char *val)
1171{
1172 nameval(vp, val, NULL);
1173}
1174
1175static void export(struct var *vp)
1176{
1177 vp->status |= EXPORT;
1178}
1179
1180static void ronly(struct var *vp)
1181{
1182 if (isalpha(vp->name[0]) || vp->name[0] == '_') /* not an internal symbol */
1183 vp->status |= RONLY;
1184}
1185
1186static int isassign(const char *s)
1187{
1188 unsigned char c;
1189 DBGPRINTF7(("ISASSIGN: enter, s=%s\n", s));
1190
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001191 c = *s;
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001192 /* no isalpha() - we shouldn't use locale */
1193 /* c | 0x20 - lowercase (Latin) letters */
1194 if (c != '_' && (unsigned)((c|0x20) - 'a') > 25)
1195 /* not letter */
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001196 return 0;
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001197
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001198 while (1) {
1199 c = *++s;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001200 if (c == '=')
1201 return 1;
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001202 if (c == '\0')
1203 return 0;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001204 if (c != '_'
1205 && (unsigned)(c - '0') > 9 /* not number */
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001206 && (unsigned)((c|0x20) - 'a') > 25 /* not letter */
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001207 ) {
1208 return 0;
1209 }
1210 }
1211}
1212
1213static int assign(const char *s, int cf)
1214{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001215 const char *cp;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001216 struct var *vp;
1217
1218 DBGPRINTF7(("ASSIGN: enter, s=%s, cf=%d\n", s, cf));
1219
1220 if (!isalpha(*s) && *s != '_')
1221 return 0;
1222 for (cp = s; *cp != '='; cp++)
1223 if (*cp == '\0' || (!isalnum(*cp) && *cp != '_'))
1224 return 0;
1225 vp = lookup(s);
1226 nameval(vp, ++cp, cf == COPYV ? NULL : s);
1227 if (cf != COPYV)
1228 vp->status &= ~GETCELL;
1229 return 1;
1230}
1231
1232static int checkname(char *cp)
1233{
1234 DBGPRINTF7(("CHECKNAME: enter, cp=%s\n", cp));
1235
1236 if (!isalpha(*cp++) && *(cp - 1) != '_')
1237 return 0;
1238 while (*cp)
1239 if (!isalnum(*cp++) && *(cp - 1) != '_')
1240 return 0;
1241 return 1;
1242}
1243
1244static void putvlist(int f, int out)
1245{
1246 struct var *vp;
1247
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001248 for (vp = vlist; vp; vp = vp->next) {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001249 if (vp->status & f && (isalpha(*vp->name) || *vp->name == '_')) {
1250 if (vp->status & EXPORT)
1251 write(out, "export ", 7);
1252 if (vp->status & RONLY)
1253 write(out, "readonly ", 9);
1254 write(out, vp->name, (int) (findeq(vp->name) - vp->name));
1255 write(out, "\n", 1);
1256 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001257 }
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001258}
1259
1260
1261/*
1262 * trap handling
1263 */
1264static void sig(int i)
1265{
1266 trapset = i;
1267 signal(i, sig);
1268}
1269
1270static void runtrap(int i)
1271{
1272 char *trapstr;
1273
1274 trapstr = trap[i];
1275 if (trapstr == NULL)
1276 return;
1277
1278 if (i == 0)
1279 trap[i] = NULL;
1280
1281 RUN(aword, trapstr, nlchar);
1282}
1283
1284
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001285static void setdash(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001286{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001287 char *cp;
1288 int c;
Eric Andersen8401eea2004-08-04 19:16:54 +00001289 char m['z' - 'a' + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00001290
1291 cp = m;
Eric Andersen8401eea2004-08-04 19:16:54 +00001292 for (c = 'a'; c <= 'z'; c++)
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00001293 if (FLAG[c])
Eric Andersenff9eee42001-06-29 04:57:14 +00001294 *cp++ = c;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001295 *cp = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00001296 setval(lookup("-"), m);
1297}
1298
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001299static int newfile(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00001300{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001301 int f;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001302
1303 DBGPRINTF7(("NEWFILE: opening %s\n", s));
Eric Andersenff9eee42001-06-29 04:57:14 +00001304
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001305 f = 0;
Denis Vlasenko9f739442006-12-16 23:49:13 +00001306 if (NOT_LONE_DASH(s)) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001307 DBGPRINTF(("NEWFILE: s is %s\n", s));
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00001308 f = open(s, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00001309 if (f < 0) {
1310 prs(s);
1311 err(": cannot open");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001312 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001313 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001314 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001315
Eric Andersenff9eee42001-06-29 04:57:14 +00001316 next(remap(f));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001317 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001318}
1319
Eric Andersen12de6cf2004-08-04 19:19:10 +00001320
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001321struct op *scantree(struct op *head)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001322{
1323 struct op *dotnode;
1324
1325 if (head == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001326 return NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001327
1328 if (head->left != NULL) {
1329 dotnode = scantree(head->left);
1330 if (dotnode)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001331 return dotnode;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001332 }
1333
1334 if (head->right != NULL) {
1335 dotnode = scantree(head->right);
1336 if (dotnode)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001337 return dotnode;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001338 }
1339
1340 if (head->words == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001341 return NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001342
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001343 DBGPRINTF5(("SCANTREE: checking node %p\n", head));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001344
Denis Vlasenkocf787cf2007-02-04 17:11:25 +00001345 if ((head->type != TDOT) && LONE_CHAR(head->words[0], '.')) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001346 DBGPRINTF5(("SCANTREE: dot found in node %p\n", head));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001347 return head;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001348 }
1349
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001350 return NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001351}
1352
1353
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001354static void onecommand(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001355{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001356 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00001357 jmp_buf m1;
1358
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001359 DBGPRINTF(("ONECOMMAND: enter, outtree=%p\n", outtree));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001360
Eric Andersenff9eee42001-06-29 04:57:14 +00001361 while (e.oenv)
1362 quitenv();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001363
Eric Andersenff9eee42001-06-29 04:57:14 +00001364 areanum = 1;
1365 freehere(areanum);
1366 freearea(areanum);
1367 garbage();
1368 wdlist = 0;
1369 iolist = 0;
1370 e.errpt = 0;
1371 e.linep = line;
1372 yynerrs = 0;
1373 multiline = 0;
1374 inparse = 1;
1375 intr = 0;
1376 execflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001377
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001378 failpt = m1;
1379 setjmp(failpt); /* Bruce Evans' fix */
1380 failpt = m1;
1381 if (setjmp(failpt) || yyparse() || intr) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001382 DBGPRINTF(("ONECOMMAND: this is not good.\n"));
1383
Eric Andersenff9eee42001-06-29 04:57:14 +00001384 while (e.oenv)
1385 quitenv();
1386 scraphere();
1387 if (!interactive && intr)
1388 leave();
1389 inparse = 0;
1390 intr = 0;
1391 return;
1392 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001393
Eric Andersenff9eee42001-06-29 04:57:14 +00001394 inparse = 0;
1395 brklist = 0;
1396 intr = 0;
1397 execflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001398
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00001399 if (!FLAG['n']) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001400 DBGPRINTF(("ONECOMMAND: calling execute, t=outtree=%p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00001401 outtree));
Eric Andersenff9eee42001-06-29 04:57:14 +00001402 execute(outtree, NOPIPE, NOPIPE, 0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001403 }
1404
Eric Andersenff9eee42001-06-29 04:57:14 +00001405 if (!interactive && intr) {
1406 execflg = 0;
1407 leave();
1408 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001409
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001410 i = trapset;
1411 if (i != 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001412 trapset = 0;
1413 runtrap(i);
1414 }
1415}
1416
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001417static int newenv(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00001418{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001419 struct env *ep;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001420
1421 DBGPRINTF(("NEWENV: f=%d (indicates quitenv and return)\n", f));
Eric Andersenff9eee42001-06-29 04:57:14 +00001422
1423 if (f) {
1424 quitenv();
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001425 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001426 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001427
Eric Andersenff9eee42001-06-29 04:57:14 +00001428 ep = (struct env *) space(sizeof(*ep));
1429 if (ep == NULL) {
1430 while (e.oenv)
1431 quitenv();
1432 fail();
1433 }
1434 *ep = e;
1435 e.oenv = ep;
1436 e.errpt = errpt;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001437
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001438 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001439}
1440
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001441static void quitenv(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001442{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001443 struct env *ep;
1444 int fd;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001445
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001446 DBGPRINTF(("QUITENV: e.oenv=%p\n", e.oenv));
Eric Andersenff9eee42001-06-29 04:57:14 +00001447
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001448 ep = e.oenv;
1449 if (ep != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001450 fd = e.iofd;
1451 e = *ep;
1452 /* should close `'d files */
1453 DELETE(ep);
1454 while (--fd >= e.iofd)
1455 close(fd);
1456 }
1457}
1458
1459/*
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001460 * Is character c in s?
Eric Andersenff9eee42001-06-29 04:57:14 +00001461 */
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001462static int any(int c, const char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00001463{
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001464 while (*s)
1465 if (*s++ == c)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001466 return 1;
1467 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001468}
1469
1470/*
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001471 * Is any character from s1 in s2?
Eric Andersenff9eee42001-06-29 04:57:14 +00001472 */
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001473static int anys(const char *s1, const char *s2)
Eric Andersenff9eee42001-06-29 04:57:14 +00001474{
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001475 while (*s1)
1476 if (any(*s1++, s2))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001477 return 1;
1478 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001479}
1480
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001481static char *putn(int n)
Eric Andersenff9eee42001-06-29 04:57:14 +00001482{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001483 return itoa(n);
Eric Andersenff9eee42001-06-29 04:57:14 +00001484}
1485
Eric Andersen8401eea2004-08-04 19:16:54 +00001486static void next(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00001487{
1488 PUSHIO(afile, f, filechar);
1489}
1490
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001491static void onintr(int s) /* ANSI C requires a parameter */
Eric Andersenff9eee42001-06-29 04:57:14 +00001492{
1493 signal(SIGINT, onintr);
1494 intr = 1;
1495 if (interactive) {
1496 if (inparse) {
1497 prs("\n");
1498 fail();
1499 }
Eric Andersen8401eea2004-08-04 19:16:54 +00001500 } else if (heedint) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001501 execflg = 0;
1502 leave();
1503 }
1504}
1505
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001506
Eric Andersenff9eee42001-06-29 04:57:14 +00001507/* -------- gmatch.c -------- */
1508/*
1509 * int gmatch(string, pattern)
1510 * char *string, *pattern;
1511 *
1512 * Match a pattern as in sh(1).
1513 */
1514
1515#define CMASK 0377
1516#define QUOTE 0200
Denis Vlasenko55f30b02007-03-24 22:42:29 +00001517#define QMASK (CMASK & ~QUOTE)
Eric Andersen8401eea2004-08-04 19:16:54 +00001518#define NOT '!' /* might use ^ */
Eric Andersenff9eee42001-06-29 04:57:14 +00001519
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001520static const char *cclass(const char *p, int sub)
1521{
1522 int c, d, not, found;
1523
1524 not = (*p == NOT);
1525 if (not != 0)
1526 p++;
1527 found = not;
1528 do {
1529 if (*p == '\0')
1530 return NULL;
1531 c = *p & CMASK;
1532 if (p[1] == '-' && p[2] != ']') {
1533 d = p[2] & CMASK;
1534 p++;
1535 } else
1536 d = c;
1537 if (c == sub || (c <= sub && sub <= d))
1538 found = !not;
1539 } while (*++p != ']');
1540 return found ? p + 1 : NULL;
1541}
1542
1543static int gmatch(const char *s, const char *p)
Eric Andersenff9eee42001-06-29 04:57:14 +00001544{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001545 int sc, pc;
Eric Andersenff9eee42001-06-29 04:57:14 +00001546
1547 if (s == NULL || p == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001548 return 0;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001549
Eric Andersenff9eee42001-06-29 04:57:14 +00001550 while ((pc = *p++ & CMASK) != '\0') {
1551 sc = *s++ & QMASK;
1552 switch (pc) {
1553 case '[':
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001554 p = cclass(p, sc);
1555 if (p == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001556 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001557 break;
1558
1559 case '?':
1560 if (sc == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001561 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001562 break;
1563
1564 case '*':
1565 s--;
1566 do {
1567 if (*p == '\0' || gmatch(s, p))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001568 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001569 } while (*s++ != '\0');
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001570 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001571
1572 default:
Eric Andersen8401eea2004-08-04 19:16:54 +00001573 if (sc != (pc & ~QUOTE))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001574 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001575 }
1576 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001577 return *s == '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00001578}
1579
Eric Andersenff9eee42001-06-29 04:57:14 +00001580
Eric Andersenff9eee42001-06-29 04:57:14 +00001581/* -------- csyn.c -------- */
1582/*
1583 * shell: syntax (C version)
1584 */
1585
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001586static void yyerror(const char *s) ATTRIBUTE_NORETURN;
1587static void yyerror(const char *s)
1588{
1589 yynerrs++;
1590 if (interactive && e.iop <= iostack) {
1591 multiline = 0;
1592 while (eofc() == 0 && yylex(0) != '\n');
1593 }
1594 err(s);
1595 fail();
1596}
1597
1598static void zzerr(void) ATTRIBUTE_NORETURN;
1599static void zzerr(void)
1600{
1601 yyerror("syntax error");
1602}
1603
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001604int yyparse(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001605{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001606 DBGPRINTF7(("YYPARSE: enter...\n"));
1607
Eric Andersen8401eea2004-08-04 19:16:54 +00001608 startl = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001609 peeksym = 0;
1610 yynerrs = 0;
1611 outtree = c_list();
1612 musthave('\n', 0);
Eric Andersen8401eea2004-08-04 19:16:54 +00001613 return (yynerrs != 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001614}
1615
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001616static struct op *pipeline(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001617{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001618 struct op *t, *p;
1619 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001620
1621 DBGPRINTF7(("PIPELINE: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001622
1623 t = command(cf);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001624
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001625 DBGPRINTF9(("PIPELINE: t=%p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001626
Eric Andersenff9eee42001-06-29 04:57:14 +00001627 if (t != NULL) {
1628 while ((c = yylex(0)) == '|') {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001629 p = command(CONTIN);
1630 if (p == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001631 DBGPRINTF8(("PIPELINE: error!\n"));
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001632 zzerr();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001633 }
1634
Eric Andersenff9eee42001-06-29 04:57:14 +00001635 if (t->type != TPAREN && t->type != TCOM) {
1636 /* shell statement */
1637 t = block(TPAREN, t, NOBLOCK, NOWORDS);
1638 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001639
Eric Andersenff9eee42001-06-29 04:57:14 +00001640 t = block(TPIPE, t, p, NOWORDS);
1641 }
1642 peeksym = c;
1643 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001644
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001645 DBGPRINTF7(("PIPELINE: returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001646 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001647}
1648
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001649static struct op *andor(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001650{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001651 struct op *t, *p;
1652 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001653
1654 DBGPRINTF7(("ANDOR: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001655
1656 t = pipeline(0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001657
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001658 DBGPRINTF9(("ANDOR: t=%p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001659
Eric Andersenff9eee42001-06-29 04:57:14 +00001660 if (t != NULL) {
1661 while ((c = yylex(0)) == LOGAND || c == LOGOR) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001662 p = pipeline(CONTIN);
1663 if (p == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001664 DBGPRINTF8(("ANDOR: error!\n"));
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001665 zzerr();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001666 }
1667
Eric Andersen8401eea2004-08-04 19:16:54 +00001668 t = block(c == LOGAND ? TAND : TOR, t, p, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001669 } /* WHILE */
1670
Eric Andersenff9eee42001-06-29 04:57:14 +00001671 peeksym = c;
1672 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001673
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001674 DBGPRINTF7(("ANDOR: returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001675 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001676}
1677
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001678static struct op *c_list(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001679{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001680 struct op *t, *p;
1681 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001682
1683 DBGPRINTF7(("C_LIST: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001684
1685 t = andor();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001686
Eric Andersenff9eee42001-06-29 04:57:14 +00001687 if (t != NULL) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001688 peeksym = yylex(0);
1689 if (peeksym == '&')
Eric Andersenff9eee42001-06-29 04:57:14 +00001690 t = block(TASYNC, t, NOBLOCK, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001691
Eric Andersen8401eea2004-08-04 19:16:54 +00001692 while ((c = yylex(0)) == ';' || c == '&'
1693 || (multiline && c == '\n')) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001694
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001695 p = andor();
1696 if (p== NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001697 return t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001698
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001699 peeksym = yylex(0);
1700 if (peeksym == '&')
Eric Andersenff9eee42001-06-29 04:57:14 +00001701 p = block(TASYNC, p, NOBLOCK, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001702
Eric Andersenff9eee42001-06-29 04:57:14 +00001703 t = list(t, p);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001704 } /* WHILE */
1705
Eric Andersenff9eee42001-06-29 04:57:14 +00001706 peeksym = c;
1707 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001708 /* IF */
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001709 DBGPRINTF7(("C_LIST: returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001710 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001711}
1712
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001713static int synio(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001714{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001715 struct ioword *iop;
1716 int i;
1717 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001718
1719 DBGPRINTF7(("SYNIO: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001720
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001721 c = yylex(cf);
1722 if (c != '<' && c != '>') {
Eric Andersenff9eee42001-06-29 04:57:14 +00001723 peeksym = c;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001724 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001725 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001726
Eric Andersenff9eee42001-06-29 04:57:14 +00001727 i = yylval.i;
1728 musthave(WORD, 0);
1729 iop = io(iounit, i, yylval.cp);
1730 iounit = IODEFAULT;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001731
Eric Andersenff9eee42001-06-29 04:57:14 +00001732 if (i & IOHERE)
1733 markhere(yylval.cp, iop);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001734
1735 DBGPRINTF7(("SYNIO: returning 1\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001736 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001737}
1738
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001739static void musthave(int c, int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001740{
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001741 peeksym = yylex(cf);
1742 if (peeksym != c) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001743 DBGPRINTF7(("MUSTHAVE: error!\n"));
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001744 zzerr();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001745 }
1746
Eric Andersenff9eee42001-06-29 04:57:14 +00001747 peeksym = 0;
1748}
1749
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001750static struct op *simple(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001751{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001752 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001753
1754 t = NULL;
1755 for (;;) {
1756 switch (peeksym = yylex(0)) {
1757 case '<':
1758 case '>':
1759 (void) synio(0);
1760 break;
1761
1762 case WORD:
1763 if (t == NULL) {
1764 t = newtp();
1765 t->type = TCOM;
1766 }
1767 peeksym = 0;
1768 word(yylval.cp);
1769 break;
1770
1771 default:
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001772 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001773 }
1774 }
1775}
1776
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001777static struct op *nested(int type, int mark)
Eric Andersenff9eee42001-06-29 04:57:14 +00001778{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001779 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001780
1781 DBGPRINTF3(("NESTED: enter, type=%d, mark=%d\n", type, mark));
Eric Andersenff9eee42001-06-29 04:57:14 +00001782
1783 multiline++;
1784 t = c_list();
1785 musthave(mark, 0);
1786 multiline--;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001787 return block(type, t, NOBLOCK, NOWORDS);
Eric Andersenff9eee42001-06-29 04:57:14 +00001788}
1789
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001790static struct op *command(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001791{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001792 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001793 struct wdblock *iosave;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001794 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001795
1796 DBGPRINTF(("COMMAND: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001797
1798 iosave = iolist;
1799 iolist = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001800
Eric Andersenff9eee42001-06-29 04:57:14 +00001801 if (multiline)
1802 cf |= CONTIN;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001803
Eric Andersenff9eee42001-06-29 04:57:14 +00001804 while (synio(cf))
1805 cf = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001806
1807 c = yylex(cf);
1808
1809 switch (c) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001810 default:
1811 peeksym = c;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001812 t = simple();
1813 if (t == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001814 if (iolist == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001815 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001816 t = newtp();
1817 t->type = TCOM;
1818 }
1819 break;
1820
1821 case '(':
1822 t = nested(TPAREN, ')');
1823 break;
1824
1825 case '{':
1826 t = nested(TBRACE, '}');
1827 break;
1828
1829 case FOR:
1830 t = newtp();
1831 t->type = TFOR;
1832 musthave(WORD, 0);
1833 startl = 1;
1834 t->str = yylval.cp;
1835 multiline++;
1836 t->words = wordlist();
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001837 c = yylex(0);
1838 if (c != '\n' && c != ';')
Eric Andersenff9eee42001-06-29 04:57:14 +00001839 peeksym = c;
1840 t->left = dogroup(0);
1841 multiline--;
1842 break;
1843
1844 case WHILE:
1845 case UNTIL:
1846 multiline++;
1847 t = newtp();
Eric Andersen8401eea2004-08-04 19:16:54 +00001848 t->type = c == WHILE ? TWHILE : TUNTIL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001849 t->left = c_list();
1850 t->right = dogroup(1);
1851 t->words = NULL;
1852 multiline--;
1853 break;
1854
1855 case CASE:
1856 t = newtp();
1857 t->type = TCASE;
1858 musthave(WORD, 0);
1859 t->str = yylval.cp;
1860 startl++;
1861 multiline++;
1862 musthave(IN, CONTIN);
1863 startl++;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001864
Eric Andersenff9eee42001-06-29 04:57:14 +00001865 t->left = caselist();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001866
Eric Andersenff9eee42001-06-29 04:57:14 +00001867 musthave(ESAC, 0);
1868 multiline--;
1869 break;
1870
1871 case IF:
1872 multiline++;
1873 t = newtp();
1874 t->type = TIF;
1875 t->left = c_list();
1876 t->right = thenpart();
1877 musthave(FI, 0);
1878 multiline--;
1879 break;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001880
1881 case DOT:
1882 t = newtp();
1883 t->type = TDOT;
1884
1885 musthave(WORD, 0); /* gets name of file */
1886 DBGPRINTF7(("COMMAND: DOT clause, yylval.cp is %s\n", yylval.cp));
1887
1888 word(yylval.cp); /* add word to wdlist */
1889 word(NOWORD); /* terminate wdlist */
1890 t->words = copyw(); /* dup wdlist */
1891 break;
1892
Eric Andersenff9eee42001-06-29 04:57:14 +00001893 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001894
Eric Andersen8401eea2004-08-04 19:16:54 +00001895 while (synio(0));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001896
Eric Andersenff9eee42001-06-29 04:57:14 +00001897 t = namelist(t);
1898 iolist = iosave;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001899
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001900 DBGPRINTF(("COMMAND: returning %p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001901
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001902 return t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001903}
1904
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001905static struct op *dowholefile(int type, int mark)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001906{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001907 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001908
1909 DBGPRINTF(("DOWHOLEFILE: enter, type=%d, mark=%d\n", type, mark));
1910
1911 multiline++;
1912 t = c_list();
1913 multiline--;
1914 t = block(type, t, NOBLOCK, NOWORDS);
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001915 DBGPRINTF(("DOWHOLEFILE: return t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001916 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001917}
1918
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001919static struct op *dogroup(int onlydone)
Eric Andersenff9eee42001-06-29 04:57:14 +00001920{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001921 int c;
1922 struct op *mylist;
Eric Andersenff9eee42001-06-29 04:57:14 +00001923
1924 c = yylex(CONTIN);
1925 if (c == DONE && onlydone)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001926 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001927 if (c != DO)
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001928 zzerr();
Eric Andersenff9eee42001-06-29 04:57:14 +00001929 mylist = c_list();
1930 musthave(DONE, 0);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001931 return mylist;
Eric Andersenff9eee42001-06-29 04:57:14 +00001932}
1933
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001934static struct op *thenpart(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001935{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001936 int c;
1937 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001938
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001939 c = yylex(0);
1940 if (c != THEN) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001941 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001942 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001943 }
1944 t = newtp();
1945 t->type = 0;
1946 t->left = c_list();
1947 if (t->left == NULL)
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001948 zzerr();
Eric Andersenff9eee42001-06-29 04:57:14 +00001949 t->right = elsepart();
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001950 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001951}
1952
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001953static struct op *elsepart(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001954{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001955 int c;
1956 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001957
1958 switch (c = yylex(0)) {
1959 case ELSE:
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001960 t = c_list();
1961 if (t == NULL)
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001962 zzerr();
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001963 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001964
1965 case ELIF:
1966 t = newtp();
1967 t->type = TELIF;
1968 t->left = c_list();
1969 t->right = thenpart();
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001970 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001971
1972 default:
1973 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001974 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001975 }
1976}
1977
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001978static struct op *caselist(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001979{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001980 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001981
1982 t = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001983 while ((peeksym = yylex(CONTIN)) != ESAC) {
1984 DBGPRINTF(("CASELIST, doing yylex, peeksym=%d\n", peeksym));
Eric Andersenff9eee42001-06-29 04:57:14 +00001985 t = list(t, casepart());
Eric Andersen12de6cf2004-08-04 19:19:10 +00001986 }
1987
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001988 DBGPRINTF(("CASELIST, returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001989 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001990}
1991
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001992static struct op *casepart(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001993{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001994 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001995
1996 DBGPRINTF7(("CASEPART: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001997
1998 t = newtp();
1999 t->type = TPAT;
2000 t->words = pattern();
2001 musthave(')', 0);
2002 t->left = c_list();
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002003 peeksym = yylex(CONTIN);
2004 if (peeksym != ESAC)
Eric Andersenff9eee42001-06-29 04:57:14 +00002005 musthave(BREAK, CONTIN);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002006
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002007 DBGPRINTF7(("CASEPART: made newtp(TPAT, t=%p)\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002008
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002009 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002010}
2011
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002012static char **pattern(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002013{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002014 int c, cf;
Eric Andersenff9eee42001-06-29 04:57:14 +00002015
2016 cf = CONTIN;
2017 do {
2018 musthave(WORD, cf);
2019 word(yylval.cp);
2020 cf = 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002021 c = yylex(0);
2022 } while (c == '|');
Eric Andersenff9eee42001-06-29 04:57:14 +00002023 peeksym = c;
2024 word(NOWORD);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002025
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002026 return copyw();
Eric Andersenff9eee42001-06-29 04:57:14 +00002027}
2028
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002029static char **wordlist(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002030{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002031 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002032
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002033 c = yylex(0);
2034 if (c != IN) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002035 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002036 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00002037 }
2038 startl = 0;
2039 while ((c = yylex(0)) == WORD)
2040 word(yylval.cp);
2041 word(NOWORD);
2042 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002043 return copyw();
Eric Andersenff9eee42001-06-29 04:57:14 +00002044}
2045
2046/*
2047 * supporting functions
2048 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002049static struct op *list(struct op *t1, struct op *t2)
Eric Andersenff9eee42001-06-29 04:57:14 +00002050{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002051 DBGPRINTF7(("LIST: enter, t1=%p, t2=%p\n", t1, t2));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002052
Eric Andersenff9eee42001-06-29 04:57:14 +00002053 if (t1 == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002054 return t2;
Eric Andersenff9eee42001-06-29 04:57:14 +00002055 if (t2 == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002056 return t1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002057
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002058 return block(TLIST, t1, t2, NOWORDS);
Eric Andersenff9eee42001-06-29 04:57:14 +00002059}
2060
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002061static struct op *block(int type, struct op *t1, struct op *t2, char **wp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002062{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002063 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002064
2065 DBGPRINTF7(("BLOCK: enter, type=%d (%s)\n", type, T_CMD_NAMES[type]));
Eric Andersenff9eee42001-06-29 04:57:14 +00002066
2067 t = newtp();
2068 t->type = type;
2069 t->left = t1;
2070 t->right = t2;
2071 t->words = wp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002072
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002073 DBGPRINTF7(("BLOCK: inserted %p between %p and %p\n", t, t1,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002074 t2));
2075
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002076 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002077}
2078
Eric Andersen12de6cf2004-08-04 19:19:10 +00002079/* See if given string is a shell multiline (FOR, IF, etc) */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002080static int rlookup(char *n)
Eric Andersenff9eee42001-06-29 04:57:14 +00002081{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002082 const struct res *rp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002083
2084 DBGPRINTF7(("RLOOKUP: enter, n is %s\n", n));
Eric Andersenff9eee42001-06-29 04:57:14 +00002085
2086 for (rp = restab; rp->r_name; rp++)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002087 if (strcmp(rp->r_name, n) == 0) {
2088 DBGPRINTF7(("RLOOKUP: match, returning %d\n", rp->r_val));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002089 return rp->r_val; /* Return numeric code for shell multiline */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002090 }
2091
2092 DBGPRINTF7(("RLOOKUP: NO match, returning 0\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002093 return 0; /* Not a shell multiline */
Eric Andersenff9eee42001-06-29 04:57:14 +00002094}
2095
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002096static struct op *newtp(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002097{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002098 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002099
Eric Andersen8401eea2004-08-04 19:16:54 +00002100 t = (struct op *) tree(sizeof(*t));
Eric Andersenff9eee42001-06-29 04:57:14 +00002101 t->type = 0;
2102 t->words = NULL;
2103 t->ioact = NULL;
2104 t->left = NULL;
2105 t->right = NULL;
2106 t->str = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002107
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002108 DBGPRINTF3(("NEWTP: allocated %p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002109
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002110 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002111}
2112
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002113static struct op *namelist(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00002114{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002115 DBGPRINTF7(("NAMELIST: enter, t=%p, type %s, iolist=%p\n", t,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002116 T_CMD_NAMES[t->type], iolist));
2117
Eric Andersenff9eee42001-06-29 04:57:14 +00002118 if (iolist) {
Eric Andersen8401eea2004-08-04 19:16:54 +00002119 iolist = addword((char *) NULL, iolist);
Eric Andersenff9eee42001-06-29 04:57:14 +00002120 t->ioact = copyio();
2121 } else
2122 t->ioact = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002123
Eric Andersenff9eee42001-06-29 04:57:14 +00002124 if (t->type != TCOM) {
2125 if (t->type != TPAREN && t->ioact != NULL) {
2126 t = block(TPAREN, t, NOBLOCK, NOWORDS);
2127 t->ioact = t->left->ioact;
2128 t->left->ioact = NULL;
2129 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002130 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002131 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002132
Eric Andersenff9eee42001-06-29 04:57:14 +00002133 word(NOWORD);
2134 t->words = copyw();
Eric Andersen12de6cf2004-08-04 19:19:10 +00002135
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002136 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002137}
2138
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002139static char **copyw(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002140{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002141 char **wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00002142
2143 wd = getwords(wdlist);
2144 wdlist = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002145 return wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00002146}
2147
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002148static void word(char *cp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002149{
2150 wdlist = addword(cp, wdlist);
2151}
2152
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002153static struct ioword **copyio(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002154{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002155 struct ioword **iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002156
2157 iop = (struct ioword **) getwords(iolist);
2158 iolist = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002159 return iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002160}
2161
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002162static struct ioword *io(int u, int f, char *cp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002163{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002164 struct ioword *iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002165
2166 iop = (struct ioword *) tree(sizeof(*iop));
2167 iop->io_unit = u;
2168 iop->io_flag = f;
2169 iop->io_name = cp;
Eric Andersen8401eea2004-08-04 19:16:54 +00002170 iolist = addword((char *) iop, iolist);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002171 return iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002172}
2173
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002174static int yylex(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00002175{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002176 int c, c1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002177 int atstart;
2178
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002179 c = peeksym;
2180 if (c > 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002181 peeksym = 0;
2182 if (c == '\n')
2183 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002184 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002185 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002186
Eric Andersenff9eee42001-06-29 04:57:14 +00002187 nlseen = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002188 atstart = startl;
2189 startl = 0;
2190 yylval.i = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002191 e.linep = line;
2192
2193/* MALAMO */
2194 line[LINELIM - 1] = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00002195
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002196 loop:
Eric Andersen12de6cf2004-08-04 19:19:10 +00002197 while ((c = my_getc(0)) == ' ' || c == '\t') /* Skip whitespace */
2198 ;
2199
Eric Andersenff9eee42001-06-29 04:57:14 +00002200 switch (c) {
2201 default:
2202 if (any(c, "0123456789")) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002203 c1 = my_getc(0);
2204 unget(c1);
Eric Andersenff9eee42001-06-29 04:57:14 +00002205 if (c1 == '<' || c1 == '>') {
2206 iounit = c - '0';
2207 goto loop;
2208 }
2209 *e.linep++ = c;
2210 c = c1;
2211 }
2212 break;
2213
Eric Andersen12de6cf2004-08-04 19:19:10 +00002214 case '#': /* Comment, skip to next newline or End-of-string */
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002215 while ((c = my_getc(0)) != '\0' && c != '\n');
Eric Andersenff9eee42001-06-29 04:57:14 +00002216 unget(c);
2217 goto loop;
2218
2219 case 0:
Eric Andersen12de6cf2004-08-04 19:19:10 +00002220 DBGPRINTF5(("YYLEX: return 0, c=%d\n", c));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002221 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002222
2223 case '$':
Eric Andersen12de6cf2004-08-04 19:19:10 +00002224 DBGPRINTF9(("YYLEX: found $\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00002225 *e.linep++ = c;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002226 c = my_getc(0);
2227 if (c == '{') {
2228 c = collect(c, '}');
2229 if (c != '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002230 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002231 goto pack;
2232 }
2233 break;
2234
2235 case '`':
2236 case '\'':
2237 case '"':
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002238 c = collect(c, c);
2239 if (c != '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002240 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002241 goto pack;
2242
2243 case '|':
2244 case '&':
2245 case ';':
Eric Andersenff9eee42001-06-29 04:57:14 +00002246 startl = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002247 /* If more chars process them, else return NULL char */
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002248 c1 = dual(c);
2249 if (c1 != '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002250 return c1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002251 return c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002252
Eric Andersenff9eee42001-06-29 04:57:14 +00002253 case '^':
2254 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002255 return '|';
Eric Andersenff9eee42001-06-29 04:57:14 +00002256 case '>':
2257 case '<':
2258 diag(c);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002259 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002260
2261 case '\n':
2262 nlseen++;
2263 gethere();
2264 startl = 1;
2265 if (multiline || cf & CONTIN) {
2266 if (interactive && e.iop <= iostack) {
Denis Vlasenko38f63192007-01-22 09:03:07 +00002267#if ENABLE_FEATURE_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00002268 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00002269#else
Eric Andersen8401eea2004-08-04 19:16:54 +00002270 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00002271#endif
2272 }
2273 if (cf & CONTIN)
2274 goto loop;
2275 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002276 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002277
2278 case '(':
2279 case ')':
2280 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002281 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002282 }
2283
2284 unget(c);
2285
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002286 pack:
2287 while ((c = my_getc(0)) != '\0' && !any(c, "`$ '\"\t;&<>()|^\n")) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002288 if (e.linep >= elinep)
2289 err("word too long");
2290 else
2291 *e.linep++ = c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002292 };
2293
Eric Andersenff9eee42001-06-29 04:57:14 +00002294 unget(c);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002295
Eric Andersen8401eea2004-08-04 19:16:54 +00002296 if (any(c, "\"'`$"))
Eric Andersenff9eee42001-06-29 04:57:14 +00002297 goto loop;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002298
Eric Andersenff9eee42001-06-29 04:57:14 +00002299 *e.linep++ = '\0';
Eric Andersen12de6cf2004-08-04 19:19:10 +00002300
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002301 if (atstart) {
2302 c = rlookup(line);
2303 if (c != 0) {
2304 startl = 1;
2305 return c;
2306 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002307 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002308
Eric Andersenff9eee42001-06-29 04:57:14 +00002309 yylval.cp = strsave(line, areanum);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002310 return WORD;
Eric Andersenff9eee42001-06-29 04:57:14 +00002311}
2312
Eric Andersen12de6cf2004-08-04 19:19:10 +00002313
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002314static int collect(int c, int c1)
Eric Andersenff9eee42001-06-29 04:57:14 +00002315{
2316 char s[2];
2317
Eric Andersen12de6cf2004-08-04 19:19:10 +00002318 DBGPRINTF8(("COLLECT: enter, c=%d, c1=%d\n", c, c1));
2319
Eric Andersenff9eee42001-06-29 04:57:14 +00002320 *e.linep++ = c;
2321 while ((c = my_getc(c1)) != c1) {
2322 if (c == 0) {
2323 unget(c);
2324 s[0] = c1;
2325 s[1] = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00002326 prs("no closing ");
2327 yyerror(s);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002328 return YYERRCODE;
Eric Andersenff9eee42001-06-29 04:57:14 +00002329 }
2330 if (interactive && c == '\n' && e.iop <= iostack) {
Denis Vlasenko38f63192007-01-22 09:03:07 +00002331#if ENABLE_FEATURE_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00002332 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00002333#else
Eric Andersen8401eea2004-08-04 19:16:54 +00002334 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00002335#endif
2336 }
2337 *e.linep++ = c;
2338 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002339
Eric Andersenff9eee42001-06-29 04:57:14 +00002340 *e.linep++ = c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002341
2342 DBGPRINTF8(("COLLECT: return 0, line is %s\n", line));
2343
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002344 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002345}
2346
Eric Andersen12de6cf2004-08-04 19:19:10 +00002347/* "multiline commands" helper func */
2348/* see if next 2 chars form a shell multiline */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002349static int dual(int c)
Eric Andersenff9eee42001-06-29 04:57:14 +00002350{
2351 char s[3];
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002352 char *cp = s;
Eric Andersenff9eee42001-06-29 04:57:14 +00002353
Eric Andersen12de6cf2004-08-04 19:19:10 +00002354 DBGPRINTF8(("DUAL: enter, c=%d\n", c));
2355
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002356 *cp++ = c; /* c is the given "peek" char */
2357 *cp++ = my_getc(0); /* get next char of input */
2358 *cp = '\0'; /* add EOS marker */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002359
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002360 c = rlookup(s); /* see if 2 chars form a shell multiline */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002361 if (c == 0)
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002362 unget(*--cp); /* String is not a shell multiline, put peek char back */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002363
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002364 return c; /* String is multiline, return numeric multiline (restab) code */
Eric Andersenff9eee42001-06-29 04:57:14 +00002365}
2366
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002367static void diag(int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00002368{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002369 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002370
2371 DBGPRINTF8(("DIAG: enter, ec=%d\n", ec));
Eric Andersenff9eee42001-06-29 04:57:14 +00002372
2373 c = my_getc(0);
2374 if (c == '>' || c == '<') {
2375 if (c != ec)
2376 zzerr();
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002377 yylval.i = (ec == '>' ? IOWRITE | IOCAT : IOHERE);
Eric Andersenff9eee42001-06-29 04:57:14 +00002378 c = my_getc(0);
2379 } else
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002380 yylval.i = (ec == '>' ? IOWRITE : IOREAD);
Eric Andersenff9eee42001-06-29 04:57:14 +00002381 if (c != '&' || yylval.i == IOHERE)
2382 unget(c);
2383 else
2384 yylval.i |= IODUP;
2385}
2386
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002387static char *tree(unsigned size)
Eric Andersenff9eee42001-06-29 04:57:14 +00002388{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002389 char *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002390
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002391 t = getcell(size);
2392 if (t == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002393 DBGPRINTF2(("TREE: getcell(%d) failed!\n", size));
Eric Andersenff9eee42001-06-29 04:57:14 +00002394 prs("command line too complicated\n");
2395 fail();
2396 /* NOTREACHED */
2397 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002398 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002399}
2400
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002401
Eric Andersenff9eee42001-06-29 04:57:14 +00002402/* VARARGS1 */
2403/* ARGSUSED */
2404
2405/* -------- exec.c -------- */
2406
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002407static struct op **find1case(struct op *t, const char *w)
2408{
2409 struct op *t1;
2410 struct op **tp;
2411 char **wp;
2412 char *cp;
2413
2414 if (t == NULL) {
2415 DBGPRINTF3(("FIND1CASE: enter, t==NULL, returning.\n"));
2416 return NULL;
2417 }
2418
2419 DBGPRINTF3(("FIND1CASE: enter, t->type=%d (%s)\n", t->type,
2420 T_CMD_NAMES[t->type]));
2421
2422 if (t->type == TLIST) {
2423 tp = find1case(t->left, w);
2424 if (tp != NULL) {
2425 DBGPRINTF3(("FIND1CASE: found one to the left, returning tp=%p\n", tp));
2426 return tp;
2427 }
2428 t1 = t->right; /* TPAT */
2429 } else
2430 t1 = t;
2431
2432 for (wp = t1->words; *wp;) {
2433 cp = evalstr(*wp++, DOSUB);
2434 if (cp && gmatch(w, cp)) {
2435 DBGPRINTF3(("FIND1CASE: returning &t1->left= %p.\n",
2436 &t1->left));
2437 return &t1->left;
2438 }
2439 }
2440
2441 DBGPRINTF(("FIND1CASE: returning NULL\n"));
2442 return NULL;
2443}
2444
2445static struct op *findcase(struct op *t, const char *w)
2446{
2447 struct op **tp;
2448
2449 tp = find1case(t, w);
2450 return tp != NULL ? *tp : NULL;
2451}
2452
Eric Andersenff9eee42001-06-29 04:57:14 +00002453/*
2454 * execute tree
2455 */
2456
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002457static int execute(struct op *t, int *pin, int *pout, int act)
Eric Andersenff9eee42001-06-29 04:57:14 +00002458{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002459 struct op *t1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002460 volatile int i, rv, a;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002461 const char *cp;
2462 char **wp, **wp2;
Eric Andersenff9eee42001-06-29 04:57:14 +00002463 struct var *vp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002464 struct op *outtree_save;
Eric Andersenff9eee42001-06-29 04:57:14 +00002465 struct brkcon bc;
2466
2467#if __GNUC__
2468 /* Avoid longjmp clobbering */
2469 (void) &wp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002470#endif
Eric Andersenff9eee42001-06-29 04:57:14 +00002471
Eric Andersen12de6cf2004-08-04 19:19:10 +00002472 if (t == NULL) {
2473 DBGPRINTF4(("EXECUTE: enter, t==null, returning.\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002474 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002475 }
2476
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002477 DBGPRINTF(("EXECUTE: t=%p, t->type=%d (%s), t->words is %s\n", t,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002478 t->type, T_CMD_NAMES[t->type],
2479 ((t->words == NULL) ? "NULL" : t->words[0])));
2480
Eric Andersenff9eee42001-06-29 04:57:14 +00002481 rv = 0;
2482 a = areanum++;
2483 wp = (wp2 = t->words) != NULL
Eric Andersen8401eea2004-08-04 19:16:54 +00002484 ? eval(wp2, t->type == TCOM ? DOALL : DOALL & ~DOKEY)
2485 : NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00002486
Eric Andersen8401eea2004-08-04 19:16:54 +00002487 switch (t->type) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002488 case TDOT:
2489 DBGPRINTF3(("EXECUTE: TDOT\n"));
2490
2491 outtree_save = outtree;
2492
2493 newfile(evalstr(t->words[0], DOALL));
2494
2495 t->left = dowholefile(TLIST, 0);
2496 t->right = NULL;
2497
2498 outtree = outtree_save;
2499
2500 if (t->left)
2501 rv = execute(t->left, pin, pout, 0);
2502 if (t->right)
2503 rv = execute(t->right, pin, pout, 0);
2504 break;
2505
Eric Andersenff9eee42001-06-29 04:57:14 +00002506 case TPAREN:
Eric Andersen737f5fb2003-03-14 16:05:59 +00002507 rv = execute(t->left, pin, pout, 0);
2508 break;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002509
Eric Andersenff9eee42001-06-29 04:57:14 +00002510 case TCOM:
Denis Vlasenko489f93e2007-02-01 01:43:16 +00002511 rv = forkexec(t, pin, pout, act, wp);
Eric Andersenff9eee42001-06-29 04:57:14 +00002512 break;
2513
2514 case TPIPE:
2515 {
Eric Andersen8401eea2004-08-04 19:16:54 +00002516 int pv[2];
2517
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002518 rv = openpipe(pv);
2519 if (rv < 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00002520 break;
2521 pv[0] = remap(pv[0]);
2522 pv[1] = remap(pv[1]);
2523 (void) execute(t->left, pin, pv, 0);
2524 rv = execute(t->right, pv, pout, 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002525 }
2526 break;
2527
2528 case TLIST:
2529 (void) execute(t->left, pin, pout, 0);
2530 rv = execute(t->right, pin, pout, 0);
2531 break;
2532
2533 case TASYNC:
Eric Andersen8401eea2004-08-04 19:16:54 +00002534 {
2535 int hinteractive = interactive;
Eric Andersenff9eee42001-06-29 04:57:14 +00002536
Eric Andersen12de6cf2004-08-04 19:19:10 +00002537 DBGPRINTF7(("EXECUTE: TASYNC clause, calling vfork()...\n"));
2538
Eric Andersen8401eea2004-08-04 19:16:54 +00002539 i = vfork();
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002540 if (i == 0) { /* child */
Eric Andersen8401eea2004-08-04 19:16:54 +00002541 signal(SIGINT, SIG_IGN);
2542 signal(SIGQUIT, SIG_IGN);
2543 if (interactive)
2544 signal(SIGTERM, SIG_DFL);
2545 interactive = 0;
2546 if (pin == NULL) {
2547 close(0);
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00002548 xopen(bb_dev_null, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00002549 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002550 _exit(execute(t->left, pin, pout, FEXEC));
Eric Andersenff9eee42001-06-29 04:57:14 +00002551 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002552 interactive = hinteractive;
2553 if (i != -1) {
2554 setval(lookup("!"), putn(i));
2555 if (pin != NULL)
2556 closepipe(pin);
2557 if (interactive) {
2558 prs(putn(i));
2559 prs("\n");
2560 }
2561 } else
2562 rv = -1;
2563 setstatus(rv);
Eric Andersenff9eee42001-06-29 04:57:14 +00002564 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002565 break;
2566
2567 case TOR:
2568 case TAND:
2569 rv = execute(t->left, pin, pout, 0);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002570 t1 = t->right;
2571 if (t1 != NULL && (rv == 0) == (t->type == TAND))
Eric Andersenff9eee42001-06-29 04:57:14 +00002572 rv = execute(t1, pin, pout, 0);
2573 break;
2574
2575 case TFOR:
2576 if (wp == NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00002577 wp = dolv + 1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002578 i = dolc;
2579 if (i < 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00002580 i = 0;
2581 } else {
2582 i = -1;
Eric Andersen8401eea2004-08-04 19:16:54 +00002583 while (*wp++ != NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00002584 }
2585 vp = lookup(t->str);
2586 while (setjmp(bc.brkpt))
2587 if (isbreak)
2588 goto broken;
2589 brkset(&bc);
2590 for (t1 = t->left; i-- && *wp != NULL;) {
2591 setval(vp, *wp++);
2592 rv = execute(t1, pin, pout, 0);
2593 }
2594 brklist = brklist->nextlev;
2595 break;
2596
2597 case TWHILE:
2598 case TUNTIL:
2599 while (setjmp(bc.brkpt))
2600 if (isbreak)
2601 goto broken;
2602 brkset(&bc);
2603 t1 = t->left;
2604 while ((execute(t1, pin, pout, 0) == 0) == (t->type == TWHILE))
2605 rv = execute(t->right, pin, pout, 0);
2606 brklist = brklist->nextlev;
2607 break;
2608
2609 case TIF:
2610 case TELIF:
Eric Andersen8401eea2004-08-04 19:16:54 +00002611 if (t->right != NULL) {
2612 rv = !execute(t->left, pin, pout, 0) ?
2613 execute(t->right->left, pin, pout, 0) :
2614 execute(t->right->right, pin, pout, 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002615 }
2616 break;
2617
2618 case TCASE:
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002619 cp = evalstr(t->str, DOSUB | DOTRIM);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002620 if (cp == NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00002621 cp = "";
Eric Andersen12de6cf2004-08-04 19:19:10 +00002622
2623 DBGPRINTF7(("EXECUTE: TCASE, t->str is %s, cp is %s\n",
2624 ((t->str == NULL) ? "NULL" : t->str),
2625 ((cp == NULL) ? "NULL" : cp)));
2626
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002627 t1 = findcase(t->left, cp);
2628 if (t1 != NULL) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002629 DBGPRINTF7(("EXECUTE: TCASE, calling execute(t=%p, t1=%p)...\n", t, t1));
Eric Andersenff9eee42001-06-29 04:57:14 +00002630 rv = execute(t1, pin, pout, 0);
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002631 DBGPRINTF7(("EXECUTE: TCASE, back from execute(t=%p, t1=%p)...\n", t, t1));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002632 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002633 break;
2634
2635 case TBRACE:
2636/*
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002637 iopp = t->ioact;
2638 if (i)
Eric Andersenff9eee42001-06-29 04:57:14 +00002639 while (*iopp)
2640 if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) {
2641 rv = -1;
2642 break;
2643 }
2644*/
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002645 if (rv >= 0) {
2646 t1 = t->left;
2647 if (t1) {
2648 rv = execute(t1, pin, pout, 0);
2649 }
2650 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002651 break;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002652
2653 };
Eric Andersenff9eee42001-06-29 04:57:14 +00002654
Denis Vlasenkoe4712752007-04-14 15:08:41 +00002655 broken:
Eric Andersenff9eee42001-06-29 04:57:14 +00002656 t->words = wp2;
2657 isbreak = 0;
2658 freehere(areanum);
2659 freearea(areanum);
2660 areanum = a;
2661 if (interactive && intr) {
2662 closeall();
2663 fail();
2664 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002665
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002666 i = trapset;
2667 if (i != 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002668 trapset = 0;
2669 runtrap(i);
2670 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002671
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002672 DBGPRINTF(("EXECUTE: returning from t=%p, rv=%d\n", t, rv));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002673 return rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00002674}
2675
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002676typedef int (*builtin_func_ptr)(struct op *);
2677
Denis Vlasenkoe4712752007-04-14 15:08:41 +00002678static builtin_func_ptr inbuilt(const char *s)
2679{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002680 const struct builtincmd *bp;
2681
Denis Vlasenko95cb3262007-04-09 03:06:34 +00002682 for (bp = builtincmds; bp->name; bp++)
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002683 if (strcmp(bp->name, s) == 0)
2684 return bp->builtinfunc;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002685 return NULL;
2686}
2687
2688static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002689{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002690 pid_t newpid;
Eric Andersenff9eee42001-06-29 04:57:14 +00002691 int i, rv;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002692 builtin_func_ptr shcom = NULL;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002693 int f;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002694 const char *cp = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00002695 struct ioword **iopp;
2696 int resetsig;
2697 char **owp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002698 int forked = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002699
2700 int *hpin = pin;
2701 int *hpout = pout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002702 char *hwp;
2703 int hinteractive;
2704 int hintr;
Eric Andersen8401eea2004-08-04 19:16:54 +00002705 struct brkcon *hbrklist;
Eric Andersenff9eee42001-06-29 04:57:14 +00002706 int hexecflg;
2707
2708#if __GNUC__
2709 /* Avoid longjmp clobbering */
2710 (void) &pin;
2711 (void) &pout;
2712 (void) &wp;
2713 (void) &shcom;
2714 (void) &cp;
2715 (void) &resetsig;
2716 (void) &owp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002717#endif
Eric Andersenff9eee42001-06-29 04:57:14 +00002718
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002719 DBGPRINTF(("FORKEXEC: t=%p, pin %p, pout %p, act %d\n", t, pin,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002720 pout, act));
2721 DBGPRINTF7(("FORKEXEC: t->words is %s\n",
2722 ((t->words == NULL) ? "NULL" : t->words[0])));
2723
Eric Andersenff9eee42001-06-29 04:57:14 +00002724 owp = wp;
2725 resetsig = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00002726 rv = -1; /* system-detected error */
Eric Andersenff9eee42001-06-29 04:57:14 +00002727 if (t->type == TCOM) {
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00002728 while (*wp++ != NULL)
2729 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00002730 cp = *wp;
2731
2732 /* strip all initial assignments */
2733 /* not correct wrt PATH=yyy command etc */
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00002734 if (FLAG['x']) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002735 DBGPRINTF9(("FORKEXEC: echo'ing, cp=%p, wp=%p, owp=%p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00002736 cp, wp, owp));
Eric Andersen8401eea2004-08-04 19:16:54 +00002737 echo(cp ? wp : owp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002738 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002739
Eric Andersenff9eee42001-06-29 04:57:14 +00002740 if (cp == NULL && t->ioact == NULL) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002741 while ((cp = *owp++) != NULL && assign(cp, COPYV))
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00002742 continue;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002743 DBGPRINTF(("FORKEXEC: returning setstatus()\n"));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002744 return setstatus(0);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002745 }
2746 if (cp != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002747 shcom = inbuilt(cp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002748 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002749 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002750
Eric Andersenff9eee42001-06-29 04:57:14 +00002751 t->words = wp;
2752 f = act;
Eric Andersenff9eee42001-06-29 04:57:14 +00002753
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002754 DBGPRINTF(("FORKEXEC: shcom %p, f&FEXEC 0x%x, owp %p\n", shcom,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002755 f & FEXEC, owp));
2756
2757 if (shcom == NULL && (f & FEXEC) == 0) {
2758 /* Save values in case the child process alters them */
Eric Andersenff9eee42001-06-29 04:57:14 +00002759 hpin = pin;
2760 hpout = pout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002761 hwp = *wp;
2762 hinteractive = interactive;
2763 hintr = intr;
2764 hbrklist = brklist;
2765 hexecflg = execflg;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002766
Eric Andersen12de6cf2004-08-04 19:19:10 +00002767 DBGPRINTF3(("FORKEXEC: calling vfork()...\n"));
2768
2769 newpid = vfork();
2770
2771 if (newpid == -1) {
Denis Vlasenko89f0b342006-11-18 22:04:09 +00002772 DBGPRINTF(("FORKEXEC: ERROR, cannot vfork()!\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002773 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002774 }
2775
Denis Vlasenko489f93e2007-02-01 01:43:16 +00002776 if (newpid > 0) { /* Parent */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002777 /* Restore values */
Eric Andersenff9eee42001-06-29 04:57:14 +00002778 pin = hpin;
2779 pout = hpout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002780 *wp = hwp;
2781 interactive = hinteractive;
2782 intr = hintr;
2783 brklist = hbrklist;
2784 execflg = hexecflg;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002785/* moved up
Eric Andersenff9eee42001-06-29 04:57:14 +00002786 if (i == -1)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002787 return rv;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002788*/
Eric Andersenff9eee42001-06-29 04:57:14 +00002789 if (pin != NULL)
2790 closepipe(pin);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002791
2792 return (pout == NULL ? setstatus(waitfor(newpid, 0)) : 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002793 }
2794
Eric Andersen12de6cf2004-08-04 19:19:10 +00002795 /* Must be the child process, pid should be 0 */
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002796 DBGPRINTF(("FORKEXEC: child process, shcom=%p\n", shcom));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002797
Eric Andersenff9eee42001-06-29 04:57:14 +00002798 if (interactive) {
2799 signal(SIGINT, SIG_IGN);
2800 signal(SIGQUIT, SIG_IGN);
2801 resetsig = 1;
2802 }
2803 interactive = 0;
2804 intr = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002805 forked = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002806 brklist = 0;
2807 execflg = 0;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002808 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002809
Eric Andersenff9eee42001-06-29 04:57:14 +00002810 if (owp != NULL)
2811 while ((cp = *owp++) != NULL && assign(cp, COPYV))
2812 if (shcom == NULL)
2813 export(lookup(cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002814
Eric Andersenff9eee42001-06-29 04:57:14 +00002815#ifdef COMPIPE
2816 if ((pin != NULL || pout != NULL) && shcom != NULL && shcom != doexec) {
2817 err("piping to/from shell builtins not yet done");
Eric Andersen12de6cf2004-08-04 19:19:10 +00002818 if (forked)
2819 _exit(-1);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002820 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002821 }
2822#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00002823
Eric Andersenff9eee42001-06-29 04:57:14 +00002824 if (pin != NULL) {
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00002825 xmove_fd(pin[0], 0);
2826 if (pin[1] != 0) close(pin[1]);
Eric Andersenff9eee42001-06-29 04:57:14 +00002827 }
2828 if (pout != NULL) {
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00002829 xmove_fd(pout[1], 1);
2830 if (pout[1] != 1) close(pout[0]);
Eric Andersenff9eee42001-06-29 04:57:14 +00002831 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002832
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002833 iopp = t->ioact;
2834 if (iopp != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002835 if (shcom != NULL && shcom != doexec) {
2836 prs(cp);
2837 err(": cannot redirect shell command");
Eric Andersen12de6cf2004-08-04 19:19:10 +00002838 if (forked)
2839 _exit(-1);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002840 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002841 }
2842 while (*iopp)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002843 if (iosetup(*iopp++, pin != NULL, pout != NULL)) {
2844 if (forked)
2845 _exit(rv);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002846 return rv;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002847 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002848 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002849
2850 if (shcom) {
2851 i = setstatus((*shcom) (t));
2852 if (forked)
2853 _exit(i);
2854 DBGPRINTF(("FORKEXEC: returning i=%d\n", i));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002855 return i;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002856 }
2857
Eric Andersenff9eee42001-06-29 04:57:14 +00002858 /* should use FIOCEXCL */
Eric Andersen8401eea2004-08-04 19:16:54 +00002859 for (i = FDBASE; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00002860 close(i);
2861 if (resetsig) {
2862 signal(SIGINT, SIG_DFL);
2863 signal(SIGQUIT, SIG_DFL);
2864 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002865
Eric Andersen12de6cf2004-08-04 19:19:10 +00002866 if (t->type == TPAREN)
2867 _exit(execute(t->left, NOPIPE, NOPIPE, FEXEC));
2868 if (wp[0] == NULL)
2869 _exit(0);
2870
Eric Andersenfd7a4c82004-09-02 23:13:10 +00002871 cp = rexecve(wp[0], wp, makenv(0, NULL));
Eric Andersen8401eea2004-08-04 19:16:54 +00002872 prs(wp[0]);
2873 prs(": ");
Eric Andersen12de6cf2004-08-04 19:19:10 +00002874 err(cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00002875 if (!execflg)
2876 trap[0] = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002877
2878 DBGPRINTF(("FORKEXEC: calling leave(), pid=%d\n", newpid));
2879
Eric Andersenff9eee42001-06-29 04:57:14 +00002880 leave();
2881 /* NOTREACHED */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002882 _exit(1);
Eric Andersenff9eee42001-06-29 04:57:14 +00002883}
2884
2885/*
2886 * 0< 1> are ignored as required
2887 * within pipelines.
2888 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002889static int iosetup(struct ioword *iop, int pipein, int pipeout)
Eric Andersenff9eee42001-06-29 04:57:14 +00002890{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002891 int u = -1;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002892 char *cp = NULL;
2893 const char *msg;
Eric Andersenff9eee42001-06-29 04:57:14 +00002894
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002895 DBGPRINTF(("IOSETUP: iop %p, pipein %i, pipeout %i\n", iop,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002896 pipein, pipeout));
2897
Eric Andersenff9eee42001-06-29 04:57:14 +00002898 if (iop->io_unit == IODEFAULT) /* take default */
Eric Andersen8401eea2004-08-04 19:16:54 +00002899 iop->io_unit = iop->io_flag & (IOREAD | IOHERE) ? 0 : 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002900
Eric Andersenff9eee42001-06-29 04:57:14 +00002901 if (pipein && iop->io_unit == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002902 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002903
Eric Andersenff9eee42001-06-29 04:57:14 +00002904 if (pipeout && iop->io_unit == 1)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002905 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002906
Eric Andersen8401eea2004-08-04 19:16:54 +00002907 msg = iop->io_flag & (IOREAD | IOHERE) ? "open" : "create";
Eric Andersenff9eee42001-06-29 04:57:14 +00002908 if ((iop->io_flag & IOHERE) == 0) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002909 cp = iop->io_name; /* huh?? */
2910 cp = evalstr(cp, DOSUB | DOTRIM);
2911 if (cp == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002912 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002913 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002914
Eric Andersenff9eee42001-06-29 04:57:14 +00002915 if (iop->io_flag & IODUP) {
2916 if (cp[1] || (!isdigit(*cp) && *cp != '-')) {
2917 prs(cp);
2918 err(": illegal >& argument");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002919 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002920 }
2921 if (*cp == '-')
2922 iop->io_flag = IOCLOSE;
Eric Andersen8401eea2004-08-04 19:16:54 +00002923 iop->io_flag &= ~(IOREAD | IOWRITE);
Eric Andersenff9eee42001-06-29 04:57:14 +00002924 }
2925 switch (iop->io_flag) {
2926 case IOREAD:
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00002927 u = open(cp, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00002928 break;
2929
2930 case IOHERE:
Eric Andersen8401eea2004-08-04 19:16:54 +00002931 case IOHERE | IOXHERE:
2932 u = herein(iop->io_name, iop->io_flag & IOXHERE);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002933 cp = (char*)"here file";
Eric Andersenff9eee42001-06-29 04:57:14 +00002934 break;
2935
Eric Andersen8401eea2004-08-04 19:16:54 +00002936 case IOWRITE | IOCAT:
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00002937 u = open(cp, O_WRONLY);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002938 if (u >= 0) {
Denis Vlasenkoea620772006-10-14 02:23:43 +00002939 lseek(u, (long) 0, SEEK_END);
Eric Andersenff9eee42001-06-29 04:57:14 +00002940 break;
2941 }
2942 case IOWRITE:
2943 u = creat(cp, 0666);
2944 break;
2945
2946 case IODUP:
Eric Andersen8401eea2004-08-04 19:16:54 +00002947 u = dup2(*cp - '0', iop->io_unit);
Eric Andersenff9eee42001-06-29 04:57:14 +00002948 break;
2949
2950 case IOCLOSE:
2951 close(iop->io_unit);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002952 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002953 }
2954 if (u < 0) {
2955 prs(cp);
2956 prs(": cannot ");
2957 warn(msg);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002958 return 1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002959 }
2960 if (u != iop->io_unit) {
2961 dup2(u, iop->io_unit);
2962 close(u);
Eric Andersenff9eee42001-06-29 04:57:14 +00002963 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002964 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002965}
2966
Eric Andersenff9eee42001-06-29 04:57:14 +00002967/*
2968 * Enter a new loop level (marked for break/continue).
2969 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002970static void brkset(struct brkcon *bc)
Eric Andersenff9eee42001-06-29 04:57:14 +00002971{
2972 bc->nextlev = brklist;
2973 brklist = bc;
2974}
2975
2976/*
2977 * Wait for the last process created.
2978 * Print a message for each process found
2979 * that was killed by a signal.
2980 * Ignore interrupt signals while waiting
2981 * unless `canintr' is true.
2982 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002983static int waitfor(int lastpid, int canintr)
Eric Andersenff9eee42001-06-29 04:57:14 +00002984{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002985 int pid, rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00002986 int s;
2987 int oheedint = heedint;
2988
2989 heedint = 0;
2990 rv = 0;
2991 do {
2992 pid = wait(&s);
2993 if (pid == -1) {
2994 if (errno != EINTR || canintr)
2995 break;
2996 } else {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002997 rv = WAITSIG(s);
2998 if (rv != 0) {
Denis Vlasenko80b8b392007-06-25 10:55:35 +00002999 if (rv < ARRAY_SIZE(signame)) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003000 if (signame[rv] != NULL) {
3001 if (pid != lastpid) {
3002 prn(pid);
3003 prs(": ");
3004 }
3005 prs(signame[rv]);
3006 }
3007 } else {
3008 if (pid != lastpid) {
3009 prn(pid);
3010 prs(": ");
3011 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003012 prs("Signal ");
3013 prn(rv);
3014 prs(" ");
Eric Andersenff9eee42001-06-29 04:57:14 +00003015 }
3016 if (WAITCORE(s))
3017 prs(" - core dumped");
Denis Vlasenko80b8b392007-06-25 10:55:35 +00003018 if (rv >= ARRAY_SIZE(signame) || signame[rv])
Eric Andersenff9eee42001-06-29 04:57:14 +00003019 prs("\n");
3020 rv = -1;
3021 } else
3022 rv = WAITVAL(s);
3023 }
3024 } while (pid != lastpid);
3025 heedint = oheedint;
3026 if (intr) {
3027 if (interactive) {
3028 if (canintr)
3029 intr = 0;
3030 } else {
Eric Andersen8401eea2004-08-04 19:16:54 +00003031 if (exstat == 0)
3032 exstat = rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003033 onintr(0);
3034 }
3035 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003036 return rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003037}
3038
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003039static int setstatus(int s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003040{
3041 exstat = s;
3042 setval(lookup("?"), putn(s));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003043 return s;
Eric Andersenff9eee42001-06-29 04:57:14 +00003044}
3045
3046/*
3047 * PATH-searching interface to execve.
3048 * If getenv("PATH") were kept up-to-date,
3049 * execvp might be used.
3050 */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003051static const char *rexecve(char *c, char **v, char **envp)
Eric Andersenff9eee42001-06-29 04:57:14 +00003052{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003053 int i;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003054 const char *sp;
3055 char *tp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003056 int eacces = 0, asis = 0;
Eric Andersen1c039232001-07-07 00:05:55 +00003057 char *name = c;
Eric Andersen8401eea2004-08-04 19:16:54 +00003058
Denis Vlasenko80d14be2007-04-10 23:03:30 +00003059 if (ENABLE_FEATURE_SH_STANDALONE) {
Rob Landleya299efb2006-08-10 21:46:43 +00003060 if (find_applet_by_name(name)) {
3061 /* We have to exec here since we vforked. Running
Denis Vlasenkoe4f2d062007-04-11 17:03:19 +00003062 * run_applet_and_exit() won't work and bad things
Rob Landleya299efb2006-08-10 21:46:43 +00003063 * will happen. */
Denis Vlasenkobdbbb7e2007-06-08 15:02:55 +00003064 execve(bb_busybox_exec_path, v, envp);
Rob Landleya299efb2006-08-10 21:46:43 +00003065 }
Eric Andersen1c039232001-07-07 00:05:55 +00003066 }
Eric Andersen1c039232001-07-07 00:05:55 +00003067
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003068 DBGPRINTF(("REXECVE: c=%p, v=%p, envp=%p\n", c, v, envp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003069
Eric Andersen8401eea2004-08-04 19:16:54 +00003070 sp = any('/', c) ? "" : path->value;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003071 asis = (*sp == '\0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003072 while (asis || *sp != '\0') {
3073 asis = 0;
3074 tp = e.linep;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003075 for (; *sp != '\0'; tp++) {
3076 *tp = *sp++;
3077 if (*tp == ':') {
3078 asis = (*sp == '\0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003079 break;
3080 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003081 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003082 if (tp != e.linep)
3083 *tp++ = '/';
Eric Andersen8401eea2004-08-04 19:16:54 +00003084 for (i = 0; (*tp++ = c[i++]) != '\0';);
Eric Andersen1c039232001-07-07 00:05:55 +00003085
Eric Andersen12de6cf2004-08-04 19:19:10 +00003086 DBGPRINTF3(("REXECVE: e.linep is %s\n", e.linep));
3087
Eric Andersenff9eee42001-06-29 04:57:14 +00003088 execve(e.linep, v, envp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003089
Eric Andersenff9eee42001-06-29 04:57:14 +00003090 switch (errno) {
3091 case ENOEXEC:
3092 *v = e.linep;
3093 tp = *--v;
3094 *v = e.linep;
Glenn L McGrathdc4e75e2003-09-02 02:36:18 +00003095 execve(DEFAULT_SHELL, v, envp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003096 *v = tp;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003097 return "no Shell";
Eric Andersenff9eee42001-06-29 04:57:14 +00003098
3099 case ENOMEM:
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003100 return (char *) bb_msg_memory_exhausted;
Eric Andersenff9eee42001-06-29 04:57:14 +00003101
3102 case E2BIG:
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003103 return "argument list too long";
Eric Andersenff9eee42001-06-29 04:57:14 +00003104
3105 case EACCES:
3106 eacces++;
3107 break;
3108 }
3109 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003110 return errno == ENOENT ? "not found" : "cannot execute";
Eric Andersenff9eee42001-06-29 04:57:14 +00003111}
3112
3113/*
3114 * Run the command produced by generator `f'
3115 * applied to stream `arg'.
3116 */
Eric Andersen8401eea2004-08-04 19:16:54 +00003117static int run(struct ioarg *argp, int (*f) (struct ioarg *))
Eric Andersenff9eee42001-06-29 04:57:14 +00003118{
3119 struct op *otree;
3120 struct wdblock *swdlist;
3121 struct wdblock *siolist;
3122 jmp_buf ev, rt;
3123 xint *ofail;
3124 int rv;
3125
3126#if __GNUC__
3127 /* Avoid longjmp clobbering */
3128 (void) &rv;
3129#endif
3130
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003131 DBGPRINTF(("RUN: enter, areanum %d, outtree %p, failpt %p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00003132 areanum, outtree, failpt));
3133
Eric Andersenff9eee42001-06-29 04:57:14 +00003134 areanum++;
3135 swdlist = wdlist;
3136 siolist = iolist;
3137 otree = outtree;
3138 ofail = failpt;
3139 rv = -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003140
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003141 errpt = ev;
3142 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003143 wdlist = 0;
3144 iolist = 0;
3145 pushio(argp, f);
3146 e.iobase = e.iop;
3147 yynerrs = 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003148 failpt = rt;
3149 if (setjmp(failpt) == 0 && yyparse() == 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00003150 rv = execute(outtree, NOPIPE, NOPIPE, 0);
3151 quitenv();
Eric Andersen12de6cf2004-08-04 19:19:10 +00003152 } else {
3153 DBGPRINTF(("RUN: error from newenv()!\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00003154 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00003155
Eric Andersenff9eee42001-06-29 04:57:14 +00003156 wdlist = swdlist;
3157 iolist = siolist;
3158 failpt = ofail;
3159 outtree = otree;
3160 freearea(areanum--);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003161
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003162 return rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003163}
3164
3165/* -------- do.c -------- */
3166
3167/*
3168 * built-in commands: doX
3169 */
3170
Eric Andersen8401eea2004-08-04 19:16:54 +00003171static int dohelp(struct op *t)
Eric Andersen1c039232001-07-07 00:05:55 +00003172{
3173 int col;
3174 const struct builtincmd *x;
3175
Denis Vlasenko0ee39992006-12-24 15:23:28 +00003176 puts("\nBuilt-in commands:\n"
3177 "-------------------");
Eric Andersen1c039232001-07-07 00:05:55 +00003178
Denis Vlasenko95cb3262007-04-09 03:06:34 +00003179 col = 0;
3180 x = builtincmds;
3181 while (x->name) {
3182 col += printf("%c%s", ((col == 0) ? '\t' : ' '), x->name);
Eric Andersen1c039232001-07-07 00:05:55 +00003183 if (col > 60) {
Denis Vlasenkoc6f188d2006-10-26 00:37:00 +00003184 puts("");
Eric Andersen1c039232001-07-07 00:05:55 +00003185 col = 0;
3186 }
Denis Vlasenko95cb3262007-04-09 03:06:34 +00003187 x++;
Eric Andersen1c039232001-07-07 00:05:55 +00003188 }
Denis Vlasenko80d14be2007-04-10 23:03:30 +00003189#if ENABLE_FEATURE_SH_STANDALONE
Eric Andersen1c039232001-07-07 00:05:55 +00003190 {
Denis Vlasenko335b63d2007-04-10 21:38:30 +00003191 const struct bb_applet *applet = applets;
Eric Andersen1c039232001-07-07 00:05:55 +00003192
Denis Vlasenko95cb3262007-04-09 03:06:34 +00003193 while (applet->name) {
3194 col += printf("%c%s", ((col == 0) ? '\t' : ' '), applet->name);
Eric Andersen1c039232001-07-07 00:05:55 +00003195 if (col > 60) {
Denis Vlasenkoc6f188d2006-10-26 00:37:00 +00003196 puts("");
Eric Andersen1c039232001-07-07 00:05:55 +00003197 col = 0;
3198 }
Denis Vlasenko95cb3262007-04-09 03:06:34 +00003199 applet++;
Eric Andersen1c039232001-07-07 00:05:55 +00003200 }
3201 }
3202#endif
Denis Vlasenko0ee39992006-12-24 15:23:28 +00003203 puts("\n");
Eric Andersen1c039232001-07-07 00:05:55 +00003204 return EXIT_SUCCESS;
3205}
3206
Eric Andersen8401eea2004-08-04 19:16:54 +00003207static int dolabel(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003208{
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003209 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003210}
3211
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003212static int dochdir(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003213{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003214 const char *cp, *er;
Eric Andersenff9eee42001-06-29 04:57:14 +00003215
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003216 cp = t->words[1];
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003217 if (cp == NULL) {
3218 cp = homedir->value;
Denis Vlasenkod244c5e2007-02-09 17:30:14 +00003219 if (cp != NULL)
3220 goto do_cd;
3221 er = ": no home directory";
3222 } else {
3223 do_cd:
3224 if (chdir(cp) >= 0)
3225 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003226 er = ": bad directory";
Denis Vlasenkod244c5e2007-02-09 17:30:14 +00003227 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003228 prs(cp != NULL ? cp : "cd");
Eric Andersenff9eee42001-06-29 04:57:14 +00003229 err(er);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003230 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003231}
3232
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003233static int doshift(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003234{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003235 int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003236
Eric Andersen8401eea2004-08-04 19:16:54 +00003237 n = t->words[1] ? getn(t->words[1]) : 1;
3238 if (dolc < n) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003239 err("nothing to shift");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003240 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003241 }
3242 dolv[n] = dolv[0];
3243 dolv += n;
3244 dolc -= n;
3245 setval(lookup("#"), putn(dolc));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003246 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003247}
3248
3249/*
3250 * execute login and newgrp directly
3251 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003252static int dologin(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003253{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003254 const char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003255
3256 if (interactive) {
3257 signal(SIGINT, SIG_DFL);
3258 signal(SIGQUIT, SIG_DFL);
3259 }
Eric Andersenfd7a4c82004-09-02 23:13:10 +00003260 cp = rexecve(t->words[0], t->words, makenv(0, NULL));
Eric Andersen8401eea2004-08-04 19:16:54 +00003261 prs(t->words[0]);
3262 prs(": ");
3263 err(cp);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003264 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003265}
3266
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003267static int doumask(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003268{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003269 int i, n;
3270 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003271
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003272 cp = t->words[1];
3273 if (cp == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003274 i = umask(0);
3275 umask(i);
Eric Andersen8401eea2004-08-04 19:16:54 +00003276 for (n = 3 * 4; (n -= 3) >= 0;)
3277 putc('0' + ((i >> n) & 07), stderr);
Eric Andersenff9eee42001-06-29 04:57:14 +00003278 putc('\n', stderr);
3279 } else {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003280/* huh??? '8','9' are not allowed! */
Eric Andersen8401eea2004-08-04 19:16:54 +00003281 for (n = 0; *cp >= '0' && *cp <= '9'; cp++)
3282 n = n * 8 + (*cp - '0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003283 umask(n);
3284 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003285 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003286}
3287
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003288static int doexec(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003289{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003290 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00003291 jmp_buf ex;
3292 xint *ofail;
3293
3294 t->ioact = NULL;
Eric Andersen8401eea2004-08-04 19:16:54 +00003295 for (i = 0; (t->words[i] = t->words[i + 1]) != NULL; i++);
Eric Andersenff9eee42001-06-29 04:57:14 +00003296 if (i == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003297 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003298 execflg = 1;
3299 ofail = failpt;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003300 failpt = ex;
3301 if (setjmp(failpt) == 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00003302 execute(t, NOPIPE, NOPIPE, FEXEC);
3303 failpt = ofail;
3304 execflg = 0;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003305 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003306}
3307
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003308static int dodot(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003309{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003310 int i;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003311 const char *sp;
3312 char *tp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003313 char *cp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003314 int maltmp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003315
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003316 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 +00003317
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003318 cp = t->words[1];
3319 if (cp == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00003320 DBGPRINTF(("DODOT: bad args, ret 0\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003321 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003322 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003323 DBGPRINTF(("DODOT: cp is %s\n", cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003324
Eric Andersen8401eea2004-08-04 19:16:54 +00003325 sp = any('/', cp) ? ":" : path->value;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003326
3327 DBGPRINTF(("DODOT: sp is %s, e.linep is %s\n",
3328 ((sp == NULL) ? "NULL" : sp),
3329 ((e.linep == NULL) ? "NULL" : e.linep)));
3330
Eric Andersenff9eee42001-06-29 04:57:14 +00003331 while (*sp) {
3332 tp = e.linep;
3333 while (*sp && (*tp = *sp++) != ':')
3334 tp++;
3335 if (tp != e.linep)
3336 *tp++ = '/';
Eric Andersen12de6cf2004-08-04 19:19:10 +00003337
Eric Andersen8401eea2004-08-04 19:16:54 +00003338 for (i = 0; (*tp++ = cp[i++]) != '\0';);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003339
3340 /* Original code */
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00003341 i = open(e.linep, O_RDONLY);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003342 if (i >= 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003343 exstat = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003344 maltmp = remap(i);
3345 DBGPRINTF(("DODOT: remap=%d, exstat=%d, e.iofd %d, i %d, e.linep is %s\n", maltmp, exstat, e.iofd, i, e.linep));
3346
3347 next(maltmp); /* Basically a PUSHIO */
3348
3349 DBGPRINTF(("DODOT: returning exstat=%d\n", exstat));
3350
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003351 return exstat;
Eric Andersenff9eee42001-06-29 04:57:14 +00003352 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003353 } /* while */
Eric Andersen12de6cf2004-08-04 19:19:10 +00003354
Eric Andersenff9eee42001-06-29 04:57:14 +00003355 prs(cp);
3356 err(": not found");
Eric Andersen12de6cf2004-08-04 19:19:10 +00003357
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003358 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003359}
3360
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003361static int dowait(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003362{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003363 int i;
3364 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003365
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003366 cp = t->words[1];
3367 if (cp != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003368 i = getn(cp);
3369 if (i == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003370 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003371 } else
3372 i = -1;
3373 setstatus(waitfor(i, 1));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003374 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003375}
3376
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003377static int doread(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003378{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003379 char *cp, **wp;
3380 int nb = 0;
3381 int nl = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003382
3383 if (t->words[1] == NULL) {
3384 err("Usage: read name ...");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003385 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003386 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003387 for (wp = t->words + 1; *wp; wp++) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003388 for (cp = e.linep; !nl && cp < elinep - 1; cp++) {
3389 nb = read(0, cp, sizeof(*cp));
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003390 if (nb != sizeof(*cp))
Eric Andersenff9eee42001-06-29 04:57:14 +00003391 break;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003392 nl = (*cp == '\n');
3393 if (nl || (wp[1] && any(*cp, ifs->value)))
3394 break;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003395 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003396 *cp = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00003397 if (nb <= 0)
3398 break;
3399 setval(lookup(*wp), e.linep);
3400 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003401 return nb <= 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003402}
3403
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003404static int doeval(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003405{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003406 return RUN(awordlist, t->words + 1, wdchar);
Eric Andersenff9eee42001-06-29 04:57:14 +00003407}
3408
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003409static int dotrap(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003410{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003411 int n, i;
3412 int resetsig;
Eric Andersenff9eee42001-06-29 04:57:14 +00003413
3414 if (t->words[1] == NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00003415 for (i = 0; i <= _NSIG; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00003416 if (trap[i]) {
3417 prn(i);
3418 prs(": ");
3419 prs(trap[i]);
3420 prs("\n");
3421 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003422 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003423 }
3424 resetsig = isdigit(*t->words[1]);
3425 for (i = resetsig ? 1 : 2; t->words[i] != NULL; ++i) {
3426 n = getsig(t->words[i]);
3427 freecell(trap[n]);
3428 trap[n] = 0;
3429 if (!resetsig) {
3430 if (*t->words[1] != '\0') {
3431 trap[n] = strsave(t->words[1], 0);
3432 setsig(n, sig);
3433 } else
3434 setsig(n, SIG_IGN);
3435 } else {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00003436 if (interactive) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003437 if (n == SIGINT)
3438 setsig(n, onintr);
3439 else
Eric Andersen8401eea2004-08-04 19:16:54 +00003440 setsig(n, n == SIGQUIT ? SIG_IGN : SIG_DFL);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00003441 } else
Eric Andersenff9eee42001-06-29 04:57:14 +00003442 setsig(n, SIG_DFL);
3443 }
3444 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003445 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003446}
3447
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003448static int getsig(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003449{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003450 int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003451
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003452 n = getn(s);
3453 if (n < 0 || n > _NSIG) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003454 err("trap: bad signal number");
3455 n = 0;
3456 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003457 return n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003458}
3459
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003460static void setsig(int n, sighandler_t f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003461{
3462 if (n == 0)
3463 return;
3464 if (signal(n, SIG_IGN) != SIG_IGN || ourtrap[n]) {
3465 ourtrap[n] = 1;
3466 signal(n, f);
3467 }
3468}
3469
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003470static int getn(char *as)
Eric Andersenff9eee42001-06-29 04:57:14 +00003471{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003472 char *s;
3473 int n, m;
Eric Andersenff9eee42001-06-29 04:57:14 +00003474
3475 s = as;
3476 m = 1;
3477 if (*s == '-') {
3478 m = -1;
3479 s++;
3480 }
3481 for (n = 0; isdigit(*s); s++)
Eric Andersen8401eea2004-08-04 19:16:54 +00003482 n = (n * 10) + (*s - '0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003483 if (*s) {
3484 prs(as);
3485 err(": bad number");
3486 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003487 return n * m;
Eric Andersenff9eee42001-06-29 04:57:14 +00003488}
3489
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003490static int dobreak(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003491{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003492 return brkcontin(t->words[1], 1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003493}
3494
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003495static int docontinue(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003496{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003497 return brkcontin(t->words[1], 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003498}
3499
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003500static int brkcontin(char *cp, int val)
Eric Andersenff9eee42001-06-29 04:57:14 +00003501{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003502 struct brkcon *bc;
3503 int nl;
Eric Andersenff9eee42001-06-29 04:57:14 +00003504
Eric Andersen8401eea2004-08-04 19:16:54 +00003505 nl = cp == NULL ? 1 : getn(cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003506 if (nl <= 0)
3507 nl = 999;
3508 do {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003509 bc = brklist;
3510 if (bc == NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00003511 break;
3512 brklist = bc->nextlev;
3513 } while (--nl);
3514 if (nl) {
3515 err("bad break/continue level");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003516 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003517 }
3518 isbreak = val;
3519 longjmp(bc->brkpt, 1);
3520 /* NOTREACHED */
3521}
3522
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003523static int doexit(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003524{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003525 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003526
3527 execflg = 0;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003528 cp = t->words[1];
3529 if (cp != NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00003530 setstatus(getn(cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003531
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003532 DBGPRINTF(("DOEXIT: calling leave(), t=%p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003533
Eric Andersenff9eee42001-06-29 04:57:14 +00003534 leave();
3535 /* NOTREACHED */
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003536 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003537}
3538
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003539static int doexport(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003540{
Eric Andersen8401eea2004-08-04 19:16:54 +00003541 rdexp(t->words + 1, export, EXPORT);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003542 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003543}
3544
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003545static int doreadonly(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003546{
Eric Andersen8401eea2004-08-04 19:16:54 +00003547 rdexp(t->words + 1, ronly, RONLY);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003548 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003549}
3550
Eric Andersen8401eea2004-08-04 19:16:54 +00003551static void rdexp(char **wp, void (*f) (struct var *), int key)
Eric Andersenff9eee42001-06-29 04:57:14 +00003552{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003553 DBGPRINTF6(("RDEXP: enter, wp=%p, func=%p, key=%d\n", wp, f, key));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003554 DBGPRINTF6(("RDEXP: *wp=%s\n", *wp));
3555
Eric Andersenff9eee42001-06-29 04:57:14 +00003556 if (*wp != NULL) {
Matt Kraaif69bfc72001-07-12 19:39:59 +00003557 for (; *wp != NULL; wp++) {
3558 if (isassign(*wp)) {
3559 char *cp;
Eric Andersen8401eea2004-08-04 19:16:54 +00003560
Matt Kraaif69bfc72001-07-12 19:39:59 +00003561 assign(*wp, COPYV);
Eric Andersen8401eea2004-08-04 19:16:54 +00003562 for (cp = *wp; *cp != '='; cp++);
Matt Kraaif69bfc72001-07-12 19:39:59 +00003563 *cp = '\0';
3564 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003565 if (checkname(*wp))
Eric Andersen8401eea2004-08-04 19:16:54 +00003566 (*f) (lookup(*wp));
Eric Andersenff9eee42001-06-29 04:57:14 +00003567 else
3568 badid(*wp);
Matt Kraaif69bfc72001-07-12 19:39:59 +00003569 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003570 } else
3571 putvlist(key, 1);
3572}
3573
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003574static void badid(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003575{
3576 prs(s);
3577 err(": bad identifier");
3578}
3579
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003580static int doset(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003581{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003582 struct var *vp;
3583 char *cp;
3584 int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003585
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003586 cp = t->words[1];
3587 if (cp == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003588 for (vp = vlist; vp; vp = vp->next)
3589 varput(vp->name, 1);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003590 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003591 }
3592 if (*cp == '-') {
3593 /* bad: t->words++; */
Eric Andersen8401eea2004-08-04 19:16:54 +00003594 for (n = 0; (t->words[n] = t->words[n + 1]) != NULL; n++);
Eric Andersenff9eee42001-06-29 04:57:14 +00003595 if (*++cp == 0)
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003596 FLAG['x'] = FLAG['v'] = 0;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003597 else {
3598 for (; *cp; cp++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003599 switch (*cp) {
3600 case 'e':
3601 if (!interactive)
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003602 FLAG['e']++;
Eric Andersenff9eee42001-06-29 04:57:14 +00003603 break;
3604
3605 default:
Eric Andersen8401eea2004-08-04 19:16:54 +00003606 if (*cp >= 'a' && *cp <= 'z')
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003607 FLAG[(int) *cp]++;
Eric Andersenff9eee42001-06-29 04:57:14 +00003608 break;
3609 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003610 }
3611 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003612 setdash();
3613 }
3614 if (t->words[1]) {
3615 t->words[0] = dolv[0];
Eric Andersen8401eea2004-08-04 19:16:54 +00003616 for (n = 1; t->words[n]; n++)
3617 setarea((char *) t->words[n], 0);
3618 dolc = n - 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003619 dolv = t->words;
3620 setval(lookup("#"), putn(dolc));
Eric Andersen8401eea2004-08-04 19:16:54 +00003621 setarea((char *) (dolv - 1), 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003622 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003623 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003624}
3625
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003626static void varput(char *s, int out)
Eric Andersenff9eee42001-06-29 04:57:14 +00003627{
Matt Kraai69edfec2001-08-06 14:14:18 +00003628 if (isalnum(*s) || *s == '_') {
Eric Andersenff9eee42001-06-29 04:57:14 +00003629 write(out, s, strlen(s));
3630 write(out, "\n", 1);
3631 }
3632}
3633
3634
3635/*
3636 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
3637 * This file contains code for the times builtin.
Eric Andersenff9eee42001-06-29 04:57:14 +00003638 */
Eric Andersen8401eea2004-08-04 19:16:54 +00003639static int dotimes(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003640{
3641 struct tms buf;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003642 long clk_tck = sysconf(_SC_CLK_TCK);
Eric Andersenff9eee42001-06-29 04:57:14 +00003643
3644 times(&buf);
3645 printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
Eric Andersen8401eea2004-08-04 19:16:54 +00003646 (int) (buf.tms_utime / clk_tck / 60),
3647 ((double) buf.tms_utime) / clk_tck,
3648 (int) (buf.tms_stime / clk_tck / 60),
3649 ((double) buf.tms_stime) / clk_tck,
3650 (int) (buf.tms_cutime / clk_tck / 60),
3651 ((double) buf.tms_cutime) / clk_tck,
3652 (int) (buf.tms_cstime / clk_tck / 60),
3653 ((double) buf.tms_cstime) / clk_tck);
Eric Andersenff9eee42001-06-29 04:57:14 +00003654 return 0;
3655}
3656
3657
Eric Andersenff9eee42001-06-29 04:57:14 +00003658/* -------- eval.c -------- */
3659
3660/*
3661 * ${}
3662 * `command`
3663 * blank interpretation
3664 * quoting
3665 * glob
3666 */
3667
Eric Andersen8401eea2004-08-04 19:16:54 +00003668static char **eval(char **ap, int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003669{
3670 struct wdblock *wb;
3671 char **wp;
3672 char **wf;
3673 jmp_buf ev;
3674
3675#if __GNUC__
3676 /* Avoid longjmp clobbering */
3677 (void) &wp;
3678 (void) &ap;
3679#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00003680
3681 DBGPRINTF4(("EVAL: enter, f=%d\n", f));
3682
Eric Andersenff9eee42001-06-29 04:57:14 +00003683 wp = NULL;
3684 wb = NULL;
3685 wf = NULL;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003686 errpt = ev;
3687 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003688 while (*ap && isassign(*ap))
3689 expand(*ap++, &wb, f & ~DOGLOB);
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003690 if (FLAG['k']) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003691 for (wf = ap; *wf; wf++) {
3692 if (isassign(*wf))
3693 expand(*wf, &wb, f & ~DOGLOB);
3694 }
3695 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003696 for (wb = addword((char *) 0, wb); *ap; ap++) {
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003697 if (!FLAG['k'] || !isassign(*ap))
Eric Andersenff9eee42001-06-29 04:57:14 +00003698 expand(*ap, &wb, f & ~DOKEY);
3699 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003700 wb = addword((char *) 0, wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00003701 wp = getwords(wb);
3702 quitenv();
3703 } else
3704 gflg = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003705
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003706 return gflg ? (char **) NULL : wp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003707}
3708
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003709
Eric Andersenff9eee42001-06-29 04:57:14 +00003710/*
3711 * Make the exported environment from the exported
3712 * names in the dictionary. Keyword assignments
3713 * will already have been done.
3714 */
Eric Andersenfd7a4c82004-09-02 23:13:10 +00003715static char **makenv(int all, struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00003716{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003717 struct var *vp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003718
3719 DBGPRINTF5(("MAKENV: enter, all=%d\n", all));
Eric Andersenff9eee42001-06-29 04:57:14 +00003720
Eric Andersenff9eee42001-06-29 04:57:14 +00003721 for (vp = vlist; vp; vp = vp->next)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003722 if (all || vp->status & EXPORT)
Eric Andersenff9eee42001-06-29 04:57:14 +00003723 wb = addword(vp->name, wb);
Eric Andersen8401eea2004-08-04 19:16:54 +00003724 wb = addword((char *) 0, wb);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003725 return getwords(wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00003726}
3727
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003728static int expand(const char *cp, struct wdblock **wbp, int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003729{
3730 jmp_buf ev;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003731 char *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003732
3733#if __GNUC__
3734 /* Avoid longjmp clobbering */
3735 (void) &cp;
3736#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00003737
3738 DBGPRINTF3(("EXPAND: enter, f=%d\n", f));
3739
Eric Andersenff9eee42001-06-29 04:57:14 +00003740 gflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003741
Eric Andersenff9eee42001-06-29 04:57:14 +00003742 if (cp == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003743 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003744
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003745 if (!anys("$`'\"", cp) && !anys(ifs->value, cp)
3746 && ((f & DOGLOB) == 0 || !anys("[*?", cp))
3747 ) {
3748 xp = strsave(cp, areanum);
Eric Andersenff9eee42001-06-29 04:57:14 +00003749 if (f & DOTRIM)
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003750 unquote(xp);
3751 *wbp = addword(xp, *wbp);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003752 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003753 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003754 errpt = ev;
3755 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003756 PUSHIO(aword, cp, strchar);
3757 e.iobase = e.iop;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003758 while ((xp = blank(f)) && gflg == 0) {
3759 e.linep = xp;
3760 xp = strsave(xp, areanum);
Eric Andersen8401eea2004-08-04 19:16:54 +00003761 if ((f & DOGLOB) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003762 if (f & DOTRIM)
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003763 unquote(xp);
3764 *wbp = addword(xp, *wbp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003765 } else
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003766 *wbp = glob(xp, *wbp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003767 }
3768 quitenv();
3769 } else
3770 gflg = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003771 return gflg == 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003772}
3773
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003774static char *evalstr(char *cp, int f)
3775{
3776 struct wdblock *wb;
3777
3778 DBGPRINTF6(("EVALSTR: enter, cp=%p, f=%d\n", cp, f));
3779
3780 wb = NULL;
3781 if (expand(cp, &wb, f)) {
3782 if (wb == NULL || wb->w_nword == 0
3783 || (cp = wb->w_words[0]) == NULL
3784 ) {
Denis Vlasenko8e858e22007-03-07 09:35:43 +00003785// TODO: I suspect that
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003786// char *evalstr(char *cp, int f) is actually
3787// const char *evalstr(const char *cp, int f)!
3788 cp = (char*)"";
3789 }
3790 DELETE(wb);
3791 } else
3792 cp = NULL;
3793 return cp;
3794}
3795
3796
Eric Andersenff9eee42001-06-29 04:57:14 +00003797/*
3798 * Blank interpretation and quoting
3799 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003800static char *blank(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003801{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003802 int c, c1;
3803 char *sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003804 int scanequals, foundequals;
3805
Eric Andersen12de6cf2004-08-04 19:19:10 +00003806 DBGPRINTF3(("BLANK: enter, f=%d\n", f));
3807
Eric Andersenff9eee42001-06-29 04:57:14 +00003808 sp = e.linep;
3809 scanequals = f & DOKEY;
3810 foundequals = 0;
3811
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003812 loop:
3813 c = subgetc('"', foundequals);
3814 switch (c) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003815 case 0:
3816 if (sp == e.linep)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003817 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003818 *e.linep++ = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003819 return sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003820
3821 default:
3822 if (f & DOBLANK && any(c, ifs->value))
3823 goto loop;
3824 break;
3825
3826 case '"':
3827 case '\'':
3828 scanequals = 0;
3829 if (INSUB())
3830 break;
3831 for (c1 = c; (c = subgetc(c1, 1)) != c1;) {
3832 if (c == 0)
3833 break;
3834 if (c == '\'' || !any(c, "$`\""))
3835 c |= QUOTE;
3836 *e.linep++ = c;
3837 }
3838 c = 0;
3839 }
3840 unget(c);
Matt Kraai69edfec2001-08-06 14:14:18 +00003841 if (!isalpha(c) && c != '_')
Eric Andersenff9eee42001-06-29 04:57:14 +00003842 scanequals = 0;
3843 for (;;) {
3844 c = subgetc('"', foundequals);
3845 if (c == 0 ||
Eric Andersen8401eea2004-08-04 19:16:54 +00003846 f & (DOBLANK && any(c, ifs->value)) ||
3847 (!INSUB() && any(c, "\"'"))) {
3848 scanequals = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003849 unget(c);
3850 if (any(c, "\"'"))
3851 goto loop;
3852 break;
3853 }
3854 if (scanequals) {
3855 if (c == '=') {
3856 foundequals = 1;
Eric Andersen8401eea2004-08-04 19:16:54 +00003857 scanequals = 0;
3858 } else if (!isalnum(c) && c != '_')
Eric Andersenff9eee42001-06-29 04:57:14 +00003859 scanequals = 0;
3860 }
3861 *e.linep++ = c;
3862 }
3863 *e.linep++ = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003864 return sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003865}
3866
3867/*
3868 * Get characters, substituting for ` and $
3869 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003870static int subgetc(char ec, int quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00003871{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003872 char c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003873
3874 DBGPRINTF3(("SUBGETC: enter, quoted=%d\n", quoted));
Eric Andersenff9eee42001-06-29 04:57:14 +00003875
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003876 again:
Eric Andersenff9eee42001-06-29 04:57:14 +00003877 c = my_getc(ec);
3878 if (!INSUB() && ec != '\'') {
3879 if (c == '`') {
3880 if (grave(quoted) == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003881 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003882 e.iop->task = XGRAVE;
3883 goto again;
3884 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003885 if (c == '$') {
3886 c = dollar(quoted);
3887 if (c == 0) {
3888 e.iop->task = XDOLL;
3889 goto again;
3890 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003891 }
3892 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003893 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003894}
3895
3896/*
3897 * Prepare to generate the string returned by ${} substitution.
3898 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003899static int dollar(int quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00003900{
3901 int otask;
3902 struct io *oiop;
3903 char *dolp;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003904 char *s, c, *cp = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00003905 struct var *vp;
3906
Eric Andersen12de6cf2004-08-04 19:19:10 +00003907 DBGPRINTF3(("DOLLAR: enter, quoted=%d\n", quoted));
3908
Eric Andersenff9eee42001-06-29 04:57:14 +00003909 c = readc();
3910 s = e.linep;
3911 if (c != '{') {
3912 *e.linep++ = c;
Matt Kraai69edfec2001-08-06 14:14:18 +00003913 if (isalpha(c) || c == '_') {
Eric Andersen8401eea2004-08-04 19:16:54 +00003914 while ((c = readc()) != 0 && (isalnum(c) || c == '_'))
Eric Andersenff9eee42001-06-29 04:57:14 +00003915 if (e.linep < elinep)
3916 *e.linep++ = c;
3917 unget(c);
3918 }
3919 c = 0;
3920 } else {
3921 oiop = e.iop;
3922 otask = e.iop->task;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003923
Eric Andersenff9eee42001-06-29 04:57:14 +00003924 e.iop->task = XOTHER;
Eric Andersen8401eea2004-08-04 19:16:54 +00003925 while ((c = subgetc('"', 0)) != 0 && c != '}' && c != '\n')
Eric Andersenff9eee42001-06-29 04:57:14 +00003926 if (e.linep < elinep)
3927 *e.linep++ = c;
3928 if (oiop == e.iop)
3929 e.iop->task = otask;
3930 if (c != '}') {
3931 err("unclosed ${");
3932 gflg++;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003933 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003934 }
3935 }
3936 if (e.linep >= elinep) {
3937 err("string in ${} too long");
3938 gflg++;
3939 e.linep -= 10;
3940 }
3941 *e.linep = 0;
3942 if (*s)
Eric Andersen8401eea2004-08-04 19:16:54 +00003943 for (cp = s + 1; *cp; cp++)
Eric Andersenff9eee42001-06-29 04:57:14 +00003944 if (any(*cp, "=-+?")) {
3945 c = *cp;
3946 *cp++ = 0;
3947 break;
3948 }
3949 if (s[1] == 0 && (*s == '*' || *s == '@')) {
3950 if (dolc > 1) {
3951 /* currently this does not distinguish $* and $@ */
3952 /* should check dollar */
3953 e.linep = s;
Eric Andersen8401eea2004-08-04 19:16:54 +00003954 PUSHIO(awordlist, dolv + 1, dolchar);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003955 return 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00003956 } else { /* trap the nasty ${=} */
Eric Andersenff9eee42001-06-29 04:57:14 +00003957 s[0] = '1';
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003958 s[1] = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00003959 }
3960 }
3961 vp = lookup(s);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003962 dolp = vp->value;
3963 if (dolp == null) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003964 switch (c) {
3965 case '=':
3966 if (isdigit(*s)) {
3967 err("cannot use ${...=...} with $n");
3968 gflg++;
3969 break;
3970 }
3971 setval(vp, cp);
3972 dolp = vp->value;
3973 break;
3974
3975 case '-':
3976 dolp = strsave(cp, areanum);
3977 break;
3978
3979 case '?':
3980 if (*cp == 0) {
3981 prs("missing value for ");
3982 err(s);
3983 } else
3984 err(cp);
3985 gflg++;
3986 break;
3987 }
3988 } else if (c == '+')
3989 dolp = strsave(cp, areanum);
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003990 if (FLAG['u'] && dolp == null) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003991 prs("unset variable: ");
3992 err(s);
3993 gflg++;
3994 }
3995 e.linep = s;
3996 PUSHIO(aword, dolp, quoted ? qstrchar : strchar);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003997 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003998}
3999
4000/*
4001 * Run the command in `...` and read its output.
4002 */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004003
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004004static int grave(int quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00004005{
Denis Vlasenko55f30b02007-03-24 22:42:29 +00004006 /* moved to G: static char child_cmd[LINELIM]; */
4007
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004008 const char *cp;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004009 int i;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004010 int j;
Eric Andersenff9eee42001-06-29 04:57:14 +00004011 int pf[2];
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004012 const char *src;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004013 char *dest;
4014 int count;
4015 int ignore;
4016 int ignore_once;
4017 char *argument_list[4];
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004018 struct wdblock *wb = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004019
4020#if __GNUC__
4021 /* Avoid longjmp clobbering */
4022 (void) &cp;
4023#endif
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004024
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004025 for (cp = e.iop->argp->aword; *cp != '`'; cp++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004026 if (*cp == 0) {
4027 err("no closing `");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004028 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004029 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004030 }
Eric Andersen737f5fb2003-03-14 16:05:59 +00004031
4032 /* string copy with dollar expansion */
4033 src = e.iop->argp->aword;
4034 dest = child_cmd;
4035 count = 0;
4036 ignore = 0;
4037 ignore_once = 0;
4038 while ((*src != '`') && (count < LINELIM)) {
4039 if (*src == '\'')
4040 ignore = !ignore;
4041 if (*src == '\\')
4042 ignore_once = 1;
4043 if (*src == '$' && !ignore && !ignore_once) {
4044 struct var *vp;
4045 char var_name[LINELIM];
4046 char alt_value[LINELIM];
4047 int var_index = 0;
4048 int alt_index = 0;
4049 char operator = 0;
4050 int braces = 0;
4051 char *value;
4052
4053 src++;
4054 if (*src == '{') {
4055 braces = 1;
4056 src++;
4057 }
4058
4059 var_name[var_index++] = *src++;
Paul Fox54690dc2005-07-20 18:33:12 +00004060 while (isalnum(*src) || *src=='_')
Eric Andersen737f5fb2003-03-14 16:05:59 +00004061 var_name[var_index++] = *src++;
4062 var_name[var_index] = 0;
4063
4064 if (braces) {
4065 switch (*src) {
4066 case '}':
4067 break;
4068 case '-':
4069 case '=':
4070 case '+':
4071 case '?':
Eric Andersen8401eea2004-08-04 19:16:54 +00004072 operator = * src;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004073 break;
4074 default:
4075 err("unclosed ${\n");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004076 return 0;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004077 }
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004078 if (operator) {
Eric Andersen737f5fb2003-03-14 16:05:59 +00004079 src++;
4080 while (*src && (*src != '}')) {
4081 alt_value[alt_index++] = *src++;
4082 }
4083 alt_value[alt_index] = 0;
4084 if (*src != '}') {
4085 err("unclosed ${\n");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004086 return 0;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004087 }
4088 }
4089 src++;
4090 }
4091
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004092 if (isalpha(*var_name)) {
4093 /* let subshell handle it instead */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004094
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004095 char *namep = var_name;
4096
4097 *dest++ = '$';
4098 if (braces)
4099 *dest++ = '{';
4100 while (*namep)
4101 *dest++ = *namep++;
4102 if (operator) {
4103 char *altp = alt_value;
4104 *dest++ = operator;
4105 while (*altp)
4106 *dest++ = *altp++;
4107 }
4108 if (braces)
4109 *dest++ = '}';
4110
4111 wb = addword(lookup(var_name)->name, wb);
4112 } else {
4113 /* expand */
4114
4115 vp = lookup(var_name);
4116 if (vp->value != null)
4117 value = (operator == '+') ?
4118 alt_value : vp->value;
4119 else if (operator == '?') {
4120 err(alt_value);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004121 return 0;
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004122 } else if (alt_index && (operator != '+')) {
4123 value = alt_value;
4124 if (operator == '=')
4125 setval(vp, value);
4126 } else
4127 continue;
4128
4129 while (*value && (count < LINELIM)) {
4130 *dest++ = *value++;
4131 count++;
4132 }
Eric Andersen737f5fb2003-03-14 16:05:59 +00004133 }
4134 } else {
4135 *dest++ = *src++;
4136 count++;
4137 ignore_once = 0;
4138 }
4139 }
4140 *dest = '\0';
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004141
Eric Andersenff9eee42001-06-29 04:57:14 +00004142 if (openpipe(pf) < 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004143 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004144
Eric Andersen8401eea2004-08-04 19:16:54 +00004145 while ((i = vfork()) == -1 && errno == EAGAIN);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004146
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004147 DBGPRINTF3(("GRAVE: i is %p\n", io));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004148
Eric Andersen737f5fb2003-03-14 16:05:59 +00004149 if (i < 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004150 closepipe(pf);
Eric Andersen8401eea2004-08-04 19:16:54 +00004151 err((char *) bb_msg_memory_exhausted);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004152 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004153 }
4154 if (i != 0) {
Eric Andersen737f5fb2003-03-14 16:05:59 +00004155 waitpid(i, NULL, 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004156 e.iop->argp->aword = ++cp;
4157 close(pf[1]);
Eric Andersen8401eea2004-08-04 19:16:54 +00004158 PUSHIO(afile, remap(pf[0]),
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004159 (int (*)(struct ioarg *)) ((quoted) ? qgravechar : gravechar));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004160 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004161 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004162 /* allow trapped signals */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004163 /* XXX - Maybe this signal stuff should go as well? */
Eric Andersen8401eea2004-08-04 19:16:54 +00004164 for (j = 0; j <= _NSIG; j++)
Eric Andersen737f5fb2003-03-14 16:05:59 +00004165 if (ourtrap[j] && signal(j, SIG_IGN) != SIG_IGN)
4166 signal(j, SIG_DFL);
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004167
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00004168 /* Testcase where below checks are needed:
4169 * close stdout & run this script:
4170 * files=`ls`
4171 * echo "$files" >zz
4172 */
4173 xmove_fd(pf[1], 1);
4174 if (pf[0] != 1) close(pf[0]);
Eric Andersen737f5fb2003-03-14 16:05:59 +00004175
Eric Andersen8401eea2004-08-04 19:16:54 +00004176 argument_list[0] = (char *) DEFAULT_SHELL;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004177 argument_list[1] = (char *) "-c";
Eric Andersen737f5fb2003-03-14 16:05:59 +00004178 argument_list[2] = child_cmd;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004179 argument_list[3] = NULL;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004180
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004181 cp = rexecve(argument_list[0], argument_list, makenv(1, wb));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004182 prs(argument_list[0]);
4183 prs(": ");
4184 err(cp);
Eric Andersen737f5fb2003-03-14 16:05:59 +00004185 _exit(1);
Eric Andersenff9eee42001-06-29 04:57:14 +00004186}
4187
Eric Andersen737f5fb2003-03-14 16:05:59 +00004188
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004189static char *unquote(char *as)
Eric Andersenff9eee42001-06-29 04:57:14 +00004190{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004191 char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00004192
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004193 s = as;
4194 if (s != NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00004195 while (*s)
4196 *s++ &= ~QUOTE;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004197 return as;
Eric Andersenff9eee42001-06-29 04:57:14 +00004198}
4199
4200/* -------- glob.c -------- */
4201
4202/*
4203 * glob
4204 */
4205
4206#define scopy(x) strsave((x), areanum)
4207#define BLKSIZ 512
4208#define NDENT ((BLKSIZ+sizeof(struct dirent)-1)/sizeof(struct dirent))
4209
Eric Andersen8401eea2004-08-04 19:16:54 +00004210static struct wdblock *cl, *nl;
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00004211static const char spcl[] ALIGN1= "[?*";
Eric Andersenff9eee42001-06-29 04:57:14 +00004212
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004213static struct wdblock *glob(char *cp, struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004214{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004215 int i;
4216 char *pp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004217
4218 if (cp == 0)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004219 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004220 i = 0;
4221 for (pp = cp; *pp; pp++)
4222 if (any(*pp, spcl))
4223 i++;
4224 else if (!any(*pp & ~QUOTE, spcl))
4225 *pp &= ~QUOTE;
4226 if (i != 0) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004227 for (cl = addword(scopy(cp), NULL); anyspcl(cl); cl = nl) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004228 nl = newword(cl->w_nword * 2);
4229 for (i = 0; i < cl->w_nword; i++) { /* for each argument */
Eric Andersenff9eee42001-06-29 04:57:14 +00004230 for (pp = cl->w_words[i]; *pp; pp++)
4231 if (any(*pp, spcl)) {
4232 globname(cl->w_words[i], pp);
4233 break;
4234 }
4235 if (*pp == '\0')
4236 nl = addword(scopy(cl->w_words[i]), nl);
4237 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004238 for (i = 0; i < cl->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004239 DELETE(cl->w_words[i]);
4240 DELETE(cl);
4241 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004242 for (i = 0; i < cl->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004243 unquote(cl->w_words[i]);
Eric Andersen8401eea2004-08-04 19:16:54 +00004244 glob0((char *) cl->w_words, cl->w_nword, sizeof(char *), xstrcmp);
Eric Andersenff9eee42001-06-29 04:57:14 +00004245 if (cl->w_nword) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004246 for (i = 0; i < cl->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004247 wb = addword(cl->w_words[i], wb);
4248 DELETE(cl);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004249 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004250 }
4251 }
4252 wb = addword(unquote(cp), wb);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004253 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004254}
4255
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004256static void globname(char *we, char *pp)
Eric Andersenff9eee42001-06-29 04:57:14 +00004257{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004258 char *np, *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004259 char *name, *gp, *dp;
4260 int k;
4261 DIR *dirp;
4262 struct dirent *de;
Eric Andersen8401eea2004-08-04 19:16:54 +00004263 char dname[NAME_MAX + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00004264 struct stat dbuf;
4265
4266 for (np = we; np != pp; pp--)
4267 if (pp[-1] == '/')
4268 break;
Eric Andersen8401eea2004-08-04 19:16:54 +00004269 for (dp = cp = space((int) (pp - np) + 3); np < pp;)
Eric Andersenff9eee42001-06-29 04:57:14 +00004270 *cp++ = *np++;
4271 *cp++ = '.';
4272 *cp = '\0';
Eric Andersen8401eea2004-08-04 19:16:54 +00004273 for (gp = cp = space(strlen(pp) + 1); *np && *np != '/';)
Eric Andersenff9eee42001-06-29 04:57:14 +00004274 *cp++ = *np++;
4275 *cp = '\0';
4276 dirp = opendir(dp);
4277 if (dirp == 0) {
4278 DELETE(dp);
4279 DELETE(gp);
4280 return;
4281 }
4282 dname[NAME_MAX] = '\0';
Eric Andersen8401eea2004-08-04 19:16:54 +00004283 while ((de = readdir(dirp)) != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004284 /* XXX Hmmm... What this could be? (abial) */
4285 /*
Eric Andersen8401eea2004-08-04 19:16:54 +00004286 if (ent[j].d_ino == 0)
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004287 continue;
Eric Andersen8401eea2004-08-04 19:16:54 +00004288 */
Eric Andersenff9eee42001-06-29 04:57:14 +00004289 strncpy(dname, de->d_name, NAME_MAX);
Eric Andersen8401eea2004-08-04 19:16:54 +00004290 if (dname[0] == '.')
4291 if (*gp != '.')
4292 continue;
4293 for (k = 0; k < NAME_MAX; k++)
4294 if (any(dname[k], spcl))
4295 dname[k] |= QUOTE;
4296 if (gmatch(dname, gp)) {
4297 name = generate(we, pp, dname, np);
4298 if (*np && !anys(np, spcl)) {
4299 if (stat(name, &dbuf)) {
4300 DELETE(name);
Eric Andersenff9eee42001-06-29 04:57:14 +00004301 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00004302 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004303 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004304 nl = addword(name, nl);
4305 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004306 }
4307 closedir(dirp);
4308 DELETE(dp);
4309 DELETE(gp);
4310}
4311
4312/*
4313 * generate a pathname as below.
4314 * start..end1 / middle end
4315 * the slashes come for free
4316 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004317static char *generate(char *start1, char *end1, char *middle, char *end)
Eric Andersenff9eee42001-06-29 04:57:14 +00004318{
4319 char *p;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004320 char *op, *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004321
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004322 p = op = space((int)(end1 - start1) + strlen(middle) + strlen(end) + 2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004323 for (xp = start1; xp != end1;)
4324 *op++ = *xp++;
Eric Andersen8401eea2004-08-04 19:16:54 +00004325 for (xp = middle; (*op++ = *xp++) != '\0';);
Eric Andersenff9eee42001-06-29 04:57:14 +00004326 op--;
Eric Andersen8401eea2004-08-04 19:16:54 +00004327 for (xp = end; (*op++ = *xp++) != '\0';);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004328 return p;
Eric Andersenff9eee42001-06-29 04:57:14 +00004329}
4330
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004331static int anyspcl(struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004332{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004333 int i;
4334 char **wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004335
4336 wd = wb->w_words;
Eric Andersen8401eea2004-08-04 19:16:54 +00004337 for (i = 0; i < wb->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004338 if (anys(spcl, *wd++))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004339 return 1;
4340 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004341}
4342
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004343static int xstrcmp(char *p1, char *p2)
Eric Andersenff9eee42001-06-29 04:57:14 +00004344{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004345 return strcmp(*(char **) p1, *(char **) p2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004346}
4347
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004348
Eric Andersenff9eee42001-06-29 04:57:14 +00004349/* -------- word.c -------- */
4350
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004351static struct wdblock *newword(int nw)
Eric Andersenff9eee42001-06-29 04:57:14 +00004352{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004353 struct wdblock *wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004354
Eric Andersen8401eea2004-08-04 19:16:54 +00004355 wb = (struct wdblock *) space(sizeof(*wb) + nw * sizeof(char *));
Eric Andersenff9eee42001-06-29 04:57:14 +00004356 wb->w_bsize = nw;
4357 wb->w_nword = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004358 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004359}
4360
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004361static struct wdblock *addword(char *wd, struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004362{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004363 struct wdblock *wb2;
4364 int nw;
Eric Andersenff9eee42001-06-29 04:57:14 +00004365
4366 if (wb == NULL)
4367 wb = newword(NSTART);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004368 nw = wb->w_nword;
4369 if (nw >= wb->w_bsize) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004370 wb2 = newword(nw * 2);
Eric Andersen8401eea2004-08-04 19:16:54 +00004371 memcpy((char *) wb2->w_words, (char *) wb->w_words,
4372 nw * sizeof(char *));
Eric Andersenff9eee42001-06-29 04:57:14 +00004373 wb2->w_nword = nw;
4374 DELETE(wb);
4375 wb = wb2;
4376 }
4377 wb->w_words[wb->w_nword++] = wd;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004378 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004379}
Eric Andersen8401eea2004-08-04 19:16:54 +00004380
Denis Vlasenkoe4712752007-04-14 15:08:41 +00004381static char **getwords(struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004382{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004383 char **wd;
4384 int nb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004385
4386 if (wb == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004387 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004388 if (wb->w_nword == 0) {
4389 DELETE(wb);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004390 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004391 }
4392 wd = (char **) space(nb = sizeof(*wd) * wb->w_nword);
Eric Andersen8401eea2004-08-04 19:16:54 +00004393 memcpy((char *) wd, (char *) wb->w_words, nb);
4394 DELETE(wb); /* perhaps should done by caller */
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004395 return wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004396}
4397
"Vladimir N. Oleynik"ac973172005-09-22 14:38:17 +00004398static int (*func) (char *, char *);
4399static int globv;
Eric Andersenff9eee42001-06-29 04:57:14 +00004400
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004401static void glob3(char *i, char *j, char *k)
Eric Andersenff9eee42001-06-29 04:57:14 +00004402{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004403 char *index1, *index2, *index3;
4404 int c;
4405 int m;
4406
4407 m = globv;
4408 index1 = i;
4409 index2 = j;
4410 index3 = k;
4411 do {
4412 c = *index1;
4413 *index1++ = *index3;
4414 *index3++ = *index2;
4415 *index2++ = c;
4416 } while (--m);
4417}
4418
4419static void glob2(char *i, char *j)
4420{
4421 char *index1, *index2, c;
4422 int m;
4423
4424 m = globv;
4425 index1 = i;
4426 index2 = j;
4427 do {
4428 c = *index1;
4429 *index1++ = *index2;
4430 *index2++ = c;
4431 } while (--m);
Eric Andersenff9eee42001-06-29 04:57:14 +00004432}
4433
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004434static void glob1(char *base, char *lim)
Eric Andersenff9eee42001-06-29 04:57:14 +00004435{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004436 char *i, *j;
Eric Andersenff9eee42001-06-29 04:57:14 +00004437 int v2;
4438 char *lptr, *hptr;
4439 int c;
4440 unsigned n;
4441
Eric Andersenff9eee42001-06-29 04:57:14 +00004442 v2 = globv;
4443
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004444 top:
4445 n = (int) (lim - base);
4446 if (n <= v2)
Eric Andersenff9eee42001-06-29 04:57:14 +00004447 return;
Eric Andersen8401eea2004-08-04 19:16:54 +00004448 n = v2 * (n / (2 * v2));
4449 hptr = lptr = base + n;
Eric Andersenff9eee42001-06-29 04:57:14 +00004450 i = base;
Eric Andersen8401eea2004-08-04 19:16:54 +00004451 j = lim - v2;
4452 for (;;) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004453 if (i < lptr) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004454 c = (*func) (i, lptr);
4455 if (c == 0) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004456 lptr -= v2;
4457 glob2(i, lptr);
Eric Andersenff9eee42001-06-29 04:57:14 +00004458 continue;
4459 }
4460 if (c < 0) {
4461 i += v2;
4462 continue;
4463 }
4464 }
4465
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004466 begin:
Eric Andersenff9eee42001-06-29 04:57:14 +00004467 if (j > hptr) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004468 c = (*func) (hptr, j);
4469 if (c == 0) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004470 hptr += v2;
4471 glob2(hptr, j);
Eric Andersenff9eee42001-06-29 04:57:14 +00004472 goto begin;
4473 }
4474 if (c > 0) {
4475 if (i == lptr) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004476 hptr += v2;
4477 glob3(i, hptr, j);
4478 i = (lptr += v2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004479 goto begin;
4480 }
4481 glob2(i, j);
4482 j -= v2;
4483 i += v2;
4484 continue;
4485 }
4486 j -= v2;
4487 goto begin;
4488 }
4489
4490
4491 if (i == lptr) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004492 if (lptr - base >= lim - hptr) {
4493 glob1(hptr + v2, lim);
Eric Andersenff9eee42001-06-29 04:57:14 +00004494 lim = lptr;
4495 } else {
4496 glob1(base, lptr);
Eric Andersen8401eea2004-08-04 19:16:54 +00004497 base = hptr + v2;
Eric Andersenff9eee42001-06-29 04:57:14 +00004498 }
4499 goto top;
4500 }
4501
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004502 lptr -= v2;
4503 glob3(j, lptr, i);
4504 j = (hptr -= v2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004505 }
4506}
4507
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004508static void glob0(char *a0, unsigned a1, int a2, int (*a3) (char *, char *))
Eric Andersenff9eee42001-06-29 04:57:14 +00004509{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004510 func = a3;
4511 globv = a2;
4512 glob1(a0, a0 + a1 * a2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004513}
4514
Eric Andersenff9eee42001-06-29 04:57:14 +00004515
4516/* -------- io.c -------- */
4517
4518/*
4519 * shell IO
4520 */
4521
Eric Andersen8401eea2004-08-04 19:16:54 +00004522static int my_getc(int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00004523{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004524 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004525
Eric Andersen8401eea2004-08-04 19:16:54 +00004526 if (e.linep > elinep) {
4527 while ((c = readc()) != '\n' && c);
Eric Andersenff9eee42001-06-29 04:57:14 +00004528 err("input line too long");
4529 gflg++;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004530 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004531 }
4532 c = readc();
Eric Andersen737f5fb2003-03-14 16:05:59 +00004533 if ((ec != '\'') && (ec != '`') && (e.iop->task != XGRAVE)) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004534 if (c == '\\') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004535 c = readc();
4536 if (c == '\n' && ec != '\"')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004537 return my_getc(ec);
Eric Andersenff9eee42001-06-29 04:57:14 +00004538 c |= QUOTE;
4539 }
4540 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004541 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004542}
4543
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004544static void unget(int c)
Eric Andersenff9eee42001-06-29 04:57:14 +00004545{
4546 if (e.iop >= e.iobase)
4547 e.iop->peekc = c;
4548}
4549
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004550static int eofc(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00004551{
Eric Andersen8401eea2004-08-04 19:16:54 +00004552 return e.iop < e.iobase || (e.iop->peekc == 0 && e.iop->prev == 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004553}
4554
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004555static int readc(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00004556{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004557 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004558
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004559 RCPRINTF(("READC: e.iop %p, e.iobase %p\n", e.iop, e.iobase));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004560
4561 for (; e.iop >= e.iobase; e.iop--) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004562 RCPRINTF(("READC: e.iop %p, peekc 0x%x\n", e.iop, e.iop->peekc));
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004563 c = e.iop->peekc;
4564 if (c != '\0') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004565 e.iop->peekc = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004566 return c;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004567 }
4568 if (e.iop->prev != 0) {
4569 c = (*e.iop->iofn)(e.iop->argp, e.iop);
4570 if (c != '\0') {
4571 if (c == -1) {
4572 e.iop++;
4573 continue;
Eric Andersen8401eea2004-08-04 19:16:54 +00004574 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004575 if (e.iop == iostack)
4576 ioecho(c);
4577 e.iop->prev = c;
4578 return e.iop->prev;
Eric Andersenff9eee42001-06-29 04:57:14 +00004579 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004580 if (e.iop->task == XIO && e.iop->prev != '\n') {
4581 e.iop->prev = 0;
4582 if (e.iop == iostack)
4583 ioecho('\n');
4584 return '\n';
Eric Andersen8401eea2004-08-04 19:16:54 +00004585 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004586 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004587 if (e.iop->task == XIO) {
4588 if (multiline) {
4589 e.iop->prev = 0;
4590 return e.iop->prev;
4591 }
4592 if (interactive && e.iop == iostack + 1) {
4593#if ENABLE_FEATURE_EDITING
4594 current_prompt = prompt->value;
4595#else
4596 prs(prompt->value);
4597#endif
4598 }
4599 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004600 } /* FOR */
4601
4602 if (e.iop >= iostack) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004603 RCPRINTF(("READC: return 0, e.iop %p\n", e.iop));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004604 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004605 }
4606
4607 DBGPRINTF(("READC: leave()...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00004608 leave();
Eric Andersen12de6cf2004-08-04 19:19:10 +00004609
Eric Andersenff9eee42001-06-29 04:57:14 +00004610 /* NOTREACHED */
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004611 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004612}
4613
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004614static void ioecho(char c)
Eric Andersenff9eee42001-06-29 04:57:14 +00004615{
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00004616 if (FLAG['v'])
Eric Andersenff9eee42001-06-29 04:57:14 +00004617 write(2, &c, sizeof c);
4618}
4619
Eric Andersen12de6cf2004-08-04 19:19:10 +00004620
Eric Andersen8401eea2004-08-04 19:16:54 +00004621static void pushio(struct ioarg *argp, int (*fn) (struct ioarg *))
Eric Andersenff9eee42001-06-29 04:57:14 +00004622{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004623 DBGPRINTF(("PUSHIO: argp %p, argp->afid 0x%x, e.iop %p\n", argp,
Eric Andersen12de6cf2004-08-04 19:19:10 +00004624 argp->afid, e.iop));
4625
4626 /* Set env ptr for io source to next array spot and check for array overflow */
Eric Andersenff9eee42001-06-29 04:57:14 +00004627 if (++e.iop >= &iostack[NPUSH]) {
4628 e.iop--;
4629 err("Shell input nested too deeply");
4630 gflg++;
4631 return;
4632 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004633
4634 /* We did not overflow the NPUSH array spots so setup data structs */
4635
4636 e.iop->iofn = (int (*)(struct ioarg *, struct io *)) fn; /* Store data source func ptr */
Eric Andersenff9eee42001-06-29 04:57:14 +00004637
4638 if (argp->afid != AFID_NOBUF)
Eric Andersen8401eea2004-08-04 19:16:54 +00004639 e.iop->argp = argp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004640 else {
Eric Andersen12de6cf2004-08-04 19:19:10 +00004641
4642 e.iop->argp = ioargstack + (e.iop - iostack); /* MAL - index into stack */
4643 *e.iop->argp = *argp; /* copy data from temp area into stack spot */
4644
4645 /* MAL - mainbuf is for 1st data source (command line?) and all nested use a single shared buffer? */
4646
4647 if (e.iop == &iostack[0])
4648 e.iop->argp->afbuf = &mainbuf;
4649 else
4650 e.iop->argp->afbuf = &sharedbuf;
4651
4652 /* MAL - if not a termimal AND (commandline OR readable file) then give it a buffer id? */
4653 /* This line appears to be active when running scripts from command line */
4654 if ((isatty(e.iop->argp->afile) == 0)
4655 && (e.iop == &iostack[0]
Denis Vlasenkoea620772006-10-14 02:23:43 +00004656 || lseek(e.iop->argp->afile, 0L, SEEK_CUR) != -1)) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00004657 if (++bufid == AFID_NOBUF) /* counter rollover check, AFID_NOBUF = 11111111 */
4658 bufid = AFID_ID; /* AFID_ID = 0 */
4659
4660 e.iop->argp->afid = bufid; /* assign buffer id */
Eric Andersen8401eea2004-08-04 19:16:54 +00004661 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004662
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004663 DBGPRINTF(("PUSHIO: iostack %p, e.iop %p, afbuf %p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00004664 iostack, e.iop, e.iop->argp->afbuf));
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004665 DBGPRINTF(("PUSHIO: mbuf %p, sbuf %p, bid %d, e.iop %p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00004666 &mainbuf, &sharedbuf, bufid, e.iop));
4667
Eric Andersenff9eee42001-06-29 04:57:14 +00004668 }
4669
Eric Andersen8401eea2004-08-04 19:16:54 +00004670 e.iop->prev = ~'\n';
Eric Andersenff9eee42001-06-29 04:57:14 +00004671 e.iop->peekc = 0;
4672 e.iop->xchar = 0;
4673 e.iop->nlcount = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004674
Eric Andersenff9eee42001-06-29 04:57:14 +00004675 if (fn == filechar || fn == linechar)
4676 e.iop->task = XIO;
Eric Andersen8401eea2004-08-04 19:16:54 +00004677 else if (fn == (int (*)(struct ioarg *)) gravechar
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004678 || fn == (int (*)(struct ioarg *)) qgravechar)
Eric Andersenff9eee42001-06-29 04:57:14 +00004679 e.iop->task = XGRAVE;
4680 else
4681 e.iop->task = XOTHER;
4682}
4683
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004684static struct io *setbase(struct io *ip)
Eric Andersenff9eee42001-06-29 04:57:14 +00004685{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004686 struct io *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004687
4688 xp = e.iobase;
4689 e.iobase = ip;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004690 return xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004691}
4692
4693/*
4694 * Input generating functions
4695 */
4696
4697/*
4698 * Produce the characters of a string, then a newline, then EOF.
4699 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004700static int nlchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004701{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004702 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004703
4704 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004705 return 0;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004706 c = *ap->aword++;
4707 if (c == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004708 ap->aword = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004709 return '\n';
Eric Andersenff9eee42001-06-29 04:57:14 +00004710 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004711 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004712}
4713
4714/*
4715 * Given a list of words, produce the characters
4716 * in them, with a space after each word.
4717 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004718static int wdchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004719{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004720 char c;
4721 char **wl;
Eric Andersenff9eee42001-06-29 04:57:14 +00004722
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004723 wl = ap->awordlist;
4724 if (wl == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004725 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004726 if (*wl != NULL) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004727 c = *(*wl)++;
4728 if (c != 0)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004729 return c & 0177;
Eric Andersenff9eee42001-06-29 04:57:14 +00004730 ap->awordlist++;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004731 return ' ';
Eric Andersenff9eee42001-06-29 04:57:14 +00004732 }
4733 ap->awordlist = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004734 return '\n';
Eric Andersenff9eee42001-06-29 04:57:14 +00004735}
4736
4737/*
4738 * Return the characters of a list of words,
4739 * producing a space between them.
4740 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004741static int dolchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004742{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004743 char *wp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004744
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004745 wp = *ap->awordlist++;
4746 if (wp != NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004747 PUSHIO(aword, wp, *ap->awordlist == NULL ? strchar : xxchar);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004748 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004749 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004750 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004751}
4752
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004753static int xxchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004754{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004755 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004756
4757 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004758 return 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004759 c = *ap->aword++;
4760 if (c == '\0') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004761 ap->aword = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004762 return ' ';
Eric Andersenff9eee42001-06-29 04:57:14 +00004763 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004764 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004765}
4766
4767/*
4768 * Produce the characters from a single word (string).
4769 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004770static int strchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004771{
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004772 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004773 return 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004774 return *ap->aword++;
Eric Andersenff9eee42001-06-29 04:57:14 +00004775}
4776
4777/*
4778 * Produce quoted characters from a single word (string).
4779 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004780static int qstrchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004781{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004782 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004783
Denis Vlasenkob2abef32007-01-01 18:18:04 +00004784 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004785 return 0;
Denis Vlasenkob2abef32007-01-01 18:18:04 +00004786 c = *ap->aword++;
4787 if (c)
4788 c |= QUOTE;
4789 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004790}
4791
4792/*
4793 * Return the characters from a file.
4794 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004795static int filechar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004796{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004797 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004798 char c;
4799 struct iobuf *bp = ap->afbuf;
4800
4801 if (ap->afid != AFID_NOBUF) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004802 i = (ap->afid != bp->id);
4803 if (i || bp->bufp == bp->ebufp) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004804 if (i)
Denis Vlasenkoea620772006-10-14 02:23:43 +00004805 lseek(ap->afile, ap->afpos, SEEK_SET);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004806
Eric Andersen8401eea2004-08-04 19:16:54 +00004807 i = safe_read(ap->afile, bp->buf, sizeof(bp->buf));
4808 if (i <= 0) {
4809 closef(ap->afile);
4810 return 0;
4811 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004812
Eric Andersen8401eea2004-08-04 19:16:54 +00004813 bp->id = ap->afid;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004814 bp->bufp = bp->buf;
4815 bp->ebufp = bp->bufp + i;
Eric Andersen8401eea2004-08-04 19:16:54 +00004816 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004817
Eric Andersen8401eea2004-08-04 19:16:54 +00004818 ap->afpos++;
4819 return *bp->bufp++ & 0177;
Eric Andersenff9eee42001-06-29 04:57:14 +00004820 }
Denis Vlasenko38f63192007-01-22 09:03:07 +00004821#if ENABLE_FEATURE_EDITING
Eric Andersen737f5fb2003-03-14 16:05:59 +00004822 if (interactive && isatty(ap->afile)) {
Denis Vlasenko55f30b02007-03-24 22:42:29 +00004823 /* moved to G: static char filechar_cmdbuf[BUFSIZ]; */
Eric Andersen8401eea2004-08-04 19:16:54 +00004824 static int position = 0, size = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004825
Eric Andersen8401eea2004-08-04 19:16:54 +00004826 while (size == 0 || position >= size) {
Denis Vlasenko55f30b02007-03-24 22:42:29 +00004827 read_line_input(current_prompt, filechar_cmdbuf, BUFSIZ, line_input_state);
4828 size = strlen(filechar_cmdbuf);
Eric Andersen8401eea2004-08-04 19:16:54 +00004829 position = 0;
4830 }
Denis Vlasenko55f30b02007-03-24 22:42:29 +00004831 c = filechar_cmdbuf[position];
Eric Andersen8401eea2004-08-04 19:16:54 +00004832 position++;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004833 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004834 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004835#endif
4836 i = safe_read(ap->afile, &c, sizeof(c));
4837 return i == sizeof(c) ? (c & 0x7f) : (closef(ap->afile), 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004838}
4839
4840/*
4841 * Return the characters from a here temp file.
4842 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004843static int herechar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004844{
4845 char c;
4846
Eric Andersenff9eee42001-06-29 04:57:14 +00004847 if (read(ap->afile, &c, sizeof(c)) != sizeof(c)) {
4848 close(ap->afile);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004849 c = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00004850 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004851 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004852}
4853
4854/*
4855 * Return the characters produced by a process (`...`).
4856 * Quote them if required, and remove any trailing newline characters.
4857 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004858static int gravechar(struct ioarg *ap, struct io *iop)
Eric Andersenff9eee42001-06-29 04:57:14 +00004859{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004860 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004861
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004862 c = qgravechar(ap, iop) & ~QUOTE;
4863 if (c == '\n')
Eric Andersenff9eee42001-06-29 04:57:14 +00004864 c = ' ';
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004865 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004866}
4867
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004868static int qgravechar(struct ioarg *ap, struct io *iop)
Eric Andersenff9eee42001-06-29 04:57:14 +00004869{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004870 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004871
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004872 DBGPRINTF3(("QGRAVECHAR: enter, ap=%p, iop=%p\n", ap, iop));
Eric Andersenff9eee42001-06-29 04:57:14 +00004873
4874 if (iop->xchar) {
4875 if (iop->nlcount) {
4876 iop->nlcount--;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004877 return '\n' | QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00004878 }
4879 c = iop->xchar;
4880 iop->xchar = 0;
4881 } else if ((c = filechar(ap)) == '\n') {
4882 iop->nlcount = 1;
4883 while ((c = filechar(ap)) == '\n')
4884 iop->nlcount++;
4885 iop->xchar = c;
4886 if (c == 0)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004887 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004888 iop->nlcount--;
4889 c = '\n';
4890 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004891 return c != 0 ? c | QUOTE : 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004892}
4893
4894/*
4895 * Return a single command (usually the first line) from a file.
4896 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004897static int linechar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004898{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004899 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004900
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004901 c = filechar(ap);
4902 if (c == '\n') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004903 if (!multiline) {
4904 closef(ap->afile);
Eric Andersen8401eea2004-08-04 19:16:54 +00004905 ap->afile = -1; /* illegal value */
Eric Andersenff9eee42001-06-29 04:57:14 +00004906 }
4907 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004908 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004909}
4910
Eric Andersenff9eee42001-06-29 04:57:14 +00004911/*
4912 * remap fd into Shell's fd space
4913 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004914static int remap(int fd)
Eric Andersenff9eee42001-06-29 04:57:14 +00004915{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004916 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004917 int map[NOFILE];
Eric Andersen12de6cf2004-08-04 19:19:10 +00004918 int newfd;
4919
Eric Andersen12de6cf2004-08-04 19:19:10 +00004920 DBGPRINTF(("REMAP: fd=%d, e.iofd=%d\n", fd, e.iofd));
Eric Andersenff9eee42001-06-29 04:57:14 +00004921
4922 if (fd < e.iofd) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004923 for (i = 0; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004924 map[i] = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004925
Eric Andersenff9eee42001-06-29 04:57:14 +00004926 do {
4927 map[fd] = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004928 newfd = dup(fd);
4929 fd = newfd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004930 } while (fd >= 0 && fd < e.iofd);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004931
Eric Andersen8401eea2004-08-04 19:16:54 +00004932 for (i = 0; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004933 if (map[i])
4934 close(i);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004935
Eric Andersenff9eee42001-06-29 04:57:14 +00004936 if (fd < 0)
4937 err("too many files open in shell");
4938 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004939
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004940 return fd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004941}
4942
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004943static int openpipe(int *pv)
Eric Andersenff9eee42001-06-29 04:57:14 +00004944{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004945 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004946
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004947 i = pipe(pv);
4948 if (i < 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00004949 err("can't create pipe - try again");
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004950 return i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004951}
4952
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004953static void closepipe(int *pv)
Eric Andersenff9eee42001-06-29 04:57:14 +00004954{
4955 if (pv != NULL) {
4956 close(*pv++);
4957 close(*pv);
4958 }
4959}
4960
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004961
Eric Andersenff9eee42001-06-29 04:57:14 +00004962/* -------- here.c -------- */
4963
4964/*
4965 * here documents
4966 */
4967
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004968static void markhere(char *s, struct ioword *iop)
Eric Andersenff9eee42001-06-29 04:57:14 +00004969{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004970 struct here *h, *lh;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004971
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004972 DBGPRINTF7(("MARKHERE: enter, s=%p\n", s));
Eric Andersenff9eee42001-06-29 04:57:14 +00004973
4974 h = (struct here *) space(sizeof(struct here));
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004975 if (h == NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00004976 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004977
Eric Andersenff9eee42001-06-29 04:57:14 +00004978 h->h_tag = evalstr(s, DOSUB);
4979 if (h->h_tag == 0)
4980 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004981
Eric Andersenff9eee42001-06-29 04:57:14 +00004982 h->h_iop = iop;
4983 iop->io_name = 0;
4984 h->h_next = NULL;
4985 if (inhere == 0)
4986 inhere = h;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004987 else {
4988 for (lh = inhere; lh != NULL; lh = lh->h_next) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004989 if (lh->h_next == 0) {
4990 lh->h_next = h;
4991 break;
4992 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004993 }
4994 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004995 iop->io_flag |= IOHERE | IOXHERE;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004996 for (s = h->h_tag; *s; s++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004997 if (*s & QUOTE) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004998 iop->io_flag &= ~IOXHERE;
4999 *s &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00005000 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00005001 }
Eric Andersenff9eee42001-06-29 04:57:14 +00005002 h->h_dosub = iop->io_flag & IOXHERE;
5003}
5004
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005005static void gethere(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00005006{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005007 struct here *h, *hp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005008
5009 DBGPRINTF7(("GETHERE: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00005010
5011 /* Scan here files first leaving inhere list in place */
5012 for (hp = h = inhere; h != NULL; hp = h, h = h->h_next)
Eric Andersen8401eea2004-08-04 19:16:54 +00005013 readhere(&h->h_iop->io_name, h->h_tag, h->h_dosub ? 0 : '\'');
Eric Andersenff9eee42001-06-29 04:57:14 +00005014
5015 /* Make inhere list active - keep list intact for scraphere */
5016 if (hp != NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005017 hp->h_next = acthere;
5018 acthere = inhere;
5019 inhere = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00005020 }
5021}
5022
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005023static void readhere(char **name, char *s, int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00005024{
5025 int tf;
5026 char tname[30] = ".msh_XXXXXX";
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005027 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00005028 jmp_buf ev;
Eric Andersen8401eea2004-08-04 19:16:54 +00005029 char myline[LINELIM + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00005030 char *thenext;
5031
Mike Frysinger02d8fa42006-05-05 20:32:31 +00005032 DBGPRINTF7(("READHERE: enter, name=%p, s=%p\n", name, s));
Eric Andersen12de6cf2004-08-04 19:19:10 +00005033
Eric Andersenff9eee42001-06-29 04:57:14 +00005034 tf = mkstemp(tname);
5035 if (tf < 0)
5036 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005037
Eric Andersenff9eee42001-06-29 04:57:14 +00005038 *name = strsave(tname, areanum);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00005039 errpt = ev;
5040 if (newenv(setjmp(errpt)) != 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00005041 unlink(tname);
5042 else {
Eric Andersen8401eea2004-08-04 19:16:54 +00005043 pushio(e.iop->argp, (int (*)(struct ioarg *)) e.iop->iofn);
Eric Andersenff9eee42001-06-29 04:57:14 +00005044 e.iobase = e.iop;
5045 for (;;) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005046 if (interactive && e.iop <= iostack) {
Denis Vlasenko38f63192007-01-22 09:03:07 +00005047#if ENABLE_FEATURE_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00005048 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00005049#else
Eric Andersen8401eea2004-08-04 19:16:54 +00005050 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00005051#endif
5052 }
5053 thenext = myline;
5054 while ((c = my_getc(ec)) != '\n' && c) {
5055 if (ec == '\'')
Eric Andersen8401eea2004-08-04 19:16:54 +00005056 c &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00005057 if (thenext >= &myline[LINELIM]) {
5058 c = 0;
5059 break;
5060 }
5061 *thenext++ = c;
5062 }
5063 *thenext = 0;
5064 if (strcmp(s, myline) == 0 || c == 0)
5065 break;
5066 *thenext++ = '\n';
Eric Andersen8401eea2004-08-04 19:16:54 +00005067 write(tf, myline, (int) (thenext - myline));
Eric Andersenff9eee42001-06-29 04:57:14 +00005068 }
5069 if (c == 0) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005070 prs("here document `");
5071 prs(s);
5072 err("' unclosed");
Eric Andersenff9eee42001-06-29 04:57:14 +00005073 }
5074 quitenv();
5075 }
5076 close(tf);
5077}
5078
5079/*
5080 * open here temp file.
5081 * if unquoted here, expand here temp file into second temp file.
5082 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005083static int herein(char *hname, int xdoll)
Eric Andersenff9eee42001-06-29 04:57:14 +00005084{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005085 int hf;
Eric Andersenff9eee42001-06-29 04:57:14 +00005086 int tf;
5087
5088#if __GNUC__
5089 /* Avoid longjmp clobbering */
5090 (void) &tf;
5091#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00005092 if (hname == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00005093 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005094
5095 DBGPRINTF7(("HEREIN: hname is %s, xdoll=%d\n", hname, xdoll));
5096
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005097 hf = open(hname, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00005098 if (hf < 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00005099 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005100
Eric Andersenff9eee42001-06-29 04:57:14 +00005101 if (xdoll) {
5102 char c;
5103 char tname[30] = ".msh_XXXXXX";
5104 jmp_buf ev;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005105
Eric Andersenff9eee42001-06-29 04:57:14 +00005106 tf = mkstemp(tname);
5107 if (tf < 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00005108 return -1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00005109 errpt = ev;
5110 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00005111 PUSHIO(afile, hf, herechar);
5112 setbase(e.iop);
5113 while ((c = subgetc(0, 0)) != 0) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005114 c &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00005115 write(tf, &c, sizeof c);
5116 }
5117 quitenv();
5118 } else
5119 unlink(tname);
5120 close(tf);
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005121 tf = open(tname, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00005122 unlink(tname);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00005123 return tf;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00005124 }
5125 return hf;
Eric Andersenff9eee42001-06-29 04:57:14 +00005126}
5127
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005128static void scraphere(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00005129{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005130 struct here *h;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005131
5132 DBGPRINTF7(("SCRAPHERE: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00005133
5134 for (h = inhere; h != NULL; h = h->h_next) {
5135 if (h->h_iop && h->h_iop->io_name)
Eric Andersen8401eea2004-08-04 19:16:54 +00005136 unlink(h->h_iop->io_name);
Eric Andersenff9eee42001-06-29 04:57:14 +00005137 }
5138 inhere = NULL;
5139}
5140
5141/* unlink here temp files before a freearea(area) */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005142static void freehere(int area)
Eric Andersenff9eee42001-06-29 04:57:14 +00005143{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005144 struct here *h, *hl;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005145
5146 DBGPRINTF6(("FREEHERE: enter, area=%d\n", area));
Eric Andersenff9eee42001-06-29 04:57:14 +00005147
5148 hl = NULL;
5149 for (h = acthere; h != NULL; h = h->h_next)
5150 if (getarea((char *) h) >= area) {
5151 if (h->h_iop->io_name != NULL)
5152 unlink(h->h_iop->io_name);
5153 if (hl == NULL)
5154 acthere = h->h_next;
5155 else
5156 hl->h_next = h->h_next;
5157 } else
5158 hl = h;
5159}
5160
5161
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005162/* -------- sh.c -------- */
5163/*
5164 * shell
5165 */
5166
Denis Vlasenko06af2162007-02-03 17:28:39 +00005167int msh_main(int argc, char **argv);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005168int msh_main(int argc, char **argv)
5169{
5170 int f;
5171 char *s;
5172 int cflag;
5173 char *name, **ap;
5174 int (*iof) (struct ioarg *);
5175
Denis Vlasenko55f30b02007-03-24 22:42:29 +00005176 PTR_TO_GLOBALS = xzalloc(sizeof(G));
5177 sharedbuf.id = AFID_NOBUF;
5178 mainbuf.id = AFID_NOBUF;
5179 e.linep = line;
5180 elinep = line + sizeof(line) - 5;
5181
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005182#if ENABLE_FEATURE_EDITING
5183 line_input_state = new_line_input_t(FOR_SHELL);
5184#endif
5185
5186 DBGPRINTF(("MSH_MAIN: argc %d, environ %p\n", argc, environ));
5187
5188 initarea();
5189 ap = environ;
5190 if (ap != NULL) {
5191 while (*ap)
5192 assign(*ap++, !COPYV);
5193 for (ap = environ; *ap;)
5194 export(lookup(*ap++));
5195 }
5196 closeall();
5197 areanum = 1;
5198
5199 shell = lookup("SHELL");
5200 if (shell->value == null)
5201 setval(shell, (char *)DEFAULT_SHELL);
5202 export(shell);
5203
5204 homedir = lookup("HOME");
5205 if (homedir->value == null)
5206 setval(homedir, "/");
5207 export(homedir);
5208
5209 setval(lookup("$"), putn(getpid()));
5210
5211 path = lookup("PATH");
5212 if (path->value == null) {
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005213 /* Can be merged with same string elsewhere in bbox */
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005214 if (geteuid() == 0)
Denis Vlasenkof5f75c52007-06-12 22:35:19 +00005215 setval(path, bb_default_root_path);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005216 else
Denis Vlasenkof5f75c52007-06-12 22:35:19 +00005217 setval(path, bb_default_path);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005218 }
5219 export(path);
5220
5221 ifs = lookup("IFS");
5222 if (ifs->value == null)
5223 setval(ifs, " \t\n");
5224
5225#ifdef MSHDEBUG
5226 mshdbg_var = lookup("MSHDEBUG");
5227 if (mshdbg_var->value == null)
5228 setval(mshdbg_var, "0");
5229#endif
5230
5231 prompt = lookup("PS1");
5232#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
5233 if (prompt->value == null)
5234#endif
5235 setval(prompt, DEFAULT_USER_PROMPT);
5236 if (geteuid() == 0) {
5237 setval(prompt, DEFAULT_ROOT_PROMPT);
5238 prompt->status &= ~EXPORT;
5239 }
5240 cprompt = lookup("PS2");
5241#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
5242 if (cprompt->value == null)
5243#endif
5244 setval(cprompt, "> ");
5245
5246 iof = filechar;
5247 cflag = 0;
5248 name = *argv++;
5249 if (--argc >= 1) {
5250 if (argv[0][0] == '-' && argv[0][1] != '\0') {
5251 for (s = argv[0] + 1; *s; s++)
5252 switch (*s) {
5253 case 'c':
5254 prompt->status &= ~EXPORT;
5255 cprompt->status &= ~EXPORT;
5256 setval(prompt, "");
5257 setval(cprompt, "");
5258 cflag = 1;
5259 if (--argc > 0)
5260 PUSHIO(aword, *++argv, iof = nlchar);
5261 break;
5262
5263 case 'q':
5264 qflag = SIG_DFL;
5265 break;
5266
5267 case 's':
5268 /* standard input */
5269 break;
5270
5271 case 't':
5272 prompt->status &= ~EXPORT;
5273 setval(prompt, "");
5274 iof = linechar;
5275 break;
5276
5277 case 'i':
5278 interactive++;
5279 default:
5280 if (*s >= 'a' && *s <= 'z')
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00005281 FLAG[(int) *s]++;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005282 }
5283 } else {
5284 argv--;
5285 argc++;
5286 }
5287
5288 if (iof == filechar && --argc > 0) {
5289 setval(prompt, "");
5290 setval(cprompt, "");
5291 prompt->status &= ~EXPORT;
5292 cprompt->status &= ~EXPORT;
5293
5294/* Shell is non-interactive, activate printf-based debug */
5295#ifdef MSHDEBUG
5296 mshdbg = (int) (((char) (mshdbg_var->value[0])) - '0');
5297 if (mshdbg < 0)
5298 mshdbg = 0;
5299#endif
5300 DBGPRINTF(("MSH_MAIN: calling newfile()\n"));
5301
5302 name = *++argv;
5303 if (newfile(name))
5304 exit(1); /* Exit on error */
5305 }
5306 }
5307
5308 setdash();
5309
5310 /* This won't be true if PUSHIO has been called, say from newfile() above */
5311 if (e.iop < iostack) {
5312 PUSHIO(afile, 0, iof);
5313 if (isatty(0) && isatty(1) && !cflag) {
5314 interactive++;
5315#if !ENABLE_FEATURE_SH_EXTRA_QUIET
5316#ifdef MSHDEBUG
Denis Vlasenkoca525b42007-06-13 12:27:17 +00005317 printf("\n\n%s built-in shell (msh with debug)\n", bb_banner);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005318#else
Denis Vlasenkoca525b42007-06-13 12:27:17 +00005319 printf("\n\n%s built-in shell (msh)\n", bb_banner);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005320#endif
5321 printf("Enter 'help' for a list of built-in commands.\n\n");
5322#endif
5323 }
5324 }
5325
5326 signal(SIGQUIT, qflag);
5327 if (name && name[0] == '-') {
5328 interactive++;
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005329 f = open(".profile", O_RDONLY);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005330 if (f >= 0)
5331 next(remap(f));
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005332 f = open("/etc/profile", O_RDONLY);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005333 if (f >= 0)
5334 next(remap(f));
5335 }
5336 if (interactive)
5337 signal(SIGTERM, sig);
5338
5339 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
5340 signal(SIGINT, onintr);
5341 dolv = argv;
5342 dolc = argc;
5343 dolv[0] = name;
5344 if (dolc > 1) {
5345 for (ap = ++argv; --argc > 0;) {
5346 *ap = *argv++;
5347 if (assign(*ap, !COPYV)) {
5348 dolc--; /* keyword */
5349 } else {
5350 ap++;
5351 }
5352 }
5353 }
5354 setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc));
5355
5356 DBGPRINTF(("MSH_MAIN: begin FOR loop, interactive %d, e.iop %p, iostack %p\n", interactive, e.iop, iostack));
5357
5358 for (;;) {
5359 if (interactive && e.iop <= iostack) {
5360#if ENABLE_FEATURE_EDITING
5361 current_prompt = prompt->value;
5362#else
5363 prs(prompt->value);
5364#endif
5365 }
5366 onecommand();
5367 /* Ensure that getenv("PATH") stays current */
5368 setenv("PATH", path->value, 1);
5369 }
5370
5371 DBGPRINTF(("MSH_MAIN: returning.\n"));
5372}
5373
5374
Eric Andersenff9eee42001-06-29 04:57:14 +00005375/*
5376 * Copyright (c) 1987,1997, Prentice Hall
5377 * All rights reserved.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005378 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005379 * Redistribution and use of the MINIX operating system in source and
5380 * binary forms, with or without modification, are permitted provided
5381 * that the following conditions are met:
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005382 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005383 * Redistributions of source code must retain the above copyright
5384 * notice, this list of conditions and the following disclaimer.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005385 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005386 * Redistributions in binary form must reproduce the above
5387 * copyright notice, this list of conditions and the following
5388 * disclaimer in the documentation and/or other materials provided
5389 * with the distribution.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005390 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005391 * Neither the name of Prentice Hall nor the names of the software
5392 * authors or contributors may be used to endorse or promote
5393 * products derived from this software without specific prior
5394 * written permission.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005395 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005396 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND
5397 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
5398 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
5399 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
5400 * IN NO EVENT SHALL PRENTICE HALL OR ANY AUTHORS OR CONTRIBUTORS BE
5401 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
5402 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
5403 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
5404 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
5405 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
5406 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
5407 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5408 *
5409 */