blob: d4f5345513ed79e54b218522360dd53138a553b8 [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
Bernhard Reutner-Fischere15d7572006-06-02 20:56:16 +000016#include "busybox.h"
Eric Andersenff9eee42001-06-29 04:57:14 +000017#include <setjmp.h>
Eric Andersenff9eee42001-06-29 04:57:14 +000018#include <sys/times.h>
Eric Andersenff9eee42001-06-29 04:57:14 +000019
20#include "cmdedit.h"
Eric Andersenff9eee42001-06-29 04:57:14 +000021
Mike Frysinger17811882006-05-05 20:33:07 +000022/*#define MSHDEBUG 1*/
Eric Andersen12de6cf2004-08-04 19:19:10 +000023
24#ifdef MSHDEBUG
Mike Frysinger14ff19b2006-06-20 20:37:01 +000025int mshdbg = MSHDEBUG;
Eric Andersen12de6cf2004-08-04 19:19:10 +000026
27#define DBGPRINTF(x) if(mshdbg>0)printf x
28#define DBGPRINTF0(x) if(mshdbg>0)printf x
29#define DBGPRINTF1(x) if(mshdbg>1)printf x
30#define DBGPRINTF2(x) if(mshdbg>2)printf x
31#define DBGPRINTF3(x) if(mshdbg>3)printf x
32#define DBGPRINTF4(x) if(mshdbg>4)printf x
33#define DBGPRINTF5(x) if(mshdbg>5)printf x
34#define DBGPRINTF6(x) if(mshdbg>6)printf x
35#define DBGPRINTF7(x) if(mshdbg>7)printf x
36#define DBGPRINTF8(x) if(mshdbg>8)printf x
37#define DBGPRINTF9(x) if(mshdbg>9)printf x
38
39int mshdbg_rc = 0;
40
41#define RCPRINTF(x) if(mshdbg_rc)printf x
42
43#else
44
45#define DBGPRINTF(x)
46#define DBGPRINTF0(x)
47#define DBGPRINTF1(x)
48#define DBGPRINTF2(x)
49#define DBGPRINTF3(x)
50#define DBGPRINTF4(x)
51#define DBGPRINTF5(x)
52#define DBGPRINTF6(x)
53#define DBGPRINTF7(x)
54#define DBGPRINTF8(x)
55#define DBGPRINTF9(x)
56
57#define RCPRINTF(x)
58
59#endif /* MSHDEBUG */
60
61
Mike Frysinger2a131752006-06-06 06:26:12 +000062#ifdef CONFIG_FEATURE_SH_FANCY_PROMPT
63# define DEFAULT_ROOT_PROMPT "\\u:\\w> "
64# define DEFAULT_USER_PROMPT "\\u:\\w$ "
65#else
66# define DEFAULT_ROOT_PROMPT "# "
67# define DEFAULT_USER_PROMPT "$ "
68#endif
69
70
Eric Andersenff9eee42001-06-29 04:57:14 +000071/* -------- sh.h -------- */
72/*
73 * shell
74 */
75
Eric Andersen12de6cf2004-08-04 19:19:10 +000076#define LINELIM 2100
77#define NPUSH 8 /* limit to input nesting */
Eric Andersenff9eee42001-06-29 04:57:14 +000078
Eric Andersen392947c2002-12-11 07:42:46 +000079#undef NOFILE
Eric Andersen12de6cf2004-08-04 19:19:10 +000080#define NOFILE 20 /* Number of open files */
81#define NUFILE 10 /* Number of user-accessible files */
82#define FDBASE 10 /* First file usable by Shell */
Eric Andersenff9eee42001-06-29 04:57:14 +000083
84/*
85 * values returned by wait
86 */
Eric Andersen12de6cf2004-08-04 19:19:10 +000087#define WAITSIG(s) ((s)&0177)
88#define WAITVAL(s) (((s)>>8)&0377)
Eric Andersenff9eee42001-06-29 04:57:14 +000089#define WAITCORE(s) (((s)&0200)!=0)
90
91/*
Eric Andersenaff114c2004-04-14 17:51:38 +000092 * library and system definitions
Eric Andersenff9eee42001-06-29 04:57:14 +000093 */
Eric Andersen8401eea2004-08-04 19:16:54 +000094typedef void xint; /* base type of jmp_buf, for not broken compilers */
Eric Andersenff9eee42001-06-29 04:57:14 +000095
96/*
97 * shell components
98 */
99
100#define QUOTE 0200
101
102#define NOBLOCK ((struct op *)NULL)
103#define NOWORD ((char *)NULL)
104#define NOWORDS ((char **)NULL)
105#define NOPIPE ((int *)NULL)
106
107/*
108 * Description of a command or an operation on commands.
109 * Might eventually use a union.
110 */
111struct op {
Eric Andersen8401eea2004-08-04 19:16:54 +0000112 int type; /* operation type, see below */
113 char **words; /* arguments to a command */
114 struct ioword **ioact; /* IO actions (eg, < > >>) */
Eric Andersenff9eee42001-06-29 04:57:14 +0000115 struct op *left;
116 struct op *right;
Eric Andersen8401eea2004-08-04 19:16:54 +0000117 char *str; /* identifier for case and for */
Eric Andersenff9eee42001-06-29 04:57:14 +0000118};
119
Eric Andersen8401eea2004-08-04 19:16:54 +0000120#define TCOM 1 /* command */
121#define TPAREN 2 /* (c-list) */
122#define TPIPE 3 /* a | b */
123#define TLIST 4 /* a [&;] b */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000124#define TOR 5 /* || */
Eric Andersen8401eea2004-08-04 19:16:54 +0000125#define TAND 6 /* && */
Eric Andersenff9eee42001-06-29 04:57:14 +0000126#define TFOR 7
Eric Andersen12de6cf2004-08-04 19:19:10 +0000127#define TDO 8
Eric Andersenff9eee42001-06-29 04:57:14 +0000128#define TCASE 9
Eric Andersen12de6cf2004-08-04 19:19:10 +0000129#define TIF 10
Eric Andersenff9eee42001-06-29 04:57:14 +0000130#define TWHILE 11
131#define TUNTIL 12
132#define TELIF 13
Eric Andersen8401eea2004-08-04 19:16:54 +0000133#define TPAT 14 /* pattern in case */
134#define TBRACE 15 /* {c-list} */
135#define TASYNC 16 /* c & */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000136/* Added to support "." file expansion */
137#define TDOT 17
138
139/* Strings for names to make debug easier */
"Vladimir N. Oleynik"ac973172005-09-22 14:38:17 +0000140#ifdef MSHDEBUG
141static char *T_CMD_NAMES[] = {
Eric Andersen12de6cf2004-08-04 19:19:10 +0000142 "PLACEHOLDER",
143 "TCOM",
144 "TPAREN",
145 "TPIPE",
146 "TLIST",
147 "TOR",
148 "TAND",
149 "TFOR",
150 "TDO",
151 "TCASE",
152 "TIF",
153 "TWHILE",
154 "TUNTIL",
155 "TELIF",
156 "TPAT",
157 "TBRACE",
158 "TASYNC",
159 "TDOT",
160};
"Vladimir N. Oleynik"ac973172005-09-22 14:38:17 +0000161#endif
Eric Andersenff9eee42001-06-29 04:57:14 +0000162
163/*
164 * actions determining the environment of a process
165 */
166#define BIT(i) (1<<(i))
Eric Andersen8401eea2004-08-04 19:16:54 +0000167#define FEXEC BIT(0) /* execute without forking */
Eric Andersenff9eee42001-06-29 04:57:14 +0000168
Eric Andersen12de6cf2004-08-04 19:19:10 +0000169#define AREASIZE (90000)
Eric Andersen12de6cf2004-08-04 19:19:10 +0000170
Eric Andersenff9eee42001-06-29 04:57:14 +0000171/*
172 * flags to control evaluation of words
173 */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000174#define DOSUB 1 /* interpret $, `, and quotes */
175#define DOBLANK 2 /* perform blank interpretation */
176#define DOGLOB 4 /* interpret [?* */
177#define DOKEY 8 /* move words with `=' to 2nd arg. list */
178#define DOTRIM 16 /* trim resulting string */
Eric Andersenff9eee42001-06-29 04:57:14 +0000179
180#define DOALL (DOSUB|DOBLANK|DOGLOB|DOKEY|DOTRIM)
181
Eric Andersenff9eee42001-06-29 04:57:14 +0000182
Eric Andersen12de6cf2004-08-04 19:19:10 +0000183/* PROTOTYPES */
Eric Andersenff9eee42001-06-29 04:57:14 +0000184static int newfile(char *s);
185static char *findeq(char *cp);
186static char *cclass(char *p, int sub);
187static void initarea(void);
Matt Kraai2d91deb2001-08-01 17:21:35 +0000188extern int msh_main(int argc, char **argv);
Eric Andersenff9eee42001-06-29 04:57:14 +0000189
190
Eric Andersen8401eea2004-08-04 19:16:54 +0000191struct brkcon {
192 jmp_buf brkpt;
193 struct brkcon *nextlev;
194};
Eric Andersenff9eee42001-06-29 04:57:14 +0000195
Eric Andersen12de6cf2004-08-04 19:19:10 +0000196
Eric Andersenff9eee42001-06-29 04:57:14 +0000197/*
198 * redirection
199 */
200struct ioword {
Eric Andersen8401eea2004-08-04 19:16:54 +0000201 short io_unit; /* unit affected */
202 short io_flag; /* action (below) */
203 char *io_name; /* file name */
Eric Andersenff9eee42001-06-29 04:57:14 +0000204};
Eric Andersenff9eee42001-06-29 04:57:14 +0000205
Eric Andersen12de6cf2004-08-04 19:19:10 +0000206#define IOREAD 1 /* < */
207#define IOHERE 2 /* << (here file) */
208#define IOWRITE 4 /* > */
209#define IOCAT 8 /* >> */
210#define IOXHERE 16 /* ${}, ` in << */
211#define IODUP 32 /* >&digit */
212#define IOCLOSE 64 /* >&- */
Eric Andersenff9eee42001-06-29 04:57:14 +0000213
Eric Andersen8401eea2004-08-04 19:16:54 +0000214#define IODEFAULT (-1) /* token for default IO unit */
215
Eric Andersen12de6cf2004-08-04 19:19:10 +0000216
Eric Andersenff9eee42001-06-29 04:57:14 +0000217
218/*
219 * parsing & execution environment
220 */
Eric Andersen8401eea2004-08-04 19:16:54 +0000221static struct env {
222 char *linep;
223 struct io *iobase;
224 struct io *iop;
Eric Andersen12de6cf2004-08-04 19:19:10 +0000225 xint *errpt; /* void * */
Eric Andersen8401eea2004-08-04 19:16:54 +0000226 int iofd;
227 struct env *oenv;
Eric Andersenff9eee42001-06-29 04:57:14 +0000228} e;
229
230/*
231 * flags:
232 * -e: quit on error
233 * -k: look for name=value everywhere on command line
234 * -n: no execution
235 * -t: exit after reading and executing one command
236 * -v: echo as read
237 * -x: trace
238 * -u: unset variables net diagnostic
239 */
Mike Frysinger3672fe92006-11-15 21:52:10 +0000240static char flags['z' - 'a' + 1];
241/* this looks weird, but is OK ... we index flag with 'a'...'z' */
242static char *flag = flags - 'a';
Eric Andersenff9eee42001-06-29 04:57:14 +0000243
Eric Andersen8401eea2004-08-04 19:16:54 +0000244static char *null; /* null value for variable */
245static int intr; /* interrupt pending */
Eric Andersenff9eee42001-06-29 04:57:14 +0000246
Eric Andersen8401eea2004-08-04 19:16:54 +0000247static char *trap[_NSIG + 1];
248static char ourtrap[_NSIG + 1];
249static int trapset; /* trap pending */
Eric Andersenff9eee42001-06-29 04:57:14 +0000250
Eric Andersen8401eea2004-08-04 19:16:54 +0000251static int heedint; /* heed interrupt signals */
Eric Andersenff9eee42001-06-29 04:57:14 +0000252
Eric Andersen8401eea2004-08-04 19:16:54 +0000253static int yynerrs; /* yacc */
Eric Andersenff9eee42001-06-29 04:57:14 +0000254
Eric Andersen8401eea2004-08-04 19:16:54 +0000255static char line[LINELIM];
256static char *elinep;
Eric Andersenff9eee42001-06-29 04:57:14 +0000257
Eric Andersen12de6cf2004-08-04 19:19:10 +0000258
Eric Andersenff9eee42001-06-29 04:57:14 +0000259/*
260 * other functions
261 */
Eric Andersen8401eea2004-08-04 19:16:54 +0000262static int (*inbuilt(char *s)) (struct op *);
Eric Andersen392947c2002-12-11 07:42:46 +0000263
Eric Andersen8401eea2004-08-04 19:16:54 +0000264static char *rexecve(char *c, char **v, char **envp);
265static char *space(int n);
266static char *strsave(char *s, int a);
267static char *evalstr(char *cp, int f);
268static char *putn(int n);
Eric Andersen8401eea2004-08-04 19:16:54 +0000269static char *unquote(char *as);
270static struct var *lookup(char *n);
271static int rlookup(char *n);
272static struct wdblock *glob(char *cp, struct wdblock *wb);
273static int my_getc(int ec);
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +0000274static int subgetc(char ec, int quoted);
Eric Andersenfd7a4c82004-09-02 23:13:10 +0000275static char **makenv(int all, struct wdblock *wb);
Eric Andersen8401eea2004-08-04 19:16:54 +0000276static char **eval(char **ap, int f);
277static int setstatus(int s);
278static int waitfor(int lastpid, int canintr);
Eric Andersenff9eee42001-06-29 04:57:14 +0000279
Eric Andersen8401eea2004-08-04 19:16:54 +0000280static void onintr(int s); /* SIGINT handler */
Eric Andersenff9eee42001-06-29 04:57:14 +0000281
Eric Andersen8401eea2004-08-04 19:16:54 +0000282static int newenv(int f);
283static void quitenv(void);
284static void err(char *s);
285static int anys(char *s1, char *s2);
286static int any(int c, char *s);
287static void next(int f);
288static void setdash(void);
289static void onecommand(void);
290static void runtrap(int i);
291static int gmatch(char *s, char *p);
Eric Andersenff9eee42001-06-29 04:57:14 +0000292
Eric Andersen12de6cf2004-08-04 19:19:10 +0000293
Eric Andersenff9eee42001-06-29 04:57:14 +0000294/*
295 * error handling
296 */
Eric Andersen8401eea2004-08-04 19:16:54 +0000297static void leave(void); /* abort shell (or fail in subshell) */
298static void fail(void); /* fail but return to process next command */
299static void warn(char *s);
300static void sig(int i); /* default signal handler */
Eric Andersenff9eee42001-06-29 04:57:14 +0000301
302
303
304/* -------- area stuff -------- */
305
Eric Andersen12de6cf2004-08-04 19:19:10 +0000306#define REGSIZE sizeof(struct region)
307#define GROWBY (256)
308/* #define SHRINKBY (64) */
Eric Andersenff9eee42001-06-29 04:57:14 +0000309#undef SHRINKBY
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000310#define FREE (32767)
311#define BUSY (0)
312#define ALIGN (sizeof(int)-1)
Eric Andersenff9eee42001-06-29 04:57:14 +0000313
314
315struct region {
Eric Andersen8401eea2004-08-04 19:16:54 +0000316 struct region *next;
317 int area;
Eric Andersenff9eee42001-06-29 04:57:14 +0000318};
319
320
321
322/* -------- 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
Eric Andersenff9eee42001-06-29 04:57:14 +0000330#define WORD 256
331#define LOGAND 257
332#define LOGOR 258
333#define BREAK 259
Eric Andersen12de6cf2004-08-04 19:19:10 +0000334#define IF 260
Eric Andersenff9eee42001-06-29 04:57:14 +0000335#define THEN 261
336#define ELSE 262
337#define ELIF 263
Eric Andersen12de6cf2004-08-04 19:19:10 +0000338#define FI 264
Eric Andersenff9eee42001-06-29 04:57:14 +0000339#define CASE 265
340#define ESAC 266
Eric Andersen12de6cf2004-08-04 19:19:10 +0000341#define FOR 267
Eric Andersenff9eee42001-06-29 04:57:14 +0000342#define WHILE 268
343#define UNTIL 269
Eric Andersen12de6cf2004-08-04 19:19:10 +0000344#define DO 270
Eric Andersenff9eee42001-06-29 04:57:14 +0000345#define DONE 271
Eric Andersen12de6cf2004-08-04 19:19:10 +0000346#define IN 272
347/* Added for "." file expansion */
348#define DOT 273
349
Eric Andersenff9eee42001-06-29 04:57:14 +0000350#define YYERRCODE 300
351
352/* flags to yylex */
Eric Andersen8401eea2004-08-04 19:16:54 +0000353#define CONTIN 01 /* skip new lines to complete command */
Eric Andersenff9eee42001-06-29 04:57:14 +0000354
355#define SYNTAXERR zzerr()
Eric Andersen12de6cf2004-08-04 19:19:10 +0000356
Eric Andersen8401eea2004-08-04 19:16:54 +0000357static struct op *pipeline(int cf);
Eric Andersenff9eee42001-06-29 04:57:14 +0000358static struct op *andor(void);
359static struct op *c_list(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000360static int synio(int cf);
361static void musthave(int c, int cf);
Eric Andersenff9eee42001-06-29 04:57:14 +0000362static struct op *simple(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000363static struct op *nested(int type, int mark);
364static struct op *command(int cf);
365static struct op *dogroup(int onlydone);
Eric Andersenff9eee42001-06-29 04:57:14 +0000366static struct op *thenpart(void);
367static struct op *elsepart(void);
368static struct op *caselist(void);
369static struct op *casepart(void);
370static char **pattern(void);
371static char **wordlist(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000372static struct op *list(struct op *t1, struct op *t2);
373static struct op *block(int type, struct op *t1, struct op *t2, char **wp);
Eric Andersenff9eee42001-06-29 04:57:14 +0000374static struct op *newtp(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000375static struct op *namelist(struct op *t);
Eric Andersenff9eee42001-06-29 04:57:14 +0000376static char **copyw(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000377static void word(char *cp);
Eric Andersenff9eee42001-06-29 04:57:14 +0000378static struct ioword **copyio(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000379static struct ioword *io(int u, int f, char *cp);
Eric Andersenff9eee42001-06-29 04:57:14 +0000380static void zzerr(void);
Eric Andersen8401eea2004-08-04 19:16:54 +0000381static void yyerror(char *s);
382static int yylex(int cf);
383static int collect(int c, int c1);
384static int dual(int c);
385static void diag(int ec);
386static char *tree(unsigned size);
Eric Andersenff9eee42001-06-29 04:57:14 +0000387
388/* -------- var.h -------- */
389
Eric Andersen8401eea2004-08-04 19:16:54 +0000390struct var {
391 char *value;
392 char *name;
393 struct var *next;
394 char status;
Eric Andersenff9eee42001-06-29 04:57:14 +0000395};
Eric Andersenff9eee42001-06-29 04:57:14 +0000396
Eric Andersen8401eea2004-08-04 19:16:54 +0000397#define COPYV 1 /* flag to setval, suggesting copy */
398#define RONLY 01 /* variable is read-only */
399#define EXPORT 02 /* variable is to be exported */
400#define GETCELL 04 /* name & value space was got with getcell */
Eric Andersenff9eee42001-06-29 04:57:14 +0000401
Eric Andersen8401eea2004-08-04 19:16:54 +0000402static int yyparse(void);
403static struct var *lookup(char *n);
404static void setval(struct var *vp, char *val);
405static void nameval(struct var *vp, char *val, char *name);
406static void export(struct var *vp);
407static void ronly(struct var *vp);
408static int isassign(char *s);
409static int checkname(char *cp);
410static int assign(char *s, int cf);
411static void putvlist(int f, int out);
412static int eqname(char *n1, char *n2);
413
414static int execute(struct op *t, int *pin, int *pout, int act);
Eric Andersenff9eee42001-06-29 04:57:14 +0000415
Eric Andersen12de6cf2004-08-04 19:19:10 +0000416
Eric Andersenff9eee42001-06-29 04:57:14 +0000417/* -------- io.h -------- */
418/* io buffer */
419struct iobuf {
Eric Andersen8401eea2004-08-04 19:16:54 +0000420 unsigned id; /* buffer id */
421 char buf[512]; /* buffer */
422 char *bufp; /* pointer into buffer */
423 char *ebufp; /* pointer to end of buffer */
Eric Andersenff9eee42001-06-29 04:57:14 +0000424};
425
426/* possible arguments to an IO function */
427struct ioarg {
Eric Andersen8401eea2004-08-04 19:16:54 +0000428 char *aword;
429 char **awordlist;
430 int afile; /* file descriptor */
431 unsigned afid; /* buffer id */
432 long afpos; /* file position */
433 struct iobuf *afbuf; /* buffer for this file */
Eric Andersenff9eee42001-06-29 04:57:14 +0000434};
Eric Andersen8401eea2004-08-04 19:16:54 +0000435
Eric Andersenff9eee42001-06-29 04:57:14 +0000436//static struct ioarg ioargstack[NPUSH];
437#define AFID_NOBUF (~0)
438#define AFID_ID 0
439
440/* an input generator's state */
Eric Andersen8401eea2004-08-04 19:16:54 +0000441struct io {
442 int (*iofn) (struct ioarg *, struct io *);
443 struct ioarg *argp;
444 int peekc;
445 char prev; /* previous character read by readc() */
446 char nlcount; /* for `'s */
447 char xchar; /* for `'s */
448 char task; /* reason for pushed IO */
Eric Andersenff9eee42001-06-29 04:57:14 +0000449};
Eric Andersen8401eea2004-08-04 19:16:54 +0000450
451//static struct io iostack[NPUSH];
452#define XOTHER 0 /* none of the below */
453#define XDOLL 1 /* expanding ${} */
454#define XGRAVE 2 /* expanding `'s */
455#define XIO 3 /* file IO */
Eric Andersenff9eee42001-06-29 04:57:14 +0000456
457/* in substitution */
458#define INSUB() (e.iop->task == XGRAVE || e.iop->task == XDOLL)
459
Eric Andersen12de6cf2004-08-04 19:19:10 +0000460
Eric Andersenff9eee42001-06-29 04:57:14 +0000461/*
462 * input generators for IO structure
463 */
Eric Andersen8401eea2004-08-04 19:16:54 +0000464static int nlchar(struct ioarg *ap);
465static int strchar(struct ioarg *ap);
466static int qstrchar(struct ioarg *ap);
467static int filechar(struct ioarg *ap);
468static int herechar(struct ioarg *ap);
469static int linechar(struct ioarg *ap);
470static int gravechar(struct ioarg *ap, struct io *iop);
471static int qgravechar(struct ioarg *ap, struct io *iop);
472static int dolchar(struct ioarg *ap);
473static int wdchar(struct ioarg *ap);
474static void scraphere(void);
475static void freehere(int area);
476static void gethere(void);
477static void markhere(char *s, struct ioword *iop);
478static int herein(char *hname, int xdoll);
479static int run(struct ioarg *argp, int (*f) (struct ioarg *));
Eric Andersenff9eee42001-06-29 04:57:14 +0000480
Eric Andersen12de6cf2004-08-04 19:19:10 +0000481
Eric Andersenff9eee42001-06-29 04:57:14 +0000482/*
483 * IO functions
484 */
Eric Andersen8401eea2004-08-04 19:16:54 +0000485static int eofc(void);
486static int readc(void);
487static void unget(int c);
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +0000488static void ioecho(char c);
"Vladimir N. Oleynik"485d7cb2005-10-17 09:48:57 +0000489static void prs(const char *s);
Eric Andersen8401eea2004-08-04 19:16:54 +0000490static void prn(unsigned u);
491static void closef(int i);
492static void closeall(void);
Eric Andersenff9eee42001-06-29 04:57:14 +0000493
Eric Andersen12de6cf2004-08-04 19:19:10 +0000494
Eric Andersenff9eee42001-06-29 04:57:14 +0000495/*
496 * IO control
497 */
Eric Andersen8401eea2004-08-04 19:16:54 +0000498static void pushio(struct ioarg *argp, int (*f) (struct ioarg *));
499static int remap(int fd);
500static int openpipe(int *pv);
501static void closepipe(int *pv);
502static struct io *setbase(struct io *ip);
Eric Andersenff9eee42001-06-29 04:57:14 +0000503
Eric Andersenff9eee42001-06-29 04:57:14 +0000504#define PUSHIO(what,arg,gen) ((temparg.what = (arg)),pushio(&temparg,(gen)))
505#define RUN(what,arg,gen) ((temparg.what = (arg)), run(&temparg,(gen)))
506
507/* -------- word.h -------- */
508
Eric Andersen8401eea2004-08-04 19:16:54 +0000509#define NSTART 16 /* default number of words to allow for initially */
Eric Andersenff9eee42001-06-29 04:57:14 +0000510
Eric Andersen8401eea2004-08-04 19:16:54 +0000511struct wdblock {
512 short w_bsize;
513 short w_nword;
Eric Andersenff9eee42001-06-29 04:57:14 +0000514 /* bounds are arbitrary */
Eric Andersen8401eea2004-08-04 19:16:54 +0000515 char *w_words[1];
Eric Andersenff9eee42001-06-29 04:57:14 +0000516};
517
Eric Andersen8401eea2004-08-04 19:16:54 +0000518static struct wdblock *addword(char *wd, struct wdblock *wb);
519static struct wdblock *newword(int nw);
520static char **getwords(struct wdblock *wb);
Eric Andersenff9eee42001-06-29 04:57:14 +0000521
522/* -------- area.h -------- */
523
524/*
525 * storage allocation
526 */
Eric Andersen8401eea2004-08-04 19:16:54 +0000527static char *getcell(unsigned nbytes);
528static void garbage(void);
529static void setarea(char *cp, int a);
530static int getarea(char *cp);
531static void freearea(int a);
532static void freecell(char *cp);
533static int areanum; /* current allocation area */
Eric Andersenff9eee42001-06-29 04:57:14 +0000534
Eric Andersen12de6cf2004-08-04 19:19:10 +0000535#define NEW(type) (type *)getcell(sizeof(type))
Eric Andersenff9eee42001-06-29 04:57:14 +0000536#define DELETE(obj) freecell((char *)obj)
537
538
539/* -------- misc stuff -------- */
540
Eric Andersen12de6cf2004-08-04 19:19:10 +0000541static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp);
Eric Andersen8401eea2004-08-04 19:16:54 +0000542static int iosetup(struct ioword *iop, int pipein, int pipeout);
543static void echo(char **wp);
544static struct op **find1case(struct op *t, char *w);
545static struct op *findcase(struct op *t, char *w);
546static void brkset(struct brkcon *bc);
547static int dolabel(struct op *t);
548static int dohelp(struct op *t);
549static int dochdir(struct op *t);
550static int doshift(struct op *t);
551static int dologin(struct op *t);
552static int doumask(struct op *t);
553static int doexec(struct op *t);
554static int dodot(struct op *t);
555static int dowait(struct op *t);
556static int doread(struct op *t);
557static int doeval(struct op *t);
558static int dotrap(struct op *t);
559static int getsig(char *s);
560static void setsig(int n, sighandler_t f);
561static int getn(char *as);
562static int dobreak(struct op *t);
563static int docontinue(struct op *t);
564static int brkcontin(char *cp, int val);
565static int doexit(struct op *t);
566static int doexport(struct op *t);
567static int doreadonly(struct op *t);
568static void rdexp(char **wp, void (*f) (struct var *), int key);
569static void badid(char *s);
570static int doset(struct op *t);
571static void varput(char *s, int out);
572static int dotimes(struct op *t);
573static int expand(char *cp, struct wdblock **wbp, int f);
574static char *blank(int f);
575static int dollar(int quoted);
576static int grave(int quoted);
577static void globname(char *we, char *pp);
578static char *generate(char *start1, char *end1, char *middle, char *end);
579static int anyspcl(struct wdblock *wb);
580static int xstrcmp(char *p1, char *p2);
581static void glob0(char *a0, unsigned int a1, int a2,
582 int (*a3) (char *, char *));
583static void glob1(char *base, char *lim);
584static void glob2(char *i, char *j);
585static void glob3(char *i, char *j, char *k);
586static void readhere(char **name, char *s, int ec);
587static void pushio(struct ioarg *argp, int (*f) (struct ioarg *));
588static int xxchar(struct ioarg *ap);
Eric Andersenff9eee42001-06-29 04:57:14 +0000589
Eric Andersen8401eea2004-08-04 19:16:54 +0000590struct here {
591 char *h_tag;
592 int h_dosub;
593 struct ioword *h_iop;
594 struct here *h_next;
Eric Andersenff9eee42001-06-29 04:57:14 +0000595};
596
"Vladimir N. Oleynik"485d7cb2005-10-17 09:48:57 +0000597static const char * const signame[] = {
Eric Andersenff9eee42001-06-29 04:57:14 +0000598 "Signal 0",
599 "Hangup",
Eric Andersen8401eea2004-08-04 19:16:54 +0000600 (char *) NULL, /* interrupt */
Eric Andersenff9eee42001-06-29 04:57:14 +0000601 "Quit",
602 "Illegal instruction",
603 "Trace/BPT trap",
604 "Abort",
605 "Bus error",
606 "Floating Point Exception",
607 "Killed",
608 "SIGUSR1",
609 "SIGSEGV",
610 "SIGUSR2",
Eric Andersen8401eea2004-08-04 19:16:54 +0000611 (char *) NULL, /* broken pipe */
Eric Andersenff9eee42001-06-29 04:57:14 +0000612 "Alarm clock",
613 "Terminated",
614};
Eric Andersen8401eea2004-08-04 19:16:54 +0000615
Eric Andersenff9eee42001-06-29 04:57:14 +0000616#define NSIGNAL (sizeof(signame)/sizeof(signame[0]))
617
618struct res {
"Vladimir N. Oleynik"485d7cb2005-10-17 09:48:57 +0000619 const char *r_name;
Eric Andersen8401eea2004-08-04 19:16:54 +0000620 int r_val;
Eric Andersenff9eee42001-06-29 04:57:14 +0000621};
"Vladimir N. Oleynik"485d7cb2005-10-17 09:48:57 +0000622static const struct res restab[] = {
Eric Andersen8401eea2004-08-04 19:16:54 +0000623 {"for", FOR},
624 {"case", CASE},
625 {"esac", ESAC},
626 {"while", WHILE},
627 {"do", DO},
628 {"done", DONE},
629 {"if", IF},
630 {"in", IN},
631 {"then", THEN},
632 {"else", ELSE},
633 {"elif", ELIF},
634 {"until", UNTIL},
635 {"fi", FI},
Eric Andersen8401eea2004-08-04 19:16:54 +0000636 {";;", BREAK},
637 {"||", LOGOR},
638 {"&&", LOGAND},
639 {"{", '{'},
640 {"}", '}'},
Eric Andersen12de6cf2004-08-04 19:19:10 +0000641 {".", DOT},
Eric Andersen8401eea2004-08-04 19:16:54 +0000642 {0, 0},
Eric Andersenff9eee42001-06-29 04:57:14 +0000643};
644
645
Eric Andersen1c039232001-07-07 00:05:55 +0000646struct builtincmd {
647 const char *name;
Eric Andersen8401eea2004-08-04 19:16:54 +0000648 int (*builtinfunc) (struct op * t);
Eric Andersenff9eee42001-06-29 04:57:14 +0000649};
Eric Andersen8401eea2004-08-04 19:16:54 +0000650static const struct builtincmd builtincmds[] = {
651 {".", dodot},
652 {":", dolabel},
653 {"break", dobreak},
654 {"cd", dochdir},
655 {"continue", docontinue},
656 {"eval", doeval},
657 {"exec", doexec},
658 {"exit", doexit},
659 {"export", doexport},
660 {"help", dohelp},
661 {"login", dologin},
662 {"newgrp", dologin},
663 {"read", doread},
664 {"readonly", doreadonly},
665 {"set", doset},
666 {"shift", doshift},
667 {"times", dotimes},
668 {"trap", dotrap},
669 {"umask", doumask},
670 {"wait", dowait},
671 {0, 0}
Eric Andersenff9eee42001-06-29 04:57:14 +0000672};
673
"Vladimir N. Oleynik"ac973172005-09-22 14:38:17 +0000674static struct op *scantree(struct op *);
Eric Andersen12de6cf2004-08-04 19:19:10 +0000675static struct op *dowholefile(int, int);
676
Eric Andersenff9eee42001-06-29 04:57:14 +0000677/* Globals */
Eric Andersen8401eea2004-08-04 19:16:54 +0000678extern char **environ; /* environment pointer */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000679
Eric Andersen8401eea2004-08-04 19:16:54 +0000680static char **dolv;
681static int dolc;
682static int exstat;
683static char gflg;
"Vladimir N. Oleynik"485d7cb2005-10-17 09:48:57 +0000684static int interactive; /* Is this an interactive shell */
Eric Andersen8401eea2004-08-04 19:16:54 +0000685static int execflg;
686static int multiline; /* \n changed to ; */
687static struct op *outtree; /* result from parser */
688static xint *failpt;
689static xint *errpt;
690static struct brkcon *brklist;
691static int isbreak;
692static struct wdblock *wdlist;
693static struct wdblock *iolist;
694static char *trap[_NSIG + 1];
695static char ourtrap[_NSIG + 1];
696static int trapset; /* trap pending */
697static int yynerrs; /* yacc */
698static char line[LINELIM];
Eric Andersen12de6cf2004-08-04 19:19:10 +0000699
700#ifdef MSHDEBUG
701static struct var *mshdbg_var;
702#endif
Eric Andersen8401eea2004-08-04 19:16:54 +0000703static struct var *vlist; /* dictionary */
704static struct var *homedir; /* home directory */
705static struct var *prompt; /* main prompt */
706static struct var *cprompt; /* continuation prompt */
707static struct var *path; /* search path for commands */
708static struct var *shell; /* shell to interpret command files */
709static struct var *ifs; /* field separators */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000710
Eric Andersen8401eea2004-08-04 19:16:54 +0000711static int areanum; /* current allocation area */
712static int intr;
713static int inparse;
Eric Andersen8401eea2004-08-04 19:16:54 +0000714static char *null = "";
715static int heedint = 1;
Eric Andersen8401eea2004-08-04 19:16:54 +0000716static void (*qflag) (int) = SIG_IGN;
717static int startl;
718static int peeksym;
719static int nlseen;
720static int iounit = IODEFAULT;
721static YYSTYPE yylval;
Eric Andersen12de6cf2004-08-04 19:19:10 +0000722static char *elinep = line + sizeof(line) - 5;
723
724static struct ioarg temparg = { 0, 0, 0, AFID_NOBUF, 0 }; /* temporary for PUSHIO */
725static struct ioarg ioargstack[NPUSH];
726static struct io iostack[NPUSH];
Eric Andersen8401eea2004-08-04 19:16:54 +0000727static struct iobuf sharedbuf = { AFID_NOBUF };
728static struct iobuf mainbuf = { AFID_NOBUF };
Eric Andersenff9eee42001-06-29 04:57:14 +0000729static unsigned bufid = AFID_ID; /* buffer id counter */
Eric Andersen12de6cf2004-08-04 19:19:10 +0000730
Eric Andersen8401eea2004-08-04 19:16:54 +0000731static struct here *inhere; /* list of hear docs while parsing */
732static struct here *acthere; /* list of active here documents */
733static struct region *areabot; /* bottom of area */
734static struct region *areatop; /* top of area */
735static struct region *areanxt; /* starting point of scan */
736static void *brktop;
737static void *brkaddr;
Eric Andersenff9eee42001-06-29 04:57:14 +0000738
Eric Andersen12de6cf2004-08-04 19:19:10 +0000739static struct env e = {
740 line, /* linep: char ptr */
741 iostack, /* iobase: struct io ptr */
742 iostack - 1, /* iop: struct io ptr */
743 (xint *) NULL, /* errpt: void ptr for errors? */
744 FDBASE, /* iofd: file desc */
745 (struct env *) NULL /* oenv: struct env ptr */
746};
747
748#ifdef MSHDEBUG
Mike Frysinger02d8fa42006-05-05 20:32:31 +0000749void print_t(struct op *t);
Eric Andersen12de6cf2004-08-04 19:19:10 +0000750void print_t(struct op *t)
751{
Mike Frysinger02d8fa42006-05-05 20:32:31 +0000752 DBGPRINTF(("T: t=%p, type %s, words=%p, IOword=%p\n", t,
753 T_CMD_NAMES[t->type], t->words, t->ioact));
Eric Andersen12de6cf2004-08-04 19:19:10 +0000754
755 if (t->words) {
756 DBGPRINTF(("T: W1: %s", t->words[0]));
757 }
758
759 return;
760}
761
Mike Frysinger02d8fa42006-05-05 20:32:31 +0000762void print_tree(struct op *head);
Eric Andersen12de6cf2004-08-04 19:19:10 +0000763void print_tree(struct op *head)
764{
765 if (head == NULL) {
766 DBGPRINTF(("PRINT_TREE: no tree\n"));
767 return;
768 }
769
Mike Frysinger02d8fa42006-05-05 20:32:31 +0000770 DBGPRINTF(("NODE: %p, left %p, right %p\n", head, head->left,
Eric Andersen12de6cf2004-08-04 19:19:10 +0000771 head->right));
772
773 if (head->left)
774 print_tree(head->left);
775
776 if (head->right)
777 print_tree(head->right);
778
779 return;
780}
781#endif /* MSHDEBUG */
782
Eric Andersenff9eee42001-06-29 04:57:14 +0000783
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000784#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +0000785static char *current_prompt;
Eric Andersenff9eee42001-06-29 04:57:14 +0000786#endif
787
Eric Andersenff9eee42001-06-29 04:57:14 +0000788/* -------- sh.c -------- */
789/*
790 * shell
791 */
792
793
Rob Landleydfba7412006-03-06 20:47:33 +0000794int msh_main(int argc, char **argv)
Eric Andersenff9eee42001-06-29 04:57:14 +0000795{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000796 int f;
797 char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +0000798 int cflag;
799 char *name, **ap;
Eric Andersen8401eea2004-08-04 19:16:54 +0000800 int (*iof) (struct ioarg *);
Eric Andersenff9eee42001-06-29 04:57:14 +0000801
Mike Frysinger02d8fa42006-05-05 20:32:31 +0000802 DBGPRINTF(("MSH_MAIN: argc %d, environ %p\n", argc, environ));
Eric Andersen12de6cf2004-08-04 19:19:10 +0000803
Eric Andersenff9eee42001-06-29 04:57:14 +0000804 initarea();
805 if ((ap = environ) != NULL) {
806 while (*ap)
807 assign(*ap++, !COPYV);
808 for (ap = environ; *ap;)
809 export(lookup(*ap++));
810 }
811 closeall();
812 areanum = 1;
813
814 shell = lookup("SHELL");
815 if (shell->value == null)
Eric Andersen78500142004-08-27 19:55:28 +0000816 setval(shell, (char *)DEFAULT_SHELL);
Eric Andersenff9eee42001-06-29 04:57:14 +0000817 export(shell);
818
819 homedir = lookup("HOME");
820 if (homedir->value == null)
821 setval(homedir, "/");
822 export(homedir);
823
Eric Andersen737f5fb2003-03-14 16:05:59 +0000824 setval(lookup("$"), putn(getpid()));
Eric Andersenff9eee42001-06-29 04:57:14 +0000825
826 path = lookup("PATH");
Eric Andersen737f5fb2003-03-14 16:05:59 +0000827 if (path->value == null) {
828 if (geteuid() == 0)
829 setval(path, "/sbin:/bin:/usr/sbin:/usr/bin");
830 else
831 setval(path, "/bin:/usr/bin");
832 }
Eric Andersenff9eee42001-06-29 04:57:14 +0000833 export(path);
834
835 ifs = lookup("IFS");
836 if (ifs->value == null)
837 setval(ifs, " \t\n");
838
Eric Andersen12de6cf2004-08-04 19:19:10 +0000839#ifdef MSHDEBUG
840 mshdbg_var = lookup("MSHDEBUG");
841 if (mshdbg_var->value == null)
842 setval(mshdbg_var, "0");
843#endif
844
Eric Andersenff9eee42001-06-29 04:57:14 +0000845 prompt = lookup("PS1");
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000846#ifdef CONFIG_FEATURE_SH_FANCY_PROMPT
Eric Andersenff9eee42001-06-29 04:57:14 +0000847 if (prompt->value == null)
Eric Andersen1c039232001-07-07 00:05:55 +0000848#endif
Mike Frysinger2a131752006-06-06 06:26:12 +0000849 setval(prompt, DEFAULT_USER_PROMPT);
Eric Andersenff9eee42001-06-29 04:57:14 +0000850 if (geteuid() == 0) {
Mike Frysinger2a131752006-06-06 06:26:12 +0000851 setval(prompt, DEFAULT_ROOT_PROMPT);
Eric Andersenff9eee42001-06-29 04:57:14 +0000852 prompt->status &= ~EXPORT;
853 }
854 cprompt = lookup("PS2");
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000855#ifdef CONFIG_FEATURE_SH_FANCY_PROMPT
Eric Andersenff9eee42001-06-29 04:57:14 +0000856 if (cprompt->value == null)
Eric Andersen1c039232001-07-07 00:05:55 +0000857#endif
Eric Andersenff9eee42001-06-29 04:57:14 +0000858 setval(cprompt, "> ");
859
860 iof = filechar;
861 cflag = 0;
862 name = *argv++;
863 if (--argc >= 1) {
Eric Andersen8401eea2004-08-04 19:16:54 +0000864 if (argv[0][0] == '-' && argv[0][1] != '\0') {
865 for (s = argv[0] + 1; *s; s++)
Eric Andersenff9eee42001-06-29 04:57:14 +0000866 switch (*s) {
867 case 'c':
868 prompt->status &= ~EXPORT;
869 cprompt->status &= ~EXPORT;
870 setval(prompt, "");
871 setval(cprompt, "");
872 cflag = 1;
873 if (--argc > 0)
874 PUSHIO(aword, *++argv, iof = nlchar);
875 break;
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000876
Eric Andersenff9eee42001-06-29 04:57:14 +0000877 case 'q':
878 qflag = SIG_DFL;
879 break;
880
881 case 's':
882 /* standard input */
883 break;
884
885 case 't':
886 prompt->status &= ~EXPORT;
887 setval(prompt, "");
888 iof = linechar;
889 break;
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000890
Eric Andersenff9eee42001-06-29 04:57:14 +0000891 case 'i':
892 interactive++;
893 default:
Eric Andersen8401eea2004-08-04 19:16:54 +0000894 if (*s >= 'a' && *s <= 'z')
895 flag[(int) *s]++;
Eric Andersenff9eee42001-06-29 04:57:14 +0000896 }
897 } else {
898 argv--;
899 argc++;
900 }
Eric Andersen12de6cf2004-08-04 19:19:10 +0000901
Eric Andersenff9eee42001-06-29 04:57:14 +0000902 if (iof == filechar && --argc > 0) {
903 setval(prompt, "");
904 setval(cprompt, "");
905 prompt->status &= ~EXPORT;
906 cprompt->status &= ~EXPORT;
Eric Andersen12de6cf2004-08-04 19:19:10 +0000907
908/* Shell is non-interactive, activate printf-based debug */
909#ifdef MSHDEBUG
910 mshdbg = (int) (((char) (mshdbg_var->value[0])) - '0');
911 if (mshdbg < 0)
912 mshdbg = 0;
913#endif
914 DBGPRINTF(("MSH_MAIN: calling newfile()\n"));
915
Eric Andersenff9eee42001-06-29 04:57:14 +0000916 if (newfile(name = *++argv))
Eric Andersen12de6cf2004-08-04 19:19:10 +0000917 exit(1); /* Exit on error */
Eric Andersenff9eee42001-06-29 04:57:14 +0000918 }
919 }
Eric Andersen12de6cf2004-08-04 19:19:10 +0000920
Eric Andersenff9eee42001-06-29 04:57:14 +0000921 setdash();
Eric Andersen12de6cf2004-08-04 19:19:10 +0000922
923 /* This won't be true if PUSHIO has been called, say from newfile() above */
Eric Andersenff9eee42001-06-29 04:57:14 +0000924 if (e.iop < iostack) {
925 PUSHIO(afile, 0, iof);
Eric Andersen1c039232001-07-07 00:05:55 +0000926 if (isatty(0) && isatty(1) && !cflag) {
Eric Andersenff9eee42001-06-29 04:57:14 +0000927 interactive++;
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000928#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
Eric Andersen12de6cf2004-08-04 19:19:10 +0000929#ifdef MSHDEBUG
"Vladimir N. Oleynik"dd1ccdd2006-02-16 15:40:24 +0000930 printf("\n\n%s Built-in shell (msh with debug)\n", BB_BANNER);
Eric Andersen12de6cf2004-08-04 19:19:10 +0000931#else
"Vladimir N. Oleynik"dd1ccdd2006-02-16 15:40:24 +0000932 printf("\n\n%s Built-in shell (msh)\n", BB_BANNER);
Eric Andersen12de6cf2004-08-04 19:19:10 +0000933#endif
Eric Andersen8401eea2004-08-04 19:16:54 +0000934 printf("Enter 'help' for a list of built-in commands.\n\n");
Eric Andersend63dee42001-10-19 00:22:23 +0000935#endif
Eric Andersen1c039232001-07-07 00:05:55 +0000936 }
Eric Andersenff9eee42001-06-29 04:57:14 +0000937 }
Eric Andersen12de6cf2004-08-04 19:19:10 +0000938
Eric Andersenff9eee42001-06-29 04:57:14 +0000939 signal(SIGQUIT, qflag);
940 if (name && name[0] == '-') {
941 interactive++;
942 if ((f = open(".profile", 0)) >= 0)
943 next(remap(f));
944 if ((f = open("/etc/profile", 0)) >= 0)
945 next(remap(f));
946 }
947 if (interactive)
948 signal(SIGTERM, sig);
Eric Andersen12de6cf2004-08-04 19:19:10 +0000949
Eric Andersenff9eee42001-06-29 04:57:14 +0000950 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
951 signal(SIGINT, onintr);
952 dolv = argv;
953 dolc = argc;
954 dolv[0] = name;
955 if (dolc > 1) {
956 for (ap = ++argv; --argc > 0;) {
957 if (assign(*ap = *argv++, !COPYV)) {
Eric Andersen8401eea2004-08-04 19:16:54 +0000958 dolc--; /* keyword */
Eric Andersenff9eee42001-06-29 04:57:14 +0000959 } else {
960 ap++;
961 }
962 }
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000963 }
Eric Andersenff9eee42001-06-29 04:57:14 +0000964 setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc));
965
Mike Frysinger02d8fa42006-05-05 20:32:31 +0000966 DBGPRINTF(("MSH_MAIN: begin FOR loop, interactive %d, e.iop %p, iostack %p\n", interactive, e.iop, iostack));
Eric Andersen12de6cf2004-08-04 19:19:10 +0000967
Eric Andersenff9eee42001-06-29 04:57:14 +0000968 for (;;) {
969 if (interactive && e.iop <= iostack) {
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000970#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +0000971 current_prompt = prompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +0000972#else
973 prs(prompt->value);
974#endif
975 }
976 onecommand();
Eric Andersen1c315012002-04-26 23:40:09 +0000977 /* Ensure that getenv("PATH") stays current */
978 setenv("PATH", path->value, 1);
Eric Andersenff9eee42001-06-29 04:57:14 +0000979 }
Eric Andersen12de6cf2004-08-04 19:19:10 +0000980
981 DBGPRINTF(("MSH_MAIN: returning.\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +0000982}
983
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +0000984static void setdash(void)
Eric Andersenff9eee42001-06-29 04:57:14 +0000985{
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000986 char *cp;
987 int c;
Eric Andersen8401eea2004-08-04 19:16:54 +0000988 char m['z' - 'a' + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +0000989
990 cp = m;
Eric Andersen8401eea2004-08-04 19:16:54 +0000991 for (c = 'a'; c <= 'z'; c++)
992 if (flag[(int) c])
Eric Andersenff9eee42001-06-29 04:57:14 +0000993 *cp++ = c;
994 *cp = 0;
995 setval(lookup("-"), m);
996}
997
"Robert P. J. Day"68229832006-07-01 13:08:46 +0000998static int newfile(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +0000999{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001000 int f;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001001
1002 DBGPRINTF7(("NEWFILE: opening %s\n", s));
Eric Andersenff9eee42001-06-29 04:57:14 +00001003
Denis Vlasenko9f739442006-12-16 23:49:13 +00001004 if (NOT_LONE_DASH(s)) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001005 DBGPRINTF(("NEWFILE: s is %s\n", s));
Eric Andersenff9eee42001-06-29 04:57:14 +00001006 f = open(s, 0);
1007 if (f < 0) {
1008 prs(s);
1009 err(": cannot open");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001010 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001011 }
1012 } else
1013 f = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001014
Eric Andersenff9eee42001-06-29 04:57:14 +00001015 next(remap(f));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001016 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001017}
1018
Eric Andersen12de6cf2004-08-04 19:19:10 +00001019
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001020struct op *scantree(struct op *head)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001021{
1022 struct op *dotnode;
1023
1024 if (head == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001025 return NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001026
1027 if (head->left != NULL) {
1028 dotnode = scantree(head->left);
1029 if (dotnode)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001030 return dotnode;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001031 }
1032
1033 if (head->right != NULL) {
1034 dotnode = scantree(head->right);
1035 if (dotnode)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001036 return dotnode;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001037 }
1038
1039 if (head->words == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001040 return NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001041
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001042 DBGPRINTF5(("SCANTREE: checking node %p\n", head));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001043
1044 if ((head->type != TDOT) && (strcmp(".", head->words[0]) == 0)) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001045 DBGPRINTF5(("SCANTREE: dot found in node %p\n", head));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001046 return head;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001047 }
1048
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001049 return NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001050}
1051
1052
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001053static void onecommand(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001054{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001055 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00001056 jmp_buf m1;
1057
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001058 DBGPRINTF(("ONECOMMAND: enter, outtree=%p\n", outtree));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001059
Eric Andersenff9eee42001-06-29 04:57:14 +00001060 while (e.oenv)
1061 quitenv();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001062
Eric Andersenff9eee42001-06-29 04:57:14 +00001063 areanum = 1;
1064 freehere(areanum);
1065 freearea(areanum);
1066 garbage();
1067 wdlist = 0;
1068 iolist = 0;
1069 e.errpt = 0;
1070 e.linep = line;
1071 yynerrs = 0;
1072 multiline = 0;
1073 inparse = 1;
1074 intr = 0;
1075 execflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001076
Eric Andersen8401eea2004-08-04 19:16:54 +00001077 setjmp(failpt = m1); /* Bruce Evans' fix */
Eric Andersenff9eee42001-06-29 04:57:14 +00001078 if (setjmp(failpt = m1) || yyparse() || intr) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001079
1080 DBGPRINTF(("ONECOMMAND: this is not good.\n"));
1081
Eric Andersenff9eee42001-06-29 04:57:14 +00001082 while (e.oenv)
1083 quitenv();
1084 scraphere();
1085 if (!interactive && intr)
1086 leave();
1087 inparse = 0;
1088 intr = 0;
1089 return;
1090 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001091
Eric Andersenff9eee42001-06-29 04:57:14 +00001092 inparse = 0;
1093 brklist = 0;
1094 intr = 0;
1095 execflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001096
1097 if (!flag['n']) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001098 DBGPRINTF(("ONECOMMAND: calling execute, t=outtree=%p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00001099 outtree));
Eric Andersenff9eee42001-06-29 04:57:14 +00001100 execute(outtree, NOPIPE, NOPIPE, 0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001101 }
1102
Eric Andersenff9eee42001-06-29 04:57:14 +00001103 if (!interactive && intr) {
1104 execflg = 0;
1105 leave();
1106 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001107
Eric Andersenff9eee42001-06-29 04:57:14 +00001108 if ((i = trapset) != 0) {
1109 trapset = 0;
1110 runtrap(i);
1111 }
1112}
1113
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001114static void fail(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001115{
1116 longjmp(failpt, 1);
1117 /* NOTREACHED */
1118}
1119
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001120static void leave(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001121{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001122 DBGPRINTF(("LEAVE: leave called!\n"));
1123
Eric Andersenff9eee42001-06-29 04:57:14 +00001124 if (execflg)
1125 fail();
1126 scraphere();
1127 freehere(1);
1128 runtrap(0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001129 _exit(exstat);
Eric Andersenff9eee42001-06-29 04:57:14 +00001130 /* NOTREACHED */
1131}
1132
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001133static void warn(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00001134{
Eric Andersen8401eea2004-08-04 19:16:54 +00001135 if (*s) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001136 prs(s);
1137 exstat = -1;
1138 }
1139 prs("\n");
1140 if (flag['e'])
1141 leave();
1142}
1143
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001144static void err(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00001145{
1146 warn(s);
1147 if (flag['n'])
1148 return;
1149 if (!interactive)
1150 leave();
1151 if (e.errpt)
1152 longjmp(e.errpt, 1);
1153 closeall();
1154 e.iop = e.iobase = iostack;
1155}
1156
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001157static int newenv(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00001158{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001159 struct env *ep;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001160
1161 DBGPRINTF(("NEWENV: f=%d (indicates quitenv and return)\n", f));
Eric Andersenff9eee42001-06-29 04:57:14 +00001162
1163 if (f) {
1164 quitenv();
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001165 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001166 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001167
Eric Andersenff9eee42001-06-29 04:57:14 +00001168 ep = (struct env *) space(sizeof(*ep));
1169 if (ep == NULL) {
1170 while (e.oenv)
1171 quitenv();
1172 fail();
1173 }
1174 *ep = e;
1175 e.oenv = ep;
1176 e.errpt = errpt;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001177
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001178 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001179}
1180
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001181static void quitenv(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001182{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001183 struct env *ep;
1184 int fd;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001185
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001186 DBGPRINTF(("QUITENV: e.oenv=%p\n", e.oenv));
Eric Andersenff9eee42001-06-29 04:57:14 +00001187
1188 if ((ep = e.oenv) != NULL) {
1189 fd = e.iofd;
1190 e = *ep;
1191 /* should close `'d files */
1192 DELETE(ep);
1193 while (--fd >= e.iofd)
1194 close(fd);
1195 }
1196}
1197
1198/*
1199 * Is any character from s1 in s2?
1200 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001201static int anys(char *s1, char *s2)
Eric Andersenff9eee42001-06-29 04:57:14 +00001202{
1203 while (*s1)
1204 if (any(*s1++, s2))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001205 return 1;
1206 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001207}
1208
1209/*
1210 * Is character c in s?
1211 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001212static int any(int c, char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00001213{
1214 while (*s)
1215 if (*s++ == c)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001216 return 1;
1217 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001218}
1219
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001220static char *putn(int n)
Eric Andersenff9eee42001-06-29 04:57:14 +00001221{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001222 return itoa(n);
Eric Andersenff9eee42001-06-29 04:57:14 +00001223}
1224
Eric Andersen8401eea2004-08-04 19:16:54 +00001225static void next(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00001226{
1227 PUSHIO(afile, f, filechar);
1228}
1229
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001230static void onintr(int s) /* ANSI C requires a parameter */
Eric Andersenff9eee42001-06-29 04:57:14 +00001231{
1232 signal(SIGINT, onintr);
1233 intr = 1;
1234 if (interactive) {
1235 if (inparse) {
1236 prs("\n");
1237 fail();
1238 }
Eric Andersen8401eea2004-08-04 19:16:54 +00001239 } else if (heedint) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001240 execflg = 0;
1241 leave();
1242 }
1243}
1244
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001245static char *space(int n)
Eric Andersenff9eee42001-06-29 04:57:14 +00001246{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001247 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00001248
1249 if ((cp = getcell(n)) == 0)
1250 err("out of string space");
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001251 return cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00001252}
1253
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001254static char *strsave(char *s, int a)
Eric Andersenff9eee42001-06-29 04:57:14 +00001255{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001256 char *cp, *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00001257
Eric Andersen8401eea2004-08-04 19:16:54 +00001258 if ((cp = space(strlen(s) + 1)) != NULL) {
1259 setarea((char *) cp, a);
1260 for (xp = cp; (*xp++ = *s++) != '\0';);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001261 return cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00001262 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001263 return "";
Eric Andersenff9eee42001-06-29 04:57:14 +00001264}
1265
1266/*
1267 * trap handling
1268 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001269static void sig(int i)
Eric Andersenff9eee42001-06-29 04:57:14 +00001270{
1271 trapset = i;
1272 signal(i, sig);
1273}
1274
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001275static void runtrap(int i)
Eric Andersenff9eee42001-06-29 04:57:14 +00001276{
1277 char *trapstr;
1278
1279 if ((trapstr = trap[i]) == NULL)
1280 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001281
Eric Andersenff9eee42001-06-29 04:57:14 +00001282 if (i == 0)
1283 trap[i] = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001284
Eric Andersenff9eee42001-06-29 04:57:14 +00001285 RUN(aword, trapstr, nlchar);
1286}
1287
1288/* -------- var.c -------- */
1289
1290/*
1291 * Find the given name in the dictionary
1292 * and return its value. If the name was
1293 * not previously there, enter it now and
1294 * return a null value.
1295 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001296static struct var *lookup(char *n)
Eric Andersenff9eee42001-06-29 04:57:14 +00001297{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001298 struct var *vp;
1299 char *cp;
1300 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00001301 static struct var dummy;
1302
1303 if (isdigit(*n)) {
1304 dummy.name = n;
1305 for (c = 0; isdigit(*n) && c < 1000; n++)
Eric Andersen8401eea2004-08-04 19:16:54 +00001306 c = c * 10 + *n - '0';
Eric Andersenff9eee42001-06-29 04:57:14 +00001307 dummy.status = RONLY;
Eric Andersen8401eea2004-08-04 19:16:54 +00001308 dummy.value = c <= dolc ? dolv[c] : null;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001309 return &dummy;
Eric Andersenff9eee42001-06-29 04:57:14 +00001310 }
1311 for (vp = vlist; vp; vp = vp->next)
1312 if (eqname(vp->name, n))
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001313 return vp;
Eric Andersenff9eee42001-06-29 04:57:14 +00001314 cp = findeq(n);
Eric Andersen8401eea2004-08-04 19:16:54 +00001315 vp = (struct var *) space(sizeof(*vp));
1316 if (vp == 0 || (vp->name = space((int) (cp - n) + 2)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001317 dummy.name = dummy.value = "";
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001318 return &dummy;
Eric Andersenff9eee42001-06-29 04:57:14 +00001319 }
Eric Andersen8401eea2004-08-04 19:16:54 +00001320 for (cp = vp->name; (*cp = *n++) && *cp != '='; cp++);
Eric Andersenff9eee42001-06-29 04:57:14 +00001321 if (*cp == 0)
1322 *cp = '=';
1323 *++cp = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00001324 setarea((char *) vp, 0);
1325 setarea((char *) vp->name, 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001326 vp->value = null;
1327 vp->next = vlist;
1328 vp->status = GETCELL;
1329 vlist = vp;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001330 return vp;
Eric Andersenff9eee42001-06-29 04:57:14 +00001331}
1332
1333/*
1334 * give variable at `vp' the value `val'.
1335 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001336static void setval(struct var *vp, char *val)
Eric Andersenff9eee42001-06-29 04:57:14 +00001337{
Eric Andersen8401eea2004-08-04 19:16:54 +00001338 nameval(vp, val, (char *) NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00001339}
1340
1341/*
1342 * if name is not NULL, it must be
1343 * a prefix of the space `val',
1344 * and end with `='.
1345 * this is all so that exporting
1346 * values is reasonably painless.
1347 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001348static void nameval(struct var *vp, char *val, char *name)
Eric Andersenff9eee42001-06-29 04:57:14 +00001349{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001350 char *cp, *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00001351 char *nv;
1352 int fl;
1353
1354 if (vp->status & RONLY) {
1355 for (xp = vp->name; *xp && *xp != '=';)
1356 putc(*xp++, stderr);
1357 err(" is read-only");
1358 return;
1359 }
1360 fl = 0;
1361 if (name == NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00001362 xp = space(strlen(vp->name) + strlen(val) + 2);
Eric Andersenff9eee42001-06-29 04:57:14 +00001363 if (xp == 0)
1364 return;
1365 /* make string: name=value */
Eric Andersen8401eea2004-08-04 19:16:54 +00001366 setarea((char *) xp, 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001367 name = xp;
Eric Andersen8401eea2004-08-04 19:16:54 +00001368 for (cp = vp->name; (*xp = *cp++) && *xp != '='; xp++);
Eric Andersenff9eee42001-06-29 04:57:14 +00001369 if (*xp++ == 0)
1370 xp[-1] = '=';
1371 nv = xp;
Eric Andersen8401eea2004-08-04 19:16:54 +00001372 for (cp = val; (*xp++ = *cp++) != '\0';);
Eric Andersenff9eee42001-06-29 04:57:14 +00001373 val = nv;
1374 fl = GETCELL;
1375 }
1376 if (vp->status & GETCELL)
Eric Andersen8401eea2004-08-04 19:16:54 +00001377 freecell(vp->name); /* form new string `name=value' */
Eric Andersenff9eee42001-06-29 04:57:14 +00001378 vp->name = name;
1379 vp->value = val;
1380 vp->status |= fl;
1381}
1382
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001383static void export(struct var *vp)
Eric Andersenff9eee42001-06-29 04:57:14 +00001384{
1385 vp->status |= EXPORT;
1386}
1387
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001388static void ronly(struct var *vp)
Eric Andersenff9eee42001-06-29 04:57:14 +00001389{
Matt Kraai69edfec2001-08-06 14:14:18 +00001390 if (isalpha(vp->name[0]) || vp->name[0] == '_') /* not an internal symbol */
Eric Andersenff9eee42001-06-29 04:57:14 +00001391 vp->status |= RONLY;
1392}
1393
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001394static int isassign(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00001395{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001396 DBGPRINTF7(("ISASSIGN: enter, s=%s\n", s));
1397
Eric Andersen8401eea2004-08-04 19:16:54 +00001398 if (!isalpha((int) *s) && *s != '_')
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001399 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001400 for (; *s != '='; s++)
Matt Kraai69edfec2001-08-06 14:14:18 +00001401 if (*s == 0 || (!isalnum(*s) && *s != '_'))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001402 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001403
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001404 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001405}
1406
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001407static int assign(char *s, int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001408{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001409 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00001410 struct var *vp;
1411
Eric Andersen12de6cf2004-08-04 19:19:10 +00001412 DBGPRINTF7(("ASSIGN: enter, s=%s, cf=%d\n", s, cf));
1413
Matt Kraai69edfec2001-08-06 14:14:18 +00001414 if (!isalpha(*s) && *s != '_')
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001415 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001416 for (cp = s; *cp != '='; cp++)
Matt Kraai69edfec2001-08-06 14:14:18 +00001417 if (*cp == 0 || (!isalnum(*cp) && *cp != '_'))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001418 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001419 vp = lookup(s);
Eric Andersen8401eea2004-08-04 19:16:54 +00001420 nameval(vp, ++cp, cf == COPYV ? (char *) NULL : s);
Eric Andersenff9eee42001-06-29 04:57:14 +00001421 if (cf != COPYV)
1422 vp->status &= ~GETCELL;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001423 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001424}
1425
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001426static int checkname(char *cp)
Eric Andersenff9eee42001-06-29 04:57:14 +00001427{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001428 DBGPRINTF7(("CHECKNAME: enter, cp=%s\n", cp));
1429
Eric Andersen8401eea2004-08-04 19:16:54 +00001430 if (!isalpha(*cp++) && *(cp - 1) != '_')
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001431 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001432 while (*cp)
Eric Andersen8401eea2004-08-04 19:16:54 +00001433 if (!isalnum(*cp++) && *(cp - 1) != '_')
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001434 return 0;
1435 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001436}
1437
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001438static void putvlist(int f, int out)
Eric Andersenff9eee42001-06-29 04:57:14 +00001439{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001440 struct var *vp;
Eric Andersenff9eee42001-06-29 04:57:14 +00001441
1442 for (vp = vlist; vp; vp = vp->next)
Matt Kraai69edfec2001-08-06 14:14:18 +00001443 if (vp->status & f && (isalpha(*vp->name) || *vp->name == '_')) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001444 if (vp->status & EXPORT)
1445 write(out, "export ", 7);
1446 if (vp->status & RONLY)
1447 write(out, "readonly ", 9);
Eric Andersen8401eea2004-08-04 19:16:54 +00001448 write(out, vp->name, (int) (findeq(vp->name) - vp->name));
Eric Andersenff9eee42001-06-29 04:57:14 +00001449 write(out, "\n", 1);
1450 }
1451}
1452
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001453static int eqname(char *n1, char *n2)
Eric Andersenff9eee42001-06-29 04:57:14 +00001454{
1455 for (; *n1 != '=' && *n1 != 0; n1++)
1456 if (*n2++ != *n1)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001457 return 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001458 return *n2 == 0 || *n2 == '=';
Eric Andersenff9eee42001-06-29 04:57:14 +00001459}
1460
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001461static char *findeq(char *cp)
Eric Andersenff9eee42001-06-29 04:57:14 +00001462{
1463 while (*cp != '\0' && *cp != '=')
1464 cp++;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001465 return cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00001466}
1467
1468/* -------- 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
1478#define QMASK (CMASK&~QUOTE)
Eric Andersen8401eea2004-08-04 19:16:54 +00001479#define NOT '!' /* might use ^ */
Eric Andersenff9eee42001-06-29 04:57:14 +00001480
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001481static int gmatch(char *s, char *p)
Eric Andersenff9eee42001-06-29 04:57:14 +00001482{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001483 int sc, pc;
Eric Andersenff9eee42001-06-29 04:57:14 +00001484
1485 if (s == NULL || p == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001486 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001487 while ((pc = *p++ & CMASK) != '\0') {
1488 sc = *s++ & QMASK;
1489 switch (pc) {
1490 case '[':
1491 if ((p = cclass(p, sc)) == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001492 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001493 break;
1494
1495 case '?':
1496 if (sc == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001497 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001498 break;
1499
1500 case '*':
1501 s--;
1502 do {
1503 if (*p == '\0' || gmatch(s, p))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001504 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001505 } while (*s++ != '\0');
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001506 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001507
1508 default:
Eric Andersen8401eea2004-08-04 19:16:54 +00001509 if (sc != (pc & ~QUOTE))
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001510 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001511 }
1512 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001513 return *s == 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001514}
1515
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001516static char *cclass(char *p, int sub)
Eric Andersenff9eee42001-06-29 04:57:14 +00001517{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001518 int c, d, not, found;
Eric Andersenff9eee42001-06-29 04:57:14 +00001519
1520 if ((not = *p == NOT) != 0)
1521 p++;
1522 found = not;
1523 do {
1524 if (*p == '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001525 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001526 c = *p & CMASK;
1527 if (p[1] == '-' && p[2] != ']') {
1528 d = p[2] & CMASK;
1529 p++;
1530 } else
1531 d = c;
1532 if (c == sub || (c <= sub && sub <= d))
1533 found = !not;
1534 } while (*++p != ']');
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001535 return found ? p + 1 : NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001536}
1537
1538
1539/* -------- area.c -------- */
1540
1541/*
1542 * All memory between (char *)areabot and (char *)(areatop+1) is
1543 * exclusively administered by the area management routines.
1544 * It is assumed that sbrk() and brk() manipulate the high end.
1545 */
1546
1547#define sbrk(X) ({ void * __q = (void *)-1; if (brkaddr + (int)(X) < brktop) { __q = brkaddr; brkaddr+=(int)(X); } __q;})
1548
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001549static void initarea(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001550{
Mike Frysinger3132e9d2006-06-02 06:30:30 +00001551 brkaddr = xmalloc(AREASIZE);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001552 brktop = brkaddr + AREASIZE;
Eric Andersenff9eee42001-06-29 04:57:14 +00001553
Eric Andersena68ea1c2006-01-30 22:48:39 +00001554 while ((long) sbrk(0) & ALIGN)
Eric Andersenff9eee42001-06-29 04:57:14 +00001555 sbrk(1);
Eric Andersen8401eea2004-08-04 19:16:54 +00001556 areabot = (struct region *) sbrk(REGSIZE);
Eric Andersenff9eee42001-06-29 04:57:14 +00001557
1558 areabot->next = areabot;
1559 areabot->area = BUSY;
1560 areatop = areabot;
1561 areanxt = areabot;
1562}
1563
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001564char *getcell(unsigned nbytes)
Eric Andersenff9eee42001-06-29 04:57:14 +00001565{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001566 int nregio;
1567 struct region *p, *q;
1568 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00001569
1570 if (nbytes == 0) {
1571 puts("getcell(0)");
1572 abort();
Eric Andersen8401eea2004-08-04 19:16:54 +00001573 }
1574 /* silly and defeats the algorithm */
Eric Andersenff9eee42001-06-29 04:57:14 +00001575 /*
1576 * round upwards and add administration area
1577 */
Eric Andersen8401eea2004-08-04 19:16:54 +00001578 nregio = (nbytes + (REGSIZE - 1)) / REGSIZE + 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001579 for (p = areanxt;;) {
1580 if (p->area > areanum) {
1581 /*
1582 * merge free cells
1583 */
1584 while ((q = p->next)->area > areanum && q != areanxt)
1585 p->next = q->next;
1586 /*
1587 * exit loop if cell big enough
1588 */
1589 if (q >= p + nregio)
1590 goto found;
1591 }
1592 p = p->next;
1593 if (p == areanxt)
1594 break;
1595 }
1596 i = nregio >= GROWBY ? nregio : GROWBY;
Eric Andersen8401eea2004-08-04 19:16:54 +00001597 p = (struct region *) sbrk(i * REGSIZE);
1598 if (p == (struct region *) -1)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001599 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001600 p--;
1601 if (p != areatop) {
1602 puts("not contig");
Eric Andersen8401eea2004-08-04 19:16:54 +00001603 abort(); /* allocated areas are contiguous */
Eric Andersenff9eee42001-06-29 04:57:14 +00001604 }
1605 q = p + i;
1606 p->next = q;
1607 p->area = FREE;
1608 q->next = areabot;
1609 q->area = BUSY;
1610 areatop = q;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001611 found:
Eric Andersenff9eee42001-06-29 04:57:14 +00001612 /*
1613 * we found a FREE area big enough, pointed to by 'p', and up to 'q'
1614 */
1615 areanxt = p + nregio;
1616 if (areanxt < q) {
1617 /*
1618 * split into requested area and rest
1619 */
Eric Andersen8401eea2004-08-04 19:16:54 +00001620 if (areanxt + 1 > q) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001621 puts("OOM");
Eric Andersen8401eea2004-08-04 19:16:54 +00001622 abort(); /* insufficient space left for admin */
Eric Andersenff9eee42001-06-29 04:57:14 +00001623 }
1624 areanxt->next = q;
1625 areanxt->area = FREE;
1626 p->next = areanxt;
1627 }
1628 p->area = areanum;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001629 return (char *) (p + 1);
Eric Andersenff9eee42001-06-29 04:57:14 +00001630}
1631
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001632static void freecell(char *cp)
Eric Andersenff9eee42001-06-29 04:57:14 +00001633{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001634 struct region *p;
Eric Andersenff9eee42001-06-29 04:57:14 +00001635
Eric Andersen8401eea2004-08-04 19:16:54 +00001636 if ((p = (struct region *) cp) != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001637 p--;
1638 if (p < areanxt)
1639 areanxt = p;
1640 p->area = FREE;
1641 }
1642}
1643
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001644static void freearea(int a)
Eric Andersenff9eee42001-06-29 04:57:14 +00001645{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001646 struct region *p, *top;
Eric Andersenff9eee42001-06-29 04:57:14 +00001647
1648 top = areatop;
1649 for (p = areabot; p != top; p = p->next)
1650 if (p->area >= a)
1651 p->area = FREE;
1652}
1653
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001654static void setarea(char *cp, int a)
Eric Andersenff9eee42001-06-29 04:57:14 +00001655{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001656 struct region *p;
Eric Andersenff9eee42001-06-29 04:57:14 +00001657
Eric Andersen8401eea2004-08-04 19:16:54 +00001658 if ((p = (struct region *) cp) != NULL)
1659 (p - 1)->area = a;
Eric Andersenff9eee42001-06-29 04:57:14 +00001660}
1661
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001662int getarea(char *cp)
Eric Andersenff9eee42001-06-29 04:57:14 +00001663{
Eric Andersen8401eea2004-08-04 19:16:54 +00001664 return ((struct region *) cp - 1)->area;
Eric Andersenff9eee42001-06-29 04:57:14 +00001665}
1666
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001667static void garbage(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001668{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001669 struct region *p, *q, *top;
Eric Andersenff9eee42001-06-29 04:57:14 +00001670
1671 top = areatop;
1672 for (p = areabot; p != top; p = p->next) {
1673 if (p->area > areanum) {
1674 while ((q = p->next)->area > areanum)
1675 p->next = q->next;
1676 areanxt = p;
1677 }
1678 }
1679#ifdef SHRINKBY
1680 if (areatop >= q + SHRINKBY && q->area > areanum) {
Eric Andersen8401eea2004-08-04 19:16:54 +00001681 brk((char *) (q + 1));
Eric Andersenff9eee42001-06-29 04:57:14 +00001682 q->next = areabot;
1683 q->area = BUSY;
1684 areatop = q;
1685 }
1686#endif
1687}
1688
1689/* -------- csyn.c -------- */
1690/*
1691 * shell: syntax (C version)
1692 */
1693
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001694int yyparse(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001695{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001696 DBGPRINTF7(("YYPARSE: enter...\n"));
1697
Eric Andersen8401eea2004-08-04 19:16:54 +00001698 startl = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001699 peeksym = 0;
1700 yynerrs = 0;
1701 outtree = c_list();
1702 musthave('\n', 0);
Eric Andersen8401eea2004-08-04 19:16:54 +00001703 return (yynerrs != 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00001704}
1705
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001706static struct op *pipeline(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001707{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001708 struct op *t, *p;
1709 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001710
1711 DBGPRINTF7(("PIPELINE: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001712
1713 t = command(cf);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001714
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001715 DBGPRINTF9(("PIPELINE: t=%p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001716
Eric Andersenff9eee42001-06-29 04:57:14 +00001717 if (t != NULL) {
1718 while ((c = yylex(0)) == '|') {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001719 if ((p = command(CONTIN)) == NULL) {
1720 DBGPRINTF8(("PIPELINE: error!\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001721 SYNTAXERR;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001722 }
1723
Eric Andersenff9eee42001-06-29 04:57:14 +00001724 if (t->type != TPAREN && t->type != TCOM) {
1725 /* shell statement */
1726 t = block(TPAREN, t, NOBLOCK, NOWORDS);
1727 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001728
Eric Andersenff9eee42001-06-29 04:57:14 +00001729 t = block(TPIPE, t, p, NOWORDS);
1730 }
1731 peeksym = c;
1732 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001733
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001734 DBGPRINTF7(("PIPELINE: returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001735 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001736}
1737
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001738static struct op *andor(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001739{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001740 struct op *t, *p;
1741 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001742
1743 DBGPRINTF7(("ANDOR: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001744
1745 t = pipeline(0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001746
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001747 DBGPRINTF9(("ANDOR: t=%p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001748
Eric Andersenff9eee42001-06-29 04:57:14 +00001749 if (t != NULL) {
1750 while ((c = yylex(0)) == LOGAND || c == LOGOR) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001751 if ((p = pipeline(CONTIN)) == NULL) {
1752 DBGPRINTF8(("ANDOR: error!\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001753 SYNTAXERR;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001754 }
1755
Eric Andersen8401eea2004-08-04 19:16:54 +00001756 t = block(c == LOGAND ? TAND : TOR, t, p, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001757 } /* WHILE */
1758
Eric Andersenff9eee42001-06-29 04:57:14 +00001759 peeksym = c;
1760 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001761
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001762 DBGPRINTF7(("ANDOR: returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001763 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001764}
1765
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001766static struct op *c_list(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001767{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001768 struct op *t, *p;
1769 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001770
1771 DBGPRINTF7(("C_LIST: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001772
1773 t = andor();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001774
Eric Andersenff9eee42001-06-29 04:57:14 +00001775 if (t != NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00001776 if ((peeksym = yylex(0)) == '&')
Eric Andersenff9eee42001-06-29 04:57:14 +00001777 t = block(TASYNC, t, NOBLOCK, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001778
Eric Andersen8401eea2004-08-04 19:16:54 +00001779 while ((c = yylex(0)) == ';' || c == '&'
1780 || (multiline && c == '\n')) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00001781
Eric Andersenff9eee42001-06-29 04:57:14 +00001782 if ((p = andor()) == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001783 return t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001784
Eric Andersen8401eea2004-08-04 19:16:54 +00001785 if ((peeksym = yylex(0)) == '&')
Eric Andersenff9eee42001-06-29 04:57:14 +00001786 p = block(TASYNC, p, NOBLOCK, NOWORDS);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001787
Eric Andersenff9eee42001-06-29 04:57:14 +00001788 t = list(t, p);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001789 } /* WHILE */
1790
Eric Andersenff9eee42001-06-29 04:57:14 +00001791 peeksym = c;
1792 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001793 /* IF */
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001794 DBGPRINTF7(("C_LIST: returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001795 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001796}
1797
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001798static int synio(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001799{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001800 struct ioword *iop;
1801 int i;
1802 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001803
1804 DBGPRINTF7(("SYNIO: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001805
1806 if ((c = yylex(cf)) != '<' && c != '>') {
1807 peeksym = c;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001808 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00001809 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001810
Eric Andersenff9eee42001-06-29 04:57:14 +00001811 i = yylval.i;
1812 musthave(WORD, 0);
1813 iop = io(iounit, i, yylval.cp);
1814 iounit = IODEFAULT;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001815
Eric Andersenff9eee42001-06-29 04:57:14 +00001816 if (i & IOHERE)
1817 markhere(yylval.cp, iop);
Eric Andersen12de6cf2004-08-04 19:19:10 +00001818
1819 DBGPRINTF7(("SYNIO: returning 1\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00001820 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00001821}
1822
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001823static void musthave(int c, int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001824{
Eric Andersen12de6cf2004-08-04 19:19:10 +00001825 if ((peeksym = yylex(cf)) != c) {
1826 DBGPRINTF7(("MUSTHAVE: error!\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00001827 SYNTAXERR;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001828 }
1829
Eric Andersenff9eee42001-06-29 04:57:14 +00001830 peeksym = 0;
1831}
1832
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001833static struct op *simple(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00001834{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001835 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001836
1837 t = NULL;
1838 for (;;) {
1839 switch (peeksym = yylex(0)) {
1840 case '<':
1841 case '>':
1842 (void) synio(0);
1843 break;
1844
1845 case WORD:
1846 if (t == NULL) {
1847 t = newtp();
1848 t->type = TCOM;
1849 }
1850 peeksym = 0;
1851 word(yylval.cp);
1852 break;
1853
1854 default:
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001855 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001856 }
1857 }
1858}
1859
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001860static struct op *nested(int type, int mark)
Eric Andersenff9eee42001-06-29 04:57:14 +00001861{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001862 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001863
1864 DBGPRINTF3(("NESTED: enter, type=%d, mark=%d\n", type, mark));
Eric Andersenff9eee42001-06-29 04:57:14 +00001865
1866 multiline++;
1867 t = c_list();
1868 musthave(mark, 0);
1869 multiline--;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001870 return block(type, t, NOBLOCK, NOWORDS);
Eric Andersenff9eee42001-06-29 04:57:14 +00001871}
1872
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001873static struct op *command(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00001874{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001875 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001876 struct wdblock *iosave;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001877 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001878
1879 DBGPRINTF(("COMMAND: enter, cf=%d\n", cf));
Eric Andersenff9eee42001-06-29 04:57:14 +00001880
1881 iosave = iolist;
1882 iolist = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001883
Eric Andersenff9eee42001-06-29 04:57:14 +00001884 if (multiline)
1885 cf |= CONTIN;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001886
Eric Andersenff9eee42001-06-29 04:57:14 +00001887 while (synio(cf))
1888 cf = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001889
1890 c = yylex(cf);
1891
1892 switch (c) {
Eric Andersenff9eee42001-06-29 04:57:14 +00001893 default:
1894 peeksym = c;
1895 if ((t = simple()) == NULL) {
1896 if (iolist == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001897 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001898 t = newtp();
1899 t->type = TCOM;
1900 }
1901 break;
1902
1903 case '(':
1904 t = nested(TPAREN, ')');
1905 break;
1906
1907 case '{':
1908 t = nested(TBRACE, '}');
1909 break;
1910
1911 case FOR:
1912 t = newtp();
1913 t->type = TFOR;
1914 musthave(WORD, 0);
1915 startl = 1;
1916 t->str = yylval.cp;
1917 multiline++;
1918 t->words = wordlist();
1919 if ((c = yylex(0)) != '\n' && c != ';')
1920 peeksym = c;
1921 t->left = dogroup(0);
1922 multiline--;
1923 break;
1924
1925 case WHILE:
1926 case UNTIL:
1927 multiline++;
1928 t = newtp();
Eric Andersen8401eea2004-08-04 19:16:54 +00001929 t->type = c == WHILE ? TWHILE : TUNTIL;
Eric Andersenff9eee42001-06-29 04:57:14 +00001930 t->left = c_list();
1931 t->right = dogroup(1);
1932 t->words = NULL;
1933 multiline--;
1934 break;
1935
1936 case CASE:
1937 t = newtp();
1938 t->type = TCASE;
1939 musthave(WORD, 0);
1940 t->str = yylval.cp;
1941 startl++;
1942 multiline++;
1943 musthave(IN, CONTIN);
1944 startl++;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001945
Eric Andersenff9eee42001-06-29 04:57:14 +00001946 t->left = caselist();
Eric Andersen12de6cf2004-08-04 19:19:10 +00001947
Eric Andersenff9eee42001-06-29 04:57:14 +00001948 musthave(ESAC, 0);
1949 multiline--;
1950 break;
1951
1952 case IF:
1953 multiline++;
1954 t = newtp();
1955 t->type = TIF;
1956 t->left = c_list();
1957 t->right = thenpart();
1958 musthave(FI, 0);
1959 multiline--;
1960 break;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001961
1962 case DOT:
1963 t = newtp();
1964 t->type = TDOT;
1965
1966 musthave(WORD, 0); /* gets name of file */
1967 DBGPRINTF7(("COMMAND: DOT clause, yylval.cp is %s\n", yylval.cp));
1968
1969 word(yylval.cp); /* add word to wdlist */
1970 word(NOWORD); /* terminate wdlist */
1971 t->words = copyw(); /* dup wdlist */
1972 break;
1973
Eric Andersenff9eee42001-06-29 04:57:14 +00001974 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00001975
Eric Andersen8401eea2004-08-04 19:16:54 +00001976 while (synio(0));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001977
Eric Andersenff9eee42001-06-29 04:57:14 +00001978 t = namelist(t);
1979 iolist = iosave;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001980
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001981 DBGPRINTF(("COMMAND: returning %p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00001982
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001983 return t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001984}
1985
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00001986static struct op *dowholefile(int type, int mark)
Eric Andersen12de6cf2004-08-04 19:19:10 +00001987{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00001988 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00001989
1990 DBGPRINTF(("DOWHOLEFILE: enter, type=%d, mark=%d\n", type, mark));
1991
1992 multiline++;
1993 t = c_list();
1994 multiline--;
1995 t = block(type, t, NOBLOCK, NOWORDS);
Mike Frysinger02d8fa42006-05-05 20:32:31 +00001996 DBGPRINTF(("DOWHOLEFILE: return t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00001997 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00001998}
1999
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002000static struct op *dogroup(int onlydone)
Eric Andersenff9eee42001-06-29 04:57:14 +00002001{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002002 int c;
2003 struct op *mylist;
Eric Andersenff9eee42001-06-29 04:57:14 +00002004
2005 c = yylex(CONTIN);
2006 if (c == DONE && onlydone)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002007 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00002008 if (c != DO)
2009 SYNTAXERR;
2010 mylist = c_list();
2011 musthave(DONE, 0);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002012 return mylist;
Eric Andersenff9eee42001-06-29 04:57:14 +00002013}
2014
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002015static struct op *thenpart(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002016{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002017 int c;
2018 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002019
2020 if ((c = yylex(0)) != THEN) {
2021 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002022 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00002023 }
2024 t = newtp();
2025 t->type = 0;
2026 t->left = c_list();
2027 if (t->left == NULL)
2028 SYNTAXERR;
2029 t->right = elsepart();
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002030 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002031}
2032
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002033static struct op *elsepart(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002034{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002035 int c;
2036 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002037
2038 switch (c = yylex(0)) {
2039 case ELSE:
2040 if ((t = c_list()) == NULL)
2041 SYNTAXERR;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002042 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002043
2044 case ELIF:
2045 t = newtp();
2046 t->type = TELIF;
2047 t->left = c_list();
2048 t->right = thenpart();
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002049 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002050
2051 default:
2052 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002053 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00002054 }
2055}
2056
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002057static struct op *caselist(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002058{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002059 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002060
2061 t = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002062 while ((peeksym = yylex(CONTIN)) != ESAC) {
2063 DBGPRINTF(("CASELIST, doing yylex, peeksym=%d\n", peeksym));
Eric Andersenff9eee42001-06-29 04:57:14 +00002064 t = list(t, casepart());
Eric Andersen12de6cf2004-08-04 19:19:10 +00002065 }
2066
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002067 DBGPRINTF(("CASELIST, returning t=%p\n", t));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002068 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002069}
2070
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002071static struct op *casepart(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002072{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002073 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002074
2075 DBGPRINTF7(("CASEPART: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00002076
2077 t = newtp();
2078 t->type = TPAT;
2079 t->words = pattern();
2080 musthave(')', 0);
2081 t->left = c_list();
2082 if ((peeksym = yylex(CONTIN)) != ESAC)
2083 musthave(BREAK, CONTIN);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002084
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002085 DBGPRINTF7(("CASEPART: made newtp(TPAT, t=%p)\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002086
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002087 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002088}
2089
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002090static char **pattern(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002091{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002092 int c, cf;
Eric Andersenff9eee42001-06-29 04:57:14 +00002093
2094 cf = CONTIN;
2095 do {
2096 musthave(WORD, cf);
2097 word(yylval.cp);
2098 cf = 0;
2099 } while ((c = yylex(0)) == '|');
2100 peeksym = c;
2101 word(NOWORD);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002102
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002103 return copyw();
Eric Andersenff9eee42001-06-29 04:57:14 +00002104}
2105
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002106static char **wordlist(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002107{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002108 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002109
2110 if ((c = yylex(0)) != IN) {
2111 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002112 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00002113 }
2114 startl = 0;
2115 while ((c = yylex(0)) == WORD)
2116 word(yylval.cp);
2117 word(NOWORD);
2118 peeksym = c;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002119 return copyw();
Eric Andersenff9eee42001-06-29 04:57:14 +00002120}
2121
2122/*
2123 * supporting functions
2124 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002125static struct op *list(struct op *t1, struct op *t2)
Eric Andersenff9eee42001-06-29 04:57:14 +00002126{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002127 DBGPRINTF7(("LIST: enter, t1=%p, t2=%p\n", t1, t2));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002128
Eric Andersenff9eee42001-06-29 04:57:14 +00002129 if (t1 == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002130 return t2;
Eric Andersenff9eee42001-06-29 04:57:14 +00002131 if (t2 == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002132 return t1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002133
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002134 return block(TLIST, t1, t2, NOWORDS);
Eric Andersenff9eee42001-06-29 04:57:14 +00002135}
2136
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002137static struct op *block(int type, struct op *t1, struct op *t2, char **wp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002138{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002139 struct op *t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002140
2141 DBGPRINTF7(("BLOCK: enter, type=%d (%s)\n", type, T_CMD_NAMES[type]));
Eric Andersenff9eee42001-06-29 04:57:14 +00002142
2143 t = newtp();
2144 t->type = type;
2145 t->left = t1;
2146 t->right = t2;
2147 t->words = wp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002148
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002149 DBGPRINTF7(("BLOCK: inserted %p between %p and %p\n", t, t1,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002150 t2));
2151
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002152 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002153}
2154
Eric Andersen12de6cf2004-08-04 19:19:10 +00002155/* See if given string is a shell multiline (FOR, IF, etc) */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002156static int rlookup(char *n)
Eric Andersenff9eee42001-06-29 04:57:14 +00002157{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002158 const struct res *rp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002159
2160 DBGPRINTF7(("RLOOKUP: enter, n is %s\n", n));
Eric Andersenff9eee42001-06-29 04:57:14 +00002161
2162 for (rp = restab; rp->r_name; rp++)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002163 if (strcmp(rp->r_name, n) == 0) {
2164 DBGPRINTF7(("RLOOKUP: match, returning %d\n", rp->r_val));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002165 return rp->r_val; /* Return numeric code for shell multiline */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002166 }
2167
2168 DBGPRINTF7(("RLOOKUP: NO match, returning 0\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002169 return 0; /* Not a shell multiline */
Eric Andersenff9eee42001-06-29 04:57:14 +00002170}
2171
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002172static struct op *newtp(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002173{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002174 struct op *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002175
Eric Andersen8401eea2004-08-04 19:16:54 +00002176 t = (struct op *) tree(sizeof(*t));
Eric Andersenff9eee42001-06-29 04:57:14 +00002177 t->type = 0;
2178 t->words = NULL;
2179 t->ioact = NULL;
2180 t->left = NULL;
2181 t->right = NULL;
2182 t->str = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002183
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002184 DBGPRINTF3(("NEWTP: allocated %p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002185
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002186 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002187}
2188
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002189static struct op *namelist(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00002190{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002191
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002192 DBGPRINTF7(("NAMELIST: enter, t=%p, type %s, iolist=%p\n", t,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002193 T_CMD_NAMES[t->type], iolist));
2194
Eric Andersenff9eee42001-06-29 04:57:14 +00002195 if (iolist) {
Eric Andersen8401eea2004-08-04 19:16:54 +00002196 iolist = addword((char *) NULL, iolist);
Eric Andersenff9eee42001-06-29 04:57:14 +00002197 t->ioact = copyio();
2198 } else
2199 t->ioact = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002200
Eric Andersenff9eee42001-06-29 04:57:14 +00002201 if (t->type != TCOM) {
2202 if (t->type != TPAREN && t->ioact != NULL) {
2203 t = block(TPAREN, t, NOBLOCK, NOWORDS);
2204 t->ioact = t->left->ioact;
2205 t->left->ioact = NULL;
2206 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002207 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002208 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002209
Eric Andersenff9eee42001-06-29 04:57:14 +00002210 word(NOWORD);
2211 t->words = copyw();
Eric Andersen12de6cf2004-08-04 19:19:10 +00002212
2213
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002214 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002215}
2216
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002217static char **copyw(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002218{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002219 char **wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00002220
2221 wd = getwords(wdlist);
2222 wdlist = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002223 return wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00002224}
2225
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002226static void word(char *cp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002227{
2228 wdlist = addword(cp, wdlist);
2229}
2230
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002231static struct ioword **copyio(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002232{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002233 struct ioword **iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002234
2235 iop = (struct ioword **) getwords(iolist);
2236 iolist = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002237 return iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002238}
2239
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002240static struct ioword *io(int u, int f, char *cp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002241{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002242 struct ioword *iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002243
2244 iop = (struct ioword *) tree(sizeof(*iop));
2245 iop->io_unit = u;
2246 iop->io_flag = f;
2247 iop->io_name = cp;
Eric Andersen8401eea2004-08-04 19:16:54 +00002248 iolist = addword((char *) iop, iolist);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002249 return iop;
Eric Andersenff9eee42001-06-29 04:57:14 +00002250}
2251
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002252static void zzerr(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00002253{
2254 yyerror("syntax error");
2255}
2256
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002257static void yyerror(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00002258{
2259 yynerrs++;
2260 if (interactive && e.iop <= iostack) {
2261 multiline = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00002262 while (eofc() == 0 && yylex(0) != '\n');
Eric Andersenff9eee42001-06-29 04:57:14 +00002263 }
2264 err(s);
2265 fail();
2266}
2267
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002268static int yylex(int cf)
Eric Andersenff9eee42001-06-29 04:57:14 +00002269{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002270 int c, c1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002271 int atstart;
2272
2273 if ((c = peeksym) > 0) {
2274 peeksym = 0;
2275 if (c == '\n')
2276 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002277 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002278 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002279
2280
Eric Andersenff9eee42001-06-29 04:57:14 +00002281 nlseen = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002282 atstart = startl;
2283 startl = 0;
2284 yylval.i = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002285 e.linep = line;
2286
2287/* MALAMO */
2288 line[LINELIM - 1] = '\0';
Eric Andersenff9eee42001-06-29 04:57:14 +00002289
Eric Andersen8401eea2004-08-04 19:16:54 +00002290 loop:
Eric Andersen12de6cf2004-08-04 19:19:10 +00002291 while ((c = my_getc(0)) == ' ' || c == '\t') /* Skip whitespace */
2292 ;
2293
Eric Andersenff9eee42001-06-29 04:57:14 +00002294 switch (c) {
2295 default:
2296 if (any(c, "0123456789")) {
2297 unget(c1 = my_getc(0));
2298 if (c1 == '<' || c1 == '>') {
2299 iounit = c - '0';
2300 goto loop;
2301 }
2302 *e.linep++ = c;
2303 c = c1;
2304 }
2305 break;
2306
Eric Andersen12de6cf2004-08-04 19:19:10 +00002307 case '#': /* Comment, skip to next newline or End-of-string */
Eric Andersen8401eea2004-08-04 19:16:54 +00002308 while ((c = my_getc(0)) != 0 && c != '\n');
Eric Andersenff9eee42001-06-29 04:57:14 +00002309 unget(c);
2310 goto loop;
2311
2312 case 0:
Eric Andersen12de6cf2004-08-04 19:19:10 +00002313 DBGPRINTF5(("YYLEX: return 0, c=%d\n", c));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002314 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002315
2316 case '$':
Eric Andersen12de6cf2004-08-04 19:19:10 +00002317 DBGPRINTF9(("YYLEX: found $\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00002318 *e.linep++ = c;
2319 if ((c = my_getc(0)) == '{') {
2320 if ((c = collect(c, '}')) != '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002321 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002322 goto pack;
2323 }
2324 break;
2325
2326 case '`':
2327 case '\'':
2328 case '"':
2329 if ((c = collect(c, c)) != '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002330 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002331 goto pack;
2332
2333 case '|':
2334 case '&':
2335 case ';':
Eric Andersenff9eee42001-06-29 04:57:14 +00002336 startl = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002337 /* If more chars process them, else return NULL char */
2338 if ((c1 = dual(c)) != '\0')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002339 return c1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002340 else
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002341 return c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002342
Eric Andersenff9eee42001-06-29 04:57:14 +00002343 case '^':
2344 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002345 return '|';
Eric Andersenff9eee42001-06-29 04:57:14 +00002346 case '>':
2347 case '<':
2348 diag(c);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002349 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002350
2351 case '\n':
2352 nlseen++;
2353 gethere();
2354 startl = 1;
2355 if (multiline || cf & CONTIN) {
2356 if (interactive && e.iop <= iostack) {
Eric Andersenbdfd0d72001-10-24 05:00:29 +00002357#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00002358 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00002359#else
Eric Andersen8401eea2004-08-04 19:16:54 +00002360 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00002361#endif
2362 }
2363 if (cf & CONTIN)
2364 goto loop;
2365 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002366 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002367
2368 case '(':
2369 case ')':
2370 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002371 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002372 }
2373
2374 unget(c);
2375
Eric Andersen8401eea2004-08-04 19:16:54 +00002376 pack:
Eric Andersen12de6cf2004-08-04 19:19:10 +00002377 while ((c = my_getc(0)) != 0 && !any(c, "`$ '\"\t;&<>()|^\n")) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002378 if (e.linep >= elinep)
2379 err("word too long");
2380 else
2381 *e.linep++ = c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002382 };
2383
Eric Andersenff9eee42001-06-29 04:57:14 +00002384 unget(c);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002385
Eric Andersen8401eea2004-08-04 19:16:54 +00002386 if (any(c, "\"'`$"))
Eric Andersenff9eee42001-06-29 04:57:14 +00002387 goto loop;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002388
Eric Andersenff9eee42001-06-29 04:57:14 +00002389 *e.linep++ = '\0';
Eric Andersen12de6cf2004-08-04 19:19:10 +00002390
Eric Andersen8401eea2004-08-04 19:16:54 +00002391 if (atstart && (c = rlookup(line)) != 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002392 startl = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002393 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00002394 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002395
Eric Andersenff9eee42001-06-29 04:57:14 +00002396 yylval.cp = strsave(line, areanum);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002397 return WORD;
Eric Andersenff9eee42001-06-29 04:57:14 +00002398}
2399
Eric Andersen12de6cf2004-08-04 19:19:10 +00002400
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002401static int collect(int c, int c1)
Eric Andersenff9eee42001-06-29 04:57:14 +00002402{
2403 char s[2];
2404
Eric Andersen12de6cf2004-08-04 19:19:10 +00002405 DBGPRINTF8(("COLLECT: enter, c=%d, c1=%d\n", c, c1));
2406
Eric Andersenff9eee42001-06-29 04:57:14 +00002407 *e.linep++ = c;
2408 while ((c = my_getc(c1)) != c1) {
2409 if (c == 0) {
2410 unget(c);
2411 s[0] = c1;
2412 s[1] = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00002413 prs("no closing ");
2414 yyerror(s);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002415 return YYERRCODE;
Eric Andersenff9eee42001-06-29 04:57:14 +00002416 }
2417 if (interactive && c == '\n' && e.iop <= iostack) {
Eric Andersenbdfd0d72001-10-24 05:00:29 +00002418#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00002419 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00002420#else
Eric Andersen8401eea2004-08-04 19:16:54 +00002421 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00002422#endif
2423 }
2424 *e.linep++ = c;
2425 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002426
Eric Andersenff9eee42001-06-29 04:57:14 +00002427 *e.linep++ = c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002428
2429 DBGPRINTF8(("COLLECT: return 0, line is %s\n", line));
2430
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002431 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002432}
2433
Eric Andersen12de6cf2004-08-04 19:19:10 +00002434/* "multiline commands" helper func */
2435/* see if next 2 chars form a shell multiline */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002436static int dual(int c)
Eric Andersenff9eee42001-06-29 04:57:14 +00002437{
2438 char s[3];
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002439 char *cp = s;
Eric Andersenff9eee42001-06-29 04:57:14 +00002440
Eric Andersen12de6cf2004-08-04 19:19:10 +00002441 DBGPRINTF8(("DUAL: enter, c=%d\n", c));
2442
2443 *cp++ = c; /* c is the given "peek" char */
2444 *cp++ = my_getc(0); /* get next char of input */
2445 *cp = 0; /* add EOS marker */
2446
2447 c = rlookup(s); /* see if 2 chars form a shell multiline */
2448 if (c == 0)
2449 unget(*--cp); /* String is not a shell multiline, put peek char back */
2450
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002451 return c; /* String is multiline, return numeric multiline (restab) code */
Eric Andersenff9eee42001-06-29 04:57:14 +00002452}
2453
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002454static void diag(int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00002455{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002456 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002457
2458 DBGPRINTF8(("DIAG: enter, ec=%d\n", ec));
Eric Andersenff9eee42001-06-29 04:57:14 +00002459
2460 c = my_getc(0);
2461 if (c == '>' || c == '<') {
2462 if (c != ec)
2463 zzerr();
Eric Andersen8401eea2004-08-04 19:16:54 +00002464 yylval.i = ec == '>' ? IOWRITE | IOCAT : IOHERE;
Eric Andersenff9eee42001-06-29 04:57:14 +00002465 c = my_getc(0);
2466 } else
Eric Andersen8401eea2004-08-04 19:16:54 +00002467 yylval.i = ec == '>' ? IOWRITE : IOREAD;
Eric Andersenff9eee42001-06-29 04:57:14 +00002468 if (c != '&' || yylval.i == IOHERE)
2469 unget(c);
2470 else
2471 yylval.i |= IODUP;
2472}
2473
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002474static char *tree(unsigned size)
Eric Andersenff9eee42001-06-29 04:57:14 +00002475{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002476 char *t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002477
2478 if ((t = getcell(size)) == NULL) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002479 DBGPRINTF2(("TREE: getcell(%d) failed!\n", size));
Eric Andersenff9eee42001-06-29 04:57:14 +00002480 prs("command line too complicated\n");
2481 fail();
2482 /* NOTREACHED */
2483 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002484 return t;
Eric Andersenff9eee42001-06-29 04:57:14 +00002485}
2486
2487/* VARARGS1 */
2488/* ARGSUSED */
2489
2490/* -------- exec.c -------- */
2491
2492/*
2493 * execute tree
2494 */
2495
2496
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002497static int execute(struct op *t, int *pin, int *pout, int act)
Eric Andersenff9eee42001-06-29 04:57:14 +00002498{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002499 struct op *t1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002500 volatile int i, rv, a;
2501 char *cp, **wp, **wp2;
2502 struct var *vp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002503 struct op *outtree_save;
Eric Andersenff9eee42001-06-29 04:57:14 +00002504 struct brkcon bc;
2505
2506#if __GNUC__
2507 /* Avoid longjmp clobbering */
2508 (void) &wp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002509#endif
Eric Andersenff9eee42001-06-29 04:57:14 +00002510
Eric Andersen12de6cf2004-08-04 19:19:10 +00002511 if (t == NULL) {
2512 DBGPRINTF4(("EXECUTE: enter, t==null, returning.\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002513 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002514 }
2515
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002516 DBGPRINTF(("EXECUTE: t=%p, t->type=%d (%s), t->words is %s\n", t,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002517 t->type, T_CMD_NAMES[t->type],
2518 ((t->words == NULL) ? "NULL" : t->words[0])));
2519
Eric Andersenff9eee42001-06-29 04:57:14 +00002520 rv = 0;
2521 a = areanum++;
2522 wp = (wp2 = t->words) != NULL
Eric Andersen8401eea2004-08-04 19:16:54 +00002523 ? eval(wp2, t->type == TCOM ? DOALL : DOALL & ~DOKEY)
2524 : NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00002525
Eric Andersen8401eea2004-08-04 19:16:54 +00002526 switch (t->type) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002527 case TDOT:
2528 DBGPRINTF3(("EXECUTE: TDOT\n"));
2529
2530 outtree_save = outtree;
2531
2532 newfile(evalstr(t->words[0], DOALL));
2533
2534 t->left = dowholefile(TLIST, 0);
2535 t->right = NULL;
2536
2537 outtree = outtree_save;
2538
2539 if (t->left)
2540 rv = execute(t->left, pin, pout, 0);
2541 if (t->right)
2542 rv = execute(t->right, pin, pout, 0);
2543 break;
2544
Eric Andersenff9eee42001-06-29 04:57:14 +00002545 case TPAREN:
Eric Andersen737f5fb2003-03-14 16:05:59 +00002546 rv = execute(t->left, pin, pout, 0);
2547 break;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002548
Eric Andersenff9eee42001-06-29 04:57:14 +00002549 case TCOM:
Eric Andersen1c039232001-07-07 00:05:55 +00002550 {
Eric Andersen12de6cf2004-08-04 19:19:10 +00002551 rv = forkexec(t, pin, pout, act, wp);
Eric Andersenff9eee42001-06-29 04:57:14 +00002552 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002553 break;
2554
2555 case TPIPE:
2556 {
Eric Andersen8401eea2004-08-04 19:16:54 +00002557 int pv[2];
2558
2559 if ((rv = openpipe(pv)) < 0)
2560 break;
2561 pv[0] = remap(pv[0]);
2562 pv[1] = remap(pv[1]);
2563 (void) execute(t->left, pin, pv, 0);
2564 rv = execute(t->right, pv, pout, 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002565 }
2566 break;
2567
2568 case TLIST:
2569 (void) execute(t->left, pin, pout, 0);
2570 rv = execute(t->right, pin, pout, 0);
2571 break;
2572
2573 case TASYNC:
Eric Andersen8401eea2004-08-04 19:16:54 +00002574 {
2575 int hinteractive = interactive;
Eric Andersenff9eee42001-06-29 04:57:14 +00002576
Eric Andersen12de6cf2004-08-04 19:19:10 +00002577 DBGPRINTF7(("EXECUTE: TASYNC clause, calling vfork()...\n"));
2578
Eric Andersen8401eea2004-08-04 19:16:54 +00002579 i = vfork();
2580 if (i != 0) {
2581 interactive = hinteractive;
2582 if (i != -1) {
2583 setval(lookup("!"), putn(i));
2584 if (pin != NULL)
2585 closepipe(pin);
2586 if (interactive) {
2587 prs(putn(i));
2588 prs("\n");
2589 }
2590 } else
2591 rv = -1;
2592 setstatus(rv);
2593 } else {
2594 signal(SIGINT, SIG_IGN);
2595 signal(SIGQUIT, SIG_IGN);
2596 if (interactive)
2597 signal(SIGTERM, SIG_DFL);
2598 interactive = 0;
2599 if (pin == NULL) {
2600 close(0);
"Vladimir N. Oleynik"6c35c7c2005-10-12 15:34:25 +00002601 open(bb_dev_null, 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002602 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002603 _exit(execute(t->left, pin, pout, FEXEC));
Eric Andersenff9eee42001-06-29 04:57:14 +00002604 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002605 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002606 break;
2607
2608 case TOR:
2609 case TAND:
2610 rv = execute(t->left, pin, pout, 0);
Eric Andersen8401eea2004-08-04 19:16:54 +00002611 if ((t1 = t->right) != NULL && (rv == 0) == (t->type == TAND))
Eric Andersenff9eee42001-06-29 04:57:14 +00002612 rv = execute(t1, pin, pout, 0);
2613 break;
2614
2615 case TFOR:
2616 if (wp == NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00002617 wp = dolv + 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002618 if ((i = dolc) < 0)
2619 i = 0;
2620 } else {
2621 i = -1;
Eric Andersen8401eea2004-08-04 19:16:54 +00002622 while (*wp++ != NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00002623 }
2624 vp = lookup(t->str);
2625 while (setjmp(bc.brkpt))
2626 if (isbreak)
2627 goto broken;
2628 brkset(&bc);
2629 for (t1 = t->left; i-- && *wp != NULL;) {
2630 setval(vp, *wp++);
2631 rv = execute(t1, pin, pout, 0);
2632 }
2633 brklist = brklist->nextlev;
2634 break;
2635
2636 case TWHILE:
2637 case TUNTIL:
2638 while (setjmp(bc.brkpt))
2639 if (isbreak)
2640 goto broken;
2641 brkset(&bc);
2642 t1 = t->left;
2643 while ((execute(t1, pin, pout, 0) == 0) == (t->type == TWHILE))
2644 rv = execute(t->right, pin, pout, 0);
2645 brklist = brklist->nextlev;
2646 break;
2647
2648 case TIF:
2649 case TELIF:
Eric Andersen8401eea2004-08-04 19:16:54 +00002650 if (t->right != NULL) {
2651 rv = !execute(t->left, pin, pout, 0) ?
2652 execute(t->right->left, pin, pout, 0) :
2653 execute(t->right->right, pin, pout, 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002654 }
2655 break;
2656
2657 case TCASE:
Eric Andersen8401eea2004-08-04 19:16:54 +00002658 if ((cp = evalstr(t->str, DOSUB | DOTRIM)) == 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00002659 cp = "";
Eric Andersen12de6cf2004-08-04 19:19:10 +00002660
2661 DBGPRINTF7(("EXECUTE: TCASE, t->str is %s, cp is %s\n",
2662 ((t->str == NULL) ? "NULL" : t->str),
2663 ((cp == NULL) ? "NULL" : cp)));
2664
2665 if ((t1 = findcase(t->left, cp)) != NULL) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002666 DBGPRINTF7(("EXECUTE: TCASE, calling execute(t=%p, t1=%p)...\n", t, t1));
Eric Andersenff9eee42001-06-29 04:57:14 +00002667 rv = execute(t1, pin, pout, 0);
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002668 DBGPRINTF7(("EXECUTE: TCASE, back from execute(t=%p, t1=%p)...\n", t, t1));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002669 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002670 break;
2671
2672 case TBRACE:
2673/*
2674 if (iopp = t->ioact)
2675 while (*iopp)
2676 if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) {
2677 rv = -1;
2678 break;
2679 }
2680*/
2681 if (rv >= 0 && (t1 = t->left))
2682 rv = execute(t1, pin, pout, 0);
2683 break;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002684
2685 };
Eric Andersenff9eee42001-06-29 04:57:14 +00002686
Eric Andersen8401eea2004-08-04 19:16:54 +00002687 broken:
Eric Andersenff9eee42001-06-29 04:57:14 +00002688 t->words = wp2;
2689 isbreak = 0;
2690 freehere(areanum);
2691 freearea(areanum);
2692 areanum = a;
2693 if (interactive && intr) {
2694 closeall();
2695 fail();
2696 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002697
Eric Andersenff9eee42001-06-29 04:57:14 +00002698 if ((i = trapset) != 0) {
2699 trapset = 0;
2700 runtrap(i);
2701 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002702
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002703 DBGPRINTF(("EXECUTE: returning from t=%p, rv=%d\n", t, rv));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002704 return rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00002705}
2706
2707static int
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002708forkexec(struct op *t, int *pin, int *pout, int act, char **wp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002709{
Eric Andersen12de6cf2004-08-04 19:19:10 +00002710 pid_t newpid;
Eric Andersenff9eee42001-06-29 04:57:14 +00002711 int i, rv;
Eric Andersen8401eea2004-08-04 19:16:54 +00002712 int (*shcom) (struct op *) = NULL;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002713 int f;
Eric Andersenff9eee42001-06-29 04:57:14 +00002714 char *cp = NULL;
2715 struct ioword **iopp;
2716 int resetsig;
2717 char **owp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002718 int forked = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002719
2720 int *hpin = pin;
2721 int *hpout = pout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002722 char *hwp;
2723 int hinteractive;
2724 int hintr;
Eric Andersen8401eea2004-08-04 19:16:54 +00002725 struct brkcon *hbrklist;
Eric Andersenff9eee42001-06-29 04:57:14 +00002726 int hexecflg;
2727
2728#if __GNUC__
2729 /* Avoid longjmp clobbering */
2730 (void) &pin;
2731 (void) &pout;
2732 (void) &wp;
2733 (void) &shcom;
2734 (void) &cp;
2735 (void) &resetsig;
2736 (void) &owp;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002737#endif
Eric Andersenff9eee42001-06-29 04:57:14 +00002738
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002739 DBGPRINTF(("FORKEXEC: t=%p, pin %p, pout %p, act %d\n", t, pin,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002740 pout, act));
2741 DBGPRINTF7(("FORKEXEC: t->words is %s\n",
2742 ((t->words == NULL) ? "NULL" : t->words[0])));
2743
Eric Andersenff9eee42001-06-29 04:57:14 +00002744 owp = wp;
2745 resetsig = 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00002746 rv = -1; /* system-detected error */
Eric Andersenff9eee42001-06-29 04:57:14 +00002747 if (t->type == TCOM) {
Eric Andersen8401eea2004-08-04 19:16:54 +00002748 while ((cp = *wp++) != NULL);
Eric Andersenff9eee42001-06-29 04:57:14 +00002749 cp = *wp;
2750
2751 /* strip all initial assignments */
2752 /* not correct wrt PATH=yyy command etc */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002753 if (flag['x']) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002754 DBGPRINTF9(("FORKEXEC: echo'ing, cp=%p, wp=%p, owp=%p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00002755 cp, wp, owp));
Eric Andersen8401eea2004-08-04 19:16:54 +00002756 echo(cp ? wp : owp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002757 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002758
Eric Andersenff9eee42001-06-29 04:57:14 +00002759 if (cp == NULL && t->ioact == NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00002760 while ((cp = *owp++) != NULL && assign(cp, COPYV));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002761 DBGPRINTF(("FORKEXEC: returning setstatus()\n"));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002762 return setstatus(0);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002763 } else if (cp != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002764 shcom = inbuilt(cp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002765 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002766 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002767
Eric Andersenff9eee42001-06-29 04:57:14 +00002768 t->words = wp;
2769 f = act;
Eric Andersenff9eee42001-06-29 04:57:14 +00002770
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002771 DBGPRINTF(("FORKEXEC: shcom %p, f&FEXEC 0x%x, owp %p\n", shcom,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002772 f & FEXEC, owp));
2773
2774 if (shcom == NULL && (f & FEXEC) == 0) {
2775 /* Save values in case the child process alters them */
Eric Andersenff9eee42001-06-29 04:57:14 +00002776 hpin = pin;
2777 hpout = pout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002778 hwp = *wp;
2779 hinteractive = interactive;
2780 hintr = intr;
2781 hbrklist = brklist;
2782 hexecflg = execflg;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002783
Eric Andersen12de6cf2004-08-04 19:19:10 +00002784 DBGPRINTF3(("FORKEXEC: calling vfork()...\n"));
2785
2786 newpid = vfork();
2787
2788 if (newpid == -1) {
Denis Vlasenko89f0b342006-11-18 22:04:09 +00002789 DBGPRINTF(("FORKEXEC: ERROR, cannot vfork()!\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002790 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002791 }
2792
2793
2794 if (newpid > 0) { /* Parent */
2795
2796 /* Restore values */
Eric Andersenff9eee42001-06-29 04:57:14 +00002797 pin = hpin;
2798 pout = hpout;
Eric Andersenff9eee42001-06-29 04:57:14 +00002799 *wp = hwp;
2800 interactive = hinteractive;
2801 intr = hintr;
2802 brklist = hbrklist;
2803 execflg = hexecflg;
2804
Eric Andersen12de6cf2004-08-04 19:19:10 +00002805/* moved up
Eric Andersenff9eee42001-06-29 04:57:14 +00002806 if (i == -1)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002807 return rv;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002808*/
2809
Eric Andersenff9eee42001-06-29 04:57:14 +00002810 if (pin != NULL)
2811 closepipe(pin);
Eric Andersen12de6cf2004-08-04 19:19:10 +00002812
2813 return (pout == NULL ? setstatus(waitfor(newpid, 0)) : 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00002814 }
2815
Eric Andersen12de6cf2004-08-04 19:19:10 +00002816 /* Must be the child process, pid should be 0 */
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002817 DBGPRINTF(("FORKEXEC: child process, shcom=%p\n", shcom));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002818
Eric Andersenff9eee42001-06-29 04:57:14 +00002819 if (interactive) {
2820 signal(SIGINT, SIG_IGN);
2821 signal(SIGQUIT, SIG_IGN);
2822 resetsig = 1;
2823 }
2824 interactive = 0;
2825 intr = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002826 forked = 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002827 brklist = 0;
2828 execflg = 0;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00002829 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002830
2831
Eric Andersenff9eee42001-06-29 04:57:14 +00002832 if (owp != NULL)
2833 while ((cp = *owp++) != NULL && assign(cp, COPYV))
2834 if (shcom == NULL)
2835 export(lookup(cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00002836
Eric Andersenff9eee42001-06-29 04:57:14 +00002837#ifdef COMPIPE
2838 if ((pin != NULL || pout != NULL) && shcom != NULL && shcom != doexec) {
2839 err("piping to/from shell builtins not yet done");
Eric Andersen12de6cf2004-08-04 19:19:10 +00002840 if (forked)
2841 _exit(-1);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002842 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002843 }
2844#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00002845
Eric Andersenff9eee42001-06-29 04:57:14 +00002846 if (pin != NULL) {
2847 dup2(pin[0], 0);
2848 closepipe(pin);
2849 }
2850 if (pout != NULL) {
2851 dup2(pout[1], 1);
2852 closepipe(pout);
2853 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002854
Eric Andersenff9eee42001-06-29 04:57:14 +00002855 if ((iopp = t->ioact) != NULL) {
2856 if (shcom != NULL && shcom != doexec) {
2857 prs(cp);
2858 err(": cannot redirect shell command");
Eric Andersen12de6cf2004-08-04 19:19:10 +00002859 if (forked)
2860 _exit(-1);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002861 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002862 }
2863 while (*iopp)
Eric Andersen12de6cf2004-08-04 19:19:10 +00002864 if (iosetup(*iopp++, pin != NULL, pout != NULL)) {
2865 if (forked)
2866 _exit(rv);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002867 return rv;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002868 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002869 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002870
2871 if (shcom) {
2872 i = setstatus((*shcom) (t));
2873 if (forked)
2874 _exit(i);
2875 DBGPRINTF(("FORKEXEC: returning i=%d\n", i));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00002876 return i;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002877 }
2878
Eric Andersenff9eee42001-06-29 04:57:14 +00002879 /* should use FIOCEXCL */
Eric Andersen8401eea2004-08-04 19:16:54 +00002880 for (i = FDBASE; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00002881 close(i);
2882 if (resetsig) {
2883 signal(SIGINT, SIG_DFL);
2884 signal(SIGQUIT, SIG_DFL);
2885 }
Eric Andersenff9eee42001-06-29 04:57:14 +00002886
Eric Andersen12de6cf2004-08-04 19:19:10 +00002887 if (t->type == TPAREN)
2888 _exit(execute(t->left, NOPIPE, NOPIPE, FEXEC));
2889 if (wp[0] == NULL)
2890 _exit(0);
2891
Eric Andersenfd7a4c82004-09-02 23:13:10 +00002892 cp = rexecve(wp[0], wp, makenv(0, NULL));
Eric Andersen8401eea2004-08-04 19:16:54 +00002893 prs(wp[0]);
2894 prs(": ");
Eric Andersen12de6cf2004-08-04 19:19:10 +00002895 err(cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00002896 if (!execflg)
2897 trap[0] = NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002898
2899 DBGPRINTF(("FORKEXEC: calling leave(), pid=%d\n", newpid));
2900
Eric Andersenff9eee42001-06-29 04:57:14 +00002901 leave();
2902 /* NOTREACHED */
Eric Andersen12de6cf2004-08-04 19:19:10 +00002903 _exit(1);
Eric Andersenff9eee42001-06-29 04:57:14 +00002904}
2905
2906/*
2907 * 0< 1> are ignored as required
2908 * within pipelines.
2909 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002910static int iosetup(struct ioword *iop, int pipein, int pipeout)
Eric Andersenff9eee42001-06-29 04:57:14 +00002911{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002912 int u = -1;
Eric Andersen8401eea2004-08-04 19:16:54 +00002913 char *cp = NULL, *msg;
Eric Andersenff9eee42001-06-29 04:57:14 +00002914
Mike Frysinger02d8fa42006-05-05 20:32:31 +00002915 DBGPRINTF(("IOSETUP: iop %p, pipein %i, pipeout %i\n", iop,
Eric Andersen12de6cf2004-08-04 19:19:10 +00002916 pipein, pipeout));
2917
Eric Andersenff9eee42001-06-29 04:57:14 +00002918 if (iop->io_unit == IODEFAULT) /* take default */
Eric Andersen8401eea2004-08-04 19:16:54 +00002919 iop->io_unit = iop->io_flag & (IOREAD | IOHERE) ? 0 : 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002920
Eric Andersenff9eee42001-06-29 04:57:14 +00002921 if (pipein && iop->io_unit == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002922 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002923
Eric Andersenff9eee42001-06-29 04:57:14 +00002924 if (pipeout && iop->io_unit == 1)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002925 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00002926
Eric Andersen8401eea2004-08-04 19:16:54 +00002927 msg = iop->io_flag & (IOREAD | IOHERE) ? "open" : "create";
Eric Andersenff9eee42001-06-29 04:57:14 +00002928 if ((iop->io_flag & IOHERE) == 0) {
2929 cp = iop->io_name;
Eric Andersen8401eea2004-08-04 19:16:54 +00002930 if ((cp = evalstr(cp, DOSUB | DOTRIM)) == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002931 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002932 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00002933
Eric Andersenff9eee42001-06-29 04:57:14 +00002934 if (iop->io_flag & IODUP) {
2935 if (cp[1] || (!isdigit(*cp) && *cp != '-')) {
2936 prs(cp);
2937 err(": illegal >& argument");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002938 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002939 }
2940 if (*cp == '-')
2941 iop->io_flag = IOCLOSE;
Eric Andersen8401eea2004-08-04 19:16:54 +00002942 iop->io_flag &= ~(IOREAD | IOWRITE);
Eric Andersenff9eee42001-06-29 04:57:14 +00002943 }
2944 switch (iop->io_flag) {
2945 case IOREAD:
2946 u = open(cp, 0);
2947 break;
2948
2949 case IOHERE:
Eric Andersen8401eea2004-08-04 19:16:54 +00002950 case IOHERE | IOXHERE:
2951 u = herein(iop->io_name, iop->io_flag & IOXHERE);
Eric Andersenff9eee42001-06-29 04:57:14 +00002952 cp = "here file";
2953 break;
2954
Eric Andersen8401eea2004-08-04 19:16:54 +00002955 case IOWRITE | IOCAT:
Eric Andersenff9eee42001-06-29 04:57:14 +00002956 if ((u = open(cp, 1)) >= 0) {
Denis Vlasenkoea620772006-10-14 02:23:43 +00002957 lseek(u, (long) 0, SEEK_END);
Eric Andersenff9eee42001-06-29 04:57:14 +00002958 break;
2959 }
2960 case IOWRITE:
2961 u = creat(cp, 0666);
2962 break;
2963
2964 case IODUP:
Eric Andersen8401eea2004-08-04 19:16:54 +00002965 u = dup2(*cp - '0', iop->io_unit);
Eric Andersenff9eee42001-06-29 04:57:14 +00002966 break;
2967
2968 case IOCLOSE:
2969 close(iop->io_unit);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002970 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002971 }
2972 if (u < 0) {
2973 prs(cp);
2974 prs(": cannot ");
2975 warn(msg);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002976 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00002977 } else {
2978 if (u != iop->io_unit) {
2979 dup2(u, iop->io_unit);
2980 close(u);
2981 }
2982 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00002983 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00002984}
2985
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002986static void echo(char **wp)
Eric Andersenff9eee42001-06-29 04:57:14 +00002987{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00002988 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00002989
2990 prs("+");
Eric Andersen8401eea2004-08-04 19:16:54 +00002991 for (i = 0; wp[i]; i++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00002992 if (i)
2993 prs(" ");
2994 prs(wp[i]);
2995 }
2996 prs("\n");
2997}
2998
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00002999static struct op **find1case(struct op *t, char *w)
Eric Andersenff9eee42001-06-29 04:57:14 +00003000{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003001 struct op *t1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003002 struct op **tp;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003003 char **wp, *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003004
Eric Andersen12de6cf2004-08-04 19:19:10 +00003005
3006 if (t == NULL) {
3007 DBGPRINTF3(("FIND1CASE: enter, t==NULL, returning.\n"));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003008 return NULL;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003009 }
3010
3011 DBGPRINTF3(("FIND1CASE: enter, t->type=%d (%s)\n", t->type,
3012 T_CMD_NAMES[t->type]));
3013
Eric Andersenff9eee42001-06-29 04:57:14 +00003014 if (t->type == TLIST) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00003015 if ((tp = find1case(t->left, w)) != NULL) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003016 DBGPRINTF3(("FIND1CASE: found one to the left, returning tp=%p\n", tp));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003017 return tp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003018 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003019 t1 = t->right; /* TPAT */
Eric Andersenff9eee42001-06-29 04:57:14 +00003020 } else
3021 t1 = t;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003022
Eric Andersenff9eee42001-06-29 04:57:14 +00003023 for (wp = t1->words; *wp;)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003024 if ((cp = evalstr(*wp++, DOSUB)) && gmatch(w, cp)) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003025 DBGPRINTF3(("FIND1CASE: returning &t1->left= %p.\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00003026 &t1->left));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003027 return &t1->left;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003028 }
3029
3030 DBGPRINTF(("FIND1CASE: returning NULL\n"));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003031 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00003032}
3033
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003034static struct op *findcase(struct op *t, char *w)
Eric Andersenff9eee42001-06-29 04:57:14 +00003035{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003036 struct op **tp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003037
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003038 tp = find1case(t, w);
3039 return tp != NULL ? *tp : NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00003040}
3041
3042/*
3043 * Enter a new loop level (marked for break/continue).
3044 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003045static void brkset(struct brkcon *bc)
Eric Andersenff9eee42001-06-29 04:57:14 +00003046{
3047 bc->nextlev = brklist;
3048 brklist = bc;
3049}
3050
3051/*
3052 * Wait for the last process created.
3053 * Print a message for each process found
3054 * that was killed by a signal.
3055 * Ignore interrupt signals while waiting
3056 * unless `canintr' is true.
3057 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003058static int waitfor(int lastpid, int canintr)
Eric Andersenff9eee42001-06-29 04:57:14 +00003059{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003060 int pid, rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003061 int s;
3062 int oheedint = heedint;
3063
3064 heedint = 0;
3065 rv = 0;
3066 do {
3067 pid = wait(&s);
3068 if (pid == -1) {
3069 if (errno != EINTR || canintr)
3070 break;
3071 } else {
3072 if ((rv = WAITSIG(s)) != 0) {
3073 if (rv < NSIGNAL) {
3074 if (signame[rv] != NULL) {
3075 if (pid != lastpid) {
3076 prn(pid);
3077 prs(": ");
3078 }
3079 prs(signame[rv]);
3080 }
3081 } else {
3082 if (pid != lastpid) {
3083 prn(pid);
3084 prs(": ");
3085 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003086 prs("Signal ");
3087 prn(rv);
3088 prs(" ");
Eric Andersenff9eee42001-06-29 04:57:14 +00003089 }
3090 if (WAITCORE(s))
3091 prs(" - core dumped");
3092 if (rv >= NSIGNAL || signame[rv])
3093 prs("\n");
3094 rv = -1;
3095 } else
3096 rv = WAITVAL(s);
3097 }
3098 } while (pid != lastpid);
3099 heedint = oheedint;
3100 if (intr) {
3101 if (interactive) {
3102 if (canintr)
3103 intr = 0;
3104 } else {
Eric Andersen8401eea2004-08-04 19:16:54 +00003105 if (exstat == 0)
3106 exstat = rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003107 onintr(0);
3108 }
3109 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003110 return rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003111}
3112
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003113static int setstatus(int s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003114{
3115 exstat = s;
3116 setval(lookup("?"), putn(s));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003117 return s;
Eric Andersenff9eee42001-06-29 04:57:14 +00003118}
3119
3120/*
3121 * PATH-searching interface to execve.
3122 * If getenv("PATH") were kept up-to-date,
3123 * execvp might be used.
3124 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003125static char *rexecve(char *c, char **v, char **envp)
Eric Andersenff9eee42001-06-29 04:57:14 +00003126{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003127 int i;
3128 char *sp, *tp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003129 int eacces = 0, asis = 0;
Eric Andersen1c039232001-07-07 00:05:55 +00003130 char *name = c;
Eric Andersen8401eea2004-08-04 19:16:54 +00003131
Rob Landleya299efb2006-08-10 21:46:43 +00003132 if (ENABLE_FEATURE_SH_STANDALONE_SHELL) {
3133 optind = 1;
3134 if (find_applet_by_name(name)) {
3135 /* We have to exec here since we vforked. Running
3136 * run_applet_by_name() won't work and bad things
3137 * will happen. */
3138 execve(CONFIG_BUSYBOX_EXEC_PATH, v, envp);
3139 }
Eric Andersen1c039232001-07-07 00:05:55 +00003140 }
Eric Andersen1c039232001-07-07 00:05:55 +00003141
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003142 DBGPRINTF(("REXECVE: c=%p, v=%p, envp=%p\n", c, v, envp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003143
Eric Andersen8401eea2004-08-04 19:16:54 +00003144 sp = any('/', c) ? "" : path->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00003145 asis = *sp == '\0';
3146 while (asis || *sp != '\0') {
3147 asis = 0;
3148 tp = e.linep;
3149 for (; *sp != '\0'; tp++)
3150 if ((*tp = *sp++) == ':') {
3151 asis = *sp == '\0';
3152 break;
3153 }
3154 if (tp != e.linep)
3155 *tp++ = '/';
Eric Andersen8401eea2004-08-04 19:16:54 +00003156 for (i = 0; (*tp++ = c[i++]) != '\0';);
Eric Andersen1c039232001-07-07 00:05:55 +00003157
Eric Andersen12de6cf2004-08-04 19:19:10 +00003158 DBGPRINTF3(("REXECVE: e.linep is %s\n", e.linep));
3159
Eric Andersenff9eee42001-06-29 04:57:14 +00003160 execve(e.linep, v, envp);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003161
Eric Andersenff9eee42001-06-29 04:57:14 +00003162 switch (errno) {
3163 case ENOEXEC:
3164 *v = e.linep;
3165 tp = *--v;
3166 *v = e.linep;
Glenn L McGrathdc4e75e2003-09-02 02:36:18 +00003167 execve(DEFAULT_SHELL, v, envp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003168 *v = tp;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003169 return "no Shell";
Eric Andersenff9eee42001-06-29 04:57:14 +00003170
3171 case ENOMEM:
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003172 return (char *) bb_msg_memory_exhausted;
Eric Andersenff9eee42001-06-29 04:57:14 +00003173
3174 case E2BIG:
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003175 return "argument list too long";
Eric Andersenff9eee42001-06-29 04:57:14 +00003176
3177 case EACCES:
3178 eacces++;
3179 break;
3180 }
3181 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003182 return errno == ENOENT ? "not found" : "cannot execute";
Eric Andersenff9eee42001-06-29 04:57:14 +00003183}
3184
3185/*
3186 * Run the command produced by generator `f'
3187 * applied to stream `arg'.
3188 */
Eric Andersen8401eea2004-08-04 19:16:54 +00003189static int run(struct ioarg *argp, int (*f) (struct ioarg *))
Eric Andersenff9eee42001-06-29 04:57:14 +00003190{
3191 struct op *otree;
3192 struct wdblock *swdlist;
3193 struct wdblock *siolist;
3194 jmp_buf ev, rt;
3195 xint *ofail;
3196 int rv;
3197
3198#if __GNUC__
3199 /* Avoid longjmp clobbering */
3200 (void) &rv;
3201#endif
3202
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003203 DBGPRINTF(("RUN: enter, areanum %d, outtree %p, failpt %p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00003204 areanum, outtree, failpt));
3205
Eric Andersenff9eee42001-06-29 04:57:14 +00003206 areanum++;
3207 swdlist = wdlist;
3208 siolist = iolist;
3209 otree = outtree;
3210 ofail = failpt;
3211 rv = -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003212
Eric Andersenff9eee42001-06-29 04:57:14 +00003213 if (newenv(setjmp(errpt = ev)) == 0) {
3214 wdlist = 0;
3215 iolist = 0;
3216 pushio(argp, f);
3217 e.iobase = e.iop;
3218 yynerrs = 0;
3219 if (setjmp(failpt = rt) == 0 && yyparse() == 0)
3220 rv = execute(outtree, NOPIPE, NOPIPE, 0);
3221 quitenv();
Eric Andersen12de6cf2004-08-04 19:19:10 +00003222 } else {
3223 DBGPRINTF(("RUN: error from newenv()!\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00003224 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00003225
Eric Andersenff9eee42001-06-29 04:57:14 +00003226 wdlist = swdlist;
3227 iolist = siolist;
3228 failpt = ofail;
3229 outtree = otree;
3230 freearea(areanum--);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003231
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003232 return rv;
Eric Andersenff9eee42001-06-29 04:57:14 +00003233}
3234
3235/* -------- do.c -------- */
3236
3237/*
3238 * built-in commands: doX
3239 */
3240
Eric Andersen8401eea2004-08-04 19:16:54 +00003241static int dohelp(struct op *t)
Eric Andersen1c039232001-07-07 00:05:55 +00003242{
3243 int col;
3244 const struct builtincmd *x;
3245
Denis Vlasenko0ee39992006-12-24 15:23:28 +00003246 puts("\nBuilt-in commands:\n"
3247 "-------------------");
Eric Andersen1c039232001-07-07 00:05:55 +00003248
Eric Andersen8401eea2004-08-04 19:16:54 +00003249 for (col = 0, x = builtincmds; x->builtinfunc != NULL; x++) {
Eric Andersen1c039232001-07-07 00:05:55 +00003250 if (!x->name)
3251 continue;
3252 col += printf("%s%s", ((col == 0) ? "\t" : " "), x->name);
3253 if (col > 60) {
Denis Vlasenkoc6f188d2006-10-26 00:37:00 +00003254 puts("");
Eric Andersen1c039232001-07-07 00:05:55 +00003255 col = 0;
3256 }
3257 }
Eric Andersenbdfd0d72001-10-24 05:00:29 +00003258#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
Eric Andersen1c039232001-07-07 00:05:55 +00003259 {
3260 int i;
3261 const struct BB_applet *applet;
Eric Andersen1c039232001-07-07 00:05:55 +00003262
Eric Andersen8401eea2004-08-04 19:16:54 +00003263 for (i = 0, applet = applets; i < NUM_APPLETS; applet++, i++) {
Eric Andersen1c039232001-07-07 00:05:55 +00003264 if (!applet->name)
3265 continue;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00003266
Eric Andersen8401eea2004-08-04 19:16:54 +00003267 col += printf("%s%s", ((col == 0) ? "\t" : " "), applet->name);
Eric Andersen1c039232001-07-07 00:05:55 +00003268 if (col > 60) {
Denis Vlasenkoc6f188d2006-10-26 00:37:00 +00003269 puts("");
Eric Andersen1c039232001-07-07 00:05:55 +00003270 col = 0;
3271 }
3272 }
3273 }
3274#endif
Denis Vlasenko0ee39992006-12-24 15:23:28 +00003275 puts("\n");
Eric Andersen1c039232001-07-07 00:05:55 +00003276 return EXIT_SUCCESS;
3277}
3278
3279
3280
Eric Andersen8401eea2004-08-04 19:16:54 +00003281static int dolabel(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003282{
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003283 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003284}
3285
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003286static int dochdir(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003287{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003288 char *cp, *er;
Eric Andersenff9eee42001-06-29 04:57:14 +00003289
3290 if ((cp = t->words[1]) == NULL && (cp = homedir->value) == NULL)
3291 er = ": no home directory";
Eric Andersen8401eea2004-08-04 19:16:54 +00003292 else if (chdir(cp) < 0)
Eric Andersenff9eee42001-06-29 04:57:14 +00003293 er = ": bad directory";
3294 else
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003295 return 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00003296 prs(cp != NULL ? cp : "cd");
Eric Andersenff9eee42001-06-29 04:57:14 +00003297 err(er);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003298 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003299}
3300
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003301static int doshift(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003302{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003303 int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003304
Eric Andersen8401eea2004-08-04 19:16:54 +00003305 n = t->words[1] ? getn(t->words[1]) : 1;
3306 if (dolc < n) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003307 err("nothing to shift");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003308 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003309 }
3310 dolv[n] = dolv[0];
3311 dolv += n;
3312 dolc -= n;
3313 setval(lookup("#"), putn(dolc));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003314 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003315}
3316
3317/*
3318 * execute login and newgrp directly
3319 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003320static int dologin(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003321{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003322 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003323
3324 if (interactive) {
3325 signal(SIGINT, SIG_DFL);
3326 signal(SIGQUIT, SIG_DFL);
3327 }
Eric Andersenfd7a4c82004-09-02 23:13:10 +00003328 cp = rexecve(t->words[0], t->words, makenv(0, NULL));
Eric Andersen8401eea2004-08-04 19:16:54 +00003329 prs(t->words[0]);
3330 prs(": ");
3331 err(cp);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003332 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003333}
3334
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003335static int doumask(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003336{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003337 int i, n;
3338 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003339
3340 if ((cp = t->words[1]) == NULL) {
3341 i = umask(0);
3342 umask(i);
Eric Andersen8401eea2004-08-04 19:16:54 +00003343 for (n = 3 * 4; (n -= 3) >= 0;)
3344 putc('0' + ((i >> n) & 07), stderr);
Eric Andersenff9eee42001-06-29 04:57:14 +00003345 putc('\n', stderr);
3346 } else {
Eric Andersen8401eea2004-08-04 19:16:54 +00003347 for (n = 0; *cp >= '0' && *cp <= '9'; cp++)
3348 n = n * 8 + (*cp - '0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003349 umask(n);
3350 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003351 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003352}
3353
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003354static int doexec(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003355{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003356 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00003357 jmp_buf ex;
3358 xint *ofail;
3359
3360 t->ioact = NULL;
Eric Andersen8401eea2004-08-04 19:16:54 +00003361 for (i = 0; (t->words[i] = t->words[i + 1]) != NULL; i++);
Eric Andersenff9eee42001-06-29 04:57:14 +00003362 if (i == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003363 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003364 execflg = 1;
3365 ofail = failpt;
3366 if (setjmp(failpt = ex) == 0)
3367 execute(t, NOPIPE, NOPIPE, FEXEC);
3368 failpt = ofail;
3369 execflg = 0;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003370 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003371}
3372
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003373static int dodot(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003374{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003375 int i;
3376 char *sp, *tp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003377 char *cp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003378 int maltmp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003379
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003380 DBGPRINTF(("DODOT: enter, t=%p, tleft %p, tright %p, e.linep is %s\n", t, t->left, t->right, ((e.linep == NULL) ? "NULL" : e.linep)));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003381
3382 if ((cp = t->words[1]) == NULL) {
3383 DBGPRINTF(("DODOT: bad args, ret 0\n"));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003384 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003385 } else {
3386 DBGPRINTF(("DODOT: cp is %s\n", cp));
3387 }
3388
Eric Andersen8401eea2004-08-04 19:16:54 +00003389 sp = any('/', cp) ? ":" : path->value;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003390
3391 DBGPRINTF(("DODOT: sp is %s, e.linep is %s\n",
3392 ((sp == NULL) ? "NULL" : sp),
3393 ((e.linep == NULL) ? "NULL" : e.linep)));
3394
Eric Andersenff9eee42001-06-29 04:57:14 +00003395 while (*sp) {
3396 tp = e.linep;
3397 while (*sp && (*tp = *sp++) != ':')
3398 tp++;
3399 if (tp != e.linep)
3400 *tp++ = '/';
Eric Andersen12de6cf2004-08-04 19:19:10 +00003401
Eric Andersen8401eea2004-08-04 19:16:54 +00003402 for (i = 0; (*tp++ = cp[i++]) != '\0';);
Eric Andersen12de6cf2004-08-04 19:19:10 +00003403
3404 /* Original code */
Eric Andersenff9eee42001-06-29 04:57:14 +00003405 if ((i = open(e.linep, 0)) >= 0) {
3406 exstat = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003407 maltmp = remap(i);
3408 DBGPRINTF(("DODOT: remap=%d, exstat=%d, e.iofd %d, i %d, e.linep is %s\n", maltmp, exstat, e.iofd, i, e.linep));
3409
3410 next(maltmp); /* Basically a PUSHIO */
3411
3412 DBGPRINTF(("DODOT: returning exstat=%d\n", exstat));
3413
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003414 return exstat;
Eric Andersenff9eee42001-06-29 04:57:14 +00003415 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00003416
3417 } /* While */
3418
Eric Andersenff9eee42001-06-29 04:57:14 +00003419 prs(cp);
3420 err(": not found");
Eric Andersen12de6cf2004-08-04 19:19:10 +00003421
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003422 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003423}
3424
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003425static int dowait(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003426{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003427 int i;
3428 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003429
3430 if ((cp = t->words[1]) != NULL) {
3431 i = getn(cp);
3432 if (i == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003433 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003434 } else
3435 i = -1;
3436 setstatus(waitfor(i, 1));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003437 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003438}
3439
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003440static int doread(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003441{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003442 char *cp, **wp;
3443 int nb = 0;
3444 int nl = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003445
3446 if (t->words[1] == NULL) {
3447 err("Usage: read name ...");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003448 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003449 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003450 for (wp = t->words + 1; *wp; wp++) {
3451 for (cp = e.linep; !nl && cp < elinep - 1; cp++)
Eric Andersenff9eee42001-06-29 04:57:14 +00003452 if ((nb = read(0, cp, sizeof(*cp))) != sizeof(*cp) ||
Eric Andersen8401eea2004-08-04 19:16:54 +00003453 (nl = (*cp == '\n')) || (wp[1] && any(*cp, ifs->value)))
Eric Andersenff9eee42001-06-29 04:57:14 +00003454 break;
3455 *cp = 0;
3456 if (nb <= 0)
3457 break;
3458 setval(lookup(*wp), e.linep);
3459 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003460 return nb <= 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003461}
3462
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003463static int doeval(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003464{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003465 return RUN(awordlist, t->words + 1, wdchar);
Eric Andersenff9eee42001-06-29 04:57:14 +00003466}
3467
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003468static int dotrap(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003469{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003470 int n, i;
3471 int resetsig;
Eric Andersenff9eee42001-06-29 04:57:14 +00003472
3473 if (t->words[1] == NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00003474 for (i = 0; i <= _NSIG; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00003475 if (trap[i]) {
3476 prn(i);
3477 prs(": ");
3478 prs(trap[i]);
3479 prs("\n");
3480 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003481 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003482 }
3483 resetsig = isdigit(*t->words[1]);
3484 for (i = resetsig ? 1 : 2; t->words[i] != NULL; ++i) {
3485 n = getsig(t->words[i]);
3486 freecell(trap[n]);
3487 trap[n] = 0;
3488 if (!resetsig) {
3489 if (*t->words[1] != '\0') {
3490 trap[n] = strsave(t->words[1], 0);
3491 setsig(n, sig);
3492 } else
3493 setsig(n, SIG_IGN);
3494 } else {
3495 if (interactive)
3496 if (n == SIGINT)
3497 setsig(n, onintr);
3498 else
Eric Andersen8401eea2004-08-04 19:16:54 +00003499 setsig(n, n == SIGQUIT ? SIG_IGN : SIG_DFL);
Eric Andersenff9eee42001-06-29 04:57:14 +00003500 else
3501 setsig(n, SIG_DFL);
3502 }
3503 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003504 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003505}
3506
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003507static int getsig(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003508{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003509 int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003510
3511 if ((n = getn(s)) < 0 || n > _NSIG) {
3512 err("trap: bad signal number");
3513 n = 0;
3514 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003515 return n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003516}
3517
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003518static void setsig(int n, sighandler_t f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003519{
3520 if (n == 0)
3521 return;
3522 if (signal(n, SIG_IGN) != SIG_IGN || ourtrap[n]) {
3523 ourtrap[n] = 1;
3524 signal(n, f);
3525 }
3526}
3527
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003528static int getn(char *as)
Eric Andersenff9eee42001-06-29 04:57:14 +00003529{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003530 char *s;
3531 int n, m;
Eric Andersenff9eee42001-06-29 04:57:14 +00003532
3533 s = as;
3534 m = 1;
3535 if (*s == '-') {
3536 m = -1;
3537 s++;
3538 }
3539 for (n = 0; isdigit(*s); s++)
Eric Andersen8401eea2004-08-04 19:16:54 +00003540 n = (n * 10) + (*s - '0');
Eric Andersenff9eee42001-06-29 04:57:14 +00003541 if (*s) {
3542 prs(as);
3543 err(": bad number");
3544 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003545 return n * m;
Eric Andersenff9eee42001-06-29 04:57:14 +00003546}
3547
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003548static int dobreak(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003549{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003550 return brkcontin(t->words[1], 1);
Eric Andersenff9eee42001-06-29 04:57:14 +00003551}
3552
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003553static int docontinue(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003554{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003555 return brkcontin(t->words[1], 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003556}
3557
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003558static int brkcontin(char *cp, int val)
Eric Andersenff9eee42001-06-29 04:57:14 +00003559{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003560 struct brkcon *bc;
3561 int nl;
Eric Andersenff9eee42001-06-29 04:57:14 +00003562
Eric Andersen8401eea2004-08-04 19:16:54 +00003563 nl = cp == NULL ? 1 : getn(cp);
Eric Andersenff9eee42001-06-29 04:57:14 +00003564 if (nl <= 0)
3565 nl = 999;
3566 do {
3567 if ((bc = brklist) == NULL)
3568 break;
3569 brklist = bc->nextlev;
3570 } while (--nl);
3571 if (nl) {
3572 err("bad break/continue level");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003573 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003574 }
3575 isbreak = val;
3576 longjmp(bc->brkpt, 1);
3577 /* NOTREACHED */
3578}
3579
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003580static int doexit(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003581{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003582 char *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003583
3584 execflg = 0;
3585 if ((cp = t->words[1]) != NULL)
3586 setstatus(getn(cp));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003587
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003588 DBGPRINTF(("DOEXIT: calling leave(), t=%p\n", t));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003589
Eric Andersenff9eee42001-06-29 04:57:14 +00003590 leave();
3591 /* NOTREACHED */
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003592 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003593}
3594
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003595static int doexport(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003596{
Eric Andersen8401eea2004-08-04 19:16:54 +00003597 rdexp(t->words + 1, export, EXPORT);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003598 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003599}
3600
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003601static int doreadonly(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003602{
Eric Andersen8401eea2004-08-04 19:16:54 +00003603 rdexp(t->words + 1, ronly, RONLY);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003604 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003605}
3606
Eric Andersen8401eea2004-08-04 19:16:54 +00003607static void rdexp(char **wp, void (*f) (struct var *), int key)
Eric Andersenff9eee42001-06-29 04:57:14 +00003608{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003609 DBGPRINTF6(("RDEXP: enter, wp=%p, func=%p, key=%d\n", wp, f, key));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003610 DBGPRINTF6(("RDEXP: *wp=%s\n", *wp));
3611
Eric Andersenff9eee42001-06-29 04:57:14 +00003612 if (*wp != NULL) {
Matt Kraaif69bfc72001-07-12 19:39:59 +00003613 for (; *wp != NULL; wp++) {
3614 if (isassign(*wp)) {
3615 char *cp;
Eric Andersen8401eea2004-08-04 19:16:54 +00003616
Matt Kraaif69bfc72001-07-12 19:39:59 +00003617 assign(*wp, COPYV);
Eric Andersen8401eea2004-08-04 19:16:54 +00003618 for (cp = *wp; *cp != '='; cp++);
Matt Kraaif69bfc72001-07-12 19:39:59 +00003619 *cp = '\0';
3620 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003621 if (checkname(*wp))
Eric Andersen8401eea2004-08-04 19:16:54 +00003622 (*f) (lookup(*wp));
Eric Andersenff9eee42001-06-29 04:57:14 +00003623 else
3624 badid(*wp);
Matt Kraaif69bfc72001-07-12 19:39:59 +00003625 }
Eric Andersenff9eee42001-06-29 04:57:14 +00003626 } else
3627 putvlist(key, 1);
3628}
3629
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003630static void badid(char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00003631{
3632 prs(s);
3633 err(": bad identifier");
3634}
3635
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003636static int doset(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003637{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003638 struct var *vp;
3639 char *cp;
3640 int n;
Eric Andersenff9eee42001-06-29 04:57:14 +00003641
3642 if ((cp = t->words[1]) == NULL) {
3643 for (vp = vlist; vp; vp = vp->next)
3644 varput(vp->name, 1);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003645 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003646 }
3647 if (*cp == '-') {
3648 /* bad: t->words++; */
Eric Andersen8401eea2004-08-04 19:16:54 +00003649 for (n = 0; (t->words[n] = t->words[n + 1]) != NULL; n++);
Eric Andersenff9eee42001-06-29 04:57:14 +00003650 if (*++cp == 0)
3651 flag['x'] = flag['v'] = 0;
3652 else
3653 for (; *cp; cp++)
3654 switch (*cp) {
3655 case 'e':
3656 if (!interactive)
3657 flag['e']++;
3658 break;
3659
3660 default:
Eric Andersen8401eea2004-08-04 19:16:54 +00003661 if (*cp >= 'a' && *cp <= 'z')
3662 flag[(int) *cp]++;
Eric Andersenff9eee42001-06-29 04:57:14 +00003663 break;
3664 }
3665 setdash();
3666 }
3667 if (t->words[1]) {
3668 t->words[0] = dolv[0];
Eric Andersen8401eea2004-08-04 19:16:54 +00003669 for (n = 1; t->words[n]; n++)
3670 setarea((char *) t->words[n], 0);
3671 dolc = n - 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003672 dolv = t->words;
3673 setval(lookup("#"), putn(dolc));
Eric Andersen8401eea2004-08-04 19:16:54 +00003674 setarea((char *) (dolv - 1), 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00003675 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003676 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003677}
3678
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003679static void varput(char *s, int out)
Eric Andersenff9eee42001-06-29 04:57:14 +00003680{
Matt Kraai69edfec2001-08-06 14:14:18 +00003681 if (isalnum(*s) || *s == '_') {
Eric Andersenff9eee42001-06-29 04:57:14 +00003682 write(out, s, strlen(s));
3683 write(out, "\n", 1);
3684 }
3685}
3686
3687
3688/*
3689 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
3690 * This file contains code for the times builtin.
Eric Andersenff9eee42001-06-29 04:57:14 +00003691 */
Eric Andersen8401eea2004-08-04 19:16:54 +00003692static int dotimes(struct op *t)
Eric Andersenff9eee42001-06-29 04:57:14 +00003693{
3694 struct tms buf;
3695 long int clk_tck = sysconf(_SC_CLK_TCK);
3696
3697 times(&buf);
3698 printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
Eric Andersen8401eea2004-08-04 19:16:54 +00003699 (int) (buf.tms_utime / clk_tck / 60),
3700 ((double) buf.tms_utime) / clk_tck,
3701 (int) (buf.tms_stime / clk_tck / 60),
3702 ((double) buf.tms_stime) / clk_tck,
3703 (int) (buf.tms_cutime / clk_tck / 60),
3704 ((double) buf.tms_cutime) / clk_tck,
3705 (int) (buf.tms_cstime / clk_tck / 60),
3706 ((double) buf.tms_cstime) / clk_tck);
Eric Andersenff9eee42001-06-29 04:57:14 +00003707 return 0;
3708}
3709
3710
Eric Andersen8401eea2004-08-04 19:16:54 +00003711static int (*inbuilt(char *s)) (struct op *) {
Eric Andersen1c039232001-07-07 00:05:55 +00003712 const struct builtincmd *bp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003713
Eric Andersen1c039232001-07-07 00:05:55 +00003714 for (bp = builtincmds; bp->name != NULL; bp++)
3715 if (strcmp(bp->name, s) == 0)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003716 return bp->builtinfunc;
Eric Andersen1c039232001-07-07 00:05:55 +00003717
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003718 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00003719}
3720
3721/* -------- eval.c -------- */
3722
3723/*
3724 * ${}
3725 * `command`
3726 * blank interpretation
3727 * quoting
3728 * glob
3729 */
3730
Eric Andersen8401eea2004-08-04 19:16:54 +00003731static char **eval(char **ap, int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003732{
3733 struct wdblock *wb;
3734 char **wp;
3735 char **wf;
3736 jmp_buf ev;
3737
3738#if __GNUC__
3739 /* Avoid longjmp clobbering */
3740 (void) &wp;
3741 (void) &ap;
3742#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00003743
3744 DBGPRINTF4(("EVAL: enter, f=%d\n", f));
3745
Eric Andersenff9eee42001-06-29 04:57:14 +00003746 wp = NULL;
3747 wb = NULL;
3748 wf = NULL;
3749 if (newenv(setjmp(errpt = ev)) == 0) {
3750 while (*ap && isassign(*ap))
3751 expand(*ap++, &wb, f & ~DOGLOB);
3752 if (flag['k']) {
3753 for (wf = ap; *wf; wf++) {
3754 if (isassign(*wf))
3755 expand(*wf, &wb, f & ~DOGLOB);
3756 }
3757 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003758 for (wb = addword((char *) 0, wb); *ap; ap++) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003759 if (!flag['k'] || !isassign(*ap))
3760 expand(*ap, &wb, f & ~DOKEY);
3761 }
Eric Andersen8401eea2004-08-04 19:16:54 +00003762 wb = addword((char *) 0, wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00003763 wp = getwords(wb);
3764 quitenv();
3765 } else
3766 gflg = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003767
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003768 return gflg ? (char **) NULL : wp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003769}
3770
3771/*
3772 * Make the exported environment from the exported
3773 * names in the dictionary. Keyword assignments
3774 * will already have been done.
3775 */
Eric Andersenfd7a4c82004-09-02 23:13:10 +00003776static char **makenv(int all, struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00003777{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003778 struct var *vp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003779
3780 DBGPRINTF5(("MAKENV: enter, all=%d\n", all));
Eric Andersenff9eee42001-06-29 04:57:14 +00003781
Eric Andersenff9eee42001-06-29 04:57:14 +00003782 for (vp = vlist; vp; vp = vp->next)
Eric Andersen12de6cf2004-08-04 19:19:10 +00003783 if (all || vp->status & EXPORT)
Eric Andersenff9eee42001-06-29 04:57:14 +00003784 wb = addword(vp->name, wb);
Eric Andersen8401eea2004-08-04 19:16:54 +00003785 wb = addword((char *) 0, wb);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003786 return getwords(wb);
Eric Andersenff9eee42001-06-29 04:57:14 +00003787}
3788
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003789static char *evalstr(char *cp, int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003790{
3791 struct wdblock *wb;
3792
Mike Frysinger02d8fa42006-05-05 20:32:31 +00003793 DBGPRINTF6(("EVALSTR: enter, cp=%p, f=%d\n", cp, f));
Eric Andersen12de6cf2004-08-04 19:19:10 +00003794
Eric Andersenff9eee42001-06-29 04:57:14 +00003795 wb = NULL;
3796 if (expand(cp, &wb, f)) {
Eric Andersen8401eea2004-08-04 19:16:54 +00003797 if (wb == NULL || wb->w_nword == 0
3798 || (cp = wb->w_words[0]) == NULL)
Eric Andersenff9eee42001-06-29 04:57:14 +00003799 cp = "";
3800 DELETE(wb);
3801 } else
3802 cp = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003803 return cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003804}
3805
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003806static int expand(char *cp, struct wdblock **wbp, int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003807{
3808 jmp_buf ev;
3809
3810#if __GNUC__
3811 /* Avoid longjmp clobbering */
3812 (void) &cp;
3813#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00003814
3815 DBGPRINTF3(("EXPAND: enter, f=%d\n", f));
3816
Eric Andersenff9eee42001-06-29 04:57:14 +00003817 gflg = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003818
Eric Andersenff9eee42001-06-29 04:57:14 +00003819 if (cp == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003820 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003821
Eric Andersenff9eee42001-06-29 04:57:14 +00003822 if (!anys("$`'\"", cp) &&
Eric Andersen8401eea2004-08-04 19:16:54 +00003823 !anys(ifs->value, cp) && ((f & DOGLOB) == 0 || !anys("[*?", cp))) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003824 cp = strsave(cp, areanum);
3825 if (f & DOTRIM)
3826 unquote(cp);
3827 *wbp = addword(cp, *wbp);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003828 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00003829 }
3830 if (newenv(setjmp(errpt = ev)) == 0) {
3831 PUSHIO(aword, cp, strchar);
3832 e.iobase = e.iop;
3833 while ((cp = blank(f)) && gflg == 0) {
3834 e.linep = cp;
3835 cp = strsave(cp, areanum);
Eric Andersen8401eea2004-08-04 19:16:54 +00003836 if ((f & DOGLOB) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00003837 if (f & DOTRIM)
3838 unquote(cp);
3839 *wbp = addword(cp, *wbp);
3840 } else
3841 *wbp = glob(cp, *wbp);
3842 }
3843 quitenv();
3844 } else
3845 gflg = 1;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003846 return gflg == 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003847}
3848
3849/*
3850 * Blank interpretation and quoting
3851 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003852static char *blank(int f)
Eric Andersenff9eee42001-06-29 04:57:14 +00003853{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003854 int c, c1;
3855 char *sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003856 int scanequals, foundequals;
3857
Eric Andersen12de6cf2004-08-04 19:19:10 +00003858 DBGPRINTF3(("BLANK: enter, f=%d\n", f));
3859
Eric Andersenff9eee42001-06-29 04:57:14 +00003860 sp = e.linep;
3861 scanequals = f & DOKEY;
3862 foundequals = 0;
3863
Eric Andersen8401eea2004-08-04 19:16:54 +00003864 loop:
Eric Andersenff9eee42001-06-29 04:57:14 +00003865 switch (c = subgetc('"', foundequals)) {
3866 case 0:
3867 if (sp == e.linep)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003868 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003869 *e.linep++ = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003870 return sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003871
3872 default:
3873 if (f & DOBLANK && any(c, ifs->value))
3874 goto loop;
3875 break;
3876
3877 case '"':
3878 case '\'':
3879 scanequals = 0;
3880 if (INSUB())
3881 break;
3882 for (c1 = c; (c = subgetc(c1, 1)) != c1;) {
3883 if (c == 0)
3884 break;
3885 if (c == '\'' || !any(c, "$`\""))
3886 c |= QUOTE;
3887 *e.linep++ = c;
3888 }
3889 c = 0;
3890 }
3891 unget(c);
Matt Kraai69edfec2001-08-06 14:14:18 +00003892 if (!isalpha(c) && c != '_')
Eric Andersenff9eee42001-06-29 04:57:14 +00003893 scanequals = 0;
3894 for (;;) {
3895 c = subgetc('"', foundequals);
3896 if (c == 0 ||
Eric Andersen8401eea2004-08-04 19:16:54 +00003897 f & (DOBLANK && any(c, ifs->value)) ||
3898 (!INSUB() && any(c, "\"'"))) {
3899 scanequals = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003900 unget(c);
3901 if (any(c, "\"'"))
3902 goto loop;
3903 break;
3904 }
3905 if (scanequals) {
3906 if (c == '=') {
3907 foundequals = 1;
Eric Andersen8401eea2004-08-04 19:16:54 +00003908 scanequals = 0;
3909 } else if (!isalnum(c) && c != '_')
Eric Andersenff9eee42001-06-29 04:57:14 +00003910 scanequals = 0;
3911 }
3912 *e.linep++ = c;
3913 }
3914 *e.linep++ = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003915 return sp;
Eric Andersenff9eee42001-06-29 04:57:14 +00003916}
3917
3918/*
3919 * Get characters, substituting for ` and $
3920 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003921static int subgetc(char ec, int quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00003922{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003923 char c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003924
3925 DBGPRINTF3(("SUBGETC: enter, quoted=%d\n", quoted));
Eric Andersenff9eee42001-06-29 04:57:14 +00003926
Eric Andersen8401eea2004-08-04 19:16:54 +00003927 again:
Eric Andersenff9eee42001-06-29 04:57:14 +00003928 c = my_getc(ec);
3929 if (!INSUB() && ec != '\'') {
3930 if (c == '`') {
3931 if (grave(quoted) == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003932 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00003933 e.iop->task = XGRAVE;
3934 goto again;
3935 }
3936 if (c == '$' && (c = dollar(quoted)) == 0) {
3937 e.iop->task = XDOLL;
3938 goto again;
3939 }
3940 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003941 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003942}
3943
3944/*
3945 * Prepare to generate the string returned by ${} substitution.
3946 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00003947static int dollar(int quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00003948{
3949 int otask;
3950 struct io *oiop;
3951 char *dolp;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00003952 char *s, c, *cp = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00003953 struct var *vp;
3954
Eric Andersen12de6cf2004-08-04 19:19:10 +00003955 DBGPRINTF3(("DOLLAR: enter, quoted=%d\n", quoted));
3956
Eric Andersenff9eee42001-06-29 04:57:14 +00003957 c = readc();
3958 s = e.linep;
3959 if (c != '{') {
3960 *e.linep++ = c;
Matt Kraai69edfec2001-08-06 14:14:18 +00003961 if (isalpha(c) || c == '_') {
Eric Andersen8401eea2004-08-04 19:16:54 +00003962 while ((c = readc()) != 0 && (isalnum(c) || c == '_'))
Eric Andersenff9eee42001-06-29 04:57:14 +00003963 if (e.linep < elinep)
3964 *e.linep++ = c;
3965 unget(c);
3966 }
3967 c = 0;
3968 } else {
3969 oiop = e.iop;
3970 otask = e.iop->task;
Eric Andersen12de6cf2004-08-04 19:19:10 +00003971
Eric Andersenff9eee42001-06-29 04:57:14 +00003972 e.iop->task = XOTHER;
Eric Andersen8401eea2004-08-04 19:16:54 +00003973 while ((c = subgetc('"', 0)) != 0 && c != '}' && c != '\n')
Eric Andersenff9eee42001-06-29 04:57:14 +00003974 if (e.linep < elinep)
3975 *e.linep++ = c;
3976 if (oiop == e.iop)
3977 e.iop->task = otask;
3978 if (c != '}') {
3979 err("unclosed ${");
3980 gflg++;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003981 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00003982 }
3983 }
3984 if (e.linep >= elinep) {
3985 err("string in ${} too long");
3986 gflg++;
3987 e.linep -= 10;
3988 }
3989 *e.linep = 0;
3990 if (*s)
Eric Andersen8401eea2004-08-04 19:16:54 +00003991 for (cp = s + 1; *cp; cp++)
Eric Andersenff9eee42001-06-29 04:57:14 +00003992 if (any(*cp, "=-+?")) {
3993 c = *cp;
3994 *cp++ = 0;
3995 break;
3996 }
3997 if (s[1] == 0 && (*s == '*' || *s == '@')) {
3998 if (dolc > 1) {
3999 /* currently this does not distinguish $* and $@ */
4000 /* should check dollar */
4001 e.linep = s;
Eric Andersen8401eea2004-08-04 19:16:54 +00004002 PUSHIO(awordlist, dolv + 1, dolchar);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004003 return 0;
Eric Andersen8401eea2004-08-04 19:16:54 +00004004 } else { /* trap the nasty ${=} */
Eric Andersenff9eee42001-06-29 04:57:14 +00004005 s[0] = '1';
4006 s[1] = 0;
4007 }
4008 }
4009 vp = lookup(s);
4010 if ((dolp = vp->value) == null) {
4011 switch (c) {
4012 case '=':
4013 if (isdigit(*s)) {
4014 err("cannot use ${...=...} with $n");
4015 gflg++;
4016 break;
4017 }
4018 setval(vp, cp);
4019 dolp = vp->value;
4020 break;
4021
4022 case '-':
4023 dolp = strsave(cp, areanum);
4024 break;
4025
4026 case '?':
4027 if (*cp == 0) {
4028 prs("missing value for ");
4029 err(s);
4030 } else
4031 err(cp);
4032 gflg++;
4033 break;
4034 }
4035 } else if (c == '+')
4036 dolp = strsave(cp, areanum);
4037 if (flag['u'] && dolp == null) {
4038 prs("unset variable: ");
4039 err(s);
4040 gflg++;
4041 }
4042 e.linep = s;
4043 PUSHIO(aword, dolp, quoted ? qstrchar : strchar);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004044 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004045}
4046
4047/*
4048 * Run the command in `...` and read its output.
4049 */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004050
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004051static int grave(int quoted)
Eric Andersenff9eee42001-06-29 04:57:14 +00004052{
Eric Andersenff9eee42001-06-29 04:57:14 +00004053 char *cp;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004054 int i;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004055 int j;
Eric Andersenff9eee42001-06-29 04:57:14 +00004056 int pf[2];
Eric Andersen737f5fb2003-03-14 16:05:59 +00004057 static char child_cmd[LINELIM];
4058 char *src;
4059 char *dest;
4060 int count;
4061 int ignore;
4062 int ignore_once;
4063 char *argument_list[4];
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004064 struct wdblock *wb = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004065
4066#if __GNUC__
4067 /* Avoid longjmp clobbering */
4068 (void) &cp;
4069#endif
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004070
Eric Andersenff9eee42001-06-29 04:57:14 +00004071 for (cp = e.iop->argp->aword; *cp != '`'; cp++)
4072 if (*cp == 0) {
4073 err("no closing `");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004074 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004075 }
Eric Andersen737f5fb2003-03-14 16:05:59 +00004076
4077 /* string copy with dollar expansion */
4078 src = e.iop->argp->aword;
4079 dest = child_cmd;
4080 count = 0;
4081 ignore = 0;
4082 ignore_once = 0;
4083 while ((*src != '`') && (count < LINELIM)) {
4084 if (*src == '\'')
4085 ignore = !ignore;
4086 if (*src == '\\')
4087 ignore_once = 1;
4088 if (*src == '$' && !ignore && !ignore_once) {
4089 struct var *vp;
4090 char var_name[LINELIM];
4091 char alt_value[LINELIM];
4092 int var_index = 0;
4093 int alt_index = 0;
4094 char operator = 0;
4095 int braces = 0;
4096 char *value;
4097
4098 src++;
4099 if (*src == '{') {
4100 braces = 1;
4101 src++;
4102 }
4103
4104 var_name[var_index++] = *src++;
Paul Fox54690dc2005-07-20 18:33:12 +00004105 while (isalnum(*src) || *src=='_')
Eric Andersen737f5fb2003-03-14 16:05:59 +00004106 var_name[var_index++] = *src++;
4107 var_name[var_index] = 0;
4108
4109 if (braces) {
4110 switch (*src) {
4111 case '}':
4112 break;
4113 case '-':
4114 case '=':
4115 case '+':
4116 case '?':
Eric Andersen8401eea2004-08-04 19:16:54 +00004117 operator = * src;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004118 break;
4119 default:
4120 err("unclosed ${\n");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004121 return 0;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004122 }
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004123 if (operator) {
Eric Andersen737f5fb2003-03-14 16:05:59 +00004124 src++;
4125 while (*src && (*src != '}')) {
4126 alt_value[alt_index++] = *src++;
4127 }
4128 alt_value[alt_index] = 0;
4129 if (*src != '}') {
4130 err("unclosed ${\n");
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004131 return 0;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004132 }
4133 }
4134 src++;
4135 }
4136
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004137 if (isalpha(*var_name)) {
4138 /* let subshell handle it instead */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004139
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004140 char *namep = var_name;
4141
4142 *dest++ = '$';
4143 if (braces)
4144 *dest++ = '{';
4145 while (*namep)
4146 *dest++ = *namep++;
4147 if (operator) {
4148 char *altp = alt_value;
4149 *dest++ = operator;
4150 while (*altp)
4151 *dest++ = *altp++;
4152 }
4153 if (braces)
4154 *dest++ = '}';
4155
4156 wb = addword(lookup(var_name)->name, wb);
4157 } else {
4158 /* expand */
4159
4160 vp = lookup(var_name);
4161 if (vp->value != null)
4162 value = (operator == '+') ?
4163 alt_value : vp->value;
4164 else if (operator == '?') {
4165 err(alt_value);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004166 return 0;
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004167 } else if (alt_index && (operator != '+')) {
4168 value = alt_value;
4169 if (operator == '=')
4170 setval(vp, value);
4171 } else
4172 continue;
4173
4174 while (*value && (count < LINELIM)) {
4175 *dest++ = *value++;
4176 count++;
4177 }
Eric Andersen737f5fb2003-03-14 16:05:59 +00004178 }
4179 } else {
4180 *dest++ = *src++;
4181 count++;
4182 ignore_once = 0;
4183 }
4184 }
4185 *dest = '\0';
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004186
Eric Andersenff9eee42001-06-29 04:57:14 +00004187 if (openpipe(pf) < 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004188 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004189
Eric Andersen8401eea2004-08-04 19:16:54 +00004190 while ((i = vfork()) == -1 && errno == EAGAIN);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004191
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004192 DBGPRINTF3(("GRAVE: i is %p\n", io));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004193
Eric Andersen737f5fb2003-03-14 16:05:59 +00004194 if (i < 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004195 closepipe(pf);
Eric Andersen8401eea2004-08-04 19:16:54 +00004196 err((char *) bb_msg_memory_exhausted);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004197 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004198 }
4199 if (i != 0) {
Eric Andersen737f5fb2003-03-14 16:05:59 +00004200 waitpid(i, NULL, 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004201 e.iop->argp->aword = ++cp;
4202 close(pf[1]);
Eric Andersen8401eea2004-08-04 19:16:54 +00004203 PUSHIO(afile, remap(pf[0]),
4204 (int (*)(struct ioarg *)) ((quoted) ? qgravechar :
4205 gravechar));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004206 return 1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004207 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004208 /* allow trapped signals */
Eric Andersen737f5fb2003-03-14 16:05:59 +00004209 /* XXX - Maybe this signal stuff should go as well? */
Eric Andersen8401eea2004-08-04 19:16:54 +00004210 for (j = 0; j <= _NSIG; j++)
Eric Andersen737f5fb2003-03-14 16:05:59 +00004211 if (ourtrap[j] && signal(j, SIG_IGN) != SIG_IGN)
4212 signal(j, SIG_DFL);
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004213
Eric Andersenff9eee42001-06-29 04:57:14 +00004214 dup2(pf[1], 1);
4215 closepipe(pf);
Eric Andersen737f5fb2003-03-14 16:05:59 +00004216
Eric Andersen8401eea2004-08-04 19:16:54 +00004217 argument_list[0] = (char *) DEFAULT_SHELL;
Eric Andersen737f5fb2003-03-14 16:05:59 +00004218 argument_list[1] = "-c";
4219 argument_list[2] = child_cmd;
4220 argument_list[3] = 0;
4221
Eric Andersenfd7a4c82004-09-02 23:13:10 +00004222 cp = rexecve(argument_list[0], argument_list, makenv(1, wb));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004223 prs(argument_list[0]);
4224 prs(": ");
4225 err(cp);
Eric Andersen737f5fb2003-03-14 16:05:59 +00004226 _exit(1);
Eric Andersenff9eee42001-06-29 04:57:14 +00004227}
4228
Eric Andersen737f5fb2003-03-14 16:05:59 +00004229
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004230static char *unquote(char *as)
Eric Andersenff9eee42001-06-29 04:57:14 +00004231{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004232 char *s;
Eric Andersenff9eee42001-06-29 04:57:14 +00004233
4234 if ((s = as) != NULL)
4235 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;
4251static char spcl[] = "[?*";
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) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004267 for (cl = addword(scopy(cp), (struct wdblock *) 0); anyspcl(cl);
4268 cl = nl) {
4269 nl = newword(cl->w_nword * 2);
4270 for (i = 0; i < cl->w_nword; i++) { /* for each argument */
Eric Andersenff9eee42001-06-29 04:57:14 +00004271 for (pp = cl->w_words[i]; *pp; pp++)
4272 if (any(*pp, spcl)) {
4273 globname(cl->w_words[i], pp);
4274 break;
4275 }
4276 if (*pp == '\0')
4277 nl = addword(scopy(cl->w_words[i]), nl);
4278 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004279 for (i = 0; i < cl->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004280 DELETE(cl->w_words[i]);
4281 DELETE(cl);
4282 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004283 for (i = 0; i < cl->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004284 unquote(cl->w_words[i]);
Eric Andersen8401eea2004-08-04 19:16:54 +00004285 glob0((char *) cl->w_words, cl->w_nword, sizeof(char *), xstrcmp);
Eric Andersenff9eee42001-06-29 04:57:14 +00004286 if (cl->w_nword) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004287 for (i = 0; i < cl->w_nword; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004288 wb = addword(cl->w_words[i], wb);
4289 DELETE(cl);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004290 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004291 }
4292 }
4293 wb = addword(unquote(cp), wb);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004294 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004295}
4296
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004297static void globname(char *we, char *pp)
Eric Andersenff9eee42001-06-29 04:57:14 +00004298{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004299 char *np, *cp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004300 char *name, *gp, *dp;
4301 int k;
4302 DIR *dirp;
4303 struct dirent *de;
Eric Andersen8401eea2004-08-04 19:16:54 +00004304 char dname[NAME_MAX + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00004305 struct stat dbuf;
4306
4307 for (np = we; np != pp; pp--)
4308 if (pp[-1] == '/')
4309 break;
Eric Andersen8401eea2004-08-04 19:16:54 +00004310 for (dp = cp = space((int) (pp - np) + 3); np < pp;)
Eric Andersenff9eee42001-06-29 04:57:14 +00004311 *cp++ = *np++;
4312 *cp++ = '.';
4313 *cp = '\0';
Eric Andersen8401eea2004-08-04 19:16:54 +00004314 for (gp = cp = space(strlen(pp) + 1); *np && *np != '/';)
Eric Andersenff9eee42001-06-29 04:57:14 +00004315 *cp++ = *np++;
4316 *cp = '\0';
4317 dirp = opendir(dp);
4318 if (dirp == 0) {
4319 DELETE(dp);
4320 DELETE(gp);
4321 return;
4322 }
4323 dname[NAME_MAX] = '\0';
Eric Andersen8401eea2004-08-04 19:16:54 +00004324 while ((de = readdir(dirp)) != NULL) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004325 /* XXX Hmmm... What this could be? (abial) */
4326 /*
Eric Andersen8401eea2004-08-04 19:16:54 +00004327 if (ent[j].d_ino == 0)
4328 continue;
4329 */
Eric Andersenff9eee42001-06-29 04:57:14 +00004330 strncpy(dname, de->d_name, NAME_MAX);
Eric Andersen8401eea2004-08-04 19:16:54 +00004331 if (dname[0] == '.')
4332 if (*gp != '.')
4333 continue;
4334 for (k = 0; k < NAME_MAX; k++)
4335 if (any(dname[k], spcl))
4336 dname[k] |= QUOTE;
4337 if (gmatch(dname, gp)) {
4338 name = generate(we, pp, dname, np);
4339 if (*np && !anys(np, spcl)) {
4340 if (stat(name, &dbuf)) {
4341 DELETE(name);
Eric Andersenff9eee42001-06-29 04:57:14 +00004342 continue;
Eric Andersenff9eee42001-06-29 04:57:14 +00004343 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004344 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004345 nl = addword(name, nl);
4346 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004347 }
4348 closedir(dirp);
4349 DELETE(dp);
4350 DELETE(gp);
4351}
4352
4353/*
4354 * generate a pathname as below.
4355 * start..end1 / middle end
4356 * the slashes come for free
4357 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004358static char *generate(char *start1, char *end1, char *middle, char *end)
Eric Andersenff9eee42001-06-29 04:57:14 +00004359{
4360 char *p;
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004361 char *op, *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004362
Eric Andersen8401eea2004-08-04 19:16:54 +00004363 p = op =
4364 space((int) (end1 - start1) + strlen(middle) + strlen(end) + 2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004365 for (xp = start1; xp != end1;)
4366 *op++ = *xp++;
Eric Andersen8401eea2004-08-04 19:16:54 +00004367 for (xp = middle; (*op++ = *xp++) != '\0';);
Eric Andersenff9eee42001-06-29 04:57:14 +00004368 op--;
Eric Andersen8401eea2004-08-04 19:16:54 +00004369 for (xp = end; (*op++ = *xp++) != '\0';);
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
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004385static int xstrcmp(char *p1, char *p2)
Eric Andersenff9eee42001-06-29 04:57:14 +00004386{
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004387 return strcmp(*(char **) p1, *(char **) p2);
Eric Andersenff9eee42001-06-29 04:57:14 +00004388}
4389
4390/* -------- word.c -------- */
4391
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004392static struct wdblock *newword(int nw)
Eric Andersenff9eee42001-06-29 04:57:14 +00004393{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004394 struct wdblock *wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004395
Eric Andersen8401eea2004-08-04 19:16:54 +00004396 wb = (struct wdblock *) space(sizeof(*wb) + nw * sizeof(char *));
Eric Andersenff9eee42001-06-29 04:57:14 +00004397 wb->w_bsize = nw;
4398 wb->w_nword = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004399 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004400}
4401
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004402static struct wdblock *addword(char *wd, struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004403{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004404 struct wdblock *wb2;
4405 int nw;
Eric Andersenff9eee42001-06-29 04:57:14 +00004406
4407 if (wb == NULL)
4408 wb = newword(NSTART);
4409 if ((nw = wb->w_nword) >= wb->w_bsize) {
4410 wb2 = newword(nw * 2);
Eric Andersen8401eea2004-08-04 19:16:54 +00004411 memcpy((char *) wb2->w_words, (char *) wb->w_words,
4412 nw * sizeof(char *));
Eric Andersenff9eee42001-06-29 04:57:14 +00004413 wb2->w_nword = nw;
4414 DELETE(wb);
4415 wb = wb2;
4416 }
4417 wb->w_words[wb->w_nword++] = wd;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004418 return wb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004419}
Eric Andersen8401eea2004-08-04 19:16:54 +00004420
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004421static
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004422char **getwords(struct wdblock *wb)
Eric Andersenff9eee42001-06-29 04:57:14 +00004423{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004424 char **wd;
4425 int nb;
Eric Andersenff9eee42001-06-29 04:57:14 +00004426
4427 if (wb == NULL)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004428 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004429 if (wb->w_nword == 0) {
4430 DELETE(wb);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004431 return NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00004432 }
4433 wd = (char **) space(nb = sizeof(*wd) * wb->w_nword);
Eric Andersen8401eea2004-08-04 19:16:54 +00004434 memcpy((char *) wd, (char *) wb->w_words, nb);
4435 DELETE(wb); /* perhaps should done by caller */
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004436 return wd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004437}
4438
"Vladimir N. Oleynik"ac973172005-09-22 14:38:17 +00004439static int (*func) (char *, char *);
4440static int globv;
Eric Andersenff9eee42001-06-29 04:57:14 +00004441
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004442static void glob0(char *a0, unsigned a1, int a2, int (*a3) (char *, char *))
Eric Andersenff9eee42001-06-29 04:57:14 +00004443{
4444 func = a3;
4445 globv = a2;
4446 glob1(a0, a0 + a1 * a2);
4447}
4448
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004449static void glob1(char *base, char *lim)
Eric Andersenff9eee42001-06-29 04:57:14 +00004450{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004451 char *i, *j;
Eric Andersenff9eee42001-06-29 04:57:14 +00004452 int v2;
4453 char *lptr, *hptr;
4454 int c;
4455 unsigned n;
4456
4457
4458 v2 = globv;
4459
Eric Andersen8401eea2004-08-04 19:16:54 +00004460 top:
4461 if ((n = (int) (lim - base)) <= v2)
Eric Andersenff9eee42001-06-29 04:57:14 +00004462 return;
Eric Andersen8401eea2004-08-04 19:16:54 +00004463 n = v2 * (n / (2 * v2));
4464 hptr = lptr = base + n;
Eric Andersenff9eee42001-06-29 04:57:14 +00004465 i = base;
Eric Andersen8401eea2004-08-04 19:16:54 +00004466 j = lim - v2;
4467 for (;;) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004468 if (i < lptr) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004469 if ((c = (*func) (i, lptr)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004470 glob2(i, lptr -= v2);
4471 continue;
4472 }
4473 if (c < 0) {
4474 i += v2;
4475 continue;
4476 }
4477 }
4478
Eric Andersen8401eea2004-08-04 19:16:54 +00004479 begin:
Eric Andersenff9eee42001-06-29 04:57:14 +00004480 if (j > hptr) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004481 if ((c = (*func) (hptr, j)) == 0) {
Eric Andersenff9eee42001-06-29 04:57:14 +00004482 glob2(hptr += v2, j);
4483 goto begin;
4484 }
4485 if (c > 0) {
4486 if (i == lptr) {
4487 glob3(i, hptr += v2, j);
4488 i = lptr += v2;
4489 goto begin;
4490 }
4491 glob2(i, j);
4492 j -= v2;
4493 i += v2;
4494 continue;
4495 }
4496 j -= v2;
4497 goto begin;
4498 }
4499
4500
4501 if (i == lptr) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004502 if (lptr - base >= lim - hptr) {
4503 glob1(hptr + v2, lim);
Eric Andersenff9eee42001-06-29 04:57:14 +00004504 lim = lptr;
4505 } else {
4506 glob1(base, lptr);
Eric Andersen8401eea2004-08-04 19:16:54 +00004507 base = hptr + v2;
Eric Andersenff9eee42001-06-29 04:57:14 +00004508 }
4509 goto top;
4510 }
4511
4512
4513 glob3(j, lptr -= v2, i);
4514 j = hptr -= v2;
4515 }
4516}
4517
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004518static void glob2(char *i, char *j)
Eric Andersenff9eee42001-06-29 04:57:14 +00004519{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004520 char *index1, *index2, c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004521 int m;
4522
4523 m = globv;
4524 index1 = i;
4525 index2 = j;
4526 do {
4527 c = *index1;
4528 *index1++ = *index2;
4529 *index2++ = c;
Eric Andersen8401eea2004-08-04 19:16:54 +00004530 } while (--m);
Eric Andersenff9eee42001-06-29 04:57:14 +00004531}
4532
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004533static void glob3(char *i, char *j, char *k)
Eric Andersenff9eee42001-06-29 04:57:14 +00004534{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004535 char *index1, *index2, *index3;
Eric Andersenff9eee42001-06-29 04:57:14 +00004536 int c;
4537 int m;
4538
4539 m = globv;
4540 index1 = i;
4541 index2 = j;
4542 index3 = k;
4543 do {
4544 c = *index1;
4545 *index1++ = *index3;
4546 *index3++ = *index2;
4547 *index2++ = c;
Eric Andersen8401eea2004-08-04 19:16:54 +00004548 } while (--m);
Eric Andersenff9eee42001-06-29 04:57:14 +00004549}
4550
4551/* -------- io.c -------- */
4552
4553/*
4554 * shell IO
4555 */
4556
Eric Andersen8401eea2004-08-04 19:16:54 +00004557static int my_getc(int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00004558{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004559 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004560
Eric Andersen8401eea2004-08-04 19:16:54 +00004561 if (e.linep > elinep) {
4562 while ((c = readc()) != '\n' && c);
Eric Andersenff9eee42001-06-29 04:57:14 +00004563 err("input line too long");
4564 gflg++;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004565 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004566 }
4567 c = readc();
Eric Andersen737f5fb2003-03-14 16:05:59 +00004568 if ((ec != '\'') && (ec != '`') && (e.iop->task != XGRAVE)) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004569 if (c == '\\') {
Eric Andersenff9eee42001-06-29 04:57:14 +00004570 c = readc();
4571 if (c == '\n' && ec != '\"')
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004572 return my_getc(ec);
Eric Andersenff9eee42001-06-29 04:57:14 +00004573 c |= QUOTE;
4574 }
4575 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004576 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004577}
4578
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004579static void unget(int c)
Eric Andersenff9eee42001-06-29 04:57:14 +00004580{
4581 if (e.iop >= e.iobase)
4582 e.iop->peekc = c;
4583}
4584
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004585static int eofc(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00004586{
Eric Andersen8401eea2004-08-04 19:16:54 +00004587 return e.iop < e.iobase || (e.iop->peekc == 0 && e.iop->prev == 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004588}
4589
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004590static int readc(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00004591{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004592 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004593
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004594 RCPRINTF(("READC: e.iop %p, e.iobase %p\n", e.iop, e.iobase));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004595
4596 for (; e.iop >= e.iobase; e.iop--) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004597 RCPRINTF(("READC: e.iop %p, peekc 0x%x\n", e.iop, e.iop->peekc));
Eric Andersenff9eee42001-06-29 04:57:14 +00004598 if ((c = e.iop->peekc) != '\0') {
4599 e.iop->peekc = 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004600 return c;
Eric Andersen8401eea2004-08-04 19:16:54 +00004601 } else {
4602 if (e.iop->prev != 0) {
4603 if ((c = (*e.iop->iofn) (e.iop->argp, e.iop)) != '\0') {
4604 if (c == -1) {
4605 e.iop++;
4606 continue;
4607 }
4608 if (e.iop == iostack)
4609 ioecho(c);
4610 return (e.iop->prev = c);
4611 } else if (e.iop->task == XIO && e.iop->prev != '\n') {
4612 e.iop->prev = 0;
4613 if (e.iop == iostack)
4614 ioecho('\n');
4615 return '\n';
4616 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004617 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004618 if (e.iop->task == XIO) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00004619 if (multiline) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004620 return e.iop->prev = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004621 }
Eric Andersen8401eea2004-08-04 19:16:54 +00004622 if (interactive && e.iop == iostack + 1) {
4623#ifdef CONFIG_FEATURE_COMMAND_EDITING
4624 current_prompt = prompt->value;
4625#else
4626 prs(prompt->value);
4627#endif
4628 }
4629 }
Eric Andersenff9eee42001-06-29 04:57:14 +00004630 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004631
4632 } /* FOR */
4633
4634 if (e.iop >= iostack) {
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004635 RCPRINTF(("READC: return 0, e.iop %p\n", e.iop));
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004636 return 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004637 }
4638
4639 DBGPRINTF(("READC: leave()...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00004640 leave();
Eric Andersen12de6cf2004-08-04 19:19:10 +00004641
Eric Andersenff9eee42001-06-29 04:57:14 +00004642 /* NOTREACHED */
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004643 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004644}
4645
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004646static void ioecho(char c)
Eric Andersenff9eee42001-06-29 04:57:14 +00004647{
4648 if (flag['v'])
4649 write(2, &c, sizeof c);
4650}
4651
Eric Andersen12de6cf2004-08-04 19:19:10 +00004652
Eric Andersen8401eea2004-08-04 19:16:54 +00004653static void pushio(struct ioarg *argp, int (*fn) (struct ioarg *))
Eric Andersenff9eee42001-06-29 04:57:14 +00004654{
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004655 DBGPRINTF(("PUSHIO: argp %p, argp->afid 0x%x, e.iop %p\n", argp,
Eric Andersen12de6cf2004-08-04 19:19:10 +00004656 argp->afid, e.iop));
4657
4658 /* Set env ptr for io source to next array spot and check for array overflow */
Eric Andersenff9eee42001-06-29 04:57:14 +00004659 if (++e.iop >= &iostack[NPUSH]) {
4660 e.iop--;
4661 err("Shell input nested too deeply");
4662 gflg++;
4663 return;
4664 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004665
4666 /* We did not overflow the NPUSH array spots so setup data structs */
4667
4668 e.iop->iofn = (int (*)(struct ioarg *, struct io *)) fn; /* Store data source func ptr */
Eric Andersenff9eee42001-06-29 04:57:14 +00004669
4670 if (argp->afid != AFID_NOBUF)
Eric Andersen8401eea2004-08-04 19:16:54 +00004671 e.iop->argp = argp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004672 else {
Eric Andersen12de6cf2004-08-04 19:19:10 +00004673
4674 e.iop->argp = ioargstack + (e.iop - iostack); /* MAL - index into stack */
4675 *e.iop->argp = *argp; /* copy data from temp area into stack spot */
4676
4677 /* MAL - mainbuf is for 1st data source (command line?) and all nested use a single shared buffer? */
4678
4679 if (e.iop == &iostack[0])
4680 e.iop->argp->afbuf = &mainbuf;
4681 else
4682 e.iop->argp->afbuf = &sharedbuf;
4683
4684 /* MAL - if not a termimal AND (commandline OR readable file) then give it a buffer id? */
4685 /* This line appears to be active when running scripts from command line */
4686 if ((isatty(e.iop->argp->afile) == 0)
4687 && (e.iop == &iostack[0]
Denis Vlasenkoea620772006-10-14 02:23:43 +00004688 || lseek(e.iop->argp->afile, 0L, SEEK_CUR) != -1)) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00004689 if (++bufid == AFID_NOBUF) /* counter rollover check, AFID_NOBUF = 11111111 */
4690 bufid = AFID_ID; /* AFID_ID = 0 */
4691
4692 e.iop->argp->afid = bufid; /* assign buffer id */
Eric Andersen8401eea2004-08-04 19:16:54 +00004693 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004694
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004695 DBGPRINTF(("PUSHIO: iostack %p, e.iop %p, afbuf %p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00004696 iostack, e.iop, e.iop->argp->afbuf));
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004697 DBGPRINTF(("PUSHIO: mbuf %p, sbuf %p, bid %d, e.iop %p\n",
Eric Andersen12de6cf2004-08-04 19:19:10 +00004698 &mainbuf, &sharedbuf, bufid, e.iop));
4699
Eric Andersenff9eee42001-06-29 04:57:14 +00004700 }
4701
Eric Andersen8401eea2004-08-04 19:16:54 +00004702 e.iop->prev = ~'\n';
Eric Andersenff9eee42001-06-29 04:57:14 +00004703 e.iop->peekc = 0;
4704 e.iop->xchar = 0;
4705 e.iop->nlcount = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004706
Eric Andersenff9eee42001-06-29 04:57:14 +00004707 if (fn == filechar || fn == linechar)
4708 e.iop->task = XIO;
Eric Andersen8401eea2004-08-04 19:16:54 +00004709 else if (fn == (int (*)(struct ioarg *)) gravechar
4710 || fn == (int (*)(struct ioarg *)) qgravechar)
Eric Andersenff9eee42001-06-29 04:57:14 +00004711 e.iop->task = XGRAVE;
4712 else
4713 e.iop->task = XOTHER;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004714
4715 return;
Eric Andersenff9eee42001-06-29 04:57:14 +00004716}
4717
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004718static struct io *setbase(struct io *ip)
Eric Andersenff9eee42001-06-29 04:57:14 +00004719{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004720 struct io *xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004721
4722 xp = e.iobase;
4723 e.iobase = ip;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004724 return xp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004725}
4726
4727/*
4728 * Input generating functions
4729 */
4730
4731/*
4732 * Produce the characters of a string, then a newline, then EOF.
4733 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004734static int nlchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004735{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004736 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004737
4738 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004739 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004740 if ((c = *ap->aword++) == 0) {
4741 ap->aword = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004742 return '\n';
Eric Andersenff9eee42001-06-29 04:57:14 +00004743 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004744 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004745}
4746
4747/*
4748 * Given a list of words, produce the characters
4749 * in them, with a space after each word.
4750 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004751static int wdchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004752{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004753 char c;
4754 char **wl;
Eric Andersenff9eee42001-06-29 04:57:14 +00004755
4756 if ((wl = ap->awordlist) == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004757 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004758 if (*wl != NULL) {
4759 if ((c = *(*wl)++) != 0)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004760 return c & 0177;
Eric Andersenff9eee42001-06-29 04:57:14 +00004761 ap->awordlist++;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004762 return ' ';
Eric Andersenff9eee42001-06-29 04:57:14 +00004763 }
4764 ap->awordlist = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004765 return '\n';
Eric Andersenff9eee42001-06-29 04:57:14 +00004766}
4767
4768/*
4769 * Return the characters of a list of words,
4770 * producing a space between them.
4771 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004772static int dolchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004773{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004774 char *wp;
Eric Andersenff9eee42001-06-29 04:57:14 +00004775
4776 if ((wp = *ap->awordlist++) != NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004777 PUSHIO(aword, wp, *ap->awordlist == NULL ? strchar : xxchar);
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004778 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00004779 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004780 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004781}
4782
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004783static int xxchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004784{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004785 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004786
4787 if (ap->aword == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004788 return 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004789 if ((c = *ap->aword++) == '\0') {
4790 ap->aword = NULL;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004791 return ' ';
Eric Andersenff9eee42001-06-29 04:57:14 +00004792 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004793 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004794}
4795
4796/*
4797 * Produce the characters from a single word (string).
4798 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004799static int strchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004800{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004801 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004802
4803 if (ap->aword == NULL || (c = *ap->aword++) == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004804 return 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004805 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004806}
4807
4808/*
4809 * Produce quoted characters from a single word (string).
4810 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004811static int qstrchar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004812{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004813 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004814
4815 if (ap->aword == NULL || (c = *ap->aword++) == 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00004816 return 0;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004817 return c | QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00004818}
4819
4820/*
4821 * Return the characters from a file.
4822 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004823static int filechar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004824{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004825 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004826 char c;
4827 struct iobuf *bp = ap->afbuf;
4828
4829 if (ap->afid != AFID_NOBUF) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004830 if ((i = ap->afid != bp->id) || bp->bufp == bp->ebufp) {
Eric Andersen12de6cf2004-08-04 19:19:10 +00004831
Eric Andersen8401eea2004-08-04 19:16:54 +00004832 if (i)
Denis Vlasenkoea620772006-10-14 02:23:43 +00004833 lseek(ap->afile, ap->afpos, SEEK_SET);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004834
Eric Andersen8401eea2004-08-04 19:16:54 +00004835 i = safe_read(ap->afile, bp->buf, sizeof(bp->buf));
Eric Andersen12de6cf2004-08-04 19:19:10 +00004836
Eric Andersen8401eea2004-08-04 19:16:54 +00004837 if (i <= 0) {
4838 closef(ap->afile);
4839 return 0;
4840 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004841
Eric Andersen8401eea2004-08-04 19:16:54 +00004842 bp->id = ap->afid;
4843 bp->ebufp = (bp->bufp = bp->buf) + i;
4844 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004845
Eric Andersen8401eea2004-08-04 19:16:54 +00004846 ap->afpos++;
4847 return *bp->bufp++ & 0177;
Eric Andersenff9eee42001-06-29 04:57:14 +00004848 }
Eric Andersenbdfd0d72001-10-24 05:00:29 +00004849#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersen737f5fb2003-03-14 16:05:59 +00004850 if (interactive && isatty(ap->afile)) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004851 static char mycommand[BUFSIZ];
4852 static int position = 0, size = 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004853
Eric Andersen8401eea2004-08-04 19:16:54 +00004854 while (size == 0 || position >= size) {
4855 cmdedit_read_input(current_prompt, mycommand);
4856 size = strlen(mycommand);
4857 position = 0;
4858 }
4859 c = mycommand[position];
4860 position++;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004861 return c;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00004862 } else
Eric Andersenff9eee42001-06-29 04:57:14 +00004863#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00004864
Eric Andersenff9eee42001-06-29 04:57:14 +00004865 {
Eric Andersen7467c8d2001-07-12 20:26:32 +00004866 i = safe_read(ap->afile, &c, sizeof(c));
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004867 return i == sizeof(c) ? (c & 0x7f) : (closef(ap->afile), 0);
Eric Andersenff9eee42001-06-29 04:57:14 +00004868 }
4869}
4870
4871/*
4872 * Return the characters from a here temp file.
4873 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004874static int herechar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004875{
4876 char c;
4877
4878
4879 if (read(ap->afile, &c, sizeof(c)) != sizeof(c)) {
4880 close(ap->afile);
4881 c = 0;
4882 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004883 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004884
4885}
4886
4887/*
4888 * Return the characters produced by a process (`...`).
4889 * Quote them if required, and remove any trailing newline characters.
4890 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004891static int gravechar(struct ioarg *ap, struct io *iop)
Eric Andersenff9eee42001-06-29 04:57:14 +00004892{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004893 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004894
Eric Andersen8401eea2004-08-04 19:16:54 +00004895 if ((c = qgravechar(ap, iop) & ~QUOTE) == '\n')
Eric Andersenff9eee42001-06-29 04:57:14 +00004896 c = ' ';
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004897 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004898}
4899
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004900static int qgravechar(struct ioarg *ap, struct io *iop)
Eric Andersenff9eee42001-06-29 04:57:14 +00004901{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004902 int c;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004903
Mike Frysinger02d8fa42006-05-05 20:32:31 +00004904 DBGPRINTF3(("QGRAVECHAR: enter, ap=%p, iop=%p\n", ap, iop));
Eric Andersenff9eee42001-06-29 04:57:14 +00004905
4906 if (iop->xchar) {
4907 if (iop->nlcount) {
4908 iop->nlcount--;
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004909 return '\n' | QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00004910 }
4911 c = iop->xchar;
4912 iop->xchar = 0;
4913 } else if ((c = filechar(ap)) == '\n') {
4914 iop->nlcount = 1;
4915 while ((c = filechar(ap)) == '\n')
4916 iop->nlcount++;
4917 iop->xchar = c;
4918 if (c == 0)
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004919 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004920 iop->nlcount--;
4921 c = '\n';
4922 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004923 return c != 0 ? c | QUOTE : 0;
Eric Andersenff9eee42001-06-29 04:57:14 +00004924}
4925
4926/*
4927 * Return a single command (usually the first line) from a file.
4928 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004929static int linechar(struct ioarg *ap)
Eric Andersenff9eee42001-06-29 04:57:14 +00004930{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004931 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004932
4933 if ((c = filechar(ap)) == '\n') {
4934 if (!multiline) {
4935 closef(ap->afile);
Eric Andersen8401eea2004-08-04 19:16:54 +00004936 ap->afile = -1; /* illegal value */
Eric Andersenff9eee42001-06-29 04:57:14 +00004937 }
4938 }
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004939 return c;
Eric Andersenff9eee42001-06-29 04:57:14 +00004940}
4941
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004942static void prs(const char *s)
Eric Andersenff9eee42001-06-29 04:57:14 +00004943{
4944 if (*s)
4945 write(2, s, strlen(s));
4946}
4947
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004948static void prn(unsigned u)
Eric Andersenff9eee42001-06-29 04:57:14 +00004949{
Eric Andersen737f5fb2003-03-14 16:05:59 +00004950 prs(itoa(u));
Eric Andersenff9eee42001-06-29 04:57:14 +00004951}
4952
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004953static void closef(int i)
Eric Andersenff9eee42001-06-29 04:57:14 +00004954{
4955 if (i > 2)
4956 close(i);
4957}
4958
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00004959static void closeall(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00004960{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004961 int u;
Eric Andersenff9eee42001-06-29 04:57:14 +00004962
Eric Andersen8401eea2004-08-04 19:16:54 +00004963 for (u = NUFILE; u < NOFILE;)
Eric Andersenff9eee42001-06-29 04:57:14 +00004964 close(u++);
4965}
4966
Eric Andersen12de6cf2004-08-04 19:19:10 +00004967
Eric Andersenff9eee42001-06-29 04:57:14 +00004968/*
4969 * remap fd into Shell's fd space
4970 */
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004971static int remap(int fd)
Eric Andersenff9eee42001-06-29 04:57:14 +00004972{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00004973 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00004974 int map[NOFILE];
Eric Andersen12de6cf2004-08-04 19:19:10 +00004975 int newfd;
4976
4977
4978 DBGPRINTF(("REMAP: fd=%d, e.iofd=%d\n", fd, e.iofd));
Eric Andersenff9eee42001-06-29 04:57:14 +00004979
4980 if (fd < e.iofd) {
Eric Andersen8401eea2004-08-04 19:16:54 +00004981 for (i = 0; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004982 map[i] = 0;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004983
Eric Andersenff9eee42001-06-29 04:57:14 +00004984 do {
4985 map[fd] = 1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00004986 newfd = dup(fd);
4987 fd = newfd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004988 } while (fd >= 0 && fd < e.iofd);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004989
Eric Andersen8401eea2004-08-04 19:16:54 +00004990 for (i = 0; i < NOFILE; i++)
Eric Andersenff9eee42001-06-29 04:57:14 +00004991 if (map[i])
4992 close(i);
Eric Andersen12de6cf2004-08-04 19:19:10 +00004993
Eric Andersenff9eee42001-06-29 04:57:14 +00004994 if (fd < 0)
4995 err("too many files open in shell");
4996 }
Eric Andersen12de6cf2004-08-04 19:19:10 +00004997
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00004998 return fd;
Eric Andersenff9eee42001-06-29 04:57:14 +00004999}
5000
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005001static int openpipe(int *pv)
Eric Andersenff9eee42001-06-29 04:57:14 +00005002{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005003 int i;
Eric Andersenff9eee42001-06-29 04:57:14 +00005004
5005 if ((i = pipe(pv)) < 0)
5006 err("can't create pipe - try again");
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00005007 return i;
Eric Andersenff9eee42001-06-29 04:57:14 +00005008}
5009
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005010static void closepipe(int *pv)
Eric Andersenff9eee42001-06-29 04:57:14 +00005011{
5012 if (pv != NULL) {
5013 close(*pv++);
5014 close(*pv);
5015 }
5016}
5017
5018/* -------- here.c -------- */
5019
5020/*
5021 * here documents
5022 */
5023
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005024static void markhere(char *s, struct ioword *iop)
Eric Andersenff9eee42001-06-29 04:57:14 +00005025{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005026 struct here *h, *lh;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005027
Mike Frysinger02d8fa42006-05-05 20:32:31 +00005028 DBGPRINTF7(("MARKHERE: enter, s=%p\n", s));
Eric Andersenff9eee42001-06-29 04:57:14 +00005029
5030 h = (struct here *) space(sizeof(struct here));
5031 if (h == 0)
5032 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005033
Eric Andersenff9eee42001-06-29 04:57:14 +00005034 h->h_tag = evalstr(s, DOSUB);
5035 if (h->h_tag == 0)
5036 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005037
Eric Andersenff9eee42001-06-29 04:57:14 +00005038 h->h_iop = iop;
5039 iop->io_name = 0;
5040 h->h_next = NULL;
5041 if (inhere == 0)
5042 inhere = h;
5043 else
Eric Andersen8401eea2004-08-04 19:16:54 +00005044 for (lh = inhere; lh != NULL; lh = lh->h_next)
Eric Andersenff9eee42001-06-29 04:57:14 +00005045 if (lh->h_next == 0) {
5046 lh->h_next = h;
5047 break;
5048 }
Eric Andersen8401eea2004-08-04 19:16:54 +00005049 iop->io_flag |= IOHERE | IOXHERE;
Eric Andersenff9eee42001-06-29 04:57:14 +00005050 for (s = h->h_tag; *s; s++)
5051 if (*s & QUOTE) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005052 iop->io_flag &= ~IOXHERE;
5053 *s &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00005054 }
5055 h->h_dosub = iop->io_flag & IOXHERE;
5056}
5057
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005058static void gethere(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00005059{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005060 struct here *h, *hp;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005061
5062 DBGPRINTF7(("GETHERE: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00005063
5064 /* Scan here files first leaving inhere list in place */
5065 for (hp = h = inhere; h != NULL; hp = h, h = h->h_next)
Eric Andersen8401eea2004-08-04 19:16:54 +00005066 readhere(&h->h_iop->io_name, h->h_tag, h->h_dosub ? 0 : '\'');
Eric Andersenff9eee42001-06-29 04:57:14 +00005067
5068 /* Make inhere list active - keep list intact for scraphere */
5069 if (hp != NULL) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005070 hp->h_next = acthere;
5071 acthere = inhere;
5072 inhere = NULL;
Eric Andersenff9eee42001-06-29 04:57:14 +00005073 }
5074}
5075
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005076static void readhere(char **name, char *s, int ec)
Eric Andersenff9eee42001-06-29 04:57:14 +00005077{
5078 int tf;
5079 char tname[30] = ".msh_XXXXXX";
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005080 int c;
Eric Andersenff9eee42001-06-29 04:57:14 +00005081 jmp_buf ev;
Eric Andersen8401eea2004-08-04 19:16:54 +00005082 char myline[LINELIM + 1];
Eric Andersenff9eee42001-06-29 04:57:14 +00005083 char *thenext;
5084
Mike Frysinger02d8fa42006-05-05 20:32:31 +00005085 DBGPRINTF7(("READHERE: enter, name=%p, s=%p\n", name, s));
Eric Andersen12de6cf2004-08-04 19:19:10 +00005086
Eric Andersenff9eee42001-06-29 04:57:14 +00005087 tf = mkstemp(tname);
5088 if (tf < 0)
5089 return;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005090
Eric Andersenff9eee42001-06-29 04:57:14 +00005091 *name = strsave(tname, areanum);
5092 if (newenv(setjmp(errpt = ev)) != 0)
5093 unlink(tname);
5094 else {
Eric Andersen8401eea2004-08-04 19:16:54 +00005095 pushio(e.iop->argp, (int (*)(struct ioarg *)) e.iop->iofn);
Eric Andersenff9eee42001-06-29 04:57:14 +00005096 e.iobase = e.iop;
5097 for (;;) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005098 if (interactive && e.iop <= iostack) {
Eric Andersenbdfd0d72001-10-24 05:00:29 +00005099#ifdef CONFIG_FEATURE_COMMAND_EDITING
Eric Andersen8401eea2004-08-04 19:16:54 +00005100 current_prompt = cprompt->value;
Eric Andersenff9eee42001-06-29 04:57:14 +00005101#else
Eric Andersen8401eea2004-08-04 19:16:54 +00005102 prs(cprompt->value);
Eric Andersenff9eee42001-06-29 04:57:14 +00005103#endif
5104 }
5105 thenext = myline;
5106 while ((c = my_getc(ec)) != '\n' && c) {
5107 if (ec == '\'')
Eric Andersen8401eea2004-08-04 19:16:54 +00005108 c &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00005109 if (thenext >= &myline[LINELIM]) {
5110 c = 0;
5111 break;
5112 }
5113 *thenext++ = c;
5114 }
5115 *thenext = 0;
5116 if (strcmp(s, myline) == 0 || c == 0)
5117 break;
5118 *thenext++ = '\n';
Eric Andersen8401eea2004-08-04 19:16:54 +00005119 write(tf, myline, (int) (thenext - myline));
Eric Andersenff9eee42001-06-29 04:57:14 +00005120 }
5121 if (c == 0) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005122 prs("here document `");
5123 prs(s);
5124 err("' unclosed");
Eric Andersenff9eee42001-06-29 04:57:14 +00005125 }
5126 quitenv();
5127 }
5128 close(tf);
5129}
5130
5131/*
5132 * open here temp file.
5133 * if unquoted here, expand here temp file into second temp file.
5134 */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005135static int herein(char *hname, int xdoll)
Eric Andersenff9eee42001-06-29 04:57:14 +00005136{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005137 int hf;
Eric Andersenff9eee42001-06-29 04:57:14 +00005138 int tf;
5139
5140#if __GNUC__
5141 /* Avoid longjmp clobbering */
5142 (void) &tf;
5143#endif
Eric Andersen12de6cf2004-08-04 19:19:10 +00005144 if (hname == NULL)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00005145 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005146
5147 DBGPRINTF7(("HEREIN: hname is %s, xdoll=%d\n", hname, xdoll));
5148
Eric Andersenff9eee42001-06-29 04:57:14 +00005149 hf = open(hname, 0);
5150 if (hf < 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00005151 return -1;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005152
Eric Andersenff9eee42001-06-29 04:57:14 +00005153 if (xdoll) {
5154 char c;
5155 char tname[30] = ".msh_XXXXXX";
5156 jmp_buf ev;
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005157
Eric Andersenff9eee42001-06-29 04:57:14 +00005158 tf = mkstemp(tname);
5159 if (tf < 0)
Denis Vlasenko079f8af2006-11-27 16:49:31 +00005160 return -1;
Eric Andersenff9eee42001-06-29 04:57:14 +00005161 if (newenv(setjmp(errpt = ev)) == 0) {
5162 PUSHIO(afile, hf, herechar);
5163 setbase(e.iop);
5164 while ((c = subgetc(0, 0)) != 0) {
Eric Andersen8401eea2004-08-04 19:16:54 +00005165 c &= ~QUOTE;
Eric Andersenff9eee42001-06-29 04:57:14 +00005166 write(tf, &c, sizeof c);
5167 }
5168 quitenv();
5169 } else
5170 unlink(tname);
5171 close(tf);
5172 tf = open(tname, 0);
5173 unlink(tname);
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00005174 return tf;
Eric Andersenff9eee42001-06-29 04:57:14 +00005175 } else
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00005176 return hf;
Eric Andersenff9eee42001-06-29 04:57:14 +00005177}
5178
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005179static void scraphere(void)
Eric Andersenff9eee42001-06-29 04:57:14 +00005180{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005181 struct here *h;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005182
5183 DBGPRINTF7(("SCRAPHERE: enter...\n"));
Eric Andersenff9eee42001-06-29 04:57:14 +00005184
5185 for (h = inhere; h != NULL; h = h->h_next) {
5186 if (h->h_iop && h->h_iop->io_name)
Eric Andersen8401eea2004-08-04 19:16:54 +00005187 unlink(h->h_iop->io_name);
Eric Andersenff9eee42001-06-29 04:57:14 +00005188 }
5189 inhere = NULL;
5190}
5191
5192/* unlink here temp files before a freearea(area) */
Bernhard Reutner-Fischerf0877982006-06-25 22:08:53 +00005193static void freehere(int area)
Eric Andersenff9eee42001-06-29 04:57:14 +00005194{
"Robert P. J. Day"68229832006-07-01 13:08:46 +00005195 struct here *h, *hl;
Eric Andersen12de6cf2004-08-04 19:19:10 +00005196
5197 DBGPRINTF6(("FREEHERE: enter, area=%d\n", area));
Eric Andersenff9eee42001-06-29 04:57:14 +00005198
5199 hl = NULL;
5200 for (h = acthere; h != NULL; h = h->h_next)
5201 if (getarea((char *) h) >= area) {
5202 if (h->h_iop->io_name != NULL)
5203 unlink(h->h_iop->io_name);
5204 if (hl == NULL)
5205 acthere = h->h_next;
5206 else
5207 hl->h_next = h->h_next;
5208 } else
5209 hl = h;
5210}
5211
5212
5213
5214/*
5215 * Copyright (c) 1987,1997, Prentice Hall
5216 * All rights reserved.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005217 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005218 * Redistribution and use of the MINIX operating system in source and
5219 * binary forms, with or without modification, are permitted provided
5220 * that the following conditions are met:
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005221 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005222 * Redistributions of source code must retain the above copyright
5223 * notice, this list of conditions and the following disclaimer.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005224 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005225 * Redistributions in binary form must reproduce the above
5226 * copyright notice, this list of conditions and the following
5227 * disclaimer in the documentation and/or other materials provided
5228 * with the distribution.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005229 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005230 * Neither the name of Prentice Hall nor the names of the software
5231 * authors or contributors may be used to endorse or promote
5232 * products derived from this software without specific prior
5233 * written permission.
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005234 *
Eric Andersenff9eee42001-06-29 04:57:14 +00005235 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND
5236 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
5237 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
5238 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
5239 * IN NO EVENT SHALL PRENTICE HALL OR ANY AUTHORS OR CONTRIBUTORS BE
5240 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
5241 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
5242 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
5243 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
5244 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
5245 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
5246 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5247 *
5248 */