blob: 65556043dcd7cf53428b2034afa52a601d7c6806 [file] [log] [blame]
Eric Andersenff9eee42001-06-29 04:57:14 +00001/* vi: set sw=4 ts=4: */
2/*
3 * Minix shell port for busybox
4 *
5 * This version of the Minix shell was adapted for use in busybox
Eric Andersencb81e642003-07-14 21:21:08 +00006 * by Erik Andersen <andersen@codepoet.org>
Eric Andersenff9eee42001-06-29 04:57:14 +00007 *
Eric Andersen737f5fb2003-03-14 16:05:59 +00008 * - backtick expansion did not work properly
9 * Jonas Holmberg <jonas.holmberg@axis.com>
10 * Robert Schwebel <r.schwebel@pengutronix.de>
Eric Andersencb81e642003-07-14 21:21:08 +000011 * Erik Andersen <andersen@codepoet.org>
Eric Andersen737f5fb2003-03-14 16:05:59 +000012 *
Rob Landleyc9c1a412006-07-12 19:17:55 +000013 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
Eric Andersenff9eee42001-06-29 04:57:14 +000014 */
15
Denis Vlasenko95cb3262007-04-09 03:06:34 +000016#include <sys/times.h>
17#include <setjmp.h>
Denis Vlasenko55f30b02007-03-24 22:42:29 +000018
Mike Frysinger67a32ad2007-03-09 08:25:24 +000019#ifdef STANDALONE
20# ifndef _GNU_SOURCE
21# define _GNU_SOURCE
22# endif
Mike Frysinger67a32ad2007-03-09 08:25:24 +000023# include <sys/types.h>
24# include <sys/stat.h>
25# include <sys/wait.h>
26# include <signal.h>
27# include <stdio.h>
28# include <stdlib.h>
29# include <unistd.h>
30# include <string.h>
31# include <errno.h>
32# include <dirent.h>
33# include <fcntl.h>
34# include <ctype.h>
35# include <assert.h>
36# define bb_dev_null "/dev/null"
37# define DEFAULT_SHELL "/proc/self/exe"
38# define CONFIG_BUSYBOX_EXEC_PATH "/proc/self/exe"
Denis Vlasenkoca525b42007-06-13 12:27:17 +000039# define bb_banner "busybox standalone"
Denis Vlasenko80d14be2007-04-10 23:03:30 +000040# define ENABLE_FEATURE_SH_STANDALONE 0
Mike Frysinger67a32ad2007-03-09 08:25:24 +000041# define bb_msg_memory_exhausted "memory exhausted"
42# define xmalloc(size) malloc(size)
43# define msh_main(argc,argv) main(argc,argv)
44# define safe_read(fd,buf,count) read(fd,buf,count)
45# define NOT_LONE_DASH(s) ((s)[0] != '-' || (s)[1])
46# define LONE_CHAR(s,c) ((s)[0] == (c) && !(s)[1])
47# define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__))
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000048static int find_applet_by_name(const char *applet)
Mike Frysinger67a32ad2007-03-09 08:25:24 +000049{
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000050 return -1;
Mike Frysinger67a32ad2007-03-09 08:25:24 +000051}
Denis Vlasenko10457b92007-03-27 22:01:31 +000052static char *utoa_to_buf(unsigned n, char *buf, unsigned buflen)
Mike Frysinger67a32ad2007-03-09 08:25:24 +000053{
Denis Vlasenkoc86e0522007-03-20 11:30:28 +000054 unsigned i, out, res;
55 assert(sizeof(unsigned) == 4);
56 if (buflen) {
57 out = 0;
58 for (i = 1000000000; i; i /= 10) {
59 res = n / i;
60 if (res || out || i == 1) {
Denis Vlasenko4b924f32007-05-30 00:29:55 +000061 if (!--buflen) break;
62 out++;
63 n -= res*i;
64 *buf++ = '0' + res;
Denis Vlasenkoc86e0522007-03-20 11:30:28 +000065 }
66 }
Denis Vlasenkoc86e0522007-03-20 11:30:28 +000067 }
Denis Vlasenko10457b92007-03-27 22:01:31 +000068 return buf;
Mike Frysinger67a32ad2007-03-09 08:25:24 +000069}
Denis Vlasenko10457b92007-03-27 22:01:31 +000070static char *itoa_to_buf(int n, char *buf, unsigned buflen)
Mike Frysinger67a32ad2007-03-09 08:25:24 +000071{
Denis Vlasenkoc86e0522007-03-20 11:30:28 +000072 if (buflen && n < 0) {
73 n = -n;
74 *buf++ = '-';
75 buflen--;
76 }
Denis Vlasenko10457b92007-03-27 22:01:31 +000077 return utoa_to_buf((unsigned)n, buf, buflen);
Mike Frysinger67a32ad2007-03-09 08:25:24 +000078}
79static char local_buf[12];
80static char *itoa(int n)
81{
Denis Vlasenko10457b92007-03-27 22:01:31 +000082 *(itoa_to_buf(n, local_buf, sizeof(local_buf))) = '\0';
Denis Vlasenkoc86e0522007-03-20 11:30:28 +000083 return local_buf;
Mike Frysinger67a32ad2007-03-09 08:25:24 +000084}
85#else
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000086# include "busybox.h" /* for applet_names */
Mike Frysinger67a32ad2007-03-09 08:25:24 +000087#endif
Eric Andersenff9eee42001-06-29 04:57:14 +000088
Denis Vlasenko7e497522008-02-12 09:51:03 +000089//#define MSHDEBUG 4
Eric Andersen12de6cf2004-08-04 19:19:10 +000090
91#ifdef MSHDEBUG
Mike Frysinger14ff19b2006-06-20 20:37:01 +000092int mshdbg = MSHDEBUG;
Eric Andersen12de6cf2004-08-04 19:19:10 +000093
Denis Vlasenko51742f42007-04-12 00:32:05 +000094#define DBGPRINTF(x) if (mshdbg>0) printf x
95#define DBGPRINTF0(x) if (mshdbg>0) printf x
96#define DBGPRINTF1(x) if (mshdbg>1) printf x
97#define DBGPRINTF2(x) if (mshdbg>2) printf x
98#define DBGPRINTF3(x) if (mshdbg>3) printf x
99#define DBGPRINTF4(x) if (mshdbg>4) printf x
100#define DBGPRINTF5(x) if (mshdbg>5) printf x
101#define DBGPRINTF6(x) if (mshdbg>6) printf x
102#define DBGPRINTF7(x) if (mshdbg>7) printf x
103#define DBGPRINTF8(x) if (mshdbg>8) printf x
104#define DBGPRINTF9(x) if (mshdbg>9) printf x
Eric Andersen12de6cf2004-08-04 19:19:10 +0000105
106int mshdbg_rc = 0;
107
Denis Vlasenko51742f42007-04-12 00:32:05 +0000108#define RCPRINTF(x) if (mshdbg_rc) printf x
Eric Andersen12de6cf2004-08-04 19:19:10 +0000109
110#else
111
112#define DBGPRINTF(x)
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000113#define DBGPRINTF0(x) ((void)0)
114#define DBGPRINTF1(x) ((void)0)
115#define DBGPRINTF2(x) ((void)0)
116#define DBGPRINTF3(x) ((void)0)
117#define DBGPRINTF4(x) ((void)0)
118#define DBGPRINTF5(x) ((void)0)
119#define DBGPRINTF6(x) ((void)0)
120#define DBGPRINTF7(x) ((void)0)
121#define DBGPRINTF8(x) ((void)0)
122#define DBGPRINTF9(x) ((void)0)
Eric Andersen12de6cf2004-08-04 19:19:10 +0000123
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000124#define RCPRINTF(x) ((void)0)
Eric Andersen12de6cf2004-08-04 19:19:10 +0000125
126#endif /* MSHDEBUG */
127
128
Denis Vlasenko38f63192007-01-22 09:03:07 +0000129#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
Mike Frysinger2a131752006-06-06 06:26:12 +0000130# define DEFAULT_ROOT_PROMPT "\\u:\\w> "
131# define DEFAULT_USER_PROMPT "\\u:\\w$ "
132#else
133# define DEFAULT_ROOT_PROMPT "# "
134# define DEFAULT_USER_PROMPT "$ "
135#endif
136
137
Eric Andersenff9eee42001-06-29 04:57:14 +0000138/* -------- sh.h -------- */
139/*
140 * shell
141 */
142
Eric Andersen12de6cf2004-08-04 19:19:10 +0000143#define LINELIM 2100
144#define NPUSH 8 /* limit to input nesting */
Eric Andersenff9eee42001-06-29 04:57:14 +0000145
Eric Andersen392947c2002-12-11 07:42:46 +0000146#undef NOFILE
Eric Andersen12de6cf2004-08-04 19:19:10 +0000147#define NOFILE 20 /* Number of open files */
148#define NUFILE 10 /* Number of user-accessible files */
149#define FDBASE 10 /* First file usable by Shell */
Eric Andersenff9eee42001-06-29 04:57:14 +0000150
151/*
152 * values returned by wait
153 */
Denis Vlasenko5f9468e2007-04-14 13:22:09 +0000154#define WAITSIG(s) ((s) & 0177)
155#define WAITVAL(s) (((s) >> 8) & 0377)
156#define WAITCORE(s) (((s) & 0200) != 0)
Eric Andersenff9eee42001-06-29 04:57:14 +0000157
158/*
Eric Andersenaff114c2004-04-14 17:51:38 +0000159 * library and system definitions
Eric Andersenff9eee42001-06-29 04:57:14 +0000160 */
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000161typedef void xint; /* base type of jmp_buf, for not broken compilers */
Eric Andersenff9eee42001-06-29 04:57:14 +0000162
163/*
164 * shell components
165 */
Eric Andersenff9eee42001-06-29 04:57:14 +0000166#define NOBLOCK ((struct op *)NULL)
167#define NOWORD ((char *)NULL)
168#define NOWORDS ((char **)NULL)
169#define NOPIPE ((int *)NULL)
170
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000171/*
172 * redirection
173 */
174struct ioword {
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000175 short io_unit; /* unit affected */
176 short io_flag; /* action (below) */
177 char *io_name; /* file name */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000178};
179
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000180#define IOREAD 1 /* < */
181#define IOHERE 2 /* << (here file) */
182#define IOWRITE 4 /* > */
183#define IOCAT 8 /* >> */
184#define IOXHERE 16 /* ${}, ` in << */
185#define IODUP 32 /* >&digit */
186#define IOCLOSE 64 /* >&- */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000187
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000188#define IODEFAULT (-1) /* token for default IO unit */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000189
190
Eric Andersenff9eee42001-06-29 04:57:14 +0000191/*
192 * Description of a command or an operation on commands.
193 * Might eventually use a union.
194 */
195struct op {
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000196 smallint type; /* operation type, see Txxxx below */
197 char **words; /* arguments to a command */
198 struct ioword **ioact; /* IO actions (eg, < > >>) */
Eric Andersenff9eee42001-06-29 04:57:14 +0000199 struct op *left;
200 struct op *right;
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000201 char *str; /* identifier for case and for */
Eric Andersenff9eee42001-06-29 04:57:14 +0000202};
203
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000204#define TCOM 1 /* command */
205#define TPAREN 2 /* (c-list) */
206#define TPIPE 3 /* a | b */
207#define TLIST 4 /* a [&;] b */
208#define TOR 5 /* || */
209#define TAND 6 /* && */
210#define TFOR 7
211#define TDO 8
212#define TCASE 9
213#define TIF 10
214#define TWHILE 11
215#define TUNTIL 12
216#define TELIF 13
217#define TPAT 14 /* pattern in case */
218#define TBRACE 15 /* {c-list} */
219#define TASYNC 16 /* c & */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000220/* Added to support "." file expansion */
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000221#define TDOT 17
Eric Andersen12de6cf2004-08-04 19:19:10 +0000222
223/* Strings for names to make debug easier */
"Vladimir N. Oleynik"ac973172005-09-22 14:38:17 +0000224#ifdef MSHDEBUG
Denis Vlasenkoe27f1562007-01-01 06:00:38 +0000225static const char *const T_CMD_NAMES[] = {
Eric Andersen12de6cf2004-08-04 19:19:10 +0000226 "PLACEHOLDER",
227 "TCOM",
228 "TPAREN",
229 "TPIPE",
230 "TLIST",
231 "TOR",
232 "TAND",
233 "TFOR",
234 "TDO",
235 "TCASE",
236 "TIF",
237 "TWHILE",
238 "TUNTIL",
239 "TELIF",
240 "TPAT",
241 "TBRACE",
242 "TASYNC",
243 "TDOT",
244};
"Vladimir N. Oleynik"ac973172005-09-22 14:38:17 +0000245#endif
Eric Andersenff9eee42001-06-29 04:57:14 +0000246
Denis Vlasenko5f9468e2007-04-14 13:22:09 +0000247#define AREASIZE (90000)
Eric Andersen12de6cf2004-08-04 19:19:10 +0000248
Eric Andersenff9eee42001-06-29 04:57:14 +0000249/*
250 * flags to control evaluation of words
251 */
Denis Vlasenko5f9468e2007-04-14 13:22:09 +0000252#define DOSUB 1 /* interpret $, `, and quotes */
253#define DOBLANK 2 /* perform blank interpretation */
254#define DOGLOB 4 /* interpret [?* */
255#define DOKEY 8 /* move words with `=' to 2nd arg. list */
256#define DOTRIM 16 /* trim resulting string */
Eric Andersenff9eee42001-06-29 04:57:14 +0000257
Denis Vlasenko5f9468e2007-04-14 13:22:09 +0000258#define DOALL (DOSUB|DOBLANK|DOGLOB|DOKEY|DOTRIM)
Eric Andersenff9eee42001-06-29 04:57:14 +0000259
Eric Andersenff9eee42001-06-29 04:57:14 +0000260
Eric Andersen8401eea2004-08-04 19:16:54 +0000261struct brkcon {
262 jmp_buf brkpt;
263 struct brkcon *nextlev;
264};
Eric Andersenff9eee42001-06-29 04:57:14 +0000265
Eric Andersen12de6cf2004-08-04 19:19:10 +0000266
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000267static smallint trapset; /* trap pending (signal number) */
Eric Andersenff9eee42001-06-29 04:57:14 +0000268
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000269static smallint yynerrs; /* yacc (flag) */
Eric Andersenff9eee42001-06-29 04:57:14 +0000270
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000271/* moved to G: static char line[LINELIM]; */
Eric Andersenff9eee42001-06-29 04:57:14 +0000272
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000273#if ENABLE_FEATURE_EDITING
274static char *current_prompt;
275static line_input_t *line_input_state;
276#endif
277
Eric Andersen12de6cf2004-08-04 19:19:10 +0000278
Eric Andersenff9eee42001-06-29 04:57:14 +0000279/*
280 * other functions
281 */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000282static const char *rexecve(char *c, char **v, char **envp);
Eric Andersen8401eea2004-08-04 19:16:54 +0000283static char *evalstr(char *cp, int f);
284static char *putn(int n);
Eric Andersen8401eea2004-08-04 19:16:54 +0000285static char *unquote(char *as);
Eric Andersen8401eea2004-08-04 19:16:54 +0000286static int rlookup(char *n);
287static struct wdblock *glob(char *cp, struct wdblock *wb);
288static int my_getc(int ec);
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +0000289static int subgetc(char ec, int quoted);
Eric Andersenfd7a4c82004-09-02 23:13:10 +0000290static char **makenv(int all, struct wdblock *wb);
Eric Andersen8401eea2004-08-04 19:16:54 +0000291static char **eval(char **ap, int f);
292static int setstatus(int s);
293static int waitfor(int lastpid, int canintr);
Eric Andersenff9eee42001-06-29 04:57:14 +0000294
Eric Andersen8401eea2004-08-04 19:16:54 +0000295static void onintr(int s); /* SIGINT handler */
Eric Andersenff9eee42001-06-29 04:57:14 +0000296
Eric Andersen8401eea2004-08-04 19:16:54 +0000297static int newenv(int f);
298static void quitenv(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000299static void next(int f);
300static void setdash(void);
301static void onecommand(void);
302static void runtrap(int i);
Eric Andersenff9eee42001-06-29 04:57:14 +0000303
Eric Andersen12de6cf2004-08-04 19:19:10 +0000304
Eric Andersenff9eee42001-06-29 04:57:14 +0000305/* -------- area stuff -------- */
306
Denis Vlasenko5f9468e2007-04-14 13:22:09 +0000307#define REGSIZE sizeof(struct region)
308#define GROWBY (256)
309/* #define SHRINKBY (64) */
310#undef SHRINKBY
311#define FREE (32767)
312#define BUSY (0)
313#define ALIGN (sizeof(int)-1)
Eric Andersenff9eee42001-06-29 04:57:14 +0000314
315
316struct region {
Eric Andersen8401eea2004-08-04 19:16:54 +0000317 struct region *next;
318 int area;
Eric Andersenff9eee42001-06-29 04:57:14 +0000319};
320
321
Eric Andersenff9eee42001-06-29 04:57:14 +0000322/* -------- grammar stuff -------- */
323typedef union {
Eric Andersen8401eea2004-08-04 19:16:54 +0000324 char *cp;
325 char **wp;
326 int i;
327 struct op *o;
Eric Andersenff9eee42001-06-29 04:57:14 +0000328} YYSTYPE;
Eric Andersen8401eea2004-08-04 19:16:54 +0000329
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000330#define WORD 256
331#define LOGAND 257
332#define LOGOR 258
333#define BREAK 259
334#define IF 260
335#define THEN 261
336#define ELSE 262
337#define ELIF 263
338#define FI 264
339#define CASE 265
340#define ESAC 266
341#define FOR 267
342#define WHILE 268
343#define UNTIL 269
344#define DO 270
345#define DONE 271
346#define IN 272
Eric Andersen12de6cf2004-08-04 19:19:10 +0000347/* Added for "." file expansion */
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000348#define DOT 273
Eric Andersen12de6cf2004-08-04 19:19:10 +0000349
Eric Andersenff9eee42001-06-29 04:57:14 +0000350#define YYERRCODE 300
351
352/* flags to yylex */
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000353#define CONTIN 01 /* skip new lines to complete command */
Eric Andersenff9eee42001-06-29 04:57:14 +0000354
Eric Andersen8401eea2004-08-04 19:16:54 +0000355static struct op *pipeline(int cf);
Eric Andersenff9eee42001-06-29 04:57:14 +0000356static struct op *andor(void);
357static struct op *c_list(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000358static int synio(int cf);
359static void musthave(int c, int cf);
Eric Andersenff9eee42001-06-29 04:57:14 +0000360static struct op *simple(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000361static struct op *nested(int type, int mark);
362static struct op *command(int cf);
363static struct op *dogroup(int onlydone);
Eric Andersenff9eee42001-06-29 04:57:14 +0000364static struct op *thenpart(void);
365static struct op *elsepart(void);
366static struct op *caselist(void);
367static struct op *casepart(void);
368static char **pattern(void);
369static char **wordlist(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000370static struct op *list(struct op *t1, struct op *t2);
371static struct op *block(int type, struct op *t1, struct op *t2, char **wp);
Eric Andersenff9eee42001-06-29 04:57:14 +0000372static struct op *newtp(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000373static struct op *namelist(struct op *t);
Eric Andersenff9eee42001-06-29 04:57:14 +0000374static char **copyw(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000375static void word(char *cp);
Eric Andersenff9eee42001-06-29 04:57:14 +0000376static struct ioword **copyio(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000377static struct ioword *io(int u, int f, char *cp);
Eric Andersen8401eea2004-08-04 19:16:54 +0000378static int yylex(int cf);
379static int collect(int c, int c1);
380static int dual(int c);
381static void diag(int ec);
382static char *tree(unsigned size);
Eric Andersenff9eee42001-06-29 04:57:14 +0000383
384/* -------- var.h -------- */
385
Eric Andersen8401eea2004-08-04 19:16:54 +0000386struct var {
387 char *value;
388 char *name;
389 struct var *next;
390 char status;
Eric Andersenff9eee42001-06-29 04:57:14 +0000391};
Eric Andersenff9eee42001-06-29 04:57:14 +0000392
Eric Andersen8401eea2004-08-04 19:16:54 +0000393#define COPYV 1 /* flag to setval, suggesting copy */
394#define RONLY 01 /* variable is read-only */
395#define EXPORT 02 /* variable is to be exported */
396#define GETCELL 04 /* name & value space was got with getcell */
Eric Andersenff9eee42001-06-29 04:57:14 +0000397
Eric Andersen8401eea2004-08-04 19:16:54 +0000398static int yyparse(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000399
Eric Andersen12de6cf2004-08-04 19:19:10 +0000400
Eric Andersenff9eee42001-06-29 04:57:14 +0000401/* -------- io.h -------- */
402/* io buffer */
403struct iobuf {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000404 unsigned id; /* buffer id */
405 char buf[512]; /* buffer */
406 char *bufp; /* pointer into buffer */
407 char *ebufp; /* pointer to end of buffer */
Eric Andersenff9eee42001-06-29 04:57:14 +0000408};
409
410/* possible arguments to an IO function */
411struct ioarg {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000412 const char *aword;
Eric Andersen8401eea2004-08-04 19:16:54 +0000413 char **awordlist;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000414 int afile; /* file descriptor */
415 unsigned afid; /* buffer id */
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000416 off_t afpos; /* file position */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000417 struct iobuf *afbuf; /* buffer for this file */
Eric Andersenff9eee42001-06-29 04:57:14 +0000418};
Eric Andersen8401eea2004-08-04 19:16:54 +0000419
Eric Andersenff9eee42001-06-29 04:57:14 +0000420/* an input generator's state */
Eric Andersen8401eea2004-08-04 19:16:54 +0000421struct io {
422 int (*iofn) (struct ioarg *, struct io *);
423 struct ioarg *argp;
424 int peekc;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000425 char prev; /* previous character read by readc() */
426 char nlcount; /* for `'s */
427 char xchar; /* for `'s */
428 char task; /* reason for pushed IO */
Eric Andersenff9eee42001-06-29 04:57:14 +0000429};
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000430/* ->task: */
431#define XOTHER 0 /* none of the below */
432#define XDOLL 1 /* expanding ${} */
433#define XGRAVE 2 /* expanding `'s */
434#define XIO 3 /* file IO */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000435
436
437/*
Eric Andersenff9eee42001-06-29 04:57:14 +0000438 * input generators for IO structure
439 */
Eric Andersen8401eea2004-08-04 19:16:54 +0000440static int nlchar(struct ioarg *ap);
441static int strchar(struct ioarg *ap);
442static int qstrchar(struct ioarg *ap);
443static int filechar(struct ioarg *ap);
444static int herechar(struct ioarg *ap);
445static int linechar(struct ioarg *ap);
446static int gravechar(struct ioarg *ap, struct io *iop);
447static int qgravechar(struct ioarg *ap, struct io *iop);
448static int dolchar(struct ioarg *ap);
449static int wdchar(struct ioarg *ap);
450static void scraphere(void);
451static void freehere(int area);
452static void gethere(void);
453static void markhere(char *s, struct ioword *iop);
454static int herein(char *hname, int xdoll);
455static int run(struct ioarg *argp, int (*f) (struct ioarg *));
Eric Andersenff9eee42001-06-29 04:57:14 +0000456
Eric Andersen12de6cf2004-08-04 19:19:10 +0000457
Eric Andersen8401eea2004-08-04 19:16:54 +0000458static int eofc(void);
459static int readc(void);
460static void unget(int c);
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +0000461static void ioecho(char c);
Eric Andersenff9eee42001-06-29 04:57:14 +0000462
Eric Andersen12de6cf2004-08-04 19:19:10 +0000463
Eric Andersenff9eee42001-06-29 04:57:14 +0000464/*
465 * IO control
466 */
Eric Andersen8401eea2004-08-04 19:16:54 +0000467static void pushio(struct ioarg *argp, int (*f) (struct ioarg *));
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000468#define PUSHIO(what,arg,gen) ((temparg.what = (arg)), pushio(&temparg,(gen)))
Eric Andersen8401eea2004-08-04 19:16:54 +0000469static int remap(int fd);
470static int openpipe(int *pv);
471static void closepipe(int *pv);
472static struct io *setbase(struct io *ip);
Eric Andersenff9eee42001-06-29 04:57:14 +0000473
Eric Andersenff9eee42001-06-29 04:57:14 +0000474/* -------- word.h -------- */
475
Eric Andersen8401eea2004-08-04 19:16:54 +0000476#define NSTART 16 /* default number of words to allow for initially */
Eric Andersenff9eee42001-06-29 04:57:14 +0000477
Eric Andersen8401eea2004-08-04 19:16:54 +0000478struct wdblock {
479 short w_bsize;
480 short w_nword;
Eric Andersenff9eee42001-06-29 04:57:14 +0000481 /* bounds are arbitrary */
Eric Andersen8401eea2004-08-04 19:16:54 +0000482 char *w_words[1];
Eric Andersenff9eee42001-06-29 04:57:14 +0000483};
484
Eric Andersen8401eea2004-08-04 19:16:54 +0000485static struct wdblock *addword(char *wd, struct wdblock *wb);
486static struct wdblock *newword(int nw);
487static char **getwords(struct wdblock *wb);
Eric Andersenff9eee42001-06-29 04:57:14 +0000488
Eric Andersenff9eee42001-06-29 04:57:14 +0000489/* -------- misc stuff -------- */
490
Denis Vlasenko7e497522008-02-12 09:51:03 +0000491static int forkexec(struct op *t, int *pin, int *pout, int no_fork, char **wp);
492static int execute(struct op *t, int *pin, int *pout, int no_fork);
Eric Andersen8401eea2004-08-04 19:16:54 +0000493static int iosetup(struct ioword *iop, int pipein, int pipeout);
Eric Andersen8401eea2004-08-04 19:16:54 +0000494static void brkset(struct brkcon *bc);
495static int dolabel(struct op *t);
496static int dohelp(struct op *t);
497static int dochdir(struct op *t);
498static int doshift(struct op *t);
499static int dologin(struct op *t);
500static int doumask(struct op *t);
501static int doexec(struct op *t);
502static int dodot(struct op *t);
503static int dowait(struct op *t);
504static int doread(struct op *t);
505static int doeval(struct op *t);
506static int dotrap(struct op *t);
507static int getsig(char *s);
508static void setsig(int n, sighandler_t f);
509static int getn(char *as);
510static int dobreak(struct op *t);
511static int docontinue(struct op *t);
512static int brkcontin(char *cp, int val);
513static int doexit(struct op *t);
514static int doexport(struct op *t);
515static int doreadonly(struct op *t);
516static void rdexp(char **wp, void (*f) (struct var *), int key);
517static void badid(char *s);
518static int doset(struct op *t);
519static void varput(char *s, int out);
520static int dotimes(struct op *t);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000521static int expand(const char *cp, struct wdblock **wbp, int f);
Eric Andersen8401eea2004-08-04 19:16:54 +0000522static char *blank(int f);
523static int dollar(int quoted);
524static int grave(int quoted);
525static void globname(char *we, char *pp);
526static char *generate(char *start1, char *end1, char *middle, char *end);
527static int anyspcl(struct wdblock *wb);
528static int xstrcmp(char *p1, char *p2);
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000529static void glob0(char *a0, unsigned a1, int a2,
Eric Andersen8401eea2004-08-04 19:16:54 +0000530 int (*a3) (char *, char *));
Eric Andersen8401eea2004-08-04 19:16:54 +0000531static void readhere(char **name, char *s, int ec);
Eric Andersen8401eea2004-08-04 19:16:54 +0000532static int xxchar(struct ioarg *ap);
Eric Andersenff9eee42001-06-29 04:57:14 +0000533
Eric Andersen8401eea2004-08-04 19:16:54 +0000534struct here {
535 char *h_tag;
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000536 char h_dosub;
Eric Andersen8401eea2004-08-04 19:16:54 +0000537 struct ioword *h_iop;
538 struct here *h_next;
Eric Andersenff9eee42001-06-29 04:57:14 +0000539};
540
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000541static const char *const signame[] = {
Eric Andersenff9eee42001-06-29 04:57:14 +0000542 "Signal 0",
543 "Hangup",
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000544 NULL, /* interrupt */
Eric Andersenff9eee42001-06-29 04:57:14 +0000545 "Quit",
546 "Illegal instruction",
547 "Trace/BPT trap",
548 "Abort",
549 "Bus error",
550 "Floating Point Exception",
551 "Killed",
552 "SIGUSR1",
553 "SIGSEGV",
554 "SIGUSR2",
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000555 NULL, /* broken pipe */
Eric Andersenff9eee42001-06-29 04:57:14 +0000556 "Alarm clock",
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000557 "Terminated"
Eric Andersenff9eee42001-06-29 04:57:14 +0000558};
Eric Andersen8401eea2004-08-04 19:16:54 +0000559
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000560
Denis Vlasenko7e497522008-02-12 09:51:03 +0000561typedef int (*builtin_func_ptr)(struct op *);
562
Eric Andersen1c039232001-07-07 00:05:55 +0000563struct builtincmd {
564 const char *name;
Denis Vlasenko7e497522008-02-12 09:51:03 +0000565 builtin_func_ptr builtinfunc;
Eric Andersenff9eee42001-06-29 04:57:14 +0000566};
Denis Vlasenko7e497522008-02-12 09:51:03 +0000567
Eric Andersen8401eea2004-08-04 19:16:54 +0000568static const struct builtincmd builtincmds[] = {
Denis Vlasenko95cb3262007-04-09 03:06:34 +0000569 { "." , dodot },
570 { ":" , dolabel },
571 { "break" , dobreak },
572 { "cd" , dochdir },
573 { "continue", docontinue },
574 { "eval" , doeval },
575 { "exec" , doexec },
576 { "exit" , doexit },
577 { "export" , doexport },
578 { "help" , dohelp },
579 { "login" , dologin },
580 { "newgrp" , dologin },
581 { "read" , doread },
582 { "readonly", doreadonly },
583 { "set" , doset },
584 { "shift" , doshift },
585 { "times" , dotimes },
586 { "trap" , dotrap },
587 { "umask" , doumask },
588 { "wait" , dowait },
589 { NULL , NULL },
Eric Andersenff9eee42001-06-29 04:57:14 +0000590};
591
"Vladimir N. Oleynik"ac973172005-09-22 14:38:17 +0000592static struct op *scantree(struct op *);
Eric Andersen12de6cf2004-08-04 19:19:10 +0000593static struct op *dowholefile(int, int);
594
Eric Andersen12de6cf2004-08-04 19:19:10 +0000595
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000596/* Globals */
Eric Andersen8401eea2004-08-04 19:16:54 +0000597static char **dolv;
598static int dolc;
599static int exstat;
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000600static smallint gflg; /* (seems to be a parse error indicator) */
601static smallint interactive; /* Is this an interactive shell */
602static smallint execflg;
603static smallint isbreak; /* "break" statement was seen */
604static int multiline; /* '\n' changed to ';' (counter) */
605static struct op *outtree; /* result from parser */
Eric Andersen8401eea2004-08-04 19:16:54 +0000606static xint *failpt;
607static xint *errpt;
608static struct brkcon *brklist;
Eric Andersen8401eea2004-08-04 19:16:54 +0000609static struct wdblock *wdlist;
610static struct wdblock *iolist;
Eric Andersen12de6cf2004-08-04 19:19:10 +0000611
612#ifdef MSHDEBUG
613static struct var *mshdbg_var;
614#endif
Eric Andersen8401eea2004-08-04 19:16:54 +0000615static struct var *vlist; /* dictionary */
616static struct var *homedir; /* home directory */
617static struct var *prompt; /* main prompt */
618static struct var *cprompt; /* continuation prompt */
619static struct var *path; /* search path for commands */
620static struct var *shell; /* shell to interpret command files */
621static struct var *ifs; /* field separators */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000622
Denis Vlasenko95cb3262007-04-09 03:06:34 +0000623static int areanum; /* current allocation area */
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000624static smallint intr; /* interrupt pending (bool) */
625static smallint heedint = 1; /* heed interrupt signals (bool) */
Eric Andersen8401eea2004-08-04 19:16:54 +0000626static int inparse;
Denis Vlasenko95cb3262007-04-09 03:06:34 +0000627static char *null = (char*)""; /* null value for variable */
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +0000628static void (*qflag)(int) = SIG_IGN;
Eric Andersen8401eea2004-08-04 19:16:54 +0000629static int startl;
630static int peeksym;
631static int nlseen;
632static int iounit = IODEFAULT;
633static YYSTYPE yylval;
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000634static char *elinep; /* done in main(): = line + sizeof(line) - 5 */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000635
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000636static struct here *inhere; /* list of hear docs while parsing */
637static struct here *acthere; /* list of active here documents */
638static struct region *areabot; /* bottom of area */
639static struct region *areatop; /* top of area */
640static struct region *areanxt; /* starting point of scan */
Eric Andersen8401eea2004-08-04 19:16:54 +0000641static void *brktop;
642static void *brkaddr;
Eric Andersenff9eee42001-06-29 04:57:14 +0000643
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000644#define AFID_NOBUF (~0)
645#define AFID_ID 0
646
647
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000648/*
649 * parsing & execution environment
650 */
651struct env {
652 char *linep;
653 struct io *iobase;
654 struct io *iop;
655 xint *errpt; /* void * */
656 int iofd;
657 struct env *oenv;
658};
659
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000660
661struct globals {
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000662 struct env global_env;
663 struct ioarg temparg; // = { .afid = AFID_NOBUF }; /* temporary for PUSHIO */
664 unsigned bufid; // = AFID_ID; /* buffer id counter */
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000665 char ourtrap[_NSIG + 1];
666 char *trap[_NSIG + 1];
667 struct iobuf sharedbuf; /* in main(): set to { AFID_NOBUF } */
668 struct iobuf mainbuf; /* in main(): set to { AFID_NOBUF } */
669 struct ioarg ioargstack[NPUSH];
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000670 /*
671 * flags:
672 * -e: quit on error
673 * -k: look for name=value everywhere on command line
674 * -n: no execution
675 * -t: exit after reading and executing one command
676 * -v: echo as read
677 * -x: trace
678 * -u: unset variables net diagnostic
679 */
680 char flags['z' - 'a' + 1];
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000681 char filechar_cmdbuf[BUFSIZ];
682 char line[LINELIM];
683 char child_cmd[LINELIM];
Denis Vlasenkoab801872007-12-02 08:35:37 +0000684
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000685 struct io iostack[NPUSH];
686
Denis Vlasenkoab801872007-12-02 08:35:37 +0000687 char grave__var_name[LINELIM];
688 char grave__alt_value[LINELIM];
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000689};
690
691#define G (*ptr_to_globals)
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000692#define global_env (G.global_env )
693#define temparg (G.temparg )
694#define bufid (G.bufid )
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000695#define ourtrap (G.ourtrap )
696#define trap (G.trap )
697#define sharedbuf (G.sharedbuf )
698#define mainbuf (G.mainbuf )
699#define ioargstack (G.ioargstack )
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000700/* this looks weird, but is OK ... we index FLAG with 'a'...'z' */
701#define FLAG (G.flags - 'a' )
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000702#define filechar_cmdbuf (G.filechar_cmdbuf)
703#define line (G.line )
704#define child_cmd (G.child_cmd )
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000705#define iostack (G.iostack )
Denis Vlasenkoab801872007-12-02 08:35:37 +0000706#define INIT_G() do { \
707 PTR_TO_GLOBALS = xzalloc(sizeof(G)); \
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000708 global_env.linep = line; \
709 global_env.iobase = iostack; \
710 global_env.iop = iostack - 1; \
711 global_env.iofd = FDBASE; \
712 temparg.afid = AFID_NOBUF; \
713 bufid = AFID_ID; \
Denis Vlasenkoab801872007-12-02 08:35:37 +0000714} while (0)
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000715
716
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000717/* in substitution */
718#define INSUB() (global_env.iop->task == XGRAVE || global_env.iop->task == XDOLL)
719
720#define RUN(what, arg, gen) ((temparg.what = (arg)), run(&temparg, (gen)))
721
Eric Andersen12de6cf2004-08-04 19:19:10 +0000722#ifdef MSHDEBUG
723void print_t(struct op *t)
724{
Mike Frysinger02d8fa42006-05-05 20:32:31 +0000725 DBGPRINTF(("T: t=%p, type %s, words=%p, IOword=%p\n", t,
726 T_CMD_NAMES[t->type], t->words, t->ioact));
Eric Andersen12de6cf2004-08-04 19:19:10 +0000727
728 if (t->words) {
729 DBGPRINTF(("T: W1: %s", t->words[0]));
730 }
Eric Andersen12de6cf2004-08-04 19:19:10 +0000731}
732
733void print_tree(struct op *head)
734{
735 if (head == NULL) {
736 DBGPRINTF(("PRINT_TREE: no tree\n"));
737 return;
738 }
739
Mike Frysinger02d8fa42006-05-05 20:32:31 +0000740 DBGPRINTF(("NODE: %p, left %p, right %p\n", head, head->left,
Eric Andersen12de6cf2004-08-04 19:19:10 +0000741 head->right));
742
743 if (head->left)
744 print_tree(head->left);
745
746 if (head->right)
747 print_tree(head->right);
Eric Andersen12de6cf2004-08-04 19:19:10 +0000748}
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000749#endif /* MSHDEBUG */
750
751
752/*
753 * IO functions
754 */
755static void prs(const char *s)
756{
757 if (*s)
758 write(2, s, strlen(s));
759}
760
761static void prn(unsigned u)
762{
763 prs(itoa(u));
764}
765
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000766static void echo(char **wp)
767{
768 int i;
769
770 prs("+");
771 for (i = 0; wp[i]; i++) {
772 if (i)
773 prs(" ");
774 prs(wp[i]);
775 }
776 prs("\n");
777}
778
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000779static void closef(int i)
780{
781 if (i > 2)
782 close(i);
783}
784
785static void closeall(void)
786{
787 int u;
788
789 for (u = NUFILE; u < NOFILE;)
790 close(u++);
791}
Eric Andersen12de6cf2004-08-04 19:19:10 +0000792
Eric Andersenff9eee42001-06-29 04:57:14 +0000793
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000794/* fail but return to process next command */
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000795static void fail(void) ATTRIBUTE_NORETURN;
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000796static void fail(void)
797{
798 longjmp(failpt, 1);
799 /* NOTREACHED */
800}
Eric Andersenff9eee42001-06-29 04:57:14 +0000801
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000802/* abort shell (or fail in subshell) */
803static void leave(void) ATTRIBUTE_NORETURN;
804static void leave(void)
805{
806 DBGPRINTF(("LEAVE: leave called!\n"));
807
808 if (execflg)
809 fail();
810 scraphere();
811 freehere(1);
812 runtrap(0);
813 _exit(exstat);
814 /* NOTREACHED */
815}
816
817static void warn(const char *s)
818{
819 if (*s) {
820 prs(s);
821 exstat = -1;
822 }
823 prs("\n");
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +0000824 if (FLAG['e'])
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000825 leave();
826}
827
828static void err(const char *s)
829{
830 warn(s);
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +0000831 if (FLAG['n'])
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000832 return;
833 if (!interactive)
834 leave();
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000835 if (global_env.errpt)
836 longjmp(global_env.errpt, 1);
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000837 closeall();
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000838 global_env.iop = global_env.iobase = iostack;
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000839}
840
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000841
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000842/* -------- area.c -------- */
843
Eric Andersenff9eee42001-06-29 04:57:14 +0000844/*
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000845 * All memory between (char *)areabot and (char *)(areatop+1) is
846 * exclusively administered by the area management routines.
847 * It is assumed that sbrk() and brk() manipulate the high end.
Eric Andersenff9eee42001-06-29 04:57:14 +0000848 */
849
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000850#define sbrk(X) ({ \
851 void * __q = (void *)-1; \
852 if (brkaddr + (int)(X) < brktop) { \
853 __q = brkaddr; \
854 brkaddr += (int)(X); \
855 } \
856 __q; \
857})
Eric Andersenff9eee42001-06-29 04:57:14 +0000858
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000859static void initarea(void)
Eric Andersenff9eee42001-06-29 04:57:14 +0000860{
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000861 brkaddr = xmalloc(AREASIZE);
862 brktop = brkaddr + AREASIZE;
Eric Andersenff9eee42001-06-29 04:57:14 +0000863
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000864 while ((long) sbrk(0) & ALIGN)
865 sbrk(1);
866 areabot = (struct region *) sbrk(REGSIZE);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +0000867
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000868 areabot->next = areabot;
869 areabot->area = BUSY;
870 areatop = areabot;
871 areanxt = areabot;
Eric Andersenff9eee42001-06-29 04:57:14 +0000872}
873
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000874static char *getcell(unsigned nbytes)
875{
876 int nregio;
877 struct region *p, *q;
878 int i;
879
880 if (nbytes == 0) {
881 puts("getcell(0)");
882 abort();
883 }
884 /* silly and defeats the algorithm */
885 /*
886 * round upwards and add administration area
887 */
888 nregio = (nbytes + (REGSIZE - 1)) / REGSIZE + 1;
889 p = areanxt;
890 for (;;) {
891 if (p->area > areanum) {
892 /*
893 * merge free cells
894 */
895 while ((q = p->next)->area > areanum && q != areanxt)
896 p->next = q->next;
897 /*
898 * exit loop if cell big enough
899 */
900 if (q >= p + nregio)
901 goto found;
902 }
903 p = p->next;
904 if (p == areanxt)
905 break;
906 }
907 i = nregio >= GROWBY ? nregio : GROWBY;
908 p = (struct region *) sbrk(i * REGSIZE);
909 if (p == (struct region *) -1)
910 return NULL;
911 p--;
912 if (p != areatop) {
913 puts("not contig");
914 abort(); /* allocated areas are contiguous */
915 }
916 q = p + i;
917 p->next = q;
918 p->area = FREE;
919 q->next = areabot;
920 q->area = BUSY;
921 areatop = q;
922 found:
923 /*
924 * we found a FREE area big enough, pointed to by 'p', and up to 'q'
925 */
926 areanxt = p + nregio;
927 if (areanxt < q) {
928 /*
929 * split into requested area and rest
930 */
931 if (areanxt + 1 > q) {
932 puts("OOM");
933 abort(); /* insufficient space left for admin */
934 }
935 areanxt->next = q;
936 areanxt->area = FREE;
937 p->next = areanxt;
938 }
939 p->area = areanum;
940 return (char *) (p + 1);
941}
942
943static void freecell(char *cp)
944{
945 struct region *p;
946
947 p = (struct region *) cp;
948 if (p != NULL) {
949 p--;
950 if (p < areanxt)
951 areanxt = p;
952 p->area = FREE;
953 }
954}
955#define DELETE(obj) freecell((char *)obj)
956
957static void freearea(int a)
958{
959 struct region *p, *top;
960
961 top = areatop;
962 for (p = areabot; p != top; p = p->next)
963 if (p->area >= a)
964 p->area = FREE;
965}
966
967static void setarea(char *cp, int a)
968{
969 struct region *p;
970
971 p = (struct region *) cp;
972 if (p != NULL)
973 (p - 1)->area = a;
974}
975
976static int getarea(char *cp)
977{
978 return ((struct region *) cp - 1)->area;
979}
980
981static void garbage(void)
982{
983 struct region *p, *q, *top;
984
985 top = areatop;
986 for (p = areabot; p != top; p = p->next) {
987 if (p->area > areanum) {
988 while ((q = p->next)->area > areanum)
989 p->next = q->next;
990 areanxt = p;
991 }
992 }
993#ifdef SHRINKBY
994 if (areatop >= q + SHRINKBY && q->area > areanum) {
995 brk((char *) (q + 1));
996 q->next = areabot;
997 q->area = BUSY;
998 areatop = q;
999 }
1000#endif
1001}
1002
1003static char *space(int n)
1004{
1005 char *cp;
1006
1007 cp = getcell(n);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001008 if (cp == NULL)
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001009 err("out of string space");
1010 return cp;
1011}
1012
1013static char *strsave(const char *s, int a)
1014{
1015 char *cp;
1016
1017 cp = space(strlen(s) + 1);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001018 if (cp == NULL) {
1019// FIXME: I highly doubt this is good.
1020 return (char*)"";
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001021 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001022 setarea(cp, a);
1023 strcpy(cp, s);
1024 return cp;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001025}
1026
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001027
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001028/* -------- var.c -------- */
1029
1030static int eqname(const char *n1, const char *n2)
1031{
1032 for (; *n1 != '=' && *n1 != '\0'; n1++)
1033 if (*n2++ != *n1)
1034 return 0;
1035 return *n2 == '\0' || *n2 == '=';
1036}
1037
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001038static const char *findeq(const char *cp)
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001039{
1040 while (*cp != '\0' && *cp != '=')
1041 cp++;
1042 return cp;
1043}
1044
1045/*
1046 * Find the given name in the dictionary
1047 * and return its value. If the name was
1048 * not previously there, enter it now and
1049 * return a null value.
1050 */
1051static struct var *lookup(const char *n)
1052{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001053// FIXME: dirty hack
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001054 static struct var dummy;
1055
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001056 struct var *vp;
1057 const char *cp;
1058 char *xp;
1059 int c;
1060
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001061 if (isdigit(*n)) {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001062 dummy.name = (char*)n;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001063 for (c = 0; isdigit(*n) && c < 1000; n++)
1064 c = c * 10 + *n - '0';
1065 dummy.status = RONLY;
1066 dummy.value = (c <= dolc ? dolv[c] : null);
1067 return &dummy;
1068 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001069
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001070 for (vp = vlist; vp; vp = vp->next)
1071 if (eqname(vp->name, n))
1072 return vp;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001073
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001074 cp = findeq(n);
1075 vp = (struct var *) space(sizeof(*vp));
1076 if (vp == 0 || (vp->name = space((int) (cp - n) + 2)) == 0) {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001077 dummy.name = dummy.value = (char*)"";
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001078 return &dummy;
1079 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001080
1081 xp = vp->name;
1082 while ((*xp = *n++) != '\0' && *xp != '=')
1083 xp++;
1084 *xp++ = '=';
1085 *xp = '\0';
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001086 setarea((char *) vp, 0);
1087 setarea((char *) vp->name, 0);
1088 vp->value = null;
1089 vp->next = vlist;
1090 vp->status = GETCELL;
1091 vlist = vp;
1092 return vp;
1093}
1094
1095/*
1096 * if name is not NULL, it must be
1097 * a prefix of the space `val',
1098 * and end with `='.
1099 * this is all so that exporting
1100 * values is reasonably painless.
1101 */
1102static void nameval(struct var *vp, const char *val, const char *name)
1103{
1104 const char *cp;
1105 char *xp;
1106 int fl;
1107
1108 if (vp->status & RONLY) {
1109 xp = vp->name;
1110 while (*xp && *xp != '=')
Denis Vlasenko4daad902007-09-27 10:20:47 +00001111 fputc(*xp++, stderr);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001112 err(" is read-only");
1113 return;
1114 }
1115 fl = 0;
1116 if (name == NULL) {
1117 xp = space(strlen(vp->name) + strlen(val) + 2);
1118 if (xp == NULL)
1119 return;
1120 /* make string: name=value */
1121 setarea(xp, 0);
1122 name = xp;
1123 cp = vp->name;
1124 while ((*xp = *cp++) != '\0' && *xp != '=')
1125 xp++;
1126 *xp++ = '=';
1127 strcpy(xp, val);
1128 val = xp;
1129 fl = GETCELL;
1130 }
1131 if (vp->status & GETCELL)
1132 freecell(vp->name); /* form new string `name=value' */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001133 vp->name = (char*)name;
1134 vp->value = (char*)val;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001135 vp->status |= fl;
1136}
1137
1138/*
1139 * give variable at `vp' the value `val'.
1140 */
1141static void setval(struct var *vp, const char *val)
1142{
1143 nameval(vp, val, NULL);
1144}
1145
1146static void export(struct var *vp)
1147{
1148 vp->status |= EXPORT;
1149}
1150
1151static void ronly(struct var *vp)
1152{
1153 if (isalpha(vp->name[0]) || vp->name[0] == '_') /* not an internal symbol */
1154 vp->status |= RONLY;
1155}
1156
1157static int isassign(const char *s)
1158{
1159 unsigned char c;
1160 DBGPRINTF7(("ISASSIGN: enter, s=%s\n", s));
1161
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001162 c = *s;
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001163 /* no isalpha() - we shouldn't use locale */
1164 /* c | 0x20 - lowercase (Latin) letters */
1165 if (c != '_' && (unsigned)((c|0x20) - 'a') > 25)
1166 /* not letter */
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001167 return 0;
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001168
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001169 while (1) {
1170 c = *++s;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001171 if (c == '=')
1172 return 1;
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001173 if (c == '\0')
1174 return 0;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001175 if (c != '_'
1176 && (unsigned)(c - '0') > 9 /* not number */
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001177 && (unsigned)((c|0x20) - 'a') > 25 /* not letter */
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001178 ) {
1179 return 0;
1180 }
1181 }
1182}
1183
1184static int assign(const char *s, int cf)
1185{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001186 const char *cp;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001187 struct var *vp;
1188
1189 DBGPRINTF7(("ASSIGN: enter, s=%s, cf=%d\n", s, cf));
1190
1191 if (!isalpha(*s) && *s != '_')
1192 return 0;
1193 for (cp = s; *cp != '='; cp++)
1194 if (*cp == '\0' || (!isalnum(*cp) && *cp != '_'))
1195 return 0;
1196 vp = lookup(s);
1197 nameval(vp, ++cp, cf == COPYV ? NULL : s);
1198 if (cf != COPYV)
1199 vp->status &= ~GETCELL;
1200 return 1;
1201}
1202
1203static int checkname(char *cp)
1204{
1205 DBGPRINTF7(("CHECKNAME: enter, cp=%s\n", cp));
1206
1207 if (!isalpha(*cp++) && *(cp - 1) != '_')
1208 return 0;
1209 while (*cp)
1210 if (!isalnum(*cp++) && *(cp - 1) != '_')
1211 return 0;
1212 return 1;
1213}
1214
1215static void putvlist(int f, int out)
1216{
1217 struct var *vp;
1218
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001219 for (vp = vlist; vp; vp = vp->next) {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001220 if (vp->status & f && (isalpha(*vp->name) || *vp->name == '_')) {
1221 if (vp->status & EXPORT)
1222 write(out, "export ", 7);
1223 if (vp->status & RONLY)
1224 write(out, "readonly ", 9);
1225 write(out, vp->name, (int) (findeq(vp->name) - vp->name));
1226 write(out, "\n", 1);
1227 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001228 }
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001229}
1230
1231
1232/*
1233 * trap handling
1234 */
1235static void sig(int i)
1236{
1237 trapset = i;
1238 signal(i, sig);
1239}
1240
1241static void runtrap(int i)
1242{
1243 char *trapstr;
1244
1245 trapstr = trap[i];
1246 if (trapstr == NULL)
1247 return;
1248
1249 if (i == 0)
1250 trap[i] = NULL;
1251
1252 RUN(aword, trapstr, nlchar);
1253}
1254
1255
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001256static void setdash(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001257{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001258 char *cp;
1259 int c;
Eric Andersen8401eea2004-08-04 19:16:54 +00001260 char m['z' - 'a' + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00001261
1262 cp = m;
Eric Andersen8401eea2004-08-04 19:16:54 +00001263 for (c = 'a'; c <= 'z'; c++)
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00001264 if (FLAG[c])
Eric Andersenff9eee42001-06-29 04:57:14 +00001265 *cp++ = c;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001266 *cp = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00001267 setval(lookup("-"), m);
1268}
1269
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001270static int newfile(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00001271{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001272 int f;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001273
1274 DBGPRINTF7(("NEWFILE: opening %s\n", s));
Eric Andersenff9eee42001-06-29 04:57:14 +00001275
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001276 f = 0;
Denis Vlasenko9f739442006-12-16 23:49:13 +00001277 if (NOT_LONE_DASH(s)) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001278 DBGPRINTF(("NEWFILE: s is %s\n", s));
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00001279 f = open(s, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00001280 if (f < 0) {
1281 prs(s);
1282 err(": cannot open");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001283 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001284 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001285 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001286
Eric Andersenff9eee42001-06-29 04:57:14 +00001287 next(remap(f));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001288 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001289}
1290
Eric Andersen12de6cf2004-08-04 19:19:10 +00001291
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001292struct op *scantree(struct op *head)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001293{
1294 struct op *dotnode;
1295
1296 if (head == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001297 return NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001298
1299 if (head->left != NULL) {
1300 dotnode = scantree(head->left);
1301 if (dotnode)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001302 return dotnode;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001303 }
1304
1305 if (head->right != NULL) {
1306 dotnode = scantree(head->right);
1307 if (dotnode)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001308 return dotnode;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001309 }
1310
1311 if (head->words == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001312 return NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001313
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001314 DBGPRINTF5(("SCANTREE: checking node %p\n", head));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001315
Denis Vlasenkocf787cf2007-02-04 17:11:25 +00001316 if ((head->type != TDOT) && LONE_CHAR(head->words[0], '.')) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001317 DBGPRINTF5(("SCANTREE: dot found in node %p\n", head));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001318 return head;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001319 }
1320
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001321 return NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001322}
1323
1324
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001325static void onecommand(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001326{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001327 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00001328 jmp_buf m1;
1329
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001330 DBGPRINTF(("ONECOMMAND: enter, outtree=%p\n", outtree));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001331
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001332 while (global_env.oenv)
Eric Andersenff9eee42001-06-29 04:57:14 +00001333 quitenv();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001334
Eric Andersenff9eee42001-06-29 04:57:14 +00001335 areanum = 1;
1336 freehere(areanum);
1337 freearea(areanum);
1338 garbage();
1339 wdlist = 0;
1340 iolist = 0;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001341 global_env.errpt = 0;
1342 global_env.linep = line;
Eric Andersenff9eee42001-06-29 04:57:14 +00001343 yynerrs = 0;
1344 multiline = 0;
1345 inparse = 1;
1346 intr = 0;
1347 execflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001348
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001349 failpt = m1;
1350 setjmp(failpt); /* Bruce Evans' fix */
1351 failpt = m1;
1352 if (setjmp(failpt) || yyparse() || intr) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001353 DBGPRINTF(("ONECOMMAND: this is not good.\n"));
1354
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001355 while (global_env.oenv)
Eric Andersenff9eee42001-06-29 04:57:14 +00001356 quitenv();
1357 scraphere();
1358 if (!interactive && intr)
1359 leave();
1360 inparse = 0;
1361 intr = 0;
1362 return;
1363 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001364
Eric Andersenff9eee42001-06-29 04:57:14 +00001365 inparse = 0;
1366 brklist = 0;
1367 intr = 0;
1368 execflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001369
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00001370 if (!FLAG['n']) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001371 DBGPRINTF(("ONECOMMAND: calling execute, t=outtree=%p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00001372 outtree));
Denis Vlasenko7e497522008-02-12 09:51:03 +00001373 execute(outtree, NOPIPE, NOPIPE, /* no_fork: */ 0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001374 }
1375
Eric Andersenff9eee42001-06-29 04:57:14 +00001376 if (!interactive && intr) {
1377 execflg = 0;
1378 leave();
1379 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001380
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001381 i = trapset;
1382 if (i != 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001383 trapset = 0;
1384 runtrap(i);
1385 }
1386}
1387
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001388static int newenv(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00001389{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001390 struct env *ep;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001391
1392 DBGPRINTF(("NEWENV: f=%d (indicates quitenv and return)\n", f));
Eric Andersenff9eee42001-06-29 04:57:14 +00001393
1394 if (f) {
1395 quitenv();
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001396 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001397 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001398
Eric Andersenff9eee42001-06-29 04:57:14 +00001399 ep = (struct env *) space(sizeof(*ep));
1400 if (ep == NULL) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001401 while (global_env.oenv)
Eric Andersenff9eee42001-06-29 04:57:14 +00001402 quitenv();
1403 fail();
1404 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001405 *ep = global_env;
1406 global_env.oenv = ep;
1407 global_env.errpt = errpt;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001408
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001409 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001410}
1411
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001412static void quitenv(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001413{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001414 struct env *ep;
1415 int fd;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001416
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001417 DBGPRINTF(("QUITENV: global_env.oenv=%p\n", global_env.oenv));
Eric Andersenff9eee42001-06-29 04:57:14 +00001418
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001419 ep = global_env.oenv;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001420 if (ep != NULL) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001421 fd = global_env.iofd;
1422 global_env = *ep;
Eric Andersenff9eee42001-06-29 04:57:14 +00001423 /* should close `'d files */
1424 DELETE(ep);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001425 while (--fd >= global_env.iofd)
Eric Andersenff9eee42001-06-29 04:57:14 +00001426 close(fd);
1427 }
1428}
1429
1430/*
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001431 * Is character c in s?
Eric Andersenff9eee42001-06-29 04:57:14 +00001432 */
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001433static int any(int c, const char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00001434{
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001435 while (*s)
1436 if (*s++ == c)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001437 return 1;
1438 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001439}
1440
1441/*
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001442 * Is any character from s1 in s2?
Eric Andersenff9eee42001-06-29 04:57:14 +00001443 */
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001444static int anys(const char *s1, const char *s2)
Eric Andersenff9eee42001-06-29 04:57:14 +00001445{
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001446 while (*s1)
1447 if (any(*s1++, s2))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001448 return 1;
1449 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001450}
1451
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001452static char *putn(int n)
Eric Andersenff9eee42001-06-29 04:57:14 +00001453{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001454 return itoa(n);
Eric Andersenff9eee42001-06-29 04:57:14 +00001455}
1456
Eric Andersen8401eea2004-08-04 19:16:54 +00001457static void next(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00001458{
1459 PUSHIO(afile, f, filechar);
1460}
1461
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001462static void onintr(int s) /* ANSI C requires a parameter */
Eric Andersenff9eee42001-06-29 04:57:14 +00001463{
1464 signal(SIGINT, onintr);
1465 intr = 1;
1466 if (interactive) {
1467 if (inparse) {
1468 prs("\n");
1469 fail();
1470 }
Eric Andersen8401eea2004-08-04 19:16:54 +00001471 } else if (heedint) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001472 execflg = 0;
1473 leave();
1474 }
1475}
1476
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001477
Eric Andersenff9eee42001-06-29 04:57:14 +00001478/* -------- gmatch.c -------- */
1479/*
1480 * int gmatch(string, pattern)
1481 * char *string, *pattern;
1482 *
1483 * Match a pattern as in sh(1).
1484 */
1485
1486#define CMASK 0377
1487#define QUOTE 0200
Denis Vlasenko55f30b02007-03-24 22:42:29 +00001488#define QMASK (CMASK & ~QUOTE)
Eric Andersen8401eea2004-08-04 19:16:54 +00001489#define NOT '!' /* might use ^ */
Eric Andersenff9eee42001-06-29 04:57:14 +00001490
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001491static const char *cclass(const char *p, int sub)
1492{
1493 int c, d, not, found;
1494
1495 not = (*p == NOT);
1496 if (not != 0)
1497 p++;
1498 found = not;
1499 do {
1500 if (*p == '\0')
1501 return NULL;
1502 c = *p & CMASK;
1503 if (p[1] == '-' && p[2] != ']') {
1504 d = p[2] & CMASK;
1505 p++;
1506 } else
1507 d = c;
1508 if (c == sub || (c <= sub && sub <= d))
1509 found = !not;
1510 } while (*++p != ']');
1511 return found ? p + 1 : NULL;
1512}
1513
1514static int gmatch(const char *s, const char *p)
Eric Andersenff9eee42001-06-29 04:57:14 +00001515{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001516 int sc, pc;
Eric Andersenff9eee42001-06-29 04:57:14 +00001517
1518 if (s == NULL || p == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001519 return 0;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001520
Eric Andersenff9eee42001-06-29 04:57:14 +00001521 while ((pc = *p++ & CMASK) != '\0') {
1522 sc = *s++ & QMASK;
1523 switch (pc) {
1524 case '[':
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001525 p = cclass(p, sc);
1526 if (p == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001527 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001528 break;
1529
1530 case '?':
1531 if (sc == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001532 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001533 break;
1534
1535 case '*':
1536 s--;
1537 do {
1538 if (*p == '\0' || gmatch(s, p))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001539 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001540 } while (*s++ != '\0');
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001541 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001542
1543 default:
Eric Andersen8401eea2004-08-04 19:16:54 +00001544 if (sc != (pc & ~QUOTE))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001545 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001546 }
1547 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001548 return *s == '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00001549}
1550
Eric Andersenff9eee42001-06-29 04:57:14 +00001551
Eric Andersenff9eee42001-06-29 04:57:14 +00001552/* -------- csyn.c -------- */
1553/*
1554 * shell: syntax (C version)
1555 */
1556
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001557static void yyerror(const char *s) ATTRIBUTE_NORETURN;
1558static void yyerror(const char *s)
1559{
Denis Vlasenko648b44f2008-02-12 06:04:06 +00001560 yynerrs = 1;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001561 if (interactive && global_env.iop <= iostack) {
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001562 multiline = 0;
Denis Vlasenko648b44f2008-02-12 06:04:06 +00001563 while (eofc() == 0 && yylex(0) != '\n')
1564 continue;
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001565 }
1566 err(s);
1567 fail();
1568}
1569
1570static void zzerr(void) ATTRIBUTE_NORETURN;
1571static void zzerr(void)
1572{
1573 yyerror("syntax error");
1574}
1575
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001576int yyparse(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001577{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001578 DBGPRINTF7(("YYPARSE: enter...\n"));
1579
Eric Andersen8401eea2004-08-04 19:16:54 +00001580 startl = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001581 peeksym = 0;
1582 yynerrs = 0;
1583 outtree = c_list();
1584 musthave('\n', 0);
Denis Vlasenko648b44f2008-02-12 06:04:06 +00001585 return yynerrs; /* 0/1 */
Eric Andersenff9eee42001-06-29 04:57:14 +00001586}
1587
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001588static struct op *pipeline(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001589{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001590 struct op *t, *p;
1591 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001592
1593 DBGPRINTF7(("PIPELINE: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001594
1595 t = command(cf);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001596
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001597 DBGPRINTF9(("PIPELINE: t=%p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001598
Eric Andersenff9eee42001-06-29 04:57:14 +00001599 if (t != NULL) {
1600 while ((c = yylex(0)) == '|') {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001601 p = command(CONTIN);
1602 if (p == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001603 DBGPRINTF8(("PIPELINE: error!\n"));
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001604 zzerr();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001605 }
1606
Eric Andersenff9eee42001-06-29 04:57:14 +00001607 if (t->type != TPAREN && t->type != TCOM) {
1608 /* shell statement */
1609 t = block(TPAREN, t, NOBLOCK, NOWORDS);
1610 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001611
Eric Andersenff9eee42001-06-29 04:57:14 +00001612 t = block(TPIPE, t, p, NOWORDS);
1613 }
1614 peeksym = c;
1615 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001616
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001617 DBGPRINTF7(("PIPELINE: returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001618 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001619}
1620
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001621static struct op *andor(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001622{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001623 struct op *t, *p;
1624 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001625
1626 DBGPRINTF7(("ANDOR: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001627
1628 t = pipeline(0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001629
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001630 DBGPRINTF9(("ANDOR: t=%p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001631
Eric Andersenff9eee42001-06-29 04:57:14 +00001632 if (t != NULL) {
1633 while ((c = yylex(0)) == LOGAND || c == LOGOR) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001634 p = pipeline(CONTIN);
1635 if (p == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001636 DBGPRINTF8(("ANDOR: error!\n"));
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001637 zzerr();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001638 }
1639
Eric Andersen8401eea2004-08-04 19:16:54 +00001640 t = block(c == LOGAND ? TAND : TOR, t, p, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001641 } /* WHILE */
1642
Eric Andersenff9eee42001-06-29 04:57:14 +00001643 peeksym = c;
1644 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001645
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001646 DBGPRINTF7(("ANDOR: returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001647 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001648}
1649
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001650static struct op *c_list(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001651{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001652 struct op *t, *p;
1653 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001654
1655 DBGPRINTF7(("C_LIST: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001656
1657 t = andor();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001658
Eric Andersenff9eee42001-06-29 04:57:14 +00001659 if (t != NULL) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001660 peeksym = yylex(0);
1661 if (peeksym == '&')
Eric Andersenff9eee42001-06-29 04:57:14 +00001662 t = block(TASYNC, t, NOBLOCK, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001663
Eric Andersen8401eea2004-08-04 19:16:54 +00001664 while ((c = yylex(0)) == ';' || c == '&'
1665 || (multiline && c == '\n')) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001666
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001667 p = andor();
1668 if (p== NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001669 return t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001670
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001671 peeksym = yylex(0);
1672 if (peeksym == '&')
Eric Andersenff9eee42001-06-29 04:57:14 +00001673 p = block(TASYNC, p, NOBLOCK, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001674
Eric Andersenff9eee42001-06-29 04:57:14 +00001675 t = list(t, p);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001676 } /* WHILE */
1677
Eric Andersenff9eee42001-06-29 04:57:14 +00001678 peeksym = c;
1679 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001680 /* IF */
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001681 DBGPRINTF7(("C_LIST: returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001682 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001683}
1684
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001685static int synio(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001686{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001687 struct ioword *iop;
1688 int i;
1689 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001690
1691 DBGPRINTF7(("SYNIO: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001692
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001693 c = yylex(cf);
1694 if (c != '<' && c != '>') {
Eric Andersenff9eee42001-06-29 04:57:14 +00001695 peeksym = c;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001696 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001697 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001698
Eric Andersenff9eee42001-06-29 04:57:14 +00001699 i = yylval.i;
1700 musthave(WORD, 0);
1701 iop = io(iounit, i, yylval.cp);
1702 iounit = IODEFAULT;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001703
Eric Andersenff9eee42001-06-29 04:57:14 +00001704 if (i & IOHERE)
1705 markhere(yylval.cp, iop);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001706
1707 DBGPRINTF7(("SYNIO: returning 1\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001708 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001709}
1710
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001711static void musthave(int c, int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001712{
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001713 peeksym = yylex(cf);
1714 if (peeksym != c) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001715 DBGPRINTF7(("MUSTHAVE: error!\n"));
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001716 zzerr();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001717 }
1718
Eric Andersenff9eee42001-06-29 04:57:14 +00001719 peeksym = 0;
1720}
1721
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001722static struct op *simple(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001723{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001724 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001725
1726 t = NULL;
1727 for (;;) {
1728 switch (peeksym = yylex(0)) {
1729 case '<':
1730 case '>':
1731 (void) synio(0);
1732 break;
1733
1734 case WORD:
1735 if (t == NULL) {
1736 t = newtp();
1737 t->type = TCOM;
1738 }
1739 peeksym = 0;
1740 word(yylval.cp);
1741 break;
1742
1743 default:
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001744 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001745 }
1746 }
1747}
1748
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001749static struct op *nested(int type, int mark)
Eric Andersenff9eee42001-06-29 04:57:14 +00001750{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001751 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001752
1753 DBGPRINTF3(("NESTED: enter, type=%d, mark=%d\n", type, mark));
Eric Andersenff9eee42001-06-29 04:57:14 +00001754
1755 multiline++;
1756 t = c_list();
1757 musthave(mark, 0);
1758 multiline--;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001759 return block(type, t, NOBLOCK, NOWORDS);
Eric Andersenff9eee42001-06-29 04:57:14 +00001760}
1761
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001762static struct op *command(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001763{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001764 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001765 struct wdblock *iosave;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001766 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001767
1768 DBGPRINTF(("COMMAND: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001769
1770 iosave = iolist;
1771 iolist = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001772
Eric Andersenff9eee42001-06-29 04:57:14 +00001773 if (multiline)
1774 cf |= CONTIN;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001775
Eric Andersenff9eee42001-06-29 04:57:14 +00001776 while (synio(cf))
1777 cf = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001778
1779 c = yylex(cf);
1780
1781 switch (c) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001782 default:
1783 peeksym = c;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001784 t = simple();
1785 if (t == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001786 if (iolist == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001787 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001788 t = newtp();
1789 t->type = TCOM;
1790 }
1791 break;
1792
1793 case '(':
1794 t = nested(TPAREN, ')');
1795 break;
1796
1797 case '{':
1798 t = nested(TBRACE, '}');
1799 break;
1800
1801 case FOR:
1802 t = newtp();
1803 t->type = TFOR;
1804 musthave(WORD, 0);
1805 startl = 1;
1806 t->str = yylval.cp;
1807 multiline++;
1808 t->words = wordlist();
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001809 c = yylex(0);
1810 if (c != '\n' && c != ';')
Eric Andersenff9eee42001-06-29 04:57:14 +00001811 peeksym = c;
1812 t->left = dogroup(0);
1813 multiline--;
1814 break;
1815
1816 case WHILE:
1817 case UNTIL:
1818 multiline++;
1819 t = newtp();
Denis Vlasenko648b44f2008-02-12 06:04:06 +00001820 t->type = (c == WHILE ? TWHILE : TUNTIL);
Eric Andersenff9eee42001-06-29 04:57:14 +00001821 t->left = c_list();
1822 t->right = dogroup(1);
1823 t->words = NULL;
1824 multiline--;
1825 break;
1826
1827 case CASE:
1828 t = newtp();
1829 t->type = TCASE;
1830 musthave(WORD, 0);
1831 t->str = yylval.cp;
1832 startl++;
1833 multiline++;
1834 musthave(IN, CONTIN);
1835 startl++;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001836
Eric Andersenff9eee42001-06-29 04:57:14 +00001837 t->left = caselist();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001838
Eric Andersenff9eee42001-06-29 04:57:14 +00001839 musthave(ESAC, 0);
1840 multiline--;
1841 break;
1842
1843 case IF:
1844 multiline++;
1845 t = newtp();
1846 t->type = TIF;
1847 t->left = c_list();
1848 t->right = thenpart();
1849 musthave(FI, 0);
1850 multiline--;
1851 break;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001852
1853 case DOT:
1854 t = newtp();
1855 t->type = TDOT;
1856
1857 musthave(WORD, 0); /* gets name of file */
1858 DBGPRINTF7(("COMMAND: DOT clause, yylval.cp is %s\n", yylval.cp));
1859
1860 word(yylval.cp); /* add word to wdlist */
1861 word(NOWORD); /* terminate wdlist */
1862 t->words = copyw(); /* dup wdlist */
1863 break;
1864
Eric Andersenff9eee42001-06-29 04:57:14 +00001865 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001866
Eric Andersen8401eea2004-08-04 19:16:54 +00001867 while (synio(0));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001868
Eric Andersenff9eee42001-06-29 04:57:14 +00001869 t = namelist(t);
1870 iolist = iosave;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001871
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001872 DBGPRINTF(("COMMAND: returning %p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001873
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001874 return t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001875}
1876
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001877static struct op *dowholefile(int type, int mark)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001878{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001879 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001880
1881 DBGPRINTF(("DOWHOLEFILE: enter, type=%d, mark=%d\n", type, mark));
1882
1883 multiline++;
1884 t = c_list();
1885 multiline--;
1886 t = block(type, t, NOBLOCK, NOWORDS);
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001887 DBGPRINTF(("DOWHOLEFILE: return t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001888 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001889}
1890
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001891static struct op *dogroup(int onlydone)
Eric Andersenff9eee42001-06-29 04:57:14 +00001892{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001893 int c;
1894 struct op *mylist;
Eric Andersenff9eee42001-06-29 04:57:14 +00001895
1896 c = yylex(CONTIN);
1897 if (c == DONE && onlydone)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001898 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001899 if (c != DO)
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001900 zzerr();
Eric Andersenff9eee42001-06-29 04:57:14 +00001901 mylist = c_list();
1902 musthave(DONE, 0);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001903 return mylist;
Eric Andersenff9eee42001-06-29 04:57:14 +00001904}
1905
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001906static struct op *thenpart(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001907{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001908 int c;
1909 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001910
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001911 c = yylex(0);
1912 if (c != THEN) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001913 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001914 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001915 }
1916 t = newtp();
Denis Vlasenko648b44f2008-02-12 06:04:06 +00001917 /*t->type = 0; - newtp() did this */
Eric Andersenff9eee42001-06-29 04:57:14 +00001918 t->left = c_list();
1919 if (t->left == NULL)
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001920 zzerr();
Eric Andersenff9eee42001-06-29 04:57:14 +00001921 t->right = elsepart();
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001922 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001923}
1924
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001925static struct op *elsepart(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001926{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001927 int c;
1928 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001929
1930 switch (c = yylex(0)) {
1931 case ELSE:
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001932 t = c_list();
1933 if (t == NULL)
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001934 zzerr();
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001935 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001936
1937 case ELIF:
1938 t = newtp();
1939 t->type = TELIF;
1940 t->left = c_list();
1941 t->right = thenpart();
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001942 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001943
1944 default:
1945 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001946 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001947 }
1948}
1949
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001950static struct op *caselist(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001951{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001952 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001953
1954 t = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001955 while ((peeksym = yylex(CONTIN)) != ESAC) {
1956 DBGPRINTF(("CASELIST, doing yylex, peeksym=%d\n", peeksym));
Eric Andersenff9eee42001-06-29 04:57:14 +00001957 t = list(t, casepart());
Eric Andersen12de6cf2004-08-04 19:19:10 +00001958 }
1959
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001960 DBGPRINTF(("CASELIST, returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001961 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001962}
1963
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001964static struct op *casepart(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001965{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001966 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001967
1968 DBGPRINTF7(("CASEPART: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001969
1970 t = newtp();
1971 t->type = TPAT;
1972 t->words = pattern();
1973 musthave(')', 0);
1974 t->left = c_list();
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001975 peeksym = yylex(CONTIN);
1976 if (peeksym != ESAC)
Eric Andersenff9eee42001-06-29 04:57:14 +00001977 musthave(BREAK, CONTIN);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001978
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001979 DBGPRINTF7(("CASEPART: made newtp(TPAT, t=%p)\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001980
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001981 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001982}
1983
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001984static char **pattern(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001985{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001986 int c, cf;
Eric Andersenff9eee42001-06-29 04:57:14 +00001987
1988 cf = CONTIN;
1989 do {
1990 musthave(WORD, cf);
1991 word(yylval.cp);
1992 cf = 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001993 c = yylex(0);
1994 } while (c == '|');
Eric Andersenff9eee42001-06-29 04:57:14 +00001995 peeksym = c;
1996 word(NOWORD);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001997
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001998 return copyw();
Eric Andersenff9eee42001-06-29 04:57:14 +00001999}
2000
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002001static char **wordlist(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002002{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002003 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002004
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002005 c = yylex(0);
2006 if (c != IN) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002007 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002008 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00002009 }
2010 startl = 0;
2011 while ((c = yylex(0)) == WORD)
2012 word(yylval.cp);
2013 word(NOWORD);
2014 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002015 return copyw();
Eric Andersenff9eee42001-06-29 04:57:14 +00002016}
2017
2018/*
2019 * supporting functions
2020 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002021static struct op *list(struct op *t1, struct op *t2)
Eric Andersenff9eee42001-06-29 04:57:14 +00002022{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002023 DBGPRINTF7(("LIST: enter, t1=%p, t2=%p\n", t1, t2));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002024
Eric Andersenff9eee42001-06-29 04:57:14 +00002025 if (t1 == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002026 return t2;
Eric Andersenff9eee42001-06-29 04:57:14 +00002027 if (t2 == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002028 return t1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002029
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002030 return block(TLIST, t1, t2, NOWORDS);
Eric Andersenff9eee42001-06-29 04:57:14 +00002031}
2032
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002033static struct op *block(int type, struct op *t1, struct op *t2, char **wp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002034{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002035 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002036
2037 DBGPRINTF7(("BLOCK: enter, type=%d (%s)\n", type, T_CMD_NAMES[type]));
Eric Andersenff9eee42001-06-29 04:57:14 +00002038
2039 t = newtp();
2040 t->type = type;
2041 t->left = t1;
2042 t->right = t2;
2043 t->words = wp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002044
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002045 DBGPRINTF7(("BLOCK: inserted %p between %p and %p\n", t, t1, t2));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002046
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002047 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002048}
2049
Eric Andersen12de6cf2004-08-04 19:19:10 +00002050/* See if given string is a shell multiline (FOR, IF, etc) */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002051static int rlookup(char *n)
Eric Andersenff9eee42001-06-29 04:57:14 +00002052{
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002053 struct res {
2054 char r_name[6];
2055 int16_t r_val;
2056 };
2057 static const struct res restab[] = {
2058 { "for" , FOR },
2059 { "case" , CASE },
2060 { "esac" , ESAC },
2061 { "while", WHILE },
2062 { "do" , DO },
2063 { "done" , DONE },
2064 { "if" , IF },
2065 { "in" , IN },
2066 { "then" , THEN },
2067 { "else" , ELSE },
2068 { "elif" , ELIF },
2069 { "until", UNTIL },
2070 { "fi" , FI },
2071 { ";;" , BREAK },
2072 { "||" , LOGOR },
2073 { "&&" , LOGAND },
2074 { "{" , '{' },
2075 { "}" , '}' },
2076 { "." , DOT },
2077 { },
2078 };
2079
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002080 const struct res *rp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002081
2082 DBGPRINTF7(("RLOOKUP: enter, n is %s\n", n));
Eric Andersenff9eee42001-06-29 04:57:14 +00002083
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002084 for (rp = restab; rp->r_name[0]; rp++)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002085 if (strcmp(rp->r_name, n) == 0) {
2086 DBGPRINTF7(("RLOOKUP: match, returning %d\n", rp->r_val));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002087 return rp->r_val; /* Return numeric code for shell multiline */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002088 }
2089
2090 DBGPRINTF7(("RLOOKUP: NO match, returning 0\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002091 return 0; /* Not a shell multiline */
Eric Andersenff9eee42001-06-29 04:57:14 +00002092}
2093
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002094static struct op *newtp(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002095{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002096 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002097
Eric Andersen8401eea2004-08-04 19:16:54 +00002098 t = (struct op *) tree(sizeof(*t));
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002099 memset(t, 0, sizeof(*t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002100
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002101 DBGPRINTF3(("NEWTP: allocated %p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002102
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002103 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002104}
2105
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002106static struct op *namelist(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00002107{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002108 DBGPRINTF7(("NAMELIST: enter, t=%p, type %s, iolist=%p\n", t,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002109 T_CMD_NAMES[t->type], iolist));
2110
Eric Andersenff9eee42001-06-29 04:57:14 +00002111 if (iolist) {
Eric Andersen8401eea2004-08-04 19:16:54 +00002112 iolist = addword((char *) NULL, iolist);
Eric Andersenff9eee42001-06-29 04:57:14 +00002113 t->ioact = copyio();
2114 } else
2115 t->ioact = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002116
Eric Andersenff9eee42001-06-29 04:57:14 +00002117 if (t->type != TCOM) {
2118 if (t->type != TPAREN && t->ioact != NULL) {
2119 t = block(TPAREN, t, NOBLOCK, NOWORDS);
2120 t->ioact = t->left->ioact;
2121 t->left->ioact = NULL;
2122 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002123 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002124 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002125
Eric Andersenff9eee42001-06-29 04:57:14 +00002126 word(NOWORD);
2127 t->words = copyw();
Eric Andersen12de6cf2004-08-04 19:19:10 +00002128
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002129 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002130}
2131
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002132static char **copyw(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002133{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002134 char **wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00002135
2136 wd = getwords(wdlist);
2137 wdlist = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002138 return wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00002139}
2140
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002141static void word(char *cp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002142{
2143 wdlist = addword(cp, wdlist);
2144}
2145
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002146static struct ioword **copyio(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002147{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002148 struct ioword **iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002149
2150 iop = (struct ioword **) getwords(iolist);
2151 iolist = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002152 return iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002153}
2154
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002155static struct ioword *io(int u, int f, char *cp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002156{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002157 struct ioword *iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002158
2159 iop = (struct ioword *) tree(sizeof(*iop));
2160 iop->io_unit = u;
2161 iop->io_flag = f;
2162 iop->io_name = cp;
Eric Andersen8401eea2004-08-04 19:16:54 +00002163 iolist = addword((char *) iop, iolist);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002164 return iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002165}
2166
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002167static int yylex(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00002168{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002169 int c, c1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002170 int atstart;
2171
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002172 c = peeksym;
2173 if (c > 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002174 peeksym = 0;
2175 if (c == '\n')
2176 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002177 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002178 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002179
Eric Andersenff9eee42001-06-29 04:57:14 +00002180 nlseen = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002181 atstart = startl;
2182 startl = 0;
2183 yylval.i = 0;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002184 global_env.linep = line;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002185
2186/* MALAMO */
2187 line[LINELIM - 1] = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00002188
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002189 loop:
Eric Andersen12de6cf2004-08-04 19:19:10 +00002190 while ((c = my_getc(0)) == ' ' || c == '\t') /* Skip whitespace */
2191 ;
2192
Eric Andersenff9eee42001-06-29 04:57:14 +00002193 switch (c) {
2194 default:
2195 if (any(c, "0123456789")) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002196 c1 = my_getc(0);
2197 unget(c1);
Eric Andersenff9eee42001-06-29 04:57:14 +00002198 if (c1 == '<' || c1 == '>') {
2199 iounit = c - '0';
2200 goto loop;
2201 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002202 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002203 c = c1;
2204 }
2205 break;
2206
Eric Andersen12de6cf2004-08-04 19:19:10 +00002207 case '#': /* Comment, skip to next newline or End-of-string */
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002208 while ((c = my_getc(0)) != '\0' && c != '\n');
Eric Andersenff9eee42001-06-29 04:57:14 +00002209 unget(c);
2210 goto loop;
2211
2212 case 0:
Eric Andersen12de6cf2004-08-04 19:19:10 +00002213 DBGPRINTF5(("YYLEX: return 0, c=%d\n", c));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002214 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002215
2216 case '$':
Eric Andersen12de6cf2004-08-04 19:19:10 +00002217 DBGPRINTF9(("YYLEX: found $\n"));
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002218 *global_env.linep++ = c;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002219 c = my_getc(0);
2220 if (c == '{') {
2221 c = collect(c, '}');
2222 if (c != '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002223 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002224 goto pack;
2225 }
2226 break;
2227
2228 case '`':
2229 case '\'':
2230 case '"':
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002231 c = collect(c, c);
2232 if (c != '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002233 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002234 goto pack;
2235
2236 case '|':
2237 case '&':
2238 case ';':
Eric Andersenff9eee42001-06-29 04:57:14 +00002239 startl = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002240 /* If more chars process them, else return NULL char */
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002241 c1 = dual(c);
2242 if (c1 != '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002243 return c1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002244 return c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002245
Eric Andersenff9eee42001-06-29 04:57:14 +00002246 case '^':
2247 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002248 return '|';
Eric Andersenff9eee42001-06-29 04:57:14 +00002249 case '>':
2250 case '<':
2251 diag(c);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002252 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002253
2254 case '\n':
2255 nlseen++;
2256 gethere();
2257 startl = 1;
2258 if (multiline || cf & CONTIN) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002259 if (interactive && global_env.iop <= iostack) {
Denis Vlasenko38f63192007-01-22 09:03:07 +00002260#if ENABLE_FEATURE_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00002261 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00002262#else
Eric Andersen8401eea2004-08-04 19:16:54 +00002263 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00002264#endif
2265 }
2266 if (cf & CONTIN)
2267 goto loop;
2268 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002269 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002270
2271 case '(':
2272 case ')':
2273 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002274 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002275 }
2276
2277 unget(c);
2278
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002279 pack:
2280 while ((c = my_getc(0)) != '\0' && !any(c, "`$ '\"\t;&<>()|^\n")) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002281 if (global_env.linep >= elinep)
Eric Andersenff9eee42001-06-29 04:57:14 +00002282 err("word too long");
2283 else
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002284 *global_env.linep++ = c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002285 };
2286
Eric Andersenff9eee42001-06-29 04:57:14 +00002287 unget(c);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002288
Eric Andersen8401eea2004-08-04 19:16:54 +00002289 if (any(c, "\"'`$"))
Eric Andersenff9eee42001-06-29 04:57:14 +00002290 goto loop;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002291
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002292 *global_env.linep++ = '\0';
Eric Andersen12de6cf2004-08-04 19:19:10 +00002293
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002294 if (atstart) {
2295 c = rlookup(line);
2296 if (c != 0) {
2297 startl = 1;
2298 return c;
2299 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002300 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002301
Eric Andersenff9eee42001-06-29 04:57:14 +00002302 yylval.cp = strsave(line, areanum);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002303 return WORD;
Eric Andersenff9eee42001-06-29 04:57:14 +00002304}
2305
Eric Andersen12de6cf2004-08-04 19:19:10 +00002306
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002307static int collect(int c, int c1)
Eric Andersenff9eee42001-06-29 04:57:14 +00002308{
2309 char s[2];
2310
Eric Andersen12de6cf2004-08-04 19:19:10 +00002311 DBGPRINTF8(("COLLECT: enter, c=%d, c1=%d\n", c, c1));
2312
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002313 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002314 while ((c = my_getc(c1)) != c1) {
2315 if (c == 0) {
2316 unget(c);
2317 s[0] = c1;
2318 s[1] = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00002319 prs("no closing ");
2320 yyerror(s);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002321 return YYERRCODE;
Eric Andersenff9eee42001-06-29 04:57:14 +00002322 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002323 if (interactive && c == '\n' && global_env.iop <= iostack) {
Denis Vlasenko38f63192007-01-22 09:03:07 +00002324#if ENABLE_FEATURE_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00002325 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00002326#else
Eric Andersen8401eea2004-08-04 19:16:54 +00002327 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00002328#endif
2329 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002330 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002331 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002332
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002333 *global_env.linep++ = c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002334
2335 DBGPRINTF8(("COLLECT: return 0, line is %s\n", line));
2336
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002337 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002338}
2339
Eric Andersen12de6cf2004-08-04 19:19:10 +00002340/* "multiline commands" helper func */
2341/* see if next 2 chars form a shell multiline */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002342static int dual(int c)
Eric Andersenff9eee42001-06-29 04:57:14 +00002343{
2344 char s[3];
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002345 char *cp = s;
Eric Andersenff9eee42001-06-29 04:57:14 +00002346
Eric Andersen12de6cf2004-08-04 19:19:10 +00002347 DBGPRINTF8(("DUAL: enter, c=%d\n", c));
2348
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002349 *cp++ = c; /* c is the given "peek" char */
2350 *cp++ = my_getc(0); /* get next char of input */
2351 *cp = '\0'; /* add EOS marker */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002352
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002353 c = rlookup(s); /* see if 2 chars form a shell multiline */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002354 if (c == 0)
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002355 unget(*--cp); /* String is not a shell multiline, put peek char back */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002356
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002357 return c; /* String is multiline, return numeric multiline (restab) code */
Eric Andersenff9eee42001-06-29 04:57:14 +00002358}
2359
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002360static void diag(int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00002361{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002362 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002363
2364 DBGPRINTF8(("DIAG: enter, ec=%d\n", ec));
Eric Andersenff9eee42001-06-29 04:57:14 +00002365
2366 c = my_getc(0);
2367 if (c == '>' || c == '<') {
2368 if (c != ec)
2369 zzerr();
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002370 yylval.i = (ec == '>' ? IOWRITE | IOCAT : IOHERE);
Eric Andersenff9eee42001-06-29 04:57:14 +00002371 c = my_getc(0);
2372 } else
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002373 yylval.i = (ec == '>' ? IOWRITE : IOREAD);
Eric Andersenff9eee42001-06-29 04:57:14 +00002374 if (c != '&' || yylval.i == IOHERE)
2375 unget(c);
2376 else
2377 yylval.i |= IODUP;
2378}
2379
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002380static char *tree(unsigned size)
Eric Andersenff9eee42001-06-29 04:57:14 +00002381{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002382 char *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002383
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002384 t = getcell(size);
2385 if (t == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002386 DBGPRINTF2(("TREE: getcell(%d) failed!\n", size));
Eric Andersenff9eee42001-06-29 04:57:14 +00002387 prs("command line too complicated\n");
2388 fail();
2389 /* NOTREACHED */
2390 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002391 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002392}
2393
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002394
Eric Andersenff9eee42001-06-29 04:57:14 +00002395/* VARARGS1 */
2396/* ARGSUSED */
2397
2398/* -------- exec.c -------- */
2399
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002400static struct op **find1case(struct op *t, const char *w)
2401{
2402 struct op *t1;
2403 struct op **tp;
2404 char **wp;
2405 char *cp;
2406
2407 if (t == NULL) {
2408 DBGPRINTF3(("FIND1CASE: enter, t==NULL, returning.\n"));
2409 return NULL;
2410 }
2411
2412 DBGPRINTF3(("FIND1CASE: enter, t->type=%d (%s)\n", t->type,
2413 T_CMD_NAMES[t->type]));
2414
2415 if (t->type == TLIST) {
2416 tp = find1case(t->left, w);
2417 if (tp != NULL) {
2418 DBGPRINTF3(("FIND1CASE: found one to the left, returning tp=%p\n", tp));
2419 return tp;
2420 }
2421 t1 = t->right; /* TPAT */
2422 } else
2423 t1 = t;
2424
2425 for (wp = t1->words; *wp;) {
2426 cp = evalstr(*wp++, DOSUB);
2427 if (cp && gmatch(w, cp)) {
2428 DBGPRINTF3(("FIND1CASE: returning &t1->left= %p.\n",
2429 &t1->left));
2430 return &t1->left;
2431 }
2432 }
2433
2434 DBGPRINTF(("FIND1CASE: returning NULL\n"));
2435 return NULL;
2436}
2437
2438static struct op *findcase(struct op *t, const char *w)
2439{
2440 struct op **tp;
2441
2442 tp = find1case(t, w);
2443 return tp != NULL ? *tp : NULL;
2444}
2445
Eric Andersenff9eee42001-06-29 04:57:14 +00002446/*
2447 * execute tree
2448 */
2449
Denis Vlasenko7e497522008-02-12 09:51:03 +00002450static int execute(struct op *t, int *pin, int *pout, int no_fork)
Eric Andersenff9eee42001-06-29 04:57:14 +00002451{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002452 struct op *t1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002453 volatile int i, rv, a;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002454 const char *cp;
2455 char **wp, **wp2;
Eric Andersenff9eee42001-06-29 04:57:14 +00002456 struct var *vp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002457 struct op *outtree_save;
Eric Andersenff9eee42001-06-29 04:57:14 +00002458 struct brkcon bc;
2459
2460#if __GNUC__
2461 /* Avoid longjmp clobbering */
2462 (void) &wp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002463#endif
Eric Andersenff9eee42001-06-29 04:57:14 +00002464
Eric Andersen12de6cf2004-08-04 19:19:10 +00002465 if (t == NULL) {
2466 DBGPRINTF4(("EXECUTE: enter, t==null, returning.\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002467 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002468 }
2469
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002470 DBGPRINTF(("EXECUTE: t=%p, t->type=%d (%s), t->words is %s\n", t,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002471 t->type, T_CMD_NAMES[t->type],
2472 ((t->words == NULL) ? "NULL" : t->words[0])));
2473
Eric Andersenff9eee42001-06-29 04:57:14 +00002474 rv = 0;
2475 a = areanum++;
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002476 wp2 = t->words;
2477 wp = (wp2 != NULL)
Eric Andersen8401eea2004-08-04 19:16:54 +00002478 ? eval(wp2, t->type == TCOM ? DOALL : DOALL & ~DOKEY)
2479 : NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00002480
Eric Andersen8401eea2004-08-04 19:16:54 +00002481 switch (t->type) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002482 case TDOT:
2483 DBGPRINTF3(("EXECUTE: TDOT\n"));
2484
2485 outtree_save = outtree;
2486
2487 newfile(evalstr(t->words[0], DOALL));
2488
2489 t->left = dowholefile(TLIST, 0);
2490 t->right = NULL;
2491
2492 outtree = outtree_save;
2493
2494 if (t->left)
Denis Vlasenko7e497522008-02-12 09:51:03 +00002495 rv = execute(t->left, pin, pout, /* no_fork: */ 0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002496 if (t->right)
Denis Vlasenko7e497522008-02-12 09:51:03 +00002497 rv = execute(t->right, pin, pout, /* no_fork: */ 0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002498 break;
2499
Eric Andersenff9eee42001-06-29 04:57:14 +00002500 case TPAREN:
Denis Vlasenko7e497522008-02-12 09:51:03 +00002501 rv = execute(t->left, pin, pout, /* no_fork: */ 0);
Eric Andersen737f5fb2003-03-14 16:05:59 +00002502 break;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002503
Eric Andersenff9eee42001-06-29 04:57:14 +00002504 case TCOM:
Denis Vlasenko7e497522008-02-12 09:51:03 +00002505 rv = forkexec(t, pin, pout, no_fork, wp);
Eric Andersenff9eee42001-06-29 04:57:14 +00002506 break;
2507
2508 case TPIPE:
2509 {
Eric Andersen8401eea2004-08-04 19:16:54 +00002510 int pv[2];
2511
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002512 rv = openpipe(pv);
2513 if (rv < 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00002514 break;
2515 pv[0] = remap(pv[0]);
2516 pv[1] = remap(pv[1]);
Denis Vlasenko7e497522008-02-12 09:51:03 +00002517 (void) execute(t->left, pin, pv, /* no_fork: */ 0);
2518 rv = execute(t->right, pv, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002519 }
2520 break;
2521
2522 case TLIST:
Denis Vlasenko7e497522008-02-12 09:51:03 +00002523 (void) execute(t->left, pin, pout, /* no_fork: */ 0);
2524 rv = execute(t->right, pin, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002525 break;
2526
2527 case TASYNC:
Eric Andersen8401eea2004-08-04 19:16:54 +00002528 {
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002529 smallint hinteractive = interactive;
Eric Andersenff9eee42001-06-29 04:57:14 +00002530
Eric Andersen12de6cf2004-08-04 19:19:10 +00002531 DBGPRINTF7(("EXECUTE: TASYNC clause, calling vfork()...\n"));
2532
Eric Andersen8401eea2004-08-04 19:16:54 +00002533 i = vfork();
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002534 if (i == 0) { /* child */
Eric Andersen8401eea2004-08-04 19:16:54 +00002535 signal(SIGINT, SIG_IGN);
2536 signal(SIGQUIT, SIG_IGN);
2537 if (interactive)
2538 signal(SIGTERM, SIG_DFL);
2539 interactive = 0;
2540 if (pin == NULL) {
2541 close(0);
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00002542 xopen(bb_dev_null, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00002543 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002544 _exit(execute(t->left, pin, pout, /* no_fork: */ 1));
Eric Andersenff9eee42001-06-29 04:57:14 +00002545 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002546 interactive = hinteractive;
2547 if (i != -1) {
2548 setval(lookup("!"), putn(i));
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002549 closepipe(pin);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002550 if (interactive) {
2551 prs(putn(i));
2552 prs("\n");
2553 }
2554 } else
2555 rv = -1;
2556 setstatus(rv);
Eric Andersenff9eee42001-06-29 04:57:14 +00002557 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002558 break;
2559
2560 case TOR:
2561 case TAND:
Denis Vlasenko7e497522008-02-12 09:51:03 +00002562 rv = execute(t->left, pin, pout, /* no_fork: */ 0);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002563 t1 = t->right;
2564 if (t1 != NULL && (rv == 0) == (t->type == TAND))
Denis Vlasenko7e497522008-02-12 09:51:03 +00002565 rv = execute(t1, pin, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002566 break;
2567
2568 case TFOR:
2569 if (wp == NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00002570 wp = dolv + 1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002571 i = dolc;
2572 if (i < 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00002573 i = 0;
2574 } else {
2575 i = -1;
Eric Andersen8401eea2004-08-04 19:16:54 +00002576 while (*wp++ != NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00002577 }
2578 vp = lookup(t->str);
2579 while (setjmp(bc.brkpt))
2580 if (isbreak)
2581 goto broken;
2582 brkset(&bc);
2583 for (t1 = t->left; i-- && *wp != NULL;) {
2584 setval(vp, *wp++);
Denis Vlasenko7e497522008-02-12 09:51:03 +00002585 rv = execute(t1, pin, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002586 }
2587 brklist = brklist->nextlev;
2588 break;
2589
2590 case TWHILE:
2591 case TUNTIL:
2592 while (setjmp(bc.brkpt))
2593 if (isbreak)
2594 goto broken;
2595 brkset(&bc);
2596 t1 = t->left;
Denis Vlasenko7e497522008-02-12 09:51:03 +00002597 while ((execute(t1, pin, pout, /* no_fork: */ 0) == 0) == (t->type == TWHILE))
2598 rv = execute(t->right, pin, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002599 brklist = brklist->nextlev;
2600 break;
2601
2602 case TIF:
2603 case TELIF:
Eric Andersen8401eea2004-08-04 19:16:54 +00002604 if (t->right != NULL) {
Denis Vlasenko7e497522008-02-12 09:51:03 +00002605 rv = !execute(t->left, pin, pout, /* no_fork: */ 0) ?
2606 execute(t->right->left, pin, pout, /* no_fork: */ 0) :
2607 execute(t->right->right, pin, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002608 }
2609 break;
2610
2611 case TCASE:
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002612 cp = evalstr(t->str, DOSUB | DOTRIM);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002613 if (cp == NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00002614 cp = "";
Eric Andersen12de6cf2004-08-04 19:19:10 +00002615
2616 DBGPRINTF7(("EXECUTE: TCASE, t->str is %s, cp is %s\n",
2617 ((t->str == NULL) ? "NULL" : t->str),
2618 ((cp == NULL) ? "NULL" : cp)));
2619
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002620 t1 = findcase(t->left, cp);
2621 if (t1 != NULL) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002622 DBGPRINTF7(("EXECUTE: TCASE, calling execute(t=%p, t1=%p)...\n", t, t1));
Denis Vlasenko7e497522008-02-12 09:51:03 +00002623 rv = execute(t1, pin, pout, /* no_fork: */ 0);
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002624 DBGPRINTF7(("EXECUTE: TCASE, back from execute(t=%p, t1=%p)...\n", t, t1));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002625 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002626 break;
2627
2628 case TBRACE:
2629/*
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002630 iopp = t->ioact;
2631 if (i)
Eric Andersenff9eee42001-06-29 04:57:14 +00002632 while (*iopp)
2633 if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) {
2634 rv = -1;
2635 break;
2636 }
2637*/
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002638 if (rv >= 0) {
2639 t1 = t->left;
2640 if (t1) {
Denis Vlasenko7e497522008-02-12 09:51:03 +00002641 rv = execute(t1, pin, pout, /* no_fork: */ 0);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002642 }
2643 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002644 break;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002645
2646 };
Eric Andersenff9eee42001-06-29 04:57:14 +00002647
Denis Vlasenkoe4712752007-04-14 15:08:41 +00002648 broken:
Eric Andersenff9eee42001-06-29 04:57:14 +00002649 t->words = wp2;
2650 isbreak = 0;
2651 freehere(areanum);
2652 freearea(areanum);
2653 areanum = a;
2654 if (interactive && intr) {
2655 closeall();
2656 fail();
2657 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002658
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002659 i = trapset;
2660 if (i != 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002661 trapset = 0;
2662 runtrap(i);
2663 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002664
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002665 DBGPRINTF(("EXECUTE: returning from t=%p, rv=%d\n", t, rv));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002666 return rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00002667}
2668
Denis Vlasenkoe4712752007-04-14 15:08:41 +00002669static builtin_func_ptr inbuilt(const char *s)
2670{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002671 const struct builtincmd *bp;
2672
Denis Vlasenko95cb3262007-04-09 03:06:34 +00002673 for (bp = builtincmds; bp->name; bp++)
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002674 if (strcmp(bp->name, s) == 0)
2675 return bp->builtinfunc;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002676 return NULL;
2677}
2678
Denis Vlasenko7e497522008-02-12 09:51:03 +00002679static int forkexec(struct op *t, int *pin, int *pout, int no_fork, char **wp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002680{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002681 pid_t newpid;
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002682 int i;
2683 builtin_func_ptr bltin = NULL;
Denis Vlasenko7e497522008-02-12 09:51:03 +00002684 const char *bltin_name = NULL;
2685 const char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00002686 struct ioword **iopp;
2687 int resetsig;
2688 char **owp;
Denis Vlasenko7e497522008-02-12 09:51:03 +00002689 int forked;
Eric Andersenff9eee42001-06-29 04:57:14 +00002690
2691 int *hpin = pin;
2692 int *hpout = pout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002693 char *hwp;
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002694 smallint hinteractive;
2695 smallint hintr;
2696 smallint hexecflg;
Eric Andersen8401eea2004-08-04 19:16:54 +00002697 struct brkcon *hbrklist;
Eric Andersenff9eee42001-06-29 04:57:14 +00002698
2699#if __GNUC__
2700 /* Avoid longjmp clobbering */
2701 (void) &pin;
2702 (void) &pout;
2703 (void) &wp;
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002704 (void) &bltin;
Eric Andersenff9eee42001-06-29 04:57:14 +00002705 (void) &cp;
2706 (void) &resetsig;
2707 (void) &owp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002708#endif
Eric Andersenff9eee42001-06-29 04:57:14 +00002709
Denis Vlasenko7e497522008-02-12 09:51:03 +00002710 DBGPRINTF(("FORKEXEC: t=%p, pin %p, pout %p, no_fork %d\n", t, pin,
2711 pout, no_fork));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002712 DBGPRINTF7(("FORKEXEC: t->words is %s\n",
Denis Vlasenko7e497522008-02-12 09:51:03 +00002713 ((t->words == NULL) ? "NULL" : t->words[0])));
Eric Andersenff9eee42001-06-29 04:57:14 +00002714 owp = wp;
2715 resetsig = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002716 if (t->type == TCOM) {
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00002717 while (*wp++ != NULL)
2718 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00002719 cp = *wp;
2720
2721 /* strip all initial assignments */
Denis Vlasenko7e497522008-02-12 09:51:03 +00002722 /* FIXME: not correct wrt PATH=yyy command etc */
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00002723 if (FLAG['x']) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002724 DBGPRINTF9(("FORKEXEC: echo'ing, cp=%p, wp=%p, owp=%p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00002725 cp, wp, owp));
Eric Andersen8401eea2004-08-04 19:16:54 +00002726 echo(cp ? wp : owp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002727 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002728
Denis Vlasenko7e497522008-02-12 09:51:03 +00002729 if (cp == NULL) {
2730 if (t->ioact == NULL) {
2731 while ((cp = *owp++) != NULL && assign(cp, COPYV))
2732 continue;
2733 DBGPRINTF(("FORKEXEC: returning setstatus(0)\n"));
2734 return setstatus(0);
2735 }
2736 } else { /* cp != NULL */
2737 bltin_name = cp;
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002738 bltin = inbuilt(cp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002739 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002740 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002741
Denis Vlasenko7e497522008-02-12 09:51:03 +00002742 forked = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002743 t->words = wp;
Denis Vlasenko7e497522008-02-12 09:51:03 +00002744 DBGPRINTF(("FORKEXEC: bltin %p, no_fork %d, owp %p\n", bltin,
2745 no_fork, owp));
2746 /* Don't fork if it is a lone builtin (not in pipe)
2747 * OR we are told to _not_ fork */
2748 if ((!bltin || pin || pout) /* not lone bltin AND */
2749 && !no_fork /* not told to avoid fork */
2750 ) {
2751 /* Save values in case child alters them after vfork */
Eric Andersenff9eee42001-06-29 04:57:14 +00002752 hpin = pin;
2753 hpout = pout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002754 hwp = *wp;
2755 hinteractive = interactive;
2756 hintr = intr;
2757 hbrklist = brklist;
2758 hexecflg = execflg;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002759
Eric Andersen12de6cf2004-08-04 19:19:10 +00002760 DBGPRINTF3(("FORKEXEC: calling vfork()...\n"));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002761 newpid = vfork();
Eric Andersen12de6cf2004-08-04 19:19:10 +00002762 if (newpid == -1) {
Denis Vlasenko89f0b342006-11-18 22:04:09 +00002763 DBGPRINTF(("FORKEXEC: ERROR, cannot vfork()!\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002764 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002765 }
2766
Denis Vlasenko489f93e2007-02-01 01:43:16 +00002767 if (newpid > 0) { /* Parent */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002768 /* Restore values */
Eric Andersenff9eee42001-06-29 04:57:14 +00002769 pin = hpin;
2770 pout = hpout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002771 *wp = hwp;
2772 interactive = hinteractive;
2773 intr = hintr;
2774 brklist = hbrklist;
2775 execflg = hexecflg;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002776
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002777 closepipe(pin);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002778 return (pout == NULL ? setstatus(waitfor(newpid, 0)) : 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002779 }
2780
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002781 /* Child */
Denis Vlasenko7e497522008-02-12 09:51:03 +00002782 DBGPRINTF(("FORKEXEC: child process, bltin=%p (%s)\n", bltin, bltin_name));
Eric Andersenff9eee42001-06-29 04:57:14 +00002783 if (interactive) {
2784 signal(SIGINT, SIG_IGN);
2785 signal(SIGQUIT, SIG_IGN);
2786 resetsig = 1;
2787 }
2788 interactive = 0;
2789 intr = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002790 forked = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002791 brklist = 0;
2792 execflg = 0;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002793 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002794
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002795 if (owp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002796 while ((cp = *owp++) != NULL && assign(cp, COPYV))
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002797 if (!bltin)
Eric Andersenff9eee42001-06-29 04:57:14 +00002798 export(lookup(cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002799
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002800 if (pin) {
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00002801 xmove_fd(pin[0], 0);
Denis Vlasenko847fa772008-01-28 22:45:43 +00002802 if (pin[1] != 0)
2803 close(pin[1]);
Eric Andersenff9eee42001-06-29 04:57:14 +00002804 }
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002805 if (pout) {
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00002806 xmove_fd(pout[1], 1);
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002807 if (pout[0] > 1)
Denis Vlasenko847fa772008-01-28 22:45:43 +00002808 close(pout[0]);
Eric Andersenff9eee42001-06-29 04:57:14 +00002809 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002810
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002811 iopp = t->ioact;
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002812 if (iopp) {
2813 if (bltin && bltin != doexec) {
Denis Vlasenko7e497522008-02-12 09:51:03 +00002814 prs(bltin_name);
Eric Andersenff9eee42001-06-29 04:57:14 +00002815 err(": cannot redirect shell command");
Eric Andersen12de6cf2004-08-04 19:19:10 +00002816 if (forked)
2817 _exit(-1);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002818 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002819 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002820 while (*iopp) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002821 if (iosetup(*iopp++, pin != NULL, pout != NULL)) {
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002822 /* system-detected error */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002823 if (forked)
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002824 _exit(-1);
2825 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002826 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002827 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002828 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002829
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002830 if (bltin) {
Denis Vlasenko7e497522008-02-12 09:51:03 +00002831 if (forked || pin || pout) {
2832 /* Builtin in pipe: disallowed */
2833 /* TODO: allow "exec"? */
2834 prs(bltin_name);
2835 err(": cannot run builtin as part of pipe");
2836 if (forked)
2837 _exit(-1);
2838 return -1;
2839 }
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002840 i = setstatus(bltin(t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002841 if (forked)
2842 _exit(i);
2843 DBGPRINTF(("FORKEXEC: returning i=%d\n", i));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002844 return i;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002845 }
2846
Eric Andersenff9eee42001-06-29 04:57:14 +00002847 /* should use FIOCEXCL */
Eric Andersen8401eea2004-08-04 19:16:54 +00002848 for (i = FDBASE; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00002849 close(i);
2850 if (resetsig) {
2851 signal(SIGINT, SIG_DFL);
2852 signal(SIGQUIT, SIG_DFL);
2853 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002854
Eric Andersen12de6cf2004-08-04 19:19:10 +00002855 if (t->type == TPAREN)
Denis Vlasenko7e497522008-02-12 09:51:03 +00002856 _exit(execute(t->left, NOPIPE, NOPIPE, /* no_fork: */ 1));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002857 if (wp[0] == NULL)
2858 _exit(0);
2859
Eric Andersenfd7a4c82004-09-02 23:13:10 +00002860 cp = rexecve(wp[0], wp, makenv(0, NULL));
Eric Andersen8401eea2004-08-04 19:16:54 +00002861 prs(wp[0]);
2862 prs(": ");
Eric Andersen12de6cf2004-08-04 19:19:10 +00002863 err(cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00002864 if (!execflg)
2865 trap[0] = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002866
Denis Vlasenko7e497522008-02-12 09:51:03 +00002867 DBGPRINTF(("FORKEXEC: calling leave(), pid=%d\n", getpid()));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002868
Eric Andersenff9eee42001-06-29 04:57:14 +00002869 leave();
2870 /* NOTREACHED */
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002871 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002872}
2873
2874/*
2875 * 0< 1> are ignored as required
2876 * within pipelines.
2877 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002878static int iosetup(struct ioword *iop, int pipein, int pipeout)
Eric Andersenff9eee42001-06-29 04:57:14 +00002879{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002880 int u = -1;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002881 char *cp = NULL;
2882 const char *msg;
Eric Andersenff9eee42001-06-29 04:57:14 +00002883
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002884 DBGPRINTF(("IOSETUP: iop %p, pipein %i, pipeout %i\n", iop,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002885 pipein, pipeout));
2886
Eric Andersenff9eee42001-06-29 04:57:14 +00002887 if (iop->io_unit == IODEFAULT) /* take default */
Eric Andersen8401eea2004-08-04 19:16:54 +00002888 iop->io_unit = iop->io_flag & (IOREAD | IOHERE) ? 0 : 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002889
Eric Andersenff9eee42001-06-29 04:57:14 +00002890 if (pipein && iop->io_unit == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002891 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002892
Eric Andersenff9eee42001-06-29 04:57:14 +00002893 if (pipeout && iop->io_unit == 1)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002894 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002895
Eric Andersen8401eea2004-08-04 19:16:54 +00002896 msg = iop->io_flag & (IOREAD | IOHERE) ? "open" : "create";
Eric Andersenff9eee42001-06-29 04:57:14 +00002897 if ((iop->io_flag & IOHERE) == 0) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002898 cp = iop->io_name; /* huh?? */
2899 cp = evalstr(cp, DOSUB | DOTRIM);
2900 if (cp == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002901 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002902 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002903
Eric Andersenff9eee42001-06-29 04:57:14 +00002904 if (iop->io_flag & IODUP) {
2905 if (cp[1] || (!isdigit(*cp) && *cp != '-')) {
2906 prs(cp);
2907 err(": illegal >& argument");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002908 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002909 }
2910 if (*cp == '-')
2911 iop->io_flag = IOCLOSE;
Eric Andersen8401eea2004-08-04 19:16:54 +00002912 iop->io_flag &= ~(IOREAD | IOWRITE);
Eric Andersenff9eee42001-06-29 04:57:14 +00002913 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002914
Eric Andersenff9eee42001-06-29 04:57:14 +00002915 switch (iop->io_flag) {
2916 case IOREAD:
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00002917 u = open(cp, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00002918 break;
2919
2920 case IOHERE:
Eric Andersen8401eea2004-08-04 19:16:54 +00002921 case IOHERE | IOXHERE:
2922 u = herein(iop->io_name, iop->io_flag & IOXHERE);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002923 cp = (char*)"here file";
Eric Andersenff9eee42001-06-29 04:57:14 +00002924 break;
2925
Eric Andersen8401eea2004-08-04 19:16:54 +00002926 case IOWRITE | IOCAT:
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00002927 u = open(cp, O_WRONLY);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002928 if (u >= 0) {
Denis Vlasenkoea620772006-10-14 02:23:43 +00002929 lseek(u, (long) 0, SEEK_END);
Eric Andersenff9eee42001-06-29 04:57:14 +00002930 break;
2931 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002932 /* fall through to creation if >>file doesn't exist */
2933
Eric Andersenff9eee42001-06-29 04:57:14 +00002934 case IOWRITE:
2935 u = creat(cp, 0666);
2936 break;
2937
2938 case IODUP:
Eric Andersen8401eea2004-08-04 19:16:54 +00002939 u = dup2(*cp - '0', iop->io_unit);
Eric Andersenff9eee42001-06-29 04:57:14 +00002940 break;
2941
2942 case IOCLOSE:
2943 close(iop->io_unit);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002944 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002945 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002946
Eric Andersenff9eee42001-06-29 04:57:14 +00002947 if (u < 0) {
2948 prs(cp);
2949 prs(": cannot ");
2950 warn(msg);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002951 return 1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002952 }
2953 if (u != iop->io_unit) {
2954 dup2(u, iop->io_unit);
2955 close(u);
Eric Andersenff9eee42001-06-29 04:57:14 +00002956 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002957 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002958}
2959
Eric Andersenff9eee42001-06-29 04:57:14 +00002960/*
2961 * Enter a new loop level (marked for break/continue).
2962 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002963static void brkset(struct brkcon *bc)
Eric Andersenff9eee42001-06-29 04:57:14 +00002964{
2965 bc->nextlev = brklist;
2966 brklist = bc;
2967}
2968
2969/*
2970 * Wait for the last process created.
2971 * Print a message for each process found
2972 * that was killed by a signal.
2973 * Ignore interrupt signals while waiting
2974 * unless `canintr' is true.
2975 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002976static int waitfor(int lastpid, int canintr)
Eric Andersenff9eee42001-06-29 04:57:14 +00002977{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002978 int pid, rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00002979 int s;
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002980 smallint oheedint = heedint;
Eric Andersenff9eee42001-06-29 04:57:14 +00002981
2982 heedint = 0;
2983 rv = 0;
2984 do {
2985 pid = wait(&s);
2986 if (pid == -1) {
2987 if (errno != EINTR || canintr)
2988 break;
2989 } else {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002990 rv = WAITSIG(s);
2991 if (rv != 0) {
Denis Vlasenko80b8b392007-06-25 10:55:35 +00002992 if (rv < ARRAY_SIZE(signame)) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002993 if (signame[rv] != NULL) {
2994 if (pid != lastpid) {
2995 prn(pid);
2996 prs(": ");
2997 }
2998 prs(signame[rv]);
2999 }
3000 } else {
3001 if (pid != lastpid) {
3002 prn(pid);
3003 prs(": ");
3004 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003005 prs("Signal ");
3006 prn(rv);
3007 prs(" ");
Eric Andersenff9eee42001-06-29 04:57:14 +00003008 }
3009 if (WAITCORE(s))
3010 prs(" - core dumped");
Denis Vlasenko80b8b392007-06-25 10:55:35 +00003011 if (rv >= ARRAY_SIZE(signame) || signame[rv])
Eric Andersenff9eee42001-06-29 04:57:14 +00003012 prs("\n");
3013 rv = -1;
3014 } else
3015 rv = WAITVAL(s);
3016 }
3017 } while (pid != lastpid);
3018 heedint = oheedint;
3019 if (intr) {
3020 if (interactive) {
3021 if (canintr)
3022 intr = 0;
3023 } else {
Eric Andersen8401eea2004-08-04 19:16:54 +00003024 if (exstat == 0)
3025 exstat = rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003026 onintr(0);
3027 }
3028 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003029 return rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003030}
3031
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003032static int setstatus(int s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003033{
3034 exstat = s;
3035 setval(lookup("?"), putn(s));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003036 return s;
Eric Andersenff9eee42001-06-29 04:57:14 +00003037}
3038
3039/*
3040 * PATH-searching interface to execve.
3041 * If getenv("PATH") were kept up-to-date,
3042 * execvp might be used.
3043 */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003044static const char *rexecve(char *c, char **v, char **envp)
Eric Andersenff9eee42001-06-29 04:57:14 +00003045{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003046 int i;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003047 const char *sp;
3048 char *tp;
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00003049 int asis = 0;
Eric Andersen1c039232001-07-07 00:05:55 +00003050 char *name = c;
Eric Andersen8401eea2004-08-04 19:16:54 +00003051
Denis Vlasenko80d14be2007-04-10 23:03:30 +00003052 if (ENABLE_FEATURE_SH_STANDALONE) {
Denis Vlasenko1aa7e472007-11-28 06:49:03 +00003053 if (find_applet_by_name(name) >= 0) {
Rob Landleya299efb2006-08-10 21:46:43 +00003054 /* We have to exec here since we vforked. Running
Denis Vlasenkoe4f2d062007-04-11 17:03:19 +00003055 * run_applet_and_exit() won't work and bad things
Rob Landleya299efb2006-08-10 21:46:43 +00003056 * will happen. */
Denis Vlasenkobdbbb7e2007-06-08 15:02:55 +00003057 execve(bb_busybox_exec_path, v, envp);
Rob Landleya299efb2006-08-10 21:46:43 +00003058 }
Eric Andersen1c039232001-07-07 00:05:55 +00003059 }
Eric Andersen1c039232001-07-07 00:05:55 +00003060
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003061 DBGPRINTF(("REXECVE: c=%p, v=%p, envp=%p\n", c, v, envp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003062
Eric Andersen8401eea2004-08-04 19:16:54 +00003063 sp = any('/', c) ? "" : path->value;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003064 asis = (*sp == '\0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003065 while (asis || *sp != '\0') {
3066 asis = 0;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003067 tp = global_env.linep;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003068 for (; *sp != '\0'; tp++) {
3069 *tp = *sp++;
3070 if (*tp == ':') {
3071 asis = (*sp == '\0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003072 break;
3073 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003074 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003075 if (tp != global_env.linep)
Eric Andersenff9eee42001-06-29 04:57:14 +00003076 *tp++ = '/';
Eric Andersen8401eea2004-08-04 19:16:54 +00003077 for (i = 0; (*tp++ = c[i++]) != '\0';);
Eric Andersen1c039232001-07-07 00:05:55 +00003078
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003079 DBGPRINTF3(("REXECVE: global_env.linep is %s\n", global_env.linep));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003080
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003081 execve(global_env.linep, v, envp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003082
Eric Andersenff9eee42001-06-29 04:57:14 +00003083 switch (errno) {
3084 case ENOEXEC:
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003085 *v = global_env.linep;
Eric Andersenff9eee42001-06-29 04:57:14 +00003086 tp = *--v;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003087 *v = global_env.linep;
Glenn L McGrathdc4e75e2003-09-02 02:36:18 +00003088 execve(DEFAULT_SHELL, v, envp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003089 *v = tp;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003090 return "no Shell";
Eric Andersenff9eee42001-06-29 04:57:14 +00003091
3092 case ENOMEM:
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003093 return (char *) bb_msg_memory_exhausted;
Eric Andersenff9eee42001-06-29 04:57:14 +00003094
3095 case E2BIG:
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003096 return "argument list too long";
Eric Andersenff9eee42001-06-29 04:57:14 +00003097 }
3098 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003099 return errno == ENOENT ? "not found" : "cannot execute";
Eric Andersenff9eee42001-06-29 04:57:14 +00003100}
3101
3102/*
3103 * Run the command produced by generator `f'
3104 * applied to stream `arg'.
3105 */
Eric Andersen8401eea2004-08-04 19:16:54 +00003106static int run(struct ioarg *argp, int (*f) (struct ioarg *))
Eric Andersenff9eee42001-06-29 04:57:14 +00003107{
3108 struct op *otree;
3109 struct wdblock *swdlist;
3110 struct wdblock *siolist;
3111 jmp_buf ev, rt;
3112 xint *ofail;
3113 int rv;
3114
3115#if __GNUC__
3116 /* Avoid longjmp clobbering */
3117 (void) &rv;
3118#endif
3119
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003120 DBGPRINTF(("RUN: enter, areanum %d, outtree %p, failpt %p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00003121 areanum, outtree, failpt));
3122
Eric Andersenff9eee42001-06-29 04:57:14 +00003123 areanum++;
3124 swdlist = wdlist;
3125 siolist = iolist;
3126 otree = outtree;
3127 ofail = failpt;
3128 rv = -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003129
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003130 errpt = ev;
3131 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003132 wdlist = 0;
3133 iolist = 0;
3134 pushio(argp, f);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003135 global_env.iobase = global_env.iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00003136 yynerrs = 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003137 failpt = rt;
3138 if (setjmp(failpt) == 0 && yyparse() == 0)
Denis Vlasenko7e497522008-02-12 09:51:03 +00003139 rv = execute(outtree, NOPIPE, NOPIPE, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003140 quitenv();
Eric Andersen12de6cf2004-08-04 19:19:10 +00003141 } else {
3142 DBGPRINTF(("RUN: error from newenv()!\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00003143 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00003144
Eric Andersenff9eee42001-06-29 04:57:14 +00003145 wdlist = swdlist;
3146 iolist = siolist;
3147 failpt = ofail;
3148 outtree = otree;
3149 freearea(areanum--);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003150
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003151 return rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003152}
3153
3154/* -------- do.c -------- */
3155
3156/*
3157 * built-in commands: doX
3158 */
3159
Eric Andersen8401eea2004-08-04 19:16:54 +00003160static int dohelp(struct op *t)
Eric Andersen1c039232001-07-07 00:05:55 +00003161{
3162 int col;
3163 const struct builtincmd *x;
3164
Denis Vlasenko0ee39992006-12-24 15:23:28 +00003165 puts("\nBuilt-in commands:\n"
3166 "-------------------");
Eric Andersen1c039232001-07-07 00:05:55 +00003167
Denis Vlasenko95cb3262007-04-09 03:06:34 +00003168 col = 0;
3169 x = builtincmds;
3170 while (x->name) {
3171 col += printf("%c%s", ((col == 0) ? '\t' : ' '), x->name);
Eric Andersen1c039232001-07-07 00:05:55 +00003172 if (col > 60) {
Denis Vlasenko4daad902007-09-27 10:20:47 +00003173 bb_putchar('\n');
Eric Andersen1c039232001-07-07 00:05:55 +00003174 col = 0;
3175 }
Denis Vlasenko95cb3262007-04-09 03:06:34 +00003176 x++;
Eric Andersen1c039232001-07-07 00:05:55 +00003177 }
Denis Vlasenko80d14be2007-04-10 23:03:30 +00003178#if ENABLE_FEATURE_SH_STANDALONE
Eric Andersen1c039232001-07-07 00:05:55 +00003179 {
Denis Vlasenko1aa7e472007-11-28 06:49:03 +00003180 const char *applet = applet_names;
Eric Andersen1c039232001-07-07 00:05:55 +00003181
Denis Vlasenko1aa7e472007-11-28 06:49:03 +00003182 while (*applet) {
3183 col += printf("%c%s", ((col == 0) ? '\t' : ' '), applet);
Eric Andersen1c039232001-07-07 00:05:55 +00003184 if (col > 60) {
Denis Vlasenko4daad902007-09-27 10:20:47 +00003185 bb_putchar('\n');
Eric Andersen1c039232001-07-07 00:05:55 +00003186 col = 0;
3187 }
Denis Vlasenko1aa7e472007-11-28 06:49:03 +00003188 applet += strlen(applet) + 1;
Eric Andersen1c039232001-07-07 00:05:55 +00003189 }
3190 }
3191#endif
Denis Vlasenko0ee39992006-12-24 15:23:28 +00003192 puts("\n");
Eric Andersen1c039232001-07-07 00:05:55 +00003193 return EXIT_SUCCESS;
3194}
3195
Eric Andersen8401eea2004-08-04 19:16:54 +00003196static int dolabel(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003197{
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003198 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003199}
3200
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003201static int dochdir(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003202{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003203 const char *cp, *er;
Eric Andersenff9eee42001-06-29 04:57:14 +00003204
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003205 cp = t->words[1];
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003206 if (cp == NULL) {
3207 cp = homedir->value;
Denis Vlasenkod244c5e2007-02-09 17:30:14 +00003208 if (cp != NULL)
3209 goto do_cd;
3210 er = ": no home directory";
3211 } else {
3212 do_cd:
3213 if (chdir(cp) >= 0)
3214 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003215 er = ": bad directory";
Denis Vlasenkod244c5e2007-02-09 17:30:14 +00003216 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003217 prs(cp != NULL ? cp : "cd");
Eric Andersenff9eee42001-06-29 04:57:14 +00003218 err(er);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003219 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003220}
3221
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003222static int doshift(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003223{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003224 int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003225
Eric Andersen8401eea2004-08-04 19:16:54 +00003226 n = t->words[1] ? getn(t->words[1]) : 1;
3227 if (dolc < n) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003228 err("nothing to shift");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003229 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003230 }
3231 dolv[n] = dolv[0];
3232 dolv += n;
3233 dolc -= n;
3234 setval(lookup("#"), putn(dolc));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003235 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003236}
3237
3238/*
3239 * execute login and newgrp directly
3240 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003241static int dologin(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003242{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003243 const char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003244
3245 if (interactive) {
3246 signal(SIGINT, SIG_DFL);
3247 signal(SIGQUIT, SIG_DFL);
3248 }
Eric Andersenfd7a4c82004-09-02 23:13:10 +00003249 cp = rexecve(t->words[0], t->words, makenv(0, NULL));
Eric Andersen8401eea2004-08-04 19:16:54 +00003250 prs(t->words[0]);
3251 prs(": ");
3252 err(cp);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003253 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003254}
3255
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003256static int doumask(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003257{
Denis Vlasenko7e497522008-02-12 09:51:03 +00003258 int i;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003259 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003260
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003261 cp = t->words[1];
3262 if (cp == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003263 i = umask(0);
3264 umask(i);
Denis Vlasenko7e497522008-02-12 09:51:03 +00003265 printf("%04o\n", i);
Eric Andersenff9eee42001-06-29 04:57:14 +00003266 } else {
Denis Vlasenko7e497522008-02-12 09:51:03 +00003267 i = bb_strtou(cp, NULL, 8);
3268 if (errno) {
3269 err("umask: bad octal number");
3270 return 1;
3271 }
3272 umask(i);
Eric Andersenff9eee42001-06-29 04:57:14 +00003273 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003274 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003275}
3276
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003277static int doexec(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003278{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003279 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00003280 jmp_buf ex;
3281 xint *ofail;
3282
3283 t->ioact = NULL;
Denis Vlasenko7e497522008-02-12 09:51:03 +00003284 for (i = 0; (t->words[i] = t->words[i + 1]) != NULL; i++)
3285 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00003286 if (i == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003287 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003288 execflg = 1;
3289 ofail = failpt;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003290 failpt = ex;
3291 if (setjmp(failpt) == 0)
Denis Vlasenko7e497522008-02-12 09:51:03 +00003292 execute(t, NOPIPE, NOPIPE, /* no_fork: */ 1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003293 failpt = ofail;
3294 execflg = 0;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003295 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003296}
3297
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003298static int dodot(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003299{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003300 int i;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003301 const char *sp;
3302 char *tp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003303 char *cp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003304 int maltmp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003305
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003306 DBGPRINTF(("DODOT: enter, t=%p, tleft %p, tright %p, global_env.linep is %s\n",
3307 t, t->left, t->right, ((global_env.linep == NULL) ? "NULL" : global_env.linep)));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003308
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003309 cp = t->words[1];
3310 if (cp == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00003311 DBGPRINTF(("DODOT: bad args, ret 0\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003312 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003313 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003314 DBGPRINTF(("DODOT: cp is %s\n", cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003315
Eric Andersen8401eea2004-08-04 19:16:54 +00003316 sp = any('/', cp) ? ":" : path->value;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003317
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003318 DBGPRINTF(("DODOT: sp is %s, global_env.linep is %s\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00003319 ((sp == NULL) ? "NULL" : sp),
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003320 ((global_env.linep == NULL) ? "NULL" : global_env.linep)));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003321
Eric Andersenff9eee42001-06-29 04:57:14 +00003322 while (*sp) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003323 tp = global_env.linep;
Eric Andersenff9eee42001-06-29 04:57:14 +00003324 while (*sp && (*tp = *sp++) != ':')
3325 tp++;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003326 if (tp != global_env.linep)
Eric Andersenff9eee42001-06-29 04:57:14 +00003327 *tp++ = '/';
Eric Andersen12de6cf2004-08-04 19:19:10 +00003328
Eric Andersen8401eea2004-08-04 19:16:54 +00003329 for (i = 0; (*tp++ = cp[i++]) != '\0';);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003330
3331 /* Original code */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003332 i = open(global_env.linep, O_RDONLY);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003333 if (i >= 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003334 exstat = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003335 maltmp = remap(i);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003336 DBGPRINTF(("DODOT: remap=%d, exstat=%d, global_env.iofd %d, i %d, global_env.linep is %s\n",
3337 maltmp, exstat, global_env.iofd, i, global_env.linep));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003338
3339 next(maltmp); /* Basically a PUSHIO */
3340
3341 DBGPRINTF(("DODOT: returning exstat=%d\n", exstat));
3342
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003343 return exstat;
Eric Andersenff9eee42001-06-29 04:57:14 +00003344 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003345 } /* while */
Eric Andersen12de6cf2004-08-04 19:19:10 +00003346
Eric Andersenff9eee42001-06-29 04:57:14 +00003347 prs(cp);
3348 err(": not found");
Eric Andersen12de6cf2004-08-04 19:19:10 +00003349
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003350 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003351}
3352
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003353static int dowait(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003354{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003355 int i;
3356 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003357
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003358 cp = t->words[1];
3359 if (cp != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003360 i = getn(cp);
3361 if (i == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003362 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003363 } else
3364 i = -1;
3365 setstatus(waitfor(i, 1));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003366 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003367}
3368
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003369static int doread(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003370{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003371 char *cp, **wp;
3372 int nb = 0;
3373 int nl = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003374
3375 if (t->words[1] == NULL) {
3376 err("Usage: read name ...");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003377 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003378 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003379 for (wp = t->words + 1; *wp; wp++) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003380 for (cp = global_env.linep; !nl && cp < elinep - 1; cp++) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003381 nb = read(0, cp, sizeof(*cp));
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003382 if (nb != sizeof(*cp))
Eric Andersenff9eee42001-06-29 04:57:14 +00003383 break;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003384 nl = (*cp == '\n');
3385 if (nl || (wp[1] && any(*cp, ifs->value)))
3386 break;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003387 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003388 *cp = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00003389 if (nb <= 0)
3390 break;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003391 setval(lookup(*wp), global_env.linep);
Eric Andersenff9eee42001-06-29 04:57:14 +00003392 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003393 return nb <= 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003394}
3395
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003396static int doeval(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003397{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003398 return RUN(awordlist, t->words + 1, wdchar);
Eric Andersenff9eee42001-06-29 04:57:14 +00003399}
3400
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003401static int dotrap(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003402{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003403 int n, i;
3404 int resetsig;
Eric Andersenff9eee42001-06-29 04:57:14 +00003405
3406 if (t->words[1] == NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00003407 for (i = 0; i <= _NSIG; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00003408 if (trap[i]) {
3409 prn(i);
3410 prs(": ");
3411 prs(trap[i]);
3412 prs("\n");
3413 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003414 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003415 }
3416 resetsig = isdigit(*t->words[1]);
3417 for (i = resetsig ? 1 : 2; t->words[i] != NULL; ++i) {
3418 n = getsig(t->words[i]);
3419 freecell(trap[n]);
3420 trap[n] = 0;
3421 if (!resetsig) {
3422 if (*t->words[1] != '\0') {
3423 trap[n] = strsave(t->words[1], 0);
3424 setsig(n, sig);
3425 } else
3426 setsig(n, SIG_IGN);
3427 } else {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00003428 if (interactive) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003429 if (n == SIGINT)
3430 setsig(n, onintr);
3431 else
Eric Andersen8401eea2004-08-04 19:16:54 +00003432 setsig(n, n == SIGQUIT ? SIG_IGN : SIG_DFL);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00003433 } else
Eric Andersenff9eee42001-06-29 04:57:14 +00003434 setsig(n, SIG_DFL);
3435 }
3436 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003437 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003438}
3439
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003440static int getsig(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003441{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003442 int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003443
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003444 n = getn(s);
3445 if (n < 0 || n > _NSIG) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003446 err("trap: bad signal number");
3447 n = 0;
3448 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003449 return n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003450}
3451
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003452static void setsig(int n, sighandler_t f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003453{
3454 if (n == 0)
3455 return;
3456 if (signal(n, SIG_IGN) != SIG_IGN || ourtrap[n]) {
3457 ourtrap[n] = 1;
3458 signal(n, f);
3459 }
3460}
3461
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003462static int getn(char *as)
Eric Andersenff9eee42001-06-29 04:57:14 +00003463{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003464 char *s;
3465 int n, m;
Eric Andersenff9eee42001-06-29 04:57:14 +00003466
3467 s = as;
3468 m = 1;
3469 if (*s == '-') {
3470 m = -1;
3471 s++;
3472 }
3473 for (n = 0; isdigit(*s); s++)
Eric Andersen8401eea2004-08-04 19:16:54 +00003474 n = (n * 10) + (*s - '0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003475 if (*s) {
3476 prs(as);
3477 err(": bad number");
3478 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003479 return n * m;
Eric Andersenff9eee42001-06-29 04:57:14 +00003480}
3481
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003482static int dobreak(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003483{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003484 return brkcontin(t->words[1], 1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003485}
3486
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003487static int docontinue(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003488{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003489 return brkcontin(t->words[1], 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003490}
3491
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003492static int brkcontin(char *cp, int val)
Eric Andersenff9eee42001-06-29 04:57:14 +00003493{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003494 struct brkcon *bc;
3495 int nl;
Eric Andersenff9eee42001-06-29 04:57:14 +00003496
Eric Andersen8401eea2004-08-04 19:16:54 +00003497 nl = cp == NULL ? 1 : getn(cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003498 if (nl <= 0)
3499 nl = 999;
3500 do {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003501 bc = brklist;
3502 if (bc == NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00003503 break;
3504 brklist = bc->nextlev;
3505 } while (--nl);
3506 if (nl) {
3507 err("bad break/continue level");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003508 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003509 }
Denis Vlasenko648b44f2008-02-12 06:04:06 +00003510 isbreak = (val != 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003511 longjmp(bc->brkpt, 1);
3512 /* NOTREACHED */
3513}
3514
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003515static int doexit(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003516{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003517 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003518
3519 execflg = 0;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003520 cp = t->words[1];
3521 if (cp != NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00003522 setstatus(getn(cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003523
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003524 DBGPRINTF(("DOEXIT: calling leave(), t=%p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003525
Eric Andersenff9eee42001-06-29 04:57:14 +00003526 leave();
3527 /* NOTREACHED */
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003528 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003529}
3530
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003531static int doexport(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003532{
Eric Andersen8401eea2004-08-04 19:16:54 +00003533 rdexp(t->words + 1, export, EXPORT);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003534 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003535}
3536
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003537static int doreadonly(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003538{
Eric Andersen8401eea2004-08-04 19:16:54 +00003539 rdexp(t->words + 1, ronly, RONLY);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003540 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003541}
3542
Eric Andersen8401eea2004-08-04 19:16:54 +00003543static void rdexp(char **wp, void (*f) (struct var *), int key)
Eric Andersenff9eee42001-06-29 04:57:14 +00003544{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003545 DBGPRINTF6(("RDEXP: enter, wp=%p, func=%p, key=%d\n", wp, f, key));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003546 DBGPRINTF6(("RDEXP: *wp=%s\n", *wp));
3547
Eric Andersenff9eee42001-06-29 04:57:14 +00003548 if (*wp != NULL) {
Matt Kraaif69bfc72001-07-12 19:39:59 +00003549 for (; *wp != NULL; wp++) {
3550 if (isassign(*wp)) {
3551 char *cp;
Eric Andersen8401eea2004-08-04 19:16:54 +00003552
Matt Kraaif69bfc72001-07-12 19:39:59 +00003553 assign(*wp, COPYV);
Eric Andersen8401eea2004-08-04 19:16:54 +00003554 for (cp = *wp; *cp != '='; cp++);
Matt Kraaif69bfc72001-07-12 19:39:59 +00003555 *cp = '\0';
3556 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003557 if (checkname(*wp))
Eric Andersen8401eea2004-08-04 19:16:54 +00003558 (*f) (lookup(*wp));
Eric Andersenff9eee42001-06-29 04:57:14 +00003559 else
3560 badid(*wp);
Matt Kraaif69bfc72001-07-12 19:39:59 +00003561 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003562 } else
3563 putvlist(key, 1);
3564}
3565
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003566static void badid(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003567{
3568 prs(s);
3569 err(": bad identifier");
3570}
3571
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003572static int doset(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003573{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003574 struct var *vp;
3575 char *cp;
3576 int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003577
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003578 cp = t->words[1];
3579 if (cp == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003580 for (vp = vlist; vp; vp = vp->next)
3581 varput(vp->name, 1);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003582 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003583 }
3584 if (*cp == '-') {
3585 /* bad: t->words++; */
Eric Andersen8401eea2004-08-04 19:16:54 +00003586 for (n = 0; (t->words[n] = t->words[n + 1]) != NULL; n++);
Eric Andersenff9eee42001-06-29 04:57:14 +00003587 if (*++cp == 0)
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003588 FLAG['x'] = FLAG['v'] = 0;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003589 else {
3590 for (; *cp; cp++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003591 switch (*cp) {
3592 case 'e':
3593 if (!interactive)
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003594 FLAG['e']++;
Eric Andersenff9eee42001-06-29 04:57:14 +00003595 break;
3596
3597 default:
Eric Andersen8401eea2004-08-04 19:16:54 +00003598 if (*cp >= 'a' && *cp <= 'z')
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003599 FLAG[(int) *cp]++;
Eric Andersenff9eee42001-06-29 04:57:14 +00003600 break;
3601 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003602 }
3603 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003604 setdash();
3605 }
3606 if (t->words[1]) {
3607 t->words[0] = dolv[0];
Eric Andersen8401eea2004-08-04 19:16:54 +00003608 for (n = 1; t->words[n]; n++)
3609 setarea((char *) t->words[n], 0);
3610 dolc = n - 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003611 dolv = t->words;
3612 setval(lookup("#"), putn(dolc));
Eric Andersen8401eea2004-08-04 19:16:54 +00003613 setarea((char *) (dolv - 1), 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003614 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003615 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003616}
3617
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003618static void varput(char *s, int out)
Eric Andersenff9eee42001-06-29 04:57:14 +00003619{
Matt Kraai69edfec2001-08-06 14:14:18 +00003620 if (isalnum(*s) || *s == '_') {
Eric Andersenff9eee42001-06-29 04:57:14 +00003621 write(out, s, strlen(s));
3622 write(out, "\n", 1);
3623 }
3624}
3625
3626
3627/*
3628 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
3629 * This file contains code for the times builtin.
Eric Andersenff9eee42001-06-29 04:57:14 +00003630 */
Eric Andersen8401eea2004-08-04 19:16:54 +00003631static int dotimes(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003632{
3633 struct tms buf;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003634 long clk_tck = sysconf(_SC_CLK_TCK);
Eric Andersenff9eee42001-06-29 04:57:14 +00003635
3636 times(&buf);
3637 printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
Eric Andersen8401eea2004-08-04 19:16:54 +00003638 (int) (buf.tms_utime / clk_tck / 60),
3639 ((double) buf.tms_utime) / clk_tck,
3640 (int) (buf.tms_stime / clk_tck / 60),
3641 ((double) buf.tms_stime) / clk_tck,
3642 (int) (buf.tms_cutime / clk_tck / 60),
3643 ((double) buf.tms_cutime) / clk_tck,
3644 (int) (buf.tms_cstime / clk_tck / 60),
3645 ((double) buf.tms_cstime) / clk_tck);
Eric Andersenff9eee42001-06-29 04:57:14 +00003646 return 0;
3647}
3648
3649
Eric Andersenff9eee42001-06-29 04:57:14 +00003650/* -------- eval.c -------- */
3651
3652/*
3653 * ${}
3654 * `command`
3655 * blank interpretation
3656 * quoting
3657 * glob
3658 */
3659
Eric Andersen8401eea2004-08-04 19:16:54 +00003660static char **eval(char **ap, int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003661{
3662 struct wdblock *wb;
3663 char **wp;
3664 char **wf;
3665 jmp_buf ev;
3666
3667#if __GNUC__
3668 /* Avoid longjmp clobbering */
3669 (void) &wp;
3670 (void) &ap;
3671#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00003672
3673 DBGPRINTF4(("EVAL: enter, f=%d\n", f));
3674
Eric Andersenff9eee42001-06-29 04:57:14 +00003675 wp = NULL;
3676 wb = NULL;
3677 wf = NULL;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003678 errpt = ev;
3679 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003680 while (*ap && isassign(*ap))
3681 expand(*ap++, &wb, f & ~DOGLOB);
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003682 if (FLAG['k']) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003683 for (wf = ap; *wf; wf++) {
3684 if (isassign(*wf))
3685 expand(*wf, &wb, f & ~DOGLOB);
3686 }
3687 }
Denis Vlasenko648b44f2008-02-12 06:04:06 +00003688 for (wb = addword((char *) NULL, wb); *ap; ap++) {
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003689 if (!FLAG['k'] || !isassign(*ap))
Eric Andersenff9eee42001-06-29 04:57:14 +00003690 expand(*ap, &wb, f & ~DOKEY);
3691 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003692 wb = addword((char *) 0, wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00003693 wp = getwords(wb);
3694 quitenv();
3695 } else
3696 gflg = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003697
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003698 return gflg ? (char **) NULL : wp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003699}
3700
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003701
Eric Andersenff9eee42001-06-29 04:57:14 +00003702/*
3703 * Make the exported environment from the exported
3704 * names in the dictionary. Keyword assignments
3705 * will already have been done.
3706 */
Eric Andersenfd7a4c82004-09-02 23:13:10 +00003707static char **makenv(int all, struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00003708{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003709 struct var *vp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003710
3711 DBGPRINTF5(("MAKENV: enter, all=%d\n", all));
Eric Andersenff9eee42001-06-29 04:57:14 +00003712
Eric Andersenff9eee42001-06-29 04:57:14 +00003713 for (vp = vlist; vp; vp = vp->next)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003714 if (all || vp->status & EXPORT)
Eric Andersenff9eee42001-06-29 04:57:14 +00003715 wb = addword(vp->name, wb);
Eric Andersen8401eea2004-08-04 19:16:54 +00003716 wb = addword((char *) 0, wb);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003717 return getwords(wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00003718}
3719
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003720static int expand(const char *cp, struct wdblock **wbp, int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003721{
3722 jmp_buf ev;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003723 char *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003724
3725#if __GNUC__
3726 /* Avoid longjmp clobbering */
3727 (void) &cp;
3728#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00003729
3730 DBGPRINTF3(("EXPAND: enter, f=%d\n", f));
3731
Eric Andersenff9eee42001-06-29 04:57:14 +00003732 gflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003733
Eric Andersenff9eee42001-06-29 04:57:14 +00003734 if (cp == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003735 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003736
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003737 if (!anys("$`'\"", cp) && !anys(ifs->value, cp)
3738 && ((f & DOGLOB) == 0 || !anys("[*?", cp))
3739 ) {
3740 xp = strsave(cp, areanum);
Eric Andersenff9eee42001-06-29 04:57:14 +00003741 if (f & DOTRIM)
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003742 unquote(xp);
3743 *wbp = addword(xp, *wbp);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003744 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003745 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003746 errpt = ev;
3747 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003748 PUSHIO(aword, cp, strchar);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003749 global_env.iobase = global_env.iop;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003750 while ((xp = blank(f)) && gflg == 0) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003751 global_env.linep = xp;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003752 xp = strsave(xp, areanum);
Eric Andersen8401eea2004-08-04 19:16:54 +00003753 if ((f & DOGLOB) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003754 if (f & DOTRIM)
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003755 unquote(xp);
3756 *wbp = addword(xp, *wbp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003757 } else
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003758 *wbp = glob(xp, *wbp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003759 }
3760 quitenv();
3761 } else
3762 gflg = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003763 return gflg == 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003764}
3765
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003766static char *evalstr(char *cp, int f)
3767{
3768 struct wdblock *wb;
3769
3770 DBGPRINTF6(("EVALSTR: enter, cp=%p, f=%d\n", cp, f));
3771
3772 wb = NULL;
3773 if (expand(cp, &wb, f)) {
3774 if (wb == NULL || wb->w_nword == 0
3775 || (cp = wb->w_words[0]) == NULL
3776 ) {
Denis Vlasenko8e858e22007-03-07 09:35:43 +00003777// TODO: I suspect that
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003778// char *evalstr(char *cp, int f) is actually
3779// const char *evalstr(const char *cp, int f)!
3780 cp = (char*)"";
3781 }
3782 DELETE(wb);
3783 } else
3784 cp = NULL;
3785 return cp;
3786}
3787
3788
Eric Andersenff9eee42001-06-29 04:57:14 +00003789/*
3790 * Blank interpretation and quoting
3791 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003792static char *blank(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003793{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003794 int c, c1;
3795 char *sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003796 int scanequals, foundequals;
3797
Eric Andersen12de6cf2004-08-04 19:19:10 +00003798 DBGPRINTF3(("BLANK: enter, f=%d\n", f));
3799
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003800 sp = global_env.linep;
Eric Andersenff9eee42001-06-29 04:57:14 +00003801 scanequals = f & DOKEY;
3802 foundequals = 0;
3803
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003804 loop:
3805 c = subgetc('"', foundequals);
3806 switch (c) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003807 case 0:
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003808 if (sp == global_env.linep)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003809 return 0;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003810 *global_env.linep++ = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003811 return sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003812
3813 default:
3814 if (f & DOBLANK && any(c, ifs->value))
3815 goto loop;
3816 break;
3817
3818 case '"':
3819 case '\'':
3820 scanequals = 0;
3821 if (INSUB())
3822 break;
3823 for (c1 = c; (c = subgetc(c1, 1)) != c1;) {
3824 if (c == 0)
3825 break;
3826 if (c == '\'' || !any(c, "$`\""))
3827 c |= QUOTE;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003828 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003829 }
3830 c = 0;
3831 }
3832 unget(c);
Matt Kraai69edfec2001-08-06 14:14:18 +00003833 if (!isalpha(c) && c != '_')
Eric Andersenff9eee42001-06-29 04:57:14 +00003834 scanequals = 0;
3835 for (;;) {
3836 c = subgetc('"', foundequals);
3837 if (c == 0 ||
Eric Andersen8401eea2004-08-04 19:16:54 +00003838 f & (DOBLANK && any(c, ifs->value)) ||
3839 (!INSUB() && any(c, "\"'"))) {
3840 scanequals = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003841 unget(c);
3842 if (any(c, "\"'"))
3843 goto loop;
3844 break;
3845 }
3846 if (scanequals) {
3847 if (c == '=') {
3848 foundequals = 1;
Eric Andersen8401eea2004-08-04 19:16:54 +00003849 scanequals = 0;
3850 } else if (!isalnum(c) && c != '_')
Eric Andersenff9eee42001-06-29 04:57:14 +00003851 scanequals = 0;
3852 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003853 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003854 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003855 *global_env.linep++ = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003856 return sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003857}
3858
3859/*
3860 * Get characters, substituting for ` and $
3861 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003862static int subgetc(char ec, int quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00003863{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003864 char c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003865
3866 DBGPRINTF3(("SUBGETC: enter, quoted=%d\n", quoted));
Eric Andersenff9eee42001-06-29 04:57:14 +00003867
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003868 again:
Eric Andersenff9eee42001-06-29 04:57:14 +00003869 c = my_getc(ec);
3870 if (!INSUB() && ec != '\'') {
3871 if (c == '`') {
3872 if (grave(quoted) == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003873 return 0;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003874 global_env.iop->task = XGRAVE;
Eric Andersenff9eee42001-06-29 04:57:14 +00003875 goto again;
3876 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003877 if (c == '$') {
3878 c = dollar(quoted);
3879 if (c == 0) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003880 global_env.iop->task = XDOLL;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003881 goto again;
3882 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003883 }
3884 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003885 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003886}
3887
3888/*
3889 * Prepare to generate the string returned by ${} substitution.
3890 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003891static int dollar(int quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00003892{
3893 int otask;
3894 struct io *oiop;
3895 char *dolp;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003896 char *s, c, *cp = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00003897 struct var *vp;
3898
Eric Andersen12de6cf2004-08-04 19:19:10 +00003899 DBGPRINTF3(("DOLLAR: enter, quoted=%d\n", quoted));
3900
Eric Andersenff9eee42001-06-29 04:57:14 +00003901 c = readc();
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003902 s = global_env.linep;
Eric Andersenff9eee42001-06-29 04:57:14 +00003903 if (c != '{') {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003904 *global_env.linep++ = c;
Matt Kraai69edfec2001-08-06 14:14:18 +00003905 if (isalpha(c) || c == '_') {
Eric Andersen8401eea2004-08-04 19:16:54 +00003906 while ((c = readc()) != 0 && (isalnum(c) || c == '_'))
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003907 if (global_env.linep < elinep)
3908 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003909 unget(c);
3910 }
3911 c = 0;
3912 } else {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003913 oiop = global_env.iop;
3914 otask = global_env.iop->task;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003915
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003916 global_env.iop->task = XOTHER;
Eric Andersen8401eea2004-08-04 19:16:54 +00003917 while ((c = subgetc('"', 0)) != 0 && c != '}' && c != '\n')
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003918 if (global_env.linep < elinep)
3919 *global_env.linep++ = c;
3920 if (oiop == global_env.iop)
3921 global_env.iop->task = otask;
Eric Andersenff9eee42001-06-29 04:57:14 +00003922 if (c != '}') {
3923 err("unclosed ${");
Denis Vlasenko648b44f2008-02-12 06:04:06 +00003924 gflg = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003925 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003926 }
3927 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003928 if (global_env.linep >= elinep) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003929 err("string in ${} too long");
Denis Vlasenko648b44f2008-02-12 06:04:06 +00003930 gflg = 1;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003931 global_env.linep -= 10;
Eric Andersenff9eee42001-06-29 04:57:14 +00003932 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003933 *global_env.linep = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003934 if (*s)
Eric Andersen8401eea2004-08-04 19:16:54 +00003935 for (cp = s + 1; *cp; cp++)
Eric Andersenff9eee42001-06-29 04:57:14 +00003936 if (any(*cp, "=-+?")) {
3937 c = *cp;
3938 *cp++ = 0;
3939 break;
3940 }
3941 if (s[1] == 0 && (*s == '*' || *s == '@')) {
3942 if (dolc > 1) {
3943 /* currently this does not distinguish $* and $@ */
3944 /* should check dollar */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003945 global_env.linep = s;
Eric Andersen8401eea2004-08-04 19:16:54 +00003946 PUSHIO(awordlist, dolv + 1, dolchar);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003947 return 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00003948 } else { /* trap the nasty ${=} */
Eric Andersenff9eee42001-06-29 04:57:14 +00003949 s[0] = '1';
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003950 s[1] = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00003951 }
3952 }
3953 vp = lookup(s);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003954 dolp = vp->value;
3955 if (dolp == null) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003956 switch (c) {
3957 case '=':
3958 if (isdigit(*s)) {
3959 err("cannot use ${...=...} with $n");
Denis Vlasenko648b44f2008-02-12 06:04:06 +00003960 gflg = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003961 break;
3962 }
3963 setval(vp, cp);
3964 dolp = vp->value;
3965 break;
3966
3967 case '-':
3968 dolp = strsave(cp, areanum);
3969 break;
3970
3971 case '?':
3972 if (*cp == 0) {
3973 prs("missing value for ");
3974 err(s);
3975 } else
3976 err(cp);
Denis Vlasenko648b44f2008-02-12 06:04:06 +00003977 gflg = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003978 break;
3979 }
3980 } else if (c == '+')
3981 dolp = strsave(cp, areanum);
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003982 if (FLAG['u'] && dolp == null) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003983 prs("unset variable: ");
3984 err(s);
Denis Vlasenko648b44f2008-02-12 06:04:06 +00003985 gflg = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003986 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003987 global_env.linep = s;
Eric Andersenff9eee42001-06-29 04:57:14 +00003988 PUSHIO(aword, dolp, quoted ? qstrchar : strchar);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003989 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003990}
3991
3992/*
3993 * Run the command in `...` and read its output.
3994 */
Eric Andersen737f5fb2003-03-14 16:05:59 +00003995
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003996static int grave(int quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00003997{
Denis Vlasenko55f30b02007-03-24 22:42:29 +00003998 /* moved to G: static char child_cmd[LINELIM]; */
3999
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004000 const char *cp;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004001 int i;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004002 int j;
Eric Andersenff9eee42001-06-29 04:57:14 +00004003 int pf[2];
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004004 const char *src;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004005 char *dest;
4006 int count;
4007 int ignore;
4008 int ignore_once;
4009 char *argument_list[4];
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004010 struct wdblock *wb = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004011
4012#if __GNUC__
4013 /* Avoid longjmp clobbering */
4014 (void) &cp;
4015#endif
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004016
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004017 for (cp = global_env.iop->argp->aword; *cp != '`'; cp++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004018 if (*cp == 0) {
4019 err("no closing `");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004020 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004021 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004022 }
Eric Andersen737f5fb2003-03-14 16:05:59 +00004023
4024 /* string copy with dollar expansion */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004025 src = global_env.iop->argp->aword;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004026 dest = child_cmd;
4027 count = 0;
4028 ignore = 0;
4029 ignore_once = 0;
4030 while ((*src != '`') && (count < LINELIM)) {
4031 if (*src == '\'')
4032 ignore = !ignore;
4033 if (*src == '\\')
4034 ignore_once = 1;
4035 if (*src == '$' && !ignore && !ignore_once) {
4036 struct var *vp;
Denis Vlasenkoab801872007-12-02 08:35:37 +00004037 /* moved to G to reduce stack usage
Eric Andersen737f5fb2003-03-14 16:05:59 +00004038 char var_name[LINELIM];
4039 char alt_value[LINELIM];
Denis Vlasenkoab801872007-12-02 08:35:37 +00004040 */
4041#define var_name (G.grave__var_name)
4042#define alt_value (G.grave__alt_value)
Eric Andersen737f5fb2003-03-14 16:05:59 +00004043 int var_index = 0;
4044 int alt_index = 0;
4045 char operator = 0;
4046 int braces = 0;
4047 char *value;
4048
4049 src++;
4050 if (*src == '{') {
4051 braces = 1;
4052 src++;
4053 }
4054
4055 var_name[var_index++] = *src++;
Paul Fox54690dc2005-07-20 18:33:12 +00004056 while (isalnum(*src) || *src=='_')
Eric Andersen737f5fb2003-03-14 16:05:59 +00004057 var_name[var_index++] = *src++;
4058 var_name[var_index] = 0;
4059
4060 if (braces) {
4061 switch (*src) {
4062 case '}':
4063 break;
4064 case '-':
4065 case '=':
4066 case '+':
4067 case '?':
Eric Andersen8401eea2004-08-04 19:16:54 +00004068 operator = * src;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004069 break;
4070 default:
4071 err("unclosed ${\n");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004072 return 0;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004073 }
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004074 if (operator) {
Eric Andersen737f5fb2003-03-14 16:05:59 +00004075 src++;
4076 while (*src && (*src != '}')) {
4077 alt_value[alt_index++] = *src++;
4078 }
4079 alt_value[alt_index] = 0;
4080 if (*src != '}') {
4081 err("unclosed ${\n");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004082 return 0;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004083 }
4084 }
4085 src++;
4086 }
4087
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004088 if (isalpha(*var_name)) {
4089 /* let subshell handle it instead */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004090
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004091 char *namep = var_name;
4092
4093 *dest++ = '$';
4094 if (braces)
4095 *dest++ = '{';
4096 while (*namep)
4097 *dest++ = *namep++;
4098 if (operator) {
4099 char *altp = alt_value;
4100 *dest++ = operator;
4101 while (*altp)
4102 *dest++ = *altp++;
4103 }
4104 if (braces)
4105 *dest++ = '}';
4106
4107 wb = addword(lookup(var_name)->name, wb);
4108 } else {
4109 /* expand */
4110
4111 vp = lookup(var_name);
4112 if (vp->value != null)
4113 value = (operator == '+') ?
4114 alt_value : vp->value;
4115 else if (operator == '?') {
4116 err(alt_value);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004117 return 0;
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004118 } else if (alt_index && (operator != '+')) {
4119 value = alt_value;
4120 if (operator == '=')
4121 setval(vp, value);
4122 } else
4123 continue;
4124
4125 while (*value && (count < LINELIM)) {
4126 *dest++ = *value++;
4127 count++;
4128 }
Eric Andersen737f5fb2003-03-14 16:05:59 +00004129 }
Denis Vlasenkoab801872007-12-02 08:35:37 +00004130#undef var_name
4131#undef alt_value
Eric Andersen737f5fb2003-03-14 16:05:59 +00004132 } else {
4133 *dest++ = *src++;
4134 count++;
4135 ignore_once = 0;
4136 }
4137 }
4138 *dest = '\0';
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004139
Eric Andersenff9eee42001-06-29 04:57:14 +00004140 if (openpipe(pf) < 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004141 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004142
Eric Andersen8401eea2004-08-04 19:16:54 +00004143 while ((i = vfork()) == -1 && errno == EAGAIN);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004144
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004145 DBGPRINTF3(("GRAVE: i is %p\n", io));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004146
Eric Andersen737f5fb2003-03-14 16:05:59 +00004147 if (i < 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004148 closepipe(pf);
Eric Andersen8401eea2004-08-04 19:16:54 +00004149 err((char *) bb_msg_memory_exhausted);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004150 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004151 }
4152 if (i != 0) {
Denis Vlasenkofb0eba72008-01-02 19:55:04 +00004153 waitpid(i, NULL, 0); // safe_waitpid?
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004154 global_env.iop->argp->aword = ++cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004155 close(pf[1]);
Eric Andersen8401eea2004-08-04 19:16:54 +00004156 PUSHIO(afile, remap(pf[0]),
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004157 (int (*)(struct ioarg *)) ((quoted) ? qgravechar : gravechar));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004158 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004159 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004160 /* allow trapped signals */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004161 /* XXX - Maybe this signal stuff should go as well? */
Eric Andersen8401eea2004-08-04 19:16:54 +00004162 for (j = 0; j <= _NSIG; j++)
Eric Andersen737f5fb2003-03-14 16:05:59 +00004163 if (ourtrap[j] && signal(j, SIG_IGN) != SIG_IGN)
4164 signal(j, SIG_DFL);
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004165
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00004166 /* Testcase where below checks are needed:
4167 * close stdout & run this script:
4168 * files=`ls`
4169 * echo "$files" >zz
4170 */
4171 xmove_fd(pf[1], 1);
Denis Vlasenko847fa772008-01-28 22:45:43 +00004172 if (pf[0] != 1)
4173 close(pf[0]);
Eric Andersen737f5fb2003-03-14 16:05:59 +00004174
Eric Andersen8401eea2004-08-04 19:16:54 +00004175 argument_list[0] = (char *) DEFAULT_SHELL;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004176 argument_list[1] = (char *) "-c";
Eric Andersen737f5fb2003-03-14 16:05:59 +00004177 argument_list[2] = child_cmd;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004178 argument_list[3] = NULL;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004179
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004180 cp = rexecve(argument_list[0], argument_list, makenv(1, wb));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004181 prs(argument_list[0]);
4182 prs(": ");
4183 err(cp);
Eric Andersen737f5fb2003-03-14 16:05:59 +00004184 _exit(1);
Eric Andersenff9eee42001-06-29 04:57:14 +00004185}
4186
Eric Andersen737f5fb2003-03-14 16:05:59 +00004187
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004188static char *unquote(char *as)
Eric Andersenff9eee42001-06-29 04:57:14 +00004189{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004190 char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00004191
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004192 s = as;
4193 if (s != NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00004194 while (*s)
4195 *s++ &= ~QUOTE;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004196 return as;
Eric Andersenff9eee42001-06-29 04:57:14 +00004197}
4198
4199/* -------- glob.c -------- */
4200
4201/*
4202 * glob
4203 */
4204
4205#define scopy(x) strsave((x), areanum)
4206#define BLKSIZ 512
4207#define NDENT ((BLKSIZ+sizeof(struct dirent)-1)/sizeof(struct dirent))
4208
Eric Andersen8401eea2004-08-04 19:16:54 +00004209static struct wdblock *cl, *nl;
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00004210static const char spcl[] ALIGN1= "[?*";
Eric Andersenff9eee42001-06-29 04:57:14 +00004211
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004212static struct wdblock *glob(char *cp, struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004213{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004214 int i;
4215 char *pp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004216
4217 if (cp == 0)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004218 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004219 i = 0;
4220 for (pp = cp; *pp; pp++)
4221 if (any(*pp, spcl))
4222 i++;
4223 else if (!any(*pp & ~QUOTE, spcl))
4224 *pp &= ~QUOTE;
4225 if (i != 0) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004226 for (cl = addword(scopy(cp), NULL); anyspcl(cl); cl = nl) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004227 nl = newword(cl->w_nword * 2);
4228 for (i = 0; i < cl->w_nword; i++) { /* for each argument */
Eric Andersenff9eee42001-06-29 04:57:14 +00004229 for (pp = cl->w_words[i]; *pp; pp++)
4230 if (any(*pp, spcl)) {
4231 globname(cl->w_words[i], pp);
4232 break;
4233 }
4234 if (*pp == '\0')
4235 nl = addword(scopy(cl->w_words[i]), nl);
4236 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004237 for (i = 0; i < cl->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004238 DELETE(cl->w_words[i]);
4239 DELETE(cl);
4240 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004241 for (i = 0; i < cl->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004242 unquote(cl->w_words[i]);
Eric Andersen8401eea2004-08-04 19:16:54 +00004243 glob0((char *) cl->w_words, cl->w_nword, sizeof(char *), xstrcmp);
Eric Andersenff9eee42001-06-29 04:57:14 +00004244 if (cl->w_nword) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004245 for (i = 0; i < cl->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004246 wb = addword(cl->w_words[i], wb);
4247 DELETE(cl);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004248 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004249 }
4250 }
4251 wb = addword(unquote(cp), wb);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004252 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004253}
4254
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004255static void globname(char *we, char *pp)
Eric Andersenff9eee42001-06-29 04:57:14 +00004256{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004257 char *np, *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004258 char *name, *gp, *dp;
4259 int k;
4260 DIR *dirp;
4261 struct dirent *de;
Eric Andersen8401eea2004-08-04 19:16:54 +00004262 char dname[NAME_MAX + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00004263 struct stat dbuf;
4264
4265 for (np = we; np != pp; pp--)
4266 if (pp[-1] == '/')
4267 break;
Eric Andersen8401eea2004-08-04 19:16:54 +00004268 for (dp = cp = space((int) (pp - np) + 3); np < pp;)
Eric Andersenff9eee42001-06-29 04:57:14 +00004269 *cp++ = *np++;
4270 *cp++ = '.';
4271 *cp = '\0';
Eric Andersen8401eea2004-08-04 19:16:54 +00004272 for (gp = cp = space(strlen(pp) + 1); *np && *np != '/';)
Eric Andersenff9eee42001-06-29 04:57:14 +00004273 *cp++ = *np++;
4274 *cp = '\0';
4275 dirp = opendir(dp);
4276 if (dirp == 0) {
4277 DELETE(dp);
4278 DELETE(gp);
4279 return;
4280 }
4281 dname[NAME_MAX] = '\0';
Eric Andersen8401eea2004-08-04 19:16:54 +00004282 while ((de = readdir(dirp)) != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004283 /* XXX Hmmm... What this could be? (abial) */
4284 /*
Eric Andersen8401eea2004-08-04 19:16:54 +00004285 if (ent[j].d_ino == 0)
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004286 continue;
Eric Andersen8401eea2004-08-04 19:16:54 +00004287 */
Eric Andersenff9eee42001-06-29 04:57:14 +00004288 strncpy(dname, de->d_name, NAME_MAX);
Eric Andersen8401eea2004-08-04 19:16:54 +00004289 if (dname[0] == '.')
4290 if (*gp != '.')
4291 continue;
4292 for (k = 0; k < NAME_MAX; k++)
4293 if (any(dname[k], spcl))
4294 dname[k] |= QUOTE;
4295 if (gmatch(dname, gp)) {
4296 name = generate(we, pp, dname, np);
4297 if (*np && !anys(np, spcl)) {
4298 if (stat(name, &dbuf)) {
4299 DELETE(name);
Eric Andersenff9eee42001-06-29 04:57:14 +00004300 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00004301 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004302 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004303 nl = addword(name, nl);
4304 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004305 }
4306 closedir(dirp);
4307 DELETE(dp);
4308 DELETE(gp);
4309}
4310
4311/*
4312 * generate a pathname as below.
4313 * start..end1 / middle end
4314 * the slashes come for free
4315 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004316static char *generate(char *start1, char *end1, char *middle, char *end)
Eric Andersenff9eee42001-06-29 04:57:14 +00004317{
4318 char *p;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004319 char *op, *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004320
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004321 p = op = space((int)(end1 - start1) + strlen(middle) + strlen(end) + 2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004322 for (xp = start1; xp != end1;)
4323 *op++ = *xp++;
Eric Andersen8401eea2004-08-04 19:16:54 +00004324 for (xp = middle; (*op++ = *xp++) != '\0';);
Eric Andersenff9eee42001-06-29 04:57:14 +00004325 op--;
Eric Andersen8401eea2004-08-04 19:16:54 +00004326 for (xp = end; (*op++ = *xp++) != '\0';);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004327 return p;
Eric Andersenff9eee42001-06-29 04:57:14 +00004328}
4329
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004330static int anyspcl(struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004331{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004332 int i;
4333 char **wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004334
4335 wd = wb->w_words;
Eric Andersen8401eea2004-08-04 19:16:54 +00004336 for (i = 0; i < wb->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004337 if (anys(spcl, *wd++))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004338 return 1;
4339 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004340}
4341
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004342static int xstrcmp(char *p1, char *p2)
Eric Andersenff9eee42001-06-29 04:57:14 +00004343{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004344 return strcmp(*(char **) p1, *(char **) p2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004345}
4346
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004347
Eric Andersenff9eee42001-06-29 04:57:14 +00004348/* -------- word.c -------- */
4349
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004350static struct wdblock *newword(int nw)
Eric Andersenff9eee42001-06-29 04:57:14 +00004351{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004352 struct wdblock *wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004353
Eric Andersen8401eea2004-08-04 19:16:54 +00004354 wb = (struct wdblock *) space(sizeof(*wb) + nw * sizeof(char *));
Eric Andersenff9eee42001-06-29 04:57:14 +00004355 wb->w_bsize = nw;
4356 wb->w_nword = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004357 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004358}
4359
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004360static struct wdblock *addword(char *wd, struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004361{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004362 struct wdblock *wb2;
4363 int nw;
Eric Andersenff9eee42001-06-29 04:57:14 +00004364
4365 if (wb == NULL)
4366 wb = newword(NSTART);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004367 nw = wb->w_nword;
4368 if (nw >= wb->w_bsize) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004369 wb2 = newword(nw * 2);
Eric Andersen8401eea2004-08-04 19:16:54 +00004370 memcpy((char *) wb2->w_words, (char *) wb->w_words,
4371 nw * sizeof(char *));
Eric Andersenff9eee42001-06-29 04:57:14 +00004372 wb2->w_nword = nw;
4373 DELETE(wb);
4374 wb = wb2;
4375 }
4376 wb->w_words[wb->w_nword++] = wd;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004377 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004378}
Eric Andersen8401eea2004-08-04 19:16:54 +00004379
Denis Vlasenkoe4712752007-04-14 15:08:41 +00004380static char **getwords(struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004381{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004382 char **wd;
4383 int nb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004384
4385 if (wb == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004386 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004387 if (wb->w_nword == 0) {
4388 DELETE(wb);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004389 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004390 }
4391 wd = (char **) space(nb = sizeof(*wd) * wb->w_nword);
Eric Andersen8401eea2004-08-04 19:16:54 +00004392 memcpy((char *) wd, (char *) wb->w_words, nb);
4393 DELETE(wb); /* perhaps should done by caller */
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004394 return wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004395}
4396
"Vladimir N. Oleynik"ac973172005-09-22 14:38:17 +00004397static int (*func) (char *, char *);
4398static int globv;
Eric Andersenff9eee42001-06-29 04:57:14 +00004399
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004400static void glob3(char *i, char *j, char *k)
Eric Andersenff9eee42001-06-29 04:57:14 +00004401{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004402 char *index1, *index2, *index3;
4403 int c;
4404 int m;
4405
4406 m = globv;
4407 index1 = i;
4408 index2 = j;
4409 index3 = k;
4410 do {
4411 c = *index1;
4412 *index1++ = *index3;
4413 *index3++ = *index2;
4414 *index2++ = c;
4415 } while (--m);
4416}
4417
4418static void glob2(char *i, char *j)
4419{
4420 char *index1, *index2, c;
4421 int m;
4422
4423 m = globv;
4424 index1 = i;
4425 index2 = j;
4426 do {
4427 c = *index1;
4428 *index1++ = *index2;
4429 *index2++ = c;
4430 } while (--m);
Eric Andersenff9eee42001-06-29 04:57:14 +00004431}
4432
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004433static void glob1(char *base, char *lim)
Eric Andersenff9eee42001-06-29 04:57:14 +00004434{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004435 char *i, *j;
Eric Andersenff9eee42001-06-29 04:57:14 +00004436 int v2;
4437 char *lptr, *hptr;
4438 int c;
4439 unsigned n;
4440
Eric Andersenff9eee42001-06-29 04:57:14 +00004441 v2 = globv;
4442
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004443 top:
4444 n = (int) (lim - base);
4445 if (n <= v2)
Eric Andersenff9eee42001-06-29 04:57:14 +00004446 return;
Eric Andersen8401eea2004-08-04 19:16:54 +00004447 n = v2 * (n / (2 * v2));
4448 hptr = lptr = base + n;
Eric Andersenff9eee42001-06-29 04:57:14 +00004449 i = base;
Eric Andersen8401eea2004-08-04 19:16:54 +00004450 j = lim - v2;
4451 for (;;) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004452 if (i < lptr) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004453 c = (*func) (i, lptr);
4454 if (c == 0) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004455 lptr -= v2;
4456 glob2(i, lptr);
Eric Andersenff9eee42001-06-29 04:57:14 +00004457 continue;
4458 }
4459 if (c < 0) {
4460 i += v2;
4461 continue;
4462 }
4463 }
4464
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004465 begin:
Eric Andersenff9eee42001-06-29 04:57:14 +00004466 if (j > hptr) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004467 c = (*func) (hptr, j);
4468 if (c == 0) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004469 hptr += v2;
4470 glob2(hptr, j);
Eric Andersenff9eee42001-06-29 04:57:14 +00004471 goto begin;
4472 }
4473 if (c > 0) {
4474 if (i == lptr) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004475 hptr += v2;
4476 glob3(i, hptr, j);
4477 i = (lptr += v2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004478 goto begin;
4479 }
4480 glob2(i, j);
4481 j -= v2;
4482 i += v2;
4483 continue;
4484 }
4485 j -= v2;
4486 goto begin;
4487 }
4488
4489
4490 if (i == lptr) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004491 if (lptr - base >= lim - hptr) {
4492 glob1(hptr + v2, lim);
Eric Andersenff9eee42001-06-29 04:57:14 +00004493 lim = lptr;
4494 } else {
4495 glob1(base, lptr);
Eric Andersen8401eea2004-08-04 19:16:54 +00004496 base = hptr + v2;
Eric Andersenff9eee42001-06-29 04:57:14 +00004497 }
4498 goto top;
4499 }
4500
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004501 lptr -= v2;
4502 glob3(j, lptr, i);
4503 j = (hptr -= v2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004504 }
4505}
4506
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004507static void glob0(char *a0, unsigned a1, int a2, int (*a3) (char *, char *))
Eric Andersenff9eee42001-06-29 04:57:14 +00004508{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004509 func = a3;
4510 globv = a2;
4511 glob1(a0, a0 + a1 * a2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004512}
4513
Eric Andersenff9eee42001-06-29 04:57:14 +00004514
4515/* -------- io.c -------- */
4516
4517/*
4518 * shell IO
4519 */
4520
Eric Andersen8401eea2004-08-04 19:16:54 +00004521static int my_getc(int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00004522{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004523 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004524
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004525 if (global_env.linep > elinep) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004526 while ((c = readc()) != '\n' && c);
Eric Andersenff9eee42001-06-29 04:57:14 +00004527 err("input line too long");
Denis Vlasenko648b44f2008-02-12 06:04:06 +00004528 gflg = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004529 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004530 }
4531 c = readc();
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004532 if ((ec != '\'') && (ec != '`') && (global_env.iop->task != XGRAVE)) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004533 if (c == '\\') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004534 c = readc();
4535 if (c == '\n' && ec != '\"')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004536 return my_getc(ec);
Eric Andersenff9eee42001-06-29 04:57:14 +00004537 c |= QUOTE;
4538 }
4539 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004540 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004541}
4542
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004543static void unget(int c)
Eric Andersenff9eee42001-06-29 04:57:14 +00004544{
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004545 if (global_env.iop >= global_env.iobase)
4546 global_env.iop->peekc = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004547}
4548
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004549static int eofc(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00004550{
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004551 return global_env.iop < global_env.iobase || (global_env.iop->peekc == 0 && global_env.iop->prev == 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004552}
4553
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004554static int readc(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00004555{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004556 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004557
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004558 RCPRINTF(("READC: global_env.iop %p, global_env.iobase %p\n", global_env.iop, global_env.iobase));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004559
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004560 for (; global_env.iop >= global_env.iobase; global_env.iop--) {
4561 RCPRINTF(("READC: global_env.iop %p, peekc 0x%x\n", global_env.iop, global_env.iop->peekc));
4562 c = global_env.iop->peekc;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004563 if (c != '\0') {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004564 global_env.iop->peekc = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004565 return c;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004566 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004567 if (global_env.iop->prev != 0) {
4568 c = (*global_env.iop->iofn)(global_env.iop->argp, global_env.iop);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004569 if (c != '\0') {
4570 if (c == -1) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004571 global_env.iop++;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004572 continue;
Eric Andersen8401eea2004-08-04 19:16:54 +00004573 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004574 if (global_env.iop == iostack)
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004575 ioecho(c);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004576 global_env.iop->prev = c;
4577 return global_env.iop->prev;
Eric Andersenff9eee42001-06-29 04:57:14 +00004578 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004579 if (global_env.iop->task == XIO && global_env.iop->prev != '\n') {
4580 global_env.iop->prev = 0;
4581 if (global_env.iop == iostack)
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004582 ioecho('\n');
4583 return '\n';
Eric Andersen8401eea2004-08-04 19:16:54 +00004584 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004585 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004586 if (global_env.iop->task == XIO) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004587 if (multiline) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004588 global_env.iop->prev = 0;
4589 return global_env.iop->prev;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004590 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004591 if (interactive && global_env.iop == iostack + 1) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004592#if ENABLE_FEATURE_EDITING
4593 current_prompt = prompt->value;
4594#else
4595 prs(prompt->value);
4596#endif
4597 }
4598 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004599 } /* FOR */
4600
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004601 if (global_env.iop >= iostack) {
4602 RCPRINTF(("READC: return 0, global_env.iop %p\n", global_env.iop));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004603 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004604 }
4605
4606 DBGPRINTF(("READC: leave()...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00004607 leave();
4608 /* NOTREACHED */
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004609 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004610}
4611
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004612static void ioecho(char c)
Eric Andersenff9eee42001-06-29 04:57:14 +00004613{
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00004614 if (FLAG['v'])
Eric Andersenff9eee42001-06-29 04:57:14 +00004615 write(2, &c, sizeof c);
4616}
4617
Eric Andersen8401eea2004-08-04 19:16:54 +00004618static void pushio(struct ioarg *argp, int (*fn) (struct ioarg *))
Eric Andersenff9eee42001-06-29 04:57:14 +00004619{
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004620 DBGPRINTF(("PUSHIO: argp %p, argp->afid 0x%x, global_env.iop %p\n", argp,
4621 argp->afid, global_env.iop));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004622
4623 /* Set env ptr for io source to next array spot and check for array overflow */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004624 if (++global_env.iop >= &iostack[NPUSH]) {
4625 global_env.iop--;
Eric Andersenff9eee42001-06-29 04:57:14 +00004626 err("Shell input nested too deeply");
Denis Vlasenko648b44f2008-02-12 06:04:06 +00004627 gflg = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004628 return;
4629 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004630
4631 /* We did not overflow the NPUSH array spots so setup data structs */
4632
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004633 global_env.iop->iofn = (int (*)(struct ioarg *, struct io *)) fn; /* Store data source func ptr */
Eric Andersenff9eee42001-06-29 04:57:14 +00004634
4635 if (argp->afid != AFID_NOBUF)
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004636 global_env.iop->argp = argp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004637 else {
Eric Andersen12de6cf2004-08-04 19:19:10 +00004638
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004639 global_env.iop->argp = ioargstack + (global_env.iop - iostack); /* MAL - index into stack */
4640 *global_env.iop->argp = *argp; /* copy data from temp area into stack spot */
Eric Andersen12de6cf2004-08-04 19:19:10 +00004641
4642 /* MAL - mainbuf is for 1st data source (command line?) and all nested use a single shared buffer? */
4643
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004644 if (global_env.iop == &iostack[0])
4645 global_env.iop->argp->afbuf = &mainbuf;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004646 else
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004647 global_env.iop->argp->afbuf = &sharedbuf;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004648
4649 /* MAL - if not a termimal AND (commandline OR readable file) then give it a buffer id? */
4650 /* This line appears to be active when running scripts from command line */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004651 if ((isatty(global_env.iop->argp->afile) == 0)
4652 && (global_env.iop == &iostack[0]
4653 || lseek(global_env.iop->argp->afile, 0L, SEEK_CUR) != -1)) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00004654 if (++bufid == AFID_NOBUF) /* counter rollover check, AFID_NOBUF = 11111111 */
4655 bufid = AFID_ID; /* AFID_ID = 0 */
4656
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004657 global_env.iop->argp->afid = bufid; /* assign buffer id */
Eric Andersen8401eea2004-08-04 19:16:54 +00004658 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004659
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004660 DBGPRINTF(("PUSHIO: iostack %p, global_env.iop %p, afbuf %p\n",
4661 iostack, global_env.iop, global_env.iop->argp->afbuf));
4662 DBGPRINTF(("PUSHIO: mbuf %p, sbuf %p, bid %d, global_env.iop %p\n",
4663 &mainbuf, &sharedbuf, bufid, global_env.iop));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004664
Eric Andersenff9eee42001-06-29 04:57:14 +00004665 }
4666
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004667 global_env.iop->prev = ~'\n';
4668 global_env.iop->peekc = 0;
4669 global_env.iop->xchar = 0;
4670 global_env.iop->nlcount = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004671
Eric Andersenff9eee42001-06-29 04:57:14 +00004672 if (fn == filechar || fn == linechar)
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004673 global_env.iop->task = XIO;
Eric Andersen8401eea2004-08-04 19:16:54 +00004674 else if (fn == (int (*)(struct ioarg *)) gravechar
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004675 || fn == (int (*)(struct ioarg *)) qgravechar)
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004676 global_env.iop->task = XGRAVE;
Eric Andersenff9eee42001-06-29 04:57:14 +00004677 else
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004678 global_env.iop->task = XOTHER;
Eric Andersenff9eee42001-06-29 04:57:14 +00004679}
4680
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004681static struct io *setbase(struct io *ip)
Eric Andersenff9eee42001-06-29 04:57:14 +00004682{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004683 struct io *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004684
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004685 xp = global_env.iobase;
4686 global_env.iobase = ip;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004687 return xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004688}
4689
4690/*
4691 * Input generating functions
4692 */
4693
4694/*
4695 * Produce the characters of a string, then a newline, then EOF.
4696 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004697static int nlchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004698{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004699 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004700
4701 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004702 return 0;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004703 c = *ap->aword++;
4704 if (c == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004705 ap->aword = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004706 return '\n';
Eric Andersenff9eee42001-06-29 04:57:14 +00004707 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004708 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004709}
4710
4711/*
4712 * Given a list of words, produce the characters
4713 * in them, with a space after each word.
4714 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004715static int wdchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004716{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004717 char c;
4718 char **wl;
Eric Andersenff9eee42001-06-29 04:57:14 +00004719
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004720 wl = ap->awordlist;
4721 if (wl == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004722 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004723 if (*wl != NULL) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004724 c = *(*wl)++;
4725 if (c != 0)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004726 return c & 0177;
Eric Andersenff9eee42001-06-29 04:57:14 +00004727 ap->awordlist++;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004728 return ' ';
Eric Andersenff9eee42001-06-29 04:57:14 +00004729 }
4730 ap->awordlist = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004731 return '\n';
Eric Andersenff9eee42001-06-29 04:57:14 +00004732}
4733
4734/*
4735 * Return the characters of a list of words,
4736 * producing a space between them.
4737 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004738static int dolchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004739{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004740 char *wp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004741
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004742 wp = *ap->awordlist++;
4743 if (wp != NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004744 PUSHIO(aword, wp, *ap->awordlist == NULL ? strchar : xxchar);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004745 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004746 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004747 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004748}
4749
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004750static int xxchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004751{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004752 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004753
4754 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004755 return 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004756 c = *ap->aword++;
4757 if (c == '\0') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004758 ap->aword = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004759 return ' ';
Eric Andersenff9eee42001-06-29 04:57:14 +00004760 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004761 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004762}
4763
4764/*
4765 * Produce the characters from a single word (string).
4766 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004767static int strchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004768{
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004769 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004770 return 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004771 return *ap->aword++;
Eric Andersenff9eee42001-06-29 04:57:14 +00004772}
4773
4774/*
4775 * Produce quoted characters from a single word (string).
4776 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004777static int qstrchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004778{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004779 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004780
Denis Vlasenkob2abef32007-01-01 18:18:04 +00004781 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004782 return 0;
Denis Vlasenkob2abef32007-01-01 18:18:04 +00004783 c = *ap->aword++;
4784 if (c)
4785 c |= QUOTE;
4786 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004787}
4788
4789/*
4790 * Return the characters from a file.
4791 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004792static int filechar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004793{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004794 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004795 char c;
4796 struct iobuf *bp = ap->afbuf;
4797
4798 if (ap->afid != AFID_NOBUF) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004799 i = (ap->afid != bp->id);
4800 if (i || bp->bufp == bp->ebufp) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004801 if (i)
Denis Vlasenkoea620772006-10-14 02:23:43 +00004802 lseek(ap->afile, ap->afpos, SEEK_SET);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004803
Eric Andersen8401eea2004-08-04 19:16:54 +00004804 i = safe_read(ap->afile, bp->buf, sizeof(bp->buf));
4805 if (i <= 0) {
4806 closef(ap->afile);
4807 return 0;
4808 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004809
Eric Andersen8401eea2004-08-04 19:16:54 +00004810 bp->id = ap->afid;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004811 bp->bufp = bp->buf;
4812 bp->ebufp = bp->bufp + i;
Eric Andersen8401eea2004-08-04 19:16:54 +00004813 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004814
Eric Andersen8401eea2004-08-04 19:16:54 +00004815 ap->afpos++;
4816 return *bp->bufp++ & 0177;
Eric Andersenff9eee42001-06-29 04:57:14 +00004817 }
Denis Vlasenko38f63192007-01-22 09:03:07 +00004818#if ENABLE_FEATURE_EDITING
Eric Andersen737f5fb2003-03-14 16:05:59 +00004819 if (interactive && isatty(ap->afile)) {
Denis Vlasenko55f30b02007-03-24 22:42:29 +00004820 /* moved to G: static char filechar_cmdbuf[BUFSIZ]; */
Eric Andersen8401eea2004-08-04 19:16:54 +00004821 static int position = 0, size = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004822
Eric Andersen8401eea2004-08-04 19:16:54 +00004823 while (size == 0 || position >= size) {
Denis Vlasenko6e602c42008-02-02 18:50:50 +00004824 size = read_line_input(current_prompt, filechar_cmdbuf, BUFSIZ, line_input_state);
4825 if (size < 0) /* Error/EOF */
4826 exit(0);
Eric Andersen8401eea2004-08-04 19:16:54 +00004827 position = 0;
Denis Vlasenko6e602c42008-02-02 18:50:50 +00004828 /* if Ctrl-C, size == 0 and loop will repeat */
Eric Andersen8401eea2004-08-04 19:16:54 +00004829 }
Denis Vlasenko55f30b02007-03-24 22:42:29 +00004830 c = filechar_cmdbuf[position];
Eric Andersen8401eea2004-08-04 19:16:54 +00004831 position++;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004832 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004833 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004834#endif
4835 i = safe_read(ap->afile, &c, sizeof(c));
4836 return i == sizeof(c) ? (c & 0x7f) : (closef(ap->afile), 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004837}
4838
4839/*
4840 * Return the characters from a here temp file.
4841 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004842static int herechar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004843{
4844 char c;
4845
Eric Andersenff9eee42001-06-29 04:57:14 +00004846 if (read(ap->afile, &c, sizeof(c)) != sizeof(c)) {
4847 close(ap->afile);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004848 c = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00004849 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004850 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004851}
4852
4853/*
4854 * Return the characters produced by a process (`...`).
4855 * Quote them if required, and remove any trailing newline characters.
4856 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004857static int gravechar(struct ioarg *ap, struct io *iop)
Eric Andersenff9eee42001-06-29 04:57:14 +00004858{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004859 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004860
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004861 c = qgravechar(ap, iop) & ~QUOTE;
4862 if (c == '\n')
Eric Andersenff9eee42001-06-29 04:57:14 +00004863 c = ' ';
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004864 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004865}
4866
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004867static int qgravechar(struct ioarg *ap, struct io *iop)
Eric Andersenff9eee42001-06-29 04:57:14 +00004868{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004869 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004870
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004871 DBGPRINTF3(("QGRAVECHAR: enter, ap=%p, iop=%p\n", ap, iop));
Eric Andersenff9eee42001-06-29 04:57:14 +00004872
4873 if (iop->xchar) {
4874 if (iop->nlcount) {
4875 iop->nlcount--;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004876 return '\n' | QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00004877 }
4878 c = iop->xchar;
4879 iop->xchar = 0;
4880 } else if ((c = filechar(ap)) == '\n') {
4881 iop->nlcount = 1;
4882 while ((c = filechar(ap)) == '\n')
4883 iop->nlcount++;
4884 iop->xchar = c;
4885 if (c == 0)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004886 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004887 iop->nlcount--;
4888 c = '\n';
4889 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004890 return c != 0 ? c | QUOTE : 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004891}
4892
4893/*
4894 * Return a single command (usually the first line) from a file.
4895 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004896static int linechar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004897{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004898 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004899
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004900 c = filechar(ap);
4901 if (c == '\n') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004902 if (!multiline) {
4903 closef(ap->afile);
Eric Andersen8401eea2004-08-04 19:16:54 +00004904 ap->afile = -1; /* illegal value */
Eric Andersenff9eee42001-06-29 04:57:14 +00004905 }
4906 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004907 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004908}
4909
Eric Andersenff9eee42001-06-29 04:57:14 +00004910/*
4911 * remap fd into Shell's fd space
4912 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004913static int remap(int fd)
Eric Andersenff9eee42001-06-29 04:57:14 +00004914{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004915 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004916 int map[NOFILE];
Eric Andersen12de6cf2004-08-04 19:19:10 +00004917 int newfd;
4918
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004919 DBGPRINTF(("REMAP: fd=%d, global_env.iofd=%d\n", fd, global_env.iofd));
Eric Andersenff9eee42001-06-29 04:57:14 +00004920
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004921 if (fd < global_env.iofd) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004922 for (i = 0; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004923 map[i] = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004924
Eric Andersenff9eee42001-06-29 04:57:14 +00004925 do {
4926 map[fd] = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004927 newfd = dup(fd);
4928 fd = newfd;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004929 } while (fd >= 0 && fd < global_env.iofd);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004930
Eric Andersen8401eea2004-08-04 19:16:54 +00004931 for (i = 0; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004932 if (map[i])
4933 close(i);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004934
Eric Andersenff9eee42001-06-29 04:57:14 +00004935 if (fd < 0)
4936 err("too many files open in shell");
4937 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004938
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004939 return fd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004940}
4941
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004942static int openpipe(int *pv)
Eric Andersenff9eee42001-06-29 04:57:14 +00004943{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004944 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004945
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004946 i = pipe(pv);
4947 if (i < 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00004948 err("can't create pipe - try again");
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004949 return i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004950}
4951
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004952static void closepipe(int *pv)
Eric Andersenff9eee42001-06-29 04:57:14 +00004953{
4954 if (pv != NULL) {
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00004955 close(pv[0]);
4956 close(pv[1]);
Eric Andersenff9eee42001-06-29 04:57:14 +00004957 }
4958}
4959
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004960
Eric Andersenff9eee42001-06-29 04:57:14 +00004961/* -------- here.c -------- */
4962
4963/*
4964 * here documents
4965 */
4966
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004967static void markhere(char *s, struct ioword *iop)
Eric Andersenff9eee42001-06-29 04:57:14 +00004968{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004969 struct here *h, *lh;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004970
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004971 DBGPRINTF7(("MARKHERE: enter, s=%p\n", s));
Eric Andersenff9eee42001-06-29 04:57:14 +00004972
4973 h = (struct here *) space(sizeof(struct here));
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004974 if (h == NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00004975 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004976
Eric Andersenff9eee42001-06-29 04:57:14 +00004977 h->h_tag = evalstr(s, DOSUB);
4978 if (h->h_tag == 0)
4979 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004980
Eric Andersenff9eee42001-06-29 04:57:14 +00004981 h->h_iop = iop;
4982 iop->io_name = 0;
4983 h->h_next = NULL;
4984 if (inhere == 0)
4985 inhere = h;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004986 else {
4987 for (lh = inhere; lh != NULL; lh = lh->h_next) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004988 if (lh->h_next == 0) {
4989 lh->h_next = h;
4990 break;
4991 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004992 }
4993 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004994 iop->io_flag |= IOHERE | IOXHERE;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004995 for (s = h->h_tag; *s; s++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004996 if (*s & QUOTE) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004997 iop->io_flag &= ~IOXHERE;
4998 *s &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00004999 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00005000 }
Denis Vlasenko648b44f2008-02-12 06:04:06 +00005001 h->h_dosub = ((iop->io_flag & IOXHERE) ? '\0' : '\'');
Eric Andersenff9eee42001-06-29 04:57:14 +00005002}
5003
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005004static void gethere(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00005005{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005006 struct here *h, *hp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005007
5008 DBGPRINTF7(("GETHERE: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00005009
5010 /* Scan here files first leaving inhere list in place */
5011 for (hp = h = inhere; h != NULL; hp = h, h = h->h_next)
Denis Vlasenko648b44f2008-02-12 06:04:06 +00005012 readhere(&h->h_iop->io_name, h->h_tag, h->h_dosub /* NUL or ' */);
Eric Andersenff9eee42001-06-29 04:57:14 +00005013
5014 /* Make inhere list active - keep list intact for scraphere */
5015 if (hp != NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005016 hp->h_next = acthere;
5017 acthere = inhere;
5018 inhere = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00005019 }
5020}
5021
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005022static void readhere(char **name, char *s, int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00005023{
5024 int tf;
5025 char tname[30] = ".msh_XXXXXX";
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005026 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00005027 jmp_buf ev;
Eric Andersen8401eea2004-08-04 19:16:54 +00005028 char myline[LINELIM + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00005029 char *thenext;
5030
Mike Frysinger02d8fa42006-05-05 20:32:31 +00005031 DBGPRINTF7(("READHERE: enter, name=%p, s=%p\n", name, s));
Eric Andersen12de6cf2004-08-04 19:19:10 +00005032
Eric Andersenff9eee42001-06-29 04:57:14 +00005033 tf = mkstemp(tname);
5034 if (tf < 0)
5035 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005036
Eric Andersenff9eee42001-06-29 04:57:14 +00005037 *name = strsave(tname, areanum);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00005038 errpt = ev;
5039 if (newenv(setjmp(errpt)) != 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00005040 unlink(tname);
5041 else {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005042 pushio(global_env.iop->argp, (int (*)(struct ioarg *)) global_env.iop->iofn);
5043 global_env.iobase = global_env.iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00005044 for (;;) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005045 if (interactive && global_env.iop <= iostack) {
Denis Vlasenko38f63192007-01-22 09:03:07 +00005046#if ENABLE_FEATURE_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00005047 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00005048#else
Eric Andersen8401eea2004-08-04 19:16:54 +00005049 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00005050#endif
5051 }
5052 thenext = myline;
5053 while ((c = my_getc(ec)) != '\n' && c) {
5054 if (ec == '\'')
Eric Andersen8401eea2004-08-04 19:16:54 +00005055 c &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00005056 if (thenext >= &myline[LINELIM]) {
5057 c = 0;
5058 break;
5059 }
5060 *thenext++ = c;
5061 }
5062 *thenext = 0;
5063 if (strcmp(s, myline) == 0 || c == 0)
5064 break;
5065 *thenext++ = '\n';
Eric Andersen8401eea2004-08-04 19:16:54 +00005066 write(tf, myline, (int) (thenext - myline));
Eric Andersenff9eee42001-06-29 04:57:14 +00005067 }
5068 if (c == 0) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005069 prs("here document `");
5070 prs(s);
5071 err("' unclosed");
Eric Andersenff9eee42001-06-29 04:57:14 +00005072 }
5073 quitenv();
5074 }
5075 close(tf);
5076}
5077
5078/*
5079 * open here temp file.
5080 * if unquoted here, expand here temp file into second temp file.
5081 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005082static int herein(char *hname, int xdoll)
Eric Andersenff9eee42001-06-29 04:57:14 +00005083{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005084 int hf;
Eric Andersenff9eee42001-06-29 04:57:14 +00005085 int tf;
5086
5087#if __GNUC__
5088 /* Avoid longjmp clobbering */
5089 (void) &tf;
5090#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00005091 if (hname == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00005092 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005093
5094 DBGPRINTF7(("HEREIN: hname is %s, xdoll=%d\n", hname, xdoll));
5095
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005096 hf = open(hname, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00005097 if (hf < 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00005098 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005099
Eric Andersenff9eee42001-06-29 04:57:14 +00005100 if (xdoll) {
5101 char c;
5102 char tname[30] = ".msh_XXXXXX";
5103 jmp_buf ev;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005104
Eric Andersenff9eee42001-06-29 04:57:14 +00005105 tf = mkstemp(tname);
5106 if (tf < 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00005107 return -1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00005108 errpt = ev;
5109 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00005110 PUSHIO(afile, hf, herechar);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005111 setbase(global_env.iop);
Eric Andersenff9eee42001-06-29 04:57:14 +00005112 while ((c = subgetc(0, 0)) != 0) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005113 c &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00005114 write(tf, &c, sizeof c);
5115 }
5116 quitenv();
5117 } else
5118 unlink(tname);
5119 close(tf);
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005120 tf = open(tname, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00005121 unlink(tname);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00005122 return tf;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00005123 }
5124 return hf;
Eric Andersenff9eee42001-06-29 04:57:14 +00005125}
5126
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005127static void scraphere(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00005128{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005129 struct here *h;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005130
5131 DBGPRINTF7(("SCRAPHERE: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00005132
5133 for (h = inhere; h != NULL; h = h->h_next) {
5134 if (h->h_iop && h->h_iop->io_name)
Eric Andersen8401eea2004-08-04 19:16:54 +00005135 unlink(h->h_iop->io_name);
Eric Andersenff9eee42001-06-29 04:57:14 +00005136 }
5137 inhere = NULL;
5138}
5139
5140/* unlink here temp files before a freearea(area) */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005141static void freehere(int area)
Eric Andersenff9eee42001-06-29 04:57:14 +00005142{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005143 struct here *h, *hl;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005144
5145 DBGPRINTF6(("FREEHERE: enter, area=%d\n", area));
Eric Andersenff9eee42001-06-29 04:57:14 +00005146
5147 hl = NULL;
5148 for (h = acthere; h != NULL; h = h->h_next)
5149 if (getarea((char *) h) >= area) {
5150 if (h->h_iop->io_name != NULL)
5151 unlink(h->h_iop->io_name);
5152 if (hl == NULL)
5153 acthere = h->h_next;
5154 else
5155 hl->h_next = h->h_next;
5156 } else
5157 hl = h;
5158}
5159
5160
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005161/* -------- sh.c -------- */
5162/*
5163 * shell
5164 */
5165
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00005166int msh_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005167int msh_main(int argc, char **argv)
5168{
5169 int f;
5170 char *s;
5171 int cflag;
5172 char *name, **ap;
5173 int (*iof) (struct ioarg *);
5174
Denis Vlasenkoab801872007-12-02 08:35:37 +00005175 INIT_G();
5176
Denis Vlasenko55f30b02007-03-24 22:42:29 +00005177 sharedbuf.id = AFID_NOBUF;
5178 mainbuf.id = AFID_NOBUF;
Denis Vlasenko55f30b02007-03-24 22:42:29 +00005179 elinep = line + sizeof(line) - 5;
5180
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005181#if ENABLE_FEATURE_EDITING
5182 line_input_state = new_line_input_t(FOR_SHELL);
5183#endif
5184
5185 DBGPRINTF(("MSH_MAIN: argc %d, environ %p\n", argc, environ));
5186
5187 initarea();
5188 ap = environ;
5189 if (ap != NULL) {
5190 while (*ap)
5191 assign(*ap++, !COPYV);
5192 for (ap = environ; *ap;)
5193 export(lookup(*ap++));
5194 }
5195 closeall();
5196 areanum = 1;
5197
5198 shell = lookup("SHELL");
5199 if (shell->value == null)
5200 setval(shell, (char *)DEFAULT_SHELL);
5201 export(shell);
5202
5203 homedir = lookup("HOME");
5204 if (homedir->value == null)
5205 setval(homedir, "/");
5206 export(homedir);
5207
5208 setval(lookup("$"), putn(getpid()));
5209
5210 path = lookup("PATH");
5211 if (path->value == null) {
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005212 /* Can be merged with same string elsewhere in bbox */
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005213 if (geteuid() == 0)
Denis Vlasenkof5f75c52007-06-12 22:35:19 +00005214 setval(path, bb_default_root_path);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005215 else
Denis Vlasenkof5f75c52007-06-12 22:35:19 +00005216 setval(path, bb_default_path);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005217 }
5218 export(path);
5219
5220 ifs = lookup("IFS");
5221 if (ifs->value == null)
5222 setval(ifs, " \t\n");
5223
5224#ifdef MSHDEBUG
5225 mshdbg_var = lookup("MSHDEBUG");
5226 if (mshdbg_var->value == null)
5227 setval(mshdbg_var, "0");
5228#endif
5229
5230 prompt = lookup("PS1");
5231#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
5232 if (prompt->value == null)
5233#endif
5234 setval(prompt, DEFAULT_USER_PROMPT);
5235 if (geteuid() == 0) {
5236 setval(prompt, DEFAULT_ROOT_PROMPT);
5237 prompt->status &= ~EXPORT;
5238 }
5239 cprompt = lookup("PS2");
5240#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
5241 if (cprompt->value == null)
5242#endif
5243 setval(cprompt, "> ");
5244
5245 iof = filechar;
5246 cflag = 0;
5247 name = *argv++;
5248 if (--argc >= 1) {
5249 if (argv[0][0] == '-' && argv[0][1] != '\0') {
5250 for (s = argv[0] + 1; *s; s++)
5251 switch (*s) {
5252 case 'c':
5253 prompt->status &= ~EXPORT;
5254 cprompt->status &= ~EXPORT;
5255 setval(prompt, "");
5256 setval(cprompt, "");
5257 cflag = 1;
5258 if (--argc > 0)
5259 PUSHIO(aword, *++argv, iof = nlchar);
5260 break;
5261
5262 case 'q':
5263 qflag = SIG_DFL;
5264 break;
5265
5266 case 's':
5267 /* standard input */
5268 break;
5269
5270 case 't':
5271 prompt->status &= ~EXPORT;
5272 setval(prompt, "");
5273 iof = linechar;
5274 break;
5275
5276 case 'i':
Denis Vlasenko648b44f2008-02-12 06:04:06 +00005277 interactive = 1;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005278 default:
5279 if (*s >= 'a' && *s <= 'z')
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00005280 FLAG[(int) *s]++;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005281 }
5282 } else {
5283 argv--;
5284 argc++;
5285 }
5286
5287 if (iof == filechar && --argc > 0) {
5288 setval(prompt, "");
5289 setval(cprompt, "");
5290 prompt->status &= ~EXPORT;
5291 cprompt->status &= ~EXPORT;
5292
5293/* Shell is non-interactive, activate printf-based debug */
5294#ifdef MSHDEBUG
5295 mshdbg = (int) (((char) (mshdbg_var->value[0])) - '0');
5296 if (mshdbg < 0)
5297 mshdbg = 0;
5298#endif
5299 DBGPRINTF(("MSH_MAIN: calling newfile()\n"));
5300
5301 name = *++argv;
5302 if (newfile(name))
5303 exit(1); /* Exit on error */
5304 }
5305 }
5306
5307 setdash();
5308
5309 /* This won't be true if PUSHIO has been called, say from newfile() above */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005310 if (global_env.iop < iostack) {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005311 PUSHIO(afile, 0, iof);
5312 if (isatty(0) && isatty(1) && !cflag) {
Denis Vlasenko648b44f2008-02-12 06:04:06 +00005313 interactive = 1;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005314#if !ENABLE_FEATURE_SH_EXTRA_QUIET
5315#ifdef MSHDEBUG
Denis Vlasenkoca525b42007-06-13 12:27:17 +00005316 printf("\n\n%s built-in shell (msh with debug)\n", bb_banner);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005317#else
Denis Vlasenkoca525b42007-06-13 12:27:17 +00005318 printf("\n\n%s built-in shell (msh)\n", bb_banner);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005319#endif
5320 printf("Enter 'help' for a list of built-in commands.\n\n");
5321#endif
5322 }
5323 }
5324
5325 signal(SIGQUIT, qflag);
5326 if (name && name[0] == '-') {
Denis Vlasenko648b44f2008-02-12 06:04:06 +00005327 interactive = 1;
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005328 f = open(".profile", O_RDONLY);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005329 if (f >= 0)
5330 next(remap(f));
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005331 f = open("/etc/profile", O_RDONLY);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005332 if (f >= 0)
5333 next(remap(f));
5334 }
5335 if (interactive)
5336 signal(SIGTERM, sig);
5337
5338 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
5339 signal(SIGINT, onintr);
Denis Vlasenkofee2d0c2008-02-12 10:12:18 +00005340
5341/* Handle "msh SCRIPT VAR=val params..." */
5342/* Disabled: bash does not do it! */
5343#if 0
5344 argv++;
5345 /* skip leading args of the form VAR=val */
5346 while (*argv && assign(*argv, !COPYV)) {
5347 argc--;
5348 argv++;
5349 }
5350 argv--;
5351#endif
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005352 dolv = argv;
5353 dolc = argc;
5354 dolv[0] = name;
Denis Vlasenkofee2d0c2008-02-12 10:12:18 +00005355
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005356 setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc));
5357
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005358 DBGPRINTF(("MSH_MAIN: begin FOR loop, interactive %d, global_env.iop %p, iostack %p\n", interactive, global_env.iop, iostack));
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005359
5360 for (;;) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005361 if (interactive && global_env.iop <= iostack) {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005362#if ENABLE_FEATURE_EDITING
5363 current_prompt = prompt->value;
5364#else
5365 prs(prompt->value);
5366#endif
5367 }
5368 onecommand();
5369 /* Ensure that getenv("PATH") stays current */
5370 setenv("PATH", path->value, 1);
5371 }
5372
5373 DBGPRINTF(("MSH_MAIN: returning.\n"));
5374}
5375
5376
Eric Andersenff9eee42001-06-29 04:57:14 +00005377/*
5378 * Copyright (c) 1987,1997, Prentice Hall
5379 * All rights reserved.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005380 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005381 * Redistribution and use of the MINIX operating system in source and
5382 * binary forms, with or without modification, are permitted provided
5383 * that the following conditions are met:
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005384 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005385 * Redistributions of source code must retain the above copyright
5386 * notice, this list of conditions and the following disclaimer.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005387 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005388 * Redistributions in binary form must reproduce the above
5389 * copyright notice, this list of conditions and the following
5390 * disclaimer in the documentation and/or other materials provided
5391 * with the distribution.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005392 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005393 * Neither the name of Prentice Hall nor the names of the software
5394 * authors or contributors may be used to endorse or promote
5395 * products derived from this software without specific prior
5396 * written permission.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005397 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005398 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND
5399 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
5400 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
5401 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
5402 * IN NO EVENT SHALL PRENTICE HALL OR ANY AUTHORS OR CONTRIBUTORS BE
5403 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
5404 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
5405 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
5406 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
5407 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
5408 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
5409 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5410 *
5411 */