blob: 0cb81fee7286b9e178423580ba774381739f18dd [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)
Denis Vlasenkoe376d452008-02-20 22:23:24 +000045# define nonblock_safe_read(fd,buf,count) read(fd,buf,count)
Mike Frysinger67a32ad2007-03-09 08:25:24 +000046# define NOT_LONE_DASH(s) ((s)[0] != '-' || (s)[1])
47# define LONE_CHAR(s,c) ((s)[0] == (c) && !(s)[1])
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000048# define NORETURN __attribute__ ((__noreturn__))
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000049static int find_applet_by_name(const char *applet)
Mike Frysinger67a32ad2007-03-09 08:25:24 +000050{
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000051 return -1;
Mike Frysinger67a32ad2007-03-09 08:25:24 +000052}
Denis Vlasenko10457b92007-03-27 22:01:31 +000053static char *utoa_to_buf(unsigned n, char *buf, unsigned buflen)
Mike Frysinger67a32ad2007-03-09 08:25:24 +000054{
Denis Vlasenkoc86e0522007-03-20 11:30:28 +000055 unsigned i, out, res;
56 assert(sizeof(unsigned) == 4);
57 if (buflen) {
58 out = 0;
59 for (i = 1000000000; i; i /= 10) {
60 res = n / i;
61 if (res || out || i == 1) {
Denis Vlasenko4b924f32007-05-30 00:29:55 +000062 if (!--buflen) break;
63 out++;
64 n -= res*i;
65 *buf++ = '0' + res;
Denis Vlasenkoc86e0522007-03-20 11:30:28 +000066 }
67 }
Denis Vlasenkoc86e0522007-03-20 11:30:28 +000068 }
Denis Vlasenko10457b92007-03-27 22:01:31 +000069 return buf;
Mike Frysinger67a32ad2007-03-09 08:25:24 +000070}
Denis Vlasenko10457b92007-03-27 22:01:31 +000071static char *itoa_to_buf(int n, char *buf, unsigned buflen)
Mike Frysinger67a32ad2007-03-09 08:25:24 +000072{
Denis Vlasenkoc86e0522007-03-20 11:30:28 +000073 if (buflen && n < 0) {
74 n = -n;
75 *buf++ = '-';
76 buflen--;
77 }
Denis Vlasenko10457b92007-03-27 22:01:31 +000078 return utoa_to_buf((unsigned)n, buf, buflen);
Mike Frysinger67a32ad2007-03-09 08:25:24 +000079}
80static char local_buf[12];
81static char *itoa(int n)
82{
Denis Vlasenko10457b92007-03-27 22:01:31 +000083 *(itoa_to_buf(n, local_buf, sizeof(local_buf))) = '\0';
Denis Vlasenkoc86e0522007-03-20 11:30:28 +000084 return local_buf;
Mike Frysinger67a32ad2007-03-09 08:25:24 +000085}
86#else
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000087# include "busybox.h" /* for applet_names */
Mike Frysinger67a32ad2007-03-09 08:25:24 +000088#endif
Eric Andersenff9eee42001-06-29 04:57:14 +000089
Denis Vlasenko7e497522008-02-12 09:51:03 +000090//#define MSHDEBUG 4
Eric Andersen12de6cf2004-08-04 19:19:10 +000091
92#ifdef MSHDEBUG
Denis Vlasenko509697f2008-03-02 12:49:39 +000093static int mshdbg = MSHDEBUG;
Eric Andersen12de6cf2004-08-04 19:19:10 +000094
Denis Vlasenkoed9d6212008-06-09 07:44:19 +000095#define DBGPRINTF(x) if (mshdbg > 0) printf x
96#define DBGPRINTF0(x) if (mshdbg > 0) printf x
97#define DBGPRINTF1(x) if (mshdbg > 1) printf x
98#define DBGPRINTF2(x) if (mshdbg > 2) printf x
99#define DBGPRINTF3(x) if (mshdbg > 3) printf x
100#define DBGPRINTF4(x) if (mshdbg > 4) printf x
101#define DBGPRINTF5(x) if (mshdbg > 5) printf x
102#define DBGPRINTF6(x) if (mshdbg > 6) printf x
103#define DBGPRINTF7(x) if (mshdbg > 7) printf x
104#define DBGPRINTF8(x) if (mshdbg > 8) printf x
105#define DBGPRINTF9(x) if (mshdbg > 9) printf x
Eric Andersen12de6cf2004-08-04 19:19:10 +0000106
Denis Vlasenko509697f2008-03-02 12:49:39 +0000107static int mshdbg_rc = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +0000108
Denis Vlasenko51742f42007-04-12 00:32:05 +0000109#define RCPRINTF(x) if (mshdbg_rc) printf x
Eric Andersen12de6cf2004-08-04 19:19:10 +0000110
111#else
112
113#define DBGPRINTF(x)
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000114#define DBGPRINTF0(x) ((void)0)
115#define DBGPRINTF1(x) ((void)0)
116#define DBGPRINTF2(x) ((void)0)
117#define DBGPRINTF3(x) ((void)0)
118#define DBGPRINTF4(x) ((void)0)
119#define DBGPRINTF5(x) ((void)0)
120#define DBGPRINTF6(x) ((void)0)
121#define DBGPRINTF7(x) ((void)0)
122#define DBGPRINTF8(x) ((void)0)
123#define DBGPRINTF9(x) ((void)0)
Eric Andersen12de6cf2004-08-04 19:19:10 +0000124
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000125#define RCPRINTF(x) ((void)0)
Eric Andersen12de6cf2004-08-04 19:19:10 +0000126
Denis Vlasenkoed9d6212008-06-09 07:44:19 +0000127#endif /* MSHDEBUG */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000128
129
Denis Vlasenko38f63192007-01-22 09:03:07 +0000130#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
Mike Frysinger2a131752006-06-06 06:26:12 +0000131# define DEFAULT_ROOT_PROMPT "\\u:\\w> "
132# define DEFAULT_USER_PROMPT "\\u:\\w$ "
133#else
134# define DEFAULT_ROOT_PROMPT "# "
135# define DEFAULT_USER_PROMPT "$ "
136#endif
137
138
Eric Andersenff9eee42001-06-29 04:57:14 +0000139/* -------- sh.h -------- */
140/*
141 * shell
142 */
143
Denis Vlasenkoed9d6212008-06-09 07:44:19 +0000144#define LINELIM 2100
145#define NPUSH 8 /* limit to input nesting */
Eric Andersenff9eee42001-06-29 04:57:14 +0000146
Eric Andersen392947c2002-12-11 07:42:46 +0000147#undef NOFILE
Denis Vlasenkoed9d6212008-06-09 07:44:19 +0000148#define NOFILE 20 /* Number of open files */
149#define NUFILE 10 /* Number of user-accessible files */
150#define FDBASE 10 /* First file usable by Shell */
Eric Andersenff9eee42001-06-29 04:57:14 +0000151
152/*
153 * values returned by wait
154 */
Denis Vlasenko5f9468e2007-04-14 13:22:09 +0000155#define WAITSIG(s) ((s) & 0177)
156#define WAITVAL(s) (((s) >> 8) & 0377)
157#define WAITCORE(s) (((s) & 0200) != 0)
Eric Andersenff9eee42001-06-29 04:57:14 +0000158
159/*
Eric Andersenaff114c2004-04-14 17:51:38 +0000160 * library and system definitions
Eric Andersenff9eee42001-06-29 04:57:14 +0000161 */
Denis Vlasenkoed9d6212008-06-09 07:44:19 +0000162typedef void xint; /* base type of jmp_buf, for not broken compilers */
Eric Andersenff9eee42001-06-29 04:57:14 +0000163
164/*
165 * shell components
166 */
Eric Andersenff9eee42001-06-29 04:57:14 +0000167#define NOBLOCK ((struct op *)NULL)
168#define NOWORD ((char *)NULL)
169#define NOWORDS ((char **)NULL)
170#define NOPIPE ((int *)NULL)
171
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000172/*
173 * redirection
174 */
175struct ioword {
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +0000176 smallint io_flag; /* action (below) */
177 int io_fd; /* fd affected */
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000178 char *io_name; /* file name */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000179};
180
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000181#define IOREAD 1 /* < */
182#define IOHERE 2 /* << (here file) */
183#define IOWRITE 4 /* > */
184#define IOCAT 8 /* >> */
185#define IOXHERE 16 /* ${}, ` in << */
186#define IODUP 32 /* >&digit */
187#define IOCLOSE 64 /* >&- */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000188
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +0000189#define IODEFAULT (-1) /* "default" IO fd */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000190
191
Eric Andersenff9eee42001-06-29 04:57:14 +0000192/*
193 * Description of a command or an operation on commands.
194 * Might eventually use a union.
195 */
196struct op {
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +0000197 smallint op_type; /* operation type, see Txxxx below */
Denis Vlasenko509697f2008-03-02 12:49:39 +0000198 char **op_words; /* arguments to a command */
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000199 struct ioword **ioact; /* IO actions (eg, < > >>) */
Eric Andersenff9eee42001-06-29 04:57:14 +0000200 struct op *left;
201 struct op *right;
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000202 char *str; /* identifier for case and for */
Eric Andersenff9eee42001-06-29 04:57:14 +0000203};
204
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000205#define TCOM 1 /* command */
206#define TPAREN 2 /* (c-list) */
207#define TPIPE 3 /* a | b */
208#define TLIST 4 /* a [&;] b */
209#define TOR 5 /* || */
210#define TAND 6 /* && */
211#define TFOR 7
212#define TDO 8
213#define TCASE 9
214#define TIF 10
215#define TWHILE 11
216#define TUNTIL 12
217#define TELIF 13
218#define TPAT 14 /* pattern in case */
219#define TBRACE 15 /* {c-list} */
220#define TASYNC 16 /* c & */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000221/* Added to support "." file expansion */
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000222#define TDOT 17
Eric Andersen12de6cf2004-08-04 19:19:10 +0000223
224/* Strings for names to make debug easier */
"Vladimir N. Oleynik"ac973172005-09-22 14:38:17 +0000225#ifdef MSHDEBUG
Denis Vlasenkoe27f1562007-01-01 06:00:38 +0000226static const char *const T_CMD_NAMES[] = {
Eric Andersen12de6cf2004-08-04 19:19:10 +0000227 "PLACEHOLDER",
228 "TCOM",
229 "TPAREN",
230 "TPIPE",
231 "TLIST",
232 "TOR",
233 "TAND",
234 "TFOR",
235 "TDO",
236 "TCASE",
237 "TIF",
238 "TWHILE",
239 "TUNTIL",
240 "TELIF",
241 "TPAT",
242 "TBRACE",
243 "TASYNC",
244 "TDOT",
245};
"Vladimir N. Oleynik"ac973172005-09-22 14:38:17 +0000246#endif
Eric Andersenff9eee42001-06-29 04:57:14 +0000247
Denis Vlasenko5f9468e2007-04-14 13:22:09 +0000248#define AREASIZE (90000)
Eric Andersen12de6cf2004-08-04 19:19:10 +0000249
Eric Andersenff9eee42001-06-29 04:57:14 +0000250/*
251 * flags to control evaluation of words
252 */
Denis Vlasenko5f9468e2007-04-14 13:22:09 +0000253#define DOSUB 1 /* interpret $, `, and quotes */
254#define DOBLANK 2 /* perform blank interpretation */
255#define DOGLOB 4 /* interpret [?* */
256#define DOKEY 8 /* move words with `=' to 2nd arg. list */
257#define DOTRIM 16 /* trim resulting string */
Eric Andersenff9eee42001-06-29 04:57:14 +0000258
Denis Vlasenko5f9468e2007-04-14 13:22:09 +0000259#define DOALL (DOSUB|DOBLANK|DOGLOB|DOKEY|DOTRIM)
Eric Andersenff9eee42001-06-29 04:57:14 +0000260
Eric Andersenff9eee42001-06-29 04:57:14 +0000261
Eric Andersen8401eea2004-08-04 19:16:54 +0000262struct brkcon {
263 jmp_buf brkpt;
264 struct brkcon *nextlev;
265};
Eric Andersenff9eee42001-06-29 04:57:14 +0000266
Eric Andersen12de6cf2004-08-04 19:19:10 +0000267
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000268static smallint trapset; /* trap pending (signal number) */
Eric Andersenff9eee42001-06-29 04:57:14 +0000269
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000270static smallint yynerrs; /* yacc (flag) */
Eric Andersenff9eee42001-06-29 04:57:14 +0000271
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000272/* moved to G: static char line[LINELIM]; */
Eric Andersenff9eee42001-06-29 04:57:14 +0000273
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000274#if ENABLE_FEATURE_EDITING
275static char *current_prompt;
276static line_input_t *line_input_state;
277#endif
278
Eric Andersen12de6cf2004-08-04 19:19:10 +0000279
Eric Andersenff9eee42001-06-29 04:57:14 +0000280/*
281 * other functions
282 */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000283static const char *rexecve(char *c, char **v, char **envp);
Eric Andersen8401eea2004-08-04 19:16:54 +0000284static char *evalstr(char *cp, int f);
285static char *putn(int n);
Eric Andersen8401eea2004-08-04 19:16:54 +0000286static char *unquote(char *as);
Eric Andersen8401eea2004-08-04 19:16:54 +0000287static int rlookup(char *n);
288static struct wdblock *glob(char *cp, struct wdblock *wb);
289static int my_getc(int ec);
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +0000290static int subgetc(char ec, int quoted);
Eric Andersenfd7a4c82004-09-02 23:13:10 +0000291static char **makenv(int all, struct wdblock *wb);
Eric Andersen8401eea2004-08-04 19:16:54 +0000292static char **eval(char **ap, int f);
293static int setstatus(int s);
294static int waitfor(int lastpid, int canintr);
Eric Andersenff9eee42001-06-29 04:57:14 +0000295
Eric Andersen8401eea2004-08-04 19:16:54 +0000296static void onintr(int s); /* SIGINT handler */
Eric Andersenff9eee42001-06-29 04:57:14 +0000297
Eric Andersen8401eea2004-08-04 19:16:54 +0000298static int newenv(int f);
299static void quitenv(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000300static void next(int f);
301static void setdash(void);
302static void onecommand(void);
303static void runtrap(int i);
Eric Andersenff9eee42001-06-29 04:57:14 +0000304
Eric Andersen12de6cf2004-08-04 19:19:10 +0000305
Eric Andersenff9eee42001-06-29 04:57:14 +0000306/* -------- area stuff -------- */
307
Denis Vlasenko5f9468e2007-04-14 13:22:09 +0000308#define REGSIZE sizeof(struct region)
309#define GROWBY (256)
310/* #define SHRINKBY (64) */
311#undef SHRINKBY
312#define FREE (32767)
313#define BUSY (0)
314#define ALIGN (sizeof(int)-1)
Eric Andersenff9eee42001-06-29 04:57:14 +0000315
316
317struct region {
Eric Andersen8401eea2004-08-04 19:16:54 +0000318 struct region *next;
319 int area;
Eric Andersenff9eee42001-06-29 04:57:14 +0000320};
321
322
Eric Andersenff9eee42001-06-29 04:57:14 +0000323/* -------- grammar stuff -------- */
324typedef union {
Eric Andersen8401eea2004-08-04 19:16:54 +0000325 char *cp;
326 char **wp;
327 int i;
328 struct op *o;
Eric Andersenff9eee42001-06-29 04:57:14 +0000329} YYSTYPE;
Eric Andersen8401eea2004-08-04 19:16:54 +0000330
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000331#define WORD 256
332#define LOGAND 257
333#define LOGOR 258
334#define BREAK 259
335#define IF 260
336#define THEN 261
337#define ELSE 262
338#define ELIF 263
339#define FI 264
340#define CASE 265
341#define ESAC 266
342#define FOR 267
343#define WHILE 268
344#define UNTIL 269
345#define DO 270
346#define DONE 271
347#define IN 272
Eric Andersen12de6cf2004-08-04 19:19:10 +0000348/* Added for "." file expansion */
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000349#define DOT 273
Eric Andersen12de6cf2004-08-04 19:19:10 +0000350
Eric Andersenff9eee42001-06-29 04:57:14 +0000351#define YYERRCODE 300
352
353/* flags to yylex */
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000354#define CONTIN 01 /* skip new lines to complete command */
Eric Andersenff9eee42001-06-29 04:57:14 +0000355
Eric Andersen8401eea2004-08-04 19:16:54 +0000356static struct op *pipeline(int cf);
Eric Andersenff9eee42001-06-29 04:57:14 +0000357static struct op *andor(void);
358static struct op *c_list(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000359static int synio(int cf);
360static void musthave(int c, int cf);
Eric Andersenff9eee42001-06-29 04:57:14 +0000361static struct op *simple(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000362static struct op *nested(int type, int mark);
363static struct op *command(int cf);
364static struct op *dogroup(int onlydone);
Eric Andersenff9eee42001-06-29 04:57:14 +0000365static struct op *thenpart(void);
366static struct op *elsepart(void);
367static struct op *caselist(void);
368static struct op *casepart(void);
369static char **pattern(void);
370static char **wordlist(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000371static struct op *list(struct op *t1, struct op *t2);
372static struct op *block(int type, struct op *t1, struct op *t2, char **wp);
Eric Andersenff9eee42001-06-29 04:57:14 +0000373static struct op *newtp(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000374static struct op *namelist(struct op *t);
Eric Andersenff9eee42001-06-29 04:57:14 +0000375static char **copyw(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000376static void word(char *cp);
Eric Andersenff9eee42001-06-29 04:57:14 +0000377static struct ioword **copyio(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000378static struct ioword *io(int u, int f, char *cp);
Eric Andersen8401eea2004-08-04 19:16:54 +0000379static int yylex(int cf);
380static int collect(int c, int c1);
381static int dual(int c);
382static void diag(int ec);
383static char *tree(unsigned size);
Eric Andersenff9eee42001-06-29 04:57:14 +0000384
385/* -------- var.h -------- */
386
Eric Andersen8401eea2004-08-04 19:16:54 +0000387struct var {
388 char *value;
389 char *name;
390 struct var *next;
391 char status;
Eric Andersenff9eee42001-06-29 04:57:14 +0000392};
Eric Andersenff9eee42001-06-29 04:57:14 +0000393
Eric Andersen8401eea2004-08-04 19:16:54 +0000394#define COPYV 1 /* flag to setval, suggesting copy */
395#define RONLY 01 /* variable is read-only */
396#define EXPORT 02 /* variable is to be exported */
397#define GETCELL 04 /* name & value space was got with getcell */
Eric Andersenff9eee42001-06-29 04:57:14 +0000398
Eric Andersen8401eea2004-08-04 19:16:54 +0000399static int yyparse(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000400
Eric Andersen12de6cf2004-08-04 19:19:10 +0000401
Eric Andersenff9eee42001-06-29 04:57:14 +0000402/* -------- io.h -------- */
403/* io buffer */
404struct iobuf {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000405 unsigned id; /* buffer id */
406 char buf[512]; /* buffer */
407 char *bufp; /* pointer into buffer */
408 char *ebufp; /* pointer to end of buffer */
Eric Andersenff9eee42001-06-29 04:57:14 +0000409};
410
411/* possible arguments to an IO function */
412struct ioarg {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000413 const char *aword;
Eric Andersen8401eea2004-08-04 19:16:54 +0000414 char **awordlist;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000415 int afile; /* file descriptor */
416 unsigned afid; /* buffer id */
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000417 off_t afpos; /* file position */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000418 struct iobuf *afbuf; /* buffer for this file */
Eric Andersenff9eee42001-06-29 04:57:14 +0000419};
Eric Andersen8401eea2004-08-04 19:16:54 +0000420
Eric Andersenff9eee42001-06-29 04:57:14 +0000421/* an input generator's state */
Eric Andersen8401eea2004-08-04 19:16:54 +0000422struct io {
423 int (*iofn) (struct ioarg *, struct io *);
424 struct ioarg *argp;
425 int peekc;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000426 char prev; /* previous character read by readc() */
427 char nlcount; /* for `'s */
428 char xchar; /* for `'s */
429 char task; /* reason for pushed IO */
Eric Andersenff9eee42001-06-29 04:57:14 +0000430};
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000431/* ->task: */
432#define XOTHER 0 /* none of the below */
433#define XDOLL 1 /* expanding ${} */
434#define XGRAVE 2 /* expanding `'s */
435#define XIO 3 /* file IO */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000436
437
438/*
Eric Andersenff9eee42001-06-29 04:57:14 +0000439 * input generators for IO structure
440 */
Eric Andersen8401eea2004-08-04 19:16:54 +0000441static int nlchar(struct ioarg *ap);
442static int strchar(struct ioarg *ap);
443static int qstrchar(struct ioarg *ap);
444static int filechar(struct ioarg *ap);
445static int herechar(struct ioarg *ap);
446static int linechar(struct ioarg *ap);
447static int gravechar(struct ioarg *ap, struct io *iop);
448static int qgravechar(struct ioarg *ap, struct io *iop);
449static int dolchar(struct ioarg *ap);
450static int wdchar(struct ioarg *ap);
451static void scraphere(void);
452static void freehere(int area);
453static void gethere(void);
454static void markhere(char *s, struct ioword *iop);
455static int herein(char *hname, int xdoll);
456static int run(struct ioarg *argp, int (*f) (struct ioarg *));
Eric Andersenff9eee42001-06-29 04:57:14 +0000457
Eric Andersen12de6cf2004-08-04 19:19:10 +0000458
Eric Andersen8401eea2004-08-04 19:16:54 +0000459static int eofc(void);
460static int readc(void);
461static void unget(int c);
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +0000462static void ioecho(char c);
Eric Andersenff9eee42001-06-29 04:57:14 +0000463
Eric Andersen12de6cf2004-08-04 19:19:10 +0000464
Eric Andersenff9eee42001-06-29 04:57:14 +0000465/*
466 * IO control
467 */
Eric Andersen8401eea2004-08-04 19:16:54 +0000468static void pushio(struct ioarg *argp, int (*f) (struct ioarg *));
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000469#define PUSHIO(what,arg,gen) ((temparg.what = (arg)), pushio(&temparg,(gen)))
Eric Andersen8401eea2004-08-04 19:16:54 +0000470static int remap(int fd);
471static int openpipe(int *pv);
472static void closepipe(int *pv);
473static struct io *setbase(struct io *ip);
Eric Andersenff9eee42001-06-29 04:57:14 +0000474
Eric Andersenff9eee42001-06-29 04:57:14 +0000475/* -------- word.h -------- */
476
Eric Andersen8401eea2004-08-04 19:16:54 +0000477#define NSTART 16 /* default number of words to allow for initially */
Eric Andersenff9eee42001-06-29 04:57:14 +0000478
Eric Andersen8401eea2004-08-04 19:16:54 +0000479struct wdblock {
480 short w_bsize;
481 short w_nword;
Eric Andersenff9eee42001-06-29 04:57:14 +0000482 /* bounds are arbitrary */
Eric Andersen8401eea2004-08-04 19:16:54 +0000483 char *w_words[1];
Eric Andersenff9eee42001-06-29 04:57:14 +0000484};
485
Eric Andersen8401eea2004-08-04 19:16:54 +0000486static struct wdblock *addword(char *wd, struct wdblock *wb);
487static struct wdblock *newword(int nw);
488static char **getwords(struct wdblock *wb);
Eric Andersenff9eee42001-06-29 04:57:14 +0000489
Eric Andersenff9eee42001-06-29 04:57:14 +0000490/* -------- misc stuff -------- */
491
Denis Vlasenkofe218832008-03-01 09:35:39 +0000492static int dolabel(struct op *t, char **args);
493static int dohelp(struct op *t, char **args);
494static int dochdir(struct op *t, char **args);
495static int doshift(struct op *t, char **args);
496static int dologin(struct op *t, char **args);
497static int doumask(struct op *t, char **args);
498static int doexec(struct op *t, char **args);
499static int dodot(struct op *t, char **args);
500static int dowait(struct op *t, char **args);
501static int doread(struct op *t, char **args);
502static int doeval(struct op *t, char **args);
503static int dotrap(struct op *t, char **args);
504static int dobreak(struct op *t, char **args);
505static int doexit(struct op *t, char **args);
506static int doexport(struct op *t, char **args);
507static int doreadonly(struct op *t, char **args);
508static int doset(struct op *t, char **args);
509static int dotimes(struct op *t, char **args);
510static int docontinue(struct op *t, char **args);
511
Denis Vlasenko7e497522008-02-12 09:51:03 +0000512static int forkexec(struct op *t, int *pin, int *pout, int no_fork, char **wp);
513static int execute(struct op *t, int *pin, int *pout, int no_fork);
Eric Andersen8401eea2004-08-04 19:16:54 +0000514static int iosetup(struct ioword *iop, int pipein, int pipeout);
Eric Andersen8401eea2004-08-04 19:16:54 +0000515static void brkset(struct brkcon *bc);
Eric Andersen8401eea2004-08-04 19:16:54 +0000516static int getsig(char *s);
517static void setsig(int n, sighandler_t f);
518static int getn(char *as);
Eric Andersen8401eea2004-08-04 19:16:54 +0000519static int brkcontin(char *cp, int val);
Eric Andersen8401eea2004-08-04 19:16:54 +0000520static void rdexp(char **wp, void (*f) (struct var *), int key);
521static void badid(char *s);
Eric Andersen8401eea2004-08-04 19:16:54 +0000522static void varput(char *s, int out);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000523static int expand(const char *cp, struct wdblock **wbp, int f);
Eric Andersen8401eea2004-08-04 19:16:54 +0000524static char *blank(int f);
525static int dollar(int quoted);
526static int grave(int quoted);
527static void globname(char *we, char *pp);
528static char *generate(char *start1, char *end1, char *middle, char *end);
529static int anyspcl(struct wdblock *wb);
Eric Andersen8401eea2004-08-04 19:16:54 +0000530static void readhere(char **name, char *s, int ec);
Eric Andersen8401eea2004-08-04 19:16:54 +0000531static int xxchar(struct ioarg *ap);
Eric Andersenff9eee42001-06-29 04:57:14 +0000532
Eric Andersen8401eea2004-08-04 19:16:54 +0000533struct here {
534 char *h_tag;
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000535 char h_dosub;
Eric Andersen8401eea2004-08-04 19:16:54 +0000536 struct ioword *h_iop;
537 struct here *h_next;
Eric Andersenff9eee42001-06-29 04:57:14 +0000538};
539
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000540static const char *const signame[] = {
Eric Andersenff9eee42001-06-29 04:57:14 +0000541 "Signal 0",
542 "Hangup",
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000543 NULL, /* interrupt */
Eric Andersenff9eee42001-06-29 04:57:14 +0000544 "Quit",
545 "Illegal instruction",
546 "Trace/BPT trap",
547 "Abort",
548 "Bus error",
549 "Floating Point Exception",
550 "Killed",
551 "SIGUSR1",
552 "SIGSEGV",
553 "SIGUSR2",
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000554 NULL, /* broken pipe */
Eric Andersenff9eee42001-06-29 04:57:14 +0000555 "Alarm clock",
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000556 "Terminated"
Eric Andersenff9eee42001-06-29 04:57:14 +0000557};
Eric Andersen8401eea2004-08-04 19:16:54 +0000558
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000559
Denis Vlasenkofe218832008-03-01 09:35:39 +0000560typedef int (*builtin_func_ptr)(struct op *, char **);
Denis Vlasenko7e497522008-02-12 09:51:03 +0000561
Eric Andersen1c039232001-07-07 00:05:55 +0000562struct builtincmd {
563 const char *name;
Denis Vlasenko7e497522008-02-12 09:51:03 +0000564 builtin_func_ptr builtinfunc;
Eric Andersenff9eee42001-06-29 04:57:14 +0000565};
Denis Vlasenko7e497522008-02-12 09:51:03 +0000566
Eric Andersen8401eea2004-08-04 19:16:54 +0000567static const struct builtincmd builtincmds[] = {
Denis Vlasenko95cb3262007-04-09 03:06:34 +0000568 { "." , dodot },
569 { ":" , dolabel },
570 { "break" , dobreak },
571 { "cd" , dochdir },
572 { "continue", docontinue },
573 { "eval" , doeval },
574 { "exec" , doexec },
575 { "exit" , doexit },
576 { "export" , doexport },
577 { "help" , dohelp },
578 { "login" , dologin },
579 { "newgrp" , dologin },
580 { "read" , doread },
581 { "readonly", doreadonly },
582 { "set" , doset },
583 { "shift" , doshift },
584 { "times" , dotimes },
585 { "trap" , dotrap },
586 { "umask" , doumask },
587 { "wait" , dowait },
588 { NULL , NULL },
Eric Andersenff9eee42001-06-29 04:57:14 +0000589};
590
Denis Vlasenko68404f12008-03-17 09:00:54 +0000591static struct op *dowholefile(int /*, int*/);
Eric Andersen12de6cf2004-08-04 19:19:10 +0000592
Eric Andersen12de6cf2004-08-04 19:19:10 +0000593
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000594/* Globals */
Eric Andersen8401eea2004-08-04 19:16:54 +0000595static char **dolv;
596static int dolc;
Denis Vlasenko447bd662008-05-30 22:28:32 +0000597static uint8_t exstat;
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000598static smallint gflg; /* (seems to be a parse error indicator) */
599static smallint interactive; /* Is this an interactive shell */
600static smallint execflg;
601static smallint isbreak; /* "break" statement was seen */
602static int multiline; /* '\n' changed to ';' (counter) */
603static struct op *outtree; /* result from parser */
Eric Andersen8401eea2004-08-04 19:16:54 +0000604static xint *failpt;
605static xint *errpt;
606static struct brkcon *brklist;
Eric Andersen8401eea2004-08-04 19:16:54 +0000607static struct wdblock *wdlist;
608static struct wdblock *iolist;
Eric Andersen12de6cf2004-08-04 19:19:10 +0000609
610#ifdef MSHDEBUG
611static struct var *mshdbg_var;
612#endif
Eric Andersen8401eea2004-08-04 19:16:54 +0000613static struct var *vlist; /* dictionary */
614static struct var *homedir; /* home directory */
615static struct var *prompt; /* main prompt */
616static struct var *cprompt; /* continuation prompt */
617static struct var *path; /* search path for commands */
618static struct var *shell; /* shell to interpret command files */
619static struct var *ifs; /* field separators */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000620
Denis Vlasenko95cb3262007-04-09 03:06:34 +0000621static int areanum; /* current allocation area */
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000622static smallint intr; /* interrupt pending (bool) */
623static smallint heedint = 1; /* heed interrupt signals (bool) */
Eric Andersen8401eea2004-08-04 19:16:54 +0000624static int inparse;
Denis Vlasenko95cb3262007-04-09 03:06:34 +0000625static char *null = (char*)""; /* null value for variable */
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +0000626static void (*qflag)(int) = SIG_IGN;
Eric Andersen8401eea2004-08-04 19:16:54 +0000627static int startl;
628static int peeksym;
629static int nlseen;
630static int iounit = IODEFAULT;
631static YYSTYPE yylval;
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000632static char *elinep; /* done in main(): = line + sizeof(line) - 5 */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000633
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000634static struct here *inhere; /* list of hear docs while parsing */
635static struct here *acthere; /* list of active here documents */
636static struct region *areabot; /* bottom of area */
637static struct region *areatop; /* top of area */
638static struct region *areanxt; /* starting point of scan */
Eric Andersen8401eea2004-08-04 19:16:54 +0000639static void *brktop;
640static void *brkaddr;
Eric Andersenff9eee42001-06-29 04:57:14 +0000641
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000642#define AFID_NOBUF (~0)
643#define AFID_ID 0
644
645
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000646/*
647 * parsing & execution environment
648 */
649struct env {
650 char *linep;
651 struct io *iobase;
652 struct io *iop;
653 xint *errpt; /* void * */
654 int iofd;
655 struct env *oenv;
656};
657
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000658
659struct globals {
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000660 struct env global_env;
661 struct ioarg temparg; // = { .afid = AFID_NOBUF }; /* temporary for PUSHIO */
662 unsigned bufid; // = AFID_ID; /* buffer id counter */
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000663 char ourtrap[_NSIG + 1];
664 char *trap[_NSIG + 1];
665 struct iobuf sharedbuf; /* in main(): set to { AFID_NOBUF } */
666 struct iobuf mainbuf; /* in main(): set to { AFID_NOBUF } */
667 struct ioarg ioargstack[NPUSH];
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000668 /*
669 * flags:
670 * -e: quit on error
671 * -k: look for name=value everywhere on command line
672 * -n: no execution
673 * -t: exit after reading and executing one command
674 * -v: echo as read
675 * -x: trace
676 * -u: unset variables net diagnostic
677 */
678 char flags['z' - 'a' + 1];
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000679 char filechar_cmdbuf[BUFSIZ];
680 char line[LINELIM];
681 char child_cmd[LINELIM];
Denis Vlasenkoab801872007-12-02 08:35:37 +0000682
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000683 struct io iostack[NPUSH];
684
Denis Vlasenkoab801872007-12-02 08:35:37 +0000685 char grave__var_name[LINELIM];
686 char grave__alt_value[LINELIM];
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000687};
688
689#define G (*ptr_to_globals)
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000690#define global_env (G.global_env )
691#define temparg (G.temparg )
692#define bufid (G.bufid )
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000693#define ourtrap (G.ourtrap )
694#define trap (G.trap )
695#define sharedbuf (G.sharedbuf )
696#define mainbuf (G.mainbuf )
697#define ioargstack (G.ioargstack )
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000698/* this looks weird, but is OK ... we index FLAG with 'a'...'z' */
699#define FLAG (G.flags - 'a' )
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000700#define filechar_cmdbuf (G.filechar_cmdbuf)
701#define line (G.line )
702#define child_cmd (G.child_cmd )
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000703#define iostack (G.iostack )
Denis Vlasenkoab801872007-12-02 08:35:37 +0000704#define INIT_G() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000705 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000706 global_env.linep = line; \
707 global_env.iobase = iostack; \
708 global_env.iop = iostack - 1; \
709 global_env.iofd = FDBASE; \
710 temparg.afid = AFID_NOBUF; \
711 bufid = AFID_ID; \
Denis Vlasenkoab801872007-12-02 08:35:37 +0000712} while (0)
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000713
714
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000715/* in substitution */
716#define INSUB() (global_env.iop->task == XGRAVE || global_env.iop->task == XDOLL)
717
718#define RUN(what, arg, gen) ((temparg.what = (arg)), run(&temparg, (gen)))
719
Eric Andersen12de6cf2004-08-04 19:19:10 +0000720#ifdef MSHDEBUG
Denis Vlasenko509697f2008-03-02 12:49:39 +0000721static void print_tree(struct op *head)
Eric Andersen12de6cf2004-08-04 19:19:10 +0000722{
723 if (head == NULL) {
724 DBGPRINTF(("PRINT_TREE: no tree\n"));
725 return;
726 }
727
Denis Vlasenkoed9d6212008-06-09 07:44:19 +0000728 DBGPRINTF(("NODE: %p, left %p, right %p\n", head, head->left,
Eric Andersen12de6cf2004-08-04 19:19:10 +0000729 head->right));
730
731 if (head->left)
732 print_tree(head->left);
733
734 if (head->right)
735 print_tree(head->right);
Eric Andersen12de6cf2004-08-04 19:19:10 +0000736}
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000737#endif /* MSHDEBUG */
738
739
740/*
741 * IO functions
742 */
743static void prs(const char *s)
744{
745 if (*s)
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +0000746 write(STDERR_FILENO, s, strlen(s));
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000747}
748
749static void prn(unsigned u)
750{
751 prs(itoa(u));
752}
753
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000754static void echo(char **wp)
755{
756 int i;
757
758 prs("+");
759 for (i = 0; wp[i]; i++) {
760 if (i)
761 prs(" ");
762 prs(wp[i]);
763 }
764 prs("\n");
765}
766
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000767static void closef(int i)
768{
769 if (i > 2)
770 close(i);
771}
772
773static void closeall(void)
774{
775 int u;
776
777 for (u = NUFILE; u < NOFILE;)
778 close(u++);
779}
Eric Andersen12de6cf2004-08-04 19:19:10 +0000780
Eric Andersenff9eee42001-06-29 04:57:14 +0000781
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000782/* fail but return to process next command */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000783static void fail(void) NORETURN;
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000784static void fail(void)
785{
786 longjmp(failpt, 1);
787 /* NOTREACHED */
788}
Eric Andersenff9eee42001-06-29 04:57:14 +0000789
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000790/* abort shell (or fail in subshell) */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000791static void leave(void) NORETURN;
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000792static void leave(void)
793{
794 DBGPRINTF(("LEAVE: leave called!\n"));
795
796 if (execflg)
797 fail();
798 scraphere();
799 freehere(1);
800 runtrap(0);
801 _exit(exstat);
802 /* NOTREACHED */
803}
804
805static void warn(const char *s)
806{
807 if (*s) {
808 prs(s);
Denis Vlasenko447bd662008-05-30 22:28:32 +0000809 if (!exstat)
810 exstat = 255;
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000811 }
812 prs("\n");
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +0000813 if (FLAG['e'])
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000814 leave();
815}
816
817static void err(const char *s)
818{
819 warn(s);
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +0000820 if (FLAG['n'])
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000821 return;
822 if (!interactive)
823 leave();
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000824 if (global_env.errpt)
825 longjmp(global_env.errpt, 1);
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000826 closeall();
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000827 global_env.iop = global_env.iobase = iostack;
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000828}
829
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000830
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000831/* -------- area.c -------- */
832
Eric Andersenff9eee42001-06-29 04:57:14 +0000833/*
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000834 * All memory between (char *)areabot and (char *)(areatop+1) is
835 * exclusively administered by the area management routines.
836 * It is assumed that sbrk() and brk() manipulate the high end.
Eric Andersenff9eee42001-06-29 04:57:14 +0000837 */
838
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000839#define sbrk(X) ({ \
840 void * __q = (void *)-1; \
841 if (brkaddr + (int)(X) < brktop) { \
842 __q = brkaddr; \
843 brkaddr += (int)(X); \
844 } \
845 __q; \
846})
Eric Andersenff9eee42001-06-29 04:57:14 +0000847
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000848static void initarea(void)
Eric Andersenff9eee42001-06-29 04:57:14 +0000849{
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000850 brkaddr = xmalloc(AREASIZE);
851 brktop = brkaddr + AREASIZE;
Eric Andersenff9eee42001-06-29 04:57:14 +0000852
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000853 while ((long) sbrk(0) & ALIGN)
854 sbrk(1);
855 areabot = (struct region *) sbrk(REGSIZE);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +0000856
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000857 areabot->next = areabot;
858 areabot->area = BUSY;
859 areatop = areabot;
860 areanxt = areabot;
Eric Andersenff9eee42001-06-29 04:57:14 +0000861}
862
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000863static char *getcell(unsigned nbytes)
864{
865 int nregio;
866 struct region *p, *q;
867 int i;
868
869 if (nbytes == 0) {
870 puts("getcell(0)");
871 abort();
872 }
873 /* silly and defeats the algorithm */
874 /*
875 * round upwards and add administration area
876 */
877 nregio = (nbytes + (REGSIZE - 1)) / REGSIZE + 1;
878 p = areanxt;
879 for (;;) {
880 if (p->area > areanum) {
881 /*
882 * merge free cells
883 */
884 while ((q = p->next)->area > areanum && q != areanxt)
885 p->next = q->next;
886 /*
887 * exit loop if cell big enough
888 */
889 if (q >= p + nregio)
890 goto found;
891 }
892 p = p->next;
893 if (p == areanxt)
894 break;
895 }
896 i = nregio >= GROWBY ? nregio : GROWBY;
897 p = (struct region *) sbrk(i * REGSIZE);
898 if (p == (struct region *) -1)
899 return NULL;
900 p--;
901 if (p != areatop) {
902 puts("not contig");
903 abort(); /* allocated areas are contiguous */
904 }
905 q = p + i;
906 p->next = q;
907 p->area = FREE;
908 q->next = areabot;
909 q->area = BUSY;
910 areatop = q;
911 found:
912 /*
913 * we found a FREE area big enough, pointed to by 'p', and up to 'q'
914 */
915 areanxt = p + nregio;
916 if (areanxt < q) {
917 /*
918 * split into requested area and rest
919 */
920 if (areanxt + 1 > q) {
921 puts("OOM");
922 abort(); /* insufficient space left for admin */
923 }
924 areanxt->next = q;
925 areanxt->area = FREE;
926 p->next = areanxt;
927 }
928 p->area = areanum;
929 return (char *) (p + 1);
930}
931
932static void freecell(char *cp)
933{
934 struct region *p;
935
936 p = (struct region *) cp;
937 if (p != NULL) {
938 p--;
939 if (p < areanxt)
940 areanxt = p;
941 p->area = FREE;
942 }
943}
944#define DELETE(obj) freecell((char *)obj)
945
946static void freearea(int a)
947{
948 struct region *p, *top;
949
950 top = areatop;
951 for (p = areabot; p != top; p = p->next)
952 if (p->area >= a)
953 p->area = FREE;
954}
955
956static void setarea(char *cp, int a)
957{
958 struct region *p;
959
960 p = (struct region *) cp;
961 if (p != NULL)
962 (p - 1)->area = a;
963}
964
965static int getarea(char *cp)
966{
967 return ((struct region *) cp - 1)->area;
968}
969
970static void garbage(void)
971{
972 struct region *p, *q, *top;
973
974 top = areatop;
975 for (p = areabot; p != top; p = p->next) {
976 if (p->area > areanum) {
977 while ((q = p->next)->area > areanum)
978 p->next = q->next;
979 areanxt = p;
980 }
981 }
982#ifdef SHRINKBY
983 if (areatop >= q + SHRINKBY && q->area > areanum) {
984 brk((char *) (q + 1));
985 q->next = areabot;
986 q->area = BUSY;
987 areatop = q;
988 }
989#endif
990}
991
Denis Vlasenko509697f2008-03-02 12:49:39 +0000992static void *get_space(int n)
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000993{
994 char *cp;
995
996 cp = getcell(n);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000997 if (cp == NULL)
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000998 err("out of string space");
999 return cp;
1000}
1001
1002static char *strsave(const char *s, int a)
1003{
1004 char *cp;
1005
Denis Vlasenko509697f2008-03-02 12:49:39 +00001006 cp = get_space(strlen(s) + 1);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001007 if (cp == NULL) {
1008// FIXME: I highly doubt this is good.
1009 return (char*)"";
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001010 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001011 setarea(cp, a);
1012 strcpy(cp, s);
1013 return cp;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001014}
1015
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001016
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001017/* -------- var.c -------- */
1018
1019static int eqname(const char *n1, const char *n2)
1020{
1021 for (; *n1 != '=' && *n1 != '\0'; n1++)
1022 if (*n2++ != *n1)
1023 return 0;
1024 return *n2 == '\0' || *n2 == '=';
1025}
1026
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001027static const char *findeq(const char *cp)
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001028{
1029 while (*cp != '\0' && *cp != '=')
1030 cp++;
1031 return cp;
1032}
1033
1034/*
1035 * Find the given name in the dictionary
1036 * and return its value. If the name was
1037 * not previously there, enter it now and
1038 * return a null value.
1039 */
1040static struct var *lookup(const char *n)
1041{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001042// FIXME: dirty hack
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001043 static struct var dummy;
1044
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001045 struct var *vp;
1046 const char *cp;
1047 char *xp;
1048 int c;
1049
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001050 if (isdigit(*n)) {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001051 dummy.name = (char*)n;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001052 for (c = 0; isdigit(*n) && c < 1000; n++)
1053 c = c * 10 + *n - '0';
1054 dummy.status = RONLY;
1055 dummy.value = (c <= dolc ? dolv[c] : null);
1056 return &dummy;
1057 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001058
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001059 for (vp = vlist; vp; vp = vp->next)
1060 if (eqname(vp->name, n))
1061 return vp;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001062
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001063 cp = findeq(n);
Denis Vlasenko509697f2008-03-02 12:49:39 +00001064 vp = get_space(sizeof(*vp));
1065 if (vp == 0 || (vp->name = get_space((int) (cp - n) + 2)) == NULL) {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001066 dummy.name = dummy.value = (char*)"";
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001067 return &dummy;
1068 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001069
1070 xp = vp->name;
1071 while ((*xp = *n++) != '\0' && *xp != '=')
1072 xp++;
1073 *xp++ = '=';
1074 *xp = '\0';
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001075 setarea((char *) vp, 0);
1076 setarea((char *) vp->name, 0);
1077 vp->value = null;
1078 vp->next = vlist;
1079 vp->status = GETCELL;
1080 vlist = vp;
1081 return vp;
1082}
1083
1084/*
1085 * if name is not NULL, it must be
1086 * a prefix of the space `val',
1087 * and end with `='.
1088 * this is all so that exporting
1089 * values is reasonably painless.
1090 */
1091static void nameval(struct var *vp, const char *val, const char *name)
1092{
1093 const char *cp;
1094 char *xp;
1095 int fl;
1096
1097 if (vp->status & RONLY) {
1098 xp = vp->name;
1099 while (*xp && *xp != '=')
Denis Vlasenko4daad902007-09-27 10:20:47 +00001100 fputc(*xp++, stderr);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001101 err(" is read-only");
1102 return;
1103 }
1104 fl = 0;
1105 if (name == NULL) {
Denis Vlasenko509697f2008-03-02 12:49:39 +00001106 xp = get_space(strlen(vp->name) + strlen(val) + 2);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001107 if (xp == NULL)
1108 return;
1109 /* make string: name=value */
1110 setarea(xp, 0);
1111 name = xp;
1112 cp = vp->name;
1113 while ((*xp = *cp++) != '\0' && *xp != '=')
1114 xp++;
1115 *xp++ = '=';
1116 strcpy(xp, val);
1117 val = xp;
1118 fl = GETCELL;
1119 }
1120 if (vp->status & GETCELL)
1121 freecell(vp->name); /* form new string `name=value' */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001122 vp->name = (char*)name;
1123 vp->value = (char*)val;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001124 vp->status |= fl;
1125}
1126
1127/*
1128 * give variable at `vp' the value `val'.
1129 */
1130static void setval(struct var *vp, const char *val)
1131{
1132 nameval(vp, val, NULL);
1133}
1134
1135static void export(struct var *vp)
1136{
1137 vp->status |= EXPORT;
1138}
1139
1140static void ronly(struct var *vp)
1141{
1142 if (isalpha(vp->name[0]) || vp->name[0] == '_') /* not an internal symbol */
1143 vp->status |= RONLY;
1144}
1145
1146static int isassign(const char *s)
1147{
1148 unsigned char c;
1149 DBGPRINTF7(("ISASSIGN: enter, s=%s\n", s));
1150
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001151 c = *s;
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001152 /* no isalpha() - we shouldn't use locale */
1153 /* c | 0x20 - lowercase (Latin) letters */
1154 if (c != '_' && (unsigned)((c|0x20) - 'a') > 25)
1155 /* not letter */
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001156 return 0;
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001157
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001158 while (1) {
1159 c = *++s;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001160 if (c == '=')
1161 return 1;
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001162 if (c == '\0')
1163 return 0;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001164 if (c != '_'
1165 && (unsigned)(c - '0') > 9 /* not number */
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001166 && (unsigned)((c|0x20) - 'a') > 25 /* not letter */
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001167 ) {
1168 return 0;
1169 }
1170 }
1171}
1172
1173static int assign(const char *s, int cf)
1174{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001175 const char *cp;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001176 struct var *vp;
1177
1178 DBGPRINTF7(("ASSIGN: enter, s=%s, cf=%d\n", s, cf));
1179
1180 if (!isalpha(*s) && *s != '_')
1181 return 0;
1182 for (cp = s; *cp != '='; cp++)
1183 if (*cp == '\0' || (!isalnum(*cp) && *cp != '_'))
1184 return 0;
1185 vp = lookup(s);
1186 nameval(vp, ++cp, cf == COPYV ? NULL : s);
1187 if (cf != COPYV)
1188 vp->status &= ~GETCELL;
1189 return 1;
1190}
1191
1192static int checkname(char *cp)
1193{
1194 DBGPRINTF7(("CHECKNAME: enter, cp=%s\n", cp));
1195
1196 if (!isalpha(*cp++) && *(cp - 1) != '_')
1197 return 0;
1198 while (*cp)
1199 if (!isalnum(*cp++) && *(cp - 1) != '_')
1200 return 0;
1201 return 1;
1202}
1203
1204static void putvlist(int f, int out)
1205{
1206 struct var *vp;
1207
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001208 for (vp = vlist; vp; vp = vp->next) {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001209 if (vp->status & f && (isalpha(*vp->name) || *vp->name == '_')) {
1210 if (vp->status & EXPORT)
1211 write(out, "export ", 7);
1212 if (vp->status & RONLY)
1213 write(out, "readonly ", 9);
1214 write(out, vp->name, (int) (findeq(vp->name) - vp->name));
1215 write(out, "\n", 1);
1216 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001217 }
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001218}
1219
1220
1221/*
1222 * trap handling
1223 */
1224static void sig(int i)
1225{
1226 trapset = i;
1227 signal(i, sig);
1228}
1229
1230static void runtrap(int i)
1231{
1232 char *trapstr;
1233
1234 trapstr = trap[i];
1235 if (trapstr == NULL)
1236 return;
1237
1238 if (i == 0)
1239 trap[i] = NULL;
1240
1241 RUN(aword, trapstr, nlchar);
1242}
1243
1244
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001245static void setdash(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001246{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001247 char *cp;
1248 int c;
Eric Andersen8401eea2004-08-04 19:16:54 +00001249 char m['z' - 'a' + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00001250
1251 cp = m;
Eric Andersen8401eea2004-08-04 19:16:54 +00001252 for (c = 'a'; c <= 'z'; c++)
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00001253 if (FLAG[c])
Eric Andersenff9eee42001-06-29 04:57:14 +00001254 *cp++ = c;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001255 *cp = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00001256 setval(lookup("-"), m);
1257}
1258
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001259static int newfile(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00001260{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001261 int f;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001262
1263 DBGPRINTF7(("NEWFILE: opening %s\n", s));
Eric Andersenff9eee42001-06-29 04:57:14 +00001264
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001265 f = 0;
Denis Vlasenko9f739442006-12-16 23:49:13 +00001266 if (NOT_LONE_DASH(s)) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001267 DBGPRINTF(("NEWFILE: s is %s\n", s));
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00001268 f = open(s, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00001269 if (f < 0) {
1270 prs(s);
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00001271 err(": can't open");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001272 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001273 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001274 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001275
Eric Andersenff9eee42001-06-29 04:57:14 +00001276 next(remap(f));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001277 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001278}
1279
Eric Andersen12de6cf2004-08-04 19:19:10 +00001280
Denis Vlasenkobc1918a2008-04-15 01:17:50 +00001281#ifdef UNUSED
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001282struct op *scantree(struct op *head)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001283{
1284 struct op *dotnode;
1285
1286 if (head == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001287 return NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001288
1289 if (head->left != NULL) {
1290 dotnode = scantree(head->left);
1291 if (dotnode)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001292 return dotnode;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001293 }
1294
1295 if (head->right != NULL) {
1296 dotnode = scantree(head->right);
1297 if (dotnode)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001298 return dotnode;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001299 }
1300
Denis Vlasenko509697f2008-03-02 12:49:39 +00001301 if (head->op_words == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001302 return NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001303
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001304 DBGPRINTF5(("SCANTREE: checking node %p\n", head));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001305
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001306 if ((head->op_type != TDOT) && LONE_CHAR(head->op_words[0], '.')) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001307 DBGPRINTF5(("SCANTREE: dot found in node %p\n", head));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001308 return head;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001309 }
1310
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001311 return NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001312}
Denis Vlasenkobc1918a2008-04-15 01:17:50 +00001313#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00001314
1315
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001316static void onecommand(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001317{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001318 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00001319 jmp_buf m1;
1320
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001321 DBGPRINTF(("ONECOMMAND: enter, outtree=%p\n", outtree));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001322
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001323 while (global_env.oenv)
Eric Andersenff9eee42001-06-29 04:57:14 +00001324 quitenv();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001325
Eric Andersenff9eee42001-06-29 04:57:14 +00001326 areanum = 1;
1327 freehere(areanum);
1328 freearea(areanum);
1329 garbage();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001330 wdlist = NULL;
1331 iolist = NULL;
1332 global_env.errpt = NULL;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001333 global_env.linep = line;
Eric Andersenff9eee42001-06-29 04:57:14 +00001334 yynerrs = 0;
1335 multiline = 0;
1336 inparse = 1;
1337 intr = 0;
1338 execflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001339
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001340 failpt = m1;
1341 setjmp(failpt); /* Bruce Evans' fix */
1342 failpt = m1;
1343 if (setjmp(failpt) || yyparse() || intr) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001344 DBGPRINTF(("ONECOMMAND: this is not good.\n"));
1345
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001346 while (global_env.oenv)
Eric Andersenff9eee42001-06-29 04:57:14 +00001347 quitenv();
1348 scraphere();
1349 if (!interactive && intr)
1350 leave();
1351 inparse = 0;
1352 intr = 0;
1353 return;
1354 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001355
Eric Andersenff9eee42001-06-29 04:57:14 +00001356 inparse = 0;
1357 brklist = 0;
1358 intr = 0;
1359 execflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001360
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00001361 if (!FLAG['n']) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001362 DBGPRINTF(("ONECOMMAND: calling execute, t=outtree=%p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00001363 outtree));
Denis Vlasenko7e497522008-02-12 09:51:03 +00001364 execute(outtree, NOPIPE, NOPIPE, /* no_fork: */ 0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001365 }
1366
Eric Andersenff9eee42001-06-29 04:57:14 +00001367 if (!interactive && intr) {
1368 execflg = 0;
1369 leave();
1370 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001371
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001372 i = trapset;
1373 if (i != 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001374 trapset = 0;
1375 runtrap(i);
1376 }
1377}
1378
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001379static int newenv(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00001380{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001381 struct env *ep;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001382
1383 DBGPRINTF(("NEWENV: f=%d (indicates quitenv and return)\n", f));
Eric Andersenff9eee42001-06-29 04:57:14 +00001384
1385 if (f) {
1386 quitenv();
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001387 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001388 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001389
Denis Vlasenko509697f2008-03-02 12:49:39 +00001390 ep = get_space(sizeof(*ep));
Eric Andersenff9eee42001-06-29 04:57:14 +00001391 if (ep == NULL) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001392 while (global_env.oenv)
Eric Andersenff9eee42001-06-29 04:57:14 +00001393 quitenv();
1394 fail();
1395 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001396 *ep = global_env;
1397 global_env.oenv = ep;
1398 global_env.errpt = errpt;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001399
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001400 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001401}
1402
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001403static void quitenv(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001404{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001405 struct env *ep;
1406 int fd;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001407
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001408 DBGPRINTF(("QUITENV: global_env.oenv=%p\n", global_env.oenv));
Eric Andersenff9eee42001-06-29 04:57:14 +00001409
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001410 ep = global_env.oenv;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001411 if (ep != NULL) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001412 fd = global_env.iofd;
1413 global_env = *ep;
Eric Andersenff9eee42001-06-29 04:57:14 +00001414 /* should close `'d files */
1415 DELETE(ep);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001416 while (--fd >= global_env.iofd)
Eric Andersenff9eee42001-06-29 04:57:14 +00001417 close(fd);
1418 }
1419}
1420
1421/*
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001422 * Is character c in s?
Eric Andersenff9eee42001-06-29 04:57:14 +00001423 */
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001424static int any(int c, const char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00001425{
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001426 while (*s)
1427 if (*s++ == c)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001428 return 1;
1429 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001430}
1431
1432/*
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001433 * Is any character from s1 in s2?
Eric Andersenff9eee42001-06-29 04:57:14 +00001434 */
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001435static int anys(const char *s1, const char *s2)
Eric Andersenff9eee42001-06-29 04:57:14 +00001436{
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001437 while (*s1)
1438 if (any(*s1++, s2))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001439 return 1;
1440 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001441}
1442
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001443static char *putn(int n)
Eric Andersenff9eee42001-06-29 04:57:14 +00001444{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001445 return itoa(n);
Eric Andersenff9eee42001-06-29 04:57:14 +00001446}
1447
Eric Andersen8401eea2004-08-04 19:16:54 +00001448static void next(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00001449{
1450 PUSHIO(afile, f, filechar);
1451}
1452
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001453static void onintr(int s UNUSED_PARAM) /* ANSI C requires a parameter */
Eric Andersenff9eee42001-06-29 04:57:14 +00001454{
1455 signal(SIGINT, onintr);
1456 intr = 1;
1457 if (interactive) {
1458 if (inparse) {
1459 prs("\n");
1460 fail();
1461 }
Eric Andersen8401eea2004-08-04 19:16:54 +00001462 } else if (heedint) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001463 execflg = 0;
1464 leave();
1465 }
1466}
1467
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001468
Eric Andersenff9eee42001-06-29 04:57:14 +00001469/* -------- gmatch.c -------- */
1470/*
1471 * int gmatch(string, pattern)
1472 * char *string, *pattern;
1473 *
1474 * Match a pattern as in sh(1).
1475 */
1476
1477#define CMASK 0377
1478#define QUOTE 0200
Denis Vlasenko55f30b02007-03-24 22:42:29 +00001479#define QMASK (CMASK & ~QUOTE)
Eric Andersen8401eea2004-08-04 19:16:54 +00001480#define NOT '!' /* might use ^ */
Eric Andersenff9eee42001-06-29 04:57:14 +00001481
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001482static const char *cclass(const char *p, int sub)
1483{
1484 int c, d, not, found;
1485
1486 not = (*p == NOT);
1487 if (not != 0)
1488 p++;
1489 found = not;
1490 do {
1491 if (*p == '\0')
1492 return NULL;
1493 c = *p & CMASK;
1494 if (p[1] == '-' && p[2] != ']') {
1495 d = p[2] & CMASK;
1496 p++;
1497 } else
1498 d = c;
1499 if (c == sub || (c <= sub && sub <= d))
1500 found = !not;
1501 } while (*++p != ']');
1502 return found ? p + 1 : NULL;
1503}
1504
1505static int gmatch(const char *s, const char *p)
Eric Andersenff9eee42001-06-29 04:57:14 +00001506{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001507 int sc, pc;
Eric Andersenff9eee42001-06-29 04:57:14 +00001508
1509 if (s == NULL || p == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001510 return 0;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001511
Eric Andersenff9eee42001-06-29 04:57:14 +00001512 while ((pc = *p++ & CMASK) != '\0') {
1513 sc = *s++ & QMASK;
1514 switch (pc) {
1515 case '[':
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001516 p = cclass(p, sc);
1517 if (p == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001518 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001519 break;
1520
1521 case '?':
1522 if (sc == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001523 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001524 break;
1525
1526 case '*':
1527 s--;
1528 do {
1529 if (*p == '\0' || gmatch(s, p))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001530 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001531 } while (*s++ != '\0');
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001532 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001533
1534 default:
Eric Andersen8401eea2004-08-04 19:16:54 +00001535 if (sc != (pc & ~QUOTE))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001536 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001537 }
1538 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001539 return *s == '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00001540}
1541
Eric Andersenff9eee42001-06-29 04:57:14 +00001542
Eric Andersenff9eee42001-06-29 04:57:14 +00001543/* -------- csyn.c -------- */
1544/*
1545 * shell: syntax (C version)
1546 */
1547
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001548static void yyerror(const char *s) NORETURN;
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001549static void yyerror(const char *s)
1550{
Denis Vlasenko648b44f2008-02-12 06:04:06 +00001551 yynerrs = 1;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001552 if (interactive && global_env.iop <= iostack) {
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001553 multiline = 0;
Denis Vlasenko648b44f2008-02-12 06:04:06 +00001554 while (eofc() == 0 && yylex(0) != '\n')
1555 continue;
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001556 }
1557 err(s);
1558 fail();
1559}
1560
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001561static void zzerr(void) NORETURN;
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001562static void zzerr(void)
1563{
1564 yyerror("syntax error");
1565}
1566
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001567int yyparse(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001568{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001569 DBGPRINTF7(("YYPARSE: enter...\n"));
1570
Eric Andersen8401eea2004-08-04 19:16:54 +00001571 startl = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001572 peeksym = 0;
1573 yynerrs = 0;
1574 outtree = c_list();
1575 musthave('\n', 0);
Denis Vlasenko648b44f2008-02-12 06:04:06 +00001576 return yynerrs; /* 0/1 */
Eric Andersenff9eee42001-06-29 04:57:14 +00001577}
1578
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001579static struct op *pipeline(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001580{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001581 struct op *t, *p;
1582 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001583
1584 DBGPRINTF7(("PIPELINE: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001585
1586 t = command(cf);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001587
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001588 DBGPRINTF9(("PIPELINE: t=%p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001589
Eric Andersenff9eee42001-06-29 04:57:14 +00001590 if (t != NULL) {
1591 while ((c = yylex(0)) == '|') {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001592 p = command(CONTIN);
1593 if (p == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001594 DBGPRINTF8(("PIPELINE: error!\n"));
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001595 zzerr();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001596 }
1597
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001598 if (t->op_type != TPAREN && t->op_type != TCOM) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001599 /* shell statement */
1600 t = block(TPAREN, t, NOBLOCK, NOWORDS);
1601 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001602
Eric Andersenff9eee42001-06-29 04:57:14 +00001603 t = block(TPIPE, t, p, NOWORDS);
1604 }
1605 peeksym = c;
1606 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001607
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001608 DBGPRINTF7(("PIPELINE: returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001609 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001610}
1611
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001612static struct op *andor(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001613{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001614 struct op *t, *p;
1615 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001616
1617 DBGPRINTF7(("ANDOR: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001618
1619 t = pipeline(0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001620
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001621 DBGPRINTF9(("ANDOR: t=%p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001622
Eric Andersenff9eee42001-06-29 04:57:14 +00001623 if (t != NULL) {
1624 while ((c = yylex(0)) == LOGAND || c == LOGOR) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001625 p = pipeline(CONTIN);
1626 if (p == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001627 DBGPRINTF8(("ANDOR: error!\n"));
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001628 zzerr();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001629 }
1630
Eric Andersen8401eea2004-08-04 19:16:54 +00001631 t = block(c == LOGAND ? TAND : TOR, t, p, NOWORDS);
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001632 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001633
Eric Andersenff9eee42001-06-29 04:57:14 +00001634 peeksym = c;
1635 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001636
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001637 DBGPRINTF7(("ANDOR: returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001638 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001639}
1640
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001641static struct op *c_list(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001642{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001643 struct op *t, *p;
1644 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001645
1646 DBGPRINTF7(("C_LIST: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001647
1648 t = andor();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001649
Eric Andersenff9eee42001-06-29 04:57:14 +00001650 if (t != NULL) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001651 peeksym = yylex(0);
1652 if (peeksym == '&')
Eric Andersenff9eee42001-06-29 04:57:14 +00001653 t = block(TASYNC, t, NOBLOCK, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001654
Eric Andersen8401eea2004-08-04 19:16:54 +00001655 while ((c = yylex(0)) == ';' || c == '&'
Denis Vlasenko509697f2008-03-02 12:49:39 +00001656 || (multiline && c == '\n')
1657 ) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001658 p = andor();
1659 if (p== NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001660 return t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001661
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001662 peeksym = yylex(0);
1663 if (peeksym == '&')
Eric Andersenff9eee42001-06-29 04:57:14 +00001664 p = block(TASYNC, p, NOBLOCK, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001665
Eric Andersenff9eee42001-06-29 04:57:14 +00001666 t = list(t, p);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001667 } /* WHILE */
1668
Eric Andersenff9eee42001-06-29 04:57:14 +00001669 peeksym = c;
1670 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001671 /* IF */
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001672 DBGPRINTF7(("C_LIST: returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001673 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001674}
1675
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001676static int synio(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001677{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001678 struct ioword *iop;
1679 int i;
1680 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001681
1682 DBGPRINTF7(("SYNIO: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001683
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001684 c = yylex(cf);
1685 if (c != '<' && c != '>') {
Eric Andersenff9eee42001-06-29 04:57:14 +00001686 peeksym = c;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001687 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001688 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001689
Eric Andersenff9eee42001-06-29 04:57:14 +00001690 i = yylval.i;
1691 musthave(WORD, 0);
1692 iop = io(iounit, i, yylval.cp);
1693 iounit = IODEFAULT;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001694
Eric Andersenff9eee42001-06-29 04:57:14 +00001695 if (i & IOHERE)
1696 markhere(yylval.cp, iop);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001697
1698 DBGPRINTF7(("SYNIO: returning 1\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001699 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001700}
1701
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001702static void musthave(int c, int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001703{
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001704 peeksym = yylex(cf);
1705 if (peeksym != c) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001706 DBGPRINTF7(("MUSTHAVE: error!\n"));
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001707 zzerr();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001708 }
1709
Eric Andersenff9eee42001-06-29 04:57:14 +00001710 peeksym = 0;
1711}
1712
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001713static struct op *simple(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001714{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001715 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001716
1717 t = NULL;
1718 for (;;) {
1719 switch (peeksym = yylex(0)) {
1720 case '<':
1721 case '>':
1722 (void) synio(0);
1723 break;
1724
1725 case WORD:
1726 if (t == NULL) {
1727 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001728 t->op_type = TCOM;
Eric Andersenff9eee42001-06-29 04:57:14 +00001729 }
1730 peeksym = 0;
1731 word(yylval.cp);
1732 break;
1733
1734 default:
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001735 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001736 }
1737 }
1738}
1739
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001740static struct op *nested(int type, int mark)
Eric Andersenff9eee42001-06-29 04:57:14 +00001741{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001742 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001743
1744 DBGPRINTF3(("NESTED: enter, type=%d, mark=%d\n", type, mark));
Eric Andersenff9eee42001-06-29 04:57:14 +00001745
1746 multiline++;
1747 t = c_list();
1748 musthave(mark, 0);
1749 multiline--;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001750 return block(type, t, NOBLOCK, NOWORDS);
Eric Andersenff9eee42001-06-29 04:57:14 +00001751}
1752
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001753static struct op *command(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001754{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001755 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001756 struct wdblock *iosave;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001757 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001758
1759 DBGPRINTF(("COMMAND: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001760
1761 iosave = iolist;
1762 iolist = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001763
Eric Andersenff9eee42001-06-29 04:57:14 +00001764 if (multiline)
1765 cf |= CONTIN;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001766
Eric Andersenff9eee42001-06-29 04:57:14 +00001767 while (synio(cf))
1768 cf = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001769
1770 c = yylex(cf);
1771
1772 switch (c) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001773 default:
1774 peeksym = c;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001775 t = simple();
1776 if (t == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001777 if (iolist == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001778 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001779 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001780 t->op_type = TCOM;
Eric Andersenff9eee42001-06-29 04:57:14 +00001781 }
1782 break;
1783
1784 case '(':
1785 t = nested(TPAREN, ')');
1786 break;
1787
1788 case '{':
1789 t = nested(TBRACE, '}');
1790 break;
1791
1792 case FOR:
1793 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001794 t->op_type = TFOR;
Eric Andersenff9eee42001-06-29 04:57:14 +00001795 musthave(WORD, 0);
1796 startl = 1;
1797 t->str = yylval.cp;
1798 multiline++;
Denis Vlasenko509697f2008-03-02 12:49:39 +00001799 t->op_words = wordlist();
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001800 c = yylex(0);
1801 if (c != '\n' && c != ';')
Eric Andersenff9eee42001-06-29 04:57:14 +00001802 peeksym = c;
1803 t->left = dogroup(0);
1804 multiline--;
1805 break;
1806
1807 case WHILE:
1808 case UNTIL:
1809 multiline++;
1810 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001811 t->op_type = (c == WHILE ? TWHILE : TUNTIL);
Eric Andersenff9eee42001-06-29 04:57:14 +00001812 t->left = c_list();
1813 t->right = dogroup(1);
Denis Vlasenko509697f2008-03-02 12:49:39 +00001814 /* t->op_words = NULL; - newtp() did this */
Eric Andersenff9eee42001-06-29 04:57:14 +00001815 multiline--;
1816 break;
1817
1818 case CASE:
1819 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001820 t->op_type = TCASE;
Eric Andersenff9eee42001-06-29 04:57:14 +00001821 musthave(WORD, 0);
1822 t->str = yylval.cp;
1823 startl++;
1824 multiline++;
1825 musthave(IN, CONTIN);
1826 startl++;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001827
Eric Andersenff9eee42001-06-29 04:57:14 +00001828 t->left = caselist();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001829
Eric Andersenff9eee42001-06-29 04:57:14 +00001830 musthave(ESAC, 0);
1831 multiline--;
1832 break;
1833
1834 case IF:
1835 multiline++;
1836 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001837 t->op_type = TIF;
Eric Andersenff9eee42001-06-29 04:57:14 +00001838 t->left = c_list();
1839 t->right = thenpart();
1840 musthave(FI, 0);
1841 multiline--;
1842 break;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001843
1844 case DOT:
1845 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001846 t->op_type = TDOT;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001847
Denis Vlasenko509697f2008-03-02 12:49:39 +00001848 musthave(WORD, 0); /* gets name of file */
Eric Andersen12de6cf2004-08-04 19:19:10 +00001849 DBGPRINTF7(("COMMAND: DOT clause, yylval.cp is %s\n", yylval.cp));
1850
Denis Vlasenko509697f2008-03-02 12:49:39 +00001851 word(yylval.cp); /* add word to wdlist */
1852 word(NOWORD); /* terminate wdlist */
1853 t->op_words = copyw(); /* dup wdlist */
Eric Andersen12de6cf2004-08-04 19:19:10 +00001854 break;
1855
Eric Andersenff9eee42001-06-29 04:57:14 +00001856 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001857
Denis Vlasenko509697f2008-03-02 12:49:39 +00001858 while (synio(0))
1859 continue;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001860
Eric Andersenff9eee42001-06-29 04:57:14 +00001861 t = namelist(t);
1862 iolist = iosave;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001863
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001864 DBGPRINTF(("COMMAND: returning %p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001865
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001866 return t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001867}
1868
Denis Vlasenko68404f12008-03-17 09:00:54 +00001869static struct op *dowholefile(int type /*, int mark*/)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001870{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001871 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001872
Denis Vlasenko68404f12008-03-17 09:00:54 +00001873 DBGPRINTF(("DOWHOLEFILE: enter, type=%d\n", type /*, mark*/));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001874
1875 multiline++;
1876 t = c_list();
1877 multiline--;
1878 t = block(type, t, NOBLOCK, NOWORDS);
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001879 DBGPRINTF(("DOWHOLEFILE: return t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001880 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001881}
1882
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001883static struct op *dogroup(int onlydone)
Eric Andersenff9eee42001-06-29 04:57:14 +00001884{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001885 int c;
1886 struct op *mylist;
Eric Andersenff9eee42001-06-29 04:57:14 +00001887
1888 c = yylex(CONTIN);
1889 if (c == DONE && onlydone)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001890 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001891 if (c != DO)
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001892 zzerr();
Eric Andersenff9eee42001-06-29 04:57:14 +00001893 mylist = c_list();
1894 musthave(DONE, 0);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001895 return mylist;
Eric Andersenff9eee42001-06-29 04:57:14 +00001896}
1897
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001898static struct op *thenpart(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001899{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001900 int c;
1901 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001902
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001903 c = yylex(0);
1904 if (c != THEN) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001905 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001906 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001907 }
1908 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001909 /*t->op_type = 0; - newtp() did this */
Eric Andersenff9eee42001-06-29 04:57:14 +00001910 t->left = c_list();
1911 if (t->left == NULL)
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001912 zzerr();
Eric Andersenff9eee42001-06-29 04:57:14 +00001913 t->right = elsepart();
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001914 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001915}
1916
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001917static struct op *elsepart(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001918{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001919 int c;
1920 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001921
1922 switch (c = yylex(0)) {
1923 case ELSE:
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001924 t = c_list();
1925 if (t == NULL)
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001926 zzerr();
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001927 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001928
1929 case ELIF:
1930 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001931 t->op_type = TELIF;
Eric Andersenff9eee42001-06-29 04:57:14 +00001932 t->left = c_list();
1933 t->right = thenpart();
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001934 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001935
1936 default:
1937 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001938 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001939 }
1940}
1941
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001942static struct op *caselist(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001943{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001944 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001945
1946 t = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001947 while ((peeksym = yylex(CONTIN)) != ESAC) {
1948 DBGPRINTF(("CASELIST, doing yylex, peeksym=%d\n", peeksym));
Eric Andersenff9eee42001-06-29 04:57:14 +00001949 t = list(t, casepart());
Eric Andersen12de6cf2004-08-04 19:19:10 +00001950 }
1951
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001952 DBGPRINTF(("CASELIST, returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001953 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001954}
1955
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001956static struct op *casepart(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001957{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001958 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001959
1960 DBGPRINTF7(("CASEPART: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001961
1962 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001963 t->op_type = TPAT;
Denis Vlasenko509697f2008-03-02 12:49:39 +00001964 t->op_words = pattern();
Eric Andersenff9eee42001-06-29 04:57:14 +00001965 musthave(')', 0);
1966 t->left = c_list();
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001967 peeksym = yylex(CONTIN);
1968 if (peeksym != ESAC)
Eric Andersenff9eee42001-06-29 04:57:14 +00001969 musthave(BREAK, CONTIN);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001970
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001971 DBGPRINTF7(("CASEPART: made newtp(TPAT, t=%p)\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001972
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001973 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001974}
1975
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001976static char **pattern(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001977{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001978 int c, cf;
Eric Andersenff9eee42001-06-29 04:57:14 +00001979
1980 cf = CONTIN;
1981 do {
1982 musthave(WORD, cf);
1983 word(yylval.cp);
1984 cf = 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001985 c = yylex(0);
1986 } while (c == '|');
Eric Andersenff9eee42001-06-29 04:57:14 +00001987 peeksym = c;
1988 word(NOWORD);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001989
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001990 return copyw();
Eric Andersenff9eee42001-06-29 04:57:14 +00001991}
1992
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001993static char **wordlist(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001994{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001995 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00001996
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001997 c = yylex(0);
1998 if (c != IN) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001999 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002000 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00002001 }
2002 startl = 0;
2003 while ((c = yylex(0)) == WORD)
2004 word(yylval.cp);
2005 word(NOWORD);
2006 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002007 return copyw();
Eric Andersenff9eee42001-06-29 04:57:14 +00002008}
2009
2010/*
2011 * supporting functions
2012 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002013static struct op *list(struct op *t1, struct op *t2)
Eric Andersenff9eee42001-06-29 04:57:14 +00002014{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002015 DBGPRINTF7(("LIST: enter, t1=%p, t2=%p\n", t1, t2));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002016
Eric Andersenff9eee42001-06-29 04:57:14 +00002017 if (t1 == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002018 return t2;
Eric Andersenff9eee42001-06-29 04:57:14 +00002019 if (t2 == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002020 return t1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002021
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002022 return block(TLIST, t1, t2, NOWORDS);
Eric Andersenff9eee42001-06-29 04:57:14 +00002023}
2024
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002025static struct op *block(int type, struct op *t1, struct op *t2, char **wp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002026{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002027 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002028
2029 DBGPRINTF7(("BLOCK: enter, type=%d (%s)\n", type, T_CMD_NAMES[type]));
Eric Andersenff9eee42001-06-29 04:57:14 +00002030
2031 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002032 t->op_type = type;
Eric Andersenff9eee42001-06-29 04:57:14 +00002033 t->left = t1;
2034 t->right = t2;
Denis Vlasenko509697f2008-03-02 12:49:39 +00002035 t->op_words = wp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002036
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002037 DBGPRINTF7(("BLOCK: inserted %p between %p and %p\n", t, t1, t2));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002038
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002039 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002040}
2041
Eric Andersen12de6cf2004-08-04 19:19:10 +00002042/* See if given string is a shell multiline (FOR, IF, etc) */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002043static int rlookup(char *n)
Eric Andersenff9eee42001-06-29 04:57:14 +00002044{
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002045 struct res {
2046 char r_name[6];
2047 int16_t r_val;
2048 };
2049 static const struct res restab[] = {
2050 { "for" , FOR },
2051 { "case" , CASE },
2052 { "esac" , ESAC },
2053 { "while", WHILE },
2054 { "do" , DO },
2055 { "done" , DONE },
2056 { "if" , IF },
2057 { "in" , IN },
2058 { "then" , THEN },
2059 { "else" , ELSE },
2060 { "elif" , ELIF },
2061 { "until", UNTIL },
2062 { "fi" , FI },
2063 { ";;" , BREAK },
2064 { "||" , LOGOR },
2065 { "&&" , LOGAND },
2066 { "{" , '{' },
2067 { "}" , '}' },
2068 { "." , DOT },
2069 { },
2070 };
2071
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002072 const struct res *rp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002073
2074 DBGPRINTF7(("RLOOKUP: enter, n is %s\n", n));
Eric Andersenff9eee42001-06-29 04:57:14 +00002075
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002076 for (rp = restab; rp->r_name[0]; rp++)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002077 if (strcmp(rp->r_name, n) == 0) {
2078 DBGPRINTF7(("RLOOKUP: match, returning %d\n", rp->r_val));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002079 return rp->r_val; /* Return numeric code for shell multiline */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002080 }
2081
2082 DBGPRINTF7(("RLOOKUP: NO match, returning 0\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002083 return 0; /* Not a shell multiline */
Eric Andersenff9eee42001-06-29 04:57:14 +00002084}
2085
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002086static struct op *newtp(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002087{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002088 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002089
Eric Andersen8401eea2004-08-04 19:16:54 +00002090 t = (struct op *) tree(sizeof(*t));
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002091 memset(t, 0, sizeof(*t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002092
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002093 DBGPRINTF3(("NEWTP: allocated %p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002094
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002095 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002096}
2097
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002098static struct op *namelist(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00002099{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002100 DBGPRINTF7(("NAMELIST: enter, t=%p, type %s, iolist=%p\n", t,
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002101 T_CMD_NAMES[t->op_type], iolist));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002102
Eric Andersenff9eee42001-06-29 04:57:14 +00002103 if (iolist) {
Eric Andersen8401eea2004-08-04 19:16:54 +00002104 iolist = addword((char *) NULL, iolist);
Eric Andersenff9eee42001-06-29 04:57:14 +00002105 t->ioact = copyio();
2106 } else
2107 t->ioact = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002108
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002109 if (t->op_type != TCOM) {
2110 if (t->op_type != TPAREN && t->ioact != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002111 t = block(TPAREN, t, NOBLOCK, NOWORDS);
2112 t->ioact = t->left->ioact;
2113 t->left->ioact = NULL;
2114 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002115 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002116 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002117
Eric Andersenff9eee42001-06-29 04:57:14 +00002118 word(NOWORD);
Denis Vlasenko509697f2008-03-02 12:49:39 +00002119 t->op_words = copyw();
Eric Andersen12de6cf2004-08-04 19:19:10 +00002120
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002121 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002122}
2123
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002124static char **copyw(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002125{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002126 char **wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00002127
2128 wd = getwords(wdlist);
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002129 wdlist = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002130 return wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00002131}
2132
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002133static void word(char *cp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002134{
2135 wdlist = addword(cp, wdlist);
2136}
2137
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002138static struct ioword **copyio(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002139{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002140 struct ioword **iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002141
2142 iop = (struct ioword **) getwords(iolist);
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002143 iolist = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002144 return iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002145}
2146
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002147static struct ioword *io(int u, int f, char *cp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002148{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002149 struct ioword *iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002150
2151 iop = (struct ioword *) tree(sizeof(*iop));
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002152 iop->io_fd = u;
Eric Andersenff9eee42001-06-29 04:57:14 +00002153 iop->io_flag = f;
2154 iop->io_name = cp;
Eric Andersen8401eea2004-08-04 19:16:54 +00002155 iolist = addword((char *) iop, iolist);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002156 return iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002157}
2158
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002159static int yylex(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00002160{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002161 int c, c1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002162 int atstart;
2163
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002164 c = peeksym;
2165 if (c > 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002166 peeksym = 0;
2167 if (c == '\n')
2168 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002169 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002170 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002171
Eric Andersenff9eee42001-06-29 04:57:14 +00002172 nlseen = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002173 atstart = startl;
2174 startl = 0;
2175 yylval.i = 0;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002176 global_env.linep = line;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002177
2178/* MALAMO */
2179 line[LINELIM - 1] = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00002180
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002181 loop:
Eric Andersen12de6cf2004-08-04 19:19:10 +00002182 while ((c = my_getc(0)) == ' ' || c == '\t') /* Skip whitespace */
Denis Vlasenko509697f2008-03-02 12:49:39 +00002183 continue;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002184
Eric Andersenff9eee42001-06-29 04:57:14 +00002185 switch (c) {
2186 default:
2187 if (any(c, "0123456789")) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002188 c1 = my_getc(0);
2189 unget(c1);
Eric Andersenff9eee42001-06-29 04:57:14 +00002190 if (c1 == '<' || c1 == '>') {
2191 iounit = c - '0';
2192 goto loop;
2193 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002194 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002195 c = c1;
2196 }
2197 break;
2198
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002199 case '#': /* Comment, skip to next newline or End-of-string */
Denis Vlasenko509697f2008-03-02 12:49:39 +00002200 while ((c = my_getc(0)) != '\0' && c != '\n')
2201 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00002202 unget(c);
2203 goto loop;
2204
2205 case 0:
Eric Andersen12de6cf2004-08-04 19:19:10 +00002206 DBGPRINTF5(("YYLEX: return 0, c=%d\n", c));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002207 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002208
2209 case '$':
Eric Andersen12de6cf2004-08-04 19:19:10 +00002210 DBGPRINTF9(("YYLEX: found $\n"));
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002211 *global_env.linep++ = c;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002212 c = my_getc(0);
2213 if (c == '{') {
2214 c = collect(c, '}');
2215 if (c != '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002216 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002217 goto pack;
2218 }
2219 break;
2220
2221 case '`':
2222 case '\'':
2223 case '"':
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002224 c = collect(c, c);
2225 if (c != '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002226 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002227 goto pack;
2228
2229 case '|':
2230 case '&':
2231 case ';':
Eric Andersenff9eee42001-06-29 04:57:14 +00002232 startl = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002233 /* If more chars process them, else return NULL char */
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002234 c1 = dual(c);
2235 if (c1 != '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002236 return c1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002237 return c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002238
Eric Andersenff9eee42001-06-29 04:57:14 +00002239 case '^':
2240 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002241 return '|';
Eric Andersenff9eee42001-06-29 04:57:14 +00002242 case '>':
2243 case '<':
2244 diag(c);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002245 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002246
2247 case '\n':
2248 nlseen++;
2249 gethere();
2250 startl = 1;
2251 if (multiline || cf & CONTIN) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002252 if (interactive && global_env.iop <= iostack) {
Denis Vlasenko38f63192007-01-22 09:03:07 +00002253#if ENABLE_FEATURE_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00002254 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00002255#else
Eric Andersen8401eea2004-08-04 19:16:54 +00002256 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00002257#endif
2258 }
2259 if (cf & CONTIN)
2260 goto loop;
2261 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002262 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002263
2264 case '(':
2265 case ')':
2266 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002267 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002268 }
2269
2270 unget(c);
2271
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002272 pack:
2273 while ((c = my_getc(0)) != '\0' && !any(c, "`$ '\"\t;&<>()|^\n")) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002274 if (global_env.linep >= elinep)
Eric Andersenff9eee42001-06-29 04:57:14 +00002275 err("word too long");
2276 else
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002277 *global_env.linep++ = c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002278 };
2279
Eric Andersenff9eee42001-06-29 04:57:14 +00002280 unget(c);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002281
Eric Andersen8401eea2004-08-04 19:16:54 +00002282 if (any(c, "\"'`$"))
Eric Andersenff9eee42001-06-29 04:57:14 +00002283 goto loop;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002284
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002285 *global_env.linep++ = '\0';
Eric Andersen12de6cf2004-08-04 19:19:10 +00002286
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002287 if (atstart) {
2288 c = rlookup(line);
2289 if (c != 0) {
2290 startl = 1;
2291 return c;
2292 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002293 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002294
Eric Andersenff9eee42001-06-29 04:57:14 +00002295 yylval.cp = strsave(line, areanum);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002296 return WORD;
Eric Andersenff9eee42001-06-29 04:57:14 +00002297}
2298
Eric Andersen12de6cf2004-08-04 19:19:10 +00002299
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002300static int collect(int c, int c1)
Eric Andersenff9eee42001-06-29 04:57:14 +00002301{
2302 char s[2];
2303
Eric Andersen12de6cf2004-08-04 19:19:10 +00002304 DBGPRINTF8(("COLLECT: enter, c=%d, c1=%d\n", c, c1));
2305
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002306 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002307 while ((c = my_getc(c1)) != c1) {
2308 if (c == 0) {
2309 unget(c);
2310 s[0] = c1;
2311 s[1] = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00002312 prs("no closing ");
2313 yyerror(s);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002314 return YYERRCODE;
Eric Andersenff9eee42001-06-29 04:57:14 +00002315 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002316 if (interactive && c == '\n' && global_env.iop <= iostack) {
Denis Vlasenko38f63192007-01-22 09:03:07 +00002317#if ENABLE_FEATURE_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00002318 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00002319#else
Eric Andersen8401eea2004-08-04 19:16:54 +00002320 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00002321#endif
2322 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002323 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002324 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002325
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002326 *global_env.linep++ = c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002327
2328 DBGPRINTF8(("COLLECT: return 0, line is %s\n", line));
2329
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002330 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002331}
2332
Eric Andersen12de6cf2004-08-04 19:19:10 +00002333/* "multiline commands" helper func */
2334/* see if next 2 chars form a shell multiline */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002335static int dual(int c)
Eric Andersenff9eee42001-06-29 04:57:14 +00002336{
2337 char s[3];
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002338 char *cp = s;
Eric Andersenff9eee42001-06-29 04:57:14 +00002339
Eric Andersen12de6cf2004-08-04 19:19:10 +00002340 DBGPRINTF8(("DUAL: enter, c=%d\n", c));
2341
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002342 *cp++ = c; /* c is the given "peek" char */
2343 *cp++ = my_getc(0); /* get next char of input */
2344 *cp = '\0'; /* add EOS marker */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002345
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002346 c = rlookup(s); /* see if 2 chars form a shell multiline */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002347 if (c == 0)
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002348 unget(*--cp); /* String is not a shell multiline, put peek char back */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002349
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002350 return c; /* String is multiline, return numeric multiline (restab) code */
Eric Andersenff9eee42001-06-29 04:57:14 +00002351}
2352
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002353static void diag(int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00002354{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002355 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002356
2357 DBGPRINTF8(("DIAG: enter, ec=%d\n", ec));
Eric Andersenff9eee42001-06-29 04:57:14 +00002358
2359 c = my_getc(0);
2360 if (c == '>' || c == '<') {
2361 if (c != ec)
2362 zzerr();
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002363 yylval.i = (ec == '>' ? IOWRITE | IOCAT : IOHERE);
Eric Andersenff9eee42001-06-29 04:57:14 +00002364 c = my_getc(0);
2365 } else
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002366 yylval.i = (ec == '>' ? IOWRITE : IOREAD);
Eric Andersenff9eee42001-06-29 04:57:14 +00002367 if (c != '&' || yylval.i == IOHERE)
2368 unget(c);
2369 else
2370 yylval.i |= IODUP;
2371}
2372
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002373static char *tree(unsigned size)
Eric Andersenff9eee42001-06-29 04:57:14 +00002374{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002375 char *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002376
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002377 t = getcell(size);
2378 if (t == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002379 DBGPRINTF2(("TREE: getcell(%d) failed!\n", size));
Eric Andersenff9eee42001-06-29 04:57:14 +00002380 prs("command line too complicated\n");
2381 fail();
2382 /* NOTREACHED */
2383 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002384 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002385}
2386
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002387
Eric Andersenff9eee42001-06-29 04:57:14 +00002388/* VARARGS1 */
2389/* ARGSUSED */
2390
2391/* -------- exec.c -------- */
2392
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002393static struct op **find1case(struct op *t, const char *w)
2394{
2395 struct op *t1;
2396 struct op **tp;
2397 char **wp;
2398 char *cp;
2399
2400 if (t == NULL) {
2401 DBGPRINTF3(("FIND1CASE: enter, t==NULL, returning.\n"));
2402 return NULL;
2403 }
2404
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002405 DBGPRINTF3(("FIND1CASE: enter, t->op_type=%d (%s)\n", t->op_type,
2406 T_CMD_NAMES[t->op_type]));
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002407
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002408 if (t->op_type == TLIST) {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002409 tp = find1case(t->left, w);
2410 if (tp != NULL) {
2411 DBGPRINTF3(("FIND1CASE: found one to the left, returning tp=%p\n", tp));
2412 return tp;
2413 }
2414 t1 = t->right; /* TPAT */
2415 } else
2416 t1 = t;
2417
Denis Vlasenko509697f2008-03-02 12:49:39 +00002418 for (wp = t1->op_words; *wp;) {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002419 cp = evalstr(*wp++, DOSUB);
2420 if (cp && gmatch(w, cp)) {
2421 DBGPRINTF3(("FIND1CASE: returning &t1->left= %p.\n",
2422 &t1->left));
2423 return &t1->left;
2424 }
2425 }
2426
2427 DBGPRINTF(("FIND1CASE: returning NULL\n"));
2428 return NULL;
2429}
2430
2431static struct op *findcase(struct op *t, const char *w)
2432{
2433 struct op **tp;
2434
2435 tp = find1case(t, w);
2436 return tp != NULL ? *tp : NULL;
2437}
2438
Eric Andersenff9eee42001-06-29 04:57:14 +00002439/*
2440 * execute tree
2441 */
2442
Denis Vlasenko7e497522008-02-12 09:51:03 +00002443static int execute(struct op *t, int *pin, int *pout, int no_fork)
Eric Andersenff9eee42001-06-29 04:57:14 +00002444{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002445 struct op *t1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002446 volatile int i, rv, a;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002447 const char *cp;
2448 char **wp, **wp2;
Eric Andersenff9eee42001-06-29 04:57:14 +00002449 struct var *vp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002450 struct op *outtree_save;
Eric Andersenff9eee42001-06-29 04:57:14 +00002451 struct brkcon bc;
2452
2453#if __GNUC__
2454 /* Avoid longjmp clobbering */
2455 (void) &wp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002456#endif
Eric Andersenff9eee42001-06-29 04:57:14 +00002457
Eric Andersen12de6cf2004-08-04 19:19:10 +00002458 if (t == NULL) {
2459 DBGPRINTF4(("EXECUTE: enter, t==null, returning.\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002460 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002461 }
2462
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002463 DBGPRINTF(("EXECUTE: t=%p, t->op_type=%d (%s), t->op_words is %s\n", t,
2464 t->op_type, T_CMD_NAMES[t->op_type],
Denis Vlasenko509697f2008-03-02 12:49:39 +00002465 ((t->op_words == NULL) ? "NULL" : t->op_words[0])));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002466
Eric Andersenff9eee42001-06-29 04:57:14 +00002467 rv = 0;
2468 a = areanum++;
Denis Vlasenko509697f2008-03-02 12:49:39 +00002469 wp2 = t->op_words;
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002470 wp = (wp2 != NULL)
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002471 ? eval(wp2, t->op_type == TCOM ? DOALL : DOALL & ~DOKEY)
Eric Andersen8401eea2004-08-04 19:16:54 +00002472 : NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00002473
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002474 switch (t->op_type) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002475 case TDOT:
2476 DBGPRINTF3(("EXECUTE: TDOT\n"));
2477
2478 outtree_save = outtree;
2479
Denis Vlasenko509697f2008-03-02 12:49:39 +00002480 newfile(evalstr(t->op_words[0], DOALL));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002481
Denis Vlasenko68404f12008-03-17 09:00:54 +00002482 t->left = dowholefile(TLIST /*, 0*/);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002483 t->right = NULL;
2484
2485 outtree = outtree_save;
2486
2487 if (t->left)
Denis Vlasenko7e497522008-02-12 09:51:03 +00002488 rv = execute(t->left, pin, pout, /* no_fork: */ 0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002489 if (t->right)
Denis Vlasenko7e497522008-02-12 09:51:03 +00002490 rv = execute(t->right, pin, pout, /* no_fork: */ 0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002491 break;
2492
Eric Andersenff9eee42001-06-29 04:57:14 +00002493 case TPAREN:
Denis Vlasenko7e497522008-02-12 09:51:03 +00002494 rv = execute(t->left, pin, pout, /* no_fork: */ 0);
Eric Andersen737f5fb2003-03-14 16:05:59 +00002495 break;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002496
Eric Andersenff9eee42001-06-29 04:57:14 +00002497 case TCOM:
Denis Vlasenko7e497522008-02-12 09:51:03 +00002498 rv = forkexec(t, pin, pout, no_fork, wp);
Eric Andersenff9eee42001-06-29 04:57:14 +00002499 break;
2500
2501 case TPIPE:
2502 {
Eric Andersen8401eea2004-08-04 19:16:54 +00002503 int pv[2];
2504
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002505 rv = openpipe(pv);
2506 if (rv < 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00002507 break;
2508 pv[0] = remap(pv[0]);
2509 pv[1] = remap(pv[1]);
Denis Vlasenko7e497522008-02-12 09:51:03 +00002510 (void) execute(t->left, pin, pv, /* no_fork: */ 0);
2511 rv = execute(t->right, pv, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002512 }
2513 break;
2514
2515 case TLIST:
Denis Vlasenko7e497522008-02-12 09:51:03 +00002516 (void) execute(t->left, pin, pout, /* no_fork: */ 0);
2517 rv = execute(t->right, pin, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002518 break;
2519
2520 case TASYNC:
Eric Andersen8401eea2004-08-04 19:16:54 +00002521 {
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002522 smallint hinteractive = interactive;
Eric Andersenff9eee42001-06-29 04:57:14 +00002523
Eric Andersen12de6cf2004-08-04 19:19:10 +00002524 DBGPRINTF7(("EXECUTE: TASYNC clause, calling vfork()...\n"));
2525
Eric Andersen8401eea2004-08-04 19:16:54 +00002526 i = vfork();
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002527 if (i == 0) { /* child */
Eric Andersen8401eea2004-08-04 19:16:54 +00002528 signal(SIGINT, SIG_IGN);
2529 signal(SIGQUIT, SIG_IGN);
2530 if (interactive)
2531 signal(SIGTERM, SIG_DFL);
2532 interactive = 0;
2533 if (pin == NULL) {
2534 close(0);
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00002535 xopen(bb_dev_null, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00002536 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002537 _exit(execute(t->left, pin, pout, /* no_fork: */ 1));
Eric Andersenff9eee42001-06-29 04:57:14 +00002538 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002539 interactive = hinteractive;
2540 if (i != -1) {
2541 setval(lookup("!"), putn(i));
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002542 closepipe(pin);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002543 if (interactive) {
2544 prs(putn(i));
2545 prs("\n");
2546 }
2547 } else
2548 rv = -1;
2549 setstatus(rv);
Eric Andersenff9eee42001-06-29 04:57:14 +00002550 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002551 break;
2552
2553 case TOR:
2554 case TAND:
Denis Vlasenko7e497522008-02-12 09:51:03 +00002555 rv = execute(t->left, pin, pout, /* no_fork: */ 0);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002556 t1 = t->right;
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002557 if (t1 != NULL && (rv == 0) == (t->op_type == TAND))
Denis Vlasenko7e497522008-02-12 09:51:03 +00002558 rv = execute(t1, pin, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002559 break;
2560
2561 case TFOR:
2562 if (wp == NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00002563 wp = dolv + 1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002564 i = dolc;
2565 if (i < 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00002566 i = 0;
2567 } else {
2568 i = -1;
Denis Vlasenko509697f2008-03-02 12:49:39 +00002569 while (*wp++ != NULL)
2570 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00002571 }
2572 vp = lookup(t->str);
2573 while (setjmp(bc.brkpt))
2574 if (isbreak)
2575 goto broken;
Denis Vlasenko7ae1cc12008-07-20 23:03:23 +00002576 /* Restore areanum value. It may be incremented by execute()
2577 * below, and then "continue" may jump back to setjmp above */
2578 areanum = a + 1;
2579 freearea(areanum + 1);
Eric Andersenff9eee42001-06-29 04:57:14 +00002580 brkset(&bc);
2581 for (t1 = t->left; i-- && *wp != NULL;) {
2582 setval(vp, *wp++);
Denis Vlasenko7e497522008-02-12 09:51:03 +00002583 rv = execute(t1, pin, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002584 }
2585 brklist = brklist->nextlev;
2586 break;
2587
2588 case TWHILE:
2589 case TUNTIL:
2590 while (setjmp(bc.brkpt))
2591 if (isbreak)
2592 goto broken;
Denis Vlasenko7ae1cc12008-07-20 23:03:23 +00002593 /* Restore areanum value. It may be incremented by execute()
2594 * below, and then "continue" may jump back to setjmp above */
2595 areanum = a + 1;
2596 freearea(areanum + 1);
Eric Andersenff9eee42001-06-29 04:57:14 +00002597 brkset(&bc);
2598 t1 = t->left;
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002599 while ((execute(t1, pin, pout, /* no_fork: */ 0) == 0) == (t->op_type == TWHILE))
Denis Vlasenko7e497522008-02-12 09:51:03 +00002600 rv = execute(t->right, pin, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002601 brklist = brklist->nextlev;
2602 break;
2603
2604 case TIF:
2605 case TELIF:
Eric Andersen8401eea2004-08-04 19:16:54 +00002606 if (t->right != NULL) {
Denis Vlasenko7e497522008-02-12 09:51:03 +00002607 rv = !execute(t->left, pin, pout, /* no_fork: */ 0) ?
2608 execute(t->right->left, pin, pout, /* no_fork: */ 0) :
2609 execute(t->right->right, pin, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002610 }
2611 break;
2612
2613 case TCASE:
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002614 cp = evalstr(t->str, DOSUB | DOTRIM);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002615 if (cp == NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00002616 cp = "";
Eric Andersen12de6cf2004-08-04 19:19:10 +00002617
2618 DBGPRINTF7(("EXECUTE: TCASE, t->str is %s, cp is %s\n",
2619 ((t->str == NULL) ? "NULL" : t->str),
2620 ((cp == NULL) ? "NULL" : cp)));
2621
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002622 t1 = findcase(t->left, cp);
2623 if (t1 != NULL) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002624 DBGPRINTF7(("EXECUTE: TCASE, calling execute(t=%p, t1=%p)...\n", t, t1));
Denis Vlasenko7e497522008-02-12 09:51:03 +00002625 rv = execute(t1, pin, pout, /* no_fork: */ 0);
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002626 DBGPRINTF7(("EXECUTE: TCASE, back from execute(t=%p, t1=%p)...\n", t, t1));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002627 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002628 break;
2629
2630 case TBRACE:
2631/*
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002632 iopp = t->ioact;
2633 if (i)
Eric Andersenff9eee42001-06-29 04:57:14 +00002634 while (*iopp)
2635 if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) {
2636 rv = -1;
2637 break;
2638 }
2639*/
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002640 if (rv >= 0) {
2641 t1 = t->left;
2642 if (t1) {
Denis Vlasenko7e497522008-02-12 09:51:03 +00002643 rv = execute(t1, pin, pout, /* no_fork: */ 0);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002644 }
2645 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002646 break;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002647
2648 };
Eric Andersenff9eee42001-06-29 04:57:14 +00002649
Denis Vlasenkoe4712752007-04-14 15:08:41 +00002650 broken:
Denis Vlasenko509697f2008-03-02 12:49:39 +00002651// Restoring op_words is most likely not needed now: see comment in forkexec()
2652// (also take a look at exec builtin (doexec) - it touches t->op_words)
2653 t->op_words = wp2;
Eric Andersenff9eee42001-06-29 04:57:14 +00002654 isbreak = 0;
2655 freehere(areanum);
2656 freearea(areanum);
2657 areanum = a;
2658 if (interactive && intr) {
2659 closeall();
2660 fail();
2661 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002662
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002663 i = trapset;
2664 if (i != 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002665 trapset = 0;
2666 runtrap(i);
2667 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002668
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002669 DBGPRINTF(("EXECUTE: returning from t=%p, rv=%d\n", t, rv));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002670 return rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00002671}
2672
Denis Vlasenkoe4712752007-04-14 15:08:41 +00002673static builtin_func_ptr inbuilt(const char *s)
2674{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002675 const struct builtincmd *bp;
2676
Denis Vlasenko95cb3262007-04-09 03:06:34 +00002677 for (bp = builtincmds; bp->name; bp++)
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002678 if (strcmp(bp->name, s) == 0)
2679 return bp->builtinfunc;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002680 return NULL;
2681}
2682
Denis Vlasenko7e497522008-02-12 09:51:03 +00002683static int forkexec(struct op *t, int *pin, int *pout, int no_fork, char **wp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002684{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002685 pid_t newpid;
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002686 int i;
2687 builtin_func_ptr bltin = NULL;
Denis Vlasenko7e497522008-02-12 09:51:03 +00002688 const char *bltin_name = NULL;
2689 const char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00002690 struct ioword **iopp;
2691 int resetsig;
2692 char **owp;
Denis Vlasenko7e497522008-02-12 09:51:03 +00002693 int forked;
Eric Andersenff9eee42001-06-29 04:57:14 +00002694
2695 int *hpin = pin;
2696 int *hpout = pout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002697 char *hwp;
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002698 smallint hinteractive;
2699 smallint hintr;
2700 smallint hexecflg;
Eric Andersen8401eea2004-08-04 19:16:54 +00002701 struct brkcon *hbrklist;
Eric Andersenff9eee42001-06-29 04:57:14 +00002702
2703#if __GNUC__
2704 /* Avoid longjmp clobbering */
2705 (void) &pin;
2706 (void) &pout;
2707 (void) &wp;
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002708 (void) &bltin;
Eric Andersenff9eee42001-06-29 04:57:14 +00002709 (void) &cp;
2710 (void) &resetsig;
2711 (void) &owp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002712#endif
Eric Andersenff9eee42001-06-29 04:57:14 +00002713
Denis Vlasenko7e497522008-02-12 09:51:03 +00002714 DBGPRINTF(("FORKEXEC: t=%p, pin %p, pout %p, no_fork %d\n", t, pin,
2715 pout, no_fork));
Denis Vlasenko509697f2008-03-02 12:49:39 +00002716 DBGPRINTF7(("FORKEXEC: t->op_words is %s\n",
2717 ((t->op_words == NULL) ? "NULL" : t->op_words[0])));
Eric Andersenff9eee42001-06-29 04:57:14 +00002718 owp = wp;
2719 resetsig = 0;
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002720 if (t->op_type == TCOM) {
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00002721 while (*wp++ != NULL)
2722 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00002723 cp = *wp;
2724
2725 /* strip all initial assignments */
Denis Vlasenko7e497522008-02-12 09:51:03 +00002726 /* FIXME: not correct wrt PATH=yyy command etc */
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00002727 if (FLAG['x']) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002728 DBGPRINTF9(("FORKEXEC: echo'ing, cp=%p, wp=%p, owp=%p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00002729 cp, wp, owp));
Eric Andersen8401eea2004-08-04 19:16:54 +00002730 echo(cp ? wp : owp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002731 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002732
Denis Vlasenko7e497522008-02-12 09:51:03 +00002733 if (cp == NULL) {
2734 if (t->ioact == NULL) {
2735 while ((cp = *owp++) != NULL && assign(cp, COPYV))
2736 continue;
2737 DBGPRINTF(("FORKEXEC: returning setstatus(0)\n"));
2738 return setstatus(0);
2739 }
2740 } else { /* cp != NULL */
2741 bltin_name = cp;
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002742 bltin = inbuilt(cp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002743 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002744 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002745
Denis Vlasenko7e497522008-02-12 09:51:03 +00002746 forked = 0;
Denis Vlasenko509697f2008-03-02 12:49:39 +00002747 // We were pointing t->op_words to temporary (expanded) arg list:
2748 // t->op_words = wp;
Denis Vlasenkofe218832008-03-01 09:35:39 +00002749 // and restored it later (in execute()), but "break"
Denis Vlasenko509697f2008-03-02 12:49:39 +00002750 // longjmps away (at "Run builtin" below), leaving t->op_words clobbered!
Denis Vlasenkofe218832008-03-01 09:35:39 +00002751 // See http://bugs.busybox.net/view.php?id=846.
Denis Vlasenko509697f2008-03-02 12:49:39 +00002752 // Now we do not touch t->op_words, but separately pass wp as param list
Denis Vlasenko42cc3042008-03-24 02:05:58 +00002753 // to builtins
Denis Vlasenko7e497522008-02-12 09:51:03 +00002754 DBGPRINTF(("FORKEXEC: bltin %p, no_fork %d, owp %p\n", bltin,
2755 no_fork, owp));
2756 /* Don't fork if it is a lone builtin (not in pipe)
2757 * OR we are told to _not_ fork */
2758 if ((!bltin || pin || pout) /* not lone bltin AND */
2759 && !no_fork /* not told to avoid fork */
2760 ) {
2761 /* Save values in case child alters them after vfork */
Eric Andersenff9eee42001-06-29 04:57:14 +00002762 hpin = pin;
2763 hpout = pout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002764 hwp = *wp;
2765 hinteractive = interactive;
2766 hintr = intr;
2767 hbrklist = brklist;
2768 hexecflg = execflg;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002769
Eric Andersen12de6cf2004-08-04 19:19:10 +00002770 DBGPRINTF3(("FORKEXEC: calling vfork()...\n"));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002771 newpid = vfork();
Eric Andersen12de6cf2004-08-04 19:19:10 +00002772 if (newpid == -1) {
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00002773 DBGPRINTF(("FORKEXEC: ERROR, can't vfork()!\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002774 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002775 }
2776
Denis Vlasenko489f93e2007-02-01 01:43:16 +00002777 if (newpid > 0) { /* Parent */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002778 /* Restore values */
Eric Andersenff9eee42001-06-29 04:57:14 +00002779 pin = hpin;
2780 pout = hpout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002781 *wp = hwp;
2782 interactive = hinteractive;
2783 intr = hintr;
2784 brklist = hbrklist;
2785 execflg = hexecflg;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002786
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002787 closepipe(pin);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002788 return (pout == NULL ? setstatus(waitfor(newpid, 0)) : 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002789 }
2790
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002791 /* Child */
Denis Vlasenko7e497522008-02-12 09:51:03 +00002792 DBGPRINTF(("FORKEXEC: child process, bltin=%p (%s)\n", bltin, bltin_name));
Eric Andersenff9eee42001-06-29 04:57:14 +00002793 if (interactive) {
2794 signal(SIGINT, SIG_IGN);
2795 signal(SIGQUIT, SIG_IGN);
2796 resetsig = 1;
2797 }
2798 interactive = 0;
2799 intr = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002800 forked = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002801 brklist = 0;
2802 execflg = 0;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002803 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002804
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002805 if (owp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002806 while ((cp = *owp++) != NULL && assign(cp, COPYV))
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002807 if (!bltin)
Eric Andersenff9eee42001-06-29 04:57:14 +00002808 export(lookup(cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002809
Denis Vlasenko284d0fa2008-02-16 13:18:17 +00002810 if (pin) { /* NB: close _first_, then move fds! */
2811 close(pin[1]);
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00002812 xmove_fd(pin[0], 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002813 }
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002814 if (pout) {
Denis Vlasenko284d0fa2008-02-16 13:18:17 +00002815 close(pout[0]);
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00002816 xmove_fd(pout[1], 1);
Eric Andersenff9eee42001-06-29 04:57:14 +00002817 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002818
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002819 iopp = t->ioact;
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002820 if (iopp) {
2821 if (bltin && bltin != doexec) {
Denis Vlasenko7e497522008-02-12 09:51:03 +00002822 prs(bltin_name);
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00002823 err(": can't redirect shell command");
Eric Andersen12de6cf2004-08-04 19:19:10 +00002824 if (forked)
2825 _exit(-1);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002826 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002827 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002828 while (*iopp) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002829 if (iosetup(*iopp++, pin != NULL, pout != NULL)) {
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002830 /* system-detected error */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002831 if (forked)
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002832 _exit(-1);
2833 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002834 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002835 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002836 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002837
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002838 if (bltin) {
Denis Vlasenko7e497522008-02-12 09:51:03 +00002839 if (forked || pin || pout) {
2840 /* Builtin in pipe: disallowed */
2841 /* TODO: allow "exec"? */
2842 prs(bltin_name);
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00002843 err(": can't run builtin as part of pipe");
Denis Vlasenko7e497522008-02-12 09:51:03 +00002844 if (forked)
2845 _exit(-1);
2846 return -1;
2847 }
Denis Vlasenkofe218832008-03-01 09:35:39 +00002848 /* Run builtin */
2849 i = setstatus(bltin(t, wp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002850 if (forked)
2851 _exit(i);
2852 DBGPRINTF(("FORKEXEC: returning i=%d\n", i));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002853 return i;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002854 }
2855
Eric Andersenff9eee42001-06-29 04:57:14 +00002856 /* should use FIOCEXCL */
Eric Andersen8401eea2004-08-04 19:16:54 +00002857 for (i = FDBASE; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00002858 close(i);
2859 if (resetsig) {
2860 signal(SIGINT, SIG_DFL);
2861 signal(SIGQUIT, SIG_DFL);
2862 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002863
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002864 if (t->op_type == TPAREN)
Denis Vlasenko7e497522008-02-12 09:51:03 +00002865 _exit(execute(t->left, NOPIPE, NOPIPE, /* no_fork: */ 1));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002866 if (wp[0] == NULL)
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +00002867 _exit(EXIT_SUCCESS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002868
Eric Andersenfd7a4c82004-09-02 23:13:10 +00002869 cp = rexecve(wp[0], wp, makenv(0, NULL));
Eric Andersen8401eea2004-08-04 19:16:54 +00002870 prs(wp[0]);
2871 prs(": ");
Eric Andersen12de6cf2004-08-04 19:19:10 +00002872 err(cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00002873 if (!execflg)
2874 trap[0] = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002875
Denis Vlasenko7e497522008-02-12 09:51:03 +00002876 DBGPRINTF(("FORKEXEC: calling leave(), pid=%d\n", getpid()));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002877
Eric Andersenff9eee42001-06-29 04:57:14 +00002878 leave();
2879 /* NOTREACHED */
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002880 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002881}
2882
2883/*
2884 * 0< 1> are ignored as required
2885 * within pipelines.
2886 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002887static int iosetup(struct ioword *iop, int pipein, int pipeout)
Eric Andersenff9eee42001-06-29 04:57:14 +00002888{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002889 int u = -1;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002890 char *cp = NULL;
2891 const char *msg;
Eric Andersenff9eee42001-06-29 04:57:14 +00002892
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002893 DBGPRINTF(("IOSETUP: iop %p, pipein %i, pipeout %i\n", iop,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002894 pipein, pipeout));
2895
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002896 if (iop->io_fd == IODEFAULT) /* take default */
2897 iop->io_fd = iop->io_flag & (IOREAD | IOHERE) ? 0 : 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002898
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002899 if (pipein && iop->io_fd == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002900 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002901
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002902 if (pipeout && iop->io_fd == 1)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002903 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002904
Eric Andersen8401eea2004-08-04 19:16:54 +00002905 msg = iop->io_flag & (IOREAD | IOHERE) ? "open" : "create";
Eric Andersenff9eee42001-06-29 04:57:14 +00002906 if ((iop->io_flag & IOHERE) == 0) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002907 cp = iop->io_name; /* huh?? */
2908 cp = evalstr(cp, DOSUB | DOTRIM);
2909 if (cp == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002910 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002911 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002912
Eric Andersenff9eee42001-06-29 04:57:14 +00002913 if (iop->io_flag & IODUP) {
2914 if (cp[1] || (!isdigit(*cp) && *cp != '-')) {
2915 prs(cp);
2916 err(": illegal >& argument");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002917 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002918 }
2919 if (*cp == '-')
2920 iop->io_flag = IOCLOSE;
Eric Andersen8401eea2004-08-04 19:16:54 +00002921 iop->io_flag &= ~(IOREAD | IOWRITE);
Eric Andersenff9eee42001-06-29 04:57:14 +00002922 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002923
Eric Andersenff9eee42001-06-29 04:57:14 +00002924 switch (iop->io_flag) {
2925 case IOREAD:
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00002926 u = open(cp, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00002927 break;
2928
2929 case IOHERE:
Eric Andersen8401eea2004-08-04 19:16:54 +00002930 case IOHERE | IOXHERE:
2931 u = herein(iop->io_name, iop->io_flag & IOXHERE);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002932 cp = (char*)"here file";
Eric Andersenff9eee42001-06-29 04:57:14 +00002933 break;
2934
Eric Andersen8401eea2004-08-04 19:16:54 +00002935 case IOWRITE | IOCAT:
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00002936 u = open(cp, O_WRONLY);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002937 if (u >= 0) {
Denis Vlasenkoea620772006-10-14 02:23:43 +00002938 lseek(u, (long) 0, SEEK_END);
Eric Andersenff9eee42001-06-29 04:57:14 +00002939 break;
2940 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002941 /* fall through to creation if >>file doesn't exist */
2942
Eric Andersenff9eee42001-06-29 04:57:14 +00002943 case IOWRITE:
2944 u = creat(cp, 0666);
2945 break;
2946
2947 case IODUP:
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002948 u = dup2(*cp - '0', iop->io_fd);
Eric Andersenff9eee42001-06-29 04:57:14 +00002949 break;
2950
2951 case IOCLOSE:
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002952 close(iop->io_fd);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002953 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002954 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002955
Eric Andersenff9eee42001-06-29 04:57:14 +00002956 if (u < 0) {
2957 prs(cp);
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00002958 prs(": can't ");
Eric Andersenff9eee42001-06-29 04:57:14 +00002959 warn(msg);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002960 return 1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002961 }
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002962 xmove_fd(u, iop->io_fd);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002963 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002964}
2965
Eric Andersenff9eee42001-06-29 04:57:14 +00002966/*
2967 * Enter a new loop level (marked for break/continue).
2968 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002969static void brkset(struct brkcon *bc)
Eric Andersenff9eee42001-06-29 04:57:14 +00002970{
2971 bc->nextlev = brklist;
2972 brklist = bc;
2973}
2974
2975/*
2976 * Wait for the last process created.
2977 * Print a message for each process found
2978 * that was killed by a signal.
2979 * Ignore interrupt signals while waiting
2980 * unless `canintr' is true.
2981 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002982static int waitfor(int lastpid, int canintr)
Eric Andersenff9eee42001-06-29 04:57:14 +00002983{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002984 int pid, rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00002985 int s;
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002986 smallint oheedint = heedint;
Eric Andersenff9eee42001-06-29 04:57:14 +00002987
2988 heedint = 0;
2989 rv = 0;
2990 do {
2991 pid = wait(&s);
2992 if (pid == -1) {
2993 if (errno != EINTR || canintr)
2994 break;
2995 } else {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002996 rv = WAITSIG(s);
2997 if (rv != 0) {
Denis Vlasenko80b8b392007-06-25 10:55:35 +00002998 if (rv < ARRAY_SIZE(signame)) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002999 if (signame[rv] != NULL) {
3000 if (pid != lastpid) {
3001 prn(pid);
3002 prs(": ");
3003 }
3004 prs(signame[rv]);
3005 }
3006 } else {
3007 if (pid != lastpid) {
3008 prn(pid);
3009 prs(": ");
3010 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003011 prs("Signal ");
3012 prn(rv);
3013 prs(" ");
Eric Andersenff9eee42001-06-29 04:57:14 +00003014 }
3015 if (WAITCORE(s))
3016 prs(" - core dumped");
Denis Vlasenko80b8b392007-06-25 10:55:35 +00003017 if (rv >= ARRAY_SIZE(signame) || signame[rv])
Eric Andersenff9eee42001-06-29 04:57:14 +00003018 prs("\n");
Mike Frysingerb81f97b2008-05-14 11:51:04 +00003019 rv |= 0x80;
Eric Andersenff9eee42001-06-29 04:57:14 +00003020 } else
3021 rv = WAITVAL(s);
3022 }
3023 } while (pid != lastpid);
3024 heedint = oheedint;
3025 if (intr) {
3026 if (interactive) {
3027 if (canintr)
3028 intr = 0;
3029 } else {
Eric Andersen8401eea2004-08-04 19:16:54 +00003030 if (exstat == 0)
3031 exstat = rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003032 onintr(0);
3033 }
3034 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003035 return rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003036}
3037
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003038static int setstatus(int s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003039{
3040 exstat = s;
3041 setval(lookup("?"), putn(s));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003042 return s;
Eric Andersenff9eee42001-06-29 04:57:14 +00003043}
3044
3045/*
3046 * PATH-searching interface to execve.
3047 * If getenv("PATH") were kept up-to-date,
3048 * execvp might be used.
3049 */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003050static const char *rexecve(char *c, char **v, char **envp)
Eric Andersenff9eee42001-06-29 04:57:14 +00003051{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003052 const char *sp;
3053 char *tp;
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00003054 int asis = 0;
Eric Andersen1c039232001-07-07 00:05:55 +00003055 char *name = c;
Eric Andersen8401eea2004-08-04 19:16:54 +00003056
Denis Vlasenko80d14be2007-04-10 23:03:30 +00003057 if (ENABLE_FEATURE_SH_STANDALONE) {
Denis Vlasenko1aa7e472007-11-28 06:49:03 +00003058 if (find_applet_by_name(name) >= 0) {
Rob Landleya299efb2006-08-10 21:46:43 +00003059 /* We have to exec here since we vforked. Running
Denis Vlasenkoe4f2d062007-04-11 17:03:19 +00003060 * run_applet_and_exit() won't work and bad things
Rob Landleya299efb2006-08-10 21:46:43 +00003061 * will happen. */
Denis Vlasenkobdbbb7e2007-06-08 15:02:55 +00003062 execve(bb_busybox_exec_path, v, envp);
Rob Landleya299efb2006-08-10 21:46:43 +00003063 }
Eric Andersen1c039232001-07-07 00:05:55 +00003064 }
Eric Andersen1c039232001-07-07 00:05:55 +00003065
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003066 DBGPRINTF(("REXECVE: c=%p, v=%p, envp=%p\n", c, v, envp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003067
Eric Andersen8401eea2004-08-04 19:16:54 +00003068 sp = any('/', c) ? "" : path->value;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003069 asis = (*sp == '\0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003070 while (asis || *sp != '\0') {
3071 asis = 0;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003072 tp = global_env.linep;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003073 for (; *sp != '\0'; tp++) {
3074 *tp = *sp++;
3075 if (*tp == ':') {
3076 asis = (*sp == '\0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003077 break;
3078 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003079 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003080 if (tp != global_env.linep)
Eric Andersenff9eee42001-06-29 04:57:14 +00003081 *tp++ = '/';
Denis Vlasenko509697f2008-03-02 12:49:39 +00003082 strcpy(tp, c);
Eric Andersen1c039232001-07-07 00:05:55 +00003083
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003084 DBGPRINTF3(("REXECVE: global_env.linep is %s\n", global_env.linep));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003085
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003086 execve(global_env.linep, v, envp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003087
Eric Andersenff9eee42001-06-29 04:57:14 +00003088 switch (errno) {
3089 case ENOEXEC:
Denis Vlasenko447bd662008-05-30 22:28:32 +00003090 /* File is executable but file format isnt recognized */
3091 /* Run it as a shell script */
3092 /* (execve above didnt do it itself, unlike execvp) */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003093 *v = global_env.linep;
Denis Vlasenko509697f2008-03-02 12:49:39 +00003094 v--;
3095 tp = *v;
Denis Vlasenko447bd662008-05-30 22:28:32 +00003096 *v = (char*)DEFAULT_SHELL;
Glenn L McGrathdc4e75e2003-09-02 02:36:18 +00003097 execve(DEFAULT_SHELL, v, envp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003098 *v = tp;
Denis Vlasenko509697f2008-03-02 12:49:39 +00003099 return "no shell";
Eric Andersenff9eee42001-06-29 04:57:14 +00003100
3101 case ENOMEM:
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003102 return (char *) bb_msg_memory_exhausted;
Eric Andersenff9eee42001-06-29 04:57:14 +00003103
3104 case E2BIG:
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003105 return "argument list too long";
Eric Andersenff9eee42001-06-29 04:57:14 +00003106 }
3107 }
Denis Vlasenko447bd662008-05-30 22:28:32 +00003108 if (errno == ENOENT) {
3109 exstat = 127; /* standards require this */
3110 return "not found";
3111 }
3112 exstat = 126; /* mimic bash */
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00003113 return "can't execute";
Eric Andersenff9eee42001-06-29 04:57:14 +00003114}
3115
3116/*
3117 * Run the command produced by generator `f'
3118 * applied to stream `arg'.
3119 */
Eric Andersen8401eea2004-08-04 19:16:54 +00003120static int run(struct ioarg *argp, int (*f) (struct ioarg *))
Eric Andersenff9eee42001-06-29 04:57:14 +00003121{
3122 struct op *otree;
3123 struct wdblock *swdlist;
3124 struct wdblock *siolist;
3125 jmp_buf ev, rt;
3126 xint *ofail;
3127 int rv;
3128
3129#if __GNUC__
3130 /* Avoid longjmp clobbering */
3131 (void) &rv;
3132#endif
3133
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003134 DBGPRINTF(("RUN: enter, areanum %d, outtree %p, failpt %p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00003135 areanum, outtree, failpt));
3136
Eric Andersenff9eee42001-06-29 04:57:14 +00003137 areanum++;
3138 swdlist = wdlist;
3139 siolist = iolist;
3140 otree = outtree;
3141 ofail = failpt;
3142 rv = -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003143
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003144 errpt = ev;
3145 if (newenv(setjmp(errpt)) == 0) {
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00003146 wdlist = NULL;
3147 iolist = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00003148 pushio(argp, f);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003149 global_env.iobase = global_env.iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00003150 yynerrs = 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003151 failpt = rt;
3152 if (setjmp(failpt) == 0 && yyparse() == 0)
Denis Vlasenko7e497522008-02-12 09:51:03 +00003153 rv = execute(outtree, NOPIPE, NOPIPE, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003154 quitenv();
Eric Andersen12de6cf2004-08-04 19:19:10 +00003155 } else {
3156 DBGPRINTF(("RUN: error from newenv()!\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00003157 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00003158
Eric Andersenff9eee42001-06-29 04:57:14 +00003159 wdlist = swdlist;
3160 iolist = siolist;
3161 failpt = ofail;
3162 outtree = otree;
3163 freearea(areanum--);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003164
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003165 return rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003166}
3167
3168/* -------- do.c -------- */
3169
3170/*
3171 * built-in commands: doX
3172 */
3173
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003174static int dohelp(struct op *t UNUSED_PARAM, char **args UNUSED_PARAM)
Eric Andersen1c039232001-07-07 00:05:55 +00003175{
3176 int col;
3177 const struct builtincmd *x;
3178
Denis Vlasenko0ee39992006-12-24 15:23:28 +00003179 puts("\nBuilt-in commands:\n"
3180 "-------------------");
Eric Andersen1c039232001-07-07 00:05:55 +00003181
Denis Vlasenko95cb3262007-04-09 03:06:34 +00003182 col = 0;
3183 x = builtincmds;
3184 while (x->name) {
3185 col += printf("%c%s", ((col == 0) ? '\t' : ' '), x->name);
Eric Andersen1c039232001-07-07 00:05:55 +00003186 if (col > 60) {
Denis Vlasenko4daad902007-09-27 10:20:47 +00003187 bb_putchar('\n');
Eric Andersen1c039232001-07-07 00:05:55 +00003188 col = 0;
3189 }
Denis Vlasenko95cb3262007-04-09 03:06:34 +00003190 x++;
Eric Andersen1c039232001-07-07 00:05:55 +00003191 }
Denis Vlasenko80d14be2007-04-10 23:03:30 +00003192#if ENABLE_FEATURE_SH_STANDALONE
Eric Andersen1c039232001-07-07 00:05:55 +00003193 {
Denis Vlasenko1aa7e472007-11-28 06:49:03 +00003194 const char *applet = applet_names;
Eric Andersen1c039232001-07-07 00:05:55 +00003195
Denis Vlasenko1aa7e472007-11-28 06:49:03 +00003196 while (*applet) {
3197 col += printf("%c%s", ((col == 0) ? '\t' : ' '), applet);
Eric Andersen1c039232001-07-07 00:05:55 +00003198 if (col > 60) {
Denis Vlasenko4daad902007-09-27 10:20:47 +00003199 bb_putchar('\n');
Eric Andersen1c039232001-07-07 00:05:55 +00003200 col = 0;
3201 }
Denis Vlasenko1aa7e472007-11-28 06:49:03 +00003202 applet += strlen(applet) + 1;
Eric Andersen1c039232001-07-07 00:05:55 +00003203 }
3204 }
3205#endif
Denis Vlasenko0ee39992006-12-24 15:23:28 +00003206 puts("\n");
Eric Andersen1c039232001-07-07 00:05:55 +00003207 return EXIT_SUCCESS;
3208}
3209
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003210static int dolabel(struct op *t UNUSED_PARAM, char **args UNUSED_PARAM)
Eric Andersenff9eee42001-06-29 04:57:14 +00003211{
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003212 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003213}
3214
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003215static int dochdir(struct op *t UNUSED_PARAM, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003216{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003217 const char *cp, *er;
Eric Andersenff9eee42001-06-29 04:57:14 +00003218
Denis Vlasenkofe218832008-03-01 09:35:39 +00003219 cp = args[1];
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003220 if (cp == NULL) {
3221 cp = homedir->value;
Denis Vlasenkod244c5e2007-02-09 17:30:14 +00003222 if (cp != NULL)
3223 goto do_cd;
3224 er = ": no home directory";
3225 } else {
3226 do_cd:
3227 if (chdir(cp) >= 0)
3228 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003229 er = ": bad directory";
Denis Vlasenkod244c5e2007-02-09 17:30:14 +00003230 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003231 prs(cp != NULL ? cp : "cd");
Eric Andersenff9eee42001-06-29 04:57:14 +00003232 err(er);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003233 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003234}
3235
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003236static int doshift(struct op *t UNUSED_PARAM, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003237{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003238 int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003239
Denis Vlasenkofe218832008-03-01 09:35:39 +00003240 n = args[1] ? getn(args[1]) : 1;
Eric Andersen8401eea2004-08-04 19:16:54 +00003241 if (dolc < n) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003242 err("nothing to shift");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003243 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003244 }
3245 dolv[n] = dolv[0];
3246 dolv += n;
3247 dolc -= n;
3248 setval(lookup("#"), putn(dolc));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003249 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003250}
3251
3252/*
3253 * execute login and newgrp directly
3254 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003255static int dologin(struct op *t UNUSED_PARAM, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003256{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003257 const char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003258
3259 if (interactive) {
3260 signal(SIGINT, SIG_DFL);
3261 signal(SIGQUIT, SIG_DFL);
3262 }
Denis Vlasenkofe218832008-03-01 09:35:39 +00003263 cp = rexecve(args[0], args, makenv(0, NULL));
3264 prs(args[0]);
Eric Andersen8401eea2004-08-04 19:16:54 +00003265 prs(": ");
3266 err(cp);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003267 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003268}
3269
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003270static int doumask(struct op *t UNUSED_PARAM, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003271{
Denis Vlasenko7e497522008-02-12 09:51:03 +00003272 int i;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003273 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003274
Denis Vlasenkofe218832008-03-01 09:35:39 +00003275 cp = args[1];
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003276 if (cp == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003277 i = umask(0);
3278 umask(i);
Denis Vlasenko7e497522008-02-12 09:51:03 +00003279 printf("%04o\n", i);
Eric Andersenff9eee42001-06-29 04:57:14 +00003280 } else {
Denis Vlasenko7e497522008-02-12 09:51:03 +00003281 i = bb_strtou(cp, NULL, 8);
3282 if (errno) {
3283 err("umask: bad octal number");
3284 return 1;
3285 }
3286 umask(i);
Eric Andersenff9eee42001-06-29 04:57:14 +00003287 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003288 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003289}
3290
Denis Vlasenkofe218832008-03-01 09:35:39 +00003291static int doexec(struct op *t, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003292{
Eric Andersenff9eee42001-06-29 04:57:14 +00003293 jmp_buf ex;
3294 xint *ofail;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003295 char **sv_words;
Eric Andersenff9eee42001-06-29 04:57:14 +00003296
3297 t->ioact = NULL;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003298 if (!args[1])
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003299 return 1;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003300
Eric Andersenff9eee42001-06-29 04:57:14 +00003301 execflg = 1;
3302 ofail = failpt;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003303 failpt = ex;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003304
Denis Vlasenko509697f2008-03-02 12:49:39 +00003305 sv_words = t->op_words;
3306 t->op_words = args + 1;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003307// TODO: test what will happen with "exec break" -
Denis Vlasenko509697f2008-03-02 12:49:39 +00003308// will it leave t->op_words pointing to garbage?
Denis Vlasenkofe218832008-03-01 09:35:39 +00003309// (see http://bugs.busybox.net/view.php?id=846)
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003310 if (setjmp(failpt) == 0)
Denis Vlasenko7e497522008-02-12 09:51:03 +00003311 execute(t, NOPIPE, NOPIPE, /* no_fork: */ 1);
Denis Vlasenko509697f2008-03-02 12:49:39 +00003312 t->op_words = sv_words;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003313
Eric Andersenff9eee42001-06-29 04:57:14 +00003314 failpt = ofail;
3315 execflg = 0;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003316
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003317 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003318}
3319
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003320static int dodot(struct op *t UNUSED_PARAM, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003321{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003322 int i;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003323 const char *sp;
3324 char *tp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003325 char *cp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003326 int maltmp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003327
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003328 DBGPRINTF(("DODOT: enter, t=%p, tleft %p, tright %p, global_env.linep is %s\n",
3329 t, t->left, t->right, ((global_env.linep == NULL) ? "NULL" : global_env.linep)));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003330
Denis Vlasenkofe218832008-03-01 09:35:39 +00003331 cp = args[1];
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003332 if (cp == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00003333 DBGPRINTF(("DODOT: bad args, ret 0\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003334 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003335 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003336 DBGPRINTF(("DODOT: cp is %s\n", cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003337
Eric Andersen8401eea2004-08-04 19:16:54 +00003338 sp = any('/', cp) ? ":" : path->value;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003339
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003340 DBGPRINTF(("DODOT: sp is %s, global_env.linep is %s\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00003341 ((sp == NULL) ? "NULL" : sp),
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003342 ((global_env.linep == NULL) ? "NULL" : global_env.linep)));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003343
Eric Andersenff9eee42001-06-29 04:57:14 +00003344 while (*sp) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003345 tp = global_env.linep;
Eric Andersenff9eee42001-06-29 04:57:14 +00003346 while (*sp && (*tp = *sp++) != ':')
3347 tp++;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003348 if (tp != global_env.linep)
Eric Andersenff9eee42001-06-29 04:57:14 +00003349 *tp++ = '/';
Denis Vlasenko509697f2008-03-02 12:49:39 +00003350 strcpy(tp, cp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003351
3352 /* Original code */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003353 i = open(global_env.linep, O_RDONLY);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003354 if (i >= 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003355 exstat = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003356 maltmp = remap(i);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003357 DBGPRINTF(("DODOT: remap=%d, exstat=%d, global_env.iofd %d, i %d, global_env.linep is %s\n",
3358 maltmp, exstat, global_env.iofd, i, global_env.linep));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003359
3360 next(maltmp); /* Basically a PUSHIO */
3361
3362 DBGPRINTF(("DODOT: returning exstat=%d\n", exstat));
3363
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003364 return exstat;
Eric Andersenff9eee42001-06-29 04:57:14 +00003365 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003366 } /* while */
Eric Andersen12de6cf2004-08-04 19:19:10 +00003367
Eric Andersenff9eee42001-06-29 04:57:14 +00003368 prs(cp);
3369 err(": not found");
Eric Andersen12de6cf2004-08-04 19:19:10 +00003370
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003371 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003372}
3373
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003374static int dowait(struct op *t UNUSED_PARAM, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003375{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003376 int i;
3377 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003378
Denis Vlasenkofe218832008-03-01 09:35:39 +00003379 cp = args[1];
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003380 if (cp != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003381 i = getn(cp);
3382 if (i == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003383 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003384 } else
3385 i = -1;
3386 setstatus(waitfor(i, 1));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003387 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003388}
3389
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003390static int doread(struct op *t UNUSED_PARAM, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003391{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003392 char *cp, **wp;
3393 int nb = 0;
3394 int nl = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003395
Denis Vlasenkofe218832008-03-01 09:35:39 +00003396 if (args[1] == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003397 err("Usage: read name ...");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003398 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003399 }
Denis Vlasenkofe218832008-03-01 09:35:39 +00003400 for (wp = args + 1; *wp; wp++) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003401 for (cp = global_env.linep; !nl && cp < elinep - 1; cp++) {
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +00003402 nb = nonblock_safe_read(STDIN_FILENO, cp, sizeof(*cp));
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003403 if (nb != sizeof(*cp))
Eric Andersenff9eee42001-06-29 04:57:14 +00003404 break;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003405 nl = (*cp == '\n');
3406 if (nl || (wp[1] && any(*cp, ifs->value)))
3407 break;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003408 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003409 *cp = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00003410 if (nb <= 0)
3411 break;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003412 setval(lookup(*wp), global_env.linep);
Eric Andersenff9eee42001-06-29 04:57:14 +00003413 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003414 return nb <= 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003415}
3416
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003417static int doeval(struct op *t UNUSED_PARAM, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003418{
Denis Vlasenkofe218832008-03-01 09:35:39 +00003419 return RUN(awordlist, args + 1, wdchar);
Eric Andersenff9eee42001-06-29 04:57:14 +00003420}
3421
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003422static int dotrap(struct op *t UNUSED_PARAM, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003423{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003424 int n, i;
3425 int resetsig;
Eric Andersenff9eee42001-06-29 04:57:14 +00003426
Denis Vlasenkofe218832008-03-01 09:35:39 +00003427 if (args[1] == NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00003428 for (i = 0; i <= _NSIG; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00003429 if (trap[i]) {
3430 prn(i);
3431 prs(": ");
3432 prs(trap[i]);
3433 prs("\n");
3434 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003435 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003436 }
Denis Vlasenkofe218832008-03-01 09:35:39 +00003437 resetsig = isdigit(args[1][0]);
3438 for (i = resetsig ? 1 : 2; args[i] != NULL; ++i) {
3439 n = getsig(args[i]);
Eric Andersenff9eee42001-06-29 04:57:14 +00003440 freecell(trap[n]);
3441 trap[n] = 0;
3442 if (!resetsig) {
Denis Vlasenkofe218832008-03-01 09:35:39 +00003443 if (args[1][0] != '\0') {
3444 trap[n] = strsave(args[1], 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003445 setsig(n, sig);
3446 } else
3447 setsig(n, SIG_IGN);
3448 } else {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00003449 if (interactive) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003450 if (n == SIGINT)
3451 setsig(n, onintr);
3452 else
Eric Andersen8401eea2004-08-04 19:16:54 +00003453 setsig(n, n == SIGQUIT ? SIG_IGN : SIG_DFL);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00003454 } else
Eric Andersenff9eee42001-06-29 04:57:14 +00003455 setsig(n, SIG_DFL);
3456 }
3457 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003458 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003459}
3460
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003461static int getsig(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003462{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003463 int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003464
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003465 n = getn(s);
3466 if (n < 0 || n > _NSIG) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003467 err("trap: bad signal number");
3468 n = 0;
3469 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003470 return n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003471}
3472
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003473static void setsig(int n, sighandler_t f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003474{
3475 if (n == 0)
3476 return;
3477 if (signal(n, SIG_IGN) != SIG_IGN || ourtrap[n]) {
3478 ourtrap[n] = 1;
3479 signal(n, f);
3480 }
3481}
3482
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003483static int getn(char *as)
Eric Andersenff9eee42001-06-29 04:57:14 +00003484{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003485 char *s;
3486 int n, m;
Eric Andersenff9eee42001-06-29 04:57:14 +00003487
3488 s = as;
3489 m = 1;
3490 if (*s == '-') {
3491 m = -1;
3492 s++;
3493 }
3494 for (n = 0; isdigit(*s); s++)
Eric Andersen8401eea2004-08-04 19:16:54 +00003495 n = (n * 10) + (*s - '0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003496 if (*s) {
3497 prs(as);
3498 err(": bad number");
3499 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003500 return n * m;
Eric Andersenff9eee42001-06-29 04:57:14 +00003501}
3502
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003503static int dobreak(struct op *t UNUSED_PARAM, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003504{
Denis Vlasenkofe218832008-03-01 09:35:39 +00003505 return brkcontin(args[1], 1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003506}
3507
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003508static int docontinue(struct op *t UNUSED_PARAM, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003509{
Denis Vlasenkofe218832008-03-01 09:35:39 +00003510 return brkcontin(args[1], 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003511}
3512
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003513static int brkcontin(char *cp, int val)
Eric Andersenff9eee42001-06-29 04:57:14 +00003514{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003515 struct brkcon *bc;
3516 int nl;
Eric Andersenff9eee42001-06-29 04:57:14 +00003517
Eric Andersen8401eea2004-08-04 19:16:54 +00003518 nl = cp == NULL ? 1 : getn(cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003519 if (nl <= 0)
3520 nl = 999;
3521 do {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003522 bc = brklist;
3523 if (bc == NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00003524 break;
3525 brklist = bc->nextlev;
3526 } while (--nl);
3527 if (nl) {
3528 err("bad break/continue level");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003529 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003530 }
Denis Vlasenko648b44f2008-02-12 06:04:06 +00003531 isbreak = (val != 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003532 longjmp(bc->brkpt, 1);
3533 /* NOTREACHED */
3534}
3535
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003536static int doexit(struct op *t UNUSED_PARAM, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003537{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003538 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003539
3540 execflg = 0;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003541 cp = args[1];
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003542 if (cp != NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00003543 setstatus(getn(cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003544
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003545 DBGPRINTF(("DOEXIT: calling leave(), t=%p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003546
Eric Andersenff9eee42001-06-29 04:57:14 +00003547 leave();
3548 /* NOTREACHED */
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003549 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003550}
3551
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003552static int doexport(struct op *t UNUSED_PARAM, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003553{
Denis Vlasenkofe218832008-03-01 09:35:39 +00003554 rdexp(args + 1, export, EXPORT);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003555 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003556}
3557
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003558static int doreadonly(struct op *t UNUSED_PARAM, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003559{
Denis Vlasenkofe218832008-03-01 09:35:39 +00003560 rdexp(args + 1, ronly, RONLY);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003561 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003562}
3563
Eric Andersen8401eea2004-08-04 19:16:54 +00003564static void rdexp(char **wp, void (*f) (struct var *), int key)
Eric Andersenff9eee42001-06-29 04:57:14 +00003565{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003566 DBGPRINTF6(("RDEXP: enter, wp=%p, func=%p, key=%d\n", wp, f, key));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003567 DBGPRINTF6(("RDEXP: *wp=%s\n", *wp));
3568
Eric Andersenff9eee42001-06-29 04:57:14 +00003569 if (*wp != NULL) {
Matt Kraaif69bfc72001-07-12 19:39:59 +00003570 for (; *wp != NULL; wp++) {
3571 if (isassign(*wp)) {
3572 char *cp;
Eric Andersen8401eea2004-08-04 19:16:54 +00003573
Matt Kraaif69bfc72001-07-12 19:39:59 +00003574 assign(*wp, COPYV);
Denis Vlasenko509697f2008-03-02 12:49:39 +00003575 for (cp = *wp; *cp != '='; cp++)
3576 continue;
Matt Kraaif69bfc72001-07-12 19:39:59 +00003577 *cp = '\0';
3578 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003579 if (checkname(*wp))
Eric Andersen8401eea2004-08-04 19:16:54 +00003580 (*f) (lookup(*wp));
Eric Andersenff9eee42001-06-29 04:57:14 +00003581 else
3582 badid(*wp);
Matt Kraaif69bfc72001-07-12 19:39:59 +00003583 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003584 } else
3585 putvlist(key, 1);
3586}
3587
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003588static void badid(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003589{
3590 prs(s);
3591 err(": bad identifier");
3592}
3593
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003594static int doset(struct op *t UNUSED_PARAM, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003595{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003596 struct var *vp;
3597 char *cp;
3598 int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003599
Denis Vlasenkofe218832008-03-01 09:35:39 +00003600 cp = args[1];
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003601 if (cp == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003602 for (vp = vlist; vp; vp = vp->next)
3603 varput(vp->name, 1);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003604 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003605 }
3606 if (*cp == '-') {
Denis Vlasenkofe218832008-03-01 09:35:39 +00003607 args++;
Eric Andersenff9eee42001-06-29 04:57:14 +00003608 if (*++cp == 0)
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003609 FLAG['x'] = FLAG['v'] = 0;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003610 else {
3611 for (; *cp; cp++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003612 switch (*cp) {
3613 case 'e':
3614 if (!interactive)
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003615 FLAG['e']++;
Eric Andersenff9eee42001-06-29 04:57:14 +00003616 break;
3617
3618 default:
Eric Andersen8401eea2004-08-04 19:16:54 +00003619 if (*cp >= 'a' && *cp <= 'z')
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003620 FLAG[(int) *cp]++;
Eric Andersenff9eee42001-06-29 04:57:14 +00003621 break;
3622 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003623 }
3624 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003625 setdash();
3626 }
Denis Vlasenkofe218832008-03-01 09:35:39 +00003627 if (args[1]) {
3628 args[0] = dolv[0];
3629 for (n = 1; args[n]; n++)
3630 setarea((char *) args[n], 0);
Eric Andersen8401eea2004-08-04 19:16:54 +00003631 dolc = n - 1;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003632 dolv = args;
Eric Andersenff9eee42001-06-29 04:57:14 +00003633 setval(lookup("#"), putn(dolc));
Eric Andersen8401eea2004-08-04 19:16:54 +00003634 setarea((char *) (dolv - 1), 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003635 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003636 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003637}
3638
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003639static void varput(char *s, int out)
Eric Andersenff9eee42001-06-29 04:57:14 +00003640{
Matt Kraai69edfec2001-08-06 14:14:18 +00003641 if (isalnum(*s) || *s == '_') {
Eric Andersenff9eee42001-06-29 04:57:14 +00003642 write(out, s, strlen(s));
3643 write(out, "\n", 1);
3644 }
3645}
3646
3647
3648/*
3649 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
3650 * This file contains code for the times builtin.
Eric Andersenff9eee42001-06-29 04:57:14 +00003651 */
Denis Vlasenkofe218832008-03-01 09:35:39 +00003652static void times_fmt(char *buf, clock_t val, unsigned clk_tck)
3653{
3654 unsigned min, sec;
3655 if (sizeof(val) > sizeof(int))
3656 sec = ((unsigned long)val) / clk_tck;
3657 else
3658 sec = ((unsigned)val) / clk_tck;
3659 min = sec / 60;
3660#if ENABLE_DESKTOP
3661 sprintf(buf, "%um%u.%03us", min, (sec - min * 60),
3662 /* msec: */ ((unsigned)(val - (clock_t)sec * clk_tck)) * 1000 / clk_tck
3663 );
3664#else
3665 sprintf(buf, "%um%us", min, (sec - min * 60));
3666#endif
3667}
3668
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003669static int dotimes(struct op *t UNUSED_PARAM, char **args UNUSED_PARAM)
Eric Andersenff9eee42001-06-29 04:57:14 +00003670{
3671 struct tms buf;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003672 unsigned clk_tck = sysconf(_SC_CLK_TCK);
3673 /* How much do we need for "NmN.NNNs" ? */
3674 enum { TIMEBUF_SIZE = sizeof(int)*3 + sizeof(int)*3 + 6 };
3675 char u[TIMEBUF_SIZE], s[TIMEBUF_SIZE];
3676 char cu[TIMEBUF_SIZE], cs[TIMEBUF_SIZE];
Eric Andersenff9eee42001-06-29 04:57:14 +00003677
3678 times(&buf);
Denis Vlasenkofe218832008-03-01 09:35:39 +00003679
3680 times_fmt(u, buf.tms_utime, clk_tck);
3681 times_fmt(s, buf.tms_stime, clk_tck);
3682 times_fmt(cu, buf.tms_cutime, clk_tck);
3683 times_fmt(cs, buf.tms_cstime, clk_tck);
3684
3685 printf("%s %s\n%s %s\n", u, s, cu, cs);
Eric Andersenff9eee42001-06-29 04:57:14 +00003686 return 0;
3687}
3688
3689
Eric Andersenff9eee42001-06-29 04:57:14 +00003690/* -------- eval.c -------- */
3691
3692/*
3693 * ${}
3694 * `command`
3695 * blank interpretation
3696 * quoting
3697 * glob
3698 */
3699
Eric Andersen8401eea2004-08-04 19:16:54 +00003700static char **eval(char **ap, int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003701{
3702 struct wdblock *wb;
3703 char **wp;
3704 char **wf;
3705 jmp_buf ev;
3706
3707#if __GNUC__
3708 /* Avoid longjmp clobbering */
3709 (void) &wp;
3710 (void) &ap;
3711#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00003712
3713 DBGPRINTF4(("EVAL: enter, f=%d\n", f));
3714
Eric Andersenff9eee42001-06-29 04:57:14 +00003715 wp = NULL;
3716 wb = NULL;
3717 wf = NULL;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003718 errpt = ev;
3719 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003720 while (*ap && isassign(*ap))
3721 expand(*ap++, &wb, f & ~DOGLOB);
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003722 if (FLAG['k']) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003723 for (wf = ap; *wf; wf++) {
3724 if (isassign(*wf))
3725 expand(*wf, &wb, f & ~DOGLOB);
3726 }
3727 }
Denis Vlasenko648b44f2008-02-12 06:04:06 +00003728 for (wb = addword((char *) NULL, wb); *ap; ap++) {
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003729 if (!FLAG['k'] || !isassign(*ap))
Eric Andersenff9eee42001-06-29 04:57:14 +00003730 expand(*ap, &wb, f & ~DOKEY);
3731 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003732 wb = addword((char *) 0, wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00003733 wp = getwords(wb);
3734 quitenv();
3735 } else
3736 gflg = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003737
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003738 return gflg ? (char **) NULL : wp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003739}
3740
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003741
Eric Andersenff9eee42001-06-29 04:57:14 +00003742/*
3743 * Make the exported environment from the exported
3744 * names in the dictionary. Keyword assignments
3745 * will already have been done.
3746 */
Eric Andersenfd7a4c82004-09-02 23:13:10 +00003747static char **makenv(int all, struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00003748{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003749 struct var *vp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003750
3751 DBGPRINTF5(("MAKENV: enter, all=%d\n", all));
Eric Andersenff9eee42001-06-29 04:57:14 +00003752
Eric Andersenff9eee42001-06-29 04:57:14 +00003753 for (vp = vlist; vp; vp = vp->next)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003754 if (all || vp->status & EXPORT)
Eric Andersenff9eee42001-06-29 04:57:14 +00003755 wb = addword(vp->name, wb);
Eric Andersen8401eea2004-08-04 19:16:54 +00003756 wb = addword((char *) 0, wb);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003757 return getwords(wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00003758}
3759
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003760static int expand(const char *cp, struct wdblock **wbp, int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003761{
3762 jmp_buf ev;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003763 char *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003764
3765#if __GNUC__
3766 /* Avoid longjmp clobbering */
3767 (void) &cp;
3768#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00003769
3770 DBGPRINTF3(("EXPAND: enter, f=%d\n", f));
3771
Eric Andersenff9eee42001-06-29 04:57:14 +00003772 gflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003773
Eric Andersenff9eee42001-06-29 04:57:14 +00003774 if (cp == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003775 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003776
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003777 if (!anys("$`'\"", cp) && !anys(ifs->value, cp)
3778 && ((f & DOGLOB) == 0 || !anys("[*?", cp))
3779 ) {
3780 xp = strsave(cp, areanum);
Eric Andersenff9eee42001-06-29 04:57:14 +00003781 if (f & DOTRIM)
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003782 unquote(xp);
3783 *wbp = addword(xp, *wbp);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003784 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003785 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003786 errpt = ev;
3787 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003788 PUSHIO(aword, cp, strchar);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003789 global_env.iobase = global_env.iop;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003790 while ((xp = blank(f)) && gflg == 0) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003791 global_env.linep = xp;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003792 xp = strsave(xp, areanum);
Eric Andersen8401eea2004-08-04 19:16:54 +00003793 if ((f & DOGLOB) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003794 if (f & DOTRIM)
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003795 unquote(xp);
3796 *wbp = addword(xp, *wbp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003797 } else
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003798 *wbp = glob(xp, *wbp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003799 }
3800 quitenv();
3801 } else
3802 gflg = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003803 return gflg == 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003804}
3805
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003806static char *evalstr(char *cp, int f)
3807{
3808 struct wdblock *wb;
3809
3810 DBGPRINTF6(("EVALSTR: enter, cp=%p, f=%d\n", cp, f));
3811
3812 wb = NULL;
3813 if (expand(cp, &wb, f)) {
3814 if (wb == NULL || wb->w_nword == 0
3815 || (cp = wb->w_words[0]) == NULL
3816 ) {
Denis Vlasenko8e858e22007-03-07 09:35:43 +00003817// TODO: I suspect that
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003818// char *evalstr(char *cp, int f) is actually
3819// const char *evalstr(const char *cp, int f)!
3820 cp = (char*)"";
3821 }
3822 DELETE(wb);
3823 } else
3824 cp = NULL;
3825 return cp;
3826}
3827
3828
Eric Andersenff9eee42001-06-29 04:57:14 +00003829/*
3830 * Blank interpretation and quoting
3831 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003832static char *blank(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003833{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003834 int c, c1;
3835 char *sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003836 int scanequals, foundequals;
3837
Eric Andersen12de6cf2004-08-04 19:19:10 +00003838 DBGPRINTF3(("BLANK: enter, f=%d\n", f));
3839
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003840 sp = global_env.linep;
Eric Andersenff9eee42001-06-29 04:57:14 +00003841 scanequals = f & DOKEY;
3842 foundequals = 0;
3843
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003844 loop:
3845 c = subgetc('"', foundequals);
3846 switch (c) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003847 case 0:
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003848 if (sp == global_env.linep)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003849 return 0;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003850 *global_env.linep++ = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003851 return sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003852
3853 default:
3854 if (f & DOBLANK && any(c, ifs->value))
3855 goto loop;
3856 break;
3857
3858 case '"':
3859 case '\'':
3860 scanequals = 0;
3861 if (INSUB())
3862 break;
3863 for (c1 = c; (c = subgetc(c1, 1)) != c1;) {
3864 if (c == 0)
3865 break;
3866 if (c == '\'' || !any(c, "$`\""))
3867 c |= QUOTE;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003868 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003869 }
3870 c = 0;
3871 }
3872 unget(c);
Matt Kraai69edfec2001-08-06 14:14:18 +00003873 if (!isalpha(c) && c != '_')
Eric Andersenff9eee42001-06-29 04:57:14 +00003874 scanequals = 0;
3875 for (;;) {
3876 c = subgetc('"', foundequals);
3877 if (c == 0 ||
Eric Andersen8401eea2004-08-04 19:16:54 +00003878 f & (DOBLANK && any(c, ifs->value)) ||
3879 (!INSUB() && any(c, "\"'"))) {
3880 scanequals = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003881 unget(c);
3882 if (any(c, "\"'"))
3883 goto loop;
3884 break;
3885 }
3886 if (scanequals) {
3887 if (c == '=') {
3888 foundequals = 1;
Eric Andersen8401eea2004-08-04 19:16:54 +00003889 scanequals = 0;
3890 } else if (!isalnum(c) && c != '_')
Eric Andersenff9eee42001-06-29 04:57:14 +00003891 scanequals = 0;
3892 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003893 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003894 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003895 *global_env.linep++ = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003896 return sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003897}
3898
3899/*
3900 * Get characters, substituting for ` and $
3901 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003902static int subgetc(char ec, int quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00003903{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003904 char c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003905
3906 DBGPRINTF3(("SUBGETC: enter, quoted=%d\n", quoted));
Eric Andersenff9eee42001-06-29 04:57:14 +00003907
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003908 again:
Eric Andersenff9eee42001-06-29 04:57:14 +00003909 c = my_getc(ec);
3910 if (!INSUB() && ec != '\'') {
3911 if (c == '`') {
3912 if (grave(quoted) == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003913 return 0;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003914 global_env.iop->task = XGRAVE;
Eric Andersenff9eee42001-06-29 04:57:14 +00003915 goto again;
3916 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003917 if (c == '$') {
3918 c = dollar(quoted);
3919 if (c == 0) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003920 global_env.iop->task = XDOLL;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003921 goto again;
3922 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003923 }
3924 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003925 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003926}
3927
3928/*
3929 * Prepare to generate the string returned by ${} substitution.
3930 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003931static int dollar(int quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00003932{
3933 int otask;
3934 struct io *oiop;
3935 char *dolp;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003936 char *s, c, *cp = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00003937 struct var *vp;
3938
Eric Andersen12de6cf2004-08-04 19:19:10 +00003939 DBGPRINTF3(("DOLLAR: enter, quoted=%d\n", quoted));
3940
Eric Andersenff9eee42001-06-29 04:57:14 +00003941 c = readc();
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003942 s = global_env.linep;
Eric Andersenff9eee42001-06-29 04:57:14 +00003943 if (c != '{') {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003944 *global_env.linep++ = c;
Matt Kraai69edfec2001-08-06 14:14:18 +00003945 if (isalpha(c) || c == '_') {
Eric Andersen8401eea2004-08-04 19:16:54 +00003946 while ((c = readc()) != 0 && (isalnum(c) || c == '_'))
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003947 if (global_env.linep < elinep)
3948 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003949 unget(c);
3950 }
3951 c = 0;
3952 } else {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003953 oiop = global_env.iop;
3954 otask = global_env.iop->task;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003955
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003956 global_env.iop->task = XOTHER;
Eric Andersen8401eea2004-08-04 19:16:54 +00003957 while ((c = subgetc('"', 0)) != 0 && c != '}' && c != '\n')
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003958 if (global_env.linep < elinep)
3959 *global_env.linep++ = c;
3960 if (oiop == global_env.iop)
3961 global_env.iop->task = otask;
Eric Andersenff9eee42001-06-29 04:57:14 +00003962 if (c != '}') {
3963 err("unclosed ${");
Denis Vlasenko648b44f2008-02-12 06:04:06 +00003964 gflg = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003965 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003966 }
3967 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003968 if (global_env.linep >= elinep) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003969 err("string in ${} too long");
Denis Vlasenko648b44f2008-02-12 06:04:06 +00003970 gflg = 1;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003971 global_env.linep -= 10;
Eric Andersenff9eee42001-06-29 04:57:14 +00003972 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003973 *global_env.linep = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003974 if (*s)
Eric Andersen8401eea2004-08-04 19:16:54 +00003975 for (cp = s + 1; *cp; cp++)
Eric Andersenff9eee42001-06-29 04:57:14 +00003976 if (any(*cp, "=-+?")) {
3977 c = *cp;
3978 *cp++ = 0;
3979 break;
3980 }
3981 if (s[1] == 0 && (*s == '*' || *s == '@')) {
3982 if (dolc > 1) {
3983 /* currently this does not distinguish $* and $@ */
3984 /* should check dollar */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003985 global_env.linep = s;
Eric Andersen8401eea2004-08-04 19:16:54 +00003986 PUSHIO(awordlist, dolv + 1, dolchar);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003987 return 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00003988 } else { /* trap the nasty ${=} */
Eric Andersenff9eee42001-06-29 04:57:14 +00003989 s[0] = '1';
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003990 s[1] = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00003991 }
3992 }
3993 vp = lookup(s);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003994 dolp = vp->value;
3995 if (dolp == null) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003996 switch (c) {
3997 case '=':
3998 if (isdigit(*s)) {
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00003999 err("can't use ${...=...} with $n");
Denis Vlasenko648b44f2008-02-12 06:04:06 +00004000 gflg = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004001 break;
4002 }
4003 setval(vp, cp);
4004 dolp = vp->value;
4005 break;
4006
4007 case '-':
4008 dolp = strsave(cp, areanum);
4009 break;
4010
4011 case '?':
4012 if (*cp == 0) {
4013 prs("missing value for ");
4014 err(s);
4015 } else
4016 err(cp);
Denis Vlasenko648b44f2008-02-12 06:04:06 +00004017 gflg = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004018 break;
4019 }
4020 } else if (c == '+')
4021 dolp = strsave(cp, areanum);
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00004022 if (FLAG['u'] && dolp == null) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004023 prs("unset variable: ");
4024 err(s);
Denis Vlasenko648b44f2008-02-12 06:04:06 +00004025 gflg = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004026 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004027 global_env.linep = s;
Eric Andersenff9eee42001-06-29 04:57:14 +00004028 PUSHIO(aword, dolp, quoted ? qstrchar : strchar);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004029 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004030}
4031
4032/*
4033 * Run the command in `...` and read its output.
4034 */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004035
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004036static int grave(int quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00004037{
Denis Vlasenko55f30b02007-03-24 22:42:29 +00004038 /* moved to G: static char child_cmd[LINELIM]; */
4039
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004040 const char *cp;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004041 int i;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004042 int j;
Eric Andersenff9eee42001-06-29 04:57:14 +00004043 int pf[2];
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004044 const char *src;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004045 char *dest;
4046 int count;
4047 int ignore;
4048 int ignore_once;
4049 char *argument_list[4];
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004050 struct wdblock *wb = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004051
4052#if __GNUC__
4053 /* Avoid longjmp clobbering */
4054 (void) &cp;
4055#endif
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004056
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004057 for (cp = global_env.iop->argp->aword; *cp != '`'; cp++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004058 if (*cp == 0) {
4059 err("no closing `");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004060 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004061 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004062 }
Eric Andersen737f5fb2003-03-14 16:05:59 +00004063
4064 /* string copy with dollar expansion */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004065 src = global_env.iop->argp->aword;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004066 dest = child_cmd;
4067 count = 0;
4068 ignore = 0;
4069 ignore_once = 0;
4070 while ((*src != '`') && (count < LINELIM)) {
4071 if (*src == '\'')
4072 ignore = !ignore;
4073 if (*src == '\\')
4074 ignore_once = 1;
4075 if (*src == '$' && !ignore && !ignore_once) {
4076 struct var *vp;
Denis Vlasenkoab801872007-12-02 08:35:37 +00004077 /* moved to G to reduce stack usage
Eric Andersen737f5fb2003-03-14 16:05:59 +00004078 char var_name[LINELIM];
4079 char alt_value[LINELIM];
Denis Vlasenkoab801872007-12-02 08:35:37 +00004080 */
4081#define var_name (G.grave__var_name)
4082#define alt_value (G.grave__alt_value)
Eric Andersen737f5fb2003-03-14 16:05:59 +00004083 int var_index = 0;
4084 int alt_index = 0;
4085 char operator = 0;
4086 int braces = 0;
4087 char *value;
4088
4089 src++;
4090 if (*src == '{') {
4091 braces = 1;
4092 src++;
4093 }
4094
4095 var_name[var_index++] = *src++;
Paul Fox54690dc2005-07-20 18:33:12 +00004096 while (isalnum(*src) || *src=='_')
Eric Andersen737f5fb2003-03-14 16:05:59 +00004097 var_name[var_index++] = *src++;
4098 var_name[var_index] = 0;
4099
4100 if (braces) {
4101 switch (*src) {
4102 case '}':
4103 break;
4104 case '-':
4105 case '=':
4106 case '+':
4107 case '?':
Eric Andersen8401eea2004-08-04 19:16:54 +00004108 operator = * src;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004109 break;
4110 default:
4111 err("unclosed ${\n");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004112 return 0;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004113 }
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004114 if (operator) {
Eric Andersen737f5fb2003-03-14 16:05:59 +00004115 src++;
4116 while (*src && (*src != '}')) {
4117 alt_value[alt_index++] = *src++;
4118 }
4119 alt_value[alt_index] = 0;
4120 if (*src != '}') {
4121 err("unclosed ${\n");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004122 return 0;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004123 }
4124 }
4125 src++;
4126 }
4127
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004128 if (isalpha(*var_name)) {
4129 /* let subshell handle it instead */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004130
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004131 char *namep = var_name;
4132
4133 *dest++ = '$';
4134 if (braces)
4135 *dest++ = '{';
4136 while (*namep)
4137 *dest++ = *namep++;
4138 if (operator) {
4139 char *altp = alt_value;
4140 *dest++ = operator;
4141 while (*altp)
4142 *dest++ = *altp++;
4143 }
4144 if (braces)
4145 *dest++ = '}';
4146
4147 wb = addword(lookup(var_name)->name, wb);
4148 } else {
4149 /* expand */
4150
4151 vp = lookup(var_name);
4152 if (vp->value != null)
4153 value = (operator == '+') ?
4154 alt_value : vp->value;
4155 else if (operator == '?') {
4156 err(alt_value);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004157 return 0;
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004158 } else if (alt_index && (operator != '+')) {
4159 value = alt_value;
4160 if (operator == '=')
4161 setval(vp, value);
4162 } else
4163 continue;
4164
4165 while (*value && (count < LINELIM)) {
4166 *dest++ = *value++;
4167 count++;
4168 }
Eric Andersen737f5fb2003-03-14 16:05:59 +00004169 }
Denis Vlasenkoab801872007-12-02 08:35:37 +00004170#undef var_name
4171#undef alt_value
Eric Andersen737f5fb2003-03-14 16:05:59 +00004172 } else {
4173 *dest++ = *src++;
4174 count++;
4175 ignore_once = 0;
4176 }
4177 }
4178 *dest = '\0';
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004179
Eric Andersenff9eee42001-06-29 04:57:14 +00004180 if (openpipe(pf) < 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004181 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004182
Denis Vlasenko509697f2008-03-02 12:49:39 +00004183 while ((i = vfork()) == -1 && errno == EAGAIN)
4184 continue;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004185
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004186 DBGPRINTF3(("GRAVE: i is %p\n", io));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004187
Eric Andersen737f5fb2003-03-14 16:05:59 +00004188 if (i < 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004189 closepipe(pf);
Eric Andersen8401eea2004-08-04 19:16:54 +00004190 err((char *) bb_msg_memory_exhausted);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004191 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004192 }
4193 if (i != 0) {
Denis Vlasenkofb0eba72008-01-02 19:55:04 +00004194 waitpid(i, NULL, 0); // safe_waitpid?
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004195 global_env.iop->argp->aword = ++cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004196 close(pf[1]);
Eric Andersen8401eea2004-08-04 19:16:54 +00004197 PUSHIO(afile, remap(pf[0]),
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004198 (int (*)(struct ioarg *)) ((quoted) ? qgravechar : gravechar));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004199 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004200 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004201 /* allow trapped signals */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004202 /* XXX - Maybe this signal stuff should go as well? */
Eric Andersen8401eea2004-08-04 19:16:54 +00004203 for (j = 0; j <= _NSIG; j++)
Eric Andersen737f5fb2003-03-14 16:05:59 +00004204 if (ourtrap[j] && signal(j, SIG_IGN) != SIG_IGN)
4205 signal(j, SIG_DFL);
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004206
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00004207 /* Testcase where below checks are needed:
4208 * close stdout & run this script:
4209 * files=`ls`
4210 * echo "$files" >zz
4211 */
4212 xmove_fd(pf[1], 1);
Denis Vlasenko847fa772008-01-28 22:45:43 +00004213 if (pf[0] != 1)
4214 close(pf[0]);
Eric Andersen737f5fb2003-03-14 16:05:59 +00004215
Eric Andersen8401eea2004-08-04 19:16:54 +00004216 argument_list[0] = (char *) DEFAULT_SHELL;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004217 argument_list[1] = (char *) "-c";
Eric Andersen737f5fb2003-03-14 16:05:59 +00004218 argument_list[2] = child_cmd;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004219 argument_list[3] = NULL;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004220
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004221 cp = rexecve(argument_list[0], argument_list, makenv(1, wb));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004222 prs(argument_list[0]);
4223 prs(": ");
4224 err(cp);
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +00004225 _exit(EXIT_FAILURE);
Eric Andersenff9eee42001-06-29 04:57:14 +00004226}
4227
Eric Andersen737f5fb2003-03-14 16:05:59 +00004228
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004229static char *unquote(char *as)
Eric Andersenff9eee42001-06-29 04:57:14 +00004230{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004231 char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00004232
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004233 s = as;
4234 if (s != NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00004235 while (*s)
4236 *s++ &= ~QUOTE;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004237 return as;
Eric Andersenff9eee42001-06-29 04:57:14 +00004238}
4239
4240/* -------- glob.c -------- */
4241
4242/*
4243 * glob
4244 */
4245
4246#define scopy(x) strsave((x), areanum)
4247#define BLKSIZ 512
4248#define NDENT ((BLKSIZ+sizeof(struct dirent)-1)/sizeof(struct dirent))
4249
Eric Andersen8401eea2004-08-04 19:16:54 +00004250static struct wdblock *cl, *nl;
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00004251static const char spcl[] ALIGN1= "[?*";
Eric Andersenff9eee42001-06-29 04:57:14 +00004252
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004253static struct wdblock *glob(char *cp, struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004254{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004255 int i;
4256 char *pp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004257
4258 if (cp == 0)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004259 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004260 i = 0;
4261 for (pp = cp; *pp; pp++)
4262 if (any(*pp, spcl))
4263 i++;
4264 else if (!any(*pp & ~QUOTE, spcl))
4265 *pp &= ~QUOTE;
4266 if (i != 0) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004267 for (cl = addword(scopy(cp), NULL); anyspcl(cl); cl = nl) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004268 nl = newword(cl->w_nword * 2);
4269 for (i = 0; i < cl->w_nword; i++) { /* for each argument */
Eric Andersenff9eee42001-06-29 04:57:14 +00004270 for (pp = cl->w_words[i]; *pp; pp++)
4271 if (any(*pp, spcl)) {
4272 globname(cl->w_words[i], pp);
4273 break;
4274 }
4275 if (*pp == '\0')
4276 nl = addword(scopy(cl->w_words[i]), nl);
4277 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004278 for (i = 0; i < cl->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004279 DELETE(cl->w_words[i]);
4280 DELETE(cl);
4281 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004282 if (cl->w_nword) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004283 for (i = 0; i < cl->w_nword; i++)
Denis Vlasenkofb290382008-03-02 12:51:26 +00004284 unquote(cl->w_words[i]);
4285 qsort_string_vector(cl->w_words, cl->w_nword);
4286 for (i = 0; i < cl->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004287 wb = addword(cl->w_words[i], wb);
4288 DELETE(cl);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004289 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004290 }
4291 }
4292 wb = addword(unquote(cp), wb);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004293 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004294}
4295
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004296static void globname(char *we, char *pp)
Eric Andersenff9eee42001-06-29 04:57:14 +00004297{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004298 char *np, *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004299 char *name, *gp, *dp;
4300 int k;
4301 DIR *dirp;
4302 struct dirent *de;
Eric Andersen8401eea2004-08-04 19:16:54 +00004303 char dname[NAME_MAX + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00004304 struct stat dbuf;
4305
4306 for (np = we; np != pp; pp--)
4307 if (pp[-1] == '/')
4308 break;
Denis Vlasenkofb290382008-03-02 12:51:26 +00004309 dp = cp = get_space((int) (pp - np) + 3);
4310 while (np < pp)
Eric Andersenff9eee42001-06-29 04:57:14 +00004311 *cp++ = *np++;
4312 *cp++ = '.';
4313 *cp = '\0';
Denis Vlasenkofb290382008-03-02 12:51:26 +00004314 gp = cp = get_space(strlen(pp) + 1);
4315 while (*np && *np != '/')
Eric Andersenff9eee42001-06-29 04:57:14 +00004316 *cp++ = *np++;
4317 *cp = '\0';
4318 dirp = opendir(dp);
4319 if (dirp == 0) {
4320 DELETE(dp);
4321 DELETE(gp);
4322 return;
4323 }
4324 dname[NAME_MAX] = '\0';
Eric Andersen8401eea2004-08-04 19:16:54 +00004325 while ((de = readdir(dirp)) != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004326 /* XXX Hmmm... What this could be? (abial) */
Denis Vlasenkoed9d6212008-06-09 07:44:19 +00004327 /* if (ent[j].d_ino == 0) continue;
Eric Andersen8401eea2004-08-04 19:16:54 +00004328 */
Eric Andersenff9eee42001-06-29 04:57:14 +00004329 strncpy(dname, de->d_name, NAME_MAX);
Eric Andersen8401eea2004-08-04 19:16:54 +00004330 if (dname[0] == '.')
4331 if (*gp != '.')
4332 continue;
4333 for (k = 0; k < NAME_MAX; k++)
4334 if (any(dname[k], spcl))
4335 dname[k] |= QUOTE;
4336 if (gmatch(dname, gp)) {
4337 name = generate(we, pp, dname, np);
4338 if (*np && !anys(np, spcl)) {
4339 if (stat(name, &dbuf)) {
4340 DELETE(name);
Eric Andersenff9eee42001-06-29 04:57:14 +00004341 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00004342 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004343 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004344 nl = addword(name, nl);
4345 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004346 }
4347 closedir(dirp);
4348 DELETE(dp);
4349 DELETE(gp);
4350}
4351
4352/*
4353 * generate a pathname as below.
4354 * start..end1 / middle end
4355 * the slashes come for free
4356 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004357static char *generate(char *start1, char *end1, char *middle, char *end)
Eric Andersenff9eee42001-06-29 04:57:14 +00004358{
4359 char *p;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004360 char *op, *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004361
Denis Vlasenko509697f2008-03-02 12:49:39 +00004362 p = op = get_space((int)(end1 - start1) + strlen(middle) + strlen(end) + 2);
4363 xp = start1;
4364 while (xp != end1)
Eric Andersenff9eee42001-06-29 04:57:14 +00004365 *op++ = *xp++;
Denis Vlasenko509697f2008-03-02 12:49:39 +00004366 xp = middle;
4367 while (*xp != '\0')
4368 *op++ = *xp++;
4369 strcpy(op, end);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004370 return p;
Eric Andersenff9eee42001-06-29 04:57:14 +00004371}
4372
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004373static int anyspcl(struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004374{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004375 int i;
4376 char **wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004377
4378 wd = wb->w_words;
Eric Andersen8401eea2004-08-04 19:16:54 +00004379 for (i = 0; i < wb->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004380 if (anys(spcl, *wd++))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004381 return 1;
4382 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004383}
4384
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004385
Eric Andersenff9eee42001-06-29 04:57:14 +00004386/* -------- word.c -------- */
4387
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004388static struct wdblock *newword(int nw)
Eric Andersenff9eee42001-06-29 04:57:14 +00004389{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004390 struct wdblock *wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004391
Denis Vlasenko509697f2008-03-02 12:49:39 +00004392 wb = get_space(sizeof(*wb) + nw * sizeof(char *));
Eric Andersenff9eee42001-06-29 04:57:14 +00004393 wb->w_bsize = nw;
4394 wb->w_nword = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004395 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004396}
4397
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004398static struct wdblock *addword(char *wd, struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004399{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004400 struct wdblock *wb2;
4401 int nw;
Eric Andersenff9eee42001-06-29 04:57:14 +00004402
4403 if (wb == NULL)
4404 wb = newword(NSTART);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004405 nw = wb->w_nword;
4406 if (nw >= wb->w_bsize) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004407 wb2 = newword(nw * 2);
Eric Andersen8401eea2004-08-04 19:16:54 +00004408 memcpy((char *) wb2->w_words, (char *) wb->w_words,
4409 nw * sizeof(char *));
Eric Andersenff9eee42001-06-29 04:57:14 +00004410 wb2->w_nword = nw;
4411 DELETE(wb);
4412 wb = wb2;
4413 }
4414 wb->w_words[wb->w_nword++] = wd;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004415 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004416}
Eric Andersen8401eea2004-08-04 19:16:54 +00004417
Denis Vlasenkoe4712752007-04-14 15:08:41 +00004418static char **getwords(struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004419{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004420 char **wd;
4421 int nb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004422
4423 if (wb == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004424 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004425 if (wb->w_nword == 0) {
4426 DELETE(wb);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004427 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004428 }
Denis Vlasenko509697f2008-03-02 12:49:39 +00004429 nb = sizeof(*wd) * wb->w_nword;
4430 wd = get_space(nb);
Denis Vlasenkofb290382008-03-02 12:51:26 +00004431 memcpy(wd, wb->w_words, nb);
4432 DELETE(wb); /* perhaps should done by caller */
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004433 return wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004434}
4435
Eric Andersenff9eee42001-06-29 04:57:14 +00004436
4437/* -------- io.c -------- */
4438
4439/*
4440 * shell IO
4441 */
4442
Eric Andersen8401eea2004-08-04 19:16:54 +00004443static int my_getc(int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00004444{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004445 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004446
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004447 if (global_env.linep > elinep) {
Denis Vlasenko509697f2008-03-02 12:49:39 +00004448 while ((c = readc()) != '\n' && c)
4449 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00004450 err("input line too long");
Denis Vlasenko648b44f2008-02-12 06:04:06 +00004451 gflg = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004452 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004453 }
4454 c = readc();
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004455 if ((ec != '\'') && (ec != '`') && (global_env.iop->task != XGRAVE)) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004456 if (c == '\\') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004457 c = readc();
4458 if (c == '\n' && ec != '\"')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004459 return my_getc(ec);
Eric Andersenff9eee42001-06-29 04:57:14 +00004460 c |= QUOTE;
4461 }
4462 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004463 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004464}
4465
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004466static void unget(int c)
Eric Andersenff9eee42001-06-29 04:57:14 +00004467{
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004468 if (global_env.iop >= global_env.iobase)
4469 global_env.iop->peekc = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004470}
4471
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004472static int eofc(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00004473{
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004474 return global_env.iop < global_env.iobase || (global_env.iop->peekc == 0 && global_env.iop->prev == 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004475}
4476
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004477static int readc(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00004478{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004479 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004480
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004481 RCPRINTF(("READC: global_env.iop %p, global_env.iobase %p\n", global_env.iop, global_env.iobase));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004482
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004483 for (; global_env.iop >= global_env.iobase; global_env.iop--) {
4484 RCPRINTF(("READC: global_env.iop %p, peekc 0x%x\n", global_env.iop, global_env.iop->peekc));
4485 c = global_env.iop->peekc;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004486 if (c != '\0') {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004487 global_env.iop->peekc = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004488 return c;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004489 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004490 if (global_env.iop->prev != 0) {
4491 c = (*global_env.iop->iofn)(global_env.iop->argp, global_env.iop);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004492 if (c != '\0') {
4493 if (c == -1) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004494 global_env.iop++;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004495 continue;
Eric Andersen8401eea2004-08-04 19:16:54 +00004496 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004497 if (global_env.iop == iostack)
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004498 ioecho(c);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004499 global_env.iop->prev = c;
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00004500 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004501 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004502 if (global_env.iop->task == XIO && global_env.iop->prev != '\n') {
4503 global_env.iop->prev = 0;
4504 if (global_env.iop == iostack)
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004505 ioecho('\n');
4506 return '\n';
Eric Andersen8401eea2004-08-04 19:16:54 +00004507 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004508 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004509 if (global_env.iop->task == XIO) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004510 if (multiline) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004511 global_env.iop->prev = 0;
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00004512 return 0;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004513 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004514 if (interactive && global_env.iop == iostack + 1) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004515#if ENABLE_FEATURE_EDITING
4516 current_prompt = prompt->value;
4517#else
4518 prs(prompt->value);
4519#endif
4520 }
4521 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004522 } /* FOR */
4523
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004524 if (global_env.iop >= iostack) {
4525 RCPRINTF(("READC: return 0, global_env.iop %p\n", global_env.iop));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004526 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004527 }
4528
4529 DBGPRINTF(("READC: leave()...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00004530 leave();
4531 /* NOTREACHED */
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004532 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004533}
4534
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004535static void ioecho(char c)
Eric Andersenff9eee42001-06-29 04:57:14 +00004536{
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00004537 if (FLAG['v'])
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +00004538 write(STDERR_FILENO, &c, sizeof c);
Eric Andersenff9eee42001-06-29 04:57:14 +00004539}
4540
Eric Andersen8401eea2004-08-04 19:16:54 +00004541static void pushio(struct ioarg *argp, int (*fn) (struct ioarg *))
Eric Andersenff9eee42001-06-29 04:57:14 +00004542{
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004543 DBGPRINTF(("PUSHIO: argp %p, argp->afid 0x%x, global_env.iop %p\n", argp,
4544 argp->afid, global_env.iop));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004545
4546 /* Set env ptr for io source to next array spot and check for array overflow */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004547 if (++global_env.iop >= &iostack[NPUSH]) {
4548 global_env.iop--;
Eric Andersenff9eee42001-06-29 04:57:14 +00004549 err("Shell input nested too deeply");
Denis Vlasenko648b44f2008-02-12 06:04:06 +00004550 gflg = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004551 return;
4552 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004553
4554 /* We did not overflow the NPUSH array spots so setup data structs */
4555
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004556 global_env.iop->iofn = (int (*)(struct ioarg *, struct io *)) fn; /* Store data source func ptr */
Eric Andersenff9eee42001-06-29 04:57:14 +00004557
4558 if (argp->afid != AFID_NOBUF)
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004559 global_env.iop->argp = argp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004560 else {
Eric Andersen12de6cf2004-08-04 19:19:10 +00004561
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004562 global_env.iop->argp = ioargstack + (global_env.iop - iostack); /* MAL - index into stack */
4563 *global_env.iop->argp = *argp; /* copy data from temp area into stack spot */
Eric Andersen12de6cf2004-08-04 19:19:10 +00004564
4565 /* MAL - mainbuf is for 1st data source (command line?) and all nested use a single shared buffer? */
4566
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004567 if (global_env.iop == &iostack[0])
4568 global_env.iop->argp->afbuf = &mainbuf;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004569 else
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004570 global_env.iop->argp->afbuf = &sharedbuf;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004571
4572 /* MAL - if not a termimal AND (commandline OR readable file) then give it a buffer id? */
4573 /* This line appears to be active when running scripts from command line */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004574 if ((isatty(global_env.iop->argp->afile) == 0)
4575 && (global_env.iop == &iostack[0]
4576 || lseek(global_env.iop->argp->afile, 0L, SEEK_CUR) != -1)) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00004577 if (++bufid == AFID_NOBUF) /* counter rollover check, AFID_NOBUF = 11111111 */
4578 bufid = AFID_ID; /* AFID_ID = 0 */
4579
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004580 global_env.iop->argp->afid = bufid; /* assign buffer id */
Eric Andersen8401eea2004-08-04 19:16:54 +00004581 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004582
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004583 DBGPRINTF(("PUSHIO: iostack %p, global_env.iop %p, afbuf %p\n",
4584 iostack, global_env.iop, global_env.iop->argp->afbuf));
4585 DBGPRINTF(("PUSHIO: mbuf %p, sbuf %p, bid %d, global_env.iop %p\n",
4586 &mainbuf, &sharedbuf, bufid, global_env.iop));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004587
Eric Andersenff9eee42001-06-29 04:57:14 +00004588 }
4589
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004590 global_env.iop->prev = ~'\n';
4591 global_env.iop->peekc = 0;
4592 global_env.iop->xchar = 0;
4593 global_env.iop->nlcount = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004594
Eric Andersenff9eee42001-06-29 04:57:14 +00004595 if (fn == filechar || fn == linechar)
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004596 global_env.iop->task = XIO;
Eric Andersen8401eea2004-08-04 19:16:54 +00004597 else if (fn == (int (*)(struct ioarg *)) gravechar
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00004598 || fn == (int (*)(struct ioarg *)) qgravechar)
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004599 global_env.iop->task = XGRAVE;
Eric Andersenff9eee42001-06-29 04:57:14 +00004600 else
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004601 global_env.iop->task = XOTHER;
Eric Andersenff9eee42001-06-29 04:57:14 +00004602}
4603
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004604static struct io *setbase(struct io *ip)
Eric Andersenff9eee42001-06-29 04:57:14 +00004605{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004606 struct io *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004607
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004608 xp = global_env.iobase;
4609 global_env.iobase = ip;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004610 return xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004611}
4612
4613/*
4614 * Input generating functions
4615 */
4616
4617/*
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00004618 * Produce the characters of a string, then a newline, then NUL.
Eric Andersenff9eee42001-06-29 04:57:14 +00004619 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004620static int nlchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004621{
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00004622 char c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004623
4624 if (ap->aword == NULL)
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00004625 return '\0';
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004626 c = *ap->aword++;
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00004627 if (c == '\0') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004628 ap->aword = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004629 return '\n';
Eric Andersenff9eee42001-06-29 04:57:14 +00004630 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004631 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004632}
4633
4634/*
4635 * Given a list of words, produce the characters
4636 * in them, with a space after each word.
4637 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004638static int wdchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004639{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004640 char c;
4641 char **wl;
Eric Andersenff9eee42001-06-29 04:57:14 +00004642
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004643 wl = ap->awordlist;
4644 if (wl == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004645 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004646 if (*wl != NULL) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004647 c = *(*wl)++;
4648 if (c != 0)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004649 return c & 0177;
Eric Andersenff9eee42001-06-29 04:57:14 +00004650 ap->awordlist++;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004651 return ' ';
Eric Andersenff9eee42001-06-29 04:57:14 +00004652 }
4653 ap->awordlist = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004654 return '\n';
Eric Andersenff9eee42001-06-29 04:57:14 +00004655}
4656
4657/*
4658 * Return the characters of a list of words,
4659 * producing a space between them.
4660 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004661static int dolchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004662{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004663 char *wp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004664
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004665 wp = *ap->awordlist++;
4666 if (wp != NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004667 PUSHIO(aword, wp, *ap->awordlist == NULL ? strchar : xxchar);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004668 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004669 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004670 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004671}
4672
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004673static int xxchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004674{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004675 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004676
4677 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004678 return 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004679 c = *ap->aword++;
4680 if (c == '\0') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004681 ap->aword = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004682 return ' ';
Eric Andersenff9eee42001-06-29 04:57:14 +00004683 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004684 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004685}
4686
4687/*
4688 * Produce the characters from a single word (string).
4689 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004690static int strchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004691{
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004692 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004693 return 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004694 return *ap->aword++;
Eric Andersenff9eee42001-06-29 04:57:14 +00004695}
4696
4697/*
4698 * Produce quoted characters from a single word (string).
4699 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004700static int qstrchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004701{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004702 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004703
Denis Vlasenkob2abef32007-01-01 18:18:04 +00004704 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004705 return 0;
Denis Vlasenkob2abef32007-01-01 18:18:04 +00004706 c = *ap->aword++;
4707 if (c)
4708 c |= QUOTE;
4709 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004710}
4711
4712/*
4713 * Return the characters from a file.
4714 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004715static int filechar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004716{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004717 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004718 char c;
4719 struct iobuf *bp = ap->afbuf;
4720
4721 if (ap->afid != AFID_NOBUF) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004722 i = (ap->afid != bp->id);
4723 if (i || bp->bufp == bp->ebufp) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004724 if (i)
Denis Vlasenkoea620772006-10-14 02:23:43 +00004725 lseek(ap->afile, ap->afpos, SEEK_SET);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004726
Denis Vlasenkoe376d452008-02-20 22:23:24 +00004727 i = nonblock_safe_read(ap->afile, bp->buf, sizeof(bp->buf));
Eric Andersen8401eea2004-08-04 19:16:54 +00004728 if (i <= 0) {
4729 closef(ap->afile);
4730 return 0;
4731 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004732
Eric Andersen8401eea2004-08-04 19:16:54 +00004733 bp->id = ap->afid;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004734 bp->bufp = bp->buf;
4735 bp->ebufp = bp->bufp + i;
Eric Andersen8401eea2004-08-04 19:16:54 +00004736 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004737
Eric Andersen8401eea2004-08-04 19:16:54 +00004738 ap->afpos++;
4739 return *bp->bufp++ & 0177;
Eric Andersenff9eee42001-06-29 04:57:14 +00004740 }
Denis Vlasenko38f63192007-01-22 09:03:07 +00004741#if ENABLE_FEATURE_EDITING
Eric Andersen737f5fb2003-03-14 16:05:59 +00004742 if (interactive && isatty(ap->afile)) {
Denis Vlasenko55f30b02007-03-24 22:42:29 +00004743 /* moved to G: static char filechar_cmdbuf[BUFSIZ]; */
Eric Andersen8401eea2004-08-04 19:16:54 +00004744 static int position = 0, size = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004745
Eric Andersen8401eea2004-08-04 19:16:54 +00004746 while (size == 0 || position >= size) {
Denis Vlasenko6e602c42008-02-02 18:50:50 +00004747 size = read_line_input(current_prompt, filechar_cmdbuf, BUFSIZ, line_input_state);
4748 if (size < 0) /* Error/EOF */
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +00004749 exit(EXIT_SUCCESS);
Eric Andersen8401eea2004-08-04 19:16:54 +00004750 position = 0;
Denis Vlasenko6e602c42008-02-02 18:50:50 +00004751 /* if Ctrl-C, size == 0 and loop will repeat */
Eric Andersen8401eea2004-08-04 19:16:54 +00004752 }
Denis Vlasenko55f30b02007-03-24 22:42:29 +00004753 c = filechar_cmdbuf[position];
Eric Andersen8401eea2004-08-04 19:16:54 +00004754 position++;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004755 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004756 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004757#endif
Denis Vlasenkoe376d452008-02-20 22:23:24 +00004758 i = nonblock_safe_read(ap->afile, &c, sizeof(c));
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004759 return i == sizeof(c) ? (c & 0x7f) : (closef(ap->afile), 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004760}
4761
4762/*
4763 * Return the characters from a here temp file.
4764 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004765static int herechar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004766{
4767 char c;
4768
Denis Vlasenkoe376d452008-02-20 22:23:24 +00004769 if (nonblock_safe_read(ap->afile, &c, sizeof(c)) != sizeof(c)) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004770 close(ap->afile);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004771 c = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00004772 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004773 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004774}
4775
4776/*
4777 * Return the characters produced by a process (`...`).
4778 * Quote them if required, and remove any trailing newline characters.
4779 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004780static int gravechar(struct ioarg *ap, struct io *iop)
Eric Andersenff9eee42001-06-29 04:57:14 +00004781{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004782 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004783
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004784 c = qgravechar(ap, iop) & ~QUOTE;
4785 if (c == '\n')
Eric Andersenff9eee42001-06-29 04:57:14 +00004786 c = ' ';
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004787 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004788}
4789
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004790static int qgravechar(struct ioarg *ap, struct io *iop)
Eric Andersenff9eee42001-06-29 04:57:14 +00004791{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004792 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004793
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004794 DBGPRINTF3(("QGRAVECHAR: enter, ap=%p, iop=%p\n", ap, iop));
Eric Andersenff9eee42001-06-29 04:57:14 +00004795
4796 if (iop->xchar) {
4797 if (iop->nlcount) {
4798 iop->nlcount--;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004799 return '\n' | QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00004800 }
4801 c = iop->xchar;
4802 iop->xchar = 0;
4803 } else if ((c = filechar(ap)) == '\n') {
4804 iop->nlcount = 1;
4805 while ((c = filechar(ap)) == '\n')
4806 iop->nlcount++;
4807 iop->xchar = c;
4808 if (c == 0)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004809 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004810 iop->nlcount--;
4811 c = '\n';
4812 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004813 return c != 0 ? c | QUOTE : 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004814}
4815
4816/*
4817 * Return a single command (usually the first line) from a file.
4818 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004819static int linechar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004820{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004821 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004822
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004823 c = filechar(ap);
4824 if (c == '\n') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004825 if (!multiline) {
4826 closef(ap->afile);
Eric Andersen8401eea2004-08-04 19:16:54 +00004827 ap->afile = -1; /* illegal value */
Eric Andersenff9eee42001-06-29 04:57:14 +00004828 }
4829 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004830 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004831}
4832
Eric Andersenff9eee42001-06-29 04:57:14 +00004833/*
Denis Vlasenkoed9d6212008-06-09 07:44:19 +00004834 * Remap fd into shell's fd space
Eric Andersenff9eee42001-06-29 04:57:14 +00004835 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004836static int remap(int fd)
Eric Andersenff9eee42001-06-29 04:57:14 +00004837{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004838 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004839 int map[NOFILE];
Eric Andersen12de6cf2004-08-04 19:19:10 +00004840 int newfd;
4841
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004842 DBGPRINTF(("REMAP: fd=%d, global_env.iofd=%d\n", fd, global_env.iofd));
Eric Andersenff9eee42001-06-29 04:57:14 +00004843
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004844 if (fd < global_env.iofd) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004845 for (i = 0; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004846 map[i] = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004847
Eric Andersenff9eee42001-06-29 04:57:14 +00004848 do {
4849 map[fd] = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004850 newfd = dup(fd);
4851 fd = newfd;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004852 } while (fd >= 0 && fd < global_env.iofd);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004853
Eric Andersen8401eea2004-08-04 19:16:54 +00004854 for (i = 0; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004855 if (map[i])
4856 close(i);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004857
Eric Andersenff9eee42001-06-29 04:57:14 +00004858 if (fd < 0)
4859 err("too many files open in shell");
4860 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004861
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004862 return fd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004863}
4864
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004865static int openpipe(int *pv)
Eric Andersenff9eee42001-06-29 04:57:14 +00004866{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004867 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004868
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004869 i = pipe(pv);
4870 if (i < 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00004871 err("can't create pipe - try again");
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004872 return i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004873}
4874
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004875static void closepipe(int *pv)
Eric Andersenff9eee42001-06-29 04:57:14 +00004876{
4877 if (pv != NULL) {
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00004878 close(pv[0]);
4879 close(pv[1]);
Eric Andersenff9eee42001-06-29 04:57:14 +00004880 }
4881}
4882
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004883
Eric Andersenff9eee42001-06-29 04:57:14 +00004884/* -------- here.c -------- */
4885
4886/*
4887 * here documents
4888 */
4889
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004890static void markhere(char *s, struct ioword *iop)
Eric Andersenff9eee42001-06-29 04:57:14 +00004891{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004892 struct here *h, *lh;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004893
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004894 DBGPRINTF7(("MARKHERE: enter, s=%p\n", s));
Eric Andersenff9eee42001-06-29 04:57:14 +00004895
Denis Vlasenko509697f2008-03-02 12:49:39 +00004896 h = get_space(sizeof(struct here));
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004897 if (h == NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00004898 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004899
Eric Andersenff9eee42001-06-29 04:57:14 +00004900 h->h_tag = evalstr(s, DOSUB);
4901 if (h->h_tag == 0)
4902 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004903
Eric Andersenff9eee42001-06-29 04:57:14 +00004904 h->h_iop = iop;
4905 iop->io_name = 0;
4906 h->h_next = NULL;
4907 if (inhere == 0)
4908 inhere = h;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004909 else {
4910 for (lh = inhere; lh != NULL; lh = lh->h_next) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004911 if (lh->h_next == 0) {
4912 lh->h_next = h;
4913 break;
4914 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004915 }
4916 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004917 iop->io_flag |= IOHERE | IOXHERE;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004918 for (s = h->h_tag; *s; s++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004919 if (*s & QUOTE) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004920 iop->io_flag &= ~IOXHERE;
4921 *s &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00004922 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004923 }
Denis Vlasenko648b44f2008-02-12 06:04:06 +00004924 h->h_dosub = ((iop->io_flag & IOXHERE) ? '\0' : '\'');
Eric Andersenff9eee42001-06-29 04:57:14 +00004925}
4926
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004927static void gethere(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00004928{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004929 struct here *h, *hp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004930
4931 DBGPRINTF7(("GETHERE: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00004932
4933 /* Scan here files first leaving inhere list in place */
4934 for (hp = h = inhere; h != NULL; hp = h, h = h->h_next)
Denis Vlasenko648b44f2008-02-12 06:04:06 +00004935 readhere(&h->h_iop->io_name, h->h_tag, h->h_dosub /* NUL or ' */);
Eric Andersenff9eee42001-06-29 04:57:14 +00004936
4937 /* Make inhere list active - keep list intact for scraphere */
4938 if (hp != NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004939 hp->h_next = acthere;
4940 acthere = inhere;
4941 inhere = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004942 }
4943}
4944
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004945static void readhere(char **name, char *s, int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00004946{
4947 int tf;
4948 char tname[30] = ".msh_XXXXXX";
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004949 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004950 jmp_buf ev;
Eric Andersen8401eea2004-08-04 19:16:54 +00004951 char myline[LINELIM + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00004952 char *thenext;
4953
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004954 DBGPRINTF7(("READHERE: enter, name=%p, s=%p\n", name, s));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004955
Eric Andersenff9eee42001-06-29 04:57:14 +00004956 tf = mkstemp(tname);
4957 if (tf < 0)
4958 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004959
Eric Andersenff9eee42001-06-29 04:57:14 +00004960 *name = strsave(tname, areanum);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004961 errpt = ev;
4962 if (newenv(setjmp(errpt)) != 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00004963 unlink(tname);
4964 else {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004965 pushio(global_env.iop->argp, (int (*)(struct ioarg *)) global_env.iop->iofn);
4966 global_env.iobase = global_env.iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00004967 for (;;) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004968 if (interactive && global_env.iop <= iostack) {
Denis Vlasenko38f63192007-01-22 09:03:07 +00004969#if ENABLE_FEATURE_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00004970 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00004971#else
Eric Andersen8401eea2004-08-04 19:16:54 +00004972 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00004973#endif
4974 }
4975 thenext = myline;
4976 while ((c = my_getc(ec)) != '\n' && c) {
4977 if (ec == '\'')
Eric Andersen8401eea2004-08-04 19:16:54 +00004978 c &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00004979 if (thenext >= &myline[LINELIM]) {
4980 c = 0;
4981 break;
4982 }
4983 *thenext++ = c;
4984 }
4985 *thenext = 0;
4986 if (strcmp(s, myline) == 0 || c == 0)
4987 break;
4988 *thenext++ = '\n';
Eric Andersen8401eea2004-08-04 19:16:54 +00004989 write(tf, myline, (int) (thenext - myline));
Eric Andersenff9eee42001-06-29 04:57:14 +00004990 }
4991 if (c == 0) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004992 prs("here document `");
4993 prs(s);
4994 err("' unclosed");
Eric Andersenff9eee42001-06-29 04:57:14 +00004995 }
4996 quitenv();
4997 }
4998 close(tf);
4999}
5000
5001/*
5002 * open here temp file.
5003 * if unquoted here, expand here temp file into second temp file.
5004 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005005static int herein(char *hname, int xdoll)
Eric Andersenff9eee42001-06-29 04:57:14 +00005006{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005007 int hf;
Eric Andersenff9eee42001-06-29 04:57:14 +00005008 int tf;
5009
5010#if __GNUC__
5011 /* Avoid longjmp clobbering */
5012 (void) &tf;
5013#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00005014 if (hname == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00005015 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005016
5017 DBGPRINTF7(("HEREIN: hname is %s, xdoll=%d\n", hname, xdoll));
5018
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005019 hf = open(hname, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00005020 if (hf < 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00005021 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005022
Eric Andersenff9eee42001-06-29 04:57:14 +00005023 if (xdoll) {
5024 char c;
5025 char tname[30] = ".msh_XXXXXX";
5026 jmp_buf ev;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005027
Eric Andersenff9eee42001-06-29 04:57:14 +00005028 tf = mkstemp(tname);
5029 if (tf < 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00005030 return -1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00005031 errpt = ev;
5032 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00005033 PUSHIO(afile, hf, herechar);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005034 setbase(global_env.iop);
Eric Andersenff9eee42001-06-29 04:57:14 +00005035 while ((c = subgetc(0, 0)) != 0) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005036 c &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00005037 write(tf, &c, sizeof c);
5038 }
5039 quitenv();
5040 } else
5041 unlink(tname);
5042 close(tf);
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005043 tf = open(tname, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00005044 unlink(tname);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00005045 return tf;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00005046 }
5047 return hf;
Eric Andersenff9eee42001-06-29 04:57:14 +00005048}
5049
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005050static void scraphere(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00005051{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005052 struct here *h;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005053
5054 DBGPRINTF7(("SCRAPHERE: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00005055
5056 for (h = inhere; h != NULL; h = h->h_next) {
5057 if (h->h_iop && h->h_iop->io_name)
Eric Andersen8401eea2004-08-04 19:16:54 +00005058 unlink(h->h_iop->io_name);
Eric Andersenff9eee42001-06-29 04:57:14 +00005059 }
5060 inhere = NULL;
5061}
5062
5063/* unlink here temp files before a freearea(area) */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005064static void freehere(int area)
Eric Andersenff9eee42001-06-29 04:57:14 +00005065{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005066 struct here *h, *hl;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005067
5068 DBGPRINTF6(("FREEHERE: enter, area=%d\n", area));
Eric Andersenff9eee42001-06-29 04:57:14 +00005069
5070 hl = NULL;
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00005071 for (h = acthere; h != NULL; h = h->h_next) {
Eric Andersenff9eee42001-06-29 04:57:14 +00005072 if (getarea((char *) h) >= area) {
5073 if (h->h_iop->io_name != NULL)
5074 unlink(h->h_iop->io_name);
5075 if (hl == NULL)
5076 acthere = h->h_next;
5077 else
5078 hl->h_next = h->h_next;
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00005079 } else {
Eric Andersenff9eee42001-06-29 04:57:14 +00005080 hl = h;
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00005081 }
5082 }
Eric Andersenff9eee42001-06-29 04:57:14 +00005083}
5084
5085
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005086/* -------- sh.c -------- */
5087/*
5088 * shell
5089 */
5090
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00005091int msh_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005092int msh_main(int argc, char **argv)
5093{
5094 int f;
5095 char *s;
5096 int cflag;
5097 char *name, **ap;
5098 int (*iof) (struct ioarg *);
5099
Denis Vlasenkoab801872007-12-02 08:35:37 +00005100 INIT_G();
5101
Denis Vlasenko55f30b02007-03-24 22:42:29 +00005102 sharedbuf.id = AFID_NOBUF;
5103 mainbuf.id = AFID_NOBUF;
Denis Vlasenko55f30b02007-03-24 22:42:29 +00005104 elinep = line + sizeof(line) - 5;
5105
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005106#if ENABLE_FEATURE_EDITING
5107 line_input_state = new_line_input_t(FOR_SHELL);
5108#endif
5109
5110 DBGPRINTF(("MSH_MAIN: argc %d, environ %p\n", argc, environ));
5111
5112 initarea();
5113 ap = environ;
5114 if (ap != NULL) {
5115 while (*ap)
5116 assign(*ap++, !COPYV);
5117 for (ap = environ; *ap;)
5118 export(lookup(*ap++));
5119 }
5120 closeall();
5121 areanum = 1;
5122
5123 shell = lookup("SHELL");
5124 if (shell->value == null)
5125 setval(shell, (char *)DEFAULT_SHELL);
5126 export(shell);
5127
5128 homedir = lookup("HOME");
5129 if (homedir->value == null)
5130 setval(homedir, "/");
5131 export(homedir);
5132
5133 setval(lookup("$"), putn(getpid()));
5134
5135 path = lookup("PATH");
5136 if (path->value == null) {
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005137 /* Can be merged with same string elsewhere in bbox */
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005138 if (geteuid() == 0)
Denis Vlasenkof5f75c52007-06-12 22:35:19 +00005139 setval(path, bb_default_root_path);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005140 else
Denis Vlasenkof5f75c52007-06-12 22:35:19 +00005141 setval(path, bb_default_path);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005142 }
5143 export(path);
5144
5145 ifs = lookup("IFS");
5146 if (ifs->value == null)
5147 setval(ifs, " \t\n");
5148
5149#ifdef MSHDEBUG
5150 mshdbg_var = lookup("MSHDEBUG");
5151 if (mshdbg_var->value == null)
5152 setval(mshdbg_var, "0");
5153#endif
5154
5155 prompt = lookup("PS1");
5156#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
5157 if (prompt->value == null)
5158#endif
5159 setval(prompt, DEFAULT_USER_PROMPT);
5160 if (geteuid() == 0) {
5161 setval(prompt, DEFAULT_ROOT_PROMPT);
5162 prompt->status &= ~EXPORT;
5163 }
5164 cprompt = lookup("PS2");
5165#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
5166 if (cprompt->value == null)
5167#endif
5168 setval(cprompt, "> ");
5169
5170 iof = filechar;
5171 cflag = 0;
5172 name = *argv++;
5173 if (--argc >= 1) {
5174 if (argv[0][0] == '-' && argv[0][1] != '\0') {
5175 for (s = argv[0] + 1; *s; s++)
5176 switch (*s) {
5177 case 'c':
5178 prompt->status &= ~EXPORT;
5179 cprompt->status &= ~EXPORT;
5180 setval(prompt, "");
5181 setval(cprompt, "");
5182 cflag = 1;
5183 if (--argc > 0)
5184 PUSHIO(aword, *++argv, iof = nlchar);
5185 break;
5186
5187 case 'q':
5188 qflag = SIG_DFL;
5189 break;
5190
5191 case 's':
5192 /* standard input */
5193 break;
5194
5195 case 't':
5196 prompt->status &= ~EXPORT;
5197 setval(prompt, "");
5198 iof = linechar;
5199 break;
5200
5201 case 'i':
Denis Vlasenko648b44f2008-02-12 06:04:06 +00005202 interactive = 1;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005203 default:
5204 if (*s >= 'a' && *s <= 'z')
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00005205 FLAG[(int) *s]++;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005206 }
5207 } else {
5208 argv--;
5209 argc++;
5210 }
5211
5212 if (iof == filechar && --argc > 0) {
5213 setval(prompt, "");
5214 setval(cprompt, "");
5215 prompt->status &= ~EXPORT;
5216 cprompt->status &= ~EXPORT;
5217
5218/* Shell is non-interactive, activate printf-based debug */
5219#ifdef MSHDEBUG
Denis Vlasenkoed9d6212008-06-09 07:44:19 +00005220 mshdbg = mshdbg_var->value[0] - '0';
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005221 if (mshdbg < 0)
5222 mshdbg = 0;
5223#endif
5224 DBGPRINTF(("MSH_MAIN: calling newfile()\n"));
5225
5226 name = *++argv;
5227 if (newfile(name))
Denis Vlasenkoed9d6212008-06-09 07:44:19 +00005228 exit(EXIT_FAILURE); /* Exit on error */
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005229 }
5230 }
5231
5232 setdash();
5233
5234 /* This won't be true if PUSHIO has been called, say from newfile() above */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005235 if (global_env.iop < iostack) {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005236 PUSHIO(afile, 0, iof);
5237 if (isatty(0) && isatty(1) && !cflag) {
Denis Vlasenko648b44f2008-02-12 06:04:06 +00005238 interactive = 1;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005239#if !ENABLE_FEATURE_SH_EXTRA_QUIET
5240#ifdef MSHDEBUG
Denis Vlasenkoca525b42007-06-13 12:27:17 +00005241 printf("\n\n%s built-in shell (msh with debug)\n", bb_banner);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005242#else
Denis Vlasenkoca525b42007-06-13 12:27:17 +00005243 printf("\n\n%s built-in shell (msh)\n", bb_banner);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005244#endif
5245 printf("Enter 'help' for a list of built-in commands.\n\n");
5246#endif
5247 }
5248 }
5249
5250 signal(SIGQUIT, qflag);
5251 if (name && name[0] == '-') {
Denis Vlasenko648b44f2008-02-12 06:04:06 +00005252 interactive = 1;
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005253 f = open(".profile", O_RDONLY);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005254 if (f >= 0)
5255 next(remap(f));
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005256 f = open("/etc/profile", O_RDONLY);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005257 if (f >= 0)
5258 next(remap(f));
5259 }
5260 if (interactive)
5261 signal(SIGTERM, sig);
5262
5263 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
5264 signal(SIGINT, onintr);
Denis Vlasenkofee2d0c2008-02-12 10:12:18 +00005265
5266/* Handle "msh SCRIPT VAR=val params..." */
5267/* Disabled: bash does not do it! */
5268#if 0
5269 argv++;
5270 /* skip leading args of the form VAR=val */
5271 while (*argv && assign(*argv, !COPYV)) {
5272 argc--;
5273 argv++;
5274 }
5275 argv--;
5276#endif
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005277 dolv = argv;
5278 dolc = argc;
5279 dolv[0] = name;
Denis Vlasenkofee2d0c2008-02-12 10:12:18 +00005280
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005281 setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc));
5282
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005283 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 +00005284
5285 for (;;) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005286 if (interactive && global_env.iop <= iostack) {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005287#if ENABLE_FEATURE_EDITING
5288 current_prompt = prompt->value;
5289#else
5290 prs(prompt->value);
5291#endif
5292 }
5293 onecommand();
5294 /* Ensure that getenv("PATH") stays current */
5295 setenv("PATH", path->value, 1);
5296 }
5297
5298 DBGPRINTF(("MSH_MAIN: returning.\n"));
5299}
5300
5301
Eric Andersenff9eee42001-06-29 04:57:14 +00005302/*
5303 * Copyright (c) 1987,1997, Prentice Hall
5304 * All rights reserved.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005305 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005306 * Redistribution and use of the MINIX operating system in source and
5307 * binary forms, with or without modification, are permitted provided
5308 * that the following conditions are met:
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005309 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005310 * Redistributions of source code must retain the above copyright
5311 * notice, this list of conditions and the following disclaimer.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005312 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005313 * Redistributions in binary form must reproduce the above
5314 * copyright notice, this list of conditions and the following
5315 * disclaimer in the documentation and/or other materials provided
5316 * with the distribution.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005317 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005318 * Neither the name of Prentice Hall nor the names of the software
5319 * authors or contributors may be used to endorse or promote
5320 * products derived from this software without specific prior
5321 * written permission.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005322 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005323 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND
5324 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
5325 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
5326 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
5327 * IN NO EVENT SHALL PRENTICE HALL OR ANY AUTHORS OR CONTRIBUTORS BE
5328 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
5329 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
5330 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
5331 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
5332 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
5333 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
5334 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5335 *
5336 */