blob: da1dc35768633315a45cad686a5c6d847ff45ebc [file] [log] [blame]
Eric Andersenff9eee42001-06-29 04:57:14 +00001/* vi: set sw=4 ts=4: */
2/*
3 * Minix shell port for busybox
4 *
5 * This version of the Minix shell was adapted for use in busybox
Eric Andersencb81e642003-07-14 21:21:08 +00006 * by Erik Andersen <andersen@codepoet.org>
Eric Andersenff9eee42001-06-29 04:57:14 +00007 *
Eric Andersen737f5fb2003-03-14 16:05:59 +00008 * - backtick expansion did not work properly
9 * Jonas Holmberg <jonas.holmberg@axis.com>
10 * Robert Schwebel <r.schwebel@pengutronix.de>
Eric Andersencb81e642003-07-14 21:21:08 +000011 * Erik Andersen <andersen@codepoet.org>
Eric Andersen737f5fb2003-03-14 16:05:59 +000012 *
Rob Landleyc9c1a412006-07-12 19:17:55 +000013 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
Eric Andersenff9eee42001-06-29 04:57:14 +000014 */
15
Denis Vlasenko95cb3262007-04-09 03:06:34 +000016#include <sys/times.h>
17#include <setjmp.h>
Denis Vlasenko55f30b02007-03-24 22:42:29 +000018
Mike Frysinger67a32ad2007-03-09 08:25:24 +000019#ifdef STANDALONE
20# ifndef _GNU_SOURCE
21# define _GNU_SOURCE
22# endif
Mike Frysinger67a32ad2007-03-09 08:25:24 +000023# include <sys/types.h>
24# include <sys/stat.h>
25# include <sys/wait.h>
26# include <signal.h>
27# include <stdio.h>
28# include <stdlib.h>
29# include <unistd.h>
30# include <string.h>
31# include <errno.h>
32# include <dirent.h>
33# include <fcntl.h>
34# include <ctype.h>
35# include <assert.h>
36# define bb_dev_null "/dev/null"
37# define DEFAULT_SHELL "/proc/self/exe"
Denis Vlasenkoca525b42007-06-13 12:27:17 +000038# define bb_banner "busybox standalone"
Denis Vlasenko80d14be2007-04-10 23:03:30 +000039# define ENABLE_FEATURE_SH_STANDALONE 0
Mike Frysinger67a32ad2007-03-09 08:25:24 +000040# define bb_msg_memory_exhausted "memory exhausted"
41# define xmalloc(size) malloc(size)
42# define msh_main(argc,argv) main(argc,argv)
43# define safe_read(fd,buf,count) read(fd,buf,count)
Denis Vlasenkoe376d452008-02-20 22:23:24 +000044# define nonblock_safe_read(fd,buf,count) read(fd,buf,count)
Mike Frysinger67a32ad2007-03-09 08:25:24 +000045# define NOT_LONE_DASH(s) ((s)[0] != '-' || (s)[1])
46# define LONE_CHAR(s,c) ((s)[0] == (c) && !(s)[1])
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000047# define NORETURN __attribute__ ((__noreturn__))
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000048static int find_applet_by_name(const char *applet)
Mike Frysinger67a32ad2007-03-09 08:25:24 +000049{
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000050 return -1;
Mike Frysinger67a32ad2007-03-09 08:25:24 +000051}
Denis Vlasenko10457b92007-03-27 22:01:31 +000052static char *utoa_to_buf(unsigned n, char *buf, unsigned buflen)
Mike Frysinger67a32ad2007-03-09 08:25:24 +000053{
Denis Vlasenkoc86e0522007-03-20 11:30:28 +000054 unsigned i, out, res;
55 assert(sizeof(unsigned) == 4);
56 if (buflen) {
57 out = 0;
58 for (i = 1000000000; i; i /= 10) {
59 res = n / i;
60 if (res || out || i == 1) {
Denis Vlasenko4b924f32007-05-30 00:29:55 +000061 if (!--buflen) break;
62 out++;
63 n -= res*i;
64 *buf++ = '0' + res;
Denis Vlasenkoc86e0522007-03-20 11:30:28 +000065 }
66 }
Denis Vlasenkoc86e0522007-03-20 11:30:28 +000067 }
Denis Vlasenko10457b92007-03-27 22:01:31 +000068 return buf;
Mike Frysinger67a32ad2007-03-09 08:25:24 +000069}
Denis Vlasenko10457b92007-03-27 22:01:31 +000070static char *itoa_to_buf(int n, char *buf, unsigned buflen)
Mike Frysinger67a32ad2007-03-09 08:25:24 +000071{
Denis Vlasenkoc86e0522007-03-20 11:30:28 +000072 if (buflen && n < 0) {
73 n = -n;
74 *buf++ = '-';
75 buflen--;
76 }
Denis Vlasenko10457b92007-03-27 22:01:31 +000077 return utoa_to_buf((unsigned)n, buf, buflen);
Mike Frysinger67a32ad2007-03-09 08:25:24 +000078}
79static char local_buf[12];
80static char *itoa(int n)
81{
Denis Vlasenko10457b92007-03-27 22:01:31 +000082 *(itoa_to_buf(n, local_buf, sizeof(local_buf))) = '\0';
Denis Vlasenkoc86e0522007-03-20 11:30:28 +000083 return local_buf;
Mike Frysinger67a32ad2007-03-09 08:25:24 +000084}
85#else
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000086# include "busybox.h" /* for applet_names */
Mike Frysinger67a32ad2007-03-09 08:25:24 +000087#endif
Eric Andersenff9eee42001-06-29 04:57:14 +000088
Denis Vlasenko7e497522008-02-12 09:51:03 +000089//#define MSHDEBUG 4
Eric Andersen12de6cf2004-08-04 19:19:10 +000090
91#ifdef MSHDEBUG
Denis Vlasenko509697f2008-03-02 12:49:39 +000092static int mshdbg = MSHDEBUG;
Eric Andersen12de6cf2004-08-04 19:19:10 +000093
Denis Vlasenkoed9d6212008-06-09 07:44:19 +000094#define DBGPRINTF(x) if (mshdbg > 0) printf x
95#define DBGPRINTF0(x) if (mshdbg > 0) printf x
96#define DBGPRINTF1(x) if (mshdbg > 1) printf x
97#define DBGPRINTF2(x) if (mshdbg > 2) printf x
98#define DBGPRINTF3(x) if (mshdbg > 3) printf x
99#define DBGPRINTF4(x) if (mshdbg > 4) printf x
100#define DBGPRINTF5(x) if (mshdbg > 5) printf x
101#define DBGPRINTF6(x) if (mshdbg > 6) printf x
102#define DBGPRINTF7(x) if (mshdbg > 7) printf x
103#define DBGPRINTF8(x) if (mshdbg > 8) printf x
104#define DBGPRINTF9(x) if (mshdbg > 9) printf x
Eric Andersen12de6cf2004-08-04 19:19:10 +0000105
Denis Vlasenko509697f2008-03-02 12:49:39 +0000106static int mshdbg_rc = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +0000107
Denis Vlasenko51742f42007-04-12 00:32:05 +0000108#define RCPRINTF(x) if (mshdbg_rc) printf x
Eric Andersen12de6cf2004-08-04 19:19:10 +0000109
110#else
111
112#define DBGPRINTF(x)
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000113#define DBGPRINTF0(x) ((void)0)
114#define DBGPRINTF1(x) ((void)0)
115#define DBGPRINTF2(x) ((void)0)
116#define DBGPRINTF3(x) ((void)0)
117#define DBGPRINTF4(x) ((void)0)
118#define DBGPRINTF5(x) ((void)0)
119#define DBGPRINTF6(x) ((void)0)
120#define DBGPRINTF7(x) ((void)0)
121#define DBGPRINTF8(x) ((void)0)
122#define DBGPRINTF9(x) ((void)0)
Eric Andersen12de6cf2004-08-04 19:19:10 +0000123
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000124#define RCPRINTF(x) ((void)0)
Eric Andersen12de6cf2004-08-04 19:19:10 +0000125
Denis Vlasenkoed9d6212008-06-09 07:44:19 +0000126#endif /* MSHDEBUG */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000127
128
Denis Vlasenko38f63192007-01-22 09:03:07 +0000129#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
Mike Frysinger2a131752006-06-06 06:26:12 +0000130# define DEFAULT_ROOT_PROMPT "\\u:\\w> "
131# define DEFAULT_USER_PROMPT "\\u:\\w$ "
132#else
133# define DEFAULT_ROOT_PROMPT "# "
134# define DEFAULT_USER_PROMPT "$ "
135#endif
136
137
Eric Andersenff9eee42001-06-29 04:57:14 +0000138/* -------- sh.h -------- */
139/*
140 * shell
141 */
142
Denis Vlasenkoed9d6212008-06-09 07:44:19 +0000143#define LINELIM 2100
144#define NPUSH 8 /* limit to input nesting */
Eric Andersenff9eee42001-06-29 04:57:14 +0000145
Eric Andersen392947c2002-12-11 07:42:46 +0000146#undef NOFILE
Denis Vlasenkoed9d6212008-06-09 07:44:19 +0000147#define NOFILE 20 /* Number of open files */
148#define NUFILE 10 /* Number of user-accessible files */
149#define FDBASE 10 /* First file usable by Shell */
Eric Andersenff9eee42001-06-29 04:57:14 +0000150
151/*
152 * values returned by wait
153 */
Denis Vlasenko5f9468e2007-04-14 13:22:09 +0000154#define WAITSIG(s) ((s) & 0177)
155#define WAITVAL(s) (((s) >> 8) & 0377)
156#define WAITCORE(s) (((s) & 0200) != 0)
Eric Andersenff9eee42001-06-29 04:57:14 +0000157
158/*
Eric Andersenaff114c2004-04-14 17:51:38 +0000159 * library and system definitions
Eric Andersenff9eee42001-06-29 04:57:14 +0000160 */
Denis Vlasenkoed9d6212008-06-09 07:44:19 +0000161typedef void xint; /* base type of jmp_buf, for not broken compilers */
Eric Andersenff9eee42001-06-29 04:57:14 +0000162
163/*
164 * shell components
165 */
Eric Andersenff9eee42001-06-29 04:57:14 +0000166#define NOBLOCK ((struct op *)NULL)
167#define NOWORD ((char *)NULL)
168#define NOWORDS ((char **)NULL)
169#define NOPIPE ((int *)NULL)
170
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000171/*
172 * redirection
173 */
174struct ioword {
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +0000175 smallint io_flag; /* action (below) */
176 int io_fd; /* fd affected */
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000177 char *io_name; /* file name */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000178};
179
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000180#define IOREAD 1 /* < */
181#define IOHERE 2 /* << (here file) */
182#define IOWRITE 4 /* > */
183#define IOCAT 8 /* >> */
184#define IOXHERE 16 /* ${}, ` in << */
185#define IODUP 32 /* >&digit */
186#define IOCLOSE 64 /* >&- */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000187
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +0000188#define IODEFAULT (-1) /* "default" IO fd */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000189
190
Eric Andersenff9eee42001-06-29 04:57:14 +0000191/*
192 * Description of a command or an operation on commands.
193 * Might eventually use a union.
194 */
195struct op {
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +0000196 smallint op_type; /* operation type, see Txxxx below */
Denis Vlasenko509697f2008-03-02 12:49:39 +0000197 char **op_words; /* arguments to a command */
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000198 struct ioword **ioact; /* IO actions (eg, < > >>) */
Eric Andersenff9eee42001-06-29 04:57:14 +0000199 struct op *left;
200 struct op *right;
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000201 char *str; /* identifier for case and for */
Eric Andersenff9eee42001-06-29 04:57:14 +0000202};
203
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000204#define TCOM 1 /* command */
205#define TPAREN 2 /* (c-list) */
206#define TPIPE 3 /* a | b */
207#define TLIST 4 /* a [&;] b */
208#define TOR 5 /* || */
209#define TAND 6 /* && */
210#define TFOR 7
211#define TDO 8
212#define TCASE 9
213#define TIF 10
214#define TWHILE 11
215#define TUNTIL 12
216#define TELIF 13
217#define TPAT 14 /* pattern in case */
218#define TBRACE 15 /* {c-list} */
219#define TASYNC 16 /* c & */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000220/* Added to support "." file expansion */
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000221#define TDOT 17
Eric Andersen12de6cf2004-08-04 19:19:10 +0000222
223/* Strings for names to make debug easier */
"Vladimir N. Oleynik"ac973172005-09-22 14:38:17 +0000224#ifdef MSHDEBUG
Denis Vlasenkoe27f1562007-01-01 06:00:38 +0000225static const char *const T_CMD_NAMES[] = {
Eric Andersen12de6cf2004-08-04 19:19:10 +0000226 "PLACEHOLDER",
227 "TCOM",
228 "TPAREN",
229 "TPIPE",
230 "TLIST",
231 "TOR",
232 "TAND",
233 "TFOR",
234 "TDO",
235 "TCASE",
236 "TIF",
237 "TWHILE",
238 "TUNTIL",
239 "TELIF",
240 "TPAT",
241 "TBRACE",
242 "TASYNC",
243 "TDOT",
244};
"Vladimir N. Oleynik"ac973172005-09-22 14:38:17 +0000245#endif
Eric Andersenff9eee42001-06-29 04:57:14 +0000246
Denis Vlasenko5f9468e2007-04-14 13:22:09 +0000247#define AREASIZE (90000)
Eric Andersen12de6cf2004-08-04 19:19:10 +0000248
Eric Andersenff9eee42001-06-29 04:57:14 +0000249/*
250 * flags to control evaluation of words
251 */
Denis Vlasenko5f9468e2007-04-14 13:22:09 +0000252#define DOSUB 1 /* interpret $, `, and quotes */
253#define DOBLANK 2 /* perform blank interpretation */
254#define DOGLOB 4 /* interpret [?* */
255#define DOKEY 8 /* move words with `=' to 2nd arg. list */
256#define DOTRIM 16 /* trim resulting string */
Eric Andersenff9eee42001-06-29 04:57:14 +0000257
Denis Vlasenko5f9468e2007-04-14 13:22:09 +0000258#define DOALL (DOSUB|DOBLANK|DOGLOB|DOKEY|DOTRIM)
Eric Andersenff9eee42001-06-29 04:57:14 +0000259
Eric Andersenff9eee42001-06-29 04:57:14 +0000260
Eric Andersen8401eea2004-08-04 19:16:54 +0000261struct brkcon {
262 jmp_buf brkpt;
263 struct brkcon *nextlev;
264};
Eric Andersenff9eee42001-06-29 04:57:14 +0000265
Eric Andersen12de6cf2004-08-04 19:19:10 +0000266
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000267static smallint trapset; /* trap pending (signal number) */
Eric Andersenff9eee42001-06-29 04:57:14 +0000268
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000269static smallint yynerrs; /* yacc (flag) */
Eric Andersenff9eee42001-06-29 04:57:14 +0000270
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000271/* moved to G: static char line[LINELIM]; */
Eric Andersenff9eee42001-06-29 04:57:14 +0000272
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000273#if ENABLE_FEATURE_EDITING
274static char *current_prompt;
275static line_input_t *line_input_state;
276#endif
277
Eric Andersen12de6cf2004-08-04 19:19:10 +0000278
Eric Andersenff9eee42001-06-29 04:57:14 +0000279/*
280 * other functions
281 */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000282static const char *rexecve(char *c, char **v, char **envp);
Eric Andersen8401eea2004-08-04 19:16:54 +0000283static char *evalstr(char *cp, int f);
284static char *putn(int n);
Eric Andersen8401eea2004-08-04 19:16:54 +0000285static char *unquote(char *as);
Eric Andersen8401eea2004-08-04 19:16:54 +0000286static int rlookup(char *n);
287static struct wdblock *glob(char *cp, struct wdblock *wb);
288static int my_getc(int ec);
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +0000289static int subgetc(char ec, int quoted);
Eric Andersenfd7a4c82004-09-02 23:13:10 +0000290static char **makenv(int all, struct wdblock *wb);
Eric Andersen8401eea2004-08-04 19:16:54 +0000291static char **eval(char **ap, int f);
292static int setstatus(int s);
293static int waitfor(int lastpid, int canintr);
Eric Andersenff9eee42001-06-29 04:57:14 +0000294
Eric Andersen8401eea2004-08-04 19:16:54 +0000295static void onintr(int s); /* SIGINT handler */
Eric Andersenff9eee42001-06-29 04:57:14 +0000296
Eric Andersen8401eea2004-08-04 19:16:54 +0000297static int newenv(int f);
298static void quitenv(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000299static void next(int f);
300static void setdash(void);
301static void onecommand(void);
302static void runtrap(int i);
Eric Andersenff9eee42001-06-29 04:57:14 +0000303
Eric Andersen12de6cf2004-08-04 19:19:10 +0000304
Eric Andersenff9eee42001-06-29 04:57:14 +0000305/* -------- area stuff -------- */
306
Denis Vlasenko5f9468e2007-04-14 13:22:09 +0000307#define REGSIZE sizeof(struct region)
308#define GROWBY (256)
309/* #define SHRINKBY (64) */
310#undef SHRINKBY
311#define FREE (32767)
312#define BUSY (0)
313#define ALIGN (sizeof(int)-1)
Eric Andersenff9eee42001-06-29 04:57:14 +0000314
315
316struct region {
Eric Andersen8401eea2004-08-04 19:16:54 +0000317 struct region *next;
318 int area;
Eric Andersenff9eee42001-06-29 04:57:14 +0000319};
320
321
Eric Andersenff9eee42001-06-29 04:57:14 +0000322/* -------- grammar stuff -------- */
323typedef union {
Eric Andersen8401eea2004-08-04 19:16:54 +0000324 char *cp;
325 char **wp;
326 int i;
327 struct op *o;
Eric Andersenff9eee42001-06-29 04:57:14 +0000328} YYSTYPE;
Eric Andersen8401eea2004-08-04 19:16:54 +0000329
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000330#define WORD 256
331#define LOGAND 257
332#define LOGOR 258
333#define BREAK 259
334#define IF 260
335#define THEN 261
336#define ELSE 262
337#define ELIF 263
338#define FI 264
339#define CASE 265
340#define ESAC 266
341#define FOR 267
342#define WHILE 268
343#define UNTIL 269
344#define DO 270
345#define DONE 271
346#define IN 272
Eric Andersen12de6cf2004-08-04 19:19:10 +0000347/* Added for "." file expansion */
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000348#define DOT 273
Eric Andersen12de6cf2004-08-04 19:19:10 +0000349
Eric Andersenff9eee42001-06-29 04:57:14 +0000350#define YYERRCODE 300
351
352/* flags to yylex */
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000353#define CONTIN 01 /* skip new lines to complete command */
Eric Andersenff9eee42001-06-29 04:57:14 +0000354
Eric Andersen8401eea2004-08-04 19:16:54 +0000355static struct op *pipeline(int cf);
Eric Andersenff9eee42001-06-29 04:57:14 +0000356static struct op *andor(void);
357static struct op *c_list(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000358static int synio(int cf);
359static void musthave(int c, int cf);
Eric Andersenff9eee42001-06-29 04:57:14 +0000360static struct op *simple(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000361static struct op *nested(int type, int mark);
362static struct op *command(int cf);
363static struct op *dogroup(int onlydone);
Eric Andersenff9eee42001-06-29 04:57:14 +0000364static struct op *thenpart(void);
365static struct op *elsepart(void);
366static struct op *caselist(void);
367static struct op *casepart(void);
368static char **pattern(void);
369static char **wordlist(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000370static struct op *list(struct op *t1, struct op *t2);
371static struct op *block(int type, struct op *t1, struct op *t2, char **wp);
Eric Andersenff9eee42001-06-29 04:57:14 +0000372static struct op *newtp(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000373static struct op *namelist(struct op *t);
Eric Andersenff9eee42001-06-29 04:57:14 +0000374static char **copyw(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000375static void word(char *cp);
Eric Andersenff9eee42001-06-29 04:57:14 +0000376static struct ioword **copyio(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000377static struct ioword *io(int u, int f, char *cp);
Eric Andersen8401eea2004-08-04 19:16:54 +0000378static int yylex(int cf);
379static int collect(int c, int c1);
380static int dual(int c);
381static void diag(int ec);
382static char *tree(unsigned size);
Eric Andersenff9eee42001-06-29 04:57:14 +0000383
384/* -------- var.h -------- */
385
Eric Andersen8401eea2004-08-04 19:16:54 +0000386struct var {
387 char *value;
388 char *name;
389 struct var *next;
390 char status;
Eric Andersenff9eee42001-06-29 04:57:14 +0000391};
Eric Andersenff9eee42001-06-29 04:57:14 +0000392
Eric Andersen8401eea2004-08-04 19:16:54 +0000393#define COPYV 1 /* flag to setval, suggesting copy */
394#define RONLY 01 /* variable is read-only */
395#define EXPORT 02 /* variable is to be exported */
396#define GETCELL 04 /* name & value space was got with getcell */
Eric Andersenff9eee42001-06-29 04:57:14 +0000397
Eric Andersen8401eea2004-08-04 19:16:54 +0000398static int yyparse(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000399
Eric Andersen12de6cf2004-08-04 19:19:10 +0000400
Eric Andersenff9eee42001-06-29 04:57:14 +0000401/* -------- io.h -------- */
402/* io buffer */
403struct iobuf {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000404 unsigned id; /* buffer id */
405 char buf[512]; /* buffer */
406 char *bufp; /* pointer into buffer */
407 char *ebufp; /* pointer to end of buffer */
Eric Andersenff9eee42001-06-29 04:57:14 +0000408};
409
410/* possible arguments to an IO function */
411struct ioarg {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000412 const char *aword;
Eric Andersen8401eea2004-08-04 19:16:54 +0000413 char **awordlist;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000414 int afile; /* file descriptor */
415 unsigned afid; /* buffer id */
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000416 off_t afpos; /* file position */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000417 struct iobuf *afbuf; /* buffer for this file */
Eric Andersenff9eee42001-06-29 04:57:14 +0000418};
Eric Andersen8401eea2004-08-04 19:16:54 +0000419
Eric Andersenff9eee42001-06-29 04:57:14 +0000420/* an input generator's state */
Eric Andersen8401eea2004-08-04 19:16:54 +0000421struct io {
422 int (*iofn) (struct ioarg *, struct io *);
423 struct ioarg *argp;
424 int peekc;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000425 char prev; /* previous character read by readc() */
426 char nlcount; /* for `'s */
427 char xchar; /* for `'s */
428 char task; /* reason for pushed IO */
Eric Andersenff9eee42001-06-29 04:57:14 +0000429};
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000430/* ->task: */
431#define XOTHER 0 /* none of the below */
432#define XDOLL 1 /* expanding ${} */
433#define XGRAVE 2 /* expanding `'s */
434#define XIO 3 /* file IO */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000435
436
437/*
Eric Andersenff9eee42001-06-29 04:57:14 +0000438 * input generators for IO structure
439 */
Eric Andersen8401eea2004-08-04 19:16:54 +0000440static int nlchar(struct ioarg *ap);
441static int strchar(struct ioarg *ap);
442static int qstrchar(struct ioarg *ap);
443static int filechar(struct ioarg *ap);
444static int herechar(struct ioarg *ap);
445static int linechar(struct ioarg *ap);
446static int gravechar(struct ioarg *ap, struct io *iop);
447static int qgravechar(struct ioarg *ap, struct io *iop);
448static int dolchar(struct ioarg *ap);
449static int wdchar(struct ioarg *ap);
450static void scraphere(void);
451static void freehere(int area);
452static void gethere(void);
453static void markhere(char *s, struct ioword *iop);
454static int herein(char *hname, int xdoll);
455static int run(struct ioarg *argp, int (*f) (struct ioarg *));
Eric Andersenff9eee42001-06-29 04:57:14 +0000456
Eric Andersen12de6cf2004-08-04 19:19:10 +0000457
Eric Andersen8401eea2004-08-04 19:16:54 +0000458static int eofc(void);
459static int readc(void);
460static void unget(int c);
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +0000461static void ioecho(char c);
Eric Andersenff9eee42001-06-29 04:57:14 +0000462
Eric Andersen12de6cf2004-08-04 19:19:10 +0000463
Eric Andersenff9eee42001-06-29 04:57:14 +0000464/*
465 * IO control
466 */
Eric Andersen8401eea2004-08-04 19:16:54 +0000467static void pushio(struct ioarg *argp, int (*f) (struct ioarg *));
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000468#define PUSHIO(what,arg,gen) ((temparg.what = (arg)), pushio(&temparg,(gen)))
Eric Andersen8401eea2004-08-04 19:16:54 +0000469static int remap(int fd);
470static int openpipe(int *pv);
471static void closepipe(int *pv);
472static struct io *setbase(struct io *ip);
Eric Andersenff9eee42001-06-29 04:57:14 +0000473
Eric Andersenff9eee42001-06-29 04:57:14 +0000474/* -------- word.h -------- */
475
Eric Andersen8401eea2004-08-04 19:16:54 +0000476#define NSTART 16 /* default number of words to allow for initially */
Eric Andersenff9eee42001-06-29 04:57:14 +0000477
Eric Andersen8401eea2004-08-04 19:16:54 +0000478struct wdblock {
479 short w_bsize;
480 short w_nword;
Eric Andersenff9eee42001-06-29 04:57:14 +0000481 /* bounds are arbitrary */
Eric Andersen8401eea2004-08-04 19:16:54 +0000482 char *w_words[1];
Eric Andersenff9eee42001-06-29 04:57:14 +0000483};
484
Eric Andersen8401eea2004-08-04 19:16:54 +0000485static struct wdblock *addword(char *wd, struct wdblock *wb);
486static struct wdblock *newword(int nw);
487static char **getwords(struct wdblock *wb);
Eric Andersenff9eee42001-06-29 04:57:14 +0000488
Eric Andersenff9eee42001-06-29 04:57:14 +0000489/* -------- misc stuff -------- */
490
Denis Vlasenkofe218832008-03-01 09:35:39 +0000491static int dolabel(struct op *t, char **args);
492static int dohelp(struct op *t, char **args);
493static int dochdir(struct op *t, char **args);
494static int doshift(struct op *t, char **args);
495static int dologin(struct op *t, char **args);
496static int doumask(struct op *t, char **args);
497static int doexec(struct op *t, char **args);
498static int dodot(struct op *t, char **args);
499static int dowait(struct op *t, char **args);
500static int doread(struct op *t, char **args);
501static int doeval(struct op *t, char **args);
502static int dotrap(struct op *t, char **args);
503static int dobreak(struct op *t, char **args);
504static int doexit(struct op *t, char **args);
505static int doexport(struct op *t, char **args);
506static int doreadonly(struct op *t, char **args);
507static int doset(struct op *t, char **args);
508static int dotimes(struct op *t, char **args);
509static int docontinue(struct op *t, char **args);
510
Denis Vlasenko7e497522008-02-12 09:51:03 +0000511static int forkexec(struct op *t, int *pin, int *pout, int no_fork, char **wp);
512static int execute(struct op *t, int *pin, int *pout, int no_fork);
Eric Andersen8401eea2004-08-04 19:16:54 +0000513static int iosetup(struct ioword *iop, int pipein, int pipeout);
Eric Andersen8401eea2004-08-04 19:16:54 +0000514static void brkset(struct brkcon *bc);
Eric Andersen8401eea2004-08-04 19:16:54 +0000515static int getsig(char *s);
516static void setsig(int n, sighandler_t f);
517static int getn(char *as);
Eric Andersen8401eea2004-08-04 19:16:54 +0000518static int brkcontin(char *cp, int val);
Eric Andersen8401eea2004-08-04 19:16:54 +0000519static void rdexp(char **wp, void (*f) (struct var *), int key);
520static void badid(char *s);
Eric Andersen8401eea2004-08-04 19:16:54 +0000521static void varput(char *s, int out);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000522static int expand(const char *cp, struct wdblock **wbp, int f);
Eric Andersen8401eea2004-08-04 19:16:54 +0000523static char *blank(int f);
524static int dollar(int quoted);
525static int grave(int quoted);
526static void globname(char *we, char *pp);
527static char *generate(char *start1, char *end1, char *middle, char *end);
528static int anyspcl(struct wdblock *wb);
Eric Andersen8401eea2004-08-04 19:16:54 +0000529static void readhere(char **name, char *s, int ec);
Eric Andersen8401eea2004-08-04 19:16:54 +0000530static int xxchar(struct ioarg *ap);
Eric Andersenff9eee42001-06-29 04:57:14 +0000531
Eric Andersen8401eea2004-08-04 19:16:54 +0000532struct here {
533 char *h_tag;
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000534 char h_dosub;
Eric Andersen8401eea2004-08-04 19:16:54 +0000535 struct ioword *h_iop;
536 struct here *h_next;
Eric Andersenff9eee42001-06-29 04:57:14 +0000537};
538
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000539static const char *const signame[] = {
Eric Andersenff9eee42001-06-29 04:57:14 +0000540 "Signal 0",
541 "Hangup",
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000542 NULL, /* interrupt */
Eric Andersenff9eee42001-06-29 04:57:14 +0000543 "Quit",
544 "Illegal instruction",
545 "Trace/BPT trap",
546 "Abort",
547 "Bus error",
548 "Floating Point Exception",
549 "Killed",
550 "SIGUSR1",
551 "SIGSEGV",
552 "SIGUSR2",
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000553 NULL, /* broken pipe */
Eric Andersenff9eee42001-06-29 04:57:14 +0000554 "Alarm clock",
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000555 "Terminated"
Eric Andersenff9eee42001-06-29 04:57:14 +0000556};
Eric Andersen8401eea2004-08-04 19:16:54 +0000557
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000558
Denis Vlasenkofe218832008-03-01 09:35:39 +0000559typedef int (*builtin_func_ptr)(struct op *, char **);
Denis Vlasenko7e497522008-02-12 09:51:03 +0000560
Eric Andersen1c039232001-07-07 00:05:55 +0000561struct builtincmd {
562 const char *name;
Denis Vlasenko7e497522008-02-12 09:51:03 +0000563 builtin_func_ptr builtinfunc;
Eric Andersenff9eee42001-06-29 04:57:14 +0000564};
Denis Vlasenko7e497522008-02-12 09:51:03 +0000565
Eric Andersen8401eea2004-08-04 19:16:54 +0000566static const struct builtincmd builtincmds[] = {
Denis Vlasenko95cb3262007-04-09 03:06:34 +0000567 { "." , dodot },
568 { ":" , dolabel },
569 { "break" , dobreak },
570 { "cd" , dochdir },
571 { "continue", docontinue },
572 { "eval" , doeval },
573 { "exec" , doexec },
574 { "exit" , doexit },
575 { "export" , doexport },
576 { "help" , dohelp },
577 { "login" , dologin },
578 { "newgrp" , dologin },
579 { "read" , doread },
580 { "readonly", doreadonly },
581 { "set" , doset },
582 { "shift" , doshift },
583 { "times" , dotimes },
584 { "trap" , dotrap },
585 { "umask" , doumask },
586 { "wait" , dowait },
587 { NULL , NULL },
Eric Andersenff9eee42001-06-29 04:57:14 +0000588};
589
Denis Vlasenko68404f12008-03-17 09:00:54 +0000590static struct op *dowholefile(int /*, int*/);
Eric Andersen12de6cf2004-08-04 19:19:10 +0000591
Eric Andersen12de6cf2004-08-04 19:19:10 +0000592
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000593/* Globals */
Eric Andersen8401eea2004-08-04 19:16:54 +0000594static char **dolv;
595static int dolc;
Denis Vlasenko447bd662008-05-30 22:28:32 +0000596static uint8_t exstat;
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000597static smallint gflg; /* (seems to be a parse error indicator) */
598static smallint interactive; /* Is this an interactive shell */
599static smallint execflg;
600static smallint isbreak; /* "break" statement was seen */
601static int multiline; /* '\n' changed to ';' (counter) */
602static struct op *outtree; /* result from parser */
Eric Andersen8401eea2004-08-04 19:16:54 +0000603static xint *failpt;
604static xint *errpt;
605static struct brkcon *brklist;
Eric Andersen8401eea2004-08-04 19:16:54 +0000606static struct wdblock *wdlist;
607static struct wdblock *iolist;
Eric Andersen12de6cf2004-08-04 19:19:10 +0000608
609#ifdef MSHDEBUG
610static struct var *mshdbg_var;
611#endif
Eric Andersen8401eea2004-08-04 19:16:54 +0000612static struct var *vlist; /* dictionary */
613static struct var *homedir; /* home directory */
614static struct var *prompt; /* main prompt */
615static struct var *cprompt; /* continuation prompt */
616static struct var *path; /* search path for commands */
617static struct var *shell; /* shell to interpret command files */
618static struct var *ifs; /* field separators */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000619
Denis Vlasenko95cb3262007-04-09 03:06:34 +0000620static int areanum; /* current allocation area */
Denis Vlasenko648b44f2008-02-12 06:04:06 +0000621static smallint intr; /* interrupt pending (bool) */
622static smallint heedint = 1; /* heed interrupt signals (bool) */
Eric Andersen8401eea2004-08-04 19:16:54 +0000623static int inparse;
Denis Vlasenko95cb3262007-04-09 03:06:34 +0000624static char *null = (char*)""; /* null value for variable */
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +0000625static void (*qflag)(int) = SIG_IGN;
Eric Andersen8401eea2004-08-04 19:16:54 +0000626static int startl;
627static int peeksym;
628static int nlseen;
629static int iounit = IODEFAULT;
630static YYSTYPE yylval;
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000631static char *elinep; /* done in main(): = line + sizeof(line) - 5 */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000632
Denis Vlasenko00ccf952007-02-01 01:39:24 +0000633static struct here *inhere; /* list of hear docs while parsing */
634static struct here *acthere; /* list of active here documents */
635static struct region *areabot; /* bottom of area */
636static struct region *areatop; /* top of area */
637static struct region *areanxt; /* starting point of scan */
Eric Andersen8401eea2004-08-04 19:16:54 +0000638static void *brktop;
639static void *brkaddr;
Eric Andersenff9eee42001-06-29 04:57:14 +0000640
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000641#define AFID_NOBUF (~0)
642#define AFID_ID 0
643
644
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000645/*
646 * parsing & execution environment
647 */
648struct env {
649 char *linep;
650 struct io *iobase;
651 struct io *iop;
652 xint *errpt; /* void * */
653 int iofd;
654 struct env *oenv;
655};
656
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000657
658struct globals {
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000659 struct env global_env;
660 struct ioarg temparg; // = { .afid = AFID_NOBUF }; /* temporary for PUSHIO */
661 unsigned bufid; // = AFID_ID; /* buffer id counter */
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000662 char ourtrap[_NSIG + 1];
663 char *trap[_NSIG + 1];
664 struct iobuf sharedbuf; /* in main(): set to { AFID_NOBUF } */
665 struct iobuf mainbuf; /* in main(): set to { AFID_NOBUF } */
666 struct ioarg ioargstack[NPUSH];
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000667 /*
668 * flags:
669 * -e: quit on error
670 * -k: look for name=value everywhere on command line
671 * -n: no execution
672 * -t: exit after reading and executing one command
673 * -v: echo as read
674 * -x: trace
675 * -u: unset variables net diagnostic
676 */
677 char flags['z' - 'a' + 1];
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000678 char filechar_cmdbuf[BUFSIZ];
679 char line[LINELIM];
680 char child_cmd[LINELIM];
Denis Vlasenkoab801872007-12-02 08:35:37 +0000681
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000682 struct io iostack[NPUSH];
683
Denis Vlasenkoab801872007-12-02 08:35:37 +0000684 char grave__var_name[LINELIM];
685 char grave__alt_value[LINELIM];
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000686};
687
688#define G (*ptr_to_globals)
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000689#define global_env (G.global_env )
690#define temparg (G.temparg )
691#define bufid (G.bufid )
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000692#define ourtrap (G.ourtrap )
693#define trap (G.trap )
694#define sharedbuf (G.sharedbuf )
695#define mainbuf (G.mainbuf )
696#define ioargstack (G.ioargstack )
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000697/* this looks weird, but is OK ... we index FLAG with 'a'...'z' */
698#define FLAG (G.flags - 'a' )
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000699#define filechar_cmdbuf (G.filechar_cmdbuf)
700#define line (G.line )
701#define child_cmd (G.child_cmd )
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000702#define iostack (G.iostack )
Denis Vlasenkoab801872007-12-02 08:35:37 +0000703#define INIT_G() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000704 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000705 global_env.linep = line; \
706 global_env.iobase = iostack; \
707 global_env.iop = iostack - 1; \
708 global_env.iofd = FDBASE; \
709 temparg.afid = AFID_NOBUF; \
710 bufid = AFID_ID; \
Denis Vlasenkoab801872007-12-02 08:35:37 +0000711} while (0)
Denis Vlasenko55f30b02007-03-24 22:42:29 +0000712
713
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000714/* in substitution */
715#define INSUB() (global_env.iop->task == XGRAVE || global_env.iop->task == XDOLL)
716
717#define RUN(what, arg, gen) ((temparg.what = (arg)), run(&temparg, (gen)))
718
Eric Andersen12de6cf2004-08-04 19:19:10 +0000719#ifdef MSHDEBUG
Denis Vlasenko509697f2008-03-02 12:49:39 +0000720static void print_tree(struct op *head)
Eric Andersen12de6cf2004-08-04 19:19:10 +0000721{
722 if (head == NULL) {
723 DBGPRINTF(("PRINT_TREE: no tree\n"));
724 return;
725 }
726
Denis Vlasenkoed9d6212008-06-09 07:44:19 +0000727 DBGPRINTF(("NODE: %p, left %p, right %p\n", head, head->left,
Eric Andersen12de6cf2004-08-04 19:19:10 +0000728 head->right));
729
730 if (head->left)
731 print_tree(head->left);
732
733 if (head->right)
734 print_tree(head->right);
Eric Andersen12de6cf2004-08-04 19:19:10 +0000735}
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000736#endif /* MSHDEBUG */
737
738
739/*
740 * IO functions
741 */
742static void prs(const char *s)
743{
744 if (*s)
Denis Vlasenko73c571a2009-03-09 00:12:37 +0000745 xwrite_str(STDERR_FILENO, s);
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000746}
747
748static void prn(unsigned u)
749{
750 prs(itoa(u));
751}
752
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000753static void echo(char **wp)
754{
755 int i;
756
757 prs("+");
758 for (i = 0; wp[i]; i++) {
759 if (i)
760 prs(" ");
761 prs(wp[i]);
762 }
763 prs("\n");
764}
765
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000766static void closef(int i)
767{
768 if (i > 2)
769 close(i);
770}
771
772static void closeall(void)
773{
774 int u;
775
776 for (u = NUFILE; u < NOFILE;)
777 close(u++);
778}
Eric Andersen12de6cf2004-08-04 19:19:10 +0000779
Eric Andersenff9eee42001-06-29 04:57:14 +0000780
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000781/* fail but return to process next command */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000782static void fail(void) NORETURN;
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000783static void fail(void)
784{
785 longjmp(failpt, 1);
786 /* NOTREACHED */
787}
Eric Andersenff9eee42001-06-29 04:57:14 +0000788
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000789/* abort shell (or fail in subshell) */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000790static void leave(void) NORETURN;
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000791static void leave(void)
792{
793 DBGPRINTF(("LEAVE: leave called!\n"));
794
795 if (execflg)
796 fail();
797 scraphere();
798 freehere(1);
799 runtrap(0);
800 _exit(exstat);
801 /* NOTREACHED */
802}
803
804static void warn(const char *s)
805{
806 if (*s) {
807 prs(s);
Denis Vlasenko447bd662008-05-30 22:28:32 +0000808 if (!exstat)
809 exstat = 255;
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000810 }
811 prs("\n");
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +0000812 if (FLAG['e'])
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000813 leave();
814}
815
816static void err(const char *s)
817{
818 warn(s);
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +0000819 if (FLAG['n'])
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000820 return;
821 if (!interactive)
822 leave();
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000823 if (global_env.errpt)
824 longjmp(global_env.errpt, 1);
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000825 closeall();
Denis Vlasenkoc794c512007-12-16 17:21:29 +0000826 global_env.iop = global_env.iobase = iostack;
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000827}
828
Denis Vlasenko6b50f732007-02-01 01:43:39 +0000829
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000830/* -------- area.c -------- */
831
Eric Andersenff9eee42001-06-29 04:57:14 +0000832/*
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000833 * All memory between (char *)areabot and (char *)(areatop+1) is
834 * exclusively administered by the area management routines.
835 * It is assumed that sbrk() and brk() manipulate the high end.
Eric Andersenff9eee42001-06-29 04:57:14 +0000836 */
837
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000838#define sbrk(X) ({ \
839 void * __q = (void *)-1; \
840 if (brkaddr + (int)(X) < brktop) { \
841 __q = brkaddr; \
842 brkaddr += (int)(X); \
843 } \
844 __q; \
845})
Eric Andersenff9eee42001-06-29 04:57:14 +0000846
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000847static void initarea(void)
Eric Andersenff9eee42001-06-29 04:57:14 +0000848{
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000849 brkaddr = xmalloc(AREASIZE);
850 brktop = brkaddr + AREASIZE;
Eric Andersenff9eee42001-06-29 04:57:14 +0000851
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000852 while ((long) sbrk(0) & ALIGN)
853 sbrk(1);
854 areabot = (struct region *) sbrk(REGSIZE);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +0000855
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000856 areabot->next = areabot;
857 areabot->area = BUSY;
858 areatop = areabot;
859 areanxt = areabot;
Eric Andersenff9eee42001-06-29 04:57:14 +0000860}
861
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000862static char *getcell(unsigned nbytes)
863{
864 int nregio;
865 struct region *p, *q;
866 int i;
867
868 if (nbytes == 0) {
869 puts("getcell(0)");
870 abort();
871 }
872 /* silly and defeats the algorithm */
873 /*
874 * round upwards and add administration area
875 */
876 nregio = (nbytes + (REGSIZE - 1)) / REGSIZE + 1;
877 p = areanxt;
878 for (;;) {
879 if (p->area > areanum) {
880 /*
881 * merge free cells
882 */
883 while ((q = p->next)->area > areanum && q != areanxt)
884 p->next = q->next;
885 /*
886 * exit loop if cell big enough
887 */
888 if (q >= p + nregio)
889 goto found;
890 }
891 p = p->next;
892 if (p == areanxt)
893 break;
894 }
895 i = nregio >= GROWBY ? nregio : GROWBY;
896 p = (struct region *) sbrk(i * REGSIZE);
897 if (p == (struct region *) -1)
898 return NULL;
899 p--;
900 if (p != areatop) {
901 puts("not contig");
902 abort(); /* allocated areas are contiguous */
903 }
904 q = p + i;
905 p->next = q;
906 p->area = FREE;
907 q->next = areabot;
908 q->area = BUSY;
909 areatop = q;
910 found:
911 /*
912 * we found a FREE area big enough, pointed to by 'p', and up to 'q'
913 */
914 areanxt = p + nregio;
915 if (areanxt < q) {
916 /*
917 * split into requested area and rest
918 */
919 if (areanxt + 1 > q) {
920 puts("OOM");
921 abort(); /* insufficient space left for admin */
922 }
923 areanxt->next = q;
924 areanxt->area = FREE;
925 p->next = areanxt;
926 }
927 p->area = areanum;
928 return (char *) (p + 1);
929}
930
931static void freecell(char *cp)
932{
933 struct region *p;
934
935 p = (struct region *) cp;
936 if (p != NULL) {
937 p--;
938 if (p < areanxt)
939 areanxt = p;
940 p->area = FREE;
941 }
942}
943#define DELETE(obj) freecell((char *)obj)
944
945static void freearea(int a)
946{
947 struct region *p, *top;
948
949 top = areatop;
950 for (p = areabot; p != top; p = p->next)
951 if (p->area >= a)
952 p->area = FREE;
953}
954
955static void setarea(char *cp, int a)
956{
957 struct region *p;
958
959 p = (struct region *) cp;
960 if (p != NULL)
961 (p - 1)->area = a;
962}
963
964static int getarea(char *cp)
965{
966 return ((struct region *) cp - 1)->area;
967}
968
969static void garbage(void)
970{
971 struct region *p, *q, *top;
972
973 top = areatop;
974 for (p = areabot; p != top; p = p->next) {
975 if (p->area > areanum) {
976 while ((q = p->next)->area > areanum)
977 p->next = q->next;
978 areanxt = p;
979 }
980 }
981#ifdef SHRINKBY
982 if (areatop >= q + SHRINKBY && q->area > areanum) {
983 brk((char *) (q + 1));
984 q->next = areabot;
985 q->area = BUSY;
986 areatop = q;
987 }
988#endif
989}
990
Denis Vlasenko509697f2008-03-02 12:49:39 +0000991static void *get_space(int n)
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000992{
993 char *cp;
994
995 cp = getcell(n);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +0000996 if (cp == NULL)
Denis Vlasenko489f93e2007-02-01 01:43:16 +0000997 err("out of string space");
998 return cp;
999}
1000
1001static char *strsave(const char *s, int a)
1002{
1003 char *cp;
1004
Denis Vlasenko509697f2008-03-02 12:49:39 +00001005 cp = get_space(strlen(s) + 1);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001006 if (cp == NULL) {
1007// FIXME: I highly doubt this is good.
1008 return (char*)"";
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001009 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001010 setarea(cp, a);
1011 strcpy(cp, s);
1012 return cp;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001013}
1014
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001015
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001016/* -------- var.c -------- */
1017
1018static int eqname(const char *n1, const char *n2)
1019{
1020 for (; *n1 != '=' && *n1 != '\0'; n1++)
1021 if (*n2++ != *n1)
1022 return 0;
1023 return *n2 == '\0' || *n2 == '=';
1024}
1025
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001026static const char *findeq(const char *cp)
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001027{
1028 while (*cp != '\0' && *cp != '=')
1029 cp++;
1030 return cp;
1031}
1032
1033/*
1034 * Find the given name in the dictionary
1035 * and return its value. If the name was
1036 * not previously there, enter it now and
1037 * return a null value.
1038 */
1039static struct var *lookup(const char *n)
1040{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001041// FIXME: dirty hack
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001042 static struct var dummy;
1043
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001044 struct var *vp;
1045 const char *cp;
1046 char *xp;
1047 int c;
1048
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001049 if (isdigit(*n)) {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001050 dummy.name = (char*)n;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001051 for (c = 0; isdigit(*n) && c < 1000; n++)
1052 c = c * 10 + *n - '0';
1053 dummy.status = RONLY;
1054 dummy.value = (c <= dolc ? dolv[c] : null);
1055 return &dummy;
1056 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001057
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001058 for (vp = vlist; vp; vp = vp->next)
1059 if (eqname(vp->name, n))
1060 return vp;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001061
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001062 cp = findeq(n);
Denis Vlasenko509697f2008-03-02 12:49:39 +00001063 vp = get_space(sizeof(*vp));
1064 if (vp == 0 || (vp->name = get_space((int) (cp - n) + 2)) == NULL) {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001065 dummy.name = dummy.value = (char*)"";
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001066 return &dummy;
1067 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001068
1069 xp = vp->name;
1070 while ((*xp = *n++) != '\0' && *xp != '=')
1071 xp++;
1072 *xp++ = '=';
1073 *xp = '\0';
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001074 setarea((char *) vp, 0);
1075 setarea((char *) vp->name, 0);
1076 vp->value = null;
1077 vp->next = vlist;
1078 vp->status = GETCELL;
1079 vlist = vp;
1080 return vp;
1081}
1082
1083/*
1084 * if name is not NULL, it must be
1085 * a prefix of the space `val',
1086 * and end with `='.
1087 * this is all so that exporting
1088 * values is reasonably painless.
1089 */
1090static void nameval(struct var *vp, const char *val, const char *name)
1091{
1092 const char *cp;
1093 char *xp;
1094 int fl;
1095
1096 if (vp->status & RONLY) {
1097 xp = vp->name;
1098 while (*xp && *xp != '=')
Denis Vlasenko4daad902007-09-27 10:20:47 +00001099 fputc(*xp++, stderr);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001100 err(" is read-only");
1101 return;
1102 }
1103 fl = 0;
1104 if (name == NULL) {
Denis Vlasenko509697f2008-03-02 12:49:39 +00001105 xp = get_space(strlen(vp->name) + strlen(val) + 2);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001106 if (xp == NULL)
1107 return;
1108 /* make string: name=value */
1109 setarea(xp, 0);
1110 name = xp;
1111 cp = vp->name;
1112 while ((*xp = *cp++) != '\0' && *xp != '=')
1113 xp++;
1114 *xp++ = '=';
1115 strcpy(xp, val);
1116 val = xp;
1117 fl = GETCELL;
1118 }
1119 if (vp->status & GETCELL)
1120 freecell(vp->name); /* form new string `name=value' */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001121 vp->name = (char*)name;
1122 vp->value = (char*)val;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001123 vp->status |= fl;
1124}
1125
1126/*
1127 * give variable at `vp' the value `val'.
1128 */
1129static void setval(struct var *vp, const char *val)
1130{
1131 nameval(vp, val, NULL);
1132}
1133
1134static void export(struct var *vp)
1135{
1136 vp->status |= EXPORT;
1137}
1138
1139static void ronly(struct var *vp)
1140{
1141 if (isalpha(vp->name[0]) || vp->name[0] == '_') /* not an internal symbol */
1142 vp->status |= RONLY;
1143}
1144
1145static int isassign(const char *s)
1146{
1147 unsigned char c;
1148 DBGPRINTF7(("ISASSIGN: enter, s=%s\n", s));
1149
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001150 c = *s;
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001151 /* no isalpha() - we shouldn't use locale */
1152 /* c | 0x20 - lowercase (Latin) letters */
1153 if (c != '_' && (unsigned)((c|0x20) - 'a') > 25)
1154 /* not letter */
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001155 return 0;
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001156
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001157 while (1) {
1158 c = *++s;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001159 if (c == '=')
1160 return 1;
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001161 if (c == '\0')
1162 return 0;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001163 if (c != '_'
1164 && (unsigned)(c - '0') > 9 /* not number */
Denis Vlasenko5b27fbe2007-03-24 14:06:51 +00001165 && (unsigned)((c|0x20) - 'a') > 25 /* not letter */
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001166 ) {
1167 return 0;
1168 }
1169 }
1170}
1171
1172static int assign(const char *s, int cf)
1173{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001174 const char *cp;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001175 struct var *vp;
1176
1177 DBGPRINTF7(("ASSIGN: enter, s=%s, cf=%d\n", s, cf));
1178
1179 if (!isalpha(*s) && *s != '_')
1180 return 0;
1181 for (cp = s; *cp != '='; cp++)
1182 if (*cp == '\0' || (!isalnum(*cp) && *cp != '_'))
1183 return 0;
1184 vp = lookup(s);
1185 nameval(vp, ++cp, cf == COPYV ? NULL : s);
1186 if (cf != COPYV)
1187 vp->status &= ~GETCELL;
1188 return 1;
1189}
1190
1191static int checkname(char *cp)
1192{
1193 DBGPRINTF7(("CHECKNAME: enter, cp=%s\n", cp));
1194
1195 if (!isalpha(*cp++) && *(cp - 1) != '_')
1196 return 0;
1197 while (*cp)
1198 if (!isalnum(*cp++) && *(cp - 1) != '_')
1199 return 0;
1200 return 1;
1201}
1202
1203static void putvlist(int f, int out)
1204{
1205 struct var *vp;
1206
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001207 for (vp = vlist; vp; vp = vp->next) {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001208 if (vp->status & f && (isalpha(*vp->name) || *vp->name == '_')) {
1209 if (vp->status & EXPORT)
1210 write(out, "export ", 7);
1211 if (vp->status & RONLY)
1212 write(out, "readonly ", 9);
1213 write(out, vp->name, (int) (findeq(vp->name) - vp->name));
1214 write(out, "\n", 1);
1215 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001216 }
Denis Vlasenko489f93e2007-02-01 01:43:16 +00001217}
1218
1219
1220/*
1221 * trap handling
1222 */
1223static void sig(int i)
1224{
1225 trapset = i;
1226 signal(i, sig);
1227}
1228
1229static void runtrap(int i)
1230{
1231 char *trapstr;
1232
1233 trapstr = trap[i];
1234 if (trapstr == NULL)
1235 return;
1236
1237 if (i == 0)
1238 trap[i] = NULL;
1239
1240 RUN(aword, trapstr, nlchar);
1241}
1242
1243
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001244static void setdash(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001245{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001246 char *cp;
1247 int c;
Eric Andersen8401eea2004-08-04 19:16:54 +00001248 char m['z' - 'a' + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00001249
1250 cp = m;
Eric Andersen8401eea2004-08-04 19:16:54 +00001251 for (c = 'a'; c <= 'z'; c++)
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00001252 if (FLAG[c])
Eric Andersenff9eee42001-06-29 04:57:14 +00001253 *cp++ = c;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001254 *cp = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00001255 setval(lookup("-"), m);
1256}
1257
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001258static int newfile(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00001259{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001260 int f;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001261
1262 DBGPRINTF7(("NEWFILE: opening %s\n", s));
Eric Andersenff9eee42001-06-29 04:57:14 +00001263
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001264 f = 0;
Denis Vlasenko9f739442006-12-16 23:49:13 +00001265 if (NOT_LONE_DASH(s)) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001266 DBGPRINTF(("NEWFILE: s is %s\n", s));
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00001267 f = open(s, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00001268 if (f < 0) {
1269 prs(s);
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00001270 err(": can't open");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001271 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001272 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001273 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001274
Eric Andersenff9eee42001-06-29 04:57:14 +00001275 next(remap(f));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001276 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001277}
1278
Eric Andersen12de6cf2004-08-04 19:19:10 +00001279
Denis Vlasenkobc1918a2008-04-15 01:17:50 +00001280#ifdef UNUSED
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001281struct op *scantree(struct op *head)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001282{
1283 struct op *dotnode;
1284
1285 if (head == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001286 return NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001287
1288 if (head->left != NULL) {
1289 dotnode = scantree(head->left);
1290 if (dotnode)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001291 return dotnode;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001292 }
1293
1294 if (head->right != NULL) {
1295 dotnode = scantree(head->right);
1296 if (dotnode)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001297 return dotnode;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001298 }
1299
Denis Vlasenko509697f2008-03-02 12:49:39 +00001300 if (head->op_words == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001301 return NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001302
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001303 DBGPRINTF5(("SCANTREE: checking node %p\n", head));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001304
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001305 if ((head->op_type != TDOT) && LONE_CHAR(head->op_words[0], '.')) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001306 DBGPRINTF5(("SCANTREE: dot found in node %p\n", head));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001307 return head;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001308 }
1309
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001310 return NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001311}
Denis Vlasenkobc1918a2008-04-15 01:17:50 +00001312#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00001313
1314
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001315static void onecommand(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001316{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001317 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00001318 jmp_buf m1;
1319
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001320 DBGPRINTF(("ONECOMMAND: enter, outtree=%p\n", outtree));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001321
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001322 while (global_env.oenv)
Eric Andersenff9eee42001-06-29 04:57:14 +00001323 quitenv();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001324
Eric Andersenff9eee42001-06-29 04:57:14 +00001325 areanum = 1;
1326 freehere(areanum);
1327 freearea(areanum);
1328 garbage();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001329 wdlist = NULL;
1330 iolist = NULL;
1331 global_env.errpt = NULL;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001332 global_env.linep = line;
Eric Andersenff9eee42001-06-29 04:57:14 +00001333 yynerrs = 0;
1334 multiline = 0;
1335 inparse = 1;
1336 intr = 0;
1337 execflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001338
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001339 failpt = m1;
1340 setjmp(failpt); /* Bruce Evans' fix */
1341 failpt = m1;
1342 if (setjmp(failpt) || yyparse() || intr) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001343 DBGPRINTF(("ONECOMMAND: this is not good.\n"));
1344
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001345 while (global_env.oenv)
Eric Andersenff9eee42001-06-29 04:57:14 +00001346 quitenv();
1347 scraphere();
1348 if (!interactive && intr)
1349 leave();
1350 inparse = 0;
1351 intr = 0;
1352 return;
1353 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001354
Eric Andersenff9eee42001-06-29 04:57:14 +00001355 inparse = 0;
1356 brklist = 0;
1357 intr = 0;
1358 execflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001359
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00001360 if (!FLAG['n']) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001361 DBGPRINTF(("ONECOMMAND: calling execute, t=outtree=%p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00001362 outtree));
Denis Vlasenko7e497522008-02-12 09:51:03 +00001363 execute(outtree, NOPIPE, NOPIPE, /* no_fork: */ 0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001364 }
1365
Eric Andersenff9eee42001-06-29 04:57:14 +00001366 if (!interactive && intr) {
1367 execflg = 0;
1368 leave();
1369 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001370
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001371 i = trapset;
1372 if (i != 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001373 trapset = 0;
1374 runtrap(i);
1375 }
1376}
1377
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001378static int newenv(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00001379{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001380 struct env *ep;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001381
1382 DBGPRINTF(("NEWENV: f=%d (indicates quitenv and return)\n", f));
Eric Andersenff9eee42001-06-29 04:57:14 +00001383
1384 if (f) {
1385 quitenv();
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001386 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001387 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001388
Denis Vlasenko509697f2008-03-02 12:49:39 +00001389 ep = get_space(sizeof(*ep));
Eric Andersenff9eee42001-06-29 04:57:14 +00001390 if (ep == NULL) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001391 while (global_env.oenv)
Eric Andersenff9eee42001-06-29 04:57:14 +00001392 quitenv();
1393 fail();
1394 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001395 *ep = global_env;
1396 global_env.oenv = ep;
1397 global_env.errpt = errpt;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001398
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001399 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001400}
1401
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001402static void quitenv(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001403{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001404 struct env *ep;
1405 int fd;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001406
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001407 DBGPRINTF(("QUITENV: global_env.oenv=%p\n", global_env.oenv));
Eric Andersenff9eee42001-06-29 04:57:14 +00001408
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001409 ep = global_env.oenv;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001410 if (ep != NULL) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001411 fd = global_env.iofd;
1412 global_env = *ep;
Eric Andersenff9eee42001-06-29 04:57:14 +00001413 /* should close `'d files */
1414 DELETE(ep);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001415 while (--fd >= global_env.iofd)
Eric Andersenff9eee42001-06-29 04:57:14 +00001416 close(fd);
1417 }
1418}
1419
1420/*
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001421 * Is character c in s?
Eric Andersenff9eee42001-06-29 04:57:14 +00001422 */
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001423static int any(int c, const char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00001424{
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001425 while (*s)
1426 if (*s++ == c)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001427 return 1;
1428 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001429}
1430
1431/*
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001432 * Is any character from s1 in s2?
Eric Andersenff9eee42001-06-29 04:57:14 +00001433 */
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001434static int anys(const char *s1, const char *s2)
Eric Andersenff9eee42001-06-29 04:57:14 +00001435{
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +00001436 while (*s1)
1437 if (any(*s1++, s2))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001438 return 1;
1439 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001440}
1441
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001442static char *putn(int n)
Eric Andersenff9eee42001-06-29 04:57:14 +00001443{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001444 return itoa(n);
Eric Andersenff9eee42001-06-29 04:57:14 +00001445}
1446
Eric Andersen8401eea2004-08-04 19:16:54 +00001447static void next(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00001448{
1449 PUSHIO(afile, f, filechar);
1450}
1451
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001452static void onintr(int s UNUSED_PARAM) /* ANSI C requires a parameter */
Eric Andersenff9eee42001-06-29 04:57:14 +00001453{
1454 signal(SIGINT, onintr);
1455 intr = 1;
1456 if (interactive) {
1457 if (inparse) {
1458 prs("\n");
1459 fail();
1460 }
Eric Andersen8401eea2004-08-04 19:16:54 +00001461 } else if (heedint) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001462 execflg = 0;
1463 leave();
1464 }
1465}
1466
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001467
Eric Andersenff9eee42001-06-29 04:57:14 +00001468/* -------- gmatch.c -------- */
1469/*
1470 * int gmatch(string, pattern)
1471 * char *string, *pattern;
1472 *
1473 * Match a pattern as in sh(1).
1474 */
1475
1476#define CMASK 0377
1477#define QUOTE 0200
Denis Vlasenko55f30b02007-03-24 22:42:29 +00001478#define QMASK (CMASK & ~QUOTE)
Eric Andersen8401eea2004-08-04 19:16:54 +00001479#define NOT '!' /* might use ^ */
Eric Andersenff9eee42001-06-29 04:57:14 +00001480
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001481static const char *cclass(const char *p, int sub)
1482{
1483 int c, d, not, found;
1484
1485 not = (*p == NOT);
1486 if (not != 0)
1487 p++;
1488 found = not;
1489 do {
1490 if (*p == '\0')
1491 return NULL;
1492 c = *p & CMASK;
1493 if (p[1] == '-' && p[2] != ']') {
1494 d = p[2] & CMASK;
1495 p++;
1496 } else
1497 d = c;
1498 if (c == sub || (c <= sub && sub <= d))
1499 found = !not;
1500 } while (*++p != ']');
1501 return found ? p + 1 : NULL;
1502}
1503
1504static int gmatch(const char *s, const char *p)
Eric Andersenff9eee42001-06-29 04:57:14 +00001505{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001506 int sc, pc;
Eric Andersenff9eee42001-06-29 04:57:14 +00001507
1508 if (s == NULL || p == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001509 return 0;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00001510
Eric Andersenff9eee42001-06-29 04:57:14 +00001511 while ((pc = *p++ & CMASK) != '\0') {
1512 sc = *s++ & QMASK;
1513 switch (pc) {
1514 case '[':
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001515 p = cclass(p, sc);
1516 if (p == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001517 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001518 break;
1519
1520 case '?':
1521 if (sc == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001522 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001523 break;
1524
1525 case '*':
1526 s--;
1527 do {
1528 if (*p == '\0' || gmatch(s, p))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001529 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001530 } while (*s++ != '\0');
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001531 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001532
1533 default:
Eric Andersen8401eea2004-08-04 19:16:54 +00001534 if (sc != (pc & ~QUOTE))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001535 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001536 }
1537 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001538 return *s == '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00001539}
1540
Eric Andersenff9eee42001-06-29 04:57:14 +00001541
Eric Andersenff9eee42001-06-29 04:57:14 +00001542/* -------- csyn.c -------- */
1543/*
1544 * shell: syntax (C version)
1545 */
1546
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001547static void yyerror(const char *s) NORETURN;
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001548static void yyerror(const char *s)
1549{
Denis Vlasenko648b44f2008-02-12 06:04:06 +00001550 yynerrs = 1;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00001551 if (interactive && global_env.iop <= iostack) {
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001552 multiline = 0;
Denis Vlasenko648b44f2008-02-12 06:04:06 +00001553 while (eofc() == 0 && yylex(0) != '\n')
1554 continue;
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001555 }
1556 err(s);
1557 fail();
1558}
1559
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001560static void zzerr(void) NORETURN;
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001561static void zzerr(void)
1562{
1563 yyerror("syntax error");
1564}
1565
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001566int yyparse(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001567{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001568 DBGPRINTF7(("YYPARSE: enter...\n"));
1569
Eric Andersen8401eea2004-08-04 19:16:54 +00001570 startl = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001571 peeksym = 0;
1572 yynerrs = 0;
1573 outtree = c_list();
1574 musthave('\n', 0);
Denis Vlasenko648b44f2008-02-12 06:04:06 +00001575 return yynerrs; /* 0/1 */
Eric Andersenff9eee42001-06-29 04:57:14 +00001576}
1577
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001578static struct op *pipeline(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001579{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001580 struct op *t, *p;
1581 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001582
1583 DBGPRINTF7(("PIPELINE: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001584
1585 t = command(cf);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001586
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001587 DBGPRINTF9(("PIPELINE: t=%p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001588
Eric Andersenff9eee42001-06-29 04:57:14 +00001589 if (t != NULL) {
1590 while ((c = yylex(0)) == '|') {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001591 p = command(CONTIN);
1592 if (p == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001593 DBGPRINTF8(("PIPELINE: error!\n"));
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001594 zzerr();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001595 }
1596
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001597 if (t->op_type != TPAREN && t->op_type != TCOM) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001598 /* shell statement */
1599 t = block(TPAREN, t, NOBLOCK, NOWORDS);
1600 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001601
Eric Andersenff9eee42001-06-29 04:57:14 +00001602 t = block(TPIPE, t, p, NOWORDS);
1603 }
1604 peeksym = c;
1605 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001606
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001607 DBGPRINTF7(("PIPELINE: returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001608 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001609}
1610
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001611static struct op *andor(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001612{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001613 struct op *t, *p;
1614 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001615
1616 DBGPRINTF7(("ANDOR: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001617
1618 t = pipeline(0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001619
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001620 DBGPRINTF9(("ANDOR: t=%p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001621
Eric Andersenff9eee42001-06-29 04:57:14 +00001622 if (t != NULL) {
1623 while ((c = yylex(0)) == LOGAND || c == LOGOR) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001624 p = pipeline(CONTIN);
1625 if (p == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001626 DBGPRINTF8(("ANDOR: error!\n"));
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001627 zzerr();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001628 }
1629
Eric Andersen8401eea2004-08-04 19:16:54 +00001630 t = block(c == LOGAND ? TAND : TOR, t, p, NOWORDS);
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001631 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001632
Eric Andersenff9eee42001-06-29 04:57:14 +00001633 peeksym = c;
1634 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001635
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001636 DBGPRINTF7(("ANDOR: returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001637 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001638}
1639
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001640static struct op *c_list(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001641{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001642 struct op *t, *p;
1643 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001644
1645 DBGPRINTF7(("C_LIST: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001646
1647 t = andor();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001648
Eric Andersenff9eee42001-06-29 04:57:14 +00001649 if (t != NULL) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001650 peeksym = yylex(0);
1651 if (peeksym == '&')
Eric Andersenff9eee42001-06-29 04:57:14 +00001652 t = block(TASYNC, t, NOBLOCK, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001653
Eric Andersen8401eea2004-08-04 19:16:54 +00001654 while ((c = yylex(0)) == ';' || c == '&'
Denis Vlasenko509697f2008-03-02 12:49:39 +00001655 || (multiline && c == '\n')
1656 ) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001657 p = andor();
1658 if (p== NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001659 return t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001660
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001661 peeksym = yylex(0);
1662 if (peeksym == '&')
Eric Andersenff9eee42001-06-29 04:57:14 +00001663 p = block(TASYNC, p, NOBLOCK, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001664
Eric Andersenff9eee42001-06-29 04:57:14 +00001665 t = list(t, p);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001666 } /* WHILE */
1667
Eric Andersenff9eee42001-06-29 04:57:14 +00001668 peeksym = c;
1669 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001670 /* IF */
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001671 DBGPRINTF7(("C_LIST: returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001672 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001673}
1674
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001675static int synio(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001676{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001677 struct ioword *iop;
1678 int i;
1679 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001680
1681 DBGPRINTF7(("SYNIO: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001682
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001683 c = yylex(cf);
1684 if (c != '<' && c != '>') {
Eric Andersenff9eee42001-06-29 04:57:14 +00001685 peeksym = c;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001686 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001687 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001688
Eric Andersenff9eee42001-06-29 04:57:14 +00001689 i = yylval.i;
1690 musthave(WORD, 0);
1691 iop = io(iounit, i, yylval.cp);
1692 iounit = IODEFAULT;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001693
Eric Andersenff9eee42001-06-29 04:57:14 +00001694 if (i & IOHERE)
1695 markhere(yylval.cp, iop);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001696
1697 DBGPRINTF7(("SYNIO: returning 1\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001698 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001699}
1700
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001701static void musthave(int c, int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001702{
Denis Vlasenko00ccf952007-02-01 01:39:24 +00001703 peeksym = yylex(cf);
1704 if (peeksym != c) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001705 DBGPRINTF7(("MUSTHAVE: error!\n"));
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001706 zzerr();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001707 }
1708
Eric Andersenff9eee42001-06-29 04:57:14 +00001709 peeksym = 0;
1710}
1711
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001712static struct op *simple(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001713{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001714 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001715
1716 t = NULL;
1717 for (;;) {
1718 switch (peeksym = yylex(0)) {
1719 case '<':
1720 case '>':
1721 (void) synio(0);
1722 break;
1723
1724 case WORD:
1725 if (t == NULL) {
1726 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001727 t->op_type = TCOM;
Eric Andersenff9eee42001-06-29 04:57:14 +00001728 }
1729 peeksym = 0;
1730 word(yylval.cp);
1731 break;
1732
1733 default:
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001734 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001735 }
1736 }
1737}
1738
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001739static struct op *nested(int type, int mark)
Eric Andersenff9eee42001-06-29 04:57:14 +00001740{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001741 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001742
1743 DBGPRINTF3(("NESTED: enter, type=%d, mark=%d\n", type, mark));
Eric Andersenff9eee42001-06-29 04:57:14 +00001744
1745 multiline++;
1746 t = c_list();
1747 musthave(mark, 0);
1748 multiline--;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001749 return block(type, t, NOBLOCK, NOWORDS);
Eric Andersenff9eee42001-06-29 04:57:14 +00001750}
1751
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001752static struct op *command(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001753{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001754 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001755 struct wdblock *iosave;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001756 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001757
1758 DBGPRINTF(("COMMAND: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001759
1760 iosave = iolist;
1761 iolist = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001762
Eric Andersenff9eee42001-06-29 04:57:14 +00001763 if (multiline)
1764 cf |= CONTIN;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001765
Eric Andersenff9eee42001-06-29 04:57:14 +00001766 while (synio(cf))
1767 cf = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001768
1769 c = yylex(cf);
1770
1771 switch (c) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001772 default:
1773 peeksym = c;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001774 t = simple();
1775 if (t == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001776 if (iolist == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001777 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001778 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001779 t->op_type = TCOM;
Eric Andersenff9eee42001-06-29 04:57:14 +00001780 }
1781 break;
1782
1783 case '(':
1784 t = nested(TPAREN, ')');
1785 break;
1786
1787 case '{':
1788 t = nested(TBRACE, '}');
1789 break;
1790
1791 case FOR:
1792 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001793 t->op_type = TFOR;
Eric Andersenff9eee42001-06-29 04:57:14 +00001794 musthave(WORD, 0);
1795 startl = 1;
1796 t->str = yylval.cp;
1797 multiline++;
Denis Vlasenko509697f2008-03-02 12:49:39 +00001798 t->op_words = wordlist();
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001799 c = yylex(0);
1800 if (c != '\n' && c != ';')
Eric Andersenff9eee42001-06-29 04:57:14 +00001801 peeksym = c;
1802 t->left = dogroup(0);
1803 multiline--;
1804 break;
1805
1806 case WHILE:
1807 case UNTIL:
1808 multiline++;
1809 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001810 t->op_type = (c == WHILE ? TWHILE : TUNTIL);
Eric Andersenff9eee42001-06-29 04:57:14 +00001811 t->left = c_list();
1812 t->right = dogroup(1);
Denis Vlasenko509697f2008-03-02 12:49:39 +00001813 /* t->op_words = NULL; - newtp() did this */
Eric Andersenff9eee42001-06-29 04:57:14 +00001814 multiline--;
1815 break;
1816
1817 case CASE:
1818 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001819 t->op_type = TCASE;
Eric Andersenff9eee42001-06-29 04:57:14 +00001820 musthave(WORD, 0);
1821 t->str = yylval.cp;
1822 startl++;
1823 multiline++;
1824 musthave(IN, CONTIN);
1825 startl++;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001826
Eric Andersenff9eee42001-06-29 04:57:14 +00001827 t->left = caselist();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001828
Eric Andersenff9eee42001-06-29 04:57:14 +00001829 musthave(ESAC, 0);
1830 multiline--;
1831 break;
1832
1833 case IF:
1834 multiline++;
1835 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001836 t->op_type = TIF;
Eric Andersenff9eee42001-06-29 04:57:14 +00001837 t->left = c_list();
1838 t->right = thenpart();
1839 musthave(FI, 0);
1840 multiline--;
1841 break;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001842
1843 case DOT:
1844 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001845 t->op_type = TDOT;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001846
Denis Vlasenko509697f2008-03-02 12:49:39 +00001847 musthave(WORD, 0); /* gets name of file */
Eric Andersen12de6cf2004-08-04 19:19:10 +00001848 DBGPRINTF7(("COMMAND: DOT clause, yylval.cp is %s\n", yylval.cp));
1849
Denis Vlasenko509697f2008-03-02 12:49:39 +00001850 word(yylval.cp); /* add word to wdlist */
1851 word(NOWORD); /* terminate wdlist */
1852 t->op_words = copyw(); /* dup wdlist */
Eric Andersen12de6cf2004-08-04 19:19:10 +00001853 break;
1854
Eric Andersenff9eee42001-06-29 04:57:14 +00001855 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001856
Denis Vlasenko509697f2008-03-02 12:49:39 +00001857 while (synio(0))
1858 continue;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001859
Eric Andersenff9eee42001-06-29 04:57:14 +00001860 t = namelist(t);
1861 iolist = iosave;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001862
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001863 DBGPRINTF(("COMMAND: returning %p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001864
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001865 return t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001866}
1867
Denis Vlasenko68404f12008-03-17 09:00:54 +00001868static struct op *dowholefile(int type /*, int mark*/)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001869{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001870 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001871
Denis Vlasenko68404f12008-03-17 09:00:54 +00001872 DBGPRINTF(("DOWHOLEFILE: enter, type=%d\n", type /*, mark*/));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001873
1874 multiline++;
1875 t = c_list();
1876 multiline--;
1877 t = block(type, t, NOBLOCK, NOWORDS);
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001878 DBGPRINTF(("DOWHOLEFILE: return t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001879 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001880}
1881
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001882static struct op *dogroup(int onlydone)
Eric Andersenff9eee42001-06-29 04:57:14 +00001883{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001884 int c;
1885 struct op *mylist;
Eric Andersenff9eee42001-06-29 04:57:14 +00001886
1887 c = yylex(CONTIN);
1888 if (c == DONE && onlydone)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001889 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001890 if (c != DO)
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001891 zzerr();
Eric Andersenff9eee42001-06-29 04:57:14 +00001892 mylist = c_list();
1893 musthave(DONE, 0);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001894 return mylist;
Eric Andersenff9eee42001-06-29 04:57:14 +00001895}
1896
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001897static struct op *thenpart(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001898{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001899 int c;
1900 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001901
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001902 c = yylex(0);
1903 if (c != THEN) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001904 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001905 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001906 }
1907 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001908 /*t->op_type = 0; - newtp() did this */
Eric Andersenff9eee42001-06-29 04:57:14 +00001909 t->left = c_list();
1910 if (t->left == NULL)
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001911 zzerr();
Eric Andersenff9eee42001-06-29 04:57:14 +00001912 t->right = elsepart();
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001913 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001914}
1915
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001916static struct op *elsepart(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001917{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001918 int c;
1919 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001920
1921 switch (c = yylex(0)) {
1922 case ELSE:
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001923 t = c_list();
1924 if (t == NULL)
Denis Vlasenko6b50f732007-02-01 01:43:39 +00001925 zzerr();
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001926 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001927
1928 case ELIF:
1929 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001930 t->op_type = TELIF;
Eric Andersenff9eee42001-06-29 04:57:14 +00001931 t->left = c_list();
1932 t->right = thenpart();
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001933 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001934
1935 default:
1936 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001937 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001938 }
1939}
1940
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001941static struct op *caselist(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001942{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001943 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001944
1945 t = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001946 while ((peeksym = yylex(CONTIN)) != ESAC) {
1947 DBGPRINTF(("CASELIST, doing yylex, peeksym=%d\n", peeksym));
Eric Andersenff9eee42001-06-29 04:57:14 +00001948 t = list(t, casepart());
Eric Andersen12de6cf2004-08-04 19:19:10 +00001949 }
1950
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001951 DBGPRINTF(("CASELIST, returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001952 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001953}
1954
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001955static struct op *casepart(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001956{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001957 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001958
1959 DBGPRINTF7(("CASEPART: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001960
1961 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00001962 t->op_type = TPAT;
Denis Vlasenko509697f2008-03-02 12:49:39 +00001963 t->op_words = pattern();
Eric Andersenff9eee42001-06-29 04:57:14 +00001964 musthave(')', 0);
1965 t->left = c_list();
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001966 peeksym = yylex(CONTIN);
1967 if (peeksym != ESAC)
Eric Andersenff9eee42001-06-29 04:57:14 +00001968 musthave(BREAK, CONTIN);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001969
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001970 DBGPRINTF7(("CASEPART: made newtp(TPAT, t=%p)\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001971
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001972 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001973}
1974
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001975static char **pattern(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001976{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001977 int c, cf;
Eric Andersenff9eee42001-06-29 04:57:14 +00001978
1979 cf = CONTIN;
1980 do {
1981 musthave(WORD, cf);
1982 word(yylval.cp);
1983 cf = 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001984 c = yylex(0);
1985 } while (c == '|');
Eric Andersenff9eee42001-06-29 04:57:14 +00001986 peeksym = c;
1987 word(NOWORD);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001988
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001989 return copyw();
Eric Andersenff9eee42001-06-29 04:57:14 +00001990}
1991
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001992static char **wordlist(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001993{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001994 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00001995
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00001996 c = yylex(0);
1997 if (c != IN) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001998 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001999 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00002000 }
2001 startl = 0;
2002 while ((c = yylex(0)) == WORD)
2003 word(yylval.cp);
2004 word(NOWORD);
2005 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002006 return copyw();
Eric Andersenff9eee42001-06-29 04:57:14 +00002007}
2008
2009/*
2010 * supporting functions
2011 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002012static struct op *list(struct op *t1, struct op *t2)
Eric Andersenff9eee42001-06-29 04:57:14 +00002013{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002014 DBGPRINTF7(("LIST: enter, t1=%p, t2=%p\n", t1, t2));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002015
Eric Andersenff9eee42001-06-29 04:57:14 +00002016 if (t1 == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002017 return t2;
Eric Andersenff9eee42001-06-29 04:57:14 +00002018 if (t2 == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002019 return t1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002020
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002021 return block(TLIST, t1, t2, NOWORDS);
Eric Andersenff9eee42001-06-29 04:57:14 +00002022}
2023
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002024static struct op *block(int type, struct op *t1, struct op *t2, char **wp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002025{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002026 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002027
2028 DBGPRINTF7(("BLOCK: enter, type=%d (%s)\n", type, T_CMD_NAMES[type]));
Eric Andersenff9eee42001-06-29 04:57:14 +00002029
2030 t = newtp();
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002031 t->op_type = type;
Eric Andersenff9eee42001-06-29 04:57:14 +00002032 t->left = t1;
2033 t->right = t2;
Denis Vlasenko509697f2008-03-02 12:49:39 +00002034 t->op_words = wp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002035
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002036 DBGPRINTF7(("BLOCK: inserted %p between %p and %p\n", t, t1, t2));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002037
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002038 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002039}
2040
Eric Andersen12de6cf2004-08-04 19:19:10 +00002041/* See if given string is a shell multiline (FOR, IF, etc) */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002042static int rlookup(char *n)
Eric Andersenff9eee42001-06-29 04:57:14 +00002043{
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002044 struct res {
2045 char r_name[6];
2046 int16_t r_val;
2047 };
2048 static const struct res restab[] = {
2049 { "for" , FOR },
2050 { "case" , CASE },
2051 { "esac" , ESAC },
2052 { "while", WHILE },
2053 { "do" , DO },
2054 { "done" , DONE },
2055 { "if" , IF },
2056 { "in" , IN },
2057 { "then" , THEN },
2058 { "else" , ELSE },
2059 { "elif" , ELIF },
2060 { "until", UNTIL },
2061 { "fi" , FI },
2062 { ";;" , BREAK },
2063 { "||" , LOGOR },
2064 { "&&" , LOGAND },
2065 { "{" , '{' },
2066 { "}" , '}' },
2067 { "." , DOT },
2068 { },
2069 };
2070
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002071 const struct res *rp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002072
2073 DBGPRINTF7(("RLOOKUP: enter, n is %s\n", n));
Eric Andersenff9eee42001-06-29 04:57:14 +00002074
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002075 for (rp = restab; rp->r_name[0]; rp++)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002076 if (strcmp(rp->r_name, n) == 0) {
2077 DBGPRINTF7(("RLOOKUP: match, returning %d\n", rp->r_val));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002078 return rp->r_val; /* Return numeric code for shell multiline */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002079 }
2080
2081 DBGPRINTF7(("RLOOKUP: NO match, returning 0\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002082 return 0; /* Not a shell multiline */
Eric Andersenff9eee42001-06-29 04:57:14 +00002083}
2084
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002085static struct op *newtp(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002086{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002087 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002088
Eric Andersen8401eea2004-08-04 19:16:54 +00002089 t = (struct op *) tree(sizeof(*t));
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002090 memset(t, 0, sizeof(*t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002091
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002092 DBGPRINTF3(("NEWTP: allocated %p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002093
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002094 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002095}
2096
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002097static struct op *namelist(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00002098{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002099 DBGPRINTF7(("NAMELIST: enter, t=%p, type %s, iolist=%p\n", t,
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002100 T_CMD_NAMES[t->op_type], iolist));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002101
Eric Andersenff9eee42001-06-29 04:57:14 +00002102 if (iolist) {
Eric Andersen8401eea2004-08-04 19:16:54 +00002103 iolist = addword((char *) NULL, iolist);
Eric Andersenff9eee42001-06-29 04:57:14 +00002104 t->ioact = copyio();
2105 } else
2106 t->ioact = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002107
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002108 if (t->op_type != TCOM) {
2109 if (t->op_type != TPAREN && t->ioact != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002110 t = block(TPAREN, t, NOBLOCK, NOWORDS);
2111 t->ioact = t->left->ioact;
2112 t->left->ioact = NULL;
2113 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002114 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002115 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002116
Eric Andersenff9eee42001-06-29 04:57:14 +00002117 word(NOWORD);
Denis Vlasenko509697f2008-03-02 12:49:39 +00002118 t->op_words = copyw();
Eric Andersen12de6cf2004-08-04 19:19:10 +00002119
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002120 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002121}
2122
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002123static char **copyw(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002124{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002125 char **wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00002126
2127 wd = getwords(wdlist);
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002128 wdlist = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002129 return wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00002130}
2131
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002132static void word(char *cp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002133{
2134 wdlist = addword(cp, wdlist);
2135}
2136
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002137static struct ioword **copyio(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002138{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002139 struct ioword **iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002140
2141 iop = (struct ioword **) getwords(iolist);
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002142 iolist = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002143 return iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002144}
2145
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002146static struct ioword *io(int u, int f, char *cp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002147{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002148 struct ioword *iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002149
2150 iop = (struct ioword *) tree(sizeof(*iop));
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002151 iop->io_fd = u;
Eric Andersenff9eee42001-06-29 04:57:14 +00002152 iop->io_flag = f;
2153 iop->io_name = cp;
Eric Andersen8401eea2004-08-04 19:16:54 +00002154 iolist = addword((char *) iop, iolist);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002155 return iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002156}
2157
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002158static int yylex(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00002159{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002160 int c, c1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002161 int atstart;
2162
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002163 c = peeksym;
2164 if (c > 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002165 peeksym = 0;
2166 if (c == '\n')
2167 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002168 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002169 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002170
Eric Andersenff9eee42001-06-29 04:57:14 +00002171 nlseen = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002172 atstart = startl;
2173 startl = 0;
2174 yylval.i = 0;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002175 global_env.linep = line;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002176
2177/* MALAMO */
2178 line[LINELIM - 1] = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00002179
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002180 loop:
Eric Andersen12de6cf2004-08-04 19:19:10 +00002181 while ((c = my_getc(0)) == ' ' || c == '\t') /* Skip whitespace */
Denis Vlasenko509697f2008-03-02 12:49:39 +00002182 continue;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002183
Eric Andersenff9eee42001-06-29 04:57:14 +00002184 switch (c) {
2185 default:
2186 if (any(c, "0123456789")) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002187 c1 = my_getc(0);
2188 unget(c1);
Eric Andersenff9eee42001-06-29 04:57:14 +00002189 if (c1 == '<' || c1 == '>') {
2190 iounit = c - '0';
2191 goto loop;
2192 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002193 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002194 c = c1;
2195 }
2196 break;
2197
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002198 case '#': /* Comment, skip to next newline or End-of-string */
Denis Vlasenko509697f2008-03-02 12:49:39 +00002199 while ((c = my_getc(0)) != '\0' && c != '\n')
2200 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00002201 unget(c);
2202 goto loop;
2203
2204 case 0:
Eric Andersen12de6cf2004-08-04 19:19:10 +00002205 DBGPRINTF5(("YYLEX: return 0, c=%d\n", c));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002206 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002207
2208 case '$':
Eric Andersen12de6cf2004-08-04 19:19:10 +00002209 DBGPRINTF9(("YYLEX: found $\n"));
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002210 *global_env.linep++ = c;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002211 c = my_getc(0);
2212 if (c == '{') {
2213 c = collect(c, '}');
2214 if (c != '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002215 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002216 goto pack;
2217 }
2218 break;
2219
2220 case '`':
2221 case '\'':
2222 case '"':
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002223 c = collect(c, c);
2224 if (c != '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002225 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002226 goto pack;
2227
2228 case '|':
2229 case '&':
2230 case ';':
Eric Andersenff9eee42001-06-29 04:57:14 +00002231 startl = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002232 /* If more chars process them, else return NULL char */
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002233 c1 = dual(c);
2234 if (c1 != '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002235 return c1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002236 return c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002237
Eric Andersenff9eee42001-06-29 04:57:14 +00002238 case '^':
2239 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002240 return '|';
Eric Andersenff9eee42001-06-29 04:57:14 +00002241 case '>':
2242 case '<':
2243 diag(c);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002244 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002245
2246 case '\n':
2247 nlseen++;
2248 gethere();
2249 startl = 1;
2250 if (multiline || cf & CONTIN) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002251 if (interactive && global_env.iop <= iostack) {
Denis Vlasenko38f63192007-01-22 09:03:07 +00002252#if ENABLE_FEATURE_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00002253 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00002254#else
Eric Andersen8401eea2004-08-04 19:16:54 +00002255 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00002256#endif
2257 }
2258 if (cf & CONTIN)
2259 goto loop;
2260 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002261 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002262
2263 case '(':
2264 case ')':
2265 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002266 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002267 }
2268
2269 unget(c);
2270
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002271 pack:
2272 while ((c = my_getc(0)) != '\0' && !any(c, "`$ '\"\t;&<>()|^\n")) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002273 if (global_env.linep >= elinep)
Eric Andersenff9eee42001-06-29 04:57:14 +00002274 err("word too long");
2275 else
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002276 *global_env.linep++ = c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002277 };
2278
Eric Andersenff9eee42001-06-29 04:57:14 +00002279 unget(c);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002280
Eric Andersen8401eea2004-08-04 19:16:54 +00002281 if (any(c, "\"'`$"))
Eric Andersenff9eee42001-06-29 04:57:14 +00002282 goto loop;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002283
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002284 *global_env.linep++ = '\0';
Eric Andersen12de6cf2004-08-04 19:19:10 +00002285
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002286 if (atstart) {
2287 c = rlookup(line);
2288 if (c != 0) {
2289 startl = 1;
2290 return c;
2291 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002292 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002293
Eric Andersenff9eee42001-06-29 04:57:14 +00002294 yylval.cp = strsave(line, areanum);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002295 return WORD;
Eric Andersenff9eee42001-06-29 04:57:14 +00002296}
2297
Eric Andersen12de6cf2004-08-04 19:19:10 +00002298
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002299static int collect(int c, int c1)
Eric Andersenff9eee42001-06-29 04:57:14 +00002300{
2301 char s[2];
2302
Eric Andersen12de6cf2004-08-04 19:19:10 +00002303 DBGPRINTF8(("COLLECT: enter, c=%d, c1=%d\n", c, c1));
2304
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002305 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002306 while ((c = my_getc(c1)) != c1) {
2307 if (c == 0) {
2308 unget(c);
2309 s[0] = c1;
2310 s[1] = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00002311 prs("no closing ");
2312 yyerror(s);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002313 return YYERRCODE;
Eric Andersenff9eee42001-06-29 04:57:14 +00002314 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002315 if (interactive && c == '\n' && global_env.iop <= iostack) {
Denis Vlasenko38f63192007-01-22 09:03:07 +00002316#if ENABLE_FEATURE_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00002317 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00002318#else
Eric Andersen8401eea2004-08-04 19:16:54 +00002319 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00002320#endif
2321 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002322 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002323 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002324
Denis Vlasenkoc794c512007-12-16 17:21:29 +00002325 *global_env.linep++ = c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002326
2327 DBGPRINTF8(("COLLECT: return 0, line is %s\n", line));
2328
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002329 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002330}
2331
Eric Andersen12de6cf2004-08-04 19:19:10 +00002332/* "multiline commands" helper func */
2333/* see if next 2 chars form a shell multiline */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002334static int dual(int c)
Eric Andersenff9eee42001-06-29 04:57:14 +00002335{
2336 char s[3];
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002337 char *cp = s;
Eric Andersenff9eee42001-06-29 04:57:14 +00002338
Eric Andersen12de6cf2004-08-04 19:19:10 +00002339 DBGPRINTF8(("DUAL: enter, c=%d\n", c));
2340
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002341 *cp++ = c; /* c is the given "peek" char */
2342 *cp++ = my_getc(0); /* get next char of input */
2343 *cp = '\0'; /* add EOS marker */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002344
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002345 c = rlookup(s); /* see if 2 chars form a shell multiline */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002346 if (c == 0)
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002347 unget(*--cp); /* String is not a shell multiline, put peek char back */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002348
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002349 return c; /* String is multiline, return numeric multiline (restab) code */
Eric Andersenff9eee42001-06-29 04:57:14 +00002350}
2351
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002352static void diag(int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00002353{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002354 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002355
2356 DBGPRINTF8(("DIAG: enter, ec=%d\n", ec));
Eric Andersenff9eee42001-06-29 04:57:14 +00002357
2358 c = my_getc(0);
2359 if (c == '>' || c == '<') {
2360 if (c != ec)
2361 zzerr();
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002362 yylval.i = (ec == '>' ? IOWRITE | IOCAT : IOHERE);
Eric Andersenff9eee42001-06-29 04:57:14 +00002363 c = my_getc(0);
2364 } else
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002365 yylval.i = (ec == '>' ? IOWRITE : IOREAD);
Eric Andersenff9eee42001-06-29 04:57:14 +00002366 if (c != '&' || yylval.i == IOHERE)
2367 unget(c);
2368 else
2369 yylval.i |= IODUP;
2370}
2371
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002372static char *tree(unsigned size)
Eric Andersenff9eee42001-06-29 04:57:14 +00002373{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002374 char *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002375
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002376 t = getcell(size);
2377 if (t == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002378 DBGPRINTF2(("TREE: getcell(%d) failed!\n", size));
Eric Andersenff9eee42001-06-29 04:57:14 +00002379 prs("command line too complicated\n");
2380 fail();
2381 /* NOTREACHED */
2382 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002383 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002384}
2385
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002386
Eric Andersenff9eee42001-06-29 04:57:14 +00002387/* VARARGS1 */
2388/* ARGSUSED */
2389
2390/* -------- exec.c -------- */
2391
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002392static struct op **find1case(struct op *t, const char *w)
2393{
2394 struct op *t1;
2395 struct op **tp;
2396 char **wp;
2397 char *cp;
2398
2399 if (t == NULL) {
2400 DBGPRINTF3(("FIND1CASE: enter, t==NULL, returning.\n"));
2401 return NULL;
2402 }
2403
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002404 DBGPRINTF3(("FIND1CASE: enter, t->op_type=%d (%s)\n", t->op_type,
2405 T_CMD_NAMES[t->op_type]));
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002406
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002407 if (t->op_type == TLIST) {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002408 tp = find1case(t->left, w);
2409 if (tp != NULL) {
2410 DBGPRINTF3(("FIND1CASE: found one to the left, returning tp=%p\n", tp));
2411 return tp;
2412 }
2413 t1 = t->right; /* TPAT */
2414 } else
2415 t1 = t;
2416
Denis Vlasenko509697f2008-03-02 12:49:39 +00002417 for (wp = t1->op_words; *wp;) {
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002418 cp = evalstr(*wp++, DOSUB);
2419 if (cp && gmatch(w, cp)) {
2420 DBGPRINTF3(("FIND1CASE: returning &t1->left= %p.\n",
2421 &t1->left));
2422 return &t1->left;
2423 }
2424 }
2425
2426 DBGPRINTF(("FIND1CASE: returning NULL\n"));
2427 return NULL;
2428}
2429
2430static struct op *findcase(struct op *t, const char *w)
2431{
2432 struct op **tp;
2433
2434 tp = find1case(t, w);
2435 return tp != NULL ? *tp : NULL;
2436}
2437
Eric Andersenff9eee42001-06-29 04:57:14 +00002438/*
2439 * execute tree
2440 */
2441
Denis Vlasenko7e497522008-02-12 09:51:03 +00002442static int execute(struct op *t, int *pin, int *pout, int no_fork)
Eric Andersenff9eee42001-06-29 04:57:14 +00002443{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002444 struct op *t1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002445 volatile int i, rv, a;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002446 const char *cp;
2447 char **wp, **wp2;
Eric Andersenff9eee42001-06-29 04:57:14 +00002448 struct var *vp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002449 struct op *outtree_save;
Eric Andersenff9eee42001-06-29 04:57:14 +00002450 struct brkcon bc;
2451
2452#if __GNUC__
2453 /* Avoid longjmp clobbering */
2454 (void) &wp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002455#endif
Eric Andersenff9eee42001-06-29 04:57:14 +00002456
Eric Andersen12de6cf2004-08-04 19:19:10 +00002457 if (t == NULL) {
2458 DBGPRINTF4(("EXECUTE: enter, t==null, returning.\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002459 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002460 }
2461
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002462 DBGPRINTF(("EXECUTE: t=%p, t->op_type=%d (%s), t->op_words is %s\n", t,
2463 t->op_type, T_CMD_NAMES[t->op_type],
Denis Vlasenko509697f2008-03-02 12:49:39 +00002464 ((t->op_words == NULL) ? "NULL" : t->op_words[0])));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002465
Eric Andersenff9eee42001-06-29 04:57:14 +00002466 rv = 0;
2467 a = areanum++;
Denis Vlasenko509697f2008-03-02 12:49:39 +00002468 wp2 = t->op_words;
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002469 wp = (wp2 != NULL)
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002470 ? eval(wp2, t->op_type == TCOM ? DOALL : DOALL & ~DOKEY)
Eric Andersen8401eea2004-08-04 19:16:54 +00002471 : NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00002472
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002473 switch (t->op_type) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002474 case TDOT:
2475 DBGPRINTF3(("EXECUTE: TDOT\n"));
2476
2477 outtree_save = outtree;
2478
Denis Vlasenko509697f2008-03-02 12:49:39 +00002479 newfile(evalstr(t->op_words[0], DOALL));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002480
Denis Vlasenko68404f12008-03-17 09:00:54 +00002481 t->left = dowholefile(TLIST /*, 0*/);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002482 t->right = NULL;
2483
2484 outtree = outtree_save;
2485
2486 if (t->left)
Denis Vlasenko7e497522008-02-12 09:51:03 +00002487 rv = execute(t->left, pin, pout, /* no_fork: */ 0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002488 if (t->right)
Denis Vlasenko7e497522008-02-12 09:51:03 +00002489 rv = execute(t->right, pin, pout, /* no_fork: */ 0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002490 break;
2491
Eric Andersenff9eee42001-06-29 04:57:14 +00002492 case TPAREN:
Denis Vlasenko7e497522008-02-12 09:51:03 +00002493 rv = execute(t->left, pin, pout, /* no_fork: */ 0);
Eric Andersen737f5fb2003-03-14 16:05:59 +00002494 break;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002495
Eric Andersenff9eee42001-06-29 04:57:14 +00002496 case TCOM:
Denis Vlasenko7e497522008-02-12 09:51:03 +00002497 rv = forkexec(t, pin, pout, no_fork, wp);
Eric Andersenff9eee42001-06-29 04:57:14 +00002498 break;
2499
2500 case TPIPE:
2501 {
Eric Andersen8401eea2004-08-04 19:16:54 +00002502 int pv[2];
2503
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002504 rv = openpipe(pv);
2505 if (rv < 0)
Eric Andersen8401eea2004-08-04 19:16:54 +00002506 break;
2507 pv[0] = remap(pv[0]);
2508 pv[1] = remap(pv[1]);
Denis Vlasenko7e497522008-02-12 09:51:03 +00002509 (void) execute(t->left, pin, pv, /* no_fork: */ 0);
2510 rv = execute(t->right, pv, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002511 }
2512 break;
2513
2514 case TLIST:
Denis Vlasenko7e497522008-02-12 09:51:03 +00002515 (void) execute(t->left, pin, pout, /* no_fork: */ 0);
2516 rv = execute(t->right, pin, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002517 break;
2518
2519 case TASYNC:
Eric Andersen8401eea2004-08-04 19:16:54 +00002520 {
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002521 smallint hinteractive = interactive;
Eric Andersenff9eee42001-06-29 04:57:14 +00002522
Eric Andersen12de6cf2004-08-04 19:19:10 +00002523 DBGPRINTF7(("EXECUTE: TASYNC clause, calling vfork()...\n"));
2524
Eric Andersen8401eea2004-08-04 19:16:54 +00002525 i = vfork();
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002526 if (i == 0) { /* child */
Eric Andersen8401eea2004-08-04 19:16:54 +00002527 signal(SIGINT, SIG_IGN);
2528 signal(SIGQUIT, SIG_IGN);
2529 if (interactive)
2530 signal(SIGTERM, SIG_DFL);
2531 interactive = 0;
2532 if (pin == NULL) {
2533 close(0);
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00002534 xopen(bb_dev_null, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00002535 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002536 _exit(execute(t->left, pin, pout, /* no_fork: */ 1));
Eric Andersenff9eee42001-06-29 04:57:14 +00002537 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002538 interactive = hinteractive;
2539 if (i != -1) {
2540 setval(lookup("!"), putn(i));
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002541 closepipe(pin);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002542 if (interactive) {
2543 prs(putn(i));
2544 prs("\n");
2545 }
2546 } else
2547 rv = -1;
2548 setstatus(rv);
Eric Andersenff9eee42001-06-29 04:57:14 +00002549 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002550 break;
2551
2552 case TOR:
2553 case TAND:
Denis Vlasenko7e497522008-02-12 09:51:03 +00002554 rv = execute(t->left, pin, pout, /* no_fork: */ 0);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002555 t1 = t->right;
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002556 if (t1 != NULL && (rv == 0) == (t->op_type == TAND))
Denis Vlasenko7e497522008-02-12 09:51:03 +00002557 rv = execute(t1, pin, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002558 break;
2559
2560 case TFOR:
2561 if (wp == NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00002562 wp = dolv + 1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002563 i = dolc;
2564 if (i < 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00002565 i = 0;
2566 } else {
2567 i = -1;
Denis Vlasenko509697f2008-03-02 12:49:39 +00002568 while (*wp++ != NULL)
2569 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00002570 }
2571 vp = lookup(t->str);
2572 while (setjmp(bc.brkpt))
2573 if (isbreak)
2574 goto broken;
Denis Vlasenko7ae1cc12008-07-20 23:03:23 +00002575 /* Restore areanum value. It may be incremented by execute()
2576 * below, and then "continue" may jump back to setjmp above */
2577 areanum = a + 1;
2578 freearea(areanum + 1);
Eric Andersenff9eee42001-06-29 04:57:14 +00002579 brkset(&bc);
2580 for (t1 = t->left; i-- && *wp != NULL;) {
2581 setval(vp, *wp++);
Denis Vlasenko7e497522008-02-12 09:51:03 +00002582 rv = execute(t1, pin, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002583 }
2584 brklist = brklist->nextlev;
2585 break;
2586
2587 case TWHILE:
2588 case TUNTIL:
2589 while (setjmp(bc.brkpt))
2590 if (isbreak)
2591 goto broken;
Denis Vlasenko7ae1cc12008-07-20 23:03:23 +00002592 /* Restore areanum value. It may be incremented by execute()
2593 * below, and then "continue" may jump back to setjmp above */
2594 areanum = a + 1;
2595 freearea(areanum + 1);
Eric Andersenff9eee42001-06-29 04:57:14 +00002596 brkset(&bc);
2597 t1 = t->left;
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002598 while ((execute(t1, pin, pout, /* no_fork: */ 0) == 0) == (t->op_type == TWHILE))
Denis Vlasenko7e497522008-02-12 09:51:03 +00002599 rv = execute(t->right, pin, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002600 brklist = brklist->nextlev;
2601 break;
2602
2603 case TIF:
2604 case TELIF:
Eric Andersen8401eea2004-08-04 19:16:54 +00002605 if (t->right != NULL) {
Denis Vlasenko7e497522008-02-12 09:51:03 +00002606 rv = !execute(t->left, pin, pout, /* no_fork: */ 0) ?
2607 execute(t->right->left, pin, pout, /* no_fork: */ 0) :
2608 execute(t->right->right, pin, pout, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002609 }
2610 break;
2611
2612 case TCASE:
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002613 cp = evalstr(t->str, DOSUB | DOTRIM);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002614 if (cp == NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00002615 cp = "";
Eric Andersen12de6cf2004-08-04 19:19:10 +00002616
2617 DBGPRINTF7(("EXECUTE: TCASE, t->str is %s, cp is %s\n",
2618 ((t->str == NULL) ? "NULL" : t->str),
2619 ((cp == NULL) ? "NULL" : cp)));
2620
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002621 t1 = findcase(t->left, cp);
2622 if (t1 != NULL) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002623 DBGPRINTF7(("EXECUTE: TCASE, calling execute(t=%p, t1=%p)...\n", t, t1));
Denis Vlasenko7e497522008-02-12 09:51:03 +00002624 rv = execute(t1, pin, pout, /* no_fork: */ 0);
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002625 DBGPRINTF7(("EXECUTE: TCASE, back from execute(t=%p, t1=%p)...\n", t, t1));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002626 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002627 break;
2628
2629 case TBRACE:
2630/*
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002631 iopp = t->ioact;
2632 if (i)
Eric Andersenff9eee42001-06-29 04:57:14 +00002633 while (*iopp)
2634 if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) {
2635 rv = -1;
2636 break;
2637 }
2638*/
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002639 if (rv >= 0) {
2640 t1 = t->left;
2641 if (t1) {
Denis Vlasenko7e497522008-02-12 09:51:03 +00002642 rv = execute(t1, pin, pout, /* no_fork: */ 0);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002643 }
2644 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002645 break;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002646
2647 };
Eric Andersenff9eee42001-06-29 04:57:14 +00002648
Denis Vlasenkoe4712752007-04-14 15:08:41 +00002649 broken:
Denis Vlasenko509697f2008-03-02 12:49:39 +00002650// Restoring op_words is most likely not needed now: see comment in forkexec()
2651// (also take a look at exec builtin (doexec) - it touches t->op_words)
2652 t->op_words = wp2;
Eric Andersenff9eee42001-06-29 04:57:14 +00002653 isbreak = 0;
2654 freehere(areanum);
2655 freearea(areanum);
2656 areanum = a;
2657 if (interactive && intr) {
2658 closeall();
2659 fail();
2660 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002661
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002662 i = trapset;
2663 if (i != 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002664 trapset = 0;
2665 runtrap(i);
2666 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002667
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002668 DBGPRINTF(("EXECUTE: returning from t=%p, rv=%d\n", t, rv));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002669 return rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00002670}
2671
Denis Vlasenkoe4712752007-04-14 15:08:41 +00002672static builtin_func_ptr inbuilt(const char *s)
2673{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002674 const struct builtincmd *bp;
2675
Denis Vlasenko95cb3262007-04-09 03:06:34 +00002676 for (bp = builtincmds; bp->name; bp++)
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002677 if (strcmp(bp->name, s) == 0)
2678 return bp->builtinfunc;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002679 return NULL;
2680}
2681
Denis Vlasenko7e497522008-02-12 09:51:03 +00002682static int forkexec(struct op *t, int *pin, int *pout, int no_fork, char **wp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002683{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002684 pid_t newpid;
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002685 int i;
2686 builtin_func_ptr bltin = NULL;
Denis Vlasenko7e497522008-02-12 09:51:03 +00002687 const char *bltin_name = NULL;
2688 const char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00002689 struct ioword **iopp;
2690 int resetsig;
2691 char **owp;
Denis Vlasenko7e497522008-02-12 09:51:03 +00002692 int forked;
Eric Andersenff9eee42001-06-29 04:57:14 +00002693
2694 int *hpin = pin;
2695 int *hpout = pout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002696 char *hwp;
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002697 smallint hinteractive;
2698 smallint hintr;
2699 smallint hexecflg;
Eric Andersen8401eea2004-08-04 19:16:54 +00002700 struct brkcon *hbrklist;
Eric Andersenff9eee42001-06-29 04:57:14 +00002701
2702#if __GNUC__
2703 /* Avoid longjmp clobbering */
2704 (void) &pin;
2705 (void) &pout;
2706 (void) &wp;
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002707 (void) &bltin;
Eric Andersenff9eee42001-06-29 04:57:14 +00002708 (void) &cp;
2709 (void) &resetsig;
2710 (void) &owp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002711#endif
Eric Andersenff9eee42001-06-29 04:57:14 +00002712
Denis Vlasenko7e497522008-02-12 09:51:03 +00002713 DBGPRINTF(("FORKEXEC: t=%p, pin %p, pout %p, no_fork %d\n", t, pin,
2714 pout, no_fork));
Denis Vlasenko509697f2008-03-02 12:49:39 +00002715 DBGPRINTF7(("FORKEXEC: t->op_words is %s\n",
2716 ((t->op_words == NULL) ? "NULL" : t->op_words[0])));
Eric Andersenff9eee42001-06-29 04:57:14 +00002717 owp = wp;
2718 resetsig = 0;
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002719 if (t->op_type == TCOM) {
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00002720 while (*wp++ != NULL)
2721 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00002722 cp = *wp;
2723
2724 /* strip all initial assignments */
Denis Vlasenko7e497522008-02-12 09:51:03 +00002725 /* FIXME: not correct wrt PATH=yyy command etc */
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00002726 if (FLAG['x']) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002727 DBGPRINTF9(("FORKEXEC: echo'ing, cp=%p, wp=%p, owp=%p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00002728 cp, wp, owp));
Eric Andersen8401eea2004-08-04 19:16:54 +00002729 echo(cp ? wp : owp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002730 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002731
Denis Vlasenko7e497522008-02-12 09:51:03 +00002732 if (cp == NULL) {
2733 if (t->ioact == NULL) {
2734 while ((cp = *owp++) != NULL && assign(cp, COPYV))
2735 continue;
2736 DBGPRINTF(("FORKEXEC: returning setstatus(0)\n"));
2737 return setstatus(0);
2738 }
2739 } else { /* cp != NULL */
2740 bltin_name = cp;
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002741 bltin = inbuilt(cp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002742 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002743 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002744
Denis Vlasenko7e497522008-02-12 09:51:03 +00002745 forked = 0;
Denis Vlasenko509697f2008-03-02 12:49:39 +00002746 // We were pointing t->op_words to temporary (expanded) arg list:
2747 // t->op_words = wp;
Denis Vlasenkofe218832008-03-01 09:35:39 +00002748 // and restored it later (in execute()), but "break"
Denis Vlasenko509697f2008-03-02 12:49:39 +00002749 // longjmps away (at "Run builtin" below), leaving t->op_words clobbered!
Denis Vlasenkofe218832008-03-01 09:35:39 +00002750 // See http://bugs.busybox.net/view.php?id=846.
Denis Vlasenko509697f2008-03-02 12:49:39 +00002751 // Now we do not touch t->op_words, but separately pass wp as param list
Denis Vlasenko42cc3042008-03-24 02:05:58 +00002752 // to builtins
Denis Vlasenko7e497522008-02-12 09:51:03 +00002753 DBGPRINTF(("FORKEXEC: bltin %p, no_fork %d, owp %p\n", bltin,
2754 no_fork, owp));
2755 /* Don't fork if it is a lone builtin (not in pipe)
2756 * OR we are told to _not_ fork */
2757 if ((!bltin || pin || pout) /* not lone bltin AND */
2758 && !no_fork /* not told to avoid fork */
2759 ) {
2760 /* Save values in case child alters them after vfork */
Eric Andersenff9eee42001-06-29 04:57:14 +00002761 hpin = pin;
2762 hpout = pout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002763 hwp = *wp;
2764 hinteractive = interactive;
2765 hintr = intr;
2766 hbrklist = brklist;
2767 hexecflg = execflg;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002768
Eric Andersen12de6cf2004-08-04 19:19:10 +00002769 DBGPRINTF3(("FORKEXEC: calling vfork()...\n"));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002770 newpid = vfork();
Eric Andersen12de6cf2004-08-04 19:19:10 +00002771 if (newpid == -1) {
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00002772 DBGPRINTF(("FORKEXEC: ERROR, can't vfork()!\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002773 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002774 }
2775
Denis Vlasenko489f93e2007-02-01 01:43:16 +00002776 if (newpid > 0) { /* Parent */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002777 /* Restore values */
Eric Andersenff9eee42001-06-29 04:57:14 +00002778 pin = hpin;
2779 pout = hpout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002780 *wp = hwp;
2781 interactive = hinteractive;
2782 intr = hintr;
2783 brklist = hbrklist;
2784 execflg = hexecflg;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002785
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002786 closepipe(pin);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002787 return (pout == NULL ? setstatus(waitfor(newpid, 0)) : 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002788 }
2789
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002790 /* Child */
Denis Vlasenko7e497522008-02-12 09:51:03 +00002791 DBGPRINTF(("FORKEXEC: child process, bltin=%p (%s)\n", bltin, bltin_name));
Eric Andersenff9eee42001-06-29 04:57:14 +00002792 if (interactive) {
2793 signal(SIGINT, SIG_IGN);
2794 signal(SIGQUIT, SIG_IGN);
2795 resetsig = 1;
2796 }
2797 interactive = 0;
2798 intr = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002799 forked = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002800 brklist = 0;
2801 execflg = 0;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002802 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002803
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002804 if (owp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002805 while ((cp = *owp++) != NULL && assign(cp, COPYV))
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002806 if (!bltin)
Eric Andersenff9eee42001-06-29 04:57:14 +00002807 export(lookup(cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002808
Denis Vlasenko284d0fa2008-02-16 13:18:17 +00002809 if (pin) { /* NB: close _first_, then move fds! */
2810 close(pin[1]);
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00002811 xmove_fd(pin[0], 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002812 }
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002813 if (pout) {
Denis Vlasenko284d0fa2008-02-16 13:18:17 +00002814 close(pout[0]);
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00002815 xmove_fd(pout[1], 1);
Eric Andersenff9eee42001-06-29 04:57:14 +00002816 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002817
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002818 iopp = t->ioact;
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002819 if (iopp) {
2820 if (bltin && bltin != doexec) {
Denis Vlasenko7e497522008-02-12 09:51:03 +00002821 prs(bltin_name);
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00002822 err(": can't redirect shell command");
Eric Andersen12de6cf2004-08-04 19:19:10 +00002823 if (forked)
2824 _exit(-1);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002825 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002826 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002827 while (*iopp) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002828 if (iosetup(*iopp++, pin != NULL, pout != NULL)) {
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002829 /* system-detected error */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002830 if (forked)
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002831 _exit(-1);
2832 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002833 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002834 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002835 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002836
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002837 if (bltin) {
Denis Vlasenko7e497522008-02-12 09:51:03 +00002838 if (forked || pin || pout) {
2839 /* Builtin in pipe: disallowed */
2840 /* TODO: allow "exec"? */
2841 prs(bltin_name);
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00002842 err(": can't run builtin as part of pipe");
Denis Vlasenko7e497522008-02-12 09:51:03 +00002843 if (forked)
2844 _exit(-1);
2845 return -1;
2846 }
Denis Vlasenkofe218832008-03-01 09:35:39 +00002847 /* Run builtin */
2848 i = setstatus(bltin(t, wp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002849 if (forked)
2850 _exit(i);
2851 DBGPRINTF(("FORKEXEC: returning i=%d\n", i));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002852 return i;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002853 }
2854
Eric Andersenff9eee42001-06-29 04:57:14 +00002855 /* should use FIOCEXCL */
Eric Andersen8401eea2004-08-04 19:16:54 +00002856 for (i = FDBASE; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00002857 close(i);
2858 if (resetsig) {
2859 signal(SIGINT, SIG_DFL);
2860 signal(SIGQUIT, SIG_DFL);
2861 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002862
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002863 if (t->op_type == TPAREN)
Denis Vlasenko7e497522008-02-12 09:51:03 +00002864 _exit(execute(t->left, NOPIPE, NOPIPE, /* no_fork: */ 1));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002865 if (wp[0] == NULL)
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +00002866 _exit(EXIT_SUCCESS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002867
Eric Andersenfd7a4c82004-09-02 23:13:10 +00002868 cp = rexecve(wp[0], wp, makenv(0, NULL));
Eric Andersen8401eea2004-08-04 19:16:54 +00002869 prs(wp[0]);
2870 prs(": ");
Eric Andersen12de6cf2004-08-04 19:19:10 +00002871 err(cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00002872 if (!execflg)
2873 trap[0] = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002874
Denis Vlasenko7e497522008-02-12 09:51:03 +00002875 DBGPRINTF(("FORKEXEC: calling leave(), pid=%d\n", getpid()));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002876
Eric Andersenff9eee42001-06-29 04:57:14 +00002877 leave();
2878 /* NOTREACHED */
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00002879 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002880}
2881
2882/*
2883 * 0< 1> are ignored as required
2884 * within pipelines.
2885 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002886static int iosetup(struct ioword *iop, int pipein, int pipeout)
Eric Andersenff9eee42001-06-29 04:57:14 +00002887{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002888 int u = -1;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002889 char *cp = NULL;
2890 const char *msg;
Eric Andersenff9eee42001-06-29 04:57:14 +00002891
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002892 DBGPRINTF(("IOSETUP: iop %p, pipein %i, pipeout %i\n", iop,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002893 pipein, pipeout));
2894
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002895 if (iop->io_fd == IODEFAULT) /* take default */
2896 iop->io_fd = iop->io_flag & (IOREAD | IOHERE) ? 0 : 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002897
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002898 if (pipein && iop->io_fd == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002899 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002900
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002901 if (pipeout && iop->io_fd == 1)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002902 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002903
Eric Andersen8401eea2004-08-04 19:16:54 +00002904 msg = iop->io_flag & (IOREAD | IOHERE) ? "open" : "create";
Eric Andersenff9eee42001-06-29 04:57:14 +00002905 if ((iop->io_flag & IOHERE) == 0) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002906 cp = iop->io_name; /* huh?? */
2907 cp = evalstr(cp, DOSUB | DOTRIM);
2908 if (cp == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002909 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002910 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002911
Eric Andersenff9eee42001-06-29 04:57:14 +00002912 if (iop->io_flag & IODUP) {
2913 if (cp[1] || (!isdigit(*cp) && *cp != '-')) {
2914 prs(cp);
2915 err(": illegal >& argument");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002916 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002917 }
2918 if (*cp == '-')
2919 iop->io_flag = IOCLOSE;
Eric Andersen8401eea2004-08-04 19:16:54 +00002920 iop->io_flag &= ~(IOREAD | IOWRITE);
Eric Andersenff9eee42001-06-29 04:57:14 +00002921 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002922
Eric Andersenff9eee42001-06-29 04:57:14 +00002923 switch (iop->io_flag) {
2924 case IOREAD:
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00002925 u = open(cp, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00002926 break;
2927
2928 case IOHERE:
Eric Andersen8401eea2004-08-04 19:16:54 +00002929 case IOHERE | IOXHERE:
2930 u = herein(iop->io_name, iop->io_flag & IOXHERE);
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00002931 cp = (char*)"here file";
Eric Andersenff9eee42001-06-29 04:57:14 +00002932 break;
2933
Eric Andersen8401eea2004-08-04 19:16:54 +00002934 case IOWRITE | IOCAT:
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00002935 u = open(cp, O_WRONLY);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002936 if (u >= 0) {
Denis Vlasenkoea620772006-10-14 02:23:43 +00002937 lseek(u, (long) 0, SEEK_END);
Eric Andersenff9eee42001-06-29 04:57:14 +00002938 break;
2939 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002940 /* fall through to creation if >>file doesn't exist */
2941
Eric Andersenff9eee42001-06-29 04:57:14 +00002942 case IOWRITE:
2943 u = creat(cp, 0666);
2944 break;
2945
2946 case IODUP:
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002947 u = dup2(*cp - '0', iop->io_fd);
Eric Andersenff9eee42001-06-29 04:57:14 +00002948 break;
2949
2950 case IOCLOSE:
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002951 close(iop->io_fd);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002952 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002953 }
Denis Vlasenko7e497522008-02-12 09:51:03 +00002954
Eric Andersenff9eee42001-06-29 04:57:14 +00002955 if (u < 0) {
2956 prs(cp);
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00002957 prs(": can't ");
Eric Andersenff9eee42001-06-29 04:57:14 +00002958 warn(msg);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002959 return 1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00002960 }
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00002961 xmove_fd(u, iop->io_fd);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002962 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002963}
2964
Eric Andersenff9eee42001-06-29 04:57:14 +00002965/*
2966 * Enter a new loop level (marked for break/continue).
2967 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002968static void brkset(struct brkcon *bc)
Eric Andersenff9eee42001-06-29 04:57:14 +00002969{
2970 bc->nextlev = brklist;
2971 brklist = bc;
2972}
2973
2974/*
2975 * Wait for the last process created.
2976 * Print a message for each process found
2977 * that was killed by a signal.
2978 * Ignore interrupt signals while waiting
2979 * unless `canintr' is true.
2980 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002981static int waitfor(int lastpid, int canintr)
Eric Andersenff9eee42001-06-29 04:57:14 +00002982{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002983 int pid, rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00002984 int s;
Denis Vlasenko648b44f2008-02-12 06:04:06 +00002985 smallint oheedint = heedint;
Eric Andersenff9eee42001-06-29 04:57:14 +00002986
2987 heedint = 0;
2988 rv = 0;
2989 do {
2990 pid = wait(&s);
2991 if (pid == -1) {
2992 if (errno != EINTR || canintr)
2993 break;
2994 } else {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00002995 rv = WAITSIG(s);
2996 if (rv != 0) {
Denis Vlasenko80b8b392007-06-25 10:55:35 +00002997 if (rv < ARRAY_SIZE(signame)) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002998 if (signame[rv] != NULL) {
2999 if (pid != lastpid) {
3000 prn(pid);
3001 prs(": ");
3002 }
3003 prs(signame[rv]);
3004 }
3005 } else {
3006 if (pid != lastpid) {
3007 prn(pid);
3008 prs(": ");
3009 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003010 prs("Signal ");
3011 prn(rv);
3012 prs(" ");
Eric Andersenff9eee42001-06-29 04:57:14 +00003013 }
3014 if (WAITCORE(s))
3015 prs(" - core dumped");
Denis Vlasenko80b8b392007-06-25 10:55:35 +00003016 if (rv >= ARRAY_SIZE(signame) || signame[rv])
Eric Andersenff9eee42001-06-29 04:57:14 +00003017 prs("\n");
Mike Frysingerb81f97b2008-05-14 11:51:04 +00003018 rv |= 0x80;
Eric Andersenff9eee42001-06-29 04:57:14 +00003019 } else
3020 rv = WAITVAL(s);
3021 }
3022 } while (pid != lastpid);
3023 heedint = oheedint;
3024 if (intr) {
3025 if (interactive) {
3026 if (canintr)
3027 intr = 0;
3028 } else {
Eric Andersen8401eea2004-08-04 19:16:54 +00003029 if (exstat == 0)
3030 exstat = rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003031 onintr(0);
3032 }
3033 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003034 return rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003035}
3036
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003037static int setstatus(int s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003038{
3039 exstat = s;
3040 setval(lookup("?"), putn(s));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003041 return s;
Eric Andersenff9eee42001-06-29 04:57:14 +00003042}
3043
3044/*
3045 * PATH-searching interface to execve.
3046 * If getenv("PATH") were kept up-to-date,
3047 * execvp might be used.
3048 */
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003049static const char *rexecve(char *c, char **v, char **envp)
Eric Andersenff9eee42001-06-29 04:57:14 +00003050{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003051 const char *sp;
3052 char *tp;
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00003053 int asis = 0;
Eric Andersen1c039232001-07-07 00:05:55 +00003054 char *name = c;
Eric Andersen8401eea2004-08-04 19:16:54 +00003055
Denis Vlasenko80d14be2007-04-10 23:03:30 +00003056 if (ENABLE_FEATURE_SH_STANDALONE) {
Denis Vlasenko1aa7e472007-11-28 06:49:03 +00003057 if (find_applet_by_name(name) >= 0) {
Rob Landleya299efb2006-08-10 21:46:43 +00003058 /* We have to exec here since we vforked. Running
Denis Vlasenkoe4f2d062007-04-11 17:03:19 +00003059 * run_applet_and_exit() won't work and bad things
Rob Landleya299efb2006-08-10 21:46:43 +00003060 * will happen. */
Denis Vlasenkobdbbb7e2007-06-08 15:02:55 +00003061 execve(bb_busybox_exec_path, v, envp);
Rob Landleya299efb2006-08-10 21:46:43 +00003062 }
Eric Andersen1c039232001-07-07 00:05:55 +00003063 }
Eric Andersen1c039232001-07-07 00:05:55 +00003064
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003065 DBGPRINTF(("REXECVE: c=%p, v=%p, envp=%p\n", c, v, envp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003066
Eric Andersen8401eea2004-08-04 19:16:54 +00003067 sp = any('/', c) ? "" : path->value;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003068 asis = (*sp == '\0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003069 while (asis || *sp != '\0') {
3070 asis = 0;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003071 tp = global_env.linep;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003072 for (; *sp != '\0'; tp++) {
3073 *tp = *sp++;
3074 if (*tp == ':') {
3075 asis = (*sp == '\0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003076 break;
3077 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003078 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003079 if (tp != global_env.linep)
Eric Andersenff9eee42001-06-29 04:57:14 +00003080 *tp++ = '/';
Denis Vlasenko509697f2008-03-02 12:49:39 +00003081 strcpy(tp, c);
Eric Andersen1c039232001-07-07 00:05:55 +00003082
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003083 DBGPRINTF3(("REXECVE: global_env.linep is %s\n", global_env.linep));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003084
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003085 execve(global_env.linep, v, envp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003086
Eric Andersenff9eee42001-06-29 04:57:14 +00003087 switch (errno) {
3088 case ENOEXEC:
Denis Vlasenko447bd662008-05-30 22:28:32 +00003089 /* File is executable but file format isnt recognized */
3090 /* Run it as a shell script */
3091 /* (execve above didnt do it itself, unlike execvp) */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003092 *v = global_env.linep;
Denis Vlasenko509697f2008-03-02 12:49:39 +00003093 v--;
3094 tp = *v;
Denis Vlasenko447bd662008-05-30 22:28:32 +00003095 *v = (char*)DEFAULT_SHELL;
Glenn L McGrathdc4e75e2003-09-02 02:36:18 +00003096 execve(DEFAULT_SHELL, v, envp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003097 *v = tp;
Denis Vlasenko509697f2008-03-02 12:49:39 +00003098 return "no shell";
Eric Andersenff9eee42001-06-29 04:57:14 +00003099
3100 case ENOMEM:
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003101 return (char *) bb_msg_memory_exhausted;
Eric Andersenff9eee42001-06-29 04:57:14 +00003102
3103 case E2BIG:
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003104 return "argument list too long";
Eric Andersenff9eee42001-06-29 04:57:14 +00003105 }
3106 }
Denis Vlasenko447bd662008-05-30 22:28:32 +00003107 if (errno == ENOENT) {
3108 exstat = 127; /* standards require this */
3109 return "not found";
3110 }
3111 exstat = 126; /* mimic bash */
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00003112 return "can't execute";
Eric Andersenff9eee42001-06-29 04:57:14 +00003113}
3114
3115/*
3116 * Run the command produced by generator `f'
3117 * applied to stream `arg'.
3118 */
Eric Andersen8401eea2004-08-04 19:16:54 +00003119static int run(struct ioarg *argp, int (*f) (struct ioarg *))
Eric Andersenff9eee42001-06-29 04:57:14 +00003120{
3121 struct op *otree;
3122 struct wdblock *swdlist;
3123 struct wdblock *siolist;
3124 jmp_buf ev, rt;
3125 xint *ofail;
3126 int rv;
3127
3128#if __GNUC__
3129 /* Avoid longjmp clobbering */
3130 (void) &rv;
3131#endif
3132
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003133 DBGPRINTF(("RUN: enter, areanum %d, outtree %p, failpt %p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00003134 areanum, outtree, failpt));
3135
Eric Andersenff9eee42001-06-29 04:57:14 +00003136 areanum++;
3137 swdlist = wdlist;
3138 siolist = iolist;
3139 otree = outtree;
3140 ofail = failpt;
3141 rv = -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003142
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003143 errpt = ev;
3144 if (newenv(setjmp(errpt)) == 0) {
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00003145 wdlist = NULL;
3146 iolist = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00003147 pushio(argp, f);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003148 global_env.iobase = global_env.iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00003149 yynerrs = 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003150 failpt = rt;
3151 if (setjmp(failpt) == 0 && yyparse() == 0)
Denis Vlasenko7e497522008-02-12 09:51:03 +00003152 rv = execute(outtree, NOPIPE, NOPIPE, /* no_fork: */ 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003153 quitenv();
Eric Andersen12de6cf2004-08-04 19:19:10 +00003154 } else {
3155 DBGPRINTF(("RUN: error from newenv()!\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00003156 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00003157
Eric Andersenff9eee42001-06-29 04:57:14 +00003158 wdlist = swdlist;
3159 iolist = siolist;
3160 failpt = ofail;
3161 outtree = otree;
3162 freearea(areanum--);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003163
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003164 return rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003165}
3166
3167/* -------- do.c -------- */
3168
3169/*
3170 * built-in commands: doX
3171 */
3172
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003173static int dohelp(struct op *t UNUSED_PARAM, char **args UNUSED_PARAM)
Eric Andersen1c039232001-07-07 00:05:55 +00003174{
3175 int col;
3176 const struct builtincmd *x;
3177
Denis Vlasenko34d4d892009-04-04 20:24:37 +00003178 printf("\n"
3179 "Built-in commands:\n"
3180 "------------------\n");
Eric Andersen1c039232001-07-07 00:05:55 +00003181
Denis Vlasenko95cb3262007-04-09 03:06:34 +00003182 col = 0;
3183 x = builtincmds;
3184 while (x->name) {
3185 col += printf("%c%s", ((col == 0) ? '\t' : ' '), x->name);
Eric Andersen1c039232001-07-07 00:05:55 +00003186 if (col > 60) {
Denis Vlasenko4daad902007-09-27 10:20:47 +00003187 bb_putchar('\n');
Eric Andersen1c039232001-07-07 00:05:55 +00003188 col = 0;
3189 }
Denis Vlasenko95cb3262007-04-09 03:06:34 +00003190 x++;
Eric Andersen1c039232001-07-07 00:05:55 +00003191 }
Denis Vlasenko80d14be2007-04-10 23:03:30 +00003192#if ENABLE_FEATURE_SH_STANDALONE
Eric Andersen1c039232001-07-07 00:05:55 +00003193 {
Denis Vlasenko1aa7e472007-11-28 06:49:03 +00003194 const char *applet = applet_names;
Eric Andersen1c039232001-07-07 00:05:55 +00003195
Denis Vlasenko1aa7e472007-11-28 06:49:03 +00003196 while (*applet) {
3197 col += printf("%c%s", ((col == 0) ? '\t' : ' '), applet);
Eric Andersen1c039232001-07-07 00:05:55 +00003198 if (col > 60) {
Denis Vlasenko4daad902007-09-27 10:20:47 +00003199 bb_putchar('\n');
Eric Andersen1c039232001-07-07 00:05:55 +00003200 col = 0;
3201 }
Denis Vlasenko1aa7e472007-11-28 06:49:03 +00003202 applet += strlen(applet) + 1;
Eric Andersen1c039232001-07-07 00:05:55 +00003203 }
3204 }
3205#endif
Denis Vlasenko0ee39992006-12-24 15:23:28 +00003206 puts("\n");
Eric Andersen1c039232001-07-07 00:05:55 +00003207 return EXIT_SUCCESS;
3208}
3209
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003210static int dolabel(struct op *t UNUSED_PARAM, char **args UNUSED_PARAM)
Eric Andersenff9eee42001-06-29 04:57:14 +00003211{
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003212 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003213}
3214
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003215static int dochdir(struct op *t UNUSED_PARAM, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003216{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003217 const char *cp, *er;
Eric Andersenff9eee42001-06-29 04:57:14 +00003218
Denis Vlasenkofe218832008-03-01 09:35:39 +00003219 cp = args[1];
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003220 if (cp == NULL) {
3221 cp = homedir->value;
Denis Vlasenkod244c5e2007-02-09 17:30:14 +00003222 if (cp != NULL)
3223 goto do_cd;
3224 er = ": no home directory";
3225 } else {
3226 do_cd:
3227 if (chdir(cp) >= 0)
3228 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003229 er = ": bad directory";
Denis Vlasenkod244c5e2007-02-09 17:30:14 +00003230 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003231 prs(cp != NULL ? cp : "cd");
Eric Andersenff9eee42001-06-29 04:57:14 +00003232 err(er);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003233 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003234}
3235
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003236static int doshift(struct op *t UNUSED_PARAM, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003237{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003238 int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003239
Denis Vlasenkofe218832008-03-01 09:35:39 +00003240 n = args[1] ? getn(args[1]) : 1;
Eric Andersen8401eea2004-08-04 19:16:54 +00003241 if (dolc < n) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003242 err("nothing to shift");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003243 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003244 }
3245 dolv[n] = dolv[0];
3246 dolv += n;
3247 dolc -= n;
3248 setval(lookup("#"), putn(dolc));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003249 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003250}
3251
3252/*
3253 * execute login and newgrp directly
3254 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003255static int dologin(struct op *t UNUSED_PARAM, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003256{
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003257 const char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003258
3259 if (interactive) {
3260 signal(SIGINT, SIG_DFL);
3261 signal(SIGQUIT, SIG_DFL);
3262 }
Denis Vlasenkofe218832008-03-01 09:35:39 +00003263 cp = rexecve(args[0], args, makenv(0, NULL));
3264 prs(args[0]);
Eric Andersen8401eea2004-08-04 19:16:54 +00003265 prs(": ");
3266 err(cp);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003267 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003268}
3269
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003270static int doumask(struct op *t UNUSED_PARAM, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003271{
Denis Vlasenko7e497522008-02-12 09:51:03 +00003272 int i;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003273 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003274
Denis Vlasenkofe218832008-03-01 09:35:39 +00003275 cp = args[1];
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003276 if (cp == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003277 i = umask(0);
3278 umask(i);
Denis Vlasenko7e497522008-02-12 09:51:03 +00003279 printf("%04o\n", i);
Eric Andersenff9eee42001-06-29 04:57:14 +00003280 } else {
Denis Vlasenko7e497522008-02-12 09:51:03 +00003281 i = bb_strtou(cp, NULL, 8);
3282 if (errno) {
3283 err("umask: bad octal number");
3284 return 1;
3285 }
3286 umask(i);
Eric Andersenff9eee42001-06-29 04:57:14 +00003287 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003288 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003289}
3290
Denis Vlasenkofe218832008-03-01 09:35:39 +00003291static int doexec(struct op *t, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003292{
Eric Andersenff9eee42001-06-29 04:57:14 +00003293 jmp_buf ex;
3294 xint *ofail;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003295 char **sv_words;
Eric Andersenff9eee42001-06-29 04:57:14 +00003296
3297 t->ioact = NULL;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003298 if (!args[1])
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003299 return 1;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003300
Eric Andersenff9eee42001-06-29 04:57:14 +00003301 execflg = 1;
3302 ofail = failpt;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003303 failpt = ex;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003304
Denis Vlasenko509697f2008-03-02 12:49:39 +00003305 sv_words = t->op_words;
3306 t->op_words = args + 1;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003307// TODO: test what will happen with "exec break" -
Denis Vlasenko509697f2008-03-02 12:49:39 +00003308// will it leave t->op_words pointing to garbage?
Denis Vlasenkofe218832008-03-01 09:35:39 +00003309// (see http://bugs.busybox.net/view.php?id=846)
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003310 if (setjmp(failpt) == 0)
Denis Vlasenko7e497522008-02-12 09:51:03 +00003311 execute(t, NOPIPE, NOPIPE, /* no_fork: */ 1);
Denis Vlasenko509697f2008-03-02 12:49:39 +00003312 t->op_words = sv_words;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003313
Eric Andersenff9eee42001-06-29 04:57:14 +00003314 failpt = ofail;
3315 execflg = 0;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003316
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003317 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003318}
3319
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003320static int dodot(struct op *t UNUSED_PARAM, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003321{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003322 int i;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003323 const char *sp;
3324 char *tp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003325 char *cp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003326 int maltmp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003327
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003328 DBGPRINTF(("DODOT: enter, t=%p, tleft %p, tright %p, global_env.linep is %s\n",
3329 t, t->left, t->right, ((global_env.linep == NULL) ? "NULL" : global_env.linep)));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003330
Denis Vlasenkofe218832008-03-01 09:35:39 +00003331 cp = args[1];
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003332 if (cp == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00003333 DBGPRINTF(("DODOT: bad args, ret 0\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003334 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003335 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003336 DBGPRINTF(("DODOT: cp is %s\n", cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003337
Eric Andersen8401eea2004-08-04 19:16:54 +00003338 sp = any('/', cp) ? ":" : path->value;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003339
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003340 DBGPRINTF(("DODOT: sp is %s, global_env.linep is %s\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00003341 ((sp == NULL) ? "NULL" : sp),
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003342 ((global_env.linep == NULL) ? "NULL" : global_env.linep)));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003343
Eric Andersenff9eee42001-06-29 04:57:14 +00003344 while (*sp) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003345 tp = global_env.linep;
Eric Andersenff9eee42001-06-29 04:57:14 +00003346 while (*sp && (*tp = *sp++) != ':')
3347 tp++;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003348 if (tp != global_env.linep)
Eric Andersenff9eee42001-06-29 04:57:14 +00003349 *tp++ = '/';
Denis Vlasenko509697f2008-03-02 12:49:39 +00003350 strcpy(tp, cp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003351
3352 /* Original code */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003353 i = open(global_env.linep, O_RDONLY);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003354 if (i >= 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003355 exstat = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003356 maltmp = remap(i);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003357 DBGPRINTF(("DODOT: remap=%d, exstat=%d, global_env.iofd %d, i %d, global_env.linep is %s\n",
3358 maltmp, exstat, global_env.iofd, i, global_env.linep));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003359
3360 next(maltmp); /* Basically a PUSHIO */
3361
3362 DBGPRINTF(("DODOT: returning exstat=%d\n", exstat));
3363
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003364 return exstat;
Eric Andersenff9eee42001-06-29 04:57:14 +00003365 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003366 } /* while */
Eric Andersen12de6cf2004-08-04 19:19:10 +00003367
Eric Andersenff9eee42001-06-29 04:57:14 +00003368 prs(cp);
3369 err(": not found");
Eric Andersen12de6cf2004-08-04 19:19:10 +00003370
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003371 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003372}
3373
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003374static int dowait(struct op *t UNUSED_PARAM, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003375{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003376 int i;
3377 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003378
Denis Vlasenkofe218832008-03-01 09:35:39 +00003379 cp = args[1];
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003380 if (cp != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003381 i = getn(cp);
3382 if (i == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003383 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003384 } else
3385 i = -1;
3386 setstatus(waitfor(i, 1));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003387 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003388}
3389
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003390static int doread(struct op *t UNUSED_PARAM, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003391{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003392 char *cp, **wp;
3393 int nb = 0;
3394 int nl = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003395
Denis Vlasenkofe218832008-03-01 09:35:39 +00003396 if (args[1] == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003397 err("Usage: read name ...");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003398 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003399 }
Denis Vlasenkofe218832008-03-01 09:35:39 +00003400 for (wp = args + 1; *wp; wp++) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003401 for (cp = global_env.linep; !nl && cp < elinep - 1; cp++) {
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +00003402 nb = nonblock_safe_read(STDIN_FILENO, cp, sizeof(*cp));
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003403 if (nb != sizeof(*cp))
Eric Andersenff9eee42001-06-29 04:57:14 +00003404 break;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003405 nl = (*cp == '\n');
3406 if (nl || (wp[1] && any(*cp, ifs->value)))
3407 break;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003408 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003409 *cp = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00003410 if (nb <= 0)
3411 break;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003412 setval(lookup(*wp), global_env.linep);
Eric Andersenff9eee42001-06-29 04:57:14 +00003413 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003414 return nb <= 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003415}
3416
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003417static int doeval(struct op *t UNUSED_PARAM, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003418{
Denis Vlasenkofe218832008-03-01 09:35:39 +00003419 return RUN(awordlist, args + 1, wdchar);
Eric Andersenff9eee42001-06-29 04:57:14 +00003420}
3421
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003422static int dotrap(struct op *t UNUSED_PARAM, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003423{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003424 int n, i;
3425 int resetsig;
Eric Andersenff9eee42001-06-29 04:57:14 +00003426
Denis Vlasenkofe218832008-03-01 09:35:39 +00003427 if (args[1] == NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00003428 for (i = 0; i <= _NSIG; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00003429 if (trap[i]) {
3430 prn(i);
3431 prs(": ");
3432 prs(trap[i]);
3433 prs("\n");
3434 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003435 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003436 }
Denis Vlasenkofe218832008-03-01 09:35:39 +00003437 resetsig = isdigit(args[1][0]);
3438 for (i = resetsig ? 1 : 2; args[i] != NULL; ++i) {
3439 n = getsig(args[i]);
Eric Andersenff9eee42001-06-29 04:57:14 +00003440 freecell(trap[n]);
3441 trap[n] = 0;
3442 if (!resetsig) {
Denis Vlasenkofe218832008-03-01 09:35:39 +00003443 if (args[1][0] != '\0') {
3444 trap[n] = strsave(args[1], 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003445 setsig(n, sig);
3446 } else
3447 setsig(n, SIG_IGN);
3448 } else {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00003449 if (interactive) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003450 if (n == SIGINT)
3451 setsig(n, onintr);
3452 else
Eric Andersen8401eea2004-08-04 19:16:54 +00003453 setsig(n, n == SIGQUIT ? SIG_IGN : SIG_DFL);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00003454 } else
Eric Andersenff9eee42001-06-29 04:57:14 +00003455 setsig(n, SIG_DFL);
3456 }
3457 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003458 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003459}
3460
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003461static int getsig(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003462{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003463 int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003464
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003465 n = getn(s);
3466 if (n < 0 || n > _NSIG) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003467 err("trap: bad signal number");
3468 n = 0;
3469 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003470 return n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003471}
3472
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003473static void setsig(int n, sighandler_t f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003474{
3475 if (n == 0)
3476 return;
3477 if (signal(n, SIG_IGN) != SIG_IGN || ourtrap[n]) {
3478 ourtrap[n] = 1;
3479 signal(n, f);
3480 }
3481}
3482
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003483static int getn(char *as)
Eric Andersenff9eee42001-06-29 04:57:14 +00003484{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003485 char *s;
3486 int n, m;
Eric Andersenff9eee42001-06-29 04:57:14 +00003487
3488 s = as;
3489 m = 1;
3490 if (*s == '-') {
3491 m = -1;
3492 s++;
3493 }
3494 for (n = 0; isdigit(*s); s++)
Eric Andersen8401eea2004-08-04 19:16:54 +00003495 n = (n * 10) + (*s - '0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003496 if (*s) {
3497 prs(as);
3498 err(": bad number");
3499 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003500 return n * m;
Eric Andersenff9eee42001-06-29 04:57:14 +00003501}
3502
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003503static int dobreak(struct op *t UNUSED_PARAM, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003504{
Denis Vlasenkofe218832008-03-01 09:35:39 +00003505 return brkcontin(args[1], 1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003506}
3507
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003508static int docontinue(struct op *t UNUSED_PARAM, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003509{
Denis Vlasenkofe218832008-03-01 09:35:39 +00003510 return brkcontin(args[1], 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003511}
3512
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003513static int brkcontin(char *cp, int val)
Eric Andersenff9eee42001-06-29 04:57:14 +00003514{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003515 struct brkcon *bc;
3516 int nl;
Eric Andersenff9eee42001-06-29 04:57:14 +00003517
Eric Andersen8401eea2004-08-04 19:16:54 +00003518 nl = cp == NULL ? 1 : getn(cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003519 if (nl <= 0)
3520 nl = 999;
3521 do {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003522 bc = brklist;
3523 if (bc == NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00003524 break;
3525 brklist = bc->nextlev;
3526 } while (--nl);
3527 if (nl) {
3528 err("bad break/continue level");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003529 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003530 }
Denis Vlasenko648b44f2008-02-12 06:04:06 +00003531 isbreak = (val != 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003532 longjmp(bc->brkpt, 1);
3533 /* NOTREACHED */
3534}
3535
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003536static int doexit(struct op *t UNUSED_PARAM, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003537{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003538 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003539
3540 execflg = 0;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003541 cp = args[1];
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003542 if (cp != NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00003543 setstatus(getn(cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003544
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003545 DBGPRINTF(("DOEXIT: calling leave(), t=%p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003546
Eric Andersenff9eee42001-06-29 04:57:14 +00003547 leave();
3548 /* NOTREACHED */
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003549 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003550}
3551
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003552static int doexport(struct op *t UNUSED_PARAM, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003553{
Denis Vlasenkofe218832008-03-01 09:35:39 +00003554 rdexp(args + 1, export, EXPORT);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003555 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003556}
3557
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003558static int doreadonly(struct op *t UNUSED_PARAM, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003559{
Denis Vlasenkofe218832008-03-01 09:35:39 +00003560 rdexp(args + 1, ronly, RONLY);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003561 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003562}
3563
Eric Andersen8401eea2004-08-04 19:16:54 +00003564static void rdexp(char **wp, void (*f) (struct var *), int key)
Eric Andersenff9eee42001-06-29 04:57:14 +00003565{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003566 DBGPRINTF6(("RDEXP: enter, wp=%p, func=%p, key=%d\n", wp, f, key));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003567 DBGPRINTF6(("RDEXP: *wp=%s\n", *wp));
3568
Eric Andersenff9eee42001-06-29 04:57:14 +00003569 if (*wp != NULL) {
Matt Kraaif69bfc72001-07-12 19:39:59 +00003570 for (; *wp != NULL; wp++) {
3571 if (isassign(*wp)) {
3572 char *cp;
Eric Andersen8401eea2004-08-04 19:16:54 +00003573
Matt Kraaif69bfc72001-07-12 19:39:59 +00003574 assign(*wp, COPYV);
Denis Vlasenko509697f2008-03-02 12:49:39 +00003575 for (cp = *wp; *cp != '='; cp++)
3576 continue;
Matt Kraaif69bfc72001-07-12 19:39:59 +00003577 *cp = '\0';
3578 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003579 if (checkname(*wp))
Eric Andersen8401eea2004-08-04 19:16:54 +00003580 (*f) (lookup(*wp));
Eric Andersenff9eee42001-06-29 04:57:14 +00003581 else
3582 badid(*wp);
Matt Kraaif69bfc72001-07-12 19:39:59 +00003583 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003584 } else
3585 putvlist(key, 1);
3586}
3587
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003588static void badid(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003589{
3590 prs(s);
3591 err(": bad identifier");
3592}
3593
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003594static int doset(struct op *t UNUSED_PARAM, char **args)
Eric Andersenff9eee42001-06-29 04:57:14 +00003595{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003596 struct var *vp;
3597 char *cp;
3598 int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003599
Denis Vlasenkofe218832008-03-01 09:35:39 +00003600 cp = args[1];
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003601 if (cp == NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003602 for (vp = vlist; vp; vp = vp->next)
Denis Vlasenko73c571a2009-03-09 00:12:37 +00003603 varput(vp->name, STDOUT_FILENO);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003604 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003605 }
3606 if (*cp == '-') {
Denis Vlasenkofe218832008-03-01 09:35:39 +00003607 args++;
Eric Andersenff9eee42001-06-29 04:57:14 +00003608 if (*++cp == 0)
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003609 FLAG['x'] = FLAG['v'] = 0;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003610 else {
3611 for (; *cp; cp++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003612 switch (*cp) {
3613 case 'e':
3614 if (!interactive)
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003615 FLAG['e']++;
Eric Andersenff9eee42001-06-29 04:57:14 +00003616 break;
3617
3618 default:
Eric Andersen8401eea2004-08-04 19:16:54 +00003619 if (*cp >= 'a' && *cp <= 'z')
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003620 FLAG[(int) *cp]++;
Eric Andersenff9eee42001-06-29 04:57:14 +00003621 break;
3622 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003623 }
3624 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003625 setdash();
3626 }
Denis Vlasenkofe218832008-03-01 09:35:39 +00003627 if (args[1]) {
3628 args[0] = dolv[0];
3629 for (n = 1; args[n]; n++)
3630 setarea((char *) args[n], 0);
Eric Andersen8401eea2004-08-04 19:16:54 +00003631 dolc = n - 1;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003632 dolv = args;
Eric Andersenff9eee42001-06-29 04:57:14 +00003633 setval(lookup("#"), putn(dolc));
Eric Andersen8401eea2004-08-04 19:16:54 +00003634 setarea((char *) (dolv - 1), 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003635 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003636 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003637}
3638
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003639static void varput(char *s, int out)
Eric Andersenff9eee42001-06-29 04:57:14 +00003640{
Matt Kraai69edfec2001-08-06 14:14:18 +00003641 if (isalnum(*s) || *s == '_') {
Denis Vlasenko73c571a2009-03-09 00:12:37 +00003642 xwrite_str(out, s);
3643 xwrite(out, "\n", 1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003644 }
3645}
3646
3647
3648/*
3649 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
3650 * This file contains code for the times builtin.
Eric Andersenff9eee42001-06-29 04:57:14 +00003651 */
Denis Vlasenkofe218832008-03-01 09:35:39 +00003652static void times_fmt(char *buf, clock_t val, unsigned clk_tck)
3653{
3654 unsigned min, sec;
3655 if (sizeof(val) > sizeof(int))
3656 sec = ((unsigned long)val) / clk_tck;
3657 else
3658 sec = ((unsigned)val) / clk_tck;
3659 min = sec / 60;
3660#if ENABLE_DESKTOP
3661 sprintf(buf, "%um%u.%03us", min, (sec - min * 60),
3662 /* msec: */ ((unsigned)(val - (clock_t)sec * clk_tck)) * 1000 / clk_tck
3663 );
3664#else
3665 sprintf(buf, "%um%us", min, (sec - min * 60));
3666#endif
3667}
3668
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003669static int dotimes(struct op *t UNUSED_PARAM, char **args UNUSED_PARAM)
Eric Andersenff9eee42001-06-29 04:57:14 +00003670{
3671 struct tms buf;
Denis Vlasenkofe218832008-03-01 09:35:39 +00003672 unsigned clk_tck = sysconf(_SC_CLK_TCK);
3673 /* How much do we need for "NmN.NNNs" ? */
3674 enum { TIMEBUF_SIZE = sizeof(int)*3 + sizeof(int)*3 + 6 };
3675 char u[TIMEBUF_SIZE], s[TIMEBUF_SIZE];
3676 char cu[TIMEBUF_SIZE], cs[TIMEBUF_SIZE];
Eric Andersenff9eee42001-06-29 04:57:14 +00003677
3678 times(&buf);
Denis Vlasenkofe218832008-03-01 09:35:39 +00003679
3680 times_fmt(u, buf.tms_utime, clk_tck);
3681 times_fmt(s, buf.tms_stime, clk_tck);
3682 times_fmt(cu, buf.tms_cutime, clk_tck);
3683 times_fmt(cs, buf.tms_cstime, clk_tck);
3684
3685 printf("%s %s\n%s %s\n", u, s, cu, cs);
Eric Andersenff9eee42001-06-29 04:57:14 +00003686 return 0;
3687}
3688
3689
Eric Andersenff9eee42001-06-29 04:57:14 +00003690/* -------- eval.c -------- */
3691
3692/*
3693 * ${}
3694 * `command`
3695 * blank interpretation
3696 * quoting
3697 * glob
3698 */
3699
Eric Andersen8401eea2004-08-04 19:16:54 +00003700static char **eval(char **ap, int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003701{
3702 struct wdblock *wb;
3703 char **wp;
3704 char **wf;
3705 jmp_buf ev;
3706
3707#if __GNUC__
3708 /* Avoid longjmp clobbering */
3709 (void) &wp;
3710 (void) &ap;
3711#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00003712
3713 DBGPRINTF4(("EVAL: enter, f=%d\n", f));
3714
Eric Andersenff9eee42001-06-29 04:57:14 +00003715 wp = NULL;
3716 wb = NULL;
3717 wf = NULL;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003718 errpt = ev;
3719 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003720 while (*ap && isassign(*ap))
3721 expand(*ap++, &wb, f & ~DOGLOB);
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003722 if (FLAG['k']) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003723 for (wf = ap; *wf; wf++) {
3724 if (isassign(*wf))
3725 expand(*wf, &wb, f & ~DOGLOB);
3726 }
3727 }
Denis Vlasenko648b44f2008-02-12 06:04:06 +00003728 for (wb = addword((char *) NULL, wb); *ap; ap++) {
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00003729 if (!FLAG['k'] || !isassign(*ap))
Eric Andersenff9eee42001-06-29 04:57:14 +00003730 expand(*ap, &wb, f & ~DOKEY);
3731 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003732 wb = addword((char *) 0, wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00003733 wp = getwords(wb);
3734 quitenv();
3735 } else
3736 gflg = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003737
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003738 return gflg ? (char **) NULL : wp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003739}
3740
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003741
Eric Andersenff9eee42001-06-29 04:57:14 +00003742/*
3743 * Make the exported environment from the exported
3744 * names in the dictionary. Keyword assignments
3745 * will already have been done.
3746 */
Eric Andersenfd7a4c82004-09-02 23:13:10 +00003747static char **makenv(int all, struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00003748{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003749 struct var *vp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003750
3751 DBGPRINTF5(("MAKENV: enter, all=%d\n", all));
Eric Andersenff9eee42001-06-29 04:57:14 +00003752
Eric Andersenff9eee42001-06-29 04:57:14 +00003753 for (vp = vlist; vp; vp = vp->next)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003754 if (all || vp->status & EXPORT)
Eric Andersenff9eee42001-06-29 04:57:14 +00003755 wb = addword(vp->name, wb);
Eric Andersen8401eea2004-08-04 19:16:54 +00003756 wb = addword((char *) 0, wb);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003757 return getwords(wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00003758}
3759
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003760static int expand(const char *cp, struct wdblock **wbp, int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003761{
3762 jmp_buf ev;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003763 char *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003764
3765#if __GNUC__
3766 /* Avoid longjmp clobbering */
3767 (void) &cp;
3768#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00003769
3770 DBGPRINTF3(("EXPAND: enter, f=%d\n", f));
3771
Eric Andersenff9eee42001-06-29 04:57:14 +00003772 gflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003773
Eric Andersenff9eee42001-06-29 04:57:14 +00003774 if (cp == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003775 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003776
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003777 if (!anys("$`'\"", cp) && !anys(ifs->value, cp)
3778 && ((f & DOGLOB) == 0 || !anys("[*?", cp))
3779 ) {
3780 xp = strsave(cp, areanum);
Eric Andersenff9eee42001-06-29 04:57:14 +00003781 if (f & DOTRIM)
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003782 unquote(xp);
3783 *wbp = addword(xp, *wbp);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003784 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003785 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003786 errpt = ev;
3787 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003788 PUSHIO(aword, cp, strchar);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003789 global_env.iobase = global_env.iop;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003790 while ((xp = blank(f)) && gflg == 0) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003791 global_env.linep = xp;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003792 xp = strsave(xp, areanum);
Eric Andersen8401eea2004-08-04 19:16:54 +00003793 if ((f & DOGLOB) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003794 if (f & DOTRIM)
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003795 unquote(xp);
3796 *wbp = addword(xp, *wbp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003797 } else
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003798 *wbp = glob(xp, *wbp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003799 }
3800 quitenv();
3801 } else
3802 gflg = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003803 return gflg == 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003804}
3805
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003806static char *evalstr(char *cp, int f)
3807{
3808 struct wdblock *wb;
3809
3810 DBGPRINTF6(("EVALSTR: enter, cp=%p, f=%d\n", cp, f));
3811
3812 wb = NULL;
3813 if (expand(cp, &wb, f)) {
3814 if (wb == NULL || wb->w_nword == 0
3815 || (cp = wb->w_words[0]) == NULL
3816 ) {
Denis Vlasenko8e858e22007-03-07 09:35:43 +00003817// TODO: I suspect that
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00003818// char *evalstr(char *cp, int f) is actually
3819// const char *evalstr(const char *cp, int f)!
3820 cp = (char*)"";
3821 }
3822 DELETE(wb);
3823 } else
3824 cp = NULL;
3825 return cp;
3826}
3827
3828
Eric Andersenff9eee42001-06-29 04:57:14 +00003829/*
3830 * Blank interpretation and quoting
3831 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003832static char *blank(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003833{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003834 int c, c1;
3835 char *sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003836 int scanequals, foundequals;
3837
Eric Andersen12de6cf2004-08-04 19:19:10 +00003838 DBGPRINTF3(("BLANK: enter, f=%d\n", f));
3839
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003840 sp = global_env.linep;
Eric Andersenff9eee42001-06-29 04:57:14 +00003841 scanequals = f & DOKEY;
3842 foundequals = 0;
3843
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003844 loop:
3845 c = subgetc('"', foundequals);
3846 switch (c) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003847 case 0:
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003848 if (sp == global_env.linep)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003849 return 0;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003850 *global_env.linep++ = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003851 return sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003852
3853 default:
3854 if (f & DOBLANK && any(c, ifs->value))
3855 goto loop;
3856 break;
3857
3858 case '"':
3859 case '\'':
3860 scanequals = 0;
3861 if (INSUB())
3862 break;
3863 for (c1 = c; (c = subgetc(c1, 1)) != c1;) {
3864 if (c == 0)
3865 break;
3866 if (c == '\'' || !any(c, "$`\""))
3867 c |= QUOTE;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003868 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003869 }
3870 c = 0;
3871 }
3872 unget(c);
Matt Kraai69edfec2001-08-06 14:14:18 +00003873 if (!isalpha(c) && c != '_')
Eric Andersenff9eee42001-06-29 04:57:14 +00003874 scanequals = 0;
3875 for (;;) {
3876 c = subgetc('"', foundequals);
3877 if (c == 0 ||
Eric Andersen8401eea2004-08-04 19:16:54 +00003878 f & (DOBLANK && any(c, ifs->value)) ||
3879 (!INSUB() && any(c, "\"'"))) {
3880 scanequals = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003881 unget(c);
3882 if (any(c, "\"'"))
3883 goto loop;
3884 break;
3885 }
3886 if (scanequals) {
3887 if (c == '=') {
3888 foundequals = 1;
Eric Andersen8401eea2004-08-04 19:16:54 +00003889 scanequals = 0;
3890 } else if (!isalnum(c) && c != '_')
Eric Andersenff9eee42001-06-29 04:57:14 +00003891 scanequals = 0;
3892 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003893 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003894 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003895 *global_env.linep++ = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003896 return sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003897}
3898
3899/*
3900 * Get characters, substituting for ` and $
3901 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003902static int subgetc(char ec, int quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00003903{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003904 char c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003905
3906 DBGPRINTF3(("SUBGETC: enter, quoted=%d\n", quoted));
Eric Andersenff9eee42001-06-29 04:57:14 +00003907
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00003908 again:
Eric Andersenff9eee42001-06-29 04:57:14 +00003909 c = my_getc(ec);
3910 if (!INSUB() && ec != '\'') {
3911 if (c == '`') {
3912 if (grave(quoted) == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003913 return 0;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003914 global_env.iop->task = XGRAVE;
Eric Andersenff9eee42001-06-29 04:57:14 +00003915 goto again;
3916 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003917 if (c == '$') {
3918 c = dollar(quoted);
3919 if (c == 0) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003920 global_env.iop->task = XDOLL;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003921 goto again;
3922 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003923 }
3924 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003925 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003926}
3927
3928/*
3929 * Prepare to generate the string returned by ${} substitution.
3930 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003931static int dollar(int quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00003932{
3933 int otask;
3934 struct io *oiop;
3935 char *dolp;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003936 char *s, c, *cp = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00003937 struct var *vp;
3938
Eric Andersen12de6cf2004-08-04 19:19:10 +00003939 DBGPRINTF3(("DOLLAR: enter, quoted=%d\n", quoted));
3940
Eric Andersenff9eee42001-06-29 04:57:14 +00003941 c = readc();
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003942 s = global_env.linep;
Eric Andersenff9eee42001-06-29 04:57:14 +00003943 if (c != '{') {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003944 *global_env.linep++ = c;
Matt Kraai69edfec2001-08-06 14:14:18 +00003945 if (isalpha(c) || c == '_') {
Eric Andersen8401eea2004-08-04 19:16:54 +00003946 while ((c = readc()) != 0 && (isalnum(c) || c == '_'))
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003947 if (global_env.linep < elinep)
3948 *global_env.linep++ = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003949 unget(c);
3950 }
3951 c = 0;
3952 } else {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003953 oiop = global_env.iop;
3954 otask = global_env.iop->task;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003955
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003956 global_env.iop->task = XOTHER;
Eric Andersen8401eea2004-08-04 19:16:54 +00003957 while ((c = subgetc('"', 0)) != 0 && c != '}' && c != '\n')
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003958 if (global_env.linep < elinep)
3959 *global_env.linep++ = c;
3960 if (oiop == global_env.iop)
3961 global_env.iop->task = otask;
Eric Andersenff9eee42001-06-29 04:57:14 +00003962 if (c != '}') {
3963 err("unclosed ${");
Denis Vlasenko648b44f2008-02-12 06:04:06 +00003964 gflg = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003965 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003966 }
3967 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003968 if (global_env.linep >= elinep) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003969 err("string in ${} too long");
Denis Vlasenko648b44f2008-02-12 06:04:06 +00003970 gflg = 1;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003971 global_env.linep -= 10;
Eric Andersenff9eee42001-06-29 04:57:14 +00003972 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003973 *global_env.linep = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003974 if (*s)
Eric Andersen8401eea2004-08-04 19:16:54 +00003975 for (cp = s + 1; *cp; cp++)
Eric Andersenff9eee42001-06-29 04:57:14 +00003976 if (any(*cp, "=-+?")) {
3977 c = *cp;
3978 *cp++ = 0;
3979 break;
3980 }
3981 if (s[1] == 0 && (*s == '*' || *s == '@')) {
3982 if (dolc > 1) {
3983 /* currently this does not distinguish $* and $@ */
3984 /* should check dollar */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00003985 global_env.linep = s;
Eric Andersen8401eea2004-08-04 19:16:54 +00003986 PUSHIO(awordlist, dolv + 1, dolchar);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003987 return 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00003988 } else { /* trap the nasty ${=} */
Eric Andersenff9eee42001-06-29 04:57:14 +00003989 s[0] = '1';
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003990 s[1] = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00003991 }
3992 }
3993 vp = lookup(s);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00003994 dolp = vp->value;
3995 if (dolp == null) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003996 switch (c) {
3997 case '=':
3998 if (isdigit(*s)) {
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00003999 err("can't use ${...=...} with $n");
Denis Vlasenko648b44f2008-02-12 06:04:06 +00004000 gflg = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004001 break;
4002 }
4003 setval(vp, cp);
4004 dolp = vp->value;
4005 break;
4006
4007 case '-':
4008 dolp = strsave(cp, areanum);
4009 break;
4010
4011 case '?':
4012 if (*cp == 0) {
4013 prs("missing value for ");
4014 err(s);
4015 } else
4016 err(cp);
Denis Vlasenko648b44f2008-02-12 06:04:06 +00004017 gflg = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004018 break;
4019 }
4020 } else if (c == '+')
4021 dolp = strsave(cp, areanum);
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00004022 if (FLAG['u'] && dolp == null) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004023 prs("unset variable: ");
4024 err(s);
Denis Vlasenko648b44f2008-02-12 06:04:06 +00004025 gflg = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004026 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004027 global_env.linep = s;
Eric Andersenff9eee42001-06-29 04:57:14 +00004028 PUSHIO(aword, dolp, quoted ? qstrchar : strchar);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004029 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004030}
4031
4032/*
4033 * Run the command in `...` and read its output.
4034 */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004035
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004036static int grave(int quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00004037{
Denis Vlasenko55f30b02007-03-24 22:42:29 +00004038 /* moved to G: static char child_cmd[LINELIM]; */
4039
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004040 const char *cp;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004041 int i;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004042 int j;
Eric Andersenff9eee42001-06-29 04:57:14 +00004043 int pf[2];
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004044 const char *src;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004045 char *dest;
4046 int count;
4047 int ignore;
4048 int ignore_once;
4049 char *argument_list[4];
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004050 struct wdblock *wb = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004051
4052#if __GNUC__
4053 /* Avoid longjmp clobbering */
4054 (void) &cp;
4055#endif
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004056
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004057 for (cp = global_env.iop->argp->aword; *cp != '`'; cp++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004058 if (*cp == 0) {
4059 err("no closing `");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004060 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004061 }
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004062 }
Eric Andersen737f5fb2003-03-14 16:05:59 +00004063
4064 /* string copy with dollar expansion */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004065 src = global_env.iop->argp->aword;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004066 dest = child_cmd;
4067 count = 0;
4068 ignore = 0;
4069 ignore_once = 0;
4070 while ((*src != '`') && (count < LINELIM)) {
4071 if (*src == '\'')
4072 ignore = !ignore;
4073 if (*src == '\\')
4074 ignore_once = 1;
4075 if (*src == '$' && !ignore && !ignore_once) {
4076 struct var *vp;
Denis Vlasenkoab801872007-12-02 08:35:37 +00004077 /* moved to G to reduce stack usage
Eric Andersen737f5fb2003-03-14 16:05:59 +00004078 char var_name[LINELIM];
4079 char alt_value[LINELIM];
Denis Vlasenkoab801872007-12-02 08:35:37 +00004080 */
4081#define var_name (G.grave__var_name)
4082#define alt_value (G.grave__alt_value)
Eric Andersen737f5fb2003-03-14 16:05:59 +00004083 int var_index = 0;
4084 int alt_index = 0;
4085 char operator = 0;
4086 int braces = 0;
4087 char *value;
4088
4089 src++;
4090 if (*src == '{') {
4091 braces = 1;
4092 src++;
4093 }
4094
4095 var_name[var_index++] = *src++;
Paul Fox54690dc2005-07-20 18:33:12 +00004096 while (isalnum(*src) || *src=='_')
Eric Andersen737f5fb2003-03-14 16:05:59 +00004097 var_name[var_index++] = *src++;
4098 var_name[var_index] = 0;
4099
4100 if (braces) {
4101 switch (*src) {
4102 case '}':
4103 break;
4104 case '-':
4105 case '=':
4106 case '+':
4107 case '?':
Eric Andersen8401eea2004-08-04 19:16:54 +00004108 operator = * src;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004109 break;
4110 default:
4111 err("unclosed ${\n");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004112 return 0;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004113 }
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004114 if (operator) {
Eric Andersen737f5fb2003-03-14 16:05:59 +00004115 src++;
4116 while (*src && (*src != '}')) {
4117 alt_value[alt_index++] = *src++;
4118 }
4119 alt_value[alt_index] = 0;
4120 if (*src != '}') {
4121 err("unclosed ${\n");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004122 return 0;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004123 }
4124 }
4125 src++;
4126 }
4127
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004128 if (isalpha(*var_name)) {
4129 /* let subshell handle it instead */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004130
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004131 char *namep = var_name;
4132
4133 *dest++ = '$';
4134 if (braces)
4135 *dest++ = '{';
4136 while (*namep)
4137 *dest++ = *namep++;
4138 if (operator) {
4139 char *altp = alt_value;
4140 *dest++ = operator;
4141 while (*altp)
4142 *dest++ = *altp++;
4143 }
4144 if (braces)
4145 *dest++ = '}';
4146
4147 wb = addword(lookup(var_name)->name, wb);
4148 } else {
4149 /* expand */
4150
4151 vp = lookup(var_name);
4152 if (vp->value != null)
4153 value = (operator == '+') ?
4154 alt_value : vp->value;
4155 else if (operator == '?') {
4156 err(alt_value);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004157 return 0;
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004158 } else if (alt_index && (operator != '+')) {
4159 value = alt_value;
4160 if (operator == '=')
4161 setval(vp, value);
4162 } else
4163 continue;
4164
4165 while (*value && (count < LINELIM)) {
4166 *dest++ = *value++;
4167 count++;
4168 }
Eric Andersen737f5fb2003-03-14 16:05:59 +00004169 }
Denis Vlasenkoab801872007-12-02 08:35:37 +00004170#undef var_name
4171#undef alt_value
Eric Andersen737f5fb2003-03-14 16:05:59 +00004172 } else {
4173 *dest++ = *src++;
4174 count++;
4175 ignore_once = 0;
4176 }
4177 }
4178 *dest = '\0';
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004179
Eric Andersenff9eee42001-06-29 04:57:14 +00004180 if (openpipe(pf) < 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004181 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004182
Denis Vlasenko509697f2008-03-02 12:49:39 +00004183 while ((i = vfork()) == -1 && errno == EAGAIN)
4184 continue;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004185
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004186 DBGPRINTF3(("GRAVE: i is %p\n", io));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004187
Eric Andersen737f5fb2003-03-14 16:05:59 +00004188 if (i < 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004189 closepipe(pf);
Eric Andersen8401eea2004-08-04 19:16:54 +00004190 err((char *) bb_msg_memory_exhausted);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004191 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004192 }
4193 if (i != 0) {
Denis Vlasenkofb0eba72008-01-02 19:55:04 +00004194 waitpid(i, NULL, 0); // safe_waitpid?
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004195 global_env.iop->argp->aword = ++cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004196 close(pf[1]);
Eric Andersen8401eea2004-08-04 19:16:54 +00004197 PUSHIO(afile, remap(pf[0]),
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004198 (int (*)(struct ioarg *)) ((quoted) ? qgravechar : gravechar));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004199 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004200 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004201 /* allow trapped signals */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004202 /* XXX - Maybe this signal stuff should go as well? */
Eric Andersen8401eea2004-08-04 19:16:54 +00004203 for (j = 0; j <= _NSIG; j++)
Eric Andersen737f5fb2003-03-14 16:05:59 +00004204 if (ourtrap[j] && signal(j, SIG_IGN) != SIG_IGN)
4205 signal(j, SIG_DFL);
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004206
Denis Vlasenko2b54aaa2007-05-09 22:16:08 +00004207 /* Testcase where below checks are needed:
4208 * close stdout & run this script:
4209 * files=`ls`
4210 * echo "$files" >zz
4211 */
4212 xmove_fd(pf[1], 1);
Denis Vlasenko847fa772008-01-28 22:45:43 +00004213 if (pf[0] != 1)
4214 close(pf[0]);
Eric Andersen737f5fb2003-03-14 16:05:59 +00004215
Eric Andersen8401eea2004-08-04 19:16:54 +00004216 argument_list[0] = (char *) DEFAULT_SHELL;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004217 argument_list[1] = (char *) "-c";
Eric Andersen737f5fb2003-03-14 16:05:59 +00004218 argument_list[2] = child_cmd;
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004219 argument_list[3] = NULL;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004220
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004221 cp = rexecve(argument_list[0], argument_list, makenv(1, wb));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004222 prs(argument_list[0]);
4223 prs(": ");
4224 err(cp);
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +00004225 _exit(EXIT_FAILURE);
Eric Andersenff9eee42001-06-29 04:57:14 +00004226}
4227
Eric Andersen737f5fb2003-03-14 16:05:59 +00004228
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004229static char *unquote(char *as)
Eric Andersenff9eee42001-06-29 04:57:14 +00004230{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004231 char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00004232
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004233 s = as;
4234 if (s != NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00004235 while (*s)
4236 *s++ &= ~QUOTE;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004237 return as;
Eric Andersenff9eee42001-06-29 04:57:14 +00004238}
4239
4240/* -------- glob.c -------- */
4241
4242/*
4243 * glob
4244 */
4245
4246#define scopy(x) strsave((x), areanum)
4247#define BLKSIZ 512
4248#define NDENT ((BLKSIZ+sizeof(struct dirent)-1)/sizeof(struct dirent))
4249
Eric Andersen8401eea2004-08-04 19:16:54 +00004250static struct wdblock *cl, *nl;
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00004251static const char spcl[] ALIGN1= "[?*";
Eric Andersenff9eee42001-06-29 04:57:14 +00004252
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004253static struct wdblock *glob(char *cp, struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004254{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004255 int i;
4256 char *pp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004257
4258 if (cp == 0)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004259 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004260 i = 0;
4261 for (pp = cp; *pp; pp++)
4262 if (any(*pp, spcl))
4263 i++;
4264 else if (!any(*pp & ~QUOTE, spcl))
4265 *pp &= ~QUOTE;
4266 if (i != 0) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004267 for (cl = addword(scopy(cp), NULL); anyspcl(cl); cl = nl) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004268 nl = newword(cl->w_nword * 2);
4269 for (i = 0; i < cl->w_nword; i++) { /* for each argument */
Eric Andersenff9eee42001-06-29 04:57:14 +00004270 for (pp = cl->w_words[i]; *pp; pp++)
4271 if (any(*pp, spcl)) {
4272 globname(cl->w_words[i], pp);
4273 break;
4274 }
4275 if (*pp == '\0')
4276 nl = addword(scopy(cl->w_words[i]), nl);
4277 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004278 for (i = 0; i < cl->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004279 DELETE(cl->w_words[i]);
4280 DELETE(cl);
4281 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004282 if (cl->w_nword) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004283 for (i = 0; i < cl->w_nword; i++)
Denis Vlasenkofb290382008-03-02 12:51:26 +00004284 unquote(cl->w_words[i]);
4285 qsort_string_vector(cl->w_words, cl->w_nword);
4286 for (i = 0; i < cl->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004287 wb = addword(cl->w_words[i], wb);
4288 DELETE(cl);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004289 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004290 }
4291 }
4292 wb = addword(unquote(cp), wb);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004293 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004294}
4295
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004296static void globname(char *we, char *pp)
Eric Andersenff9eee42001-06-29 04:57:14 +00004297{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004298 char *np, *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004299 char *name, *gp, *dp;
4300 int k;
4301 DIR *dirp;
4302 struct dirent *de;
Eric Andersen8401eea2004-08-04 19:16:54 +00004303 char dname[NAME_MAX + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00004304 struct stat dbuf;
4305
4306 for (np = we; np != pp; pp--)
4307 if (pp[-1] == '/')
4308 break;
Denis Vlasenkofb290382008-03-02 12:51:26 +00004309 dp = cp = get_space((int) (pp - np) + 3);
4310 while (np < pp)
Eric Andersenff9eee42001-06-29 04:57:14 +00004311 *cp++ = *np++;
4312 *cp++ = '.';
4313 *cp = '\0';
Denis Vlasenkofb290382008-03-02 12:51:26 +00004314 gp = cp = get_space(strlen(pp) + 1);
4315 while (*np && *np != '/')
Eric Andersenff9eee42001-06-29 04:57:14 +00004316 *cp++ = *np++;
4317 *cp = '\0';
4318 dirp = opendir(dp);
4319 if (dirp == 0) {
4320 DELETE(dp);
4321 DELETE(gp);
4322 return;
4323 }
4324 dname[NAME_MAX] = '\0';
Eric Andersen8401eea2004-08-04 19:16:54 +00004325 while ((de = readdir(dirp)) != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004326 /* XXX Hmmm... What this could be? (abial) */
Denis Vlasenkoed9d6212008-06-09 07:44:19 +00004327 /* if (ent[j].d_ino == 0) continue;
Eric Andersen8401eea2004-08-04 19:16:54 +00004328 */
Eric Andersenff9eee42001-06-29 04:57:14 +00004329 strncpy(dname, de->d_name, NAME_MAX);
Eric Andersen8401eea2004-08-04 19:16:54 +00004330 if (dname[0] == '.')
4331 if (*gp != '.')
4332 continue;
4333 for (k = 0; k < NAME_MAX; k++)
4334 if (any(dname[k], spcl))
4335 dname[k] |= QUOTE;
4336 if (gmatch(dname, gp)) {
4337 name = generate(we, pp, dname, np);
4338 if (*np && !anys(np, spcl)) {
4339 if (stat(name, &dbuf)) {
4340 DELETE(name);
Eric Andersenff9eee42001-06-29 04:57:14 +00004341 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00004342 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004343 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004344 nl = addword(name, nl);
4345 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004346 }
4347 closedir(dirp);
4348 DELETE(dp);
4349 DELETE(gp);
4350}
4351
4352/*
4353 * generate a pathname as below.
4354 * start..end1 / middle end
4355 * the slashes come for free
4356 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004357static char *generate(char *start1, char *end1, char *middle, char *end)
Eric Andersenff9eee42001-06-29 04:57:14 +00004358{
4359 char *p;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004360 char *op, *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004361
Denis Vlasenko509697f2008-03-02 12:49:39 +00004362 p = op = get_space((int)(end1 - start1) + strlen(middle) + strlen(end) + 2);
4363 xp = start1;
4364 while (xp != end1)
Eric Andersenff9eee42001-06-29 04:57:14 +00004365 *op++ = *xp++;
Denis Vlasenko509697f2008-03-02 12:49:39 +00004366 xp = middle;
4367 while (*xp != '\0')
4368 *op++ = *xp++;
4369 strcpy(op, end);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004370 return p;
Eric Andersenff9eee42001-06-29 04:57:14 +00004371}
4372
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004373static int anyspcl(struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004374{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004375 int i;
4376 char **wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004377
4378 wd = wb->w_words;
Eric Andersen8401eea2004-08-04 19:16:54 +00004379 for (i = 0; i < wb->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004380 if (anys(spcl, *wd++))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004381 return 1;
4382 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004383}
4384
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004385
Eric Andersenff9eee42001-06-29 04:57:14 +00004386/* -------- word.c -------- */
4387
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004388static struct wdblock *newword(int nw)
Eric Andersenff9eee42001-06-29 04:57:14 +00004389{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004390 struct wdblock *wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004391
Denis Vlasenko509697f2008-03-02 12:49:39 +00004392 wb = get_space(sizeof(*wb) + nw * sizeof(char *));
Eric Andersenff9eee42001-06-29 04:57:14 +00004393 wb->w_bsize = nw;
4394 wb->w_nword = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004395 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004396}
4397
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004398static struct wdblock *addword(char *wd, struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004399{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004400 struct wdblock *wb2;
4401 int nw;
Eric Andersenff9eee42001-06-29 04:57:14 +00004402
4403 if (wb == NULL)
4404 wb = newword(NSTART);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004405 nw = wb->w_nword;
4406 if (nw >= wb->w_bsize) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004407 wb2 = newword(nw * 2);
Eric Andersen8401eea2004-08-04 19:16:54 +00004408 memcpy((char *) wb2->w_words, (char *) wb->w_words,
4409 nw * sizeof(char *));
Eric Andersenff9eee42001-06-29 04:57:14 +00004410 wb2->w_nword = nw;
4411 DELETE(wb);
4412 wb = wb2;
4413 }
4414 wb->w_words[wb->w_nword++] = wd;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004415 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004416}
Eric Andersen8401eea2004-08-04 19:16:54 +00004417
Denis Vlasenkoe4712752007-04-14 15:08:41 +00004418static char **getwords(struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004419{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004420 char **wd;
4421 int nb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004422
4423 if (wb == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004424 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004425 if (wb->w_nword == 0) {
4426 DELETE(wb);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004427 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004428 }
Denis Vlasenko509697f2008-03-02 12:49:39 +00004429 nb = sizeof(*wd) * wb->w_nword;
4430 wd = get_space(nb);
Denis Vlasenkofb290382008-03-02 12:51:26 +00004431 memcpy(wd, wb->w_words, nb);
4432 DELETE(wb); /* perhaps should done by caller */
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004433 return wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004434}
4435
Eric Andersenff9eee42001-06-29 04:57:14 +00004436
4437/* -------- io.c -------- */
4438
4439/*
4440 * shell IO
4441 */
4442
Eric Andersen8401eea2004-08-04 19:16:54 +00004443static int my_getc(int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00004444{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004445 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004446
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004447 if (global_env.linep > elinep) {
Denis Vlasenko509697f2008-03-02 12:49:39 +00004448 while ((c = readc()) != '\n' && c)
4449 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00004450 err("input line too long");
Denis Vlasenko648b44f2008-02-12 06:04:06 +00004451 gflg = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004452 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004453 }
4454 c = readc();
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004455 if ((ec != '\'') && (ec != '`') && (global_env.iop->task != XGRAVE)) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004456 if (c == '\\') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004457 c = readc();
4458 if (c == '\n' && ec != '\"')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004459 return my_getc(ec);
Eric Andersenff9eee42001-06-29 04:57:14 +00004460 c |= QUOTE;
4461 }
4462 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004463 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004464}
4465
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004466static void unget(int c)
Eric Andersenff9eee42001-06-29 04:57:14 +00004467{
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004468 if (global_env.iop >= global_env.iobase)
4469 global_env.iop->peekc = c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004470}
4471
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004472static int eofc(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00004473{
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004474 return global_env.iop < global_env.iobase || (global_env.iop->peekc == 0 && global_env.iop->prev == 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004475}
4476
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004477static int readc(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00004478{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004479 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004480
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004481 RCPRINTF(("READC: global_env.iop %p, global_env.iobase %p\n", global_env.iop, global_env.iobase));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004482
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004483 for (; global_env.iop >= global_env.iobase; global_env.iop--) {
4484 RCPRINTF(("READC: global_env.iop %p, peekc 0x%x\n", global_env.iop, global_env.iop->peekc));
4485 c = global_env.iop->peekc;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004486 if (c != '\0') {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004487 global_env.iop->peekc = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004488 return c;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004489 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004490 if (global_env.iop->prev != 0) {
4491 c = (*global_env.iop->iofn)(global_env.iop->argp, global_env.iop);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004492 if (c != '\0') {
4493 if (c == -1) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004494 global_env.iop++;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004495 continue;
Eric Andersen8401eea2004-08-04 19:16:54 +00004496 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004497 if (global_env.iop == iostack)
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004498 ioecho(c);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004499 global_env.iop->prev = c;
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00004500 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004501 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004502 if (global_env.iop->task == XIO && global_env.iop->prev != '\n') {
4503 global_env.iop->prev = 0;
4504 if (global_env.iop == iostack)
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004505 ioecho('\n');
4506 return '\n';
Eric Andersen8401eea2004-08-04 19:16:54 +00004507 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004508 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004509 if (global_env.iop->task == XIO) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004510 if (multiline) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004511 global_env.iop->prev = 0;
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00004512 return 0;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004513 }
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004514 if (interactive && global_env.iop == iostack + 1) {
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004515#if ENABLE_FEATURE_EDITING
4516 current_prompt = prompt->value;
4517#else
4518 prs(prompt->value);
4519#endif
4520 }
4521 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004522 } /* FOR */
4523
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004524 if (global_env.iop >= iostack) {
4525 RCPRINTF(("READC: return 0, global_env.iop %p\n", global_env.iop));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004526 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004527 }
4528
4529 DBGPRINTF(("READC: leave()...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00004530 leave();
4531 /* NOTREACHED */
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004532 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004533}
4534
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004535static void ioecho(char c)
Eric Andersenff9eee42001-06-29 04:57:14 +00004536{
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00004537 if (FLAG['v'])
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +00004538 write(STDERR_FILENO, &c, sizeof c);
Eric Andersenff9eee42001-06-29 04:57:14 +00004539}
4540
Eric Andersen8401eea2004-08-04 19:16:54 +00004541static void pushio(struct ioarg *argp, int (*fn) (struct ioarg *))
Eric Andersenff9eee42001-06-29 04:57:14 +00004542{
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004543 DBGPRINTF(("PUSHIO: argp %p, argp->afid 0x%x, global_env.iop %p\n", argp,
4544 argp->afid, global_env.iop));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004545
4546 /* Set env ptr for io source to next array spot and check for array overflow */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004547 if (++global_env.iop >= &iostack[NPUSH]) {
4548 global_env.iop--;
Eric Andersenff9eee42001-06-29 04:57:14 +00004549 err("Shell input nested too deeply");
Denis Vlasenko648b44f2008-02-12 06:04:06 +00004550 gflg = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004551 return;
4552 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004553
4554 /* We did not overflow the NPUSH array spots so setup data structs */
4555
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004556 global_env.iop->iofn = (int (*)(struct ioarg *, struct io *)) fn; /* Store data source func ptr */
Eric Andersenff9eee42001-06-29 04:57:14 +00004557
4558 if (argp->afid != AFID_NOBUF)
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004559 global_env.iop->argp = argp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004560 else {
Eric Andersen12de6cf2004-08-04 19:19:10 +00004561
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004562 global_env.iop->argp = ioargstack + (global_env.iop - iostack); /* MAL - index into stack */
4563 *global_env.iop->argp = *argp; /* copy data from temp area into stack spot */
Eric Andersen12de6cf2004-08-04 19:19:10 +00004564
4565 /* MAL - mainbuf is for 1st data source (command line?) and all nested use a single shared buffer? */
4566
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004567 if (global_env.iop == &iostack[0])
4568 global_env.iop->argp->afbuf = &mainbuf;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004569 else
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004570 global_env.iop->argp->afbuf = &sharedbuf;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004571
4572 /* MAL - if not a termimal AND (commandline OR readable file) then give it a buffer id? */
4573 /* This line appears to be active when running scripts from command line */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004574 if ((isatty(global_env.iop->argp->afile) == 0)
4575 && (global_env.iop == &iostack[0]
4576 || lseek(global_env.iop->argp->afile, 0L, SEEK_CUR) != -1)) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00004577 if (++bufid == AFID_NOBUF) /* counter rollover check, AFID_NOBUF = 11111111 */
4578 bufid = AFID_ID; /* AFID_ID = 0 */
4579
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004580 global_env.iop->argp->afid = bufid; /* assign buffer id */
Eric Andersen8401eea2004-08-04 19:16:54 +00004581 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004582
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004583 DBGPRINTF(("PUSHIO: iostack %p, global_env.iop %p, afbuf %p\n",
4584 iostack, global_env.iop, global_env.iop->argp->afbuf));
4585 DBGPRINTF(("PUSHIO: mbuf %p, sbuf %p, bid %d, global_env.iop %p\n",
4586 &mainbuf, &sharedbuf, bufid, global_env.iop));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004587
Eric Andersenff9eee42001-06-29 04:57:14 +00004588 }
4589
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004590 global_env.iop->prev = ~'\n';
4591 global_env.iop->peekc = 0;
4592 global_env.iop->xchar = 0;
4593 global_env.iop->nlcount = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004594
Eric Andersenff9eee42001-06-29 04:57:14 +00004595 if (fn == filechar || fn == linechar)
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004596 global_env.iop->task = XIO;
Eric Andersen8401eea2004-08-04 19:16:54 +00004597 else if (fn == (int (*)(struct ioarg *)) gravechar
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00004598 || fn == (int (*)(struct ioarg *)) qgravechar)
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004599 global_env.iop->task = XGRAVE;
Eric Andersenff9eee42001-06-29 04:57:14 +00004600 else
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004601 global_env.iop->task = XOTHER;
Eric Andersenff9eee42001-06-29 04:57:14 +00004602}
4603
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004604static struct io *setbase(struct io *ip)
Eric Andersenff9eee42001-06-29 04:57:14 +00004605{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004606 struct io *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004607
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004608 xp = global_env.iobase;
4609 global_env.iobase = ip;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004610 return xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004611}
4612
4613/*
4614 * Input generating functions
4615 */
4616
4617/*
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00004618 * Produce the characters of a string, then a newline, then NUL.
Eric Andersenff9eee42001-06-29 04:57:14 +00004619 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004620static int nlchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004621{
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00004622 char c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004623
4624 if (ap->aword == NULL)
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00004625 return '\0';
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004626 c = *ap->aword++;
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00004627 if (c == '\0') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004628 ap->aword = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004629 return '\n';
Eric Andersenff9eee42001-06-29 04:57:14 +00004630 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004631 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004632}
4633
4634/*
4635 * Given a list of words, produce the characters
4636 * in them, with a space after each word.
4637 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004638static int wdchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004639{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004640 char c;
4641 char **wl;
Eric Andersenff9eee42001-06-29 04:57:14 +00004642
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004643 wl = ap->awordlist;
4644 if (wl == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004645 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004646 if (*wl != NULL) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004647 c = *(*wl)++;
4648 if (c != 0)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004649 return c & 0177;
Eric Andersenff9eee42001-06-29 04:57:14 +00004650 ap->awordlist++;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004651 return ' ';
Eric Andersenff9eee42001-06-29 04:57:14 +00004652 }
4653 ap->awordlist = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004654 return '\n';
Eric Andersenff9eee42001-06-29 04:57:14 +00004655}
4656
4657/*
4658 * Return the characters of a list of words,
4659 * producing a space between them.
4660 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004661static int dolchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004662{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004663 char *wp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004664
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004665 wp = *ap->awordlist++;
4666 if (wp != NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004667 PUSHIO(aword, wp, *ap->awordlist == NULL ? strchar : xxchar);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004668 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004669 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004670 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004671}
4672
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004673static int xxchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004674{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004675 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004676
4677 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004678 return 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004679 c = *ap->aword++;
4680 if (c == '\0') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004681 ap->aword = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004682 return ' ';
Eric Andersenff9eee42001-06-29 04:57:14 +00004683 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004684 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004685}
4686
4687/*
4688 * Produce the characters from a single word (string).
4689 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004690static int strchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004691{
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004692 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004693 return 0;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004694 return *ap->aword++;
Eric Andersenff9eee42001-06-29 04:57:14 +00004695}
4696
4697/*
4698 * Produce quoted characters from a single word (string).
4699 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004700static int qstrchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004701{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004702 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004703
Denis Vlasenkob2abef32007-01-01 18:18:04 +00004704 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004705 return 0;
Denis Vlasenkob2abef32007-01-01 18:18:04 +00004706 c = *ap->aword++;
4707 if (c)
4708 c |= QUOTE;
4709 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004710}
4711
4712/*
4713 * Return the characters from a file.
4714 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004715static int filechar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004716{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004717 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004718 char c;
4719 struct iobuf *bp = ap->afbuf;
4720
4721 if (ap->afid != AFID_NOBUF) {
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004722 i = (ap->afid != bp->id);
4723 if (i || bp->bufp == bp->ebufp) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004724 if (i)
Denis Vlasenkoea620772006-10-14 02:23:43 +00004725 lseek(ap->afile, ap->afpos, SEEK_SET);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004726
Denis Vlasenkoe376d452008-02-20 22:23:24 +00004727 i = nonblock_safe_read(ap->afile, bp->buf, sizeof(bp->buf));
Eric Andersen8401eea2004-08-04 19:16:54 +00004728 if (i <= 0) {
4729 closef(ap->afile);
4730 return 0;
4731 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004732
Eric Andersen8401eea2004-08-04 19:16:54 +00004733 bp->id = ap->afid;
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004734 bp->bufp = bp->buf;
4735 bp->ebufp = bp->bufp + i;
Eric Andersen8401eea2004-08-04 19:16:54 +00004736 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004737
Eric Andersen8401eea2004-08-04 19:16:54 +00004738 ap->afpos++;
4739 return *bp->bufp++ & 0177;
Eric Andersenff9eee42001-06-29 04:57:14 +00004740 }
Denis Vlasenko38f63192007-01-22 09:03:07 +00004741#if ENABLE_FEATURE_EDITING
Eric Andersen737f5fb2003-03-14 16:05:59 +00004742 if (interactive && isatty(ap->afile)) {
Denis Vlasenko55f30b02007-03-24 22:42:29 +00004743 /* moved to G: static char filechar_cmdbuf[BUFSIZ]; */
Eric Andersen8401eea2004-08-04 19:16:54 +00004744 static int position = 0, size = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004745
Eric Andersen8401eea2004-08-04 19:16:54 +00004746 while (size == 0 || position >= size) {
Denis Vlasenko6e602c42008-02-02 18:50:50 +00004747 size = read_line_input(current_prompt, filechar_cmdbuf, BUFSIZ, line_input_state);
4748 if (size < 0) /* Error/EOF */
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +00004749 exit(EXIT_SUCCESS);
Eric Andersen8401eea2004-08-04 19:16:54 +00004750 position = 0;
Denis Vlasenko6e602c42008-02-02 18:50:50 +00004751 /* if Ctrl-C, size == 0 and loop will repeat */
Eric Andersen8401eea2004-08-04 19:16:54 +00004752 }
Denis Vlasenko55f30b02007-03-24 22:42:29 +00004753 c = filechar_cmdbuf[position];
Eric Andersen8401eea2004-08-04 19:16:54 +00004754 position++;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004755 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004756 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004757#endif
Denis Vlasenkoe376d452008-02-20 22:23:24 +00004758 i = nonblock_safe_read(ap->afile, &c, sizeof(c));
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004759 return i == sizeof(c) ? (c & 0x7f) : (closef(ap->afile), 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004760}
4761
4762/*
4763 * Return the characters from a here temp file.
4764 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004765static int herechar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004766{
4767 char c;
4768
Denis Vlasenkoe376d452008-02-20 22:23:24 +00004769 if (nonblock_safe_read(ap->afile, &c, sizeof(c)) != sizeof(c)) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004770 close(ap->afile);
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004771 c = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00004772 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004773 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004774}
4775
4776/*
4777 * Return the characters produced by a process (`...`).
4778 * Quote them if required, and remove any trailing newline characters.
4779 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004780static int gravechar(struct ioarg *ap, struct io *iop)
Eric Andersenff9eee42001-06-29 04:57:14 +00004781{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004782 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004783
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004784 c = qgravechar(ap, iop) & ~QUOTE;
4785 if (c == '\n')
Eric Andersenff9eee42001-06-29 04:57:14 +00004786 c = ' ';
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004787 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004788}
4789
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004790static int qgravechar(struct ioarg *ap, struct io *iop)
Eric Andersenff9eee42001-06-29 04:57:14 +00004791{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004792 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004793
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004794 DBGPRINTF3(("QGRAVECHAR: enter, ap=%p, iop=%p\n", ap, iop));
Eric Andersenff9eee42001-06-29 04:57:14 +00004795
4796 if (iop->xchar) {
4797 if (iop->nlcount) {
4798 iop->nlcount--;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004799 return '\n' | QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00004800 }
4801 c = iop->xchar;
4802 iop->xchar = 0;
4803 } else if ((c = filechar(ap)) == '\n') {
4804 iop->nlcount = 1;
4805 while ((c = filechar(ap)) == '\n')
4806 iop->nlcount++;
4807 iop->xchar = c;
4808 if (c == 0)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004809 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004810 iop->nlcount--;
4811 c = '\n';
4812 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004813 return c != 0 ? c | QUOTE : 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004814}
4815
4816/*
4817 * Return a single command (usually the first line) from a file.
4818 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004819static int linechar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004820{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004821 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004822
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004823 c = filechar(ap);
4824 if (c == '\n') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004825 if (!multiline) {
4826 closef(ap->afile);
Eric Andersen8401eea2004-08-04 19:16:54 +00004827 ap->afile = -1; /* illegal value */
Eric Andersenff9eee42001-06-29 04:57:14 +00004828 }
4829 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004830 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004831}
4832
Eric Andersenff9eee42001-06-29 04:57:14 +00004833/*
Denis Vlasenkoed9d6212008-06-09 07:44:19 +00004834 * Remap fd into shell's fd space
Eric Andersenff9eee42001-06-29 04:57:14 +00004835 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004836static int remap(int fd)
Eric Andersenff9eee42001-06-29 04:57:14 +00004837{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004838 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004839 int map[NOFILE];
Eric Andersen12de6cf2004-08-04 19:19:10 +00004840 int newfd;
4841
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004842 DBGPRINTF(("REMAP: fd=%d, global_env.iofd=%d\n", fd, global_env.iofd));
Eric Andersenff9eee42001-06-29 04:57:14 +00004843
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004844 if (fd < global_env.iofd) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004845 for (i = 0; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004846 map[i] = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004847
Eric Andersenff9eee42001-06-29 04:57:14 +00004848 do {
4849 map[fd] = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004850 newfd = dup(fd);
4851 fd = newfd;
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004852 } while (fd >= 0 && fd < global_env.iofd);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004853
Eric Andersen8401eea2004-08-04 19:16:54 +00004854 for (i = 0; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004855 if (map[i])
4856 close(i);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004857
Eric Andersenff9eee42001-06-29 04:57:14 +00004858 if (fd < 0)
4859 err("too many files open in shell");
4860 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004861
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004862 return fd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004863}
4864
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004865static int openpipe(int *pv)
Eric Andersenff9eee42001-06-29 04:57:14 +00004866{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004867 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004868
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004869 i = pipe(pv);
4870 if (i < 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00004871 err("can't create pipe - try again");
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004872 return i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004873}
4874
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004875static void closepipe(int *pv)
Eric Andersenff9eee42001-06-29 04:57:14 +00004876{
4877 if (pv != NULL) {
Denis Vlasenkoa5f2cd32008-02-11 18:10:06 +00004878 close(pv[0]);
4879 close(pv[1]);
Eric Andersenff9eee42001-06-29 04:57:14 +00004880 }
4881}
4882
Denis Vlasenko1e3b0682007-02-01 01:43:54 +00004883
Eric Andersenff9eee42001-06-29 04:57:14 +00004884/* -------- here.c -------- */
4885
4886/*
4887 * here documents
4888 */
4889
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004890static void markhere(char *s, struct ioword *iop)
Eric Andersenff9eee42001-06-29 04:57:14 +00004891{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004892 struct here *h, *lh;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004893
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004894 DBGPRINTF7(("MARKHERE: enter, s=%p\n", s));
Eric Andersenff9eee42001-06-29 04:57:14 +00004895
Denis Vlasenko509697f2008-03-02 12:49:39 +00004896 h = get_space(sizeof(struct here));
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004897 if (h == NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00004898 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004899
Eric Andersenff9eee42001-06-29 04:57:14 +00004900 h->h_tag = evalstr(s, DOSUB);
4901 if (h->h_tag == 0)
4902 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004903
Eric Andersenff9eee42001-06-29 04:57:14 +00004904 h->h_iop = iop;
4905 iop->io_name = 0;
4906 h->h_next = NULL;
4907 if (inhere == 0)
4908 inhere = h;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004909 else {
4910 for (lh = inhere; lh != NULL; lh = lh->h_next) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004911 if (lh->h_next == 0) {
4912 lh->h_next = h;
4913 break;
4914 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004915 }
4916 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004917 iop->io_flag |= IOHERE | IOXHERE;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004918 for (s = h->h_tag; *s; s++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004919 if (*s & QUOTE) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004920 iop->io_flag &= ~IOXHERE;
4921 *s &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00004922 }
Denis Vlasenko00ccf952007-02-01 01:39:24 +00004923 }
Denis Vlasenko648b44f2008-02-12 06:04:06 +00004924 h->h_dosub = ((iop->io_flag & IOXHERE) ? '\0' : '\'');
Eric Andersenff9eee42001-06-29 04:57:14 +00004925}
4926
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004927static void gethere(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00004928{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004929 struct here *h, *hp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004930
4931 DBGPRINTF7(("GETHERE: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00004932
4933 /* Scan here files first leaving inhere list in place */
4934 for (hp = h = inhere; h != NULL; hp = h, h = h->h_next)
Denis Vlasenko648b44f2008-02-12 06:04:06 +00004935 readhere(&h->h_iop->io_name, h->h_tag, h->h_dosub /* NUL or ' */);
Eric Andersenff9eee42001-06-29 04:57:14 +00004936
4937 /* Make inhere list active - keep list intact for scraphere */
4938 if (hp != NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004939 hp->h_next = acthere;
4940 acthere = inhere;
4941 inhere = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004942 }
4943}
4944
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004945static void readhere(char **name, char *s, int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00004946{
4947 int tf;
4948 char tname[30] = ".msh_XXXXXX";
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004949 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004950 jmp_buf ev;
Eric Andersen8401eea2004-08-04 19:16:54 +00004951 char myline[LINELIM + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00004952 char *thenext;
4953
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004954 DBGPRINTF7(("READHERE: enter, name=%p, s=%p\n", name, s));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004955
Eric Andersenff9eee42001-06-29 04:57:14 +00004956 tf = mkstemp(tname);
4957 if (tf < 0)
4958 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004959
Eric Andersenff9eee42001-06-29 04:57:14 +00004960 *name = strsave(tname, areanum);
Denis Vlasenkoe27f1562007-01-01 06:00:38 +00004961 errpt = ev;
4962 if (newenv(setjmp(errpt)) != 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00004963 unlink(tname);
4964 else {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004965 pushio(global_env.iop->argp, (int (*)(struct ioarg *)) global_env.iop->iofn);
4966 global_env.iobase = global_env.iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00004967 for (;;) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00004968 if (interactive && global_env.iop <= iostack) {
Denis Vlasenko38f63192007-01-22 09:03:07 +00004969#if ENABLE_FEATURE_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00004970 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00004971#else
Eric Andersen8401eea2004-08-04 19:16:54 +00004972 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00004973#endif
4974 }
4975 thenext = myline;
4976 while ((c = my_getc(ec)) != '\n' && c) {
4977 if (ec == '\'')
Eric Andersen8401eea2004-08-04 19:16:54 +00004978 c &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00004979 if (thenext >= &myline[LINELIM]) {
4980 c = 0;
4981 break;
4982 }
4983 *thenext++ = c;
4984 }
4985 *thenext = 0;
4986 if (strcmp(s, myline) == 0 || c == 0)
4987 break;
4988 *thenext++ = '\n';
Eric Andersen8401eea2004-08-04 19:16:54 +00004989 write(tf, myline, (int) (thenext - myline));
Eric Andersenff9eee42001-06-29 04:57:14 +00004990 }
4991 if (c == 0) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004992 prs("here document `");
4993 prs(s);
4994 err("' unclosed");
Eric Andersenff9eee42001-06-29 04:57:14 +00004995 }
4996 quitenv();
4997 }
4998 close(tf);
4999}
5000
5001/*
5002 * open here temp file.
5003 * if unquoted here, expand here temp file into second temp file.
5004 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005005static int herein(char *hname, int xdoll)
Eric Andersenff9eee42001-06-29 04:57:14 +00005006{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005007 int hf;
Eric Andersenff9eee42001-06-29 04:57:14 +00005008 int tf;
5009
5010#if __GNUC__
5011 /* Avoid longjmp clobbering */
5012 (void) &tf;
5013#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00005014 if (hname == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00005015 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005016
5017 DBGPRINTF7(("HEREIN: hname is %s, xdoll=%d\n", hname, xdoll));
5018
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005019 hf = open(hname, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00005020 if (hf < 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00005021 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005022
Eric Andersenff9eee42001-06-29 04:57:14 +00005023 if (xdoll) {
5024 char c;
5025 char tname[30] = ".msh_XXXXXX";
5026 jmp_buf ev;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005027
Eric Andersenff9eee42001-06-29 04:57:14 +00005028 tf = mkstemp(tname);
5029 if (tf < 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00005030 return -1;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00005031 errpt = ev;
5032 if (newenv(setjmp(errpt)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00005033 PUSHIO(afile, hf, herechar);
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005034 setbase(global_env.iop);
Eric Andersenff9eee42001-06-29 04:57:14 +00005035 while ((c = subgetc(0, 0)) != 0) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005036 c &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00005037 write(tf, &c, sizeof c);
5038 }
5039 quitenv();
5040 } else
5041 unlink(tname);
5042 close(tf);
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005043 tf = open(tname, O_RDONLY);
Eric Andersenff9eee42001-06-29 04:57:14 +00005044 unlink(tname);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00005045 return tf;
Denis Vlasenko00ccf952007-02-01 01:39:24 +00005046 }
5047 return hf;
Eric Andersenff9eee42001-06-29 04:57:14 +00005048}
5049
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005050static void scraphere(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00005051{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005052 struct here *h;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005053
5054 DBGPRINTF7(("SCRAPHERE: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00005055
5056 for (h = inhere; h != NULL; h = h->h_next) {
5057 if (h->h_iop && h->h_iop->io_name)
Eric Andersen8401eea2004-08-04 19:16:54 +00005058 unlink(h->h_iop->io_name);
Eric Andersenff9eee42001-06-29 04:57:14 +00005059 }
5060 inhere = NULL;
5061}
5062
5063/* unlink here temp files before a freearea(area) */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005064static void freehere(int area)
Eric Andersenff9eee42001-06-29 04:57:14 +00005065{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005066 struct here *h, *hl;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005067
5068 DBGPRINTF6(("FREEHERE: enter, area=%d\n", area));
Eric Andersenff9eee42001-06-29 04:57:14 +00005069
5070 hl = NULL;
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00005071 for (h = acthere; h != NULL; h = h->h_next) {
Eric Andersenff9eee42001-06-29 04:57:14 +00005072 if (getarea((char *) h) >= area) {
5073 if (h->h_iop->io_name != NULL)
5074 unlink(h->h_iop->io_name);
5075 if (hl == NULL)
5076 acthere = h->h_next;
5077 else
5078 hl->h_next = h->h_next;
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00005079 } else {
Eric Andersenff9eee42001-06-29 04:57:14 +00005080 hl = h;
Denis Vlasenko4aafd5f2008-03-02 14:33:26 +00005081 }
5082 }
Eric Andersenff9eee42001-06-29 04:57:14 +00005083}
5084
5085
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005086/* -------- sh.c -------- */
5087/*
5088 * shell
5089 */
5090
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00005091int msh_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005092int msh_main(int argc, char **argv)
5093{
5094 int f;
5095 char *s;
5096 int cflag;
5097 char *name, **ap;
5098 int (*iof) (struct ioarg *);
5099
Denis Vlasenkoab801872007-12-02 08:35:37 +00005100 INIT_G();
5101
Denis Vlasenko55f30b02007-03-24 22:42:29 +00005102 sharedbuf.id = AFID_NOBUF;
5103 mainbuf.id = AFID_NOBUF;
Denis Vlasenko55f30b02007-03-24 22:42:29 +00005104 elinep = line + sizeof(line) - 5;
5105
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005106#if ENABLE_FEATURE_EDITING
5107 line_input_state = new_line_input_t(FOR_SHELL);
5108#endif
5109
5110 DBGPRINTF(("MSH_MAIN: argc %d, environ %p\n", argc, environ));
5111
5112 initarea();
5113 ap = environ;
5114 if (ap != NULL) {
5115 while (*ap)
5116 assign(*ap++, !COPYV);
5117 for (ap = environ; *ap;)
5118 export(lookup(*ap++));
5119 }
5120 closeall();
5121 areanum = 1;
5122
5123 shell = lookup("SHELL");
5124 if (shell->value == null)
5125 setval(shell, (char *)DEFAULT_SHELL);
5126 export(shell);
5127
5128 homedir = lookup("HOME");
5129 if (homedir->value == null)
5130 setval(homedir, "/");
5131 export(homedir);
5132
5133 setval(lookup("$"), putn(getpid()));
5134
5135 path = lookup("PATH");
5136 if (path->value == null) {
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005137 /* Can be merged with same string elsewhere in bbox */
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005138 if (geteuid() == 0)
Denis Vlasenkof5f75c52007-06-12 22:35:19 +00005139 setval(path, bb_default_root_path);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005140 else
Denis Vlasenkof5f75c52007-06-12 22:35:19 +00005141 setval(path, bb_default_path);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005142 }
5143 export(path);
5144
5145 ifs = lookup("IFS");
5146 if (ifs->value == null)
5147 setval(ifs, " \t\n");
5148
5149#ifdef MSHDEBUG
5150 mshdbg_var = lookup("MSHDEBUG");
5151 if (mshdbg_var->value == null)
5152 setval(mshdbg_var, "0");
5153#endif
5154
5155 prompt = lookup("PS1");
5156#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
5157 if (prompt->value == null)
5158#endif
5159 setval(prompt, DEFAULT_USER_PROMPT);
5160 if (geteuid() == 0) {
5161 setval(prompt, DEFAULT_ROOT_PROMPT);
5162 prompt->status &= ~EXPORT;
5163 }
5164 cprompt = lookup("PS2");
5165#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
5166 if (cprompt->value == null)
5167#endif
5168 setval(cprompt, "> ");
5169
5170 iof = filechar;
5171 cflag = 0;
5172 name = *argv++;
5173 if (--argc >= 1) {
5174 if (argv[0][0] == '-' && argv[0][1] != '\0') {
5175 for (s = argv[0] + 1; *s; s++)
5176 switch (*s) {
5177 case 'c':
5178 prompt->status &= ~EXPORT;
5179 cprompt->status &= ~EXPORT;
5180 setval(prompt, "");
5181 setval(cprompt, "");
5182 cflag = 1;
5183 if (--argc > 0)
5184 PUSHIO(aword, *++argv, iof = nlchar);
5185 break;
5186
5187 case 'q':
5188 qflag = SIG_DFL;
5189 break;
5190
5191 case 's':
5192 /* standard input */
5193 break;
5194
5195 case 't':
5196 prompt->status &= ~EXPORT;
5197 setval(prompt, "");
5198 iof = linechar;
5199 break;
5200
5201 case 'i':
Denis Vlasenko648b44f2008-02-12 06:04:06 +00005202 interactive = 1;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005203 default:
5204 if (*s >= 'a' && *s <= 'z')
Denis Vlasenko7d4c44e2007-04-16 22:34:39 +00005205 FLAG[(int) *s]++;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005206 }
5207 } else {
5208 argv--;
5209 argc++;
5210 }
5211
5212 if (iof == filechar && --argc > 0) {
5213 setval(prompt, "");
5214 setval(cprompt, "");
5215 prompt->status &= ~EXPORT;
5216 cprompt->status &= ~EXPORT;
5217
5218/* Shell is non-interactive, activate printf-based debug */
5219#ifdef MSHDEBUG
Denis Vlasenkoed9d6212008-06-09 07:44:19 +00005220 mshdbg = mshdbg_var->value[0] - '0';
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005221 if (mshdbg < 0)
5222 mshdbg = 0;
5223#endif
5224 DBGPRINTF(("MSH_MAIN: calling newfile()\n"));
5225
5226 name = *++argv;
5227 if (newfile(name))
Denis Vlasenkoed9d6212008-06-09 07:44:19 +00005228 exit(EXIT_FAILURE); /* Exit on error */
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005229 }
5230 }
5231
5232 setdash();
5233
5234 /* This won't be true if PUSHIO has been called, say from newfile() above */
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005235 if (global_env.iop < iostack) {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005236 PUSHIO(afile, 0, iof);
5237 if (isatty(0) && isatty(1) && !cflag) {
Denis Vlasenko648b44f2008-02-12 06:04:06 +00005238 interactive = 1;
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005239#if !ENABLE_FEATURE_SH_EXTRA_QUIET
5240#ifdef MSHDEBUG
Denis Vlasenkoca525b42007-06-13 12:27:17 +00005241 printf("\n\n%s built-in shell (msh with debug)\n", bb_banner);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005242#else
Denis Vlasenkoca525b42007-06-13 12:27:17 +00005243 printf("\n\n%s built-in shell (msh)\n", bb_banner);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005244#endif
5245 printf("Enter 'help' for a list of built-in commands.\n\n");
5246#endif
5247 }
5248 }
5249
5250 signal(SIGQUIT, qflag);
5251 if (name && name[0] == '-') {
Denis Vlasenko648b44f2008-02-12 06:04:06 +00005252 interactive = 1;
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005253 f = open(".profile", O_RDONLY);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005254 if (f >= 0)
5255 next(remap(f));
Denis Vlasenko5f9468e2007-04-14 13:22:09 +00005256 f = open("/etc/profile", O_RDONLY);
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005257 if (f >= 0)
5258 next(remap(f));
5259 }
5260 if (interactive)
5261 signal(SIGTERM, sig);
5262
5263 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
5264 signal(SIGINT, onintr);
Denis Vlasenkofee2d0c2008-02-12 10:12:18 +00005265
5266/* Handle "msh SCRIPT VAR=val params..." */
5267/* Disabled: bash does not do it! */
5268#if 0
5269 argv++;
5270 /* skip leading args of the form VAR=val */
5271 while (*argv && assign(*argv, !COPYV)) {
5272 argc--;
5273 argv++;
5274 }
5275 argv--;
5276#endif
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005277 dolv = argv;
5278 dolc = argc;
5279 dolv[0] = name;
Denis Vlasenkofee2d0c2008-02-12 10:12:18 +00005280
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005281 setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc));
5282
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005283 DBGPRINTF(("MSH_MAIN: begin FOR loop, interactive %d, global_env.iop %p, iostack %p\n", interactive, global_env.iop, iostack));
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005284
5285 for (;;) {
Denis Vlasenkoc794c512007-12-16 17:21:29 +00005286 if (interactive && global_env.iop <= iostack) {
Denis Vlasenko489f93e2007-02-01 01:43:16 +00005287#if ENABLE_FEATURE_EDITING
5288 current_prompt = prompt->value;
5289#else
5290 prs(prompt->value);
5291#endif
5292 }
5293 onecommand();
5294 /* Ensure that getenv("PATH") stays current */
5295 setenv("PATH", path->value, 1);
5296 }
5297
5298 DBGPRINTF(("MSH_MAIN: returning.\n"));
5299}
5300
5301
Eric Andersenff9eee42001-06-29 04:57:14 +00005302/*
5303 * Copyright (c) 1987,1997, Prentice Hall
5304 * All rights reserved.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005305 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005306 * Redistribution and use of the MINIX operating system in source and
5307 * binary forms, with or without modification, are permitted provided
5308 * that the following conditions are met:
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005309 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005310 * Redistributions of source code must retain the above copyright
5311 * notice, this list of conditions and the following disclaimer.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005312 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005313 * Redistributions in binary form must reproduce the above
5314 * copyright notice, this list of conditions and the following
5315 * disclaimer in the documentation and/or other materials provided
5316 * with the distribution.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005317 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005318 * Neither the name of Prentice Hall nor the names of the software
5319 * authors or contributors may be used to endorse or promote
5320 * products derived from this software without specific prior
5321 * written permission.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005322 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005323 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND
5324 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
5325 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
5326 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
5327 * IN NO EVENT SHALL PRENTICE HALL OR ANY AUTHORS OR CONTRIBUTORS BE
5328 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
5329 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
5330 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
5331 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
5332 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
5333 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
5334 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5335 *
5336 */