blob: fe2cca816684e2dc4c6bc117ccad2fdb399b4342 [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 */
Denis Vlasenko95cb3262007-04-09 03:06:34 +000015#include <sys/times.h>
16#include <setjmp.h>
Denis Vlasenko55f30b02007-03-24 22:42:29 +000017
Mike Frysinger67a32ad2007-03-09 08:25:24 +000018#ifdef STANDALONE
19# ifndef _GNU_SOURCE
20# define _GNU_SOURCE
21# endif
Mike Frysinger67a32ad2007-03-09 08:25:24 +000022# include <sys/types.h>
23# include <sys/stat.h>
24# include <sys/wait.h>
25# include <signal.h>
26# include <stdio.h>
27# include <stdlib.h>
28# include <unistd.h>
29# include <string.h>
30# include <errno.h>
31# include <dirent.h>
32# include <fcntl.h>
33# include <ctype.h>
34# include <assert.h>
35# define bb_dev_null "/dev/null"
36# define DEFAULT_SHELL "/proc/self/exe"
Denis Vlasenkoca525b42007-06-13 12:27:17 +000037# define bb_banner "busybox standalone"
Denis Vlasenko80d14be2007-04-10 23:03:30 +000038# define ENABLE_FEATURE_SH_STANDALONE 0
Mike Frysinger67a32ad2007-03-09 08:25:24 +000039# define bb_msg_memory_exhausted "memory exhausted"
40# define xmalloc(size) malloc(size)
41# define msh_main(argc,argv) main(argc,argv)
42# define safe_read(fd,buf,count) read(fd,buf,count)
Denis Vlasenkoe376d452008-02-20 22:23:24 +000043# define nonblock_safe_read(fd,buf,count) read(fd,buf,count)
Mike Frysinger67a32ad2007-03-09 08:25:24 +000044# define NOT_LONE_DASH(s) ((s)[0] != '-' || (s)[1])
45# define LONE_CHAR(s,c) ((s)[0] == (c) && !(s)[1])
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000046# define NORETURN __attribute__ ((__noreturn__))
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000047static int find_applet_by_name(const char *applet)
Mike Frysinger67a32ad2007-03-09 08:25:24 +000048{
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000049 return -1;
Mike Frysinger67a32ad2007-03-09 08:25:24 +000050}
Denis Vlasenko10457b92007-03-27 22:01:31 +000051static char *utoa_to_buf(unsigned n, char *buf, unsigned buflen)
Mike Frysinger67a32ad2007-03-09 08:25:24 +000052{
Denis Vlasenkoc86e0522007-03-20 11:30:28 +000053 unsigned i, out, res;
54 assert(sizeof(unsigned) == 4);
55 if (buflen) {
56 out = 0;
57 for (i = 1000000000; i; i /= 10) {
58 res = n / i;
59 if (res || out || i == 1) {
Denis Vlasenko4b924f32007-05-30 00:29:55 +000060 if (!--buflen) break;
61 out++;
62 n -= res*i;
63 *buf++ = '0' + res;
Denis Vlasenkoc86e0522007-03-20 11:30:28 +000064 }
65 }
Denis Vlasenkoc86e0522007-03-20 11:30:28 +000066 }
Denis Vlasenko10457b92007-03-27 22:01:31 +000067 return buf;
Mike Frysinger67a32ad2007-03-09 08:25:24 +000068}
Denis Vlasenko10457b92007-03-27 22:01:31 +000069static char *itoa_to_buf(int n, char *buf, unsigned buflen)
Mike Frysinger67a32ad2007-03-09 08:25:24 +000070{
Denis Vlasenkoc86e0522007-03-20 11:30:28 +000071 if (buflen && n < 0) {
72 n = -n;
73 *buf++ = '-';
74 buflen--;
75 }
Denis Vlasenko10457b92007-03-27 22:01:31 +000076 return utoa_to_buf((unsigned)n, buf, buflen);
Mike Frysinger67a32ad2007-03-09 08:25:24 +000077}
78static char local_buf[12];
79static char *itoa(int n)
80{
Denis Vlasenko10457b92007-03-27 22:01:31 +000081 *(itoa_to_buf(n, local_buf, sizeof(local_buf))) = '\0';
Denis Vlasenkoc86e0522007-03-20 11:30:28 +000082 return local_buf;
Mike Frysinger67a32ad2007-03-09 08:25:24 +000083}
84#else
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000085# include "busybox.h" /* for applet_names */
Mike Frysinger67a32ad2007-03-09 08:25:24 +000086#endif
Eric Andersenff9eee42001-06-29 04:57:14 +000087
Denis Vlasenko7e497522008-02-12 09:51:03 +000088//#define MSHDEBUG 4
Eric Andersen12de6cf2004-08-04 19:19:10 +000089
90#ifdef MSHDEBUG
Denis Vlasenko509697f2008-03-02 12:49:39 +000091static int mshdbg = MSHDEBUG;
Eric Andersen12de6cf2004-08-04 19:19:10 +000092
Denis Vlasenkoed9d6212008-06-09 07:44:19 +000093#define DBGPRINTF(x) if (mshdbg > 0) printf x
94#define DBGPRINTF0(x) if (mshdbg > 0) printf x
95#define DBGPRINTF1(x) if (mshdbg > 1) printf x
96#define DBGPRINTF2(x) if (mshdbg > 2) printf x
97#define DBGPRINTF3(x) if (mshdbg > 3) printf x
98#define DBGPRINTF4(x) if (mshdbg > 4) printf x
99#define DBGPRINTF5(x) if (mshdbg > 5) printf x
100#define DBGPRINTF6(x) if (mshdbg > 6) printf x
101#define DBGPRINTF7(x) if (mshdbg > 7) printf x
102#define DBGPRINTF8(x) if (mshdbg > 8) printf x
103#define DBGPRINTF9(x) if (mshdbg > 9) printf x
Eric Andersen12de6cf2004-08-04 19:19:10 +0000104
Denis Vlasenko509697f2008-03-02 12:49:39 +0000105static int mshdbg_rc = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +0000106
Denis Vlasenko51742f42007-04-12 00:32:05 +0000107#define RCPRINTF(x) if (mshdbg_rc) printf x
Eric Andersen12de6cf2004-08-04 19:19:10 +0000108
109#else
110
111#define DBGPRINTF(x)
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000112#define DBGPRINTF0(x) ((void)0)
113#define DBGPRINTF1(x) ((void)0)
114#define DBGPRINTF2(x) ((void)0)
115#define DBGPRINTF3(x) ((void)0)
116#define DBGPRINTF4(x) ((void)0)
117#define DBGPRINTF5(x) ((void)0)
118#define DBGPRINTF6(x) ((void)0)
119#define DBGPRINTF7(x) ((void)0)
120#define DBGPRINTF8(x) ((void)0)
121#define DBGPRINTF9(x) ((void)0)
Eric Andersen12de6cf2004-08-04 19:19:10 +0000122
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000123#define RCPRINTF(x) ((void)0)
Eric Andersen12de6cf2004-08-04 19:19:10 +0000124
Denis Vlasenkoed9d6212008-06-09 07:44:19 +0000125#endif /* MSHDEBUG */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000126
127
Denis Vlasenko38f63192007-01-22 09:03:07 +0000128#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
Mike Frysinger2a131752006-06-06 06:26:12 +0000129# define DEFAULT_ROOT_PROMPT "\\u:\\w> "
130# define DEFAULT_USER_PROMPT "\\u:\\w$ "
131#else
132# define DEFAULT_ROOT_PROMPT "# "
133# define DEFAULT_USER_PROMPT "$ "
134#endif
135
136
Eric Andersenff9eee42001-06-29 04:57:14 +0000137/* -------- sh.h -------- */
138/*
139 * shell
140 */
141
Denis Vlasenkoed9d6212008-06-09 07:44:19 +0000142#define LINELIM 2100
143#define NPUSH 8 /* limit to input nesting */
Eric Andersenff9eee42001-06-29 04:57:14 +0000144
Eric Andersen392947c2002-12-11 07:42:46 +0000145#undef NOFILE
Denis Vlasenkoed9d6212008-06-09 07:44:19 +0000146#define NOFILE 20 /* Number of open files */
147#define NUFILE 10 /* Number of user-accessible files */
148#define FDBASE 10 /* First file usable by Shell */
Eric Andersenff9eee42001-06-29 04:57:14 +0000149
150/*
151 * values returned by wait
152 */
Denis Vlasenko5f9468e2007-04-14 13:22:09 +0000153#define WAITSIG(s) ((s) & 0177)
154#define WAITVAL(s) (((s) >> 8) & 0377)
155#define WAITCORE(s) (((s) & 0200) != 0)
Eric Andersenff9eee42001-06-29 04:57:14 +0000156
157/*
Eric Andersenaff114c2004-04-14 17:51:38 +0000158 * library and system definitions
Eric Andersenff9eee42001-06-29 04:57:14 +0000159 */
Denis Vlasenkoed9d6212008-06-09 07:44:19 +0000160typedef void xint; /* base type of jmp_buf, for not broken compilers */
Eric Andersenff9eee42001-06-29 04:57:14 +0000161
162/*
163 * shell components
164 */
Eric Andersenff9eee42001-06-29 04:57:14 +0000165#define NOBLOCK ((struct op *)NULL)
166#define NOWORD ((char *)NULL)
167#define NOWORDS ((char **)NULL)
168#define NOPIPE ((int *)NULL)
169
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000170/*
171 * redirection
172 */
173struct ioword {
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +0000174 smallint io_flag; /* action (below) */
175 int io_fd; /* fd affected */
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000176 char *io_name; /* file name */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000177};
178
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000179#define IOREAD 1 /* < */
180#define IOHERE 2 /* << (here file) */
181#define IOWRITE 4 /* > */
182#define IOCAT 8 /* >> */
183#define IOXHERE 16 /* ${}, ` in << */
184#define IODUP 32 /* >&digit */
185#define IOCLOSE 64 /* >&- */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000186
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +0000187#define IODEFAULT (-1) /* "default" IO fd */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000188
189
Eric Andersenff9eee42001-06-29 04:57:14 +0000190/*
191 * Description of a command or an operation on commands.
192 * Might eventually use a union.
193 */
194struct op {
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +0000195 smallint op_type; /* operation type, see Txxxx below */
Denis Vlasenko509697f2008-03-02 12:49:39 +0000196 char **op_words; /* arguments to a command */
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000197 struct ioword **ioact; /* IO actions (eg, < > >>) */
Eric Andersenff9eee42001-06-29 04:57:14 +0000198 struct op *left;
199 struct op *right;
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000200 char *str; /* identifier for case and for */
Eric Andersenff9eee42001-06-29 04:57:14 +0000201};
202
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000203#define TCOM 1 /* command */
204#define TPAREN 2 /* (c-list) */
205#define TPIPE 3 /* a | b */
206#define TLIST 4 /* a [&;] b */
207#define TOR 5 /* || */
208#define TAND 6 /* && */
209#define TFOR 7
210#define TDO 8
211#define TCASE 9
212#define TIF 10
213#define TWHILE 11
214#define TUNTIL 12
215#define TELIF 13
216#define TPAT 14 /* pattern in case */
217#define TBRACE 15 /* {c-list} */
218#define TASYNC 16 /* c & */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000219/* Added to support "." file expansion */
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000220#define TDOT 17
Eric Andersen12de6cf2004-08-04 19:19:10 +0000221
222/* Strings for names to make debug easier */
"Vladimir N. Oleynik"ac973172005-09-22 14:38:17 +0000223#ifdef MSHDEBUG
Denis Vlasenkoe27f1562007-01-01 06:00:38 +0000224static const char *const T_CMD_NAMES[] = {
Eric Andersen12de6cf2004-08-04 19:19:10 +0000225 "PLACEHOLDER",
226 "TCOM",
227 "TPAREN",
228 "TPIPE",
229 "TLIST",
230 "TOR",
231 "TAND",
232 "TFOR",
233 "TDO",
234 "TCASE",
235 "TIF",
236 "TWHILE",
237 "TUNTIL",
238 "TELIF",
239 "TPAT",
240 "TBRACE",
241 "TASYNC",
242 "TDOT",
243};
"Vladimir N. Oleynik"ac973172005-09-22 14:38:17 +0000244#endif
Eric Andersenff9eee42001-06-29 04:57:14 +0000245
Denis Vlasenko5f9468e2007-04-14 13:22:09 +0000246#define AREASIZE (90000)
Eric Andersen12de6cf2004-08-04 19:19:10 +0000247
Eric Andersenff9eee42001-06-29 04:57:14 +0000248/*
249 * flags to control evaluation of words
250 */
Denis Vlasenko5f9468e2007-04-14 13:22:09 +0000251#define DOSUB 1 /* interpret $, `, and quotes */
252#define DOBLANK 2 /* perform blank interpretation */
253#define DOGLOB 4 /* interpret [?* */
254#define DOKEY 8 /* move words with `=' to 2nd arg. list */
255#define DOTRIM 16 /* trim resulting string */
Eric Andersenff9eee42001-06-29 04:57:14 +0000256
Denis Vlasenko5f9468e2007-04-14 13:22:09 +0000257#define DOALL (DOSUB|DOBLANK|DOGLOB|DOKEY|DOTRIM)
Eric Andersenff9eee42001-06-29 04:57:14 +0000258
Eric Andersenff9eee42001-06-29 04:57:14 +0000259
Eric Andersen8401eea2004-08-04 19:16:54 +0000260struct brkcon {
261 jmp_buf brkpt;
262 struct brkcon *nextlev;
263};
Eric Andersenff9eee42001-06-29 04:57:14 +0000264
Eric Andersen12de6cf2004-08-04 19:19:10 +0000265
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000266static smallint trapset; /* trap pending (signal number) */
Eric Andersenff9eee42001-06-29 04:57:14 +0000267
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000268static smallint yynerrs; /* yacc (flag) */
Eric Andersenff9eee42001-06-29 04:57:14 +0000269
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000270/* moved to G: static char line[LINELIM]; */
Eric Andersenff9eee42001-06-29 04:57:14 +0000271
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000272#if ENABLE_FEATURE_EDITING
273static char *current_prompt;
274static line_input_t *line_input_state;
275#endif
276
Eric Andersen12de6cf2004-08-04 19:19:10 +0000277
Eric Andersenff9eee42001-06-29 04:57:14 +0000278/*
279 * other functions
280 */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000281static const char *rexecve(char *c, char **v, char **envp);
Eric Andersen8401eea2004-08-04 19:16:54 +0000282static char *evalstr(char *cp, int f);
283static char *putn(int n);
Eric Andersen8401eea2004-08-04 19:16:54 +0000284static char *unquote(char *as);
Eric Andersen8401eea2004-08-04 19:16:54 +0000285static int rlookup(char *n);
286static struct wdblock *glob(char *cp, struct wdblock *wb);
287static int my_getc(int ec);
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +0000288static int subgetc(char ec, int quoted);
Eric Andersenfd7a4c82004-09-02 23:13:10 +0000289static char **makenv(int all, struct wdblock *wb);
Eric Andersen8401eea2004-08-04 19:16:54 +0000290static char **eval(char **ap, int f);
291static int setstatus(int s);
292static int waitfor(int lastpid, int canintr);
Eric Andersenff9eee42001-06-29 04:57:14 +0000293
Eric Andersen8401eea2004-08-04 19:16:54 +0000294static void onintr(int s); /* SIGINT handler */
Eric Andersenff9eee42001-06-29 04:57:14 +0000295
Eric Andersen8401eea2004-08-04 19:16:54 +0000296static int newenv(int f);
297static void quitenv(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000298static void next(int f);
299static void setdash(void);
300static void onecommand(void);
301static void runtrap(int i);
Eric Andersenff9eee42001-06-29 04:57:14 +0000302
Eric Andersen12de6cf2004-08-04 19:19:10 +0000303
Eric Andersenff9eee42001-06-29 04:57:14 +0000304/* -------- area stuff -------- */
305
Denis Vlasenko5f9468e2007-04-14 13:22:09 +0000306#define REGSIZE sizeof(struct region)
307#define GROWBY (256)
308/* #define SHRINKBY (64) */
309#undef SHRINKBY
310#define FREE (32767)
311#define BUSY (0)
312#define ALIGN (sizeof(int)-1)
Eric Andersenff9eee42001-06-29 04:57:14 +0000313
314
315struct region {
Eric Andersen8401eea2004-08-04 19:16:54 +0000316 struct region *next;
317 int area;
Eric Andersenff9eee42001-06-29 04:57:14 +0000318};
319
320
Eric Andersenff9eee42001-06-29 04:57:14 +0000321/* -------- grammar stuff -------- */
322typedef union {
Eric Andersen8401eea2004-08-04 19:16:54 +0000323 char *cp;
324 char **wp;
325 int i;
326 struct op *o;
Eric Andersenff9eee42001-06-29 04:57:14 +0000327} YYSTYPE;
Eric Andersen8401eea2004-08-04 19:16:54 +0000328
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000329#define WORD 256
330#define LOGAND 257
331#define LOGOR 258
332#define BREAK 259
333#define IF 260
334#define THEN 261
335#define ELSE 262
336#define ELIF 263
337#define FI 264
338#define CASE 265
339#define ESAC 266
340#define FOR 267
341#define WHILE 268
342#define UNTIL 269
343#define DO 270
344#define DONE 271
345#define IN 272
Eric Andersen12de6cf2004-08-04 19:19:10 +0000346/* Added for "." file expansion */
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000347#define DOT 273
Eric Andersen12de6cf2004-08-04 19:19:10 +0000348
Eric Andersenff9eee42001-06-29 04:57:14 +0000349#define YYERRCODE 300
350
351/* flags to yylex */
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000352#define CONTIN 01 /* skip new lines to complete command */
Eric Andersenff9eee42001-06-29 04:57:14 +0000353
Eric Andersen8401eea2004-08-04 19:16:54 +0000354static struct op *pipeline(int cf);
Eric Andersenff9eee42001-06-29 04:57:14 +0000355static struct op *andor(void);
356static struct op *c_list(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000357static int synio(int cf);
358static void musthave(int c, int cf);
Eric Andersenff9eee42001-06-29 04:57:14 +0000359static struct op *simple(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000360static struct op *nested(int type, int mark);
361static struct op *command(int cf);
362static struct op *dogroup(int onlydone);
Eric Andersenff9eee42001-06-29 04:57:14 +0000363static struct op *thenpart(void);
364static struct op *elsepart(void);
365static struct op *caselist(void);
366static struct op *casepart(void);
367static char **pattern(void);
368static char **wordlist(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000369static struct op *list(struct op *t1, struct op *t2);
370static struct op *block(int type, struct op *t1, struct op *t2, char **wp);
Eric Andersenff9eee42001-06-29 04:57:14 +0000371static struct op *newtp(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000372static struct op *namelist(struct op *t);
Eric Andersenff9eee42001-06-29 04:57:14 +0000373static char **copyw(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000374static void word(char *cp);
Eric Andersenff9eee42001-06-29 04:57:14 +0000375static struct ioword **copyio(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000376static struct ioword *io(int u, int f, char *cp);
Eric Andersen8401eea2004-08-04 19:16:54 +0000377static int yylex(int cf);
378static int collect(int c, int c1);
379static int dual(int c);
380static void diag(int ec);
381static char *tree(unsigned size);
Eric Andersenff9eee42001-06-29 04:57:14 +0000382
383/* -------- var.h -------- */
384
Eric Andersen8401eea2004-08-04 19:16:54 +0000385struct var {
386 char *value;
387 char *name;
388 struct var *next;
389 char status;
Eric Andersenff9eee42001-06-29 04:57:14 +0000390};
Eric Andersenff9eee42001-06-29 04:57:14 +0000391
Eric Andersen8401eea2004-08-04 19:16:54 +0000392#define COPYV 1 /* flag to setval, suggesting copy */
393#define RONLY 01 /* variable is read-only */
394#define EXPORT 02 /* variable is to be exported */
395#define GETCELL 04 /* name & value space was got with getcell */
Eric Andersenff9eee42001-06-29 04:57:14 +0000396
Eric Andersen8401eea2004-08-04 19:16:54 +0000397static int yyparse(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000398
Eric Andersen12de6cf2004-08-04 19:19:10 +0000399
Eric Andersenff9eee42001-06-29 04:57:14 +0000400/* -------- io.h -------- */
401/* io buffer */
402struct iobuf {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000403 unsigned id; /* buffer id */
404 char buf[512]; /* buffer */
405 char *bufp; /* pointer into buffer */
406 char *ebufp; /* pointer to end of buffer */
Eric Andersenff9eee42001-06-29 04:57:14 +0000407};
408
409/* possible arguments to an IO function */
410struct ioarg {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000411 const char *aword;
Eric Andersen8401eea2004-08-04 19:16:54 +0000412 char **awordlist;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000413 int afile; /* file descriptor */
414 unsigned afid; /* buffer id */
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000415 off_t afpos; /* file position */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000416 struct iobuf *afbuf; /* buffer for this file */
Eric Andersenff9eee42001-06-29 04:57:14 +0000417};
Eric Andersen8401eea2004-08-04 19:16:54 +0000418
Eric Andersenff9eee42001-06-29 04:57:14 +0000419/* an input generator's state */
Eric Andersen8401eea2004-08-04 19:16:54 +0000420struct io {
421 int (*iofn) (struct ioarg *, struct io *);
422 struct ioarg *argp;
423 int peekc;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000424 char prev; /* previous character read by readc() */
425 char nlcount; /* for `'s */
426 char xchar; /* for `'s */
427 char task; /* reason for pushed IO */
Eric Andersenff9eee42001-06-29 04:57:14 +0000428};
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000429/* ->task: */
430#define XOTHER 0 /* none of the below */
431#define XDOLL 1 /* expanding ${} */
432#define XGRAVE 2 /* expanding `'s */
433#define XIO 3 /* file IO */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000434
435
436/*
Eric Andersenff9eee42001-06-29 04:57:14 +0000437 * input generators for IO structure
438 */
Eric Andersen8401eea2004-08-04 19:16:54 +0000439static int nlchar(struct ioarg *ap);
440static int strchar(struct ioarg *ap);
441static int qstrchar(struct ioarg *ap);
442static int filechar(struct ioarg *ap);
443static int herechar(struct ioarg *ap);
444static int linechar(struct ioarg *ap);
445static int gravechar(struct ioarg *ap, struct io *iop);
446static int qgravechar(struct ioarg *ap, struct io *iop);
447static int dolchar(struct ioarg *ap);
448static int wdchar(struct ioarg *ap);
449static void scraphere(void);
450static void freehere(int area);
451static void gethere(void);
452static void markhere(char *s, struct ioword *iop);
453static int herein(char *hname, int xdoll);
454static int run(struct ioarg *argp, int (*f) (struct ioarg *));
Eric Andersenff9eee42001-06-29 04:57:14 +0000455
Eric Andersen12de6cf2004-08-04 19:19:10 +0000456
Eric Andersen8401eea2004-08-04 19:16:54 +0000457static int eofc(void);
458static int readc(void);
459static void unget(int c);
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +0000460static void ioecho(char c);
Eric Andersenff9eee42001-06-29 04:57:14 +0000461
Eric Andersen12de6cf2004-08-04 19:19:10 +0000462
Eric Andersenff9eee42001-06-29 04:57:14 +0000463/*
464 * IO control
465 */
Eric Andersen8401eea2004-08-04 19:16:54 +0000466static void pushio(struct ioarg *argp, int (*f) (struct ioarg *));
Denys Vlasenko083e1722010-01-28 12:30:24 +0100467#define PUSHIO(what,arg,gen) ((temparg.what = (arg)), pushio(&temparg, (gen)))
Eric Andersen8401eea2004-08-04 19:16:54 +0000468static int remap(int fd);
469static int openpipe(int *pv);
470static void closepipe(int *pv);
471static struct io *setbase(struct io *ip);
Eric Andersenff9eee42001-06-29 04:57:14 +0000472
Eric Andersenff9eee42001-06-29 04:57:14 +0000473/* -------- word.h -------- */
474
Eric Andersen8401eea2004-08-04 19:16:54 +0000475#define NSTART 16 /* default number of words to allow for initially */
Eric Andersenff9eee42001-06-29 04:57:14 +0000476
Eric Andersen8401eea2004-08-04 19:16:54 +0000477struct wdblock {
478 short w_bsize;
479 short w_nword;
Eric Andersenff9eee42001-06-29 04:57:14 +0000480 /* bounds are arbitrary */
Eric Andersen8401eea2004-08-04 19:16:54 +0000481 char *w_words[1];
Eric Andersenff9eee42001-06-29 04:57:14 +0000482};
483
Eric Andersen8401eea2004-08-04 19:16:54 +0000484static struct wdblock *addword(char *wd, struct wdblock *wb);
485static struct wdblock *newword(int nw);
486static char **getwords(struct wdblock *wb);
Eric Andersenff9eee42001-06-29 04:57:14 +0000487
Eric Andersenff9eee42001-06-29 04:57:14 +0000488/* -------- misc stuff -------- */
489
Denis Vlasenkofe218832008-03-01 09:35:39 +0000490static int dolabel(struct op *t, char **args);
491static int dohelp(struct op *t, char **args);
492static int dochdir(struct op *t, char **args);
493static int doshift(struct op *t, char **args);
494static int dologin(struct op *t, char **args);
495static int doumask(struct op *t, char **args);
496static int doexec(struct op *t, char **args);
497static int dodot(struct op *t, char **args);
498static int dowait(struct op *t, char **args);
499static int doread(struct op *t, char **args);
500static int doeval(struct op *t, char **args);
501static int dotrap(struct op *t, char **args);
502static int dobreak(struct op *t, char **args);
503static int doexit(struct op *t, char **args);
504static int doexport(struct op *t, char **args);
505static int doreadonly(struct op *t, char **args);
506static int doset(struct op *t, char **args);
507static int dotimes(struct op *t, char **args);
508static int docontinue(struct op *t, char **args);
509
Denis Vlasenko7e497522008-02-12 09:51:03 +0000510static int forkexec(struct op *t, int *pin, int *pout, int no_fork, char **wp);
511static int execute(struct op *t, int *pin, int *pout, int no_fork);
Eric Andersen8401eea2004-08-04 19:16:54 +0000512static int iosetup(struct ioword *iop, int pipein, int pipeout);
Eric Andersen8401eea2004-08-04 19:16:54 +0000513static void brkset(struct brkcon *bc);
Eric Andersen8401eea2004-08-04 19:16:54 +0000514static int getsig(char *s);
515static void setsig(int n, sighandler_t f);
516static int getn(char *as);
Eric Andersen8401eea2004-08-04 19:16:54 +0000517static int brkcontin(char *cp, int val);
Eric Andersen8401eea2004-08-04 19:16:54 +0000518static void rdexp(char **wp, void (*f) (struct var *), int key);
519static void badid(char *s);
Eric Andersen8401eea2004-08-04 19:16:54 +0000520static void varput(char *s, int out);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000521static int expand(const char *cp, struct wdblock **wbp, int f);
Eric Andersen8401eea2004-08-04 19:16:54 +0000522static char *blank(int f);
523static int dollar(int quoted);
524static int grave(int quoted);
525static void globname(char *we, char *pp);
526static char *generate(char *start1, char *end1, char *middle, char *end);
527static int anyspcl(struct wdblock *wb);
Eric Andersen8401eea2004-08-04 19:16:54 +0000528static void readhere(char **name, char *s, int ec);
Eric Andersen8401eea2004-08-04 19:16:54 +0000529static int xxchar(struct ioarg *ap);
Eric Andersenff9eee42001-06-29 04:57:14 +0000530
Eric Andersen8401eea2004-08-04 19:16:54 +0000531struct here {
532 char *h_tag;
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000533 char h_dosub;
Eric Andersen8401eea2004-08-04 19:16:54 +0000534 struct ioword *h_iop;
535 struct here *h_next;
Eric Andersenff9eee42001-06-29 04:57:14 +0000536};
537
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000538static const char *const signame[] = {
Eric Andersenff9eee42001-06-29 04:57:14 +0000539 "Signal 0",
540 "Hangup",
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000541 NULL, /* interrupt */
Eric Andersenff9eee42001-06-29 04:57:14 +0000542 "Quit",
543 "Illegal instruction",
544 "Trace/BPT trap",
545 "Abort",
546 "Bus error",
547 "Floating Point Exception",
548 "Killed",
549 "SIGUSR1",
550 "SIGSEGV",
551 "SIGUSR2",
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000552 NULL, /* broken pipe */
Eric Andersenff9eee42001-06-29 04:57:14 +0000553 "Alarm clock",
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000554 "Terminated"
Eric Andersenff9eee42001-06-29 04:57:14 +0000555};
Eric Andersen8401eea2004-08-04 19:16:54 +0000556
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000557
Denis Vlasenkofe218832008-03-01 09:35:39 +0000558typedef int (*builtin_func_ptr)(struct op *, char **);
Denis Vlasenko7e497522008-02-12 09:51:03 +0000559
Eric Andersen1c039232001-07-07 00:05:55 +0000560struct builtincmd {
561 const char *name;
Denis Vlasenko7e497522008-02-12 09:51:03 +0000562 builtin_func_ptr builtinfunc;
Eric Andersenff9eee42001-06-29 04:57:14 +0000563};
Denis Vlasenko7e497522008-02-12 09:51:03 +0000564
Eric Andersen8401eea2004-08-04 19:16:54 +0000565static const struct builtincmd builtincmds[] = {
Denis Vlasenko95cb3262007-04-09 03:06:34 +0000566 { "." , dodot },
567 { ":" , dolabel },
568 { "break" , dobreak },
569 { "cd" , dochdir },
570 { "continue", docontinue },
571 { "eval" , doeval },
572 { "exec" , doexec },
573 { "exit" , doexit },
574 { "export" , doexport },
575 { "help" , dohelp },
576 { "login" , dologin },
577 { "newgrp" , dologin },
578 { "read" , doread },
579 { "readonly", doreadonly },
580 { "set" , doset },
581 { "shift" , doshift },
582 { "times" , dotimes },
583 { "trap" , dotrap },
584 { "umask" , doumask },
585 { "wait" , dowait },
586 { NULL , NULL },
Eric Andersenff9eee42001-06-29 04:57:14 +0000587};
588
Denis Vlasenko68404f12008-03-17 09:00:54 +0000589static struct op *dowholefile(int /*, int*/);
Eric Andersen12de6cf2004-08-04 19:19:10 +0000590
Eric Andersen12de6cf2004-08-04 19:19:10 +0000591
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000592/* Globals */
Eric Andersen8401eea2004-08-04 19:16:54 +0000593static char **dolv;
594static int dolc;
Denis Vlasenko447bd662008-05-30 22:28:32 +0000595static uint8_t exstat;
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000596static smallint gflg; /* (seems to be a parse error indicator) */
597static smallint interactive; /* Is this an interactive shell */
598static smallint execflg;
599static smallint isbreak; /* "break" statement was seen */
600static int multiline; /* '\n' changed to ';' (counter) */
601static struct op *outtree; /* result from parser */
Eric Andersen8401eea2004-08-04 19:16:54 +0000602static xint *failpt;
603static xint *errpt;
604static struct brkcon *brklist;
Eric Andersen8401eea2004-08-04 19:16:54 +0000605static struct wdblock *wdlist;
606static struct wdblock *iolist;
Eric Andersen12de6cf2004-08-04 19:19:10 +0000607
608#ifdef MSHDEBUG
609static struct var *mshdbg_var;
610#endif
Eric Andersen8401eea2004-08-04 19:16:54 +0000611static struct var *vlist; /* dictionary */
612static struct var *homedir; /* home directory */
613static struct var *prompt; /* main prompt */
614static struct var *cprompt; /* continuation prompt */
615static struct var *path; /* search path for commands */
616static struct var *shell; /* shell to interpret command files */
617static struct var *ifs; /* field separators */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000618
Denis Vlasenko95cb3262007-04-09 03:06:34 +0000619static int areanum; /* current allocation area */
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000620static smallint intr; /* interrupt pending (bool) */
621static smallint heedint = 1; /* heed interrupt signals (bool) */
Eric Andersen8401eea2004-08-04 19:16:54 +0000622static int inparse;
Denis Vlasenko95cb3262007-04-09 03:06:34 +0000623static char *null = (char*)""; /* null value for variable */
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +0000624static void (*qflag)(int) = SIG_IGN;
Eric Andersen8401eea2004-08-04 19:16:54 +0000625static int startl;
626static int peeksym;
627static int nlseen;
628static int iounit = IODEFAULT;
629static YYSTYPE yylval;
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000630static char *elinep; /* done in main(): = line + sizeof(line) - 5 */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000631
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000632static struct here *inhere; /* list of hear docs while parsing */
633static struct here *acthere; /* list of active here documents */
634static struct region *areabot; /* bottom of area */
635static struct region *areatop; /* top of area */
636static struct region *areanxt; /* starting point of scan */
Eric Andersen8401eea2004-08-04 19:16:54 +0000637static void *brktop;
638static void *brkaddr;
Eric Andersenff9eee42001-06-29 04:57:14 +0000639
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000640#define AFID_NOBUF (~0)
641#define AFID_ID 0
642
643
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000644/*
645 * parsing & execution environment
646 */
647struct env {
648 char *linep;
649 struct io *iobase;
650 struct io *iop;
651 xint *errpt; /* void * */
652 int iofd;
653 struct env *oenv;
654};
655
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000656
657struct globals {
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000658 struct env global_env;
659 struct ioarg temparg; // = { .afid = AFID_NOBUF }; /* temporary for PUSHIO */
660 unsigned bufid; // = AFID_ID; /* buffer id counter */
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000661 char ourtrap[_NSIG + 1];
662 char *trap[_NSIG + 1];
663 struct iobuf sharedbuf; /* in main(): set to { AFID_NOBUF } */
664 struct iobuf mainbuf; /* in main(): set to { AFID_NOBUF } */
665 struct ioarg ioargstack[NPUSH];
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000666 /*
667 * flags:
668 * -e: quit on error
669 * -k: look for name=value everywhere on command line
670 * -n: no execution
671 * -t: exit after reading and executing one command
672 * -v: echo as read
673 * -x: trace
674 * -u: unset variables net diagnostic
675 */
676 char flags['z' - 'a' + 1];
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000677 char filechar_cmdbuf[BUFSIZ];
678 char line[LINELIM];
679 char child_cmd[LINELIM];
Denis Vlasenkoab801872007-12-02 08:35:37 +0000680
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000681 struct io iostack[NPUSH];
682
Denis Vlasenkoab801872007-12-02 08:35:37 +0000683 char grave__var_name[LINELIM];
684 char grave__alt_value[LINELIM];
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000685};
686
687#define G (*ptr_to_globals)
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000688#define global_env (G.global_env )
689#define temparg (G.temparg )
690#define bufid (G.bufid )
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000691#define ourtrap (G.ourtrap )
692#define trap (G.trap )
693#define sharedbuf (G.sharedbuf )
694#define mainbuf (G.mainbuf )
695#define ioargstack (G.ioargstack )
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000696/* this looks weird, but is OK ... we index FLAG with 'a'...'z' */
697#define FLAG (G.flags - 'a' )
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000698#define filechar_cmdbuf (G.filechar_cmdbuf)
699#define line (G.line )
700#define child_cmd (G.child_cmd )
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000701#define iostack (G.iostack )
Denis Vlasenkoab801872007-12-02 08:35:37 +0000702#define INIT_G() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000703 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000704 global_env.linep = line; \
705 global_env.iobase = iostack; \
706 global_env.iop = iostack - 1; \
707 global_env.iofd = FDBASE; \
708 temparg.afid = AFID_NOBUF; \
709 bufid = AFID_ID; \
Denis Vlasenkoab801872007-12-02 08:35:37 +0000710} while (0)
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000711
712
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000713/* in substitution */
714#define INSUB() (global_env.iop->task == XGRAVE || global_env.iop->task == XDOLL)
715
716#define RUN(what, arg, gen) ((temparg.what = (arg)), run(&temparg, (gen)))
717
Eric Andersen12de6cf2004-08-04 19:19:10 +0000718#ifdef MSHDEBUG
Denis Vlasenko509697f2008-03-02 12:49:39 +0000719static void print_tree(struct op *head)
Eric Andersen12de6cf2004-08-04 19:19:10 +0000720{
721 if (head == NULL) {
722 DBGPRINTF(("PRINT_TREE: no tree\n"));
723 return;
724 }
725
Denis Vlasenkoed9d6212008-06-09 07:44:19 +0000726 DBGPRINTF(("NODE: %p, left %p, right %p\n", head, head->left,
Eric Andersen12de6cf2004-08-04 19:19:10 +0000727 head->right));
728
729 if (head->left)
730 print_tree(head->left);
731
732 if (head->right)
733 print_tree(head->right);
Eric Andersen12de6cf2004-08-04 19:19:10 +0000734}
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000735#endif /* MSHDEBUG */
736
737
738/*
739 * IO functions
740 */
741static void prs(const char *s)
742{
743 if (*s)
Denis Vlasenko73c571a2009-03-09 00:12:37 +0000744 xwrite_str(STDERR_FILENO, s);
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000745}
746
747static void prn(unsigned u)
748{
749 prs(itoa(u));
750}
751
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000752static void echo(char **wp)
753{
754 int i;
755
756 prs("+");
757 for (i = 0; wp[i]; i++) {
758 if (i)
759 prs(" ");
760 prs(wp[i]);
761 }
762 prs("\n");
763}
764
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000765static void closef(int i)
766{
767 if (i > 2)
768 close(i);
769}
770
771static void closeall(void)
772{
773 int u;
774
775 for (u = NUFILE; u < NOFILE;)
776 close(u++);
777}
Eric Andersen12de6cf2004-08-04 19:19:10 +0000778
Eric Andersenff9eee42001-06-29 04:57:14 +0000779
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000780/* fail but return to process next command */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000781static void fail(void) NORETURN;
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000782static void fail(void)
783{
784 longjmp(failpt, 1);
785 /* NOTREACHED */
786}
Eric Andersenff9eee42001-06-29 04:57:14 +0000787
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000788/* abort shell (or fail in subshell) */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000789static void leave(void) NORETURN;
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000790static void leave(void)
791{
792 DBGPRINTF(("LEAVE: leave called!\n"));
793
794 if (execflg)
795 fail();
796 scraphere();
797 freehere(1);
798 runtrap(0);
799 _exit(exstat);
800 /* NOTREACHED */
801}
802
803static void warn(const char *s)
804{
805 if (*s) {
806 prs(s);
Denis Vlasenko447bd662008-05-30 22:28:32 +0000807 if (!exstat)
808 exstat = 255;
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000809 }
810 prs("\n");
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +0000811 if (FLAG['e'])
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000812 leave();
813}
814
815static void err(const char *s)
816{
817 warn(s);
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +0000818 if (FLAG['n'])
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000819 return;
820 if (!interactive)
821 leave();
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000822 if (global_env.errpt)
823 longjmp(global_env.errpt, 1);
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000824 closeall();
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000825 global_env.iop = global_env.iobase = iostack;
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000826}
827
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000828
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000829/* -------- area.c -------- */
830
Eric Andersenff9eee42001-06-29 04:57:14 +0000831/*
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000832 * All memory between (char *)areabot and (char *)(areatop+1) is
833 * exclusively administered by the area management routines.
834 * It is assumed that sbrk() and brk() manipulate the high end.
Eric Andersenff9eee42001-06-29 04:57:14 +0000835 */
836
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000837#define sbrk(X) ({ \
838 void * __q = (void *)-1; \
839 if (brkaddr + (int)(X) < brktop) { \
840 __q = brkaddr; \
841 brkaddr += (int)(X); \
842 } \
843 __q; \
844})
Eric Andersenff9eee42001-06-29 04:57:14 +0000845
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000846static void initarea(void)
Eric Andersenff9eee42001-06-29 04:57:14 +0000847{
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000848 brkaddr = xmalloc(AREASIZE);
849 brktop = brkaddr + AREASIZE;
Eric Andersenff9eee42001-06-29 04:57:14 +0000850
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000851 while ((long) sbrk(0) & ALIGN)
852 sbrk(1);
853 areabot = (struct region *) sbrk(REGSIZE);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +0000854
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000855 areabot->next = areabot;
856 areabot->area = BUSY;
857 areatop = areabot;
858 areanxt = areabot;
Eric Andersenff9eee42001-06-29 04:57:14 +0000859}
860
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000861static char *getcell(unsigned nbytes)
862{
863 int nregio;
864 struct region *p, *q;
865 int i;
866
867 if (nbytes == 0) {
868 puts("getcell(0)");
869 abort();
870 }
871 /* silly and defeats the algorithm */
872 /*
873 * round upwards and add administration area
874 */
875 nregio = (nbytes + (REGSIZE - 1)) / REGSIZE + 1;
876 p = areanxt;
877 for (;;) {
878 if (p->area > areanum) {
879 /*
880 * merge free cells
881 */
882 while ((q = p->next)->area > areanum && q != areanxt)
883 p->next = q->next;
884 /*
885 * exit loop if cell big enough
886 */
887 if (q >= p + nregio)
888 goto found;
889 }
890 p = p->next;
891 if (p == areanxt)
892 break;
893 }
894 i = nregio >= GROWBY ? nregio : GROWBY;
895 p = (struct region *) sbrk(i * REGSIZE);
896 if (p == (struct region *) -1)
897 return NULL;
898 p--;
899 if (p != areatop) {
900 puts("not contig");
901 abort(); /* allocated areas are contiguous */
902 }
903 q = p + i;
904 p->next = q;
905 p->area = FREE;
906 q->next = areabot;
907 q->area = BUSY;
908 areatop = q;
909 found:
910 /*
911 * we found a FREE area big enough, pointed to by 'p', and up to 'q'
912 */
913 areanxt = p + nregio;
914 if (areanxt < q) {
915 /*
916 * split into requested area and rest
917 */
918 if (areanxt + 1 > q) {
919 puts("OOM");
920 abort(); /* insufficient space left for admin */
921 }
922 areanxt->next = q;
923 areanxt->area = FREE;
924 p->next = areanxt;
925 }
926 p->area = areanum;
927 return (char *) (p + 1);
928}
929
930static void freecell(char *cp)
931{
932 struct region *p;
933
934 p = (struct region *) cp;
935 if (p != NULL) {
936 p--;
937 if (p < areanxt)
938 areanxt = p;
939 p->area = FREE;
940 }
941}
942#define DELETE(obj) freecell((char *)obj)
943
944static void freearea(int a)
945{
946 struct region *p, *top;
947
948 top = areatop;
949 for (p = areabot; p != top; p = p->next)
950 if (p->area >= a)
951 p->area = FREE;
952}
953
954static void setarea(char *cp, int a)
955{
956 struct region *p;
957
958 p = (struct region *) cp;
959 if (p != NULL)
960 (p - 1)->area = a;
961}
962
963static int getarea(char *cp)
964{
965 return ((struct region *) cp - 1)->area;
966}
967
968static void garbage(void)
969{
970 struct region *p, *q, *top;
971
972 top = areatop;
973 for (p = areabot; p != top; p = p->next) {
974 if (p->area > areanum) {
975 while ((q = p->next)->area > areanum)
976 p->next = q->next;
977 areanxt = p;
978 }
979 }
980#ifdef SHRINKBY
981 if (areatop >= q + SHRINKBY && q->area > areanum) {
982 brk((char *) (q + 1));
983 q->next = areabot;
984 q->area = BUSY;
985 areatop = q;
986 }
987#endif
988}
989
Denis Vlasenko509697f2008-03-02 12:49:39 +0000990static void *get_space(int n)
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000991{
992 char *cp;
993
994 cp = getcell(n);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000995 if (cp == NULL)
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000996 err("out of string space");
997 return cp;
998}
999
1000static char *strsave(const char *s, int a)
1001{
1002 char *cp;
1003
Denis Vlasenko509697f2008-03-02 12:49:39 +00001004 cp = get_space(strlen(s) + 1);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001005 if (cp == NULL) {
1006// FIXME: I highly doubt this is good.
1007 return (char*)"";
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001008 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001009 setarea(cp, a);
1010 strcpy(cp, s);
1011 return cp;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001012}
1013
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001014
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001015/* -------- var.c -------- */
1016
1017static int eqname(const char *n1, const char *n2)
1018{
1019 for (; *n1 != '=' && *n1 != '\0'; n1++)
1020 if (*n2++ != *n1)
1021 return 0;
1022 return *n2 == '\0' || *n2 == '=';
1023}
1024
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001025static const char *findeq(const char *cp)
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001026{
1027 while (*cp != '\0' && *cp != '=')
1028 cp++;
1029 return cp;
1030}
1031
1032/*
1033 * Find the given name in the dictionary
1034 * and return its value. If the name was
1035 * not previously there, enter it now and
1036 * return a null value.
1037 */
1038static struct var *lookup(const char *n)
1039{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001040// FIXME: dirty hack
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001041 static struct var dummy;
1042
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001043 struct var *vp;
1044 const char *cp;
1045 char *xp;
1046 int c;
1047
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001048 if (isdigit(*n)) {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001049 dummy.name = (char*)n;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001050 for (c = 0; isdigit(*n) && c < 1000; n++)
1051 c = c * 10 + *n - '0';
1052 dummy.status = RONLY;
1053 dummy.value = (c <= dolc ? dolv[c] : null);
1054 return &dummy;
1055 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001056
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001057 for (vp = vlist; vp; vp = vp->next)
1058 if (eqname(vp->name, n))
1059 return vp;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001060
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001061 cp = findeq(n);
Denis Vlasenko509697f2008-03-02 12:49:39 +00001062 vp = get_space(sizeof(*vp));
1063 if (vp == 0 || (vp->name = get_space((int) (cp - n) + 2)) == NULL) {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001064 dummy.name = dummy.value = (char*)"";
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001065 return &dummy;
1066 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001067
1068 xp = vp->name;
1069 while ((*xp = *n++) != '\0' && *xp != '=')
1070 xp++;
1071 *xp++ = '=';
1072 *xp = '\0';
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001073 setarea((char *) vp, 0);
1074 setarea((char *) vp->name, 0);
1075 vp->value = null;
1076 vp->next = vlist;
1077 vp->status = GETCELL;
1078 vlist = vp;
1079 return vp;
1080}
1081
1082/*
1083 * if name is not NULL, it must be
1084 * a prefix of the space `val',
1085 * and end with `='.
1086 * this is all so that exporting
1087 * values is reasonably painless.
1088 */
1089static void nameval(struct var *vp, const char *val, const char *name)
1090{
1091 const char *cp;
1092 char *xp;
1093 int fl;
1094
1095 if (vp->status & RONLY) {
1096 xp = vp->name;
1097 while (*xp && *xp != '=')
Denis Vlasenko4daad902007-09-27 10:20:47 +00001098 fputc(*xp++, stderr);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001099 err(" is read-only");
1100 return;
1101 }
1102 fl = 0;
1103 if (name == NULL) {
Denis Vlasenko509697f2008-03-02 12:49:39 +00001104 xp = get_space(strlen(vp->name) + strlen(val) + 2);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001105 if (xp == NULL)
1106 return;
1107 /* make string: name=value */
1108 setarea(xp, 0);
1109 name = xp;
1110 cp = vp->name;
1111 while ((*xp = *cp++) != '\0' && *xp != '=')
1112 xp++;
1113 *xp++ = '=';
1114 strcpy(xp, val);
1115 val = xp;
1116 fl = GETCELL;
1117 }
1118 if (vp->status & GETCELL)
1119 freecell(vp->name); /* form new string `name=value' */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001120 vp->name = (char*)name;
1121 vp->value = (char*)val;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001122 vp->status |= fl;
1123}
1124
1125/*
1126 * give variable at `vp' the value `val'.
1127 */
1128static void setval(struct var *vp, const char *val)
1129{
1130 nameval(vp, val, NULL);
1131}
1132
1133static void export(struct var *vp)
1134{
1135 vp->status |= EXPORT;
1136}
1137
1138static void ronly(struct var *vp)
1139{
1140 if (isalpha(vp->name[0]) || vp->name[0] == '_') /* not an internal symbol */
1141 vp->status |= RONLY;
1142}
1143
1144static int isassign(const char *s)
1145{
1146 unsigned char c;
1147 DBGPRINTF7(("ISASSIGN: enter, s=%s\n", s));
1148
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001149 c = *s;
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001150 /* no isalpha() - we shouldn't use locale */
1151 /* c | 0x20 - lowercase (Latin) letters */
1152 if (c != '_' && (unsigned)((c|0x20) - 'a') > 25)
1153 /* not letter */
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001154 return 0;
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001155
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001156 while (1) {
1157 c = *++s;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001158 if (c == '=')
1159 return 1;
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001160 if (c == '\0')
1161 return 0;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001162 if (c != '_'
1163 && (unsigned)(c - '0') > 9 /* not number */
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001164 && (unsigned)((c|0x20) - 'a') > 25 /* not letter */
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001165 ) {
1166 return 0;
1167 }
1168 }
1169}
1170
1171static int assign(const char *s, int cf)
1172{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001173 const char *cp;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001174 struct var *vp;
1175
1176 DBGPRINTF7(("ASSIGN: enter, s=%s, cf=%d\n", s, cf));
1177
1178 if (!isalpha(*s) && *s != '_')
1179 return 0;
1180 for (cp = s; *cp != '='; cp++)
1181 if (*cp == '\0' || (!isalnum(*cp) && *cp != '_'))
1182 return 0;
1183 vp = lookup(s);
1184 nameval(vp, ++cp, cf == COPYV ? NULL : s);
1185 if (cf != COPYV)
1186 vp->status &= ~GETCELL;
1187 return 1;
1188}
1189
1190static int checkname(char *cp)
1191{
1192 DBGPRINTF7(("CHECKNAME: enter, cp=%s\n", cp));
1193
1194 if (!isalpha(*cp++) && *(cp - 1) != '_')
1195 return 0;
1196 while (*cp)
1197 if (!isalnum(*cp++) && *(cp - 1) != '_')
1198 return 0;
1199 return 1;
1200}
1201
1202static void putvlist(int f, int out)
1203{
1204 struct var *vp;
1205
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001206 for (vp = vlist; vp; vp = vp->next) {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001207 if (vp->status & f && (isalpha(*vp->name) || *vp->name == '_')) {
1208 if (vp->status & EXPORT)
1209 write(out, "export ", 7);
1210 if (vp->status & RONLY)
1211 write(out, "readonly ", 9);
1212 write(out, vp->name, (int) (findeq(vp->name) - vp->name));
1213 write(out, "\n", 1);
1214 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001215 }
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001216}
1217
1218
1219/*
1220 * trap handling
1221 */
1222static void sig(int i)
1223{
1224 trapset = i;
1225 signal(i, sig);
1226}
1227
1228static void runtrap(int i)
1229{
1230 char *trapstr;
1231
1232 trapstr = trap[i];
1233 if (trapstr == NULL)
1234 return;
1235
1236 if (i == 0)
1237 trap[i] = NULL;
1238
1239 RUN(aword, trapstr, nlchar);
1240}
1241
1242
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001243static void setdash(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001244{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001245 char *cp;
1246 int c;
Eric Andersen8401eea2004-08-04 19:16:54 +00001247 char m['z' - 'a' + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00001248
1249 cp = m;
Eric Andersen8401eea2004-08-04 19:16:54 +00001250 for (c = 'a'; c <= 'z'; c++)
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00001251 if (FLAG[c])
Eric Andersenff9eee42001-06-29 04:57:14 +00001252 *cp++ = c;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001253 *cp = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00001254 setval(lookup("-"), m);
1255}
1256
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001257static int newfile(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00001258{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001259 int f;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001260
1261 DBGPRINTF7(("NEWFILE: opening %s\n", s));
Eric Andersenff9eee42001-06-29 04:57:14 +00001262
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001263 f = 0;
Denis Vlasenko9f739442006-12-16 23:49:13 +00001264 if (NOT_LONE_DASH(s)) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001265 DBGPRINTF(("NEWFILE: s is %s\n", s));
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00001266 f = open(s, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00001267 if (f < 0) {
1268 prs(s);
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00001269 err(": can't open");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001270 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001271 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001272 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001273
Eric Andersenff9eee42001-06-29 04:57:14 +00001274 next(remap(f));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001275 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001276}
1277
Eric Andersen12de6cf2004-08-04 19:19:10 +00001278
Denis Vlasenkobc1918a2008-04-15 01:17:50 +00001279#ifdef UNUSED
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001280struct op *scantree(struct op *head)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001281{
1282 struct op *dotnode;
1283
1284 if (head == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001285 return NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001286
1287 if (head->left != NULL) {
1288 dotnode = scantree(head->left);
1289 if (dotnode)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001290 return dotnode;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001291 }
1292
1293 if (head->right != NULL) {
1294 dotnode = scantree(head->right);
1295 if (dotnode)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001296 return dotnode;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001297 }
1298
Denis Vlasenko509697f2008-03-02 12:49:39 +00001299 if (head->op_words == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001300 return NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001301
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001302 DBGPRINTF5(("SCANTREE: checking node %p\n", head));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001303
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001304 if ((head->op_type != TDOT) && LONE_CHAR(head->op_words[0], '.')) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001305 DBGPRINTF5(("SCANTREE: dot found in node %p\n", head));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001306 return head;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001307 }
1308
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001309 return NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001310}
Denis Vlasenkobc1918a2008-04-15 01:17:50 +00001311#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00001312
1313
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001314static void onecommand(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001315{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001316 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00001317 jmp_buf m1;
1318
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001319 DBGPRINTF(("ONECOMMAND: enter, outtree=%p\n", outtree));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001320
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001321 while (global_env.oenv)
Eric Andersenff9eee42001-06-29 04:57:14 +00001322 quitenv();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001323
Eric Andersenff9eee42001-06-29 04:57:14 +00001324 areanum = 1;
1325 freehere(areanum);
1326 freearea(areanum);
1327 garbage();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001328 wdlist = NULL;
1329 iolist = NULL;
1330 global_env.errpt = NULL;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001331 global_env.linep = line;
Eric Andersenff9eee42001-06-29 04:57:14 +00001332 yynerrs = 0;
1333 multiline = 0;
1334 inparse = 1;
1335 intr = 0;
1336 execflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001337
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001338 failpt = m1;
1339 setjmp(failpt); /* Bruce Evans' fix */
1340 failpt = m1;
1341 if (setjmp(failpt) || yyparse() || intr) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001342 DBGPRINTF(("ONECOMMAND: this is not good.\n"));
1343
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001344 while (global_env.oenv)
Eric Andersenff9eee42001-06-29 04:57:14 +00001345 quitenv();
1346 scraphere();
1347 if (!interactive && intr)
1348 leave();
1349 inparse = 0;
1350 intr = 0;
1351 return;
1352 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001353
Eric Andersenff9eee42001-06-29 04:57:14 +00001354 inparse = 0;
1355 brklist = 0;
1356 intr = 0;
1357 execflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001358
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00001359 if (!FLAG['n']) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001360 DBGPRINTF(("ONECOMMAND: calling execute, t=outtree=%p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00001361 outtree));
Denis Vlasenko7e497522008-02-12 09:51:03 +00001362 execute(outtree, NOPIPE, NOPIPE, /* no_fork: */ 0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001363 }
1364
Eric Andersenff9eee42001-06-29 04:57:14 +00001365 if (!interactive && intr) {
1366 execflg = 0;
1367 leave();
1368 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001369
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001370 i = trapset;
1371 if (i != 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001372 trapset = 0;
1373 runtrap(i);
1374 }
1375}
1376
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001377static int newenv(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00001378{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001379 struct env *ep;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001380
1381 DBGPRINTF(("NEWENV: f=%d (indicates quitenv and return)\n", f));
Eric Andersenff9eee42001-06-29 04:57:14 +00001382
1383 if (f) {
1384 quitenv();
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001385 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001386 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001387
Denis Vlasenko509697f2008-03-02 12:49:39 +00001388 ep = get_space(sizeof(*ep));
Eric Andersenff9eee42001-06-29 04:57:14 +00001389 if (ep == NULL) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001390 while (global_env.oenv)
Eric Andersenff9eee42001-06-29 04:57:14 +00001391 quitenv();
1392 fail();
1393 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001394 *ep = global_env;
1395 global_env.oenv = ep;
1396 global_env.errpt = errpt;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001397
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001398 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001399}
1400
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001401static void quitenv(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001402{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001403 struct env *ep;
1404 int fd;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001405
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001406 DBGPRINTF(("QUITENV: global_env.oenv=%p\n", global_env.oenv));
Eric Andersenff9eee42001-06-29 04:57:14 +00001407
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001408 ep = global_env.oenv;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001409 if (ep != NULL) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001410 fd = global_env.iofd;
1411 global_env = *ep;
Eric Andersenff9eee42001-06-29 04:57:14 +00001412 /* should close `'d files */
1413 DELETE(ep);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001414 while (--fd >= global_env.iofd)
Eric Andersenff9eee42001-06-29 04:57:14 +00001415 close(fd);
1416 }
1417}
1418
1419/*
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001420 * Is character c in s?
Eric Andersenff9eee42001-06-29 04:57:14 +00001421 */
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001422static int any(int c, const char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00001423{
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001424 while (*s)
1425 if (*s++ == c)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001426 return 1;
1427 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001428}
1429
1430/*
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001431 * Is any character from s1 in s2?
Eric Andersenff9eee42001-06-29 04:57:14 +00001432 */
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001433static int anys(const char *s1, const char *s2)
Eric Andersenff9eee42001-06-29 04:57:14 +00001434{
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001435 while (*s1)
1436 if (any(*s1++, s2))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001437 return 1;
1438 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001439}
1440
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001441static char *putn(int n)
Eric Andersenff9eee42001-06-29 04:57:14 +00001442{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001443 return itoa(n);
Eric Andersenff9eee42001-06-29 04:57:14 +00001444}
1445
Eric Andersen8401eea2004-08-04 19:16:54 +00001446static void next(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00001447{
1448 PUSHIO(afile, f, filechar);
1449}
1450
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001451static void onintr(int s UNUSED_PARAM) /* ANSI C requires a parameter */
Eric Andersenff9eee42001-06-29 04:57:14 +00001452{
1453 signal(SIGINT, onintr);
1454 intr = 1;
1455 if (interactive) {
1456 if (inparse) {
1457 prs("\n");
1458 fail();
1459 }
Eric Andersen8401eea2004-08-04 19:16:54 +00001460 } else if (heedint) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001461 execflg = 0;
1462 leave();
1463 }
1464}
1465
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001466
Eric Andersenff9eee42001-06-29 04:57:14 +00001467/* -------- gmatch.c -------- */
1468/*
1469 * int gmatch(string, pattern)
1470 * char *string, *pattern;
1471 *
1472 * Match a pattern as in sh(1).
1473 */
1474
1475#define CMASK 0377
1476#define QUOTE 0200
Denis Vlasenko55f30b02007-03-24 22:42:29 +00001477#define QMASK (CMASK & ~QUOTE)
Eric Andersen8401eea2004-08-04 19:16:54 +00001478#define NOT '!' /* might use ^ */
Eric Andersenff9eee42001-06-29 04:57:14 +00001479
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001480static const char *cclass(const char *p, int sub)
1481{
1482 int c, d, not, found;
1483
1484 not = (*p == NOT);
1485 if (not != 0)
1486 p++;
1487 found = not;
1488 do {
1489 if (*p == '\0')
1490 return NULL;
1491 c = *p & CMASK;
1492 if (p[1] == '-' && p[2] != ']') {
1493 d = p[2] & CMASK;
1494 p++;
1495 } else
1496 d = c;
1497 if (c == sub || (c <= sub && sub <= d))
1498 found = !not;
1499 } while (*++p != ']');
1500 return found ? p + 1 : NULL;
1501}
1502
1503static int gmatch(const char *s, const char *p)
Eric Andersenff9eee42001-06-29 04:57:14 +00001504{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001505 int sc, pc;
Eric Andersenff9eee42001-06-29 04:57:14 +00001506
1507 if (s == NULL || p == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001508 return 0;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001509
Eric Andersenff9eee42001-06-29 04:57:14 +00001510 while ((pc = *p++ & CMASK) != '\0') {
1511 sc = *s++ & QMASK;
1512 switch (pc) {
1513 case '[':
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001514 p = cclass(p, sc);
1515 if (p == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001516 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001517 break;
1518
1519 case '?':
1520 if (sc == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001521 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001522 break;
1523
1524 case '*':
1525 s--;
1526 do {
1527 if (*p == '\0' || gmatch(s, p))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001528 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001529 } while (*s++ != '\0');
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001530 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001531
1532 default:
Eric Andersen8401eea2004-08-04 19:16:54 +00001533 if (sc != (pc & ~QUOTE))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001534 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001535 }
1536 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001537 return *s == '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00001538}
1539
Eric Andersenff9eee42001-06-29 04:57:14 +00001540
Eric Andersenff9eee42001-06-29 04:57:14 +00001541/* -------- csyn.c -------- */
1542/*
1543 * shell: syntax (C version)
1544 */
1545
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001546static void yyerror(const char *s) NORETURN;
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001547static void yyerror(const char *s)
1548{
Denis Vlasenko648b44f2008-02-12 06:04:06 +00001549 yynerrs = 1;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001550 if (interactive && global_env.iop <= iostack) {
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001551 multiline = 0;
Denis Vlasenko648b44f2008-02-12 06:04:06 +00001552 while (eofc() == 0 && yylex(0) != '\n')
1553 continue;
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001554 }
1555 err(s);
1556 fail();
1557}
1558
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001559static void zzerr(void) NORETURN;
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001560static void zzerr(void)
1561{
1562 yyerror("syntax error");
1563}
1564
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001565int yyparse(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001566{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001567 DBGPRINTF7(("YYPARSE: enter...\n"));
1568
Eric Andersen8401eea2004-08-04 19:16:54 +00001569 startl = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001570 peeksym = 0;
1571 yynerrs = 0;
1572 outtree = c_list();
1573 musthave('\n', 0);
Denis Vlasenko648b44f2008-02-12 06:04:06 +00001574 return yynerrs; /* 0/1 */
Eric Andersenff9eee42001-06-29 04:57:14 +00001575}
1576
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001577static struct op *pipeline(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001578{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001579 struct op *t, *p;
1580 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001581
1582 DBGPRINTF7(("PIPELINE: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001583
1584 t = command(cf);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001585
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001586 DBGPRINTF9(("PIPELINE: t=%p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001587
Eric Andersenff9eee42001-06-29 04:57:14 +00001588 if (t != NULL) {
1589 while ((c = yylex(0)) == '|') {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001590 p = command(CONTIN);
1591 if (p == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001592 DBGPRINTF8(("PIPELINE: error!\n"));
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001593 zzerr();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001594 }
1595
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001596 if (t->op_type != TPAREN && t->op_type != TCOM) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001597 /* shell statement */
1598 t = block(TPAREN, t, NOBLOCK, NOWORDS);
1599 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001600
Eric Andersenff9eee42001-06-29 04:57:14 +00001601 t = block(TPIPE, t, p, NOWORDS);
1602 }
1603 peeksym = c;
1604 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001605
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001606 DBGPRINTF7(("PIPELINE: returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001607 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001608}
1609
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001610static struct op *andor(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001611{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001612 struct op *t, *p;
1613 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001614
1615 DBGPRINTF7(("ANDOR: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001616
1617 t = pipeline(0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001618
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001619 DBGPRINTF9(("ANDOR: t=%p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001620
Eric Andersenff9eee42001-06-29 04:57:14 +00001621 if (t != NULL) {
1622 while ((c = yylex(0)) == LOGAND || c == LOGOR) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001623 p = pipeline(CONTIN);
1624 if (p == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001625 DBGPRINTF8(("ANDOR: error!\n"));
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001626 zzerr();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001627 }
1628
Eric Andersen8401eea2004-08-04 19:16:54 +00001629 t = block(c == LOGAND ? TAND : TOR, t, p, NOWORDS);
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001630 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001631
Eric Andersenff9eee42001-06-29 04:57:14 +00001632 peeksym = c;
1633 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001634
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001635 DBGPRINTF7(("ANDOR: returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001636 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001637}
1638
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001639static struct op *c_list(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001640{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001641 struct op *t, *p;
1642 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001643
1644 DBGPRINTF7(("C_LIST: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001645
1646 t = andor();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001647
Eric Andersenff9eee42001-06-29 04:57:14 +00001648 if (t != NULL) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001649 peeksym = yylex(0);
1650 if (peeksym == '&')
Eric Andersenff9eee42001-06-29 04:57:14 +00001651 t = block(TASYNC, t, NOBLOCK, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001652
Eric Andersen8401eea2004-08-04 19:16:54 +00001653 while ((c = yylex(0)) == ';' || c == '&'
Denis Vlasenko509697f2008-03-02 12:49:39 +00001654 || (multiline && c == '\n')
1655 ) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001656 p = andor();
1657 if (p== NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001658 return t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001659
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001660 peeksym = yylex(0);
1661 if (peeksym == '&')
Eric Andersenff9eee42001-06-29 04:57:14 +00001662 p = block(TASYNC, p, NOBLOCK, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001663
Eric Andersenff9eee42001-06-29 04:57:14 +00001664 t = list(t, p);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001665 } /* WHILE */
1666
Eric Andersenff9eee42001-06-29 04:57:14 +00001667 peeksym = c;
1668 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001669 /* IF */
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001670 DBGPRINTF7(("C_LIST: returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001671 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001672}
1673
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001674static int synio(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001675{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001676 struct ioword *iop;
1677 int i;
1678 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001679
1680 DBGPRINTF7(("SYNIO: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001681
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001682 c = yylex(cf);
1683 if (c != '<' && c != '>') {
Eric Andersenff9eee42001-06-29 04:57:14 +00001684 peeksym = c;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001685 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001686 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001687
Eric Andersenff9eee42001-06-29 04:57:14 +00001688 i = yylval.i;
1689 musthave(WORD, 0);
1690 iop = io(iounit, i, yylval.cp);
1691 iounit = IODEFAULT;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001692
Eric Andersenff9eee42001-06-29 04:57:14 +00001693 if (i & IOHERE)
1694 markhere(yylval.cp, iop);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001695
1696 DBGPRINTF7(("SYNIO: returning 1\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001697 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001698}
1699
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001700static void musthave(int c, int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001701{
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001702 peeksym = yylex(cf);
1703 if (peeksym != c) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001704 DBGPRINTF7(("MUSTHAVE: error!\n"));
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001705 zzerr();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001706 }
1707
Eric Andersenff9eee42001-06-29 04:57:14 +00001708 peeksym = 0;
1709}
1710
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001711static struct op *simple(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001712{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001713 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001714
1715 t = NULL;
1716 for (;;) {
1717 switch (peeksym = yylex(0)) {
1718 case '<':
1719 case '>':
1720 (void) synio(0);
1721 break;
1722
1723 case WORD:
1724 if (t == NULL) {
1725 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001726 t->op_type = TCOM;
Eric Andersenff9eee42001-06-29 04:57:14 +00001727 }
1728 peeksym = 0;
1729 word(yylval.cp);
1730 break;
1731
1732 default:
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001733 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001734 }
1735 }
1736}
1737
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001738static struct op *nested(int type, int mark)
Eric Andersenff9eee42001-06-29 04:57:14 +00001739{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001740 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001741
1742 DBGPRINTF3(("NESTED: enter, type=%d, mark=%d\n", type, mark));
Eric Andersenff9eee42001-06-29 04:57:14 +00001743
1744 multiline++;
1745 t = c_list();
1746 musthave(mark, 0);
1747 multiline--;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001748 return block(type, t, NOBLOCK, NOWORDS);
Eric Andersenff9eee42001-06-29 04:57:14 +00001749}
1750
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001751static struct op *command(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001752{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001753 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001754 struct wdblock *iosave;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001755 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001756
1757 DBGPRINTF(("COMMAND: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001758
1759 iosave = iolist;
1760 iolist = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001761
Eric Andersenff9eee42001-06-29 04:57:14 +00001762 if (multiline)
1763 cf |= CONTIN;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001764
Eric Andersenff9eee42001-06-29 04:57:14 +00001765 while (synio(cf))
1766 cf = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001767
1768 c = yylex(cf);
1769
1770 switch (c) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001771 default:
1772 peeksym = c;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001773 t = simple();
1774 if (t == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001775 if (iolist == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001776 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001777 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001778 t->op_type = TCOM;
Eric Andersenff9eee42001-06-29 04:57:14 +00001779 }
1780 break;
1781
1782 case '(':
1783 t = nested(TPAREN, ')');
1784 break;
1785
1786 case '{':
1787 t = nested(TBRACE, '}');
1788 break;
1789
1790 case FOR:
1791 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001792 t->op_type = TFOR;
Eric Andersenff9eee42001-06-29 04:57:14 +00001793 musthave(WORD, 0);
1794 startl = 1;
1795 t->str = yylval.cp;
1796 multiline++;
Denis Vlasenko509697f2008-03-02 12:49:39 +00001797 t->op_words = wordlist();
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001798 c = yylex(0);
1799 if (c != '\n' && c != ';')
Eric Andersenff9eee42001-06-29 04:57:14 +00001800 peeksym = c;
1801 t->left = dogroup(0);
1802 multiline--;
1803 break;
1804
1805 case WHILE:
1806 case UNTIL:
1807 multiline++;
1808 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001809 t->op_type = (c == WHILE ? TWHILE : TUNTIL);
Eric Andersenff9eee42001-06-29 04:57:14 +00001810 t->left = c_list();
1811 t->right = dogroup(1);
Denis Vlasenko509697f2008-03-02 12:49:39 +00001812 /* t->op_words = NULL; - newtp() did this */
Eric Andersenff9eee42001-06-29 04:57:14 +00001813 multiline--;
1814 break;
1815
1816 case CASE:
1817 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001818 t->op_type = TCASE;
Eric Andersenff9eee42001-06-29 04:57:14 +00001819 musthave(WORD, 0);
1820 t->str = yylval.cp;
1821 startl++;
1822 multiline++;
1823 musthave(IN, CONTIN);
1824 startl++;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001825
Eric Andersenff9eee42001-06-29 04:57:14 +00001826 t->left = caselist();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001827
Eric Andersenff9eee42001-06-29 04:57:14 +00001828 musthave(ESAC, 0);
1829 multiline--;
1830 break;
1831
1832 case IF:
1833 multiline++;
1834 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001835 t->op_type = TIF;
Eric Andersenff9eee42001-06-29 04:57:14 +00001836 t->left = c_list();
1837 t->right = thenpart();
1838 musthave(FI, 0);
1839 multiline--;
1840 break;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001841
1842 case DOT:
1843 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001844 t->op_type = TDOT;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001845
Denis Vlasenko509697f2008-03-02 12:49:39 +00001846 musthave(WORD, 0); /* gets name of file */
Eric Andersen12de6cf2004-08-04 19:19:10 +00001847 DBGPRINTF7(("COMMAND: DOT clause, yylval.cp is %s\n", yylval.cp));
1848
Denis Vlasenko509697f2008-03-02 12:49:39 +00001849 word(yylval.cp); /* add word to wdlist */
1850 word(NOWORD); /* terminate wdlist */
1851 t->op_words = copyw(); /* dup wdlist */
Eric Andersen12de6cf2004-08-04 19:19:10 +00001852 break;
1853
Eric Andersenff9eee42001-06-29 04:57:14 +00001854 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001855
Denis Vlasenko509697f2008-03-02 12:49:39 +00001856 while (synio(0))
1857 continue;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001858
Eric Andersenff9eee42001-06-29 04:57:14 +00001859 t = namelist(t);
1860 iolist = iosave;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001861
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001862 DBGPRINTF(("COMMAND: returning %p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001863
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001864 return t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001865}
1866
Denis Vlasenko68404f12008-03-17 09:00:54 +00001867static struct op *dowholefile(int type /*, int mark*/)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001868{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001869 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001870
Denis Vlasenko68404f12008-03-17 09:00:54 +00001871 DBGPRINTF(("DOWHOLEFILE: enter, type=%d\n", type /*, mark*/));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001872
1873 multiline++;
1874 t = c_list();
1875 multiline--;
1876 t = block(type, t, NOBLOCK, NOWORDS);
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001877 DBGPRINTF(("DOWHOLEFILE: return t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001878 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001879}
1880
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001881static struct op *dogroup(int onlydone)
Eric Andersenff9eee42001-06-29 04:57:14 +00001882{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001883 int c;
1884 struct op *mylist;
Eric Andersenff9eee42001-06-29 04:57:14 +00001885
1886 c = yylex(CONTIN);
1887 if (c == DONE && onlydone)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001888 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001889 if (c != DO)
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001890 zzerr();
Eric Andersenff9eee42001-06-29 04:57:14 +00001891 mylist = c_list();
1892 musthave(DONE, 0);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001893 return mylist;
Eric Andersenff9eee42001-06-29 04:57:14 +00001894}
1895
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001896static struct op *thenpart(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001897{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001898 int c;
1899 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001900
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001901 c = yylex(0);
1902 if (c != THEN) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001903 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001904 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001905 }
1906 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001907 /*t->op_type = 0; - newtp() did this */
Eric Andersenff9eee42001-06-29 04:57:14 +00001908 t->left = c_list();
1909 if (t->left == NULL)
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001910 zzerr();
Eric Andersenff9eee42001-06-29 04:57:14 +00001911 t->right = elsepart();
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001912 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001913}
1914
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001915static struct op *elsepart(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001916{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001917 int c;
1918 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001919
1920 switch (c = yylex(0)) {
1921 case ELSE:
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001922 t = c_list();
1923 if (t == NULL)
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001924 zzerr();
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001925 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001926
1927 case ELIF:
1928 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001929 t->op_type = TELIF;
Eric Andersenff9eee42001-06-29 04:57:14 +00001930 t->left = c_list();
1931 t->right = thenpart();
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001932 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001933
1934 default:
1935 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001936 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001937 }
1938}
1939
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001940static struct op *caselist(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001941{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001942 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001943
1944 t = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001945 while ((peeksym = yylex(CONTIN)) != ESAC) {
1946 DBGPRINTF(("CASELIST, doing yylex, peeksym=%d\n", peeksym));
Eric Andersenff9eee42001-06-29 04:57:14 +00001947 t = list(t, casepart());
Eric Andersen12de6cf2004-08-04 19:19:10 +00001948 }
1949
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001950 DBGPRINTF(("CASELIST, returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001951 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001952}
1953
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001954static struct op *casepart(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001955{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001956 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001957
1958 DBGPRINTF7(("CASEPART: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001959
1960 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001961 t->op_type = TPAT;
Denis Vlasenko509697f2008-03-02 12:49:39 +00001962 t->op_words = pattern();
Eric Andersenff9eee42001-06-29 04:57:14 +00001963 musthave(')', 0);
1964 t->left = c_list();
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001965 peeksym = yylex(CONTIN);
1966 if (peeksym != ESAC)
Eric Andersenff9eee42001-06-29 04:57:14 +00001967 musthave(BREAK, CONTIN);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001968
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001969 DBGPRINTF7(("CASEPART: made newtp(TPAT, t=%p)\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001970
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001971 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001972}
1973
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001974static char **pattern(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001975{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001976 int c, cf;
Eric Andersenff9eee42001-06-29 04:57:14 +00001977
1978 cf = CONTIN;
1979 do {
1980 musthave(WORD, cf);
1981 word(yylval.cp);
1982 cf = 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001983 c = yylex(0);
1984 } while (c == '|');
Eric Andersenff9eee42001-06-29 04:57:14 +00001985 peeksym = c;
1986 word(NOWORD);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001987
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001988 return copyw();
Eric Andersenff9eee42001-06-29 04:57:14 +00001989}
1990
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001991static char **wordlist(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001992{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001993 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00001994
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001995 c = yylex(0);
1996 if (c != IN) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001997 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001998 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001999 }
2000 startl = 0;
2001 while ((c = yylex(0)) == WORD)
2002 word(yylval.cp);
2003 word(NOWORD);
2004 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002005 return copyw();
Eric Andersenff9eee42001-06-29 04:57:14 +00002006}
2007
2008/*
2009 * supporting functions
2010 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002011static struct op *list(struct op *t1, struct op *t2)
Eric Andersenff9eee42001-06-29 04:57:14 +00002012{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002013 DBGPRINTF7(("LIST: enter, t1=%p, t2=%p\n", t1, t2));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002014
Eric Andersenff9eee42001-06-29 04:57:14 +00002015 if (t1 == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002016 return t2;
Eric Andersenff9eee42001-06-29 04:57:14 +00002017 if (t2 == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002018 return t1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002019
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002020 return block(TLIST, t1, t2, NOWORDS);
Eric Andersenff9eee42001-06-29 04:57:14 +00002021}
2022
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002023static struct op *block(int type, struct op *t1, struct op *t2, char **wp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002024{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002025 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002026
2027 DBGPRINTF7(("BLOCK: enter, type=%d (%s)\n", type, T_CMD_NAMES[type]));
Eric Andersenff9eee42001-06-29 04:57:14 +00002028
2029 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002030 t->op_type = type;
Eric Andersenff9eee42001-06-29 04:57:14 +00002031 t->left = t1;
2032 t->right = t2;
Denis Vlasenko509697f2008-03-02 12:49:39 +00002033 t->op_words = wp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002034
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002035 DBGPRINTF7(("BLOCK: inserted %p between %p and %p\n", t, t1, t2));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002036
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002037 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002038}
2039
Eric Andersen12de6cf2004-08-04 19:19:10 +00002040/* See if given string is a shell multiline (FOR, IF, etc) */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002041static int rlookup(char *n)
Eric Andersenff9eee42001-06-29 04:57:14 +00002042{
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002043 struct res {
2044 char r_name[6];
2045 int16_t r_val;
2046 };
2047 static const struct res restab[] = {
2048 { "for" , FOR },
2049 { "case" , CASE },
2050 { "esac" , ESAC },
2051 { "while", WHILE },
2052 { "do" , DO },
2053 { "done" , DONE },
2054 { "if" , IF },
2055 { "in" , IN },
2056 { "then" , THEN },
2057 { "else" , ELSE },
2058 { "elif" , ELIF },
2059 { "until", UNTIL },
2060 { "fi" , FI },
2061 { ";;" , BREAK },
2062 { "||" , LOGOR },
2063 { "&&" , LOGAND },
2064 { "{" , '{' },
2065 { "}" , '}' },
2066 { "." , DOT },
Denys Vlasenko043b1e52009-09-06 12:47:55 +02002067 { "" , 0 },
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002068 };
2069
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002070 const struct res *rp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002071
2072 DBGPRINTF7(("RLOOKUP: enter, n is %s\n", n));
Eric Andersenff9eee42001-06-29 04:57:14 +00002073
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002074 for (rp = restab; rp->r_name[0]; rp++)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002075 if (strcmp(rp->r_name, n) == 0) {
2076 DBGPRINTF7(("RLOOKUP: match, returning %d\n", rp->r_val));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002077 return rp->r_val; /* Return numeric code for shell multiline */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002078 }
2079
2080 DBGPRINTF7(("RLOOKUP: NO match, returning 0\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002081 return 0; /* Not a shell multiline */
Eric Andersenff9eee42001-06-29 04:57:14 +00002082}
2083
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002084static struct op *newtp(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002085{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002086 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002087
Eric Andersen8401eea2004-08-04 19:16:54 +00002088 t = (struct op *) tree(sizeof(*t));
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002089 memset(t, 0, sizeof(*t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002090
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002091 DBGPRINTF3(("NEWTP: allocated %p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002092
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002093 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002094}
2095
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002096static struct op *namelist(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00002097{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002098 DBGPRINTF7(("NAMELIST: enter, t=%p, type %s, iolist=%p\n", t,
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002099 T_CMD_NAMES[t->op_type], iolist));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002100
Eric Andersenff9eee42001-06-29 04:57:14 +00002101 if (iolist) {
Eric Andersen8401eea2004-08-04 19:16:54 +00002102 iolist = addword((char *) NULL, iolist);
Eric Andersenff9eee42001-06-29 04:57:14 +00002103 t->ioact = copyio();
2104 } else
2105 t->ioact = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002106
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002107 if (t->op_type != TCOM) {
2108 if (t->op_type != TPAREN && t->ioact != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002109 t = block(TPAREN, t, NOBLOCK, NOWORDS);
2110 t->ioact = t->left->ioact;
2111 t->left->ioact = NULL;
2112 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002113 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002114 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002115
Eric Andersenff9eee42001-06-29 04:57:14 +00002116 word(NOWORD);
Denis Vlasenko509697f2008-03-02 12:49:39 +00002117 t->op_words = copyw();
Eric Andersen12de6cf2004-08-04 19:19:10 +00002118
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002119 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002120}
2121
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002122static char **copyw(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002123{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002124 char **wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00002125
2126 wd = getwords(wdlist);
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002127 wdlist = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002128 return wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00002129}
2130
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002131static void word(char *cp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002132{
2133 wdlist = addword(cp, wdlist);
2134}
2135
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002136static struct ioword **copyio(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002137{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002138 struct ioword **iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002139
2140 iop = (struct ioword **) getwords(iolist);
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002141 iolist = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002142 return iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002143}
2144
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002145static struct ioword *io(int u, int f, char *cp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002146{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002147 struct ioword *iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002148
2149 iop = (struct ioword *) tree(sizeof(*iop));
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002150 iop->io_fd = u;
Eric Andersenff9eee42001-06-29 04:57:14 +00002151 iop->io_flag = f;
2152 iop->io_name = cp;
Eric Andersen8401eea2004-08-04 19:16:54 +00002153 iolist = addword((char *) iop, iolist);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002154 return iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002155}
2156
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002157static int yylex(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00002158{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002159 int c, c1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002160 int atstart;
2161
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002162 c = peeksym;
2163 if (c > 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002164 peeksym = 0;
2165 if (c == '\n')
2166 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002167 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002168 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002169
Eric Andersenff9eee42001-06-29 04:57:14 +00002170 nlseen = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002171 atstart = startl;
2172 startl = 0;
2173 yylval.i = 0;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002174 global_env.linep = line;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002175
2176/* MALAMO */
2177 line[LINELIM - 1] = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00002178
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002179 loop:
Eric Andersen12de6cf2004-08-04 19:19:10 +00002180 while ((c = my_getc(0)) == ' ' || c == '\t') /* Skip whitespace */
Denis Vlasenko509697f2008-03-02 12:49:39 +00002181 continue;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002182
Eric Andersenff9eee42001-06-29 04:57:14 +00002183 switch (c) {
2184 default:
2185 if (any(c, "0123456789")) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002186 c1 = my_getc(0);
2187 unget(c1);
Eric Andersenff9eee42001-06-29 04:57:14 +00002188 if (c1 == '<' || c1 == '>') {
2189 iounit = c - '0';
2190 goto loop;
2191 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002192 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002193 c = c1;
2194 }
2195 break;
2196
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002197 case '#': /* Comment, skip to next newline or End-of-string */
Denis Vlasenko509697f2008-03-02 12:49:39 +00002198 while ((c = my_getc(0)) != '\0' && c != '\n')
2199 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00002200 unget(c);
2201 goto loop;
2202
2203 case 0:
Eric Andersen12de6cf2004-08-04 19:19:10 +00002204 DBGPRINTF5(("YYLEX: return 0, c=%d\n", c));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002205 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002206
2207 case '$':
Eric Andersen12de6cf2004-08-04 19:19:10 +00002208 DBGPRINTF9(("YYLEX: found $\n"));
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002209 *global_env.linep++ = c;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002210 c = my_getc(0);
2211 if (c == '{') {
2212 c = collect(c, '}');
2213 if (c != '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002214 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002215 goto pack;
2216 }
2217 break;
2218
2219 case '`':
2220 case '\'':
2221 case '"':
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002222 c = collect(c, c);
2223 if (c != '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002224 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002225 goto pack;
2226
2227 case '|':
2228 case '&':
2229 case ';':
Eric Andersenff9eee42001-06-29 04:57:14 +00002230 startl = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002231 /* If more chars process them, else return NULL char */
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002232 c1 = dual(c);
2233 if (c1 != '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002234 return c1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002235 return c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002236
Eric Andersenff9eee42001-06-29 04:57:14 +00002237 case '^':
2238 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002239 return '|';
Eric Andersenff9eee42001-06-29 04:57:14 +00002240 case '>':
2241 case '<':
2242 diag(c);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002243 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002244
2245 case '\n':
2246 nlseen++;
2247 gethere();
2248 startl = 1;
2249 if (multiline || cf & CONTIN) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002250 if (interactive && global_env.iop <= iostack) {
Denis Vlasenko38f63192007-01-22 09:03:07 +00002251#if ENABLE_FEATURE_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00002252 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00002253#else
Eric Andersen8401eea2004-08-04 19:16:54 +00002254 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00002255#endif
2256 }
2257 if (cf & CONTIN)
2258 goto loop;
2259 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002260 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002261
2262 case '(':
2263 case ')':
2264 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002265 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002266 }
2267
2268 unget(c);
2269
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002270 pack:
2271 while ((c = my_getc(0)) != '\0' && !any(c, "`$ '\"\t;&<>()|^\n")) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002272 if (global_env.linep >= elinep)
Eric Andersenff9eee42001-06-29 04:57:14 +00002273 err("word too long");
2274 else
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002275 *global_env.linep++ = c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002276 };
2277
Eric Andersenff9eee42001-06-29 04:57:14 +00002278 unget(c);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002279
Eric Andersen8401eea2004-08-04 19:16:54 +00002280 if (any(c, "\"'`$"))
Eric Andersenff9eee42001-06-29 04:57:14 +00002281 goto loop;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002282
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002283 *global_env.linep++ = '\0';
Eric Andersen12de6cf2004-08-04 19:19:10 +00002284
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002285 if (atstart) {
2286 c = rlookup(line);
2287 if (c != 0) {
2288 startl = 1;
2289 return c;
2290 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002291 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002292
Eric Andersenff9eee42001-06-29 04:57:14 +00002293 yylval.cp = strsave(line, areanum);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002294 return WORD;
Eric Andersenff9eee42001-06-29 04:57:14 +00002295}
2296
Eric Andersen12de6cf2004-08-04 19:19:10 +00002297
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002298static int collect(int c, int c1)
Eric Andersenff9eee42001-06-29 04:57:14 +00002299{
2300 char s[2];
2301
Eric Andersen12de6cf2004-08-04 19:19:10 +00002302 DBGPRINTF8(("COLLECT: enter, c=%d, c1=%d\n", c, c1));
2303
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002304 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002305 while ((c = my_getc(c1)) != c1) {
2306 if (c == 0) {
2307 unget(c);
2308 s[0] = c1;
2309 s[1] = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00002310 prs("no closing ");
2311 yyerror(s);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002312 return YYERRCODE;
Eric Andersenff9eee42001-06-29 04:57:14 +00002313 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002314 if (interactive && c == '\n' && global_env.iop <= iostack) {
Denis Vlasenko38f63192007-01-22 09:03:07 +00002315#if ENABLE_FEATURE_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00002316 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00002317#else
Eric Andersen8401eea2004-08-04 19:16:54 +00002318 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00002319#endif
2320 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002321 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002322 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002323
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002324 *global_env.linep++ = c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002325
2326 DBGPRINTF8(("COLLECT: return 0, line is %s\n", line));
2327
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002328 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002329}
2330
Eric Andersen12de6cf2004-08-04 19:19:10 +00002331/* "multiline commands" helper func */
2332/* see if next 2 chars form a shell multiline */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002333static int dual(int c)
Eric Andersenff9eee42001-06-29 04:57:14 +00002334{
2335 char s[3];
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002336 char *cp = s;
Eric Andersenff9eee42001-06-29 04:57:14 +00002337
Eric Andersen12de6cf2004-08-04 19:19:10 +00002338 DBGPRINTF8(("DUAL: enter, c=%d\n", c));
2339
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002340 *cp++ = c; /* c is the given "peek" char */
2341 *cp++ = my_getc(0); /* get next char of input */
2342 *cp = '\0'; /* add EOS marker */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002343
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002344 c = rlookup(s); /* see if 2 chars form a shell multiline */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002345 if (c == 0)
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002346 unget(*--cp); /* String is not a shell multiline, put peek char back */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002347
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002348 return c; /* String is multiline, return numeric multiline (restab) code */
Eric Andersenff9eee42001-06-29 04:57:14 +00002349}
2350
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002351static void diag(int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00002352{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002353 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002354
2355 DBGPRINTF8(("DIAG: enter, ec=%d\n", ec));
Eric Andersenff9eee42001-06-29 04:57:14 +00002356
2357 c = my_getc(0);
2358 if (c == '>' || c == '<') {
2359 if (c != ec)
2360 zzerr();
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002361 yylval.i = (ec == '>' ? IOWRITE | IOCAT : IOHERE);
Eric Andersenff9eee42001-06-29 04:57:14 +00002362 c = my_getc(0);
2363 } else
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002364 yylval.i = (ec == '>' ? IOWRITE : IOREAD);
Eric Andersenff9eee42001-06-29 04:57:14 +00002365 if (c != '&' || yylval.i == IOHERE)
2366 unget(c);
2367 else
2368 yylval.i |= IODUP;
2369}
2370
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002371static char *tree(unsigned size)
Eric Andersenff9eee42001-06-29 04:57:14 +00002372{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002373 char *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002374
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002375 t = getcell(size);
2376 if (t == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002377 DBGPRINTF2(("TREE: getcell(%d) failed!\n", size));
Eric Andersenff9eee42001-06-29 04:57:14 +00002378 prs("command line too complicated\n");
2379 fail();
2380 /* NOTREACHED */
2381 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002382 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002383}
2384
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002385
Eric Andersenff9eee42001-06-29 04:57:14 +00002386/* VARARGS1 */
2387/* ARGSUSED */
2388
2389/* -------- exec.c -------- */
2390
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002391static struct op **find1case(struct op *t, const char *w)
2392{
2393 struct op *t1;
2394 struct op **tp;
2395 char **wp;
2396 char *cp;
2397
2398 if (t == NULL) {
2399 DBGPRINTF3(("FIND1CASE: enter, t==NULL, returning.\n"));
2400 return NULL;
2401 }
2402
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002403 DBGPRINTF3(("FIND1CASE: enter, t->op_type=%d (%s)\n", t->op_type,
2404 T_CMD_NAMES[t->op_type]));
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002405
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002406 if (t->op_type == TLIST) {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002407 tp = find1case(t->left, w);
2408 if (tp != NULL) {
2409 DBGPRINTF3(("FIND1CASE: found one to the left, returning tp=%p\n", tp));
2410 return tp;
2411 }
2412 t1 = t->right; /* TPAT */
2413 } else
2414 t1 = t;
2415
Denis Vlasenko509697f2008-03-02 12:49:39 +00002416 for (wp = t1->op_words; *wp;) {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002417 cp = evalstr(*wp++, DOSUB);
2418 if (cp && gmatch(w, cp)) {
2419 DBGPRINTF3(("FIND1CASE: returning &t1->left= %p.\n",
2420 &t1->left));
2421 return &t1->left;
2422 }
2423 }
2424
2425 DBGPRINTF(("FIND1CASE: returning NULL\n"));
2426 return NULL;
2427}
2428
2429static struct op *findcase(struct op *t, const char *w)
2430{
2431 struct op **tp;
2432
2433 tp = find1case(t, w);
2434 return tp != NULL ? *tp : NULL;
2435}
2436
Eric Andersenff9eee42001-06-29 04:57:14 +00002437/*
2438 * execute tree
2439 */
2440
Denis Vlasenko7e497522008-02-12 09:51:03 +00002441static int execute(struct op *t, int *pin, int *pout, int no_fork)
Eric Andersenff9eee42001-06-29 04:57:14 +00002442{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002443 struct op *t1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002444 volatile int i, rv, a;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002445 const char *cp;
2446 char **wp, **wp2;
Eric Andersenff9eee42001-06-29 04:57:14 +00002447 struct var *vp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002448 struct op *outtree_save;
Eric Andersenff9eee42001-06-29 04:57:14 +00002449 struct brkcon bc;
2450
2451#if __GNUC__
2452 /* Avoid longjmp clobbering */
2453 (void) &wp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002454#endif
Eric Andersenff9eee42001-06-29 04:57:14 +00002455
Eric Andersen12de6cf2004-08-04 19:19:10 +00002456 if (t == NULL) {
2457 DBGPRINTF4(("EXECUTE: enter, t==null, returning.\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002458 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002459 }
2460
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002461 DBGPRINTF(("EXECUTE: t=%p, t->op_type=%d (%s), t->op_words is %s\n", t,
2462 t->op_type, T_CMD_NAMES[t->op_type],
Denis Vlasenko509697f2008-03-02 12:49:39 +00002463 ((t->op_words == NULL) ? "NULL" : t->op_words[0])));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002464
Eric Andersenff9eee42001-06-29 04:57:14 +00002465 rv = 0;
2466 a = areanum++;
Denis Vlasenko509697f2008-03-02 12:49:39 +00002467 wp2 = t->op_words;
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002468 wp = (wp2 != NULL)
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002469 ? eval(wp2, t->op_type == TCOM ? DOALL : DOALL & ~DOKEY)
Eric Andersen8401eea2004-08-04 19:16:54 +00002470 : NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00002471
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002472 switch (t->op_type) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002473 case TDOT:
2474 DBGPRINTF3(("EXECUTE: TDOT\n"));
2475
2476 outtree_save = outtree;
2477
Denis Vlasenko509697f2008-03-02 12:49:39 +00002478 newfile(evalstr(t->op_words[0], DOALL));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002479
Denis Vlasenko68404f12008-03-17 09:00:54 +00002480 t->left = dowholefile(TLIST /*, 0*/);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002481 t->right = NULL;
2482
2483 outtree = outtree_save;
2484
2485 if (t->left)
Denis Vlasenko7e497522008-02-12 09:51:03 +00002486 rv = execute(t->left, pin, pout, /* no_fork: */ 0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002487 if (t->right)
Denis Vlasenko7e497522008-02-12 09:51:03 +00002488 rv = execute(t->right, pin, pout, /* no_fork: */ 0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002489 break;
2490
Eric Andersenff9eee42001-06-29 04:57:14 +00002491 case TPAREN:
Denis Vlasenko7e497522008-02-12 09:51:03 +00002492 rv = execute(t->left, pin, pout, /* no_fork: */ 0);
Eric Andersen737f5fb2003-03-14 16:05:59 +00002493 break;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002494
Eric Andersenff9eee42001-06-29 04:57:14 +00002495 case TCOM:
Denis Vlasenko7e497522008-02-12 09:51:03 +00002496 rv = forkexec(t, pin, pout, no_fork, wp);
Eric Andersenff9eee42001-06-29 04:57:14 +00002497 break;
2498
2499 case TPIPE:
2500 {
Eric Andersen8401eea2004-08-04 19:16:54 +00002501 int pv[2];
2502
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002503 rv = openpipe(pv);
2504 if (rv < 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00002505 break;
2506 pv[0] = remap(pv[0]);
2507 pv[1] = remap(pv[1]);
Denis Vlasenko7e497522008-02-12 09:51:03 +00002508 (void) execute(t->left, pin, pv, /* no_fork: */ 0);
2509 rv = execute(t->right, pv, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002510 }
2511 break;
2512
2513 case TLIST:
Denis Vlasenko7e497522008-02-12 09:51:03 +00002514 (void) execute(t->left, pin, pout, /* no_fork: */ 0);
2515 rv = execute(t->right, pin, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002516 break;
2517
2518 case TASYNC:
Eric Andersen8401eea2004-08-04 19:16:54 +00002519 {
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002520 smallint hinteractive = interactive;
Eric Andersenff9eee42001-06-29 04:57:14 +00002521
Eric Andersen12de6cf2004-08-04 19:19:10 +00002522 DBGPRINTF7(("EXECUTE: TASYNC clause, calling vfork()...\n"));
2523
Eric Andersen8401eea2004-08-04 19:16:54 +00002524 i = vfork();
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002525 if (i == 0) { /* child */
Eric Andersen8401eea2004-08-04 19:16:54 +00002526 signal(SIGINT, SIG_IGN);
2527 signal(SIGQUIT, SIG_IGN);
2528 if (interactive)
2529 signal(SIGTERM, SIG_DFL);
2530 interactive = 0;
2531 if (pin == NULL) {
2532 close(0);
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00002533 xopen(bb_dev_null, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00002534 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002535 _exit(execute(t->left, pin, pout, /* no_fork: */ 1));
Eric Andersenff9eee42001-06-29 04:57:14 +00002536 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002537 interactive = hinteractive;
2538 if (i != -1) {
2539 setval(lookup("!"), putn(i));
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002540 closepipe(pin);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002541 if (interactive) {
2542 prs(putn(i));
2543 prs("\n");
2544 }
2545 } else
2546 rv = -1;
2547 setstatus(rv);
Eric Andersenff9eee42001-06-29 04:57:14 +00002548 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002549 break;
2550
2551 case TOR:
2552 case TAND:
Denis Vlasenko7e497522008-02-12 09:51:03 +00002553 rv = execute(t->left, pin, pout, /* no_fork: */ 0);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002554 t1 = t->right;
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002555 if (t1 != NULL && (rv == 0) == (t->op_type == TAND))
Denis Vlasenko7e497522008-02-12 09:51:03 +00002556 rv = execute(t1, pin, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002557 break;
2558
2559 case TFOR:
2560 if (wp == NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00002561 wp = dolv + 1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002562 i = dolc;
2563 if (i < 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00002564 i = 0;
2565 } else {
2566 i = -1;
Denis Vlasenko509697f2008-03-02 12:49:39 +00002567 while (*wp++ != NULL)
2568 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00002569 }
2570 vp = lookup(t->str);
2571 while (setjmp(bc.brkpt))
2572 if (isbreak)
2573 goto broken;
Denis Vlasenko7ae1cc12008-07-20 23:03:23 +00002574 /* Restore areanum value. It may be incremented by execute()
2575 * below, and then "continue" may jump back to setjmp above */
2576 areanum = a + 1;
2577 freearea(areanum + 1);
Eric Andersenff9eee42001-06-29 04:57:14 +00002578 brkset(&bc);
2579 for (t1 = t->left; i-- && *wp != NULL;) {
2580 setval(vp, *wp++);
Denis Vlasenko7e497522008-02-12 09:51:03 +00002581 rv = execute(t1, pin, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002582 }
2583 brklist = brklist->nextlev;
2584 break;
2585
2586 case TWHILE:
2587 case TUNTIL:
2588 while (setjmp(bc.brkpt))
2589 if (isbreak)
2590 goto broken;
Denis Vlasenko7ae1cc12008-07-20 23:03:23 +00002591 /* Restore areanum value. It may be incremented by execute()
2592 * below, and then "continue" may jump back to setjmp above */
2593 areanum = a + 1;
2594 freearea(areanum + 1);
Eric Andersenff9eee42001-06-29 04:57:14 +00002595 brkset(&bc);
2596 t1 = t->left;
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002597 while ((execute(t1, pin, pout, /* no_fork: */ 0) == 0) == (t->op_type == TWHILE))
Denis Vlasenko7e497522008-02-12 09:51:03 +00002598 rv = execute(t->right, pin, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002599 brklist = brklist->nextlev;
2600 break;
2601
2602 case TIF:
2603 case TELIF:
Eric Andersen8401eea2004-08-04 19:16:54 +00002604 if (t->right != NULL) {
Denis Vlasenko7e497522008-02-12 09:51:03 +00002605 rv = !execute(t->left, pin, pout, /* no_fork: */ 0) ?
2606 execute(t->right->left, pin, pout, /* no_fork: */ 0) :
2607 execute(t->right->right, pin, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002608 }
2609 break;
2610
2611 case TCASE:
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002612 cp = evalstr(t->str, DOSUB | DOTRIM);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002613 if (cp == NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00002614 cp = "";
Eric Andersen12de6cf2004-08-04 19:19:10 +00002615
2616 DBGPRINTF7(("EXECUTE: TCASE, t->str is %s, cp is %s\n",
2617 ((t->str == NULL) ? "NULL" : t->str),
2618 ((cp == NULL) ? "NULL" : cp)));
2619
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002620 t1 = findcase(t->left, cp);
2621 if (t1 != NULL) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002622 DBGPRINTF7(("EXECUTE: TCASE, calling execute(t=%p, t1=%p)...\n", t, t1));
Denis Vlasenko7e497522008-02-12 09:51:03 +00002623 rv = execute(t1, pin, pout, /* no_fork: */ 0);
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002624 DBGPRINTF7(("EXECUTE: TCASE, back from execute(t=%p, t1=%p)...\n", t, t1));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002625 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002626 break;
2627
2628 case TBRACE:
2629/*
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002630 iopp = t->ioact;
2631 if (i)
Eric Andersenff9eee42001-06-29 04:57:14 +00002632 while (*iopp)
2633 if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) {
2634 rv = -1;
2635 break;
2636 }
2637*/
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002638 if (rv >= 0) {
2639 t1 = t->left;
2640 if (t1) {
Denis Vlasenko7e497522008-02-12 09:51:03 +00002641 rv = execute(t1, pin, pout, /* no_fork: */ 0);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002642 }
2643 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002644 break;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002645
2646 };
Eric Andersenff9eee42001-06-29 04:57:14 +00002647
Denis Vlasenkoe4712752007-04-14 15:08:41 +00002648 broken:
Denis Vlasenko509697f2008-03-02 12:49:39 +00002649// Restoring op_words is most likely not needed now: see comment in forkexec()
2650// (also take a look at exec builtin (doexec) - it touches t->op_words)
2651 t->op_words = wp2;
Eric Andersenff9eee42001-06-29 04:57:14 +00002652 isbreak = 0;
2653 freehere(areanum);
2654 freearea(areanum);
2655 areanum = a;
2656 if (interactive && intr) {
2657 closeall();
2658 fail();
2659 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002660
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002661 i = trapset;
2662 if (i != 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002663 trapset = 0;
2664 runtrap(i);
2665 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002666
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002667 DBGPRINTF(("EXECUTE: returning from t=%p, rv=%d\n", t, rv));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002668 return rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00002669}
2670
Denis Vlasenkoe4712752007-04-14 15:08:41 +00002671static builtin_func_ptr inbuilt(const char *s)
2672{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002673 const struct builtincmd *bp;
2674
Denis Vlasenko95cb3262007-04-09 03:06:34 +00002675 for (bp = builtincmds; bp->name; bp++)
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002676 if (strcmp(bp->name, s) == 0)
2677 return bp->builtinfunc;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002678 return NULL;
2679}
2680
Denis Vlasenko7e497522008-02-12 09:51:03 +00002681static int forkexec(struct op *t, int *pin, int *pout, int no_fork, char **wp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002682{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002683 pid_t newpid;
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002684 int i;
2685 builtin_func_ptr bltin = NULL;
Denis Vlasenko7e497522008-02-12 09:51:03 +00002686 const char *bltin_name = NULL;
2687 const char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00002688 struct ioword **iopp;
2689 int resetsig;
2690 char **owp;
Denis Vlasenko7e497522008-02-12 09:51:03 +00002691 int forked;
Eric Andersenff9eee42001-06-29 04:57:14 +00002692
2693 int *hpin = pin;
2694 int *hpout = pout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002695 char *hwp;
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002696 smallint hinteractive;
2697 smallint hintr;
2698 smallint hexecflg;
Eric Andersen8401eea2004-08-04 19:16:54 +00002699 struct brkcon *hbrklist;
Eric Andersenff9eee42001-06-29 04:57:14 +00002700
2701#if __GNUC__
2702 /* Avoid longjmp clobbering */
2703 (void) &pin;
2704 (void) &pout;
2705 (void) &wp;
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002706 (void) &bltin;
Eric Andersenff9eee42001-06-29 04:57:14 +00002707 (void) &cp;
2708 (void) &resetsig;
2709 (void) &owp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002710#endif
Eric Andersenff9eee42001-06-29 04:57:14 +00002711
Denis Vlasenko7e497522008-02-12 09:51:03 +00002712 DBGPRINTF(("FORKEXEC: t=%p, pin %p, pout %p, no_fork %d\n", t, pin,
2713 pout, no_fork));
Denis Vlasenko509697f2008-03-02 12:49:39 +00002714 DBGPRINTF7(("FORKEXEC: t->op_words is %s\n",
2715 ((t->op_words == NULL) ? "NULL" : t->op_words[0])));
Eric Andersenff9eee42001-06-29 04:57:14 +00002716 owp = wp;
2717 resetsig = 0;
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002718 if (t->op_type == TCOM) {
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00002719 while (*wp++ != NULL)
2720 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00002721 cp = *wp;
2722
2723 /* strip all initial assignments */
Denis Vlasenko7e497522008-02-12 09:51:03 +00002724 /* FIXME: not correct wrt PATH=yyy command etc */
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00002725 if (FLAG['x']) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002726 DBGPRINTF9(("FORKEXEC: echo'ing, cp=%p, wp=%p, owp=%p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00002727 cp, wp, owp));
Eric Andersen8401eea2004-08-04 19:16:54 +00002728 echo(cp ? wp : owp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002729 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002730
Denis Vlasenko7e497522008-02-12 09:51:03 +00002731 if (cp == NULL) {
2732 if (t->ioact == NULL) {
2733 while ((cp = *owp++) != NULL && assign(cp, COPYV))
2734 continue;
2735 DBGPRINTF(("FORKEXEC: returning setstatus(0)\n"));
2736 return setstatus(0);
2737 }
2738 } else { /* cp != NULL */
2739 bltin_name = cp;
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002740 bltin = inbuilt(cp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002741 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002742 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002743
Denis Vlasenko7e497522008-02-12 09:51:03 +00002744 forked = 0;
Denis Vlasenko509697f2008-03-02 12:49:39 +00002745 // We were pointing t->op_words to temporary (expanded) arg list:
2746 // t->op_words = wp;
Denis Vlasenkofe218832008-03-01 09:35:39 +00002747 // and restored it later (in execute()), but "break"
Denis Vlasenko509697f2008-03-02 12:49:39 +00002748 // longjmps away (at "Run builtin" below), leaving t->op_words clobbered!
Denis Vlasenkofe218832008-03-01 09:35:39 +00002749 // See http://bugs.busybox.net/view.php?id=846.
Denis Vlasenko509697f2008-03-02 12:49:39 +00002750 // Now we do not touch t->op_words, but separately pass wp as param list
Denis Vlasenko42cc3042008-03-24 02:05:58 +00002751 // to builtins
Denis Vlasenko7e497522008-02-12 09:51:03 +00002752 DBGPRINTF(("FORKEXEC: bltin %p, no_fork %d, owp %p\n", bltin,
2753 no_fork, owp));
2754 /* Don't fork if it is a lone builtin (not in pipe)
2755 * OR we are told to _not_ fork */
2756 if ((!bltin || pin || pout) /* not lone bltin AND */
2757 && !no_fork /* not told to avoid fork */
2758 ) {
2759 /* Save values in case child alters them after vfork */
Eric Andersenff9eee42001-06-29 04:57:14 +00002760 hpin = pin;
2761 hpout = pout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002762 hwp = *wp;
2763 hinteractive = interactive;
2764 hintr = intr;
2765 hbrklist = brklist;
2766 hexecflg = execflg;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002767
Eric Andersen12de6cf2004-08-04 19:19:10 +00002768 DBGPRINTF3(("FORKEXEC: calling vfork()...\n"));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002769 newpid = vfork();
Eric Andersen12de6cf2004-08-04 19:19:10 +00002770 if (newpid == -1) {
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00002771 DBGPRINTF(("FORKEXEC: ERROR, can't vfork()!\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002772 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002773 }
2774
Denis Vlasenko489f93e2007-02-01 01:43:16 +00002775 if (newpid > 0) { /* Parent */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002776 /* Restore values */
Eric Andersenff9eee42001-06-29 04:57:14 +00002777 pin = hpin;
2778 pout = hpout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002779 *wp = hwp;
2780 interactive = hinteractive;
2781 intr = hintr;
2782 brklist = hbrklist;
2783 execflg = hexecflg;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002784
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002785 closepipe(pin);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002786 return (pout == NULL ? setstatus(waitfor(newpid, 0)) : 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002787 }
2788
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002789 /* Child */
Denis Vlasenko7e497522008-02-12 09:51:03 +00002790 DBGPRINTF(("FORKEXEC: child process, bltin=%p (%s)\n", bltin, bltin_name));
Eric Andersenff9eee42001-06-29 04:57:14 +00002791 if (interactive) {
2792 signal(SIGINT, SIG_IGN);
2793 signal(SIGQUIT, SIG_IGN);
2794 resetsig = 1;
2795 }
2796 interactive = 0;
2797 intr = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002798 forked = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002799 brklist = 0;
2800 execflg = 0;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002801 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002802
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002803 if (owp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002804 while ((cp = *owp++) != NULL && assign(cp, COPYV))
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002805 if (!bltin)
Eric Andersenff9eee42001-06-29 04:57:14 +00002806 export(lookup(cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002807
Denis Vlasenko284d0fa2008-02-16 13:18:17 +00002808 if (pin) { /* NB: close _first_, then move fds! */
2809 close(pin[1]);
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00002810 xmove_fd(pin[0], 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002811 }
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002812 if (pout) {
Denis Vlasenko284d0fa2008-02-16 13:18:17 +00002813 close(pout[0]);
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00002814 xmove_fd(pout[1], 1);
Eric Andersenff9eee42001-06-29 04:57:14 +00002815 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002816
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002817 iopp = t->ioact;
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002818 if (iopp) {
2819 if (bltin && bltin != doexec) {
Denis Vlasenko7e497522008-02-12 09:51:03 +00002820 prs(bltin_name);
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00002821 err(": can't redirect shell command");
Eric Andersen12de6cf2004-08-04 19:19:10 +00002822 if (forked)
2823 _exit(-1);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002824 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002825 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002826 while (*iopp) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002827 if (iosetup(*iopp++, pin != NULL, pout != NULL)) {
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002828 /* system-detected error */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002829 if (forked)
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002830 _exit(-1);
2831 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002832 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002833 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002834 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002835
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002836 if (bltin) {
Denis Vlasenko7e497522008-02-12 09:51:03 +00002837 if (forked || pin || pout) {
2838 /* Builtin in pipe: disallowed */
2839 /* TODO: allow "exec"? */
2840 prs(bltin_name);
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00002841 err(": can't run builtin as part of pipe");
Denis Vlasenko7e497522008-02-12 09:51:03 +00002842 if (forked)
2843 _exit(-1);
2844 return -1;
2845 }
Denis Vlasenkofe218832008-03-01 09:35:39 +00002846 /* Run builtin */
2847 i = setstatus(bltin(t, wp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002848 if (forked)
2849 _exit(i);
2850 DBGPRINTF(("FORKEXEC: returning i=%d\n", i));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002851 return i;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002852 }
2853
Eric Andersenff9eee42001-06-29 04:57:14 +00002854 /* should use FIOCEXCL */
Eric Andersen8401eea2004-08-04 19:16:54 +00002855 for (i = FDBASE; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00002856 close(i);
2857 if (resetsig) {
2858 signal(SIGINT, SIG_DFL);
2859 signal(SIGQUIT, SIG_DFL);
2860 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002861
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002862 if (t->op_type == TPAREN)
Denis Vlasenko7e497522008-02-12 09:51:03 +00002863 _exit(execute(t->left, NOPIPE, NOPIPE, /* no_fork: */ 1));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002864 if (wp[0] == NULL)
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +00002865 _exit(EXIT_SUCCESS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002866
Eric Andersenfd7a4c82004-09-02 23:13:10 +00002867 cp = rexecve(wp[0], wp, makenv(0, NULL));
Eric Andersen8401eea2004-08-04 19:16:54 +00002868 prs(wp[0]);
2869 prs(": ");
Eric Andersen12de6cf2004-08-04 19:19:10 +00002870 err(cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00002871 if (!execflg)
2872 trap[0] = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002873
Denis Vlasenko7e497522008-02-12 09:51:03 +00002874 DBGPRINTF(("FORKEXEC: calling leave(), pid=%d\n", getpid()));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002875
Eric Andersenff9eee42001-06-29 04:57:14 +00002876 leave();
2877 /* NOTREACHED */
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002878 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002879}
2880
2881/*
2882 * 0< 1> are ignored as required
2883 * within pipelines.
2884 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002885static int iosetup(struct ioword *iop, int pipein, int pipeout)
Eric Andersenff9eee42001-06-29 04:57:14 +00002886{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002887 int u = -1;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002888 char *cp = NULL;
2889 const char *msg;
Eric Andersenff9eee42001-06-29 04:57:14 +00002890
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002891 DBGPRINTF(("IOSETUP: iop %p, pipein %i, pipeout %i\n", iop,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002892 pipein, pipeout));
2893
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002894 if (iop->io_fd == IODEFAULT) /* take default */
2895 iop->io_fd = iop->io_flag & (IOREAD | IOHERE) ? 0 : 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002896
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002897 if (pipein && iop->io_fd == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002898 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002899
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002900 if (pipeout && iop->io_fd == 1)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002901 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002902
Eric Andersen8401eea2004-08-04 19:16:54 +00002903 msg = iop->io_flag & (IOREAD | IOHERE) ? "open" : "create";
Eric Andersenff9eee42001-06-29 04:57:14 +00002904 if ((iop->io_flag & IOHERE) == 0) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002905 cp = iop->io_name; /* huh?? */
2906 cp = evalstr(cp, DOSUB | DOTRIM);
2907 if (cp == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002908 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002909 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002910
Eric Andersenff9eee42001-06-29 04:57:14 +00002911 if (iop->io_flag & IODUP) {
2912 if (cp[1] || (!isdigit(*cp) && *cp != '-')) {
2913 prs(cp);
2914 err(": illegal >& argument");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002915 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002916 }
2917 if (*cp == '-')
2918 iop->io_flag = IOCLOSE;
Eric Andersen8401eea2004-08-04 19:16:54 +00002919 iop->io_flag &= ~(IOREAD | IOWRITE);
Eric Andersenff9eee42001-06-29 04:57:14 +00002920 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002921
Eric Andersenff9eee42001-06-29 04:57:14 +00002922 switch (iop->io_flag) {
2923 case IOREAD:
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00002924 u = open(cp, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00002925 break;
2926
2927 case IOHERE:
Eric Andersen8401eea2004-08-04 19:16:54 +00002928 case IOHERE | IOXHERE:
2929 u = herein(iop->io_name, iop->io_flag & IOXHERE);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002930 cp = (char*)"here file";
Eric Andersenff9eee42001-06-29 04:57:14 +00002931 break;
2932
Eric Andersen8401eea2004-08-04 19:16:54 +00002933 case IOWRITE | IOCAT:
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00002934 u = open(cp, O_WRONLY);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002935 if (u >= 0) {
Denis Vlasenkoea620772006-10-14 02:23:43 +00002936 lseek(u, (long) 0, SEEK_END);
Eric Andersenff9eee42001-06-29 04:57:14 +00002937 break;
2938 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002939 /* fall through to creation if >>file doesn't exist */
2940
Eric Andersenff9eee42001-06-29 04:57:14 +00002941 case IOWRITE:
2942 u = creat(cp, 0666);
2943 break;
2944
2945 case IODUP:
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002946 u = dup2(*cp - '0', iop->io_fd);
Eric Andersenff9eee42001-06-29 04:57:14 +00002947 break;
2948
2949 case IOCLOSE:
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002950 close(iop->io_fd);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002951 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002952 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002953
Eric Andersenff9eee42001-06-29 04:57:14 +00002954 if (u < 0) {
2955 prs(cp);
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00002956 prs(": can't ");
Eric Andersenff9eee42001-06-29 04:57:14 +00002957 warn(msg);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002958 return 1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002959 }
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002960 xmove_fd(u, iop->io_fd);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002961 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002962}
2963
Eric Andersenff9eee42001-06-29 04:57:14 +00002964/*
2965 * Enter a new loop level (marked for break/continue).
2966 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002967static void brkset(struct brkcon *bc)
Eric Andersenff9eee42001-06-29 04:57:14 +00002968{
2969 bc->nextlev = brklist;
2970 brklist = bc;
2971}
2972
2973/*
2974 * Wait for the last process created.
2975 * Print a message for each process found
2976 * that was killed by a signal.
2977 * Ignore interrupt signals while waiting
2978 * unless `canintr' is true.
2979 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002980static int waitfor(int lastpid, int canintr)
Eric Andersenff9eee42001-06-29 04:57:14 +00002981{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002982 int pid, rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00002983 int s;
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002984 smallint oheedint = heedint;
Eric Andersenff9eee42001-06-29 04:57:14 +00002985
2986 heedint = 0;
2987 rv = 0;
2988 do {
2989 pid = wait(&s);
2990 if (pid == -1) {
2991 if (errno != EINTR || canintr)
2992 break;
2993 } else {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002994 rv = WAITSIG(s);
2995 if (rv != 0) {
Denis Vlasenko80b8b392007-06-25 10:55:35 +00002996 if (rv < ARRAY_SIZE(signame)) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002997 if (signame[rv] != NULL) {
2998 if (pid != lastpid) {
2999 prn(pid);
3000 prs(": ");
3001 }
3002 prs(signame[rv]);
3003 }
3004 } else {
3005 if (pid != lastpid) {
3006 prn(pid);
3007 prs(": ");
3008 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003009 prs("Signal ");
3010 prn(rv);
3011 prs(" ");
Eric Andersenff9eee42001-06-29 04:57:14 +00003012 }
3013 if (WAITCORE(s))
3014 prs(" - core dumped");
Denis Vlasenko80b8b392007-06-25 10:55:35 +00003015 if (rv >= ARRAY_SIZE(signame) || signame[rv])
Eric Andersenff9eee42001-06-29 04:57:14 +00003016 prs("\n");
Mike Frysingerb81f97b2008-05-14 11:51:04 +00003017 rv |= 0x80;
Eric Andersenff9eee42001-06-29 04:57:14 +00003018 } else
3019 rv = WAITVAL(s);
3020 }
3021 } while (pid != lastpid);
3022 heedint = oheedint;
3023 if (intr) {
3024 if (interactive) {
3025 if (canintr)
3026 intr = 0;
3027 } else {
Eric Andersen8401eea2004-08-04 19:16:54 +00003028 if (exstat == 0)
3029 exstat = rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003030 onintr(0);
3031 }
3032 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003033 return rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003034}
3035
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003036static int setstatus(int s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003037{
3038 exstat = s;
3039 setval(lookup("?"), putn(s));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003040 return s;
Eric Andersenff9eee42001-06-29 04:57:14 +00003041}
3042
3043/*
3044 * PATH-searching interface to execve.
3045 * If getenv("PATH") were kept up-to-date,
3046 * execvp might be used.
3047 */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003048static const char *rexecve(char *c, char **v, char **envp)
Eric Andersenff9eee42001-06-29 04:57:14 +00003049{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003050 const char *sp;
3051 char *tp;
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00003052 int asis = 0;
Eric Andersen1c039232001-07-07 00:05:55 +00003053 char *name = c;
Eric Andersen8401eea2004-08-04 19:16:54 +00003054
Denis Vlasenko80d14be2007-04-10 23:03:30 +00003055 if (ENABLE_FEATURE_SH_STANDALONE) {
Denis Vlasenko1aa7e472007-11-28 06:49:03 +00003056 if (find_applet_by_name(name) >= 0) {
Rob Landleya299efb2006-08-10 21:46:43 +00003057 /* We have to exec here since we vforked. Running
Denis Vlasenkoe4f2d062007-04-11 17:03:19 +00003058 * run_applet_and_exit() won't work and bad things
Rob Landleya299efb2006-08-10 21:46:43 +00003059 * will happen. */
Denis Vlasenkobdbbb7e2007-06-08 15:02:55 +00003060 execve(bb_busybox_exec_path, v, envp);
Rob Landleya299efb2006-08-10 21:46:43 +00003061 }
Eric Andersen1c039232001-07-07 00:05:55 +00003062 }
Eric Andersen1c039232001-07-07 00:05:55 +00003063
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003064 DBGPRINTF(("REXECVE: c=%p, v=%p, envp=%p\n", c, v, envp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003065
Eric Andersen8401eea2004-08-04 19:16:54 +00003066 sp = any('/', c) ? "" : path->value;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003067 asis = (*sp == '\0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003068 while (asis || *sp != '\0') {
3069 asis = 0;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003070 tp = global_env.linep;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003071 for (; *sp != '\0'; tp++) {
3072 *tp = *sp++;
3073 if (*tp == ':') {
3074 asis = (*sp == '\0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003075 break;
3076 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003077 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003078 if (tp != global_env.linep)
Eric Andersenff9eee42001-06-29 04:57:14 +00003079 *tp++ = '/';
Denis Vlasenko509697f2008-03-02 12:49:39 +00003080 strcpy(tp, c);
Eric Andersen1c039232001-07-07 00:05:55 +00003081
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003082 DBGPRINTF3(("REXECVE: global_env.linep is %s\n", global_env.linep));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003083
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003084 execve(global_env.linep, v, envp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003085
Eric Andersenff9eee42001-06-29 04:57:14 +00003086 switch (errno) {
3087 case ENOEXEC:
Denis Vlasenko447bd662008-05-30 22:28:32 +00003088 /* File is executable but file format isnt recognized */
3089 /* Run it as a shell script */
3090 /* (execve above didnt do it itself, unlike execvp) */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003091 *v = global_env.linep;
Denis Vlasenko509697f2008-03-02 12:49:39 +00003092 v--;
3093 tp = *v;
Denis Vlasenko447bd662008-05-30 22:28:32 +00003094 *v = (char*)DEFAULT_SHELL;
Glenn L McGrathdc4e75e2003-09-02 02:36:18 +00003095 execve(DEFAULT_SHELL, v, envp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003096 *v = tp;
Denis Vlasenko509697f2008-03-02 12:49:39 +00003097 return "no shell";
Eric Andersenff9eee42001-06-29 04:57:14 +00003098
3099 case ENOMEM:
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003100 return (char *) bb_msg_memory_exhausted;
Eric Andersenff9eee42001-06-29 04:57:14 +00003101
3102 case E2BIG:
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003103 return "argument list too long";
Eric Andersenff9eee42001-06-29 04:57:14 +00003104 }
3105 }
Denis Vlasenko447bd662008-05-30 22:28:32 +00003106 if (errno == ENOENT) {
3107 exstat = 127; /* standards require this */
3108 return "not found";
3109 }
3110 exstat = 126; /* mimic bash */
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00003111 return "can't execute";
Eric Andersenff9eee42001-06-29 04:57:14 +00003112}
3113
3114/*
3115 * Run the command produced by generator `f'
3116 * applied to stream `arg'.
3117 */
Eric Andersen8401eea2004-08-04 19:16:54 +00003118static int run(struct ioarg *argp, int (*f) (struct ioarg *))
Eric Andersenff9eee42001-06-29 04:57:14 +00003119{
3120 struct op *otree;
3121 struct wdblock *swdlist;
3122 struct wdblock *siolist;
3123 jmp_buf ev, rt;
3124 xint *ofail;
3125 int rv;
3126
3127#if __GNUC__
3128 /* Avoid longjmp clobbering */
3129 (void) &rv;
3130#endif
3131
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003132 DBGPRINTF(("RUN: enter, areanum %d, outtree %p, failpt %p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00003133 areanum, outtree, failpt));
3134
Eric Andersenff9eee42001-06-29 04:57:14 +00003135 areanum++;
3136 swdlist = wdlist;
3137 siolist = iolist;
3138 otree = outtree;
3139 ofail = failpt;
3140 rv = -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003141
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003142 errpt = ev;
3143 if (newenv(setjmp(errpt)) == 0) {
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00003144 wdlist = NULL;
3145 iolist = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00003146 pushio(argp, f);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003147 global_env.iobase = global_env.iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00003148 yynerrs = 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003149 failpt = rt;
3150 if (setjmp(failpt) == 0 && yyparse() == 0)
Denis Vlasenko7e497522008-02-12 09:51:03 +00003151 rv = execute(outtree, NOPIPE, NOPIPE, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003152 quitenv();
Eric Andersen12de6cf2004-08-04 19:19:10 +00003153 } else {
3154 DBGPRINTF(("RUN: error from newenv()!\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00003155 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00003156
Eric Andersenff9eee42001-06-29 04:57:14 +00003157 wdlist = swdlist;
3158 iolist = siolist;
3159 failpt = ofail;
3160 outtree = otree;
3161 freearea(areanum--);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003162
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003163 return rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003164}
3165
3166/* -------- do.c -------- */
3167
3168/*
3169 * built-in commands: doX
3170 */
3171
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003172static int dohelp(struct op *t UNUSED_PARAM, char **args UNUSED_PARAM)
Eric Andersen1c039232001-07-07 00:05:55 +00003173{
3174 int col;
3175 const struct builtincmd *x;
3176
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +02003177 printf(
Denis Vlasenko34d4d892009-04-04 20:24:37 +00003178 "Built-in commands:\n"
3179 "------------------\n");
Eric Andersen1c039232001-07-07 00:05:55 +00003180
Denis Vlasenko95cb3262007-04-09 03:06:34 +00003181 col = 0;
3182 x = builtincmds;
3183 while (x->name) {
3184 col += printf("%c%s", ((col == 0) ? '\t' : ' '), x->name);
Eric Andersen1c039232001-07-07 00:05:55 +00003185 if (col > 60) {
Denis Vlasenko4daad902007-09-27 10:20:47 +00003186 bb_putchar('\n');
Eric Andersen1c039232001-07-07 00:05:55 +00003187 col = 0;
3188 }
Denis Vlasenko95cb3262007-04-09 03:06:34 +00003189 x++;
Eric Andersen1c039232001-07-07 00:05:55 +00003190 }
Denis Vlasenko80d14be2007-04-10 23:03:30 +00003191#if ENABLE_FEATURE_SH_STANDALONE
Eric Andersen1c039232001-07-07 00:05:55 +00003192 {
Denis Vlasenko1aa7e472007-11-28 06:49:03 +00003193 const char *applet = applet_names;
Eric Andersen1c039232001-07-07 00:05:55 +00003194
Denis Vlasenko1aa7e472007-11-28 06:49:03 +00003195 while (*applet) {
3196 col += printf("%c%s", ((col == 0) ? '\t' : ' '), applet);
Eric Andersen1c039232001-07-07 00:05:55 +00003197 if (col > 60) {
Denis Vlasenko4daad902007-09-27 10:20:47 +00003198 bb_putchar('\n');
Eric Andersen1c039232001-07-07 00:05:55 +00003199 col = 0;
3200 }
Denis Vlasenko1aa7e472007-11-28 06:49:03 +00003201 applet += strlen(applet) + 1;
Eric Andersen1c039232001-07-07 00:05:55 +00003202 }
3203 }
3204#endif
Denis Vlasenko0ee39992006-12-24 15:23:28 +00003205 puts("\n");
Eric Andersen1c039232001-07-07 00:05:55 +00003206 return EXIT_SUCCESS;
3207}
3208
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003209static int dolabel(struct op *t UNUSED_PARAM, char **args UNUSED_PARAM)
Eric Andersenff9eee42001-06-29 04:57:14 +00003210{
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003211 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003212}
3213
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003214static int dochdir(struct op *t UNUSED_PARAM, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003215{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003216 const char *cp, *er;
Eric Andersenff9eee42001-06-29 04:57:14 +00003217
Denis Vlasenkofe218832008-03-01 09:35:39 +00003218 cp = args[1];
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003219 if (cp == NULL) {
3220 cp = homedir->value;
Denis Vlasenkod244c5e2007-02-09 17:30:14 +00003221 if (cp != NULL)
3222 goto do_cd;
3223 er = ": no home directory";
3224 } else {
3225 do_cd:
3226 if (chdir(cp) >= 0)
3227 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003228 er = ": bad directory";
Denis Vlasenkod244c5e2007-02-09 17:30:14 +00003229 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003230 prs(cp != NULL ? cp : "cd");
Eric Andersenff9eee42001-06-29 04:57:14 +00003231 err(er);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003232 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003233}
3234
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003235static int doshift(struct op *t UNUSED_PARAM, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003236{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003237 int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003238
Denis Vlasenkofe218832008-03-01 09:35:39 +00003239 n = args[1] ? getn(args[1]) : 1;
Eric Andersen8401eea2004-08-04 19:16:54 +00003240 if (dolc < n) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003241 err("nothing to shift");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003242 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003243 }
3244 dolv[n] = dolv[0];
3245 dolv += n;
3246 dolc -= n;
3247 setval(lookup("#"), putn(dolc));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003248 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003249}
3250
3251/*
3252 * execute login and newgrp directly
3253 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003254static int dologin(struct op *t UNUSED_PARAM, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003255{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003256 const char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003257
3258 if (interactive) {
3259 signal(SIGINT, SIG_DFL);
3260 signal(SIGQUIT, SIG_DFL);
3261 }
Denis Vlasenkofe218832008-03-01 09:35:39 +00003262 cp = rexecve(args[0], args, makenv(0, NULL));
3263 prs(args[0]);
Eric Andersen8401eea2004-08-04 19:16:54 +00003264 prs(": ");
3265 err(cp);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003266 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003267}
3268
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003269static int doumask(struct op *t UNUSED_PARAM, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003270{
Denis Vlasenko7e497522008-02-12 09:51:03 +00003271 int i;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003272 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003273
Denis Vlasenkofe218832008-03-01 09:35:39 +00003274 cp = args[1];
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003275 if (cp == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003276 i = umask(0);
3277 umask(i);
Denis Vlasenko7e497522008-02-12 09:51:03 +00003278 printf("%04o\n", i);
Eric Andersenff9eee42001-06-29 04:57:14 +00003279 } else {
Denis Vlasenko7e497522008-02-12 09:51:03 +00003280 i = bb_strtou(cp, NULL, 8);
3281 if (errno) {
3282 err("umask: bad octal number");
3283 return 1;
3284 }
3285 umask(i);
Eric Andersenff9eee42001-06-29 04:57:14 +00003286 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003287 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003288}
3289
Denis Vlasenkofe218832008-03-01 09:35:39 +00003290static int doexec(struct op *t, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003291{
Eric Andersenff9eee42001-06-29 04:57:14 +00003292 jmp_buf ex;
3293 xint *ofail;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003294 char **sv_words;
Eric Andersenff9eee42001-06-29 04:57:14 +00003295
3296 t->ioact = NULL;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003297 if (!args[1])
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003298 return 1;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003299
Eric Andersenff9eee42001-06-29 04:57:14 +00003300 execflg = 1;
3301 ofail = failpt;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003302 failpt = ex;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003303
Denis Vlasenko509697f2008-03-02 12:49:39 +00003304 sv_words = t->op_words;
3305 t->op_words = args + 1;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003306// TODO: test what will happen with "exec break" -
Denis Vlasenko509697f2008-03-02 12:49:39 +00003307// will it leave t->op_words pointing to garbage?
Denis Vlasenkofe218832008-03-01 09:35:39 +00003308// (see http://bugs.busybox.net/view.php?id=846)
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003309 if (setjmp(failpt) == 0)
Denis Vlasenko7e497522008-02-12 09:51:03 +00003310 execute(t, NOPIPE, NOPIPE, /* no_fork: */ 1);
Denis Vlasenko509697f2008-03-02 12:49:39 +00003311 t->op_words = sv_words;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003312
Eric Andersenff9eee42001-06-29 04:57:14 +00003313 failpt = ofail;
3314 execflg = 0;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003315
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003316 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003317}
3318
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003319static int dodot(struct op *t UNUSED_PARAM, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003320{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003321 int i;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003322 const char *sp;
3323 char *tp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003324 char *cp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003325 int maltmp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003326
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003327 DBGPRINTF(("DODOT: enter, t=%p, tleft %p, tright %p, global_env.linep is %s\n",
3328 t, t->left, t->right, ((global_env.linep == NULL) ? "NULL" : global_env.linep)));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003329
Denis Vlasenkofe218832008-03-01 09:35:39 +00003330 cp = args[1];
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003331 if (cp == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00003332 DBGPRINTF(("DODOT: bad args, ret 0\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003333 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003334 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003335 DBGPRINTF(("DODOT: cp is %s\n", cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003336
Eric Andersen8401eea2004-08-04 19:16:54 +00003337 sp = any('/', cp) ? ":" : path->value;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003338
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003339 DBGPRINTF(("DODOT: sp is %s, global_env.linep is %s\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00003340 ((sp == NULL) ? "NULL" : sp),
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003341 ((global_env.linep == NULL) ? "NULL" : global_env.linep)));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003342
Eric Andersenff9eee42001-06-29 04:57:14 +00003343 while (*sp) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003344 tp = global_env.linep;
Eric Andersenff9eee42001-06-29 04:57:14 +00003345 while (*sp && (*tp = *sp++) != ':')
3346 tp++;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003347 if (tp != global_env.linep)
Eric Andersenff9eee42001-06-29 04:57:14 +00003348 *tp++ = '/';
Denis Vlasenko509697f2008-03-02 12:49:39 +00003349 strcpy(tp, cp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003350
3351 /* Original code */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003352 i = open(global_env.linep, O_RDONLY);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003353 if (i >= 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003354 exstat = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003355 maltmp = remap(i);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003356 DBGPRINTF(("DODOT: remap=%d, exstat=%d, global_env.iofd %d, i %d, global_env.linep is %s\n",
3357 maltmp, exstat, global_env.iofd, i, global_env.linep));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003358
3359 next(maltmp); /* Basically a PUSHIO */
3360
3361 DBGPRINTF(("DODOT: returning exstat=%d\n", exstat));
3362
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003363 return exstat;
Eric Andersenff9eee42001-06-29 04:57:14 +00003364 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003365 } /* while */
Eric Andersen12de6cf2004-08-04 19:19:10 +00003366
Eric Andersenff9eee42001-06-29 04:57:14 +00003367 prs(cp);
3368 err(": not found");
Eric Andersen12de6cf2004-08-04 19:19:10 +00003369
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003370 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003371}
3372
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003373static int dowait(struct op *t UNUSED_PARAM, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003374{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003375 int i;
3376 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003377
Denis Vlasenkofe218832008-03-01 09:35:39 +00003378 cp = args[1];
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003379 if (cp != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003380 i = getn(cp);
3381 if (i == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003382 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003383 } else
3384 i = -1;
3385 setstatus(waitfor(i, 1));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003386 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003387}
3388
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003389static int doread(struct op *t UNUSED_PARAM, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003390{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003391 char *cp, **wp;
3392 int nb = 0;
3393 int nl = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003394
Denis Vlasenkofe218832008-03-01 09:35:39 +00003395 if (args[1] == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003396 err("Usage: read name ...");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003397 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003398 }
Denis Vlasenkofe218832008-03-01 09:35:39 +00003399 for (wp = args + 1; *wp; wp++) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003400 for (cp = global_env.linep; !nl && cp < elinep - 1; cp++) {
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +00003401 nb = nonblock_safe_read(STDIN_FILENO, cp, sizeof(*cp));
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003402 if (nb != sizeof(*cp))
Eric Andersenff9eee42001-06-29 04:57:14 +00003403 break;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003404 nl = (*cp == '\n');
3405 if (nl || (wp[1] && any(*cp, ifs->value)))
3406 break;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003407 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003408 *cp = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00003409 if (nb <= 0)
3410 break;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003411 setval(lookup(*wp), global_env.linep);
Eric Andersenff9eee42001-06-29 04:57:14 +00003412 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003413 return nb <= 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003414}
3415
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003416static int doeval(struct op *t UNUSED_PARAM, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003417{
Denis Vlasenkofe218832008-03-01 09:35:39 +00003418 return RUN(awordlist, args + 1, wdchar);
Eric Andersenff9eee42001-06-29 04:57:14 +00003419}
3420
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003421static int dotrap(struct op *t UNUSED_PARAM, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003422{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003423 int n, i;
3424 int resetsig;
Eric Andersenff9eee42001-06-29 04:57:14 +00003425
Denis Vlasenkofe218832008-03-01 09:35:39 +00003426 if (args[1] == NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00003427 for (i = 0; i <= _NSIG; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00003428 if (trap[i]) {
3429 prn(i);
3430 prs(": ");
3431 prs(trap[i]);
3432 prs("\n");
3433 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003434 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003435 }
Denis Vlasenkofe218832008-03-01 09:35:39 +00003436 resetsig = isdigit(args[1][0]);
3437 for (i = resetsig ? 1 : 2; args[i] != NULL; ++i) {
3438 n = getsig(args[i]);
Eric Andersenff9eee42001-06-29 04:57:14 +00003439 freecell(trap[n]);
3440 trap[n] = 0;
3441 if (!resetsig) {
Denis Vlasenkofe218832008-03-01 09:35:39 +00003442 if (args[1][0] != '\0') {
3443 trap[n] = strsave(args[1], 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003444 setsig(n, sig);
3445 } else
3446 setsig(n, SIG_IGN);
3447 } else {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00003448 if (interactive) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003449 if (n == SIGINT)
3450 setsig(n, onintr);
3451 else
Eric Andersen8401eea2004-08-04 19:16:54 +00003452 setsig(n, n == SIGQUIT ? SIG_IGN : SIG_DFL);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00003453 } else
Eric Andersenff9eee42001-06-29 04:57:14 +00003454 setsig(n, SIG_DFL);
3455 }
3456 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003457 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003458}
3459
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003460static int getsig(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003461{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003462 int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003463
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003464 n = getn(s);
3465 if (n < 0 || n > _NSIG) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003466 err("trap: bad signal number");
3467 n = 0;
3468 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003469 return n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003470}
3471
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003472static void setsig(int n, sighandler_t f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003473{
3474 if (n == 0)
3475 return;
3476 if (signal(n, SIG_IGN) != SIG_IGN || ourtrap[n]) {
3477 ourtrap[n] = 1;
3478 signal(n, f);
3479 }
3480}
3481
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003482static int getn(char *as)
Eric Andersenff9eee42001-06-29 04:57:14 +00003483{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003484 char *s;
3485 int n, m;
Eric Andersenff9eee42001-06-29 04:57:14 +00003486
3487 s = as;
3488 m = 1;
3489 if (*s == '-') {
3490 m = -1;
3491 s++;
3492 }
3493 for (n = 0; isdigit(*s); s++)
Eric Andersen8401eea2004-08-04 19:16:54 +00003494 n = (n * 10) + (*s - '0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003495 if (*s) {
3496 prs(as);
3497 err(": bad number");
3498 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003499 return n * m;
Eric Andersenff9eee42001-06-29 04:57:14 +00003500}
3501
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003502static int dobreak(struct op *t UNUSED_PARAM, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003503{
Denis Vlasenkofe218832008-03-01 09:35:39 +00003504 return brkcontin(args[1], 1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003505}
3506
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003507static int docontinue(struct op *t UNUSED_PARAM, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003508{
Denis Vlasenkofe218832008-03-01 09:35:39 +00003509 return brkcontin(args[1], 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003510}
3511
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003512static int brkcontin(char *cp, int val)
Eric Andersenff9eee42001-06-29 04:57:14 +00003513{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003514 struct brkcon *bc;
3515 int nl;
Eric Andersenff9eee42001-06-29 04:57:14 +00003516
Eric Andersen8401eea2004-08-04 19:16:54 +00003517 nl = cp == NULL ? 1 : getn(cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003518 if (nl <= 0)
3519 nl = 999;
3520 do {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003521 bc = brklist;
3522 if (bc == NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00003523 break;
3524 brklist = bc->nextlev;
3525 } while (--nl);
3526 if (nl) {
3527 err("bad break/continue level");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003528 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003529 }
Denis Vlasenko648b44f2008-02-12 06:04:06 +00003530 isbreak = (val != 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003531 longjmp(bc->brkpt, 1);
3532 /* NOTREACHED */
3533}
3534
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003535static int doexit(struct op *t UNUSED_PARAM, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003536{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003537 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003538
3539 execflg = 0;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003540 cp = args[1];
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003541 if (cp != NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00003542 setstatus(getn(cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003543
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003544 DBGPRINTF(("DOEXIT: calling leave(), t=%p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003545
Eric Andersenff9eee42001-06-29 04:57:14 +00003546 leave();
3547 /* NOTREACHED */
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003548 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003549}
3550
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003551static int doexport(struct op *t UNUSED_PARAM, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003552{
Denis Vlasenkofe218832008-03-01 09:35:39 +00003553 rdexp(args + 1, export, EXPORT);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003554 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003555}
3556
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003557static int doreadonly(struct op *t UNUSED_PARAM, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003558{
Denis Vlasenkofe218832008-03-01 09:35:39 +00003559 rdexp(args + 1, ronly, RONLY);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003560 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003561}
3562
Eric Andersen8401eea2004-08-04 19:16:54 +00003563static void rdexp(char **wp, void (*f) (struct var *), int key)
Eric Andersenff9eee42001-06-29 04:57:14 +00003564{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003565 DBGPRINTF6(("RDEXP: enter, wp=%p, func=%p, key=%d\n", wp, f, key));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003566 DBGPRINTF6(("RDEXP: *wp=%s\n", *wp));
3567
Eric Andersenff9eee42001-06-29 04:57:14 +00003568 if (*wp != NULL) {
Matt Kraaif69bfc72001-07-12 19:39:59 +00003569 for (; *wp != NULL; wp++) {
3570 if (isassign(*wp)) {
3571 char *cp;
Eric Andersen8401eea2004-08-04 19:16:54 +00003572
Matt Kraaif69bfc72001-07-12 19:39:59 +00003573 assign(*wp, COPYV);
Denis Vlasenko509697f2008-03-02 12:49:39 +00003574 for (cp = *wp; *cp != '='; cp++)
3575 continue;
Matt Kraaif69bfc72001-07-12 19:39:59 +00003576 *cp = '\0';
3577 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003578 if (checkname(*wp))
Eric Andersen8401eea2004-08-04 19:16:54 +00003579 (*f) (lookup(*wp));
Eric Andersenff9eee42001-06-29 04:57:14 +00003580 else
3581 badid(*wp);
Matt Kraaif69bfc72001-07-12 19:39:59 +00003582 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003583 } else
3584 putvlist(key, 1);
3585}
3586
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003587static void badid(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003588{
3589 prs(s);
3590 err(": bad identifier");
3591}
3592
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003593static int doset(struct op *t UNUSED_PARAM, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003594{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003595 struct var *vp;
3596 char *cp;
3597 int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003598
Denis Vlasenkofe218832008-03-01 09:35:39 +00003599 cp = args[1];
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003600 if (cp == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003601 for (vp = vlist; vp; vp = vp->next)
Denis Vlasenko73c571a2009-03-09 00:12:37 +00003602 varput(vp->name, STDOUT_FILENO);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003603 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003604 }
3605 if (*cp == '-') {
Denis Vlasenkofe218832008-03-01 09:35:39 +00003606 args++;
Eric Andersenff9eee42001-06-29 04:57:14 +00003607 if (*++cp == 0)
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003608 FLAG['x'] = FLAG['v'] = 0;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003609 else {
3610 for (; *cp; cp++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003611 switch (*cp) {
3612 case 'e':
3613 if (!interactive)
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003614 FLAG['e']++;
Eric Andersenff9eee42001-06-29 04:57:14 +00003615 break;
3616
3617 default:
Eric Andersen8401eea2004-08-04 19:16:54 +00003618 if (*cp >= 'a' && *cp <= 'z')
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003619 FLAG[(int) *cp]++;
Eric Andersenff9eee42001-06-29 04:57:14 +00003620 break;
3621 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003622 }
3623 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003624 setdash();
3625 }
Denis Vlasenkofe218832008-03-01 09:35:39 +00003626 if (args[1]) {
3627 args[0] = dolv[0];
3628 for (n = 1; args[n]; n++)
3629 setarea((char *) args[n], 0);
Eric Andersen8401eea2004-08-04 19:16:54 +00003630 dolc = n - 1;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003631 dolv = args;
Eric Andersenff9eee42001-06-29 04:57:14 +00003632 setval(lookup("#"), putn(dolc));
Eric Andersen8401eea2004-08-04 19:16:54 +00003633 setarea((char *) (dolv - 1), 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003634 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003635 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003636}
3637
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003638static void varput(char *s, int out)
Eric Andersenff9eee42001-06-29 04:57:14 +00003639{
Matt Kraai69edfec2001-08-06 14:14:18 +00003640 if (isalnum(*s) || *s == '_') {
Denis Vlasenko73c571a2009-03-09 00:12:37 +00003641 xwrite_str(out, s);
3642 xwrite(out, "\n", 1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003643 }
3644}
3645
3646
3647/*
3648 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
3649 * This file contains code for the times builtin.
Eric Andersenff9eee42001-06-29 04:57:14 +00003650 */
Denis Vlasenkofe218832008-03-01 09:35:39 +00003651static void times_fmt(char *buf, clock_t val, unsigned clk_tck)
3652{
3653 unsigned min, sec;
3654 if (sizeof(val) > sizeof(int))
3655 sec = ((unsigned long)val) / clk_tck;
3656 else
3657 sec = ((unsigned)val) / clk_tck;
3658 min = sec / 60;
3659#if ENABLE_DESKTOP
3660 sprintf(buf, "%um%u.%03us", min, (sec - min * 60),
3661 /* msec: */ ((unsigned)(val - (clock_t)sec * clk_tck)) * 1000 / clk_tck
3662 );
3663#else
3664 sprintf(buf, "%um%us", min, (sec - min * 60));
3665#endif
3666}
3667
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003668static int dotimes(struct op *t UNUSED_PARAM, char **args UNUSED_PARAM)
Eric Andersenff9eee42001-06-29 04:57:14 +00003669{
3670 struct tms buf;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003671 unsigned clk_tck = sysconf(_SC_CLK_TCK);
3672 /* How much do we need for "NmN.NNNs" ? */
3673 enum { TIMEBUF_SIZE = sizeof(int)*3 + sizeof(int)*3 + 6 };
3674 char u[TIMEBUF_SIZE], s[TIMEBUF_SIZE];
3675 char cu[TIMEBUF_SIZE], cs[TIMEBUF_SIZE];
Eric Andersenff9eee42001-06-29 04:57:14 +00003676
3677 times(&buf);
Denis Vlasenkofe218832008-03-01 09:35:39 +00003678
3679 times_fmt(u, buf.tms_utime, clk_tck);
3680 times_fmt(s, buf.tms_stime, clk_tck);
3681 times_fmt(cu, buf.tms_cutime, clk_tck);
3682 times_fmt(cs, buf.tms_cstime, clk_tck);
3683
3684 printf("%s %s\n%s %s\n", u, s, cu, cs);
Eric Andersenff9eee42001-06-29 04:57:14 +00003685 return 0;
3686}
3687
3688
Eric Andersenff9eee42001-06-29 04:57:14 +00003689/* -------- eval.c -------- */
3690
3691/*
3692 * ${}
3693 * `command`
3694 * blank interpretation
3695 * quoting
3696 * glob
3697 */
3698
Eric Andersen8401eea2004-08-04 19:16:54 +00003699static char **eval(char **ap, int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003700{
3701 struct wdblock *wb;
3702 char **wp;
3703 char **wf;
3704 jmp_buf ev;
3705
3706#if __GNUC__
3707 /* Avoid longjmp clobbering */
3708 (void) &wp;
3709 (void) &ap;
3710#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00003711
3712 DBGPRINTF4(("EVAL: enter, f=%d\n", f));
3713
Eric Andersenff9eee42001-06-29 04:57:14 +00003714 wp = NULL;
3715 wb = NULL;
3716 wf = NULL;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003717 errpt = ev;
3718 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003719 while (*ap && isassign(*ap))
3720 expand(*ap++, &wb, f & ~DOGLOB);
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003721 if (FLAG['k']) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003722 for (wf = ap; *wf; wf++) {
3723 if (isassign(*wf))
3724 expand(*wf, &wb, f & ~DOGLOB);
3725 }
3726 }
Denis Vlasenko648b44f2008-02-12 06:04:06 +00003727 for (wb = addword((char *) NULL, wb); *ap; ap++) {
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003728 if (!FLAG['k'] || !isassign(*ap))
Eric Andersenff9eee42001-06-29 04:57:14 +00003729 expand(*ap, &wb, f & ~DOKEY);
3730 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003731 wb = addword((char *) 0, wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00003732 wp = getwords(wb);
3733 quitenv();
3734 } else
3735 gflg = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003736
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003737 return gflg ? (char **) NULL : wp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003738}
3739
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003740
Eric Andersenff9eee42001-06-29 04:57:14 +00003741/*
3742 * Make the exported environment from the exported
3743 * names in the dictionary. Keyword assignments
3744 * will already have been done.
3745 */
Eric Andersenfd7a4c82004-09-02 23:13:10 +00003746static char **makenv(int all, struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00003747{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003748 struct var *vp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003749
3750 DBGPRINTF5(("MAKENV: enter, all=%d\n", all));
Eric Andersenff9eee42001-06-29 04:57:14 +00003751
Eric Andersenff9eee42001-06-29 04:57:14 +00003752 for (vp = vlist; vp; vp = vp->next)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003753 if (all || vp->status & EXPORT)
Eric Andersenff9eee42001-06-29 04:57:14 +00003754 wb = addword(vp->name, wb);
Eric Andersen8401eea2004-08-04 19:16:54 +00003755 wb = addword((char *) 0, wb);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003756 return getwords(wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00003757}
3758
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003759static int expand(const char *cp, struct wdblock **wbp, int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003760{
3761 jmp_buf ev;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003762 char *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003763
3764#if __GNUC__
3765 /* Avoid longjmp clobbering */
3766 (void) &cp;
3767#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00003768
3769 DBGPRINTF3(("EXPAND: enter, f=%d\n", f));
3770
Eric Andersenff9eee42001-06-29 04:57:14 +00003771 gflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003772
Eric Andersenff9eee42001-06-29 04:57:14 +00003773 if (cp == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003774 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003775
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003776 if (!anys("$`'\"", cp) && !anys(ifs->value, cp)
3777 && ((f & DOGLOB) == 0 || !anys("[*?", cp))
3778 ) {
3779 xp = strsave(cp, areanum);
Eric Andersenff9eee42001-06-29 04:57:14 +00003780 if (f & DOTRIM)
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003781 unquote(xp);
3782 *wbp = addword(xp, *wbp);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003783 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003784 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003785 errpt = ev;
3786 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003787 PUSHIO(aword, cp, strchar);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003788 global_env.iobase = global_env.iop;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003789 while ((xp = blank(f)) && gflg == 0) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003790 global_env.linep = xp;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003791 xp = strsave(xp, areanum);
Eric Andersen8401eea2004-08-04 19:16:54 +00003792 if ((f & DOGLOB) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003793 if (f & DOTRIM)
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003794 unquote(xp);
3795 *wbp = addword(xp, *wbp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003796 } else
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003797 *wbp = glob(xp, *wbp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003798 }
3799 quitenv();
3800 } else
3801 gflg = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003802 return gflg == 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003803}
3804
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003805static char *evalstr(char *cp, int f)
3806{
3807 struct wdblock *wb;
3808
3809 DBGPRINTF6(("EVALSTR: enter, cp=%p, f=%d\n", cp, f));
3810
3811 wb = NULL;
3812 if (expand(cp, &wb, f)) {
3813 if (wb == NULL || wb->w_nword == 0
3814 || (cp = wb->w_words[0]) == NULL
3815 ) {
Denis Vlasenko8e858e22007-03-07 09:35:43 +00003816// TODO: I suspect that
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003817// char *evalstr(char *cp, int f) is actually
3818// const char *evalstr(const char *cp, int f)!
3819 cp = (char*)"";
3820 }
3821 DELETE(wb);
3822 } else
3823 cp = NULL;
3824 return cp;
3825}
3826
3827
Eric Andersenff9eee42001-06-29 04:57:14 +00003828/*
3829 * Blank interpretation and quoting
3830 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003831static char *blank(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003832{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003833 int c, c1;
3834 char *sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003835 int scanequals, foundequals;
3836
Eric Andersen12de6cf2004-08-04 19:19:10 +00003837 DBGPRINTF3(("BLANK: enter, f=%d\n", f));
3838
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003839 sp = global_env.linep;
Eric Andersenff9eee42001-06-29 04:57:14 +00003840 scanequals = f & DOKEY;
3841 foundequals = 0;
3842
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003843 loop:
3844 c = subgetc('"', foundequals);
3845 switch (c) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003846 case 0:
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003847 if (sp == global_env.linep)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003848 return 0;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003849 *global_env.linep++ = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003850 return sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003851
3852 default:
3853 if (f & DOBLANK && any(c, ifs->value))
3854 goto loop;
3855 break;
3856
3857 case '"':
3858 case '\'':
3859 scanequals = 0;
3860 if (INSUB())
3861 break;
3862 for (c1 = c; (c = subgetc(c1, 1)) != c1;) {
3863 if (c == 0)
3864 break;
3865 if (c == '\'' || !any(c, "$`\""))
3866 c |= QUOTE;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003867 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003868 }
3869 c = 0;
3870 }
3871 unget(c);
Matt Kraai69edfec2001-08-06 14:14:18 +00003872 if (!isalpha(c) && c != '_')
Eric Andersenff9eee42001-06-29 04:57:14 +00003873 scanequals = 0;
3874 for (;;) {
3875 c = subgetc('"', foundequals);
Denys Vlasenko6b9f1632010-01-28 02:24:24 +01003876 if (c == 0
3877 || f & (DOBLANK && any(c, ifs->value))
3878 || (!INSUB() && any(c, "\"'"))
3879 ) {
Eric Andersen8401eea2004-08-04 19:16:54 +00003880 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 */