aboutsummaryrefslogtreecommitdiff
path: root/busybox/shell/msh.c
diff options
context:
space:
mode:
Diffstat (limited to 'busybox/shell/msh.c')
-rw-r--r--busybox/shell/msh.c5487
1 files changed, 5487 insertions, 0 deletions
diff --git a/busybox/shell/msh.c b/busybox/shell/msh.c
new file mode 100644
index 000000000..2fb0df739
--- /dev/null
+++ b/busybox/shell/msh.c
@@ -0,0 +1,5487 @@
1/* 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
6 * by Erik Andersen <andersen@codepoet.org>
7 *
8 * - backtick expansion did not work properly
9 * Jonas Holmberg <jonas.holmberg@axis.com>
10 * Robert Schwebel <r.schwebel@pengutronix.de>
11 * Erik Andersen <andersen@codepoet.org>
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 *
27 * Original copyright notice is retained at the end of this file.
28 */
29
30#include <ctype.h>
31#include <dirent.h>
32#include <errno.h>
33#include <fcntl.h>
34#include <limits.h>
35#include <setjmp.h>
36#include <signal.h>
37#include <stddef.h>
38#include <stdio.h>
39#include <stdlib.h>
40#include <string.h>
41#include <time.h>
42#include <unistd.h>
43#include <sys/stat.h>
44#include <sys/times.h>
45#include <sys/types.h>
46#include <sys/wait.h>
47
48#include "cmdedit.h"
49#include "busybox.h"
50
51
52/* Conditional use of "register" keyword */
53#define REGISTER register
54
55
56/*#define MSHDEBUG 1*/
57
58#ifdef MSHDEBUG
59int mshdbg = 0;
60
61#define DBGPRINTF(x) if(mshdbg>0)printf x
62#define DBGPRINTF0(x) if(mshdbg>0)printf x
63#define DBGPRINTF1(x) if(mshdbg>1)printf x
64#define DBGPRINTF2(x) if(mshdbg>2)printf x
65#define DBGPRINTF3(x) if(mshdbg>3)printf x
66#define DBGPRINTF4(x) if(mshdbg>4)printf x
67#define DBGPRINTF5(x) if(mshdbg>5)printf x
68#define DBGPRINTF6(x) if(mshdbg>6)printf x
69#define DBGPRINTF7(x) if(mshdbg>7)printf x
70#define DBGPRINTF8(x) if(mshdbg>8)printf x
71#define DBGPRINTF9(x) if(mshdbg>9)printf x
72
73int mshdbg_rc = 0;
74
75#define RCPRINTF(x) if(mshdbg_rc)printf x
76
77#else
78
79#define DBGPRINTF(x)
80#define DBGPRINTF0(x)
81#define DBGPRINTF1(x)
82#define DBGPRINTF2(x)
83#define DBGPRINTF3(x)
84#define DBGPRINTF4(x)
85#define DBGPRINTF5(x)
86#define DBGPRINTF6(x)
87#define DBGPRINTF7(x)
88#define DBGPRINTF8(x)
89#define DBGPRINTF9(x)
90
91#define RCPRINTF(x)
92
93#endif /* MSHDEBUG */
94
95
96/* -------- sh.h -------- */
97/*
98 * shell
99 */
100
101#define LINELIM 2100
102#define NPUSH 8 /* limit to input nesting */
103
104#undef NOFILE
105#define NOFILE 20 /* Number of open files */
106#define NUFILE 10 /* Number of user-accessible files */
107#define FDBASE 10 /* First file usable by Shell */
108
109/*
110 * values returned by wait
111 */
112#define WAITSIG(s) ((s)&0177)
113#define WAITVAL(s) (((s)>>8)&0377)
114#define WAITCORE(s) (((s)&0200)!=0)
115
116/*
117 * library and system definitions
118 */
119typedef void xint; /* base type of jmp_buf, for not broken compilers */
120
121/*
122 * shell components
123 */
124
125#define QUOTE 0200
126
127#define NOBLOCK ((struct op *)NULL)
128#define NOWORD ((char *)NULL)
129#define NOWORDS ((char **)NULL)
130#define NOPIPE ((int *)NULL)
131
132/*
133 * Description of a command or an operation on commands.
134 * Might eventually use a union.
135 */
136struct op {
137 int type; /* operation type, see below */
138 char **words; /* arguments to a command */
139 struct ioword **ioact; /* IO actions (eg, < > >>) */
140 struct op *left;
141 struct op *right;
142 char *str; /* identifier for case and for */
143};
144
145#define TCOM 1 /* command */
146#define TPAREN 2 /* (c-list) */
147#define TPIPE 3 /* a | b */
148#define TLIST 4 /* a [&;] b */
149#define TOR 5 /* || */
150#define TAND 6 /* && */
151#define TFOR 7
152#define TDO 8
153#define TCASE 9
154#define TIF 10
155#define TWHILE 11
156#define TUNTIL 12
157#define TELIF 13
158#define TPAT 14 /* pattern in case */
159#define TBRACE 15 /* {c-list} */
160#define TASYNC 16 /* c & */
161/* Added to support "." file expansion */
162#define TDOT 17
163
164/* Strings for names to make debug easier */
165char *T_CMD_NAMES[] = {
166 "PLACEHOLDER",
167 "TCOM",
168 "TPAREN",
169 "TPIPE",
170 "TLIST",
171 "TOR",
172 "TAND",
173 "TFOR",
174 "TDO",
175 "TCASE",
176 "TIF",
177 "TWHILE",
178 "TUNTIL",
179 "TELIF",
180 "TPAT",
181 "TBRACE",
182 "TASYNC",
183 "TDOT",
184};
185
186
187/*
188 * actions determining the environment of a process
189 */
190#define BIT(i) (1<<(i))
191#define FEXEC BIT(0) /* execute without forking */
192
193#if 0 /* Original value */
194#define AREASIZE (65000)
195#else
196#define AREASIZE (90000)
197#endif
198
199/*
200 * flags to control evaluation of words
201 */
202#define DOSUB 1 /* interpret $, `, and quotes */
203#define DOBLANK 2 /* perform blank interpretation */
204#define DOGLOB 4 /* interpret [?* */
205#define DOKEY 8 /* move words with `=' to 2nd arg. list */
206#define DOTRIM 16 /* trim resulting string */
207
208#define DOALL (DOSUB|DOBLANK|DOGLOB|DOKEY|DOTRIM)
209
210
211/* PROTOTYPES */
212static int newfile(char *s);
213static char *findeq(char *cp);
214static char *cclass(char *p, int sub);
215static void initarea(void);
216extern int msh_main(int argc, char **argv);
217
218
219struct brkcon {
220 jmp_buf brkpt;
221 struct brkcon *nextlev;
222};
223
224
225/*
226 * redirection
227 */
228struct ioword {
229 short io_unit; /* unit affected */
230 short io_flag; /* action (below) */
231 char *io_name; /* file name */
232};
233
234#define IOREAD 1 /* < */
235#define IOHERE 2 /* << (here file) */
236#define IOWRITE 4 /* > */
237#define IOCAT 8 /* >> */
238#define IOXHERE 16 /* ${}, ` in << */
239#define IODUP 32 /* >&digit */
240#define IOCLOSE 64 /* >&- */
241
242#define IODEFAULT (-1) /* token for default IO unit */
243
244
245
246/*
247 * parsing & execution environment
248 */
249static struct env {
250 char *linep;
251 struct io *iobase;
252 struct io *iop;
253 xint *errpt; /* void * */
254 int iofd;
255 struct env *oenv;
256} e;
257
258/*
259 * flags:
260 * -e: quit on error
261 * -k: look for name=value everywhere on command line
262 * -n: no execution
263 * -t: exit after reading and executing one command
264 * -v: echo as read
265 * -x: trace
266 * -u: unset variables net diagnostic
267 */
268static char *flag;
269
270static char *null; /* null value for variable */
271static int intr; /* interrupt pending */
272
273static char *trap[_NSIG + 1];
274static char ourtrap[_NSIG + 1];
275static int trapset; /* trap pending */
276
277static int heedint; /* heed interrupt signals */
278
279static int yynerrs; /* yacc */
280
281static char line[LINELIM];
282static char *elinep;
283
284
285/*
286 * other functions
287 */
288static int (*inbuilt(char *s)) (struct op *);
289
290static char *rexecve(char *c, char **v, char **envp);
291static char *space(int n);
292static char *strsave(char *s, int a);
293static char *evalstr(char *cp, int f);
294static char *putn(int n);
295static char *itoa(int n);
296static char *unquote(char *as);
297static struct var *lookup(char *n);
298static int rlookup(char *n);
299static struct wdblock *glob(char *cp, struct wdblock *wb);
300static int my_getc(int ec);
301static int subgetc(int ec, int quoted);
302static char **makenv(int all, struct wdblock *wb);
303static char **eval(char **ap, int f);
304static int setstatus(int s);
305static int waitfor(int lastpid, int canintr);
306
307static void onintr(int s); /* SIGINT handler */
308
309static int newenv(int f);
310static void quitenv(void);
311static void err(char *s);
312static int anys(char *s1, char *s2);
313static int any(int c, char *s);
314static void next(int f);
315static void setdash(void);
316static void onecommand(void);
317static void runtrap(int i);
318static int gmatch(char *s, char *p);
319
320
321/*
322 * error handling
323 */
324static void leave(void); /* abort shell (or fail in subshell) */
325static void fail(void); /* fail but return to process next command */
326static void warn(char *s);
327static void sig(int i); /* default signal handler */
328
329
330
331/* -------- area stuff -------- */
332
333#define REGSIZE sizeof(struct region)
334#define GROWBY (256)
335/* #define SHRINKBY (64) */
336#undef SHRINKBY
337#define FREE (32767)
338#define BUSY (0)
339#define ALIGN (sizeof(int)-1)
340
341
342struct region {
343 struct region *next;
344 int area;
345};
346
347
348
349/* -------- grammar stuff -------- */
350typedef union {
351 char *cp;
352 char **wp;
353 int i;
354 struct op *o;
355} YYSTYPE;
356
357#define WORD 256
358#define LOGAND 257
359#define LOGOR 258
360#define BREAK 259
361#define IF 260
362#define THEN 261
363#define ELSE 262
364#define ELIF 263
365#define FI 264
366#define CASE 265
367#define ESAC 266
368#define FOR 267
369#define WHILE 268
370#define UNTIL 269
371#define DO 270
372#define DONE 271
373#define IN 272
374/* Added for "." file expansion */
375#define DOT 273
376
377#define YYERRCODE 300
378
379/* flags to yylex */
380#define CONTIN 01 /* skip new lines to complete command */
381
382#define SYNTAXERR zzerr()
383
384static struct op *pipeline(int cf);
385static struct op *andor(void);
386static struct op *c_list(void);
387static int synio(int cf);
388static void musthave(int c, int cf);
389static struct op *simple(void);
390static struct op *nested(int type, int mark);
391static struct op *command(int cf);
392static struct op *dogroup(int onlydone);
393static struct op *thenpart(void);
394static struct op *elsepart(void);
395static struct op *caselist(void);
396static struct op *casepart(void);
397static char **pattern(void);
398static char **wordlist(void);
399static struct op *list(struct op *t1, struct op *t2);
400static struct op *block(int type, struct op *t1, struct op *t2, char **wp);
401static struct op *newtp(void);
402static struct op *namelist(struct op *t);
403static char **copyw(void);
404static void word(char *cp);
405static struct ioword **copyio(void);
406static struct ioword *io(int u, int f, char *cp);
407static void zzerr(void);
408static void yyerror(char *s);
409static int yylex(int cf);
410static int collect(int c, int c1);
411static int dual(int c);
412static void diag(int ec);
413static char *tree(unsigned size);
414
415/* -------- var.h -------- */
416
417struct var {
418 char *value;
419 char *name;
420 struct var *next;
421 char status;
422};
423
424#define COPYV 1 /* flag to setval, suggesting copy */
425#define RONLY 01 /* variable is read-only */
426#define EXPORT 02 /* variable is to be exported */
427#define GETCELL 04 /* name & value space was got with getcell */
428
429static int yyparse(void);
430static struct var *lookup(char *n);
431static void setval(struct var *vp, char *val);
432static void nameval(struct var *vp, char *val, char *name);
433static void export(struct var *vp);
434static void ronly(struct var *vp);
435static int isassign(char *s);
436static int checkname(char *cp);
437static int assign(char *s, int cf);
438static void putvlist(int f, int out);
439static int eqname(char *n1, char *n2);
440
441static int execute(struct op *t, int *pin, int *pout, int act);
442
443
444/* -------- io.h -------- */
445/* io buffer */
446struct iobuf {
447 unsigned id; /* buffer id */
448 char buf[512]; /* buffer */
449 char *bufp; /* pointer into buffer */
450 char *ebufp; /* pointer to end of buffer */
451};
452
453/* possible arguments to an IO function */
454struct ioarg {
455 char *aword;
456 char **awordlist;
457 int afile; /* file descriptor */
458 unsigned afid; /* buffer id */
459 long afpos; /* file position */
460 struct iobuf *afbuf; /* buffer for this file */
461};
462
463//static struct ioarg ioargstack[NPUSH];
464#define AFID_NOBUF (~0)
465#define AFID_ID 0
466
467/* an input generator's state */
468struct io {
469 int (*iofn) (struct ioarg *, struct io *);
470 struct ioarg *argp;
471 int peekc;
472 char prev; /* previous character read by readc() */
473 char nlcount; /* for `'s */
474 char xchar; /* for `'s */
475 char task; /* reason for pushed IO */
476};
477
478//static struct io iostack[NPUSH];
479#define XOTHER 0 /* none of the below */
480#define XDOLL 1 /* expanding ${} */
481#define XGRAVE 2 /* expanding `'s */
482#define XIO 3 /* file IO */
483
484/* in substitution */
485#define INSUB() (e.iop->task == XGRAVE || e.iop->task == XDOLL)
486
487
488/*
489 * input generators for IO structure
490 */
491static int nlchar(struct ioarg *ap);
492static int strchar(struct ioarg *ap);
493static int qstrchar(struct ioarg *ap);
494static int filechar(struct ioarg *ap);
495static int herechar(struct ioarg *ap);
496static int linechar(struct ioarg *ap);
497static int gravechar(struct ioarg *ap, struct io *iop);
498static int qgravechar(struct ioarg *ap, struct io *iop);
499static int dolchar(struct ioarg *ap);
500static int wdchar(struct ioarg *ap);
501static void scraphere(void);
502static void freehere(int area);
503static void gethere(void);
504static void markhere(char *s, struct ioword *iop);
505static int herein(char *hname, int xdoll);
506static int run(struct ioarg *argp, int (*f) (struct ioarg *));
507
508
509/*
510 * IO functions
511 */
512static int eofc(void);
513static int readc(void);
514static void unget(int c);
515static void ioecho(int c);
516static void prs(char *s);
517static void prn(unsigned u);
518static void closef(int i);
519static void closeall(void);
520
521
522/*
523 * IO control
524 */
525static void pushio(struct ioarg *argp, int (*f) (struct ioarg *));
526static int remap(int fd);
527static int openpipe(int *pv);
528static void closepipe(int *pv);
529static struct io *setbase(struct io *ip);
530
531#define PUSHIO(what,arg,gen) ((temparg.what = (arg)),pushio(&temparg,(gen)))
532#define RUN(what,arg,gen) ((temparg.what = (arg)), run(&temparg,(gen)))
533
534/* -------- word.h -------- */
535
536#define NSTART 16 /* default number of words to allow for initially */
537
538struct wdblock {
539 short w_bsize;
540 short w_nword;
541 /* bounds are arbitrary */
542 char *w_words[1];
543};
544
545static struct wdblock *addword(char *wd, struct wdblock *wb);
546static struct wdblock *newword(int nw);
547static char **getwords(struct wdblock *wb);
548
549/* -------- area.h -------- */
550
551/*
552 * storage allocation
553 */
554static char *getcell(unsigned nbytes);
555static void garbage(void);
556static void setarea(char *cp, int a);
557static int getarea(char *cp);
558static void freearea(int a);
559static void freecell(char *cp);
560static int areanum; /* current allocation area */
561
562#define NEW(type) (type *)getcell(sizeof(type))
563#define DELETE(obj) freecell((char *)obj)
564
565
566/* -------- misc stuff -------- */
567
568static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp);
569static int iosetup(struct ioword *iop, int pipein, int pipeout);
570static void echo(char **wp);
571static struct op **find1case(struct op *t, char *w);
572static struct op *findcase(struct op *t, char *w);
573static void brkset(struct brkcon *bc);
574static int dolabel(struct op *t);
575static int dohelp(struct op *t);
576static int dochdir(struct op *t);
577static int doshift(struct op *t);
578static int dologin(struct op *t);
579static int doumask(struct op *t);
580static int doexec(struct op *t);
581static int dodot(struct op *t);
582static int dowait(struct op *t);
583static int doread(struct op *t);
584static int doeval(struct op *t);
585static int dotrap(struct op *t);
586static int getsig(char *s);
587static void setsig(int n, sighandler_t f);
588static int getn(char *as);
589static int dobreak(struct op *t);
590static int docontinue(struct op *t);
591static int brkcontin(char *cp, int val);
592static int doexit(struct op *t);
593static int doexport(struct op *t);
594static int doreadonly(struct op *t);
595static void rdexp(char **wp, void (*f) (struct var *), int key);
596static void badid(char *s);
597static int doset(struct op *t);
598static void varput(char *s, int out);
599static int dotimes(struct op *t);
600static int expand(char *cp, struct wdblock **wbp, int f);
601static char *blank(int f);
602static int dollar(int quoted);
603static int grave(int quoted);
604static void globname(char *we, char *pp);
605static char *generate(char *start1, char *end1, char *middle, char *end);
606static int anyspcl(struct wdblock *wb);
607static int xstrcmp(char *p1, char *p2);
608static void glob0(char *a0, unsigned int a1, int a2,
609 int (*a3) (char *, char *));
610static void glob1(char *base, char *lim);
611static void glob2(char *i, char *j);
612static void glob3(char *i, char *j, char *k);
613static void readhere(char **name, char *s, int ec);
614static void pushio(struct ioarg *argp, int (*f) (struct ioarg *));
615static int xxchar(struct ioarg *ap);
616
617struct here {
618 char *h_tag;
619 int h_dosub;
620 struct ioword *h_iop;
621 struct here *h_next;
622};
623
624static char *signame[] = {
625 "Signal 0",
626 "Hangup",
627 (char *) NULL, /* interrupt */
628 "Quit",
629 "Illegal instruction",
630 "Trace/BPT trap",
631 "Abort",
632 "Bus error",
633 "Floating Point Exception",
634 "Killed",
635 "SIGUSR1",
636 "SIGSEGV",
637 "SIGUSR2",
638 (char *) NULL, /* broken pipe */
639 "Alarm clock",
640 "Terminated",
641};
642
643#define NSIGNAL (sizeof(signame)/sizeof(signame[0]))
644
645struct res {
646 char *r_name;
647 int r_val;
648};
649static struct res restab[] = {
650 {"for", FOR},
651 {"case", CASE},
652 {"esac", ESAC},
653 {"while", WHILE},
654 {"do", DO},
655 {"done", DONE},
656 {"if", IF},
657 {"in", IN},
658 {"then", THEN},
659 {"else", ELSE},
660 {"elif", ELIF},
661 {"until", UNTIL},
662 {"fi", FI},
663 {";;", BREAK},
664 {"||", LOGOR},
665 {"&&", LOGAND},
666 {"{", '{'},
667 {"}", '}'},
668 {".", DOT},
669 {0, 0},
670};
671
672
673struct builtincmd {
674 const char *name;
675 int (*builtinfunc) (struct op * t);
676};
677static const struct builtincmd builtincmds[] = {
678 {".", dodot},
679 {":", dolabel},
680 {"break", dobreak},
681 {"cd", dochdir},
682 {"continue", docontinue},
683 {"eval", doeval},
684 {"exec", doexec},
685 {"exit", doexit},
686 {"export", doexport},
687 {"help", dohelp},
688 {"login", dologin},
689 {"newgrp", dologin},
690 {"read", doread},
691 {"readonly", doreadonly},
692 {"set", doset},
693 {"shift", doshift},
694 {"times", dotimes},
695 {"trap", dotrap},
696 {"umask", doumask},
697 {"wait", dowait},
698 {0, 0}
699};
700
701struct op *scantree(struct op *);
702static struct op *dowholefile(int, int);
703
704/* Globals */
705extern char **environ; /* environment pointer */
706
707static char **dolv;
708static int dolc;
709static int exstat;
710static char gflg;
711static int interactive = 0; /* Is this an interactive shell */
712static int execflg;
713static int multiline; /* \n changed to ; */
714static struct op *outtree; /* result from parser */
715static xint *failpt;
716static xint *errpt;
717static struct brkcon *brklist;
718static int isbreak;
719static struct wdblock *wdlist;
720static struct wdblock *iolist;
721static char *trap[_NSIG + 1];
722static char ourtrap[_NSIG + 1];
723static int trapset; /* trap pending */
724static int yynerrs; /* yacc */
725static char line[LINELIM];
726
727#ifdef MSHDEBUG
728static struct var *mshdbg_var;
729#endif
730static struct var *vlist; /* dictionary */
731static struct var *homedir; /* home directory */
732static struct var *prompt; /* main prompt */
733static struct var *cprompt; /* continuation prompt */
734static struct var *path; /* search path for commands */
735static struct var *shell; /* shell to interpret command files */
736static struct var *ifs; /* field separators */
737
738static int areanum; /* current allocation area */
739static int intr;
740static int inparse;
741static char flags['z' - 'a' + 1];
742static char *flag = flags - 'a';
743static char *null = "";
744static int heedint = 1;
745static void (*qflag) (int) = SIG_IGN;
746static int startl;
747static int peeksym;
748static int nlseen;
749static int iounit = IODEFAULT;
750static YYSTYPE yylval;
751static char *elinep = line + sizeof(line) - 5;
752
753static struct ioarg temparg = { 0, 0, 0, AFID_NOBUF, 0 }; /* temporary for PUSHIO */
754static struct ioarg ioargstack[NPUSH];
755static struct io iostack[NPUSH];
756static struct iobuf sharedbuf = { AFID_NOBUF };
757static struct iobuf mainbuf = { AFID_NOBUF };
758static unsigned bufid = AFID_ID; /* buffer id counter */
759
760static struct here *inhere; /* list of hear docs while parsing */
761static struct here *acthere; /* list of active here documents */
762static struct region *areabot; /* bottom of area */
763static struct region *areatop; /* top of area */
764static struct region *areanxt; /* starting point of scan */
765static void *brktop;
766static void *brkaddr;
767
768static struct env e = {
769 line, /* linep: char ptr */
770 iostack, /* iobase: struct io ptr */
771 iostack - 1, /* iop: struct io ptr */
772 (xint *) NULL, /* errpt: void ptr for errors? */
773 FDBASE, /* iofd: file desc */
774 (struct env *) NULL /* oenv: struct env ptr */
775};
776
777#ifdef MSHDEBUG
778void print_t(struct op *t)
779{
780 DBGPRINTF(("T: t=0x%x, type %s, words=0x%x, IOword=0x%x\n", t,
781 T_CMD_NAMES[t->type], t->words, t->ioact));
782
783 if (t->words) {
784 DBGPRINTF(("T: W1: %s", t->words[0]));
785 }
786
787 return;
788}
789
790void print_tree(struct op *head)
791{
792 if (head == NULL) {
793 DBGPRINTF(("PRINT_TREE: no tree\n"));
794 return;
795 }
796
797 DBGPRINTF(("NODE: 0x%x, left 0x%x, right 0x%x\n", head, head->left,
798 head->right));
799
800 if (head->left)
801 print_tree(head->left);
802
803 if (head->right)
804 print_tree(head->right);
805
806 return;
807}
808#endif /* MSHDEBUG */
809
810
811#ifdef CONFIG_FEATURE_COMMAND_EDITING
812static char *current_prompt;
813#endif
814
815/* -------- sh.c -------- */
816/*
817 * shell
818 */
819
820
821extern int msh_main(int argc, char **argv)
822{
823 REGISTER int f;
824 REGISTER char *s;
825 int cflag;
826 char *name, **ap;
827 int (*iof) (struct ioarg *);
828
829 DBGPRINTF(("MSH_MAIN: argc %d, environ 0x%x\n", argc, environ));
830
831 initarea();
832 if ((ap = environ) != NULL) {
833 while (*ap)
834 assign(*ap++, !COPYV);
835 for (ap = environ; *ap;)
836 export(lookup(*ap++));
837 }
838 closeall();
839 areanum = 1;
840
841 shell = lookup("SHELL");
842 if (shell->value == null)
843 setval(shell, (char *)DEFAULT_SHELL);
844 export(shell);
845
846 homedir = lookup("HOME");
847 if (homedir->value == null)
848 setval(homedir, "/");
849 export(homedir);
850
851 setval(lookup("$"), putn(getpid()));
852
853 path = lookup("PATH");
854 if (path->value == null) {
855 if (geteuid() == 0)
856 setval(path, "/sbin:/bin:/usr/sbin:/usr/bin");
857 else
858 setval(path, "/bin:/usr/bin");
859 }
860 export(path);
861
862 ifs = lookup("IFS");
863 if (ifs->value == null)
864 setval(ifs, " \t\n");
865
866#ifdef MSHDEBUG
867 mshdbg_var = lookup("MSHDEBUG");
868 if (mshdbg_var->value == null)
869 setval(mshdbg_var, "0");
870#endif
871
872
873 prompt = lookup("PS1");
874#ifdef CONFIG_FEATURE_SH_FANCY_PROMPT
875 if (prompt->value == null)
876#endif
877 setval(prompt, "$ ");
878 if (geteuid() == 0) {
879 setval(prompt, "# ");
880 prompt->status &= ~EXPORT;
881 }
882 cprompt = lookup("PS2");
883#ifdef CONFIG_FEATURE_SH_FANCY_PROMPT
884 if (cprompt->value == null)
885#endif
886 setval(cprompt, "> ");
887
888 iof = filechar;
889 cflag = 0;
890 name = *argv++;
891 if (--argc >= 1) {
892 if (argv[0][0] == '-' && argv[0][1] != '\0') {
893 for (s = argv[0] + 1; *s; s++)
894 switch (*s) {
895 case 'c':
896 prompt->status &= ~EXPORT;
897 cprompt->status &= ~EXPORT;
898 setval(prompt, "");
899 setval(cprompt, "");
900 cflag = 1;
901 if (--argc > 0)
902 PUSHIO(aword, *++argv, iof = nlchar);
903 break;
904
905 case 'q':
906 qflag = SIG_DFL;
907 break;
908
909 case 's':
910 /* standard input */
911 break;
912
913 case 't':
914 prompt->status &= ~EXPORT;
915 setval(prompt, "");
916 iof = linechar;
917 break;
918
919 case 'i':
920 interactive++;
921 default:
922 if (*s >= 'a' && *s <= 'z')
923 flag[(int) *s]++;
924 }
925 } else {
926 argv--;
927 argc++;
928 }
929
930 if (iof == filechar && --argc > 0) {
931 setval(prompt, "");
932 setval(cprompt, "");
933 prompt->status &= ~EXPORT;
934 cprompt->status &= ~EXPORT;
935
936/* Shell is non-interactive, activate printf-based debug */
937#ifdef MSHDEBUG
938 mshdbg = (int) (((char) (mshdbg_var->value[0])) - '0');
939 if (mshdbg < 0)
940 mshdbg = 0;
941#endif
942 DBGPRINTF(("MSH_MAIN: calling newfile()\n"));
943
944 if (newfile(name = *++argv))
945 exit(1); /* Exit on error */
946 }
947 }
948
949 setdash();
950
951 /* This won't be true if PUSHIO has been called, say from newfile() above */
952 if (e.iop < iostack) {
953 PUSHIO(afile, 0, iof);
954 if (isatty(0) && isatty(1) && !cflag) {
955 interactive++;
956#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET
957#ifdef MSHDEBUG
958 printf("\n\n" BB_BANNER " Built-in shell (msh with debug)\n");
959#else
960 printf("\n\n" BB_BANNER " Built-in shell (msh)\n");
961#endif
962 printf("Enter 'help' for a list of built-in commands.\n\n");
963#endif
964 }
965 }
966
967 signal(SIGQUIT, qflag);
968 if (name && name[0] == '-') {
969 interactive++;
970 if ((f = open(".profile", 0)) >= 0)
971 next(remap(f));
972 if ((f = open("/etc/profile", 0)) >= 0)
973 next(remap(f));
974 }
975 if (interactive)
976 signal(SIGTERM, sig);
977
978 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
979 signal(SIGINT, onintr);
980 dolv = argv;
981 dolc = argc;
982 dolv[0] = name;
983 if (dolc > 1) {
984 for (ap = ++argv; --argc > 0;) {
985 if (assign(*ap = *argv++, !COPYV)) {
986 dolc--; /* keyword */
987 } else {
988 ap++;
989 }
990 }
991 }
992 setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc));
993
994 DBGPRINTF(("MSH_MAIN: begin FOR loop, interactive %d, e.iop 0x%x, iostack 0x%x\n", interactive, e.iop, iostack));
995
996 for (;;) {
997 if (interactive && e.iop <= iostack) {
998#ifdef CONFIG_FEATURE_COMMAND_EDITING
999 current_prompt = prompt->value;
1000#else
1001 prs(prompt->value);
1002#endif
1003 }
1004 onecommand();
1005 /* Ensure that getenv("PATH") stays current */
1006 setenv("PATH", path->value, 1);
1007 }
1008
1009 DBGPRINTF(("MSH_MAIN: returning.\n"));
1010}
1011
1012static void setdash()
1013{
1014 REGISTER char *cp;
1015 REGISTER int c;
1016 char m['z' - 'a' + 1];
1017
1018 cp = m;
1019 for (c = 'a'; c <= 'z'; c++)
1020 if (flag[(int) c])
1021 *cp++ = c;
1022 *cp = 0;
1023 setval(lookup("-"), m);
1024}
1025
1026static int newfile(s)
1027REGISTER char *s;
1028{
1029 REGISTER int f;
1030
1031 DBGPRINTF7(("NEWFILE: opening %s\n", s));
1032
1033 if (strcmp(s, "-") != 0) {
1034 DBGPRINTF(("NEWFILE: s is %s\n", s));
1035 f = open(s, 0);
1036 if (f < 0) {
1037 prs(s);
1038 err(": cannot open");
1039 return (1);
1040 }
1041 } else
1042 f = 0;
1043
1044 next(remap(f));
1045 return (0);
1046}
1047
1048
1049struct op *scantree(head)
1050struct op *head;
1051{
1052 struct op *dotnode;
1053
1054 if (head == NULL)
1055 return (NULL);
1056
1057 if (head->left != NULL) {
1058 dotnode = scantree(head->left);
1059 if (dotnode)
1060 return (dotnode);
1061 }
1062
1063 if (head->right != NULL) {
1064 dotnode = scantree(head->right);
1065 if (dotnode)
1066 return (dotnode);
1067 }
1068
1069 if (head->words == NULL)
1070 return (NULL);
1071
1072 DBGPRINTF5(("SCANTREE: checking node 0x%x\n", head));
1073
1074 if ((head->type != TDOT) && (strcmp(".", head->words[0]) == 0)) {
1075 DBGPRINTF5(("SCANTREE: dot found in node 0x%x\n", head));
1076 return (head);
1077 }
1078
1079 return (NULL);
1080}
1081
1082
1083static void onecommand()
1084{
1085 REGISTER int i;
1086 jmp_buf m1;
1087
1088 DBGPRINTF(("ONECOMMAND: enter, outtree=0x%x\n", outtree));
1089
1090 while (e.oenv)
1091 quitenv();
1092
1093 areanum = 1;
1094 freehere(areanum);
1095 freearea(areanum);
1096 garbage();
1097 wdlist = 0;
1098 iolist = 0;
1099 e.errpt = 0;
1100 e.linep = line;
1101 yynerrs = 0;
1102 multiline = 0;
1103 inparse = 1;
1104 intr = 0;
1105 execflg = 0;
1106
1107 setjmp(failpt = m1); /* Bruce Evans' fix */
1108 if (setjmp(failpt = m1) || yyparse() || intr) {
1109
1110 DBGPRINTF(("ONECOMMAND: this is not good.\n"));
1111
1112 while (e.oenv)
1113 quitenv();
1114 scraphere();
1115 if (!interactive && intr)
1116 leave();
1117 inparse = 0;
1118 intr = 0;
1119 return;
1120 }
1121
1122 inparse = 0;
1123 brklist = 0;
1124 intr = 0;
1125 execflg = 0;
1126
1127 if (!flag['n']) {
1128 DBGPRINTF(("ONECOMMAND: calling execute, t=outtree=0x%x\n",
1129 outtree));
1130 execute(outtree, NOPIPE, NOPIPE, 0);
1131 }
1132
1133 if (!interactive && intr) {
1134 execflg = 0;
1135 leave();
1136 }
1137
1138 if ((i = trapset) != 0) {
1139 trapset = 0;
1140 runtrap(i);
1141 }
1142}
1143
1144static void fail()
1145{
1146 longjmp(failpt, 1);
1147 /* NOTREACHED */
1148}
1149
1150static void leave()
1151{
1152 DBGPRINTF(("LEAVE: leave called!\n"));
1153
1154 if (execflg)
1155 fail();
1156 scraphere();
1157 freehere(1);
1158 runtrap(0);
1159 _exit(exstat);
1160 /* NOTREACHED */
1161}
1162
1163static void warn(s)
1164REGISTER char *s;
1165{
1166 if (*s) {
1167 prs(s);
1168 exstat = -1;
1169 }
1170 prs("\n");
1171 if (flag['e'])
1172 leave();
1173}
1174
1175static void err(s)
1176char *s;
1177{
1178 warn(s);
1179 if (flag['n'])
1180 return;
1181 if (!interactive)
1182 leave();
1183 if (e.errpt)
1184 longjmp(e.errpt, 1);
1185 closeall();
1186 e.iop = e.iobase = iostack;
1187}
1188
1189static int newenv(f)
1190int f;
1191{
1192 REGISTER struct env *ep;
1193
1194 DBGPRINTF(("NEWENV: f=%d (indicates quitenv and return)\n", f));
1195
1196 if (f) {
1197 quitenv();
1198 return (1);
1199 }
1200
1201 ep = (struct env *) space(sizeof(*ep));
1202 if (ep == NULL) {
1203 while (e.oenv)
1204 quitenv();
1205 fail();
1206 }
1207 *ep = e;
1208 e.oenv = ep;
1209 e.errpt = errpt;
1210
1211 return (0);
1212}
1213
1214static void quitenv()
1215{
1216 REGISTER struct env *ep;
1217 REGISTER int fd;
1218
1219 DBGPRINTF(("QUITENV: e.oenv=0x%x\n", e.oenv));
1220
1221 if ((ep = e.oenv) != NULL) {
1222 fd = e.iofd;
1223 e = *ep;
1224 /* should close `'d files */
1225 DELETE(ep);
1226 while (--fd >= e.iofd)
1227 close(fd);
1228 }
1229}
1230
1231/*
1232 * Is any character from s1 in s2?
1233 */
1234static int anys(s1, s2)
1235REGISTER char *s1, *s2;
1236{
1237 while (*s1)
1238 if (any(*s1++, s2))
1239 return (1);
1240 return (0);
1241}
1242
1243/*
1244 * Is character c in s?
1245 */
1246static int any(c, s)
1247REGISTER int c;
1248REGISTER char *s;
1249{
1250 while (*s)
1251 if (*s++ == c)
1252 return (1);
1253 return (0);
1254}
1255
1256static char *putn(n)
1257REGISTER int n;
1258{
1259 return (itoa(n));
1260}
1261
1262static char *itoa(n)
1263REGISTER int n;
1264{
1265 static char s[20];
1266
1267 snprintf(s, sizeof(s), "%u", n);
1268 return (s);
1269}
1270
1271
1272static void next(int f)
1273{
1274 PUSHIO(afile, f, filechar);
1275}
1276
1277static void onintr(s)
1278int s; /* ANSI C requires a parameter */
1279{
1280 signal(SIGINT, onintr);
1281 intr = 1;
1282 if (interactive) {
1283 if (inparse) {
1284 prs("\n");
1285 fail();
1286 }
1287 } else if (heedint) {
1288 execflg = 0;
1289 leave();
1290 }
1291}
1292
1293static char *space(n)
1294int n;
1295{
1296 REGISTER char *cp;
1297
1298 if ((cp = getcell(n)) == 0)
1299 err("out of string space");
1300 return (cp);
1301}
1302
1303static char *strsave(s, a)
1304REGISTER char *s;
1305int a;
1306{
1307 REGISTER char *cp, *xp;
1308
1309 if ((cp = space(strlen(s) + 1)) != NULL) {
1310 setarea((char *) cp, a);
1311 for (xp = cp; (*xp++ = *s++) != '\0';);
1312 return (cp);
1313 }
1314 return ("");
1315}
1316
1317/*
1318 * trap handling
1319 */
1320static void sig(i)
1321REGISTER int i;
1322{
1323 trapset = i;
1324 signal(i, sig);
1325}
1326
1327static void runtrap(i)
1328int i;
1329{
1330 char *trapstr;
1331
1332 if ((trapstr = trap[i]) == NULL)
1333 return;
1334
1335 if (i == 0)
1336 trap[i] = 0;
1337
1338 RUN(aword, trapstr, nlchar);
1339}
1340
1341/* -------- var.c -------- */
1342
1343/*
1344 * Find the given name in the dictionary
1345 * and return its value. If the name was
1346 * not previously there, enter it now and
1347 * return a null value.
1348 */
1349static struct var *lookup(n)
1350REGISTER char *n;
1351{
1352 REGISTER struct var *vp;
1353 REGISTER char *cp;
1354 REGISTER int c;
1355 static struct var dummy;
1356
1357 if (isdigit(*n)) {
1358 dummy.name = n;
1359 for (c = 0; isdigit(*n) && c < 1000; n++)
1360 c = c * 10 + *n - '0';
1361 dummy.status = RONLY;
1362 dummy.value = c <= dolc ? dolv[c] : null;
1363 return (&dummy);
1364 }
1365 for (vp = vlist; vp; vp = vp->next)
1366 if (eqname(vp->name, n))
1367 return (vp);
1368 cp = findeq(n);
1369 vp = (struct var *) space(sizeof(*vp));
1370 if (vp == 0 || (vp->name = space((int) (cp - n) + 2)) == 0) {
1371 dummy.name = dummy.value = "";
1372 return (&dummy);
1373 }
1374 for (cp = vp->name; (*cp = *n++) && *cp != '='; cp++);
1375 if (*cp == 0)
1376 *cp = '=';
1377 *++cp = 0;
1378 setarea((char *) vp, 0);
1379 setarea((char *) vp->name, 0);
1380 vp->value = null;
1381 vp->next = vlist;
1382 vp->status = GETCELL;
1383 vlist = vp;
1384 return (vp);
1385}
1386
1387/*
1388 * give variable at `vp' the value `val'.
1389 */
1390static void setval(vp, val)
1391struct var *vp;
1392char *val;
1393{
1394 nameval(vp, val, (char *) NULL);
1395}
1396
1397/*
1398 * if name is not NULL, it must be
1399 * a prefix of the space `val',
1400 * and end with `='.
1401 * this is all so that exporting
1402 * values is reasonably painless.
1403 */
1404static void nameval(vp, val, name)
1405REGISTER struct var *vp;
1406char *val, *name;
1407{
1408 REGISTER char *cp, *xp;
1409 char *nv;
1410 int fl;
1411
1412 if (vp->status & RONLY) {
1413 for (xp = vp->name; *xp && *xp != '=';)
1414 putc(*xp++, stderr);
1415 err(" is read-only");
1416 return;
1417 }
1418 fl = 0;
1419 if (name == NULL) {
1420 xp = space(strlen(vp->name) + strlen(val) + 2);
1421 if (xp == 0)
1422 return;
1423 /* make string: name=value */
1424 setarea((char *) xp, 0);
1425 name = xp;
1426 for (cp = vp->name; (*xp = *cp++) && *xp != '='; xp++);
1427 if (*xp++ == 0)
1428 xp[-1] = '=';
1429 nv = xp;
1430 for (cp = val; (*xp++ = *cp++) != '\0';);
1431 val = nv;
1432 fl = GETCELL;
1433 }
1434 if (vp->status & GETCELL)
1435 freecell(vp->name); /* form new string `name=value' */
1436 vp->name = name;
1437 vp->value = val;
1438 vp->status |= fl;
1439}
1440
1441static void export(vp)
1442struct var *vp;
1443{
1444 vp->status |= EXPORT;
1445}
1446
1447static void ronly(vp)
1448struct var *vp;
1449{
1450 if (isalpha(vp->name[0]) || vp->name[0] == '_') /* not an internal symbol */
1451 vp->status |= RONLY;
1452}
1453
1454static int isassign(s)
1455REGISTER char *s;
1456{
1457 DBGPRINTF7(("ISASSIGN: enter, s=%s\n", s));
1458
1459 if (!isalpha((int) *s) && *s != '_')
1460 return (0);
1461 for (; *s != '='; s++)
1462 if (*s == 0 || (!isalnum(*s) && *s != '_'))
1463 return (0);
1464
1465 return (1);
1466}
1467
1468static int assign(s, cf)
1469REGISTER char *s;
1470int cf;
1471{
1472 REGISTER char *cp;
1473 struct var *vp;
1474
1475 DBGPRINTF7(("ASSIGN: enter, s=%s, cf=%d\n", s, cf));
1476
1477 if (!isalpha(*s) && *s != '_')
1478 return (0);
1479 for (cp = s; *cp != '='; cp++)
1480 if (*cp == 0 || (!isalnum(*cp) && *cp != '_'))
1481 return (0);
1482 vp = lookup(s);
1483 nameval(vp, ++cp, cf == COPYV ? (char *) NULL : s);
1484 if (cf != COPYV)
1485 vp->status &= ~GETCELL;
1486 return (1);
1487}
1488
1489static int checkname(cp)
1490REGISTER char *cp;
1491{
1492 DBGPRINTF7(("CHECKNAME: enter, cp=%s\n", cp));
1493
1494 if (!isalpha(*cp++) && *(cp - 1) != '_')
1495 return (0);
1496 while (*cp)
1497 if (!isalnum(*cp++) && *(cp - 1) != '_')
1498 return (0);
1499 return (1);
1500}
1501
1502static void putvlist(f, out)
1503REGISTER int f, out;
1504{
1505 REGISTER struct var *vp;
1506
1507 for (vp = vlist; vp; vp = vp->next)
1508 if (vp->status & f && (isalpha(*vp->name) || *vp->name == '_')) {
1509 if (vp->status & EXPORT)
1510 write(out, "export ", 7);
1511 if (vp->status & RONLY)
1512 write(out, "readonly ", 9);
1513 write(out, vp->name, (int) (findeq(vp->name) - vp->name));
1514 write(out, "\n", 1);
1515 }
1516}
1517
1518static int eqname(n1, n2)
1519REGISTER char *n1, *n2;
1520{
1521 for (; *n1 != '=' && *n1 != 0; n1++)
1522 if (*n2++ != *n1)
1523 return (0);
1524 return (*n2 == 0 || *n2 == '=');
1525}
1526
1527static char *findeq(cp)
1528REGISTER char *cp;
1529{
1530 while (*cp != '\0' && *cp != '=')
1531 cp++;
1532 return (cp);
1533}
1534
1535/* -------- gmatch.c -------- */
1536/*
1537 * int gmatch(string, pattern)
1538 * char *string, *pattern;
1539 *
1540 * Match a pattern as in sh(1).
1541 */
1542
1543#define CMASK 0377
1544#define QUOTE 0200
1545#define QMASK (CMASK&~QUOTE)
1546#define NOT '!' /* might use ^ */
1547
1548static int gmatch(s, p)
1549REGISTER char *s, *p;
1550{
1551 REGISTER int sc, pc;
1552
1553 if (s == NULL || p == NULL)
1554 return (0);
1555 while ((pc = *p++ & CMASK) != '\0') {
1556 sc = *s++ & QMASK;
1557 switch (pc) {
1558 case '[':
1559 if ((p = cclass(p, sc)) == NULL)
1560 return (0);
1561 break;
1562
1563 case '?':
1564 if (sc == 0)
1565 return (0);
1566 break;
1567
1568 case '*':
1569 s--;
1570 do {
1571 if (*p == '\0' || gmatch(s, p))
1572 return (1);
1573 } while (*s++ != '\0');
1574 return (0);
1575
1576 default:
1577 if (sc != (pc & ~QUOTE))
1578 return (0);
1579 }
1580 }
1581 return (*s == 0);
1582}
1583
1584static char *cclass(p, sub)
1585REGISTER char *p;
1586REGISTER int sub;
1587{
1588 REGISTER int c, d, not, found;
1589
1590 if ((not = *p == NOT) != 0)
1591 p++;
1592 found = not;
1593 do {
1594 if (*p == '\0')
1595 return ((char *) NULL);
1596 c = *p & CMASK;
1597 if (p[1] == '-' && p[2] != ']') {
1598 d = p[2] & CMASK;
1599 p++;
1600 } else
1601 d = c;
1602 if (c == sub || (c <= sub && sub <= d))
1603 found = !not;
1604 } while (*++p != ']');
1605 return (found ? p + 1 : (char *) NULL);
1606}
1607
1608
1609/* -------- area.c -------- */
1610
1611/*
1612 * All memory between (char *)areabot and (char *)(areatop+1) is
1613 * exclusively administered by the area management routines.
1614 * It is assumed that sbrk() and brk() manipulate the high end.
1615 */
1616
1617#define sbrk(X) ({ void * __q = (void *)-1; if (brkaddr + (int)(X) < brktop) { __q = brkaddr; brkaddr+=(int)(X); } __q;})
1618
1619static void initarea()
1620{
1621 brkaddr = malloc(AREASIZE);
1622 brktop = brkaddr + AREASIZE;
1623
1624 while ((int) sbrk(0) & ALIGN)
1625 sbrk(1);
1626 areabot = (struct region *) sbrk(REGSIZE);
1627
1628 areabot->next = areabot;
1629 areabot->area = BUSY;
1630 areatop = areabot;
1631 areanxt = areabot;
1632}
1633
1634char *getcell(nbytes)
1635unsigned nbytes;
1636{
1637 REGISTER int nregio;
1638 REGISTER struct region *p, *q;
1639 REGISTER int i;
1640
1641 if (nbytes == 0) {
1642 puts("getcell(0)");
1643 abort();
1644 }
1645 /* silly and defeats the algorithm */
1646 /*
1647 * round upwards and add administration area
1648 */
1649 nregio = (nbytes + (REGSIZE - 1)) / REGSIZE + 1;
1650 for (p = areanxt;;) {
1651 if (p->area > areanum) {
1652 /*
1653 * merge free cells
1654 */
1655 while ((q = p->next)->area > areanum && q != areanxt)
1656 p->next = q->next;
1657 /*
1658 * exit loop if cell big enough
1659 */
1660 if (q >= p + nregio)
1661 goto found;
1662 }
1663 p = p->next;
1664 if (p == areanxt)
1665 break;
1666 }
1667 i = nregio >= GROWBY ? nregio : GROWBY;
1668 p = (struct region *) sbrk(i * REGSIZE);
1669 if (p == (struct region *) -1)
1670 return ((char *) NULL);
1671 p--;
1672 if (p != areatop) {
1673 puts("not contig");
1674 abort(); /* allocated areas are contiguous */
1675 }
1676 q = p + i;
1677 p->next = q;
1678 p->area = FREE;
1679 q->next = areabot;
1680 q->area = BUSY;
1681 areatop = q;
1682 found:
1683 /*
1684 * we found a FREE area big enough, pointed to by 'p', and up to 'q'
1685 */
1686 areanxt = p + nregio;
1687 if (areanxt < q) {
1688 /*
1689 * split into requested area and rest
1690 */
1691 if (areanxt + 1 > q) {
1692 puts("OOM");
1693 abort(); /* insufficient space left for admin */
1694 }
1695 areanxt->next = q;
1696 areanxt->area = FREE;
1697 p->next = areanxt;
1698 }
1699 p->area = areanum;
1700 return ((char *) (p + 1));
1701}
1702
1703static void freecell(cp)
1704char *cp;
1705{
1706 REGISTER struct region *p;
1707
1708 if ((p = (struct region *) cp) != NULL) {
1709 p--;
1710 if (p < areanxt)
1711 areanxt = p;
1712 p->area = FREE;
1713 }
1714}
1715
1716static void freearea(a)
1717REGISTER int a;
1718{
1719 REGISTER struct region *p, *top;
1720
1721 top = areatop;
1722 for (p = areabot; p != top; p = p->next)
1723 if (p->area >= a)
1724 p->area = FREE;
1725}
1726
1727static void setarea(cp, a)
1728char *cp;
1729int a;
1730{
1731 REGISTER struct region *p;
1732
1733 if ((p = (struct region *) cp) != NULL)
1734 (p - 1)->area = a;
1735}
1736
1737int getarea(cp)
1738char *cp;
1739{
1740 return ((struct region *) cp - 1)->area;
1741}
1742
1743static void garbage()
1744{
1745 REGISTER struct region *p, *q, *top;
1746
1747 top = areatop;
1748 for (p = areabot; p != top; p = p->next) {
1749 if (p->area > areanum) {
1750 while ((q = p->next)->area > areanum)
1751 p->next = q->next;
1752 areanxt = p;
1753 }
1754 }
1755#ifdef SHRINKBY
1756 if (areatop >= q + SHRINKBY && q->area > areanum) {
1757 brk((char *) (q + 1));
1758 q->next = areabot;
1759 q->area = BUSY;
1760 areatop = q;
1761 }
1762#endif
1763}
1764
1765/* -------- csyn.c -------- */
1766/*
1767 * shell: syntax (C version)
1768 */
1769
1770int yyparse()
1771{
1772 DBGPRINTF7(("YYPARSE: enter...\n"));
1773
1774 startl = 1;
1775 peeksym = 0;
1776 yynerrs = 0;
1777 outtree = c_list();
1778 musthave('\n', 0);
1779 return (yynerrs != 0);
1780}
1781
1782static struct op *pipeline(cf)
1783int cf;
1784{
1785 REGISTER struct op *t, *p;
1786 REGISTER int c;
1787
1788 DBGPRINTF7(("PIPELINE: enter, cf=%d\n", cf));
1789
1790 t = command(cf);
1791
1792 DBGPRINTF9(("PIPELINE: t=0x%x\n", t));
1793
1794 if (t != NULL) {
1795 while ((c = yylex(0)) == '|') {
1796 if ((p = command(CONTIN)) == NULL) {
1797 DBGPRINTF8(("PIPELINE: error!\n"));
1798 SYNTAXERR;
1799 }
1800
1801 if (t->type != TPAREN && t->type != TCOM) {
1802 /* shell statement */
1803 t = block(TPAREN, t, NOBLOCK, NOWORDS);
1804 }
1805
1806 t = block(TPIPE, t, p, NOWORDS);
1807 }
1808 peeksym = c;
1809 }
1810
1811 DBGPRINTF7(("PIPELINE: returning t=0x%x\n", t));
1812 return (t);
1813}
1814
1815static struct op *andor()
1816{
1817 REGISTER struct op *t, *p;
1818 REGISTER int c;
1819
1820 DBGPRINTF7(("ANDOR: enter...\n"));
1821
1822 t = pipeline(0);
1823
1824 DBGPRINTF9(("ANDOR: t=0x%x\n", t));
1825
1826 if (t != NULL) {
1827 while ((c = yylex(0)) == LOGAND || c == LOGOR) {
1828 if ((p = pipeline(CONTIN)) == NULL) {
1829 DBGPRINTF8(("ANDOR: error!\n"));
1830 SYNTAXERR;
1831 }
1832
1833 t = block(c == LOGAND ? TAND : TOR, t, p, NOWORDS);
1834 } /* WHILE */
1835
1836 peeksym = c;
1837 }
1838
1839 DBGPRINTF7(("ANDOR: returning t=0x%x\n", t));
1840 return (t);
1841}
1842
1843static struct op *c_list()
1844{
1845 REGISTER struct op *t, *p;
1846 REGISTER int c;
1847
1848 DBGPRINTF7(("C_LIST: enter...\n"));
1849
1850 t = andor();
1851
1852 if (t != NULL) {
1853 if ((peeksym = yylex(0)) == '&')
1854 t = block(TASYNC, t, NOBLOCK, NOWORDS);
1855
1856 while ((c = yylex(0)) == ';' || c == '&'
1857 || (multiline && c == '\n')) {
1858
1859 if ((p = andor()) == NULL)
1860 return (t);
1861
1862 if ((peeksym = yylex(0)) == '&')
1863 p = block(TASYNC, p, NOBLOCK, NOWORDS);
1864
1865 t = list(t, p);
1866 } /* WHILE */
1867
1868 peeksym = c;
1869 }
1870 /* IF */
1871 DBGPRINTF7(("C_LIST: returning t=0x%x\n", t));
1872 return (t);
1873}
1874
1875static int synio(cf)
1876int cf;
1877{
1878 REGISTER struct ioword *iop;
1879 REGISTER int i;
1880 REGISTER int c;
1881
1882 DBGPRINTF7(("SYNIO: enter, cf=%d\n", cf));
1883
1884 if ((c = yylex(cf)) != '<' && c != '>') {
1885 peeksym = c;
1886 return (0);
1887 }
1888
1889 i = yylval.i;
1890 musthave(WORD, 0);
1891 iop = io(iounit, i, yylval.cp);
1892 iounit = IODEFAULT;
1893
1894 if (i & IOHERE)
1895 markhere(yylval.cp, iop);
1896
1897 DBGPRINTF7(("SYNIO: returning 1\n"));
1898 return (1);
1899}
1900
1901static void musthave(c, cf)
1902int c, cf;
1903{
1904 if ((peeksym = yylex(cf)) != c) {
1905 DBGPRINTF7(("MUSTHAVE: error!\n"));
1906 SYNTAXERR;
1907 }
1908
1909 peeksym = 0;
1910}
1911
1912static struct op *simple()
1913{
1914 REGISTER struct op *t;
1915
1916 t = NULL;
1917 for (;;) {
1918 switch (peeksym = yylex(0)) {
1919 case '<':
1920 case '>':
1921 (void) synio(0);
1922 break;
1923
1924 case WORD:
1925 if (t == NULL) {
1926 t = newtp();
1927 t->type = TCOM;
1928 }
1929 peeksym = 0;
1930 word(yylval.cp);
1931 break;
1932
1933 default:
1934 return (t);
1935 }
1936 }
1937}
1938
1939static struct op *nested(type, mark)
1940int type, mark;
1941{
1942 REGISTER struct op *t;
1943
1944 DBGPRINTF3(("NESTED: enter, type=%d, mark=%d\n", type, mark));
1945
1946 multiline++;
1947 t = c_list();
1948 musthave(mark, 0);
1949 multiline--;
1950 return (block(type, t, NOBLOCK, NOWORDS));
1951}
1952
1953static struct op *command(cf)
1954int cf;
1955{
1956 REGISTER struct op *t;
1957 struct wdblock *iosave;
1958 REGISTER int c;
1959
1960 DBGPRINTF(("COMMAND: enter, cf=%d\n", cf));
1961
1962 iosave = iolist;
1963 iolist = NULL;
1964
1965 if (multiline)
1966 cf |= CONTIN;
1967
1968 while (synio(cf))
1969 cf = 0;
1970
1971 c = yylex(cf);
1972
1973 switch (c) {
1974 default:
1975 peeksym = c;
1976 if ((t = simple()) == NULL) {
1977 if (iolist == NULL)
1978 return ((struct op *) NULL);
1979 t = newtp();
1980 t->type = TCOM;
1981 }
1982 break;
1983
1984 case '(':
1985 t = nested(TPAREN, ')');
1986 break;
1987
1988 case '{':
1989 t = nested(TBRACE, '}');
1990 break;
1991
1992 case FOR:
1993 t = newtp();
1994 t->type = TFOR;
1995 musthave(WORD, 0);
1996 startl = 1;
1997 t->str = yylval.cp;
1998 multiline++;
1999 t->words = wordlist();
2000 if ((c = yylex(0)) != '\n' && c != ';')
2001 peeksym = c;
2002 t->left = dogroup(0);
2003 multiline--;
2004 break;
2005
2006 case WHILE:
2007 case UNTIL:
2008 multiline++;
2009 t = newtp();
2010 t->type = c == WHILE ? TWHILE : TUNTIL;
2011 t->left = c_list();
2012 t->right = dogroup(1);
2013 t->words = NULL;
2014 multiline--;
2015 break;
2016
2017 case CASE:
2018 t = newtp();
2019 t->type = TCASE;
2020 musthave(WORD, 0);
2021 t->str = yylval.cp;
2022 startl++;
2023 multiline++;
2024 musthave(IN, CONTIN);
2025 startl++;
2026
2027 t->left = caselist();
2028
2029 musthave(ESAC, 0);
2030 multiline--;
2031 break;
2032
2033 case IF:
2034 multiline++;
2035 t = newtp();
2036 t->type = TIF;
2037 t->left = c_list();
2038 t->right = thenpart();
2039 musthave(FI, 0);
2040 multiline--;
2041 break;
2042
2043 case DOT:
2044 t = newtp();
2045 t->type = TDOT;
2046
2047 musthave(WORD, 0); /* gets name of file */
2048 DBGPRINTF7(("COMMAND: DOT clause, yylval.cp is %s\n", yylval.cp));
2049
2050 word(yylval.cp); /* add word to wdlist */
2051 word(NOWORD); /* terminate wdlist */
2052 t->words = copyw(); /* dup wdlist */
2053 break;
2054
2055 }
2056
2057 while (synio(0));
2058
2059 t = namelist(t);
2060 iolist = iosave;
2061
2062 DBGPRINTF(("COMMAND: returning 0x%x\n", t));
2063
2064 return (t);
2065}
2066
2067static struct op *dowholefile(type, mark)
2068int type;
2069int mark;
2070{
2071 REGISTER struct op *t;
2072
2073 DBGPRINTF(("DOWHOLEFILE: enter, type=%d, mark=%d\n", type, mark));
2074
2075 multiline++;
2076 t = c_list();
2077 multiline--;
2078 t = block(type, t, NOBLOCK, NOWORDS);
2079 DBGPRINTF(("DOWHOLEFILE: return t=0x%x\n", t));
2080 return (t);
2081}
2082
2083static struct op *dogroup(onlydone)
2084int onlydone;
2085{
2086 REGISTER int c;
2087 REGISTER struct op *mylist;
2088
2089 c = yylex(CONTIN);
2090 if (c == DONE && onlydone)
2091 return ((struct op *) NULL);
2092 if (c != DO)
2093 SYNTAXERR;
2094 mylist = c_list();
2095 musthave(DONE, 0);
2096 return (mylist);
2097}
2098
2099static struct op *thenpart()
2100{
2101 REGISTER int c;
2102 REGISTER struct op *t;
2103
2104 if ((c = yylex(0)) != THEN) {
2105 peeksym = c;
2106 return ((struct op *) NULL);
2107 }
2108 t = newtp();
2109 t->type = 0;
2110 t->left = c_list();
2111 if (t->left == NULL)
2112 SYNTAXERR;
2113 t->right = elsepart();
2114 return (t);
2115}
2116
2117static struct op *elsepart()
2118{
2119 REGISTER int c;
2120 REGISTER struct op *t;
2121
2122 switch (c = yylex(0)) {
2123 case ELSE:
2124 if ((t = c_list()) == NULL)
2125 SYNTAXERR;
2126 return (t);
2127
2128 case ELIF:
2129 t = newtp();
2130 t->type = TELIF;
2131 t->left = c_list();
2132 t->right = thenpart();
2133 return (t);
2134
2135 default:
2136 peeksym = c;
2137 return ((struct op *) NULL);
2138 }
2139}
2140
2141static struct op *caselist()
2142{
2143 REGISTER struct op *t;
2144
2145 t = NULL;
2146 while ((peeksym = yylex(CONTIN)) != ESAC) {
2147 DBGPRINTF(("CASELIST, doing yylex, peeksym=%d\n", peeksym));
2148 t = list(t, casepart());
2149 }
2150
2151 DBGPRINTF(("CASELIST, returning t=0x%x\n", t));
2152 return (t);
2153}
2154
2155static struct op *casepart()
2156{
2157 REGISTER struct op *t;
2158
2159 DBGPRINTF7(("CASEPART: enter...\n"));
2160
2161 t = newtp();
2162 t->type = TPAT;
2163 t->words = pattern();
2164 musthave(')', 0);
2165 t->left = c_list();
2166 if ((peeksym = yylex(CONTIN)) != ESAC)
2167 musthave(BREAK, CONTIN);
2168
2169 DBGPRINTF7(("CASEPART: made newtp(TPAT, t=0x%x)\n", t));
2170
2171 return (t);
2172}
2173
2174static char **pattern()
2175{
2176 REGISTER int c, cf;
2177
2178 cf = CONTIN;
2179 do {
2180 musthave(WORD, cf);
2181 word(yylval.cp);
2182 cf = 0;
2183 } while ((c = yylex(0)) == '|');
2184 peeksym = c;
2185 word(NOWORD);
2186
2187 return (copyw());
2188}
2189
2190static char **wordlist()
2191{
2192 REGISTER int c;
2193
2194 if ((c = yylex(0)) != IN) {
2195 peeksym = c;
2196 return ((char **) NULL);
2197 }
2198 startl = 0;
2199 while ((c = yylex(0)) == WORD)
2200 word(yylval.cp);
2201 word(NOWORD);
2202 peeksym = c;
2203 return (copyw());
2204}
2205
2206/*
2207 * supporting functions
2208 */
2209static struct op *list(t1, t2)
2210REGISTER struct op *t1, *t2;
2211{
2212 DBGPRINTF7(("LIST: enter, t1=0x%x, t2=0x%x\n", t1, t2));
2213
2214 if (t1 == NULL)
2215 return (t2);
2216 if (t2 == NULL)
2217 return (t1);
2218
2219 return (block(TLIST, t1, t2, NOWORDS));
2220}
2221
2222static struct op *block(type, t1, t2, wp)
2223int type;
2224struct op *t1, *t2;
2225char **wp;
2226{
2227 REGISTER struct op *t;
2228
2229 DBGPRINTF7(("BLOCK: enter, type=%d (%s)\n", type, T_CMD_NAMES[type]));
2230
2231 t = newtp();
2232 t->type = type;
2233 t->left = t1;
2234 t->right = t2;
2235 t->words = wp;
2236
2237 DBGPRINTF7(("BLOCK: inserted 0x%x between 0x%x and 0x%x\n", t, t1,
2238 t2));
2239
2240 return (t);
2241}
2242
2243/* See if given string is a shell multiline (FOR, IF, etc) */
2244static int rlookup(n)
2245REGISTER char *n;
2246{
2247 REGISTER struct res *rp;
2248
2249 DBGPRINTF7(("RLOOKUP: enter, n is %s\n", n));
2250
2251 for (rp = restab; rp->r_name; rp++)
2252 if (strcmp(rp->r_name, n) == 0) {
2253 DBGPRINTF7(("RLOOKUP: match, returning %d\n", rp->r_val));
2254 return (rp->r_val); /* Return numeric code for shell multiline */
2255 }
2256
2257 DBGPRINTF7(("RLOOKUP: NO match, returning 0\n"));
2258 return (0); /* Not a shell multiline */
2259}
2260
2261static struct op *newtp()
2262{
2263 REGISTER struct op *t;
2264
2265 t = (struct op *) tree(sizeof(*t));
2266 t->type = 0;
2267 t->words = NULL;
2268 t->ioact = NULL;
2269 t->left = NULL;
2270 t->right = NULL;
2271 t->str = NULL;
2272
2273 DBGPRINTF3(("NEWTP: allocated 0x%x\n", t));
2274
2275 return (t);
2276}
2277
2278static struct op *namelist(t)
2279REGISTER struct op *t;
2280{
2281
2282 DBGPRINTF7(("NAMELIST: enter, t=0x%x, type %s, iolist=0x%x\n", t,
2283 T_CMD_NAMES[t->type], iolist));
2284
2285 if (iolist) {
2286 iolist = addword((char *) NULL, iolist);
2287 t->ioact = copyio();
2288 } else
2289 t->ioact = NULL;
2290
2291 if (t->type != TCOM) {
2292 if (t->type != TPAREN && t->ioact != NULL) {
2293 t = block(TPAREN, t, NOBLOCK, NOWORDS);
2294 t->ioact = t->left->ioact;
2295 t->left->ioact = NULL;
2296 }
2297 return (t);
2298 }
2299
2300 word(NOWORD);
2301 t->words = copyw();
2302
2303
2304 return (t);
2305}
2306
2307static char **copyw()
2308{
2309 REGISTER char **wd;
2310
2311 wd = getwords(wdlist);
2312 wdlist = 0;
2313 return (wd);
2314}
2315
2316static void word(cp)
2317char *cp;
2318{
2319 wdlist = addword(cp, wdlist);
2320}
2321
2322static struct ioword **copyio()
2323{
2324 REGISTER struct ioword **iop;
2325
2326 iop = (struct ioword **) getwords(iolist);
2327 iolist = 0;
2328 return (iop);
2329}
2330
2331static struct ioword *io(u, f, cp)
2332int u;
2333int f;
2334char *cp;
2335{
2336 REGISTER struct ioword *iop;
2337
2338 iop = (struct ioword *) tree(sizeof(*iop));
2339 iop->io_unit = u;
2340 iop->io_flag = f;
2341 iop->io_name = cp;
2342 iolist = addword((char *) iop, iolist);
2343 return (iop);
2344}
2345
2346static void zzerr()
2347{
2348 yyerror("syntax error");
2349}
2350
2351static void yyerror(s)
2352char *s;
2353{
2354 yynerrs++;
2355 if (interactive && e.iop <= iostack) {
2356 multiline = 0;
2357 while (eofc() == 0 && yylex(0) != '\n');
2358 }
2359 err(s);
2360 fail();
2361}
2362
2363static int yylex(cf)
2364int cf;
2365{
2366 REGISTER int c, c1;
2367 int atstart;
2368
2369 if ((c = peeksym) > 0) {
2370 peeksym = 0;
2371 if (c == '\n')
2372 startl = 1;
2373 return (c);
2374 }
2375
2376
2377 nlseen = 0;
2378 atstart = startl;
2379 startl = 0;
2380 yylval.i = 0;
2381 e.linep = line;
2382
2383/* MALAMO */
2384 line[LINELIM - 1] = '\0';
2385
2386 loop:
2387 while ((c = my_getc(0)) == ' ' || c == '\t') /* Skip whitespace */
2388 ;
2389
2390 switch (c) {
2391 default:
2392 if (any(c, "0123456789")) {
2393 unget(c1 = my_getc(0));
2394 if (c1 == '<' || c1 == '>') {
2395 iounit = c - '0';
2396 goto loop;
2397 }
2398 *e.linep++ = c;
2399 c = c1;
2400 }
2401 break;
2402
2403 case '#': /* Comment, skip to next newline or End-of-string */
2404 while ((c = my_getc(0)) != 0 && c != '\n');
2405 unget(c);
2406 goto loop;
2407
2408 case 0:
2409 DBGPRINTF5(("YYLEX: return 0, c=%d\n", c));
2410 return (c);
2411
2412 case '$':
2413 DBGPRINTF9(("YYLEX: found $\n"));
2414 *e.linep++ = c;
2415 if ((c = my_getc(0)) == '{') {
2416 if ((c = collect(c, '}')) != '\0')
2417 return (c);
2418 goto pack;
2419 }
2420 break;
2421
2422 case '`':
2423 case '\'':
2424 case '"':
2425 if ((c = collect(c, c)) != '\0')
2426 return (c);
2427 goto pack;
2428
2429 case '|':
2430 case '&':
2431 case ';':
2432 startl = 1;
2433 /* If more chars process them, else return NULL char */
2434 if ((c1 = dual(c)) != '\0')
2435 return (c1);
2436 else
2437 return (c);
2438
2439 case '^':
2440 startl = 1;
2441 return ('|');
2442 case '>':
2443 case '<':
2444 diag(c);
2445 return (c);
2446
2447 case '\n':
2448 nlseen++;
2449 gethere();
2450 startl = 1;
2451 if (multiline || cf & CONTIN) {
2452 if (interactive && e.iop <= iostack) {
2453#ifdef CONFIG_FEATURE_COMMAND_EDITING
2454 current_prompt = cprompt->value;
2455#else
2456 prs(cprompt->value);
2457#endif
2458 }
2459 if (cf & CONTIN)
2460 goto loop;
2461 }
2462 return (c);
2463
2464 case '(':
2465 case ')':
2466 startl = 1;
2467 return (c);
2468 }
2469
2470 unget(c);
2471
2472 pack:
2473 while ((c = my_getc(0)) != 0 && !any(c, "`$ '\"\t;&<>()|^\n")) {
2474 if (e.linep >= elinep)
2475 err("word too long");
2476 else
2477 *e.linep++ = c;
2478 };
2479
2480 unget(c);
2481
2482 if (any(c, "\"'`$"))
2483 goto loop;
2484
2485 *e.linep++ = '\0';
2486
2487 if (atstart && (c = rlookup(line)) != 0) {
2488 startl = 1;
2489 return (c);
2490 }
2491
2492 yylval.cp = strsave(line, areanum);
2493 return (WORD);
2494}
2495
2496
2497static int collect(c, c1)
2498REGISTER int c, c1;
2499{
2500 char s[2];
2501
2502 DBGPRINTF8(("COLLECT: enter, c=%d, c1=%d\n", c, c1));
2503
2504 *e.linep++ = c;
2505 while ((c = my_getc(c1)) != c1) {
2506 if (c == 0) {
2507 unget(c);
2508 s[0] = c1;
2509 s[1] = 0;
2510 prs("no closing ");
2511 yyerror(s);
2512 return (YYERRCODE);
2513 }
2514 if (interactive && c == '\n' && e.iop <= iostack) {
2515#ifdef CONFIG_FEATURE_COMMAND_EDITING
2516 current_prompt = cprompt->value;
2517#else
2518 prs(cprompt->value);
2519#endif
2520 }
2521 *e.linep++ = c;
2522 }
2523
2524 *e.linep++ = c;
2525
2526 DBGPRINTF8(("COLLECT: return 0, line is %s\n", line));
2527
2528 return (0);
2529}
2530
2531/* "multiline commands" helper func */
2532/* see if next 2 chars form a shell multiline */
2533static int dual(c)
2534REGISTER int c;
2535{
2536 char s[3];
2537 REGISTER char *cp = s;
2538
2539 DBGPRINTF8(("DUAL: enter, c=%d\n", c));
2540
2541 *cp++ = c; /* c is the given "peek" char */
2542 *cp++ = my_getc(0); /* get next char of input */
2543 *cp = 0; /* add EOS marker */
2544
2545 c = rlookup(s); /* see if 2 chars form a shell multiline */
2546 if (c == 0)
2547 unget(*--cp); /* String is not a shell multiline, put peek char back */
2548
2549 return (c); /* String is multiline, return numeric multiline (restab) code */
2550}
2551
2552static void diag(ec)
2553REGISTER int ec;
2554{
2555 REGISTER int c;
2556
2557 DBGPRINTF8(("DIAG: enter, ec=%d\n", ec));
2558
2559 c = my_getc(0);
2560 if (c == '>' || c == '<') {
2561 if (c != ec)
2562 zzerr();
2563 yylval.i = ec == '>' ? IOWRITE | IOCAT : IOHERE;
2564 c = my_getc(0);
2565 } else
2566 yylval.i = ec == '>' ? IOWRITE : IOREAD;
2567 if (c != '&' || yylval.i == IOHERE)
2568 unget(c);
2569 else
2570 yylval.i |= IODUP;
2571}
2572
2573static char *tree(size)
2574unsigned size;
2575{
2576 REGISTER char *t;
2577
2578 if ((t = getcell(size)) == NULL) {
2579 DBGPRINTF2(("TREE: getcell(%d) failed!\n", size));
2580 prs("command line too complicated\n");
2581 fail();
2582 /* NOTREACHED */
2583 }
2584 return (t);
2585}
2586
2587/* VARARGS1 */
2588/* ARGSUSED */
2589
2590/* -------- exec.c -------- */
2591
2592/*
2593 * execute tree
2594 */
2595
2596
2597static int execute(t, pin, pout, act)
2598REGISTER struct op *t;
2599int *pin, *pout;
2600int act;
2601{
2602 REGISTER struct op *t1;
2603 volatile int i, rv, a;
2604 char *cp, **wp, **wp2;
2605 struct var *vp;
2606 struct op *outtree_save;
2607 struct brkcon bc;
2608
2609#if __GNUC__
2610 /* Avoid longjmp clobbering */
2611 (void) &wp;
2612#endif
2613
2614 if (t == NULL) {
2615 DBGPRINTF4(("EXECUTE: enter, t==null, returning.\n"));
2616 return (0);
2617 }
2618
2619 DBGPRINTF(("EXECUTE: t=0x%x, t->type=%d (%s), t->words is %s\n", t,
2620 t->type, T_CMD_NAMES[t->type],
2621 ((t->words == NULL) ? "NULL" : t->words[0])));
2622
2623 rv = 0;
2624 a = areanum++;
2625 wp = (wp2 = t->words) != NULL
2626 ? eval(wp2, t->type == TCOM ? DOALL : DOALL & ~DOKEY)
2627 : NULL;
2628
2629/* Hard to know how many words there are, be careful of garbage pointer values */
2630/* They are likely to cause "PCI bus fault" errors */
2631#if 0
2632 DBGPRINTF(("EXECUTE: t->left=0x%x, t->right=0x%x, t->words[1] is %s\n",
2633 t->left, t->right,
2634 ((t->words[1] == NULL) ? "NULL" : t->words[1])));
2635 DBGPRINTF7(("EXECUTE: t->words[2] is %s, t->words[3] is %s\n",
2636 ((t->words[2] == NULL) ? "NULL" : t->words[2]),
2637 ((t->words[3] == NULL) ? "NULL" : t->words[3])));
2638#endif
2639
2640
2641 switch (t->type) {
2642 case TDOT:
2643 DBGPRINTF3(("EXECUTE: TDOT\n"));
2644
2645 outtree_save = outtree;
2646
2647 newfile(evalstr(t->words[0], DOALL));
2648
2649 t->left = dowholefile(TLIST, 0);
2650 t->right = NULL;
2651
2652 outtree = outtree_save;
2653
2654 if (t->left)
2655 rv = execute(t->left, pin, pout, 0);
2656 if (t->right)
2657 rv = execute(t->right, pin, pout, 0);
2658 break;
2659
2660 case TPAREN:
2661 rv = execute(t->left, pin, pout, 0);
2662 break;
2663
2664 case TCOM:
2665 {
2666 rv = forkexec(t, pin, pout, act, wp);
2667 }
2668 break;
2669
2670 case TPIPE:
2671 {
2672 int pv[2];
2673
2674 if ((rv = openpipe(pv)) < 0)
2675 break;
2676 pv[0] = remap(pv[0]);
2677 pv[1] = remap(pv[1]);
2678 (void) execute(t->left, pin, pv, 0);
2679 rv = execute(t->right, pv, pout, 0);
2680 }
2681 break;
2682
2683 case TLIST:
2684 (void) execute(t->left, pin, pout, 0);
2685 rv = execute(t->right, pin, pout, 0);
2686 break;
2687
2688 case TASYNC:
2689 {
2690 int hinteractive = interactive;
2691
2692 DBGPRINTF7(("EXECUTE: TASYNC clause, calling vfork()...\n"));
2693
2694 i = vfork();
2695 if (i != 0) {
2696 interactive = hinteractive;
2697 if (i != -1) {
2698 setval(lookup("!"), putn(i));
2699 if (pin != NULL)
2700 closepipe(pin);
2701 if (interactive) {
2702 prs(putn(i));
2703 prs("\n");
2704 }
2705 } else
2706 rv = -1;
2707 setstatus(rv);
2708 } else {
2709 signal(SIGINT, SIG_IGN);
2710 signal(SIGQUIT, SIG_IGN);
2711 if (interactive)
2712 signal(SIGTERM, SIG_DFL);
2713 interactive = 0;
2714 if (pin == NULL) {
2715 close(0);
2716 open("/dev/null", 0);
2717 }
2718 _exit(execute(t->left, pin, pout, FEXEC));
2719 }
2720 }
2721 break;
2722
2723 case TOR:
2724 case TAND:
2725 rv = execute(t->left, pin, pout, 0);
2726 if ((t1 = t->right) != NULL && (rv == 0) == (t->type == TAND))
2727 rv = execute(t1, pin, pout, 0);
2728 break;
2729
2730 case TFOR:
2731 if (wp == NULL) {
2732 wp = dolv + 1;
2733 if ((i = dolc) < 0)
2734 i = 0;
2735 } else {
2736 i = -1;
2737 while (*wp++ != NULL);
2738 }
2739 vp = lookup(t->str);
2740 while (setjmp(bc.brkpt))
2741 if (isbreak)
2742 goto broken;
2743 brkset(&bc);
2744 for (t1 = t->left; i-- && *wp != NULL;) {
2745 setval(vp, *wp++);
2746 rv = execute(t1, pin, pout, 0);
2747 }
2748 brklist = brklist->nextlev;
2749 break;
2750
2751 case TWHILE:
2752 case TUNTIL:
2753 while (setjmp(bc.brkpt))
2754 if (isbreak)
2755 goto broken;
2756 brkset(&bc);
2757 t1 = t->left;
2758 while ((execute(t1, pin, pout, 0) == 0) == (t->type == TWHILE))
2759 rv = execute(t->right, pin, pout, 0);
2760 brklist = brklist->nextlev;
2761 break;
2762
2763 case TIF:
2764 case TELIF:
2765 if (t->right != NULL) {
2766 rv = !execute(t->left, pin, pout, 0) ?
2767 execute(t->right->left, pin, pout, 0) :
2768 execute(t->right->right, pin, pout, 0);
2769 }
2770 break;
2771
2772 case TCASE:
2773 if ((cp = evalstr(t->str, DOSUB | DOTRIM)) == 0)
2774 cp = "";
2775
2776 DBGPRINTF7(("EXECUTE: TCASE, t->str is %s, cp is %s\n",
2777 ((t->str == NULL) ? "NULL" : t->str),
2778 ((cp == NULL) ? "NULL" : cp)));
2779
2780 if ((t1 = findcase(t->left, cp)) != NULL) {
2781 DBGPRINTF7(("EXECUTE: TCASE, calling execute(t=0x%x, t1=0x%x)...\n", t, t1));
2782 rv = execute(t1, pin, pout, 0);
2783 DBGPRINTF7(("EXECUTE: TCASE, back from execute(t=0x%x, t1=0x%x)...\n", t, t1));
2784 }
2785 break;
2786
2787 case TBRACE:
2788/*
2789 if (iopp = t->ioact)
2790 while (*iopp)
2791 if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) {
2792 rv = -1;
2793 break;
2794 }
2795*/
2796 if (rv >= 0 && (t1 = t->left))
2797 rv = execute(t1, pin, pout, 0);
2798 break;
2799
2800 };
2801
2802 broken:
2803 t->words = wp2;
2804 isbreak = 0;
2805 freehere(areanum);
2806 freearea(areanum);
2807 areanum = a;
2808 if (interactive && intr) {
2809 closeall();
2810 fail();
2811 }
2812
2813 if ((i = trapset) != 0) {
2814 trapset = 0;
2815 runtrap(i);
2816 }
2817
2818 DBGPRINTF(("EXECUTE: returning from t=0x%x, rv=%d\n", t, rv));
2819 return (rv);
2820}
2821
2822static int
2823forkexec(REGISTER struct op *t, int *pin, int *pout, int act, char **wp)
2824{
2825 pid_t newpid;
2826 int i, rv;
2827 int (*shcom) (struct op *) = NULL;
2828 REGISTER int f;
2829 char *cp = NULL;
2830 struct ioword **iopp;
2831 int resetsig;
2832 char **owp;
2833 int forked = 0;
2834
2835 int *hpin = pin;
2836 int *hpout = pout;
2837 char *hwp;
2838 int hinteractive;
2839 int hintr;
2840 struct brkcon *hbrklist;
2841 int hexecflg;
2842
2843#if __GNUC__
2844 /* Avoid longjmp clobbering */
2845 (void) &pin;
2846 (void) &pout;
2847 (void) &wp;
2848 (void) &shcom;
2849 (void) &cp;
2850 (void) &resetsig;
2851 (void) &owp;
2852#endif
2853
2854 DBGPRINTF(("FORKEXEC: t=0x%x, pin 0x%x, pout 0x%x, act %d\n", t, pin,
2855 pout, act));
2856 DBGPRINTF7(("FORKEXEC: t->words is %s\n",
2857 ((t->words == NULL) ? "NULL" : t->words[0])));
2858
2859/* Hard to know how many words there are, be careful of garbage pointer values */
2860/* They are likely to cause "PCI bus fault" errors */
2861#if 0
2862 DBGPRINTF7(("FORKEXEC: t->words is %s, t->words[1] is %s\n",
2863 ((t->words == NULL) ? "NULL" : t->words[0]),
2864 ((t->words == NULL) ? "NULL" : t->words[1])));
2865 DBGPRINTF7(("FORKEXEC: wp is %s, wp[1] is %s\n",
2866 ((wp == NULL) ? "NULL" : wp[0]),
2867 ((wp[1] == NULL) ? "NULL" : wp[1])));
2868 DBGPRINTF7(("FORKEXEC: wp2 is %s, wp[3] is %s\n",
2869 ((wp[2] == NULL) ? "NULL" : wp[2]),
2870 ((wp[3] == NULL) ? "NULL" : wp[3])));
2871#endif
2872
2873
2874 owp = wp;
2875 resetsig = 0;
2876 rv = -1; /* system-detected error */
2877 if (t->type == TCOM) {
2878 while ((cp = *wp++) != NULL);
2879 cp = *wp;
2880
2881 /* strip all initial assignments */
2882 /* not correct wrt PATH=yyy command etc */
2883 if (flag['x']) {
2884 DBGPRINTF9(("FORKEXEC: echo'ing, cp=0x%x, wp=0x%x, owp=0x%x\n",
2885 cp, wp, owp));
2886 echo(cp ? wp : owp);
2887 }
2888#if 0
2889 DBGPRINTF9(("FORKEXEC: t->words is %s, t->words[1] is %s\n",
2890 ((t->words == NULL) ? "NULL" : t->words[0]),
2891 ((t->words == NULL) ? "NULL" : t->words[1])));
2892 DBGPRINTF9(("FORKEXEC: wp is %s, wp[1] is %s\n",
2893 ((wp == NULL) ? "NULL" : wp[0]),
2894 ((wp == NULL) ? "NULL" : wp[1])));
2895#endif
2896
2897 if (cp == NULL && t->ioact == NULL) {
2898 while ((cp = *owp++) != NULL && assign(cp, COPYV));
2899 DBGPRINTF(("FORKEXEC: returning setstatus()\n"));
2900 return (setstatus(0));
2901 } else if (cp != NULL) {
2902 shcom = inbuilt(cp);
2903 }
2904 }
2905
2906 t->words = wp;
2907 f = act;
2908
2909#if 0
2910 DBGPRINTF3(("FORKEXEC: t->words is %s, t->words[1] is %s\n",
2911 ((t->words == NULL) ? "NULL" : t->words[0]),
2912 ((t->words == NULL) ? "NULL" : t->words[1])));
2913#endif
2914 DBGPRINTF(("FORKEXEC: shcom 0x%x, f&FEXEC 0x%x, owp 0x%x\n", shcom,
2915 f & FEXEC, owp));
2916
2917 if (shcom == NULL && (f & FEXEC) == 0) {
2918 /* Save values in case the child process alters them */
2919 hpin = pin;
2920 hpout = pout;
2921 hwp = *wp;
2922 hinteractive = interactive;
2923 hintr = intr;
2924 hbrklist = brklist;
2925 hexecflg = execflg;
2926
2927 DBGPRINTF3(("FORKEXEC: calling vfork()...\n"));
2928
2929 newpid = vfork();
2930
2931 if (newpid == -1) {
2932 DBGPRINTF(("FORKEXEC: ERROR, unable to vfork()!\n"));
2933 return (-1);
2934 }
2935
2936
2937 if (newpid > 0) { /* Parent */
2938
2939 /* Restore values */
2940 pin = hpin;
2941 pout = hpout;
2942 *wp = hwp;
2943 interactive = hinteractive;
2944 intr = hintr;
2945 brklist = hbrklist;
2946 execflg = hexecflg;
2947
2948/* moved up
2949 if (i == -1)
2950 return(rv);
2951*/
2952
2953 if (pin != NULL)
2954 closepipe(pin);
2955
2956 return (pout == NULL ? setstatus(waitfor(newpid, 0)) : 0);
2957 }
2958
2959 /* Must be the child process, pid should be 0 */
2960 DBGPRINTF(("FORKEXEC: child process, shcom=0x%x\n", shcom));
2961
2962 if (interactive) {
2963 signal(SIGINT, SIG_IGN);
2964 signal(SIGQUIT, SIG_IGN);
2965 resetsig = 1;
2966 }
2967 interactive = 0;
2968 intr = 0;
2969 forked = 1;
2970 brklist = 0;
2971 execflg = 0;
2972 }
2973
2974
2975 if (owp != NULL)
2976 while ((cp = *owp++) != NULL && assign(cp, COPYV))
2977 if (shcom == NULL)
2978 export(lookup(cp));
2979
2980#ifdef COMPIPE
2981 if ((pin != NULL || pout != NULL) && shcom != NULL && shcom != doexec) {
2982 err("piping to/from shell builtins not yet done");
2983 if (forked)
2984 _exit(-1);
2985 return (-1);
2986 }
2987#endif
2988
2989 if (pin != NULL) {
2990 dup2(pin[0], 0);
2991 closepipe(pin);
2992 }
2993 if (pout != NULL) {
2994 dup2(pout[1], 1);
2995 closepipe(pout);
2996 }
2997
2998 if ((iopp = t->ioact) != NULL) {
2999 if (shcom != NULL && shcom != doexec) {
3000 prs(cp);
3001 err(": cannot redirect shell command");
3002 if (forked)
3003 _exit(-1);
3004 return (-1);
3005 }
3006 while (*iopp)
3007 if (iosetup(*iopp++, pin != NULL, pout != NULL)) {
3008 if (forked)
3009 _exit(rv);
3010 return (rv);
3011 }
3012 }
3013
3014 if (shcom) {
3015 i = setstatus((*shcom) (t));
3016 if (forked)
3017 _exit(i);
3018 DBGPRINTF(("FORKEXEC: returning i=%d\n", i));
3019 return (i);
3020 }
3021
3022 /* should use FIOCEXCL */
3023 for (i = FDBASE; i < NOFILE; i++)
3024 close(i);
3025 if (resetsig) {
3026 signal(SIGINT, SIG_DFL);
3027 signal(SIGQUIT, SIG_DFL);
3028 }
3029
3030 if (t->type == TPAREN)
3031 _exit(execute(t->left, NOPIPE, NOPIPE, FEXEC));
3032 if (wp[0] == NULL)
3033 _exit(0);
3034
3035 cp = rexecve(wp[0], wp, makenv(0, NULL));
3036 prs(wp[0]);
3037 prs(": ");
3038 err(cp);
3039 if (!execflg)
3040 trap[0] = NULL;
3041
3042 DBGPRINTF(("FORKEXEC: calling leave(), pid=%d\n", newpid));
3043
3044 leave();
3045 /* NOTREACHED */
3046 _exit(1);
3047}
3048
3049/*
3050 * 0< 1> are ignored as required
3051 * within pipelines.
3052 */
3053static int iosetup(iop, pipein, pipeout)
3054REGISTER struct ioword *iop;
3055int pipein, pipeout;
3056{
3057 REGISTER int u = -1;
3058 char *cp = NULL, *msg;
3059
3060 DBGPRINTF(("IOSETUP: iop 0x%x, pipein 0x%x, pipeout 0x%x\n", iop,
3061 pipein, pipeout));
3062
3063 if (iop->io_unit == IODEFAULT) /* take default */
3064 iop->io_unit = iop->io_flag & (IOREAD | IOHERE) ? 0 : 1;
3065
3066 if (pipein && iop->io_unit == 0)
3067 return (0);
3068
3069 if (pipeout && iop->io_unit == 1)
3070 return (0);
3071
3072 msg = iop->io_flag & (IOREAD | IOHERE) ? "open" : "create";
3073 if ((iop->io_flag & IOHERE) == 0) {
3074 cp = iop->io_name;
3075 if ((cp = evalstr(cp, DOSUB | DOTRIM)) == NULL)
3076 return (1);
3077 }
3078
3079 if (iop->io_flag & IODUP) {
3080 if (cp[1] || (!isdigit(*cp) && *cp != '-')) {
3081 prs(cp);
3082 err(": illegal >& argument");
3083 return (1);
3084 }
3085 if (*cp == '-')
3086 iop->io_flag = IOCLOSE;
3087 iop->io_flag &= ~(IOREAD | IOWRITE);
3088 }
3089 switch (iop->io_flag) {
3090 case IOREAD:
3091 u = open(cp, 0);
3092 break;
3093
3094 case IOHERE:
3095 case IOHERE | IOXHERE:
3096 u = herein(iop->io_name, iop->io_flag & IOXHERE);
3097 cp = "here file";
3098 break;
3099
3100 case IOWRITE | IOCAT:
3101 if ((u = open(cp, 1)) >= 0) {
3102 lseek(u, (long) 0, 2);
3103 break;
3104 }
3105 case IOWRITE:
3106 u = creat(cp, 0666);
3107 break;
3108
3109 case IODUP:
3110 u = dup2(*cp - '0', iop->io_unit);
3111 break;
3112
3113 case IOCLOSE:
3114 close(iop->io_unit);
3115 return (0);
3116 }
3117 if (u < 0) {
3118 prs(cp);
3119 prs(": cannot ");
3120 warn(msg);
3121 return (1);
3122 } else {
3123 if (u != iop->io_unit) {
3124 dup2(u, iop->io_unit);
3125 close(u);
3126 }
3127 }
3128 return (0);
3129}
3130
3131static void echo(wp)
3132REGISTER char **wp;
3133{
3134 REGISTER int i;
3135
3136 prs("+");
3137 for (i = 0; wp[i]; i++) {
3138 if (i)
3139 prs(" ");
3140 prs(wp[i]);
3141 }
3142 prs("\n");
3143}
3144
3145static struct op **find1case(t, w)
3146struct op *t;
3147char *w;
3148{
3149 REGISTER struct op *t1;
3150 struct op **tp;
3151 REGISTER char **wp, *cp;
3152
3153
3154 if (t == NULL) {
3155 DBGPRINTF3(("FIND1CASE: enter, t==NULL, returning.\n"));
3156 return ((struct op **) NULL);
3157 }
3158
3159 DBGPRINTF3(("FIND1CASE: enter, t->type=%d (%s)\n", t->type,
3160 T_CMD_NAMES[t->type]));
3161
3162 if (t->type == TLIST) {
3163 if ((tp = find1case(t->left, w)) != NULL) {
3164 DBGPRINTF3(("FIND1CASE: found one to the left, returning tp=0x%x\n", tp));
3165 return (tp);
3166 }
3167 t1 = t->right; /* TPAT */
3168 } else
3169 t1 = t;
3170
3171 for (wp = t1->words; *wp;)
3172 if ((cp = evalstr(*wp++, DOSUB)) && gmatch(w, cp)) {
3173 DBGPRINTF3(("FIND1CASE: returning &t1->left= 0x%x.\n",
3174 &t1->left));
3175 return (&t1->left);
3176 }
3177
3178 DBGPRINTF(("FIND1CASE: returning NULL\n"));
3179 return ((struct op **) NULL);
3180}
3181
3182static struct op *findcase(t, w)
3183struct op *t;
3184char *w;
3185{
3186 REGISTER struct op **tp;
3187
3188 return ((tp = find1case(t, w)) != NULL ? *tp : (struct op *) NULL);
3189}
3190
3191/*
3192 * Enter a new loop level (marked for break/continue).
3193 */
3194static void brkset(bc)
3195struct brkcon *bc;
3196{
3197 bc->nextlev = brklist;
3198 brklist = bc;
3199}
3200
3201/*
3202 * Wait for the last process created.
3203 * Print a message for each process found
3204 * that was killed by a signal.
3205 * Ignore interrupt signals while waiting
3206 * unless `canintr' is true.
3207 */
3208static int waitfor(lastpid, canintr)
3209REGISTER int lastpid;
3210int canintr;
3211{
3212 REGISTER int pid, rv;
3213 int s;
3214 int oheedint = heedint;
3215
3216 heedint = 0;
3217 rv = 0;
3218 do {
3219 pid = wait(&s);
3220 if (pid == -1) {
3221 if (errno != EINTR || canintr)
3222 break;
3223 } else {
3224 if ((rv = WAITSIG(s)) != 0) {
3225 if (rv < NSIGNAL) {
3226 if (signame[rv] != NULL) {
3227 if (pid != lastpid) {
3228 prn(pid);
3229 prs(": ");
3230 }
3231 prs(signame[rv]);
3232 }
3233 } else {
3234 if (pid != lastpid) {
3235 prn(pid);
3236 prs(": ");
3237 }
3238 prs("Signal ");
3239 prn(rv);
3240 prs(" ");
3241 }
3242 if (WAITCORE(s))
3243 prs(" - core dumped");
3244 if (rv >= NSIGNAL || signame[rv])
3245 prs("\n");
3246 rv = -1;
3247 } else
3248 rv = WAITVAL(s);
3249 }
3250 } while (pid != lastpid);
3251 heedint = oheedint;
3252 if (intr) {
3253 if (interactive) {
3254 if (canintr)
3255 intr = 0;
3256 } else {
3257 if (exstat == 0)
3258 exstat = rv;
3259 onintr(0);
3260 }
3261 }
3262 return (rv);
3263}
3264
3265static int setstatus(s)
3266REGISTER int s;
3267{
3268 exstat = s;
3269 setval(lookup("?"), putn(s));
3270 return (s);
3271}
3272
3273/*
3274 * PATH-searching interface to execve.
3275 * If getenv("PATH") were kept up-to-date,
3276 * execvp might be used.
3277 */
3278static char *rexecve(c, v, envp)
3279char *c, **v, **envp;
3280{
3281 REGISTER int i;
3282 REGISTER char *sp, *tp;
3283 int eacces = 0, asis = 0;
3284
3285#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3286 char *name = c;
3287
3288 optind = 1;
3289 if (find_applet_by_name(name)) {
3290 /* We have to exec here since we vforked. Running
3291 * run_applet_by_name() won't work and bad things
3292 * will happen. */
3293 execve("/proc/self/exe", v, envp);
3294 execve("busybox", v, envp);
3295 }
3296#endif
3297
3298 DBGPRINTF(("REXECVE: c=0x%x, v=0x%x, envp=0x%x\n", c, v, envp));
3299
3300 sp = any('/', c) ? "" : path->value;
3301 asis = *sp == '\0';
3302 while (asis || *sp != '\0') {
3303 asis = 0;
3304 tp = e.linep;
3305 for (; *sp != '\0'; tp++)
3306 if ((*tp = *sp++) == ':') {
3307 asis = *sp == '\0';
3308 break;
3309 }
3310 if (tp != e.linep)
3311 *tp++ = '/';
3312 for (i = 0; (*tp++ = c[i++]) != '\0';);
3313
3314 DBGPRINTF3(("REXECVE: e.linep is %s\n", e.linep));
3315
3316 execve(e.linep, v, envp);
3317
3318 switch (errno) {
3319 case ENOEXEC:
3320 *v = e.linep;
3321 tp = *--v;
3322 *v = e.linep;
3323 execve(DEFAULT_SHELL, v, envp);
3324 *v = tp;
3325 return ("no Shell");
3326
3327 case ENOMEM:
3328 return ((char *) bb_msg_memory_exhausted);
3329
3330 case E2BIG:
3331 return ("argument list too long");
3332
3333 case EACCES:
3334 eacces++;
3335 break;
3336 }
3337 }
3338 return (errno == ENOENT ? "not found" : "cannot execute");
3339}
3340
3341/*
3342 * Run the command produced by generator `f'
3343 * applied to stream `arg'.
3344 */
3345static int run(struct ioarg *argp, int (*f) (struct ioarg *))
3346{
3347 struct op *otree;
3348 struct wdblock *swdlist;
3349 struct wdblock *siolist;
3350 jmp_buf ev, rt;
3351 xint *ofail;
3352 int rv;
3353
3354#if __GNUC__
3355 /* Avoid longjmp clobbering */
3356 (void) &rv;
3357#endif
3358
3359 DBGPRINTF(("RUN: enter, areanum %d, outtree 0x%x, failpt 0x%x\n",
3360 areanum, outtree, failpt));
3361
3362 areanum++;
3363 swdlist = wdlist;
3364 siolist = iolist;
3365 otree = outtree;
3366 ofail = failpt;
3367 rv = -1;
3368
3369 if (newenv(setjmp(errpt = ev)) == 0) {
3370 wdlist = 0;
3371 iolist = 0;
3372 pushio(argp, f);
3373 e.iobase = e.iop;
3374 yynerrs = 0;
3375 if (setjmp(failpt = rt) == 0 && yyparse() == 0)
3376 rv = execute(outtree, NOPIPE, NOPIPE, 0);
3377 quitenv();
3378 } else {
3379 DBGPRINTF(("RUN: error from newenv()!\n"));
3380 }
3381
3382 wdlist = swdlist;
3383 iolist = siolist;
3384 failpt = ofail;
3385 outtree = otree;
3386 freearea(areanum--);
3387
3388 return (rv);
3389}
3390
3391/* -------- do.c -------- */
3392
3393/*
3394 * built-in commands: doX
3395 */
3396
3397static int dohelp(struct op *t)
3398{
3399 int col;
3400 const struct builtincmd *x;
3401
3402 printf("\nBuilt-in commands:\n");
3403 printf("-------------------\n");
3404
3405 for (col = 0, x = builtincmds; x->builtinfunc != NULL; x++) {
3406 if (!x->name)
3407 continue;
3408 col += printf("%s%s", ((col == 0) ? "\t" : " "), x->name);
3409 if (col > 60) {
3410 printf("\n");
3411 col = 0;
3412 }
3413 }
3414#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3415 {
3416 int i;
3417 const struct BB_applet *applet;
3418 extern const struct BB_applet applets[];
3419 extern const size_t NUM_APPLETS;
3420
3421 for (i = 0, applet = applets; i < NUM_APPLETS; applet++, i++) {
3422 if (!applet->name)
3423 continue;
3424
3425 col += printf("%s%s", ((col == 0) ? "\t" : " "), applet->name);
3426 if (col > 60) {
3427 printf("\n");
3428 col = 0;
3429 }
3430 }
3431 }
3432#endif
3433 printf("\n\n");
3434 return EXIT_SUCCESS;
3435}
3436
3437
3438
3439static int dolabel(struct op *t)
3440{
3441 return (0);
3442}
3443
3444static int dochdir(t)
3445REGISTER struct op *t;
3446{
3447 REGISTER char *cp, *er;
3448
3449 if ((cp = t->words[1]) == NULL && (cp = homedir->value) == NULL)
3450 er = ": no home directory";
3451 else if (chdir(cp) < 0)
3452 er = ": bad directory";
3453 else
3454 return (0);
3455 prs(cp != NULL ? cp : "cd");
3456 err(er);
3457 return (1);
3458}
3459
3460static int doshift(t)
3461REGISTER struct op *t;
3462{
3463 REGISTER int n;
3464
3465 n = t->words[1] ? getn(t->words[1]) : 1;
3466 if (dolc < n) {
3467 err("nothing to shift");
3468 return (1);
3469 }
3470 dolv[n] = dolv[0];
3471 dolv += n;
3472 dolc -= n;
3473 setval(lookup("#"), putn(dolc));
3474 return (0);
3475}
3476
3477/*
3478 * execute login and newgrp directly
3479 */
3480static int dologin(t)
3481struct op *t;
3482{
3483 REGISTER char *cp;
3484
3485 if (interactive) {
3486 signal(SIGINT, SIG_DFL);
3487 signal(SIGQUIT, SIG_DFL);
3488 }
3489 cp = rexecve(t->words[0], t->words, makenv(0, NULL));
3490 prs(t->words[0]);
3491 prs(": ");
3492 err(cp);
3493 return (1);
3494}
3495
3496static int doumask(t)
3497REGISTER struct op *t;
3498{
3499 REGISTER int i, n;
3500 REGISTER char *cp;
3501
3502 if ((cp = t->words[1]) == NULL) {
3503 i = umask(0);
3504 umask(i);
3505 for (n = 3 * 4; (n -= 3) >= 0;)
3506 putc('0' + ((i >> n) & 07), stderr);
3507 putc('\n', stderr);
3508 } else {
3509 for (n = 0; *cp >= '0' && *cp <= '9'; cp++)
3510 n = n * 8 + (*cp - '0');
3511 umask(n);
3512 }
3513 return (0);
3514}
3515
3516static int doexec(t)
3517REGISTER struct op *t;
3518{
3519 REGISTER int i;
3520 jmp_buf ex;
3521 xint *ofail;
3522
3523 t->ioact = NULL;
3524 for (i = 0; (t->words[i] = t->words[i + 1]) != NULL; i++);
3525 if (i == 0)
3526 return (1);
3527 execflg = 1;
3528 ofail = failpt;
3529 if (setjmp(failpt = ex) == 0)
3530 execute(t, NOPIPE, NOPIPE, FEXEC);
3531 failpt = ofail;
3532 execflg = 0;
3533 return (1);
3534}
3535
3536static int dodot(t)
3537struct op *t;
3538{
3539 REGISTER int i;
3540 REGISTER char *sp, *tp;
3541 char *cp;
3542 int maltmp;
3543
3544 DBGPRINTF(("DODOT: enter, t=0x%x, tleft 0x%x, tright 0x%x, e.linep is %s\n", t, t->left, t->right, ((e.linep == NULL) ? "NULL" : e.linep)));
3545
3546 if ((cp = t->words[1]) == NULL) {
3547 DBGPRINTF(("DODOT: bad args, ret 0\n"));
3548 return (0);
3549 } else {
3550 DBGPRINTF(("DODOT: cp is %s\n", cp));
3551 }
3552
3553 sp = any('/', cp) ? ":" : path->value;
3554
3555 DBGPRINTF(("DODOT: sp is %s, e.linep is %s\n",
3556 ((sp == NULL) ? "NULL" : sp),
3557 ((e.linep == NULL) ? "NULL" : e.linep)));
3558
3559 while (*sp) {
3560 tp = e.linep;
3561 while (*sp && (*tp = *sp++) != ':')
3562 tp++;
3563 if (tp != e.linep)
3564 *tp++ = '/';
3565
3566 for (i = 0; (*tp++ = cp[i++]) != '\0';);
3567
3568 /* Original code */
3569 if ((i = open(e.linep, 0)) >= 0) {
3570 exstat = 0;
3571 maltmp = remap(i);
3572 DBGPRINTF(("DODOT: remap=%d, exstat=%d, e.iofd %d, i %d, e.linep is %s\n", maltmp, exstat, e.iofd, i, e.linep));
3573
3574 next(maltmp); /* Basically a PUSHIO */
3575
3576 DBGPRINTF(("DODOT: returning exstat=%d\n", exstat));
3577
3578 return (exstat);
3579 }
3580
3581 } /* While */
3582
3583 prs(cp);
3584 err(": not found");
3585
3586 return (-1);
3587}
3588
3589static int dowait(t)
3590struct op *t;
3591{
3592 REGISTER int i;
3593 REGISTER char *cp;
3594
3595 if ((cp = t->words[1]) != NULL) {
3596 i = getn(cp);
3597 if (i == 0)
3598 return (0);
3599 } else
3600 i = -1;
3601 setstatus(waitfor(i, 1));
3602 return (0);
3603}
3604
3605static int doread(t)
3606struct op *t;
3607{
3608 REGISTER char *cp, **wp;
3609 REGISTER int nb = 0;
3610 REGISTER int nl = 0;
3611
3612 if (t->words[1] == NULL) {
3613 err("Usage: read name ...");
3614 return (1);
3615 }
3616 for (wp = t->words + 1; *wp; wp++) {
3617 for (cp = e.linep; !nl && cp < elinep - 1; cp++)
3618 if ((nb = read(0, cp, sizeof(*cp))) != sizeof(*cp) ||
3619 (nl = (*cp == '\n')) || (wp[1] && any(*cp, ifs->value)))
3620 break;
3621 *cp = 0;
3622 if (nb <= 0)
3623 break;
3624 setval(lookup(*wp), e.linep);
3625 }
3626 return (nb <= 0);
3627}
3628
3629static int doeval(t)
3630REGISTER struct op *t;
3631{
3632 return (RUN(awordlist, t->words + 1, wdchar));
3633}
3634
3635static int dotrap(t)
3636REGISTER struct op *t;
3637{
3638 REGISTER int n, i;
3639 REGISTER int resetsig;
3640
3641 if (t->words[1] == NULL) {
3642 for (i = 0; i <= _NSIG; i++)
3643 if (trap[i]) {
3644 prn(i);
3645 prs(": ");
3646 prs(trap[i]);
3647 prs("\n");
3648 }
3649 return (0);
3650 }
3651 resetsig = isdigit(*t->words[1]);
3652 for (i = resetsig ? 1 : 2; t->words[i] != NULL; ++i) {
3653 n = getsig(t->words[i]);
3654 freecell(trap[n]);
3655 trap[n] = 0;
3656 if (!resetsig) {
3657 if (*t->words[1] != '\0') {
3658 trap[n] = strsave(t->words[1], 0);
3659 setsig(n, sig);
3660 } else
3661 setsig(n, SIG_IGN);
3662 } else {
3663 if (interactive)
3664 if (n == SIGINT)
3665 setsig(n, onintr);
3666 else
3667 setsig(n, n == SIGQUIT ? SIG_IGN : SIG_DFL);
3668 else
3669 setsig(n, SIG_DFL);
3670 }
3671 }
3672 return (0);
3673}
3674
3675static int getsig(s)
3676char *s;
3677{
3678 REGISTER int n;
3679
3680 if ((n = getn(s)) < 0 || n > _NSIG) {
3681 err("trap: bad signal number");
3682 n = 0;
3683 }
3684 return (n);
3685}
3686
3687static void setsig(REGISTER int n, sighandler_t f)
3688{
3689 if (n == 0)
3690 return;
3691 if (signal(n, SIG_IGN) != SIG_IGN || ourtrap[n]) {
3692 ourtrap[n] = 1;
3693 signal(n, f);
3694 }
3695}
3696
3697static int getn(as)
3698char *as;
3699{
3700 REGISTER char *s;
3701 REGISTER int n, m;
3702
3703 s = as;
3704 m = 1;
3705 if (*s == '-') {
3706 m = -1;
3707 s++;
3708 }
3709 for (n = 0; isdigit(*s); s++)
3710 n = (n * 10) + (*s - '0');
3711 if (*s) {
3712 prs(as);
3713 err(": bad number");
3714 }
3715 return (n * m);
3716}
3717
3718static int dobreak(t)
3719struct op *t;
3720{
3721 return (brkcontin(t->words[1], 1));
3722}
3723
3724static int docontinue(t)
3725struct op *t;
3726{
3727 return (brkcontin(t->words[1], 0));
3728}
3729
3730static int brkcontin(cp, val)
3731REGISTER char *cp;
3732int val;
3733{
3734 REGISTER struct brkcon *bc;
3735 REGISTER int nl;
3736
3737 nl = cp == NULL ? 1 : getn(cp);
3738 if (nl <= 0)
3739 nl = 999;
3740 do {
3741 if ((bc = brklist) == NULL)
3742 break;
3743 brklist = bc->nextlev;
3744 } while (--nl);
3745 if (nl) {
3746 err("bad break/continue level");
3747 return (1);
3748 }
3749 isbreak = val;
3750 longjmp(bc->brkpt, 1);
3751 /* NOTREACHED */
3752}
3753
3754static int doexit(t)
3755struct op *t;
3756{
3757 REGISTER char *cp;
3758
3759 execflg = 0;
3760 if ((cp = t->words[1]) != NULL)
3761 setstatus(getn(cp));
3762
3763 DBGPRINTF(("DOEXIT: calling leave(), t=0x%x\n", t));
3764
3765 leave();
3766 /* NOTREACHED */
3767 return (0);
3768}
3769
3770static int doexport(t)
3771struct op *t;
3772{
3773 rdexp(t->words + 1, export, EXPORT);
3774 return (0);
3775}
3776
3777static int doreadonly(t)
3778struct op *t;
3779{
3780 rdexp(t->words + 1, ronly, RONLY);
3781 return (0);
3782}
3783
3784static void rdexp(char **wp, void (*f) (struct var *), int key)
3785{
3786 DBGPRINTF6(("RDEXP: enter, wp=0x%x, func=0x%x, key=%d\n", wp, f, key));
3787 DBGPRINTF6(("RDEXP: *wp=%s\n", *wp));
3788
3789 if (*wp != NULL) {
3790 for (; *wp != NULL; wp++) {
3791 if (isassign(*wp)) {
3792 char *cp;
3793
3794 assign(*wp, COPYV);
3795 for (cp = *wp; *cp != '='; cp++);
3796 *cp = '\0';
3797 }
3798 if (checkname(*wp))
3799 (*f) (lookup(*wp));
3800 else
3801 badid(*wp);
3802 }
3803 } else
3804 putvlist(key, 1);
3805}
3806
3807static void badid(s)
3808REGISTER char *s;
3809{
3810 prs(s);
3811 err(": bad identifier");
3812}
3813
3814static int doset(t)
3815REGISTER struct op *t;
3816{
3817 REGISTER struct var *vp;
3818 REGISTER char *cp;
3819 REGISTER int n;
3820
3821 if ((cp = t->words[1]) == NULL) {
3822 for (vp = vlist; vp; vp = vp->next)
3823 varput(vp->name, 1);
3824 return (0);
3825 }
3826 if (*cp == '-') {
3827 /* bad: t->words++; */
3828 for (n = 0; (t->words[n] = t->words[n + 1]) != NULL; n++);
3829 if (*++cp == 0)
3830 flag['x'] = flag['v'] = 0;
3831 else
3832 for (; *cp; cp++)
3833 switch (*cp) {
3834 case 'e':
3835 if (!interactive)
3836 flag['e']++;
3837 break;
3838
3839 default:
3840 if (*cp >= 'a' && *cp <= 'z')
3841 flag[(int) *cp]++;
3842 break;
3843 }
3844 setdash();
3845 }
3846 if (t->words[1]) {
3847 t->words[0] = dolv[0];
3848 for (n = 1; t->words[n]; n++)
3849 setarea((char *) t->words[n], 0);
3850 dolc = n - 1;
3851 dolv = t->words;
3852 setval(lookup("#"), putn(dolc));
3853 setarea((char *) (dolv - 1), 0);
3854 }
3855 return (0);
3856}
3857
3858static void varput(s, out)
3859REGISTER char *s;
3860int out;
3861{
3862 if (isalnum(*s) || *s == '_') {
3863 write(out, s, strlen(s));
3864 write(out, "\n", 1);
3865 }
3866}
3867
3868
3869/*
3870 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
3871 * This file contains code for the times builtin.
3872 */
3873static int dotimes(struct op *t)
3874{
3875 struct tms buf;
3876 long int clk_tck = sysconf(_SC_CLK_TCK);
3877
3878 times(&buf);
3879 printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
3880 (int) (buf.tms_utime / clk_tck / 60),
3881 ((double) buf.tms_utime) / clk_tck,
3882 (int) (buf.tms_stime / clk_tck / 60),
3883 ((double) buf.tms_stime) / clk_tck,
3884 (int) (buf.tms_cutime / clk_tck / 60),
3885 ((double) buf.tms_cutime) / clk_tck,
3886 (int) (buf.tms_cstime / clk_tck / 60),
3887 ((double) buf.tms_cstime) / clk_tck);
3888 return 0;
3889}
3890
3891
3892static int (*inbuilt(char *s)) (struct op *) {
3893 const struct builtincmd *bp;
3894
3895 for (bp = builtincmds; bp->name != NULL; bp++)
3896 if (strcmp(bp->name, s) == 0)
3897 return (bp->builtinfunc);
3898
3899 return (NULL);
3900}
3901
3902/* -------- eval.c -------- */
3903
3904/*
3905 * ${}
3906 * `command`
3907 * blank interpretation
3908 * quoting
3909 * glob
3910 */
3911
3912static char **eval(char **ap, int f)
3913{
3914 struct wdblock *wb;
3915 char **wp;
3916 char **wf;
3917 jmp_buf ev;
3918
3919#if __GNUC__
3920 /* Avoid longjmp clobbering */
3921 (void) &wp;
3922 (void) &ap;
3923#endif
3924
3925 DBGPRINTF4(("EVAL: enter, f=%d\n", f));
3926
3927 wp = NULL;
3928 wb = NULL;
3929 wf = NULL;
3930 if (newenv(setjmp(errpt = ev)) == 0) {
3931 while (*ap && isassign(*ap))
3932 expand(*ap++, &wb, f & ~DOGLOB);
3933 if (flag['k']) {
3934 for (wf = ap; *wf; wf++) {
3935 if (isassign(*wf))
3936 expand(*wf, &wb, f & ~DOGLOB);
3937 }
3938 }
3939 for (wb = addword((char *) 0, wb); *ap; ap++) {
3940 if (!flag['k'] || !isassign(*ap))
3941 expand(*ap, &wb, f & ~DOKEY);
3942 }
3943 wb = addword((char *) 0, wb);
3944 wp = getwords(wb);
3945 quitenv();
3946 } else
3947 gflg = 1;
3948
3949 return (gflg ? (char **) NULL : wp);
3950}
3951
3952/*
3953 * Make the exported environment from the exported
3954 * names in the dictionary. Keyword assignments
3955 * will already have been done.
3956 */
3957static char **makenv(int all, struct wdblock *wb)
3958{
3959 REGISTER struct var *vp;
3960
3961 DBGPRINTF5(("MAKENV: enter, all=%d\n", all));
3962
3963 for (vp = vlist; vp; vp = vp->next)
3964 if (all || vp->status & EXPORT)
3965 wb = addword(vp->name, wb);
3966 wb = addword((char *) 0, wb);
3967 return (getwords(wb));
3968}
3969
3970static char *evalstr(cp, f)
3971REGISTER char *cp;
3972int f;
3973{
3974 struct wdblock *wb;
3975
3976 DBGPRINTF6(("EVALSTR: enter, cp=0x%x, f=%d\n", cp, f));
3977
3978 wb = NULL;
3979 if (expand(cp, &wb, f)) {
3980 if (wb == NULL || wb->w_nword == 0
3981 || (cp = wb->w_words[0]) == NULL)
3982 cp = "";
3983 DELETE(wb);
3984 } else
3985 cp = NULL;
3986 return (cp);
3987}
3988
3989static int expand(char *cp, REGISTER struct wdblock **wbp, int f)
3990{
3991 jmp_buf ev;
3992
3993#if __GNUC__
3994 /* Avoid longjmp clobbering */
3995 (void) &cp;
3996#endif
3997
3998 DBGPRINTF3(("EXPAND: enter, f=%d\n", f));
3999
4000 gflg = 0;
4001
4002 if (cp == NULL)
4003 return (0);
4004
4005 if (!anys("$`'\"", cp) &&
4006 !anys(ifs->value, cp) && ((f & DOGLOB) == 0 || !anys("[*?", cp))) {
4007 cp = strsave(cp, areanum);
4008 if (f & DOTRIM)
4009 unquote(cp);
4010 *wbp = addword(cp, *wbp);
4011 return (1);
4012 }
4013 if (newenv(setjmp(errpt = ev)) == 0) {
4014 PUSHIO(aword, cp, strchar);
4015 e.iobase = e.iop;
4016 while ((cp = blank(f)) && gflg == 0) {
4017 e.linep = cp;
4018 cp = strsave(cp, areanum);
4019 if ((f & DOGLOB) == 0) {
4020 if (f & DOTRIM)
4021 unquote(cp);
4022 *wbp = addword(cp, *wbp);
4023 } else
4024 *wbp = glob(cp, *wbp);
4025 }
4026 quitenv();
4027 } else
4028 gflg = 1;
4029 return (gflg == 0);
4030}
4031
4032/*
4033 * Blank interpretation and quoting
4034 */
4035static char *blank(f)
4036int f;
4037{
4038 REGISTER int c, c1;
4039 REGISTER char *sp;
4040 int scanequals, foundequals;
4041
4042 DBGPRINTF3(("BLANK: enter, f=%d\n", f));
4043
4044 sp = e.linep;
4045 scanequals = f & DOKEY;
4046 foundequals = 0;
4047
4048 loop:
4049 switch (c = subgetc('"', foundequals)) {
4050 case 0:
4051 if (sp == e.linep)
4052 return (0);
4053 *e.linep++ = 0;
4054 return (sp);
4055
4056 default:
4057 if (f & DOBLANK && any(c, ifs->value))
4058 goto loop;
4059 break;
4060
4061 case '"':
4062 case '\'':
4063 scanequals = 0;
4064 if (INSUB())
4065 break;
4066 for (c1 = c; (c = subgetc(c1, 1)) != c1;) {
4067 if (c == 0)
4068 break;
4069 if (c == '\'' || !any(c, "$`\""))
4070 c |= QUOTE;
4071 *e.linep++ = c;
4072 }
4073 c = 0;
4074 }
4075 unget(c);
4076 if (!isalpha(c) && c != '_')
4077 scanequals = 0;
4078 for (;;) {
4079 c = subgetc('"', foundequals);
4080 if (c == 0 ||
4081 f & (DOBLANK && any(c, ifs->value)) ||
4082 (!INSUB() && any(c, "\"'"))) {
4083 scanequals = 0;
4084 unget(c);
4085 if (any(c, "\"'"))
4086 goto loop;
4087 break;
4088 }
4089 if (scanequals) {
4090 if (c == '=') {
4091 foundequals = 1;
4092 scanequals = 0;
4093 } else if (!isalnum(c) && c != '_')
4094 scanequals = 0;
4095 }
4096 *e.linep++ = c;
4097 }
4098 *e.linep++ = 0;
4099 return (sp);
4100}
4101
4102/*
4103 * Get characters, substituting for ` and $
4104 */
4105static int subgetc(ec, quoted)
4106REGISTER char ec;
4107int quoted;
4108{
4109 REGISTER char c;
4110
4111 DBGPRINTF3(("SUBGETC: enter, quoted=%d\n", quoted));
4112
4113 again:
4114 c = my_getc(ec);
4115 if (!INSUB() && ec != '\'') {
4116 if (c == '`') {
4117 if (grave(quoted) == 0)
4118 return (0);
4119 e.iop->task = XGRAVE;
4120 goto again;
4121 }
4122 if (c == '$' && (c = dollar(quoted)) == 0) {
4123 e.iop->task = XDOLL;
4124 goto again;
4125 }
4126 }
4127 return (c);
4128}
4129
4130/*
4131 * Prepare to generate the string returned by ${} substitution.
4132 */
4133static int dollar(quoted)
4134int quoted;
4135{
4136 int otask;
4137 struct io *oiop;
4138 char *dolp;
4139 REGISTER char *s, c, *cp = NULL;
4140 struct var *vp;
4141
4142 DBGPRINTF3(("DOLLAR: enter, quoted=%d\n", quoted));
4143
4144 c = readc();
4145 s = e.linep;
4146 if (c != '{') {
4147 *e.linep++ = c;
4148 if (isalpha(c) || c == '_') {
4149 while ((c = readc()) != 0 && (isalnum(c) || c == '_'))
4150 if (e.linep < elinep)
4151 *e.linep++ = c;
4152 unget(c);
4153 }
4154 c = 0;
4155 } else {
4156 oiop = e.iop;
4157 otask = e.iop->task;
4158
4159 e.iop->task = XOTHER;
4160 while ((c = subgetc('"', 0)) != 0 && c != '}' && c != '\n')
4161 if (e.linep < elinep)
4162 *e.linep++ = c;
4163 if (oiop == e.iop)
4164 e.iop->task = otask;
4165 if (c != '}') {
4166 err("unclosed ${");
4167 gflg++;
4168 return (c);
4169 }
4170 }
4171 if (e.linep >= elinep) {
4172 err("string in ${} too long");
4173 gflg++;
4174 e.linep -= 10;
4175 }
4176 *e.linep = 0;
4177 if (*s)
4178 for (cp = s + 1; *cp; cp++)
4179 if (any(*cp, "=-+?")) {
4180 c = *cp;
4181 *cp++ = 0;
4182 break;
4183 }
4184 if (s[1] == 0 && (*s == '*' || *s == '@')) {
4185 if (dolc > 1) {
4186 /* currently this does not distinguish $* and $@ */
4187 /* should check dollar */
4188 e.linep = s;
4189 PUSHIO(awordlist, dolv + 1, dolchar);
4190 return (0);
4191 } else { /* trap the nasty ${=} */
4192 s[0] = '1';
4193 s[1] = 0;
4194 }
4195 }
4196 vp = lookup(s);
4197 if ((dolp = vp->value) == null) {
4198 switch (c) {
4199 case '=':
4200 if (isdigit(*s)) {
4201 err("cannot use ${...=...} with $n");
4202 gflg++;
4203 break;
4204 }
4205 setval(vp, cp);
4206 dolp = vp->value;
4207 break;
4208
4209 case '-':
4210 dolp = strsave(cp, areanum);
4211 break;
4212
4213 case '?':
4214 if (*cp == 0) {
4215 prs("missing value for ");
4216 err(s);
4217 } else
4218 err(cp);
4219 gflg++;
4220 break;
4221 }
4222 } else if (c == '+')
4223 dolp = strsave(cp, areanum);
4224 if (flag['u'] && dolp == null) {
4225 prs("unset variable: ");
4226 err(s);
4227 gflg++;
4228 }
4229 e.linep = s;
4230 PUSHIO(aword, dolp, quoted ? qstrchar : strchar);
4231 return (0);
4232}
4233
4234/*
4235 * Run the command in `...` and read its output.
4236 */
4237
4238static int grave(quoted)
4239int quoted;
4240{
4241 char *cp;
4242 REGISTER int i;
4243 int j;
4244 int pf[2];
4245 static char child_cmd[LINELIM];
4246 char *src;
4247 char *dest;
4248 int count;
4249 int ignore;
4250 int ignore_once;
4251 char *argument_list[4];
4252 struct wdblock *wb = NULL;
4253
4254#if __GNUC__
4255 /* Avoid longjmp clobbering */
4256 (void) &cp;
4257#endif
4258
4259 for (cp = e.iop->argp->aword; *cp != '`'; cp++)
4260 if (*cp == 0) {
4261 err("no closing `");
4262 return (0);
4263 }
4264
4265 /* string copy with dollar expansion */
4266 src = e.iop->argp->aword;
4267 dest = child_cmd;
4268 count = 0;
4269 ignore = 0;
4270 ignore_once = 0;
4271 while ((*src != '`') && (count < LINELIM)) {
4272 if (*src == '\'')
4273 ignore = !ignore;
4274 if (*src == '\\')
4275 ignore_once = 1;
4276 if (*src == '$' && !ignore && !ignore_once) {
4277 struct var *vp;
4278 char var_name[LINELIM];
4279 char alt_value[LINELIM];
4280 int var_index = 0;
4281 int alt_index = 0;
4282 char operator = 0;
4283 int braces = 0;
4284 char *value;
4285
4286 src++;
4287 if (*src == '{') {
4288 braces = 1;
4289 src++;
4290 }
4291
4292 var_name[var_index++] = *src++;
4293 while (isalnum(*src))
4294 var_name[var_index++] = *src++;
4295 var_name[var_index] = 0;
4296
4297 if (braces) {
4298 switch (*src) {
4299 case '}':
4300 break;
4301 case '-':
4302 case '=':
4303 case '+':
4304 case '?':
4305 operator = * src;
4306 break;
4307 default:
4308 err("unclosed ${\n");
4309 return (0);
4310 }
4311 if (operator) {
4312 src++;
4313 while (*src && (*src != '}')) {
4314 alt_value[alt_index++] = *src++;
4315 }
4316 alt_value[alt_index] = 0;
4317 if (*src != '}') {
4318 err("unclosed ${\n");
4319 return (0);
4320 }
4321 }
4322 src++;
4323 }
4324
4325 if (isalpha(*var_name)) {
4326 /* let subshell handle it instead */
4327
4328 char *namep = var_name;
4329
4330 *dest++ = '$';
4331 if (braces)
4332 *dest++ = '{';
4333 while (*namep)
4334 *dest++ = *namep++;
4335 if (operator) {
4336 char *altp = alt_value;
4337 *dest++ = operator;
4338 while (*altp)
4339 *dest++ = *altp++;
4340 }
4341 if (braces)
4342 *dest++ = '}';
4343
4344 wb = addword(lookup(var_name)->name, wb);
4345 } else {
4346 /* expand */
4347
4348 vp = lookup(var_name);
4349 if (vp->value != null)
4350 value = (operator == '+') ?
4351 alt_value : vp->value;
4352 else if (operator == '?') {
4353 err(alt_value);
4354 return (0);
4355 } else if (alt_index && (operator != '+')) {
4356 value = alt_value;
4357 if (operator == '=')
4358 setval(vp, value);
4359 } else
4360 continue;
4361
4362 while (*value && (count < LINELIM)) {
4363 *dest++ = *value++;
4364 count++;
4365 }
4366 }
4367 } else {
4368 *dest++ = *src++;
4369 count++;
4370 ignore_once = 0;
4371 }
4372 }
4373 *dest = '\0';
4374
4375 if (openpipe(pf) < 0)
4376 return (0);
4377
4378 while ((i = vfork()) == -1 && errno == EAGAIN);
4379
4380 DBGPRINTF3(("GRAVE: i is %d\n", io));
4381
4382 if (i < 0) {
4383 closepipe(pf);
4384 err((char *) bb_msg_memory_exhausted);
4385 return (0);
4386 }
4387 if (i != 0) {
4388 waitpid(i, NULL, 0);
4389 e.iop->argp->aword = ++cp;
4390 close(pf[1]);
4391 PUSHIO(afile, remap(pf[0]),
4392 (int (*)(struct ioarg *)) ((quoted) ? qgravechar :
4393 gravechar));
4394 return (1);
4395 }
4396 /* allow trapped signals */
4397 /* XXX - Maybe this signal stuff should go as well? */
4398 for (j = 0; j <= _NSIG; j++)
4399 if (ourtrap[j] && signal(j, SIG_IGN) != SIG_IGN)
4400 signal(j, SIG_DFL);
4401
4402 dup2(pf[1], 1);
4403 closepipe(pf);
4404
4405 argument_list[0] = (char *) DEFAULT_SHELL;
4406 argument_list[1] = "-c";
4407 argument_list[2] = child_cmd;
4408 argument_list[3] = 0;
4409
4410 cp = rexecve(argument_list[0], argument_list, makenv(1, wb));
4411 prs(argument_list[0]);
4412 prs(": ");
4413 err(cp);
4414 _exit(1);
4415}
4416
4417
4418static char *unquote(as)
4419REGISTER char *as;
4420{
4421 REGISTER char *s;
4422
4423 if ((s = as) != NULL)
4424 while (*s)
4425 *s++ &= ~QUOTE;
4426 return (as);
4427}
4428
4429/* -------- glob.c -------- */
4430
4431/*
4432 * glob
4433 */
4434
4435#define scopy(x) strsave((x), areanum)
4436#define BLKSIZ 512
4437#define NDENT ((BLKSIZ+sizeof(struct dirent)-1)/sizeof(struct dirent))
4438
4439static struct wdblock *cl, *nl;
4440static char spcl[] = "[?*";
4441
4442static struct wdblock *glob(cp, wb)
4443char *cp;
4444struct wdblock *wb;
4445{
4446 REGISTER int i;
4447 REGISTER char *pp;
4448
4449 if (cp == 0)
4450 return (wb);
4451 i = 0;
4452 for (pp = cp; *pp; pp++)
4453 if (any(*pp, spcl))
4454 i++;
4455 else if (!any(*pp & ~QUOTE, spcl))
4456 *pp &= ~QUOTE;
4457 if (i != 0) {
4458 for (cl = addword(scopy(cp), (struct wdblock *) 0); anyspcl(cl);
4459 cl = nl) {
4460 nl = newword(cl->w_nword * 2);
4461 for (i = 0; i < cl->w_nword; i++) { /* for each argument */
4462 for (pp = cl->w_words[i]; *pp; pp++)
4463 if (any(*pp, spcl)) {
4464 globname(cl->w_words[i], pp);
4465 break;
4466 }
4467 if (*pp == '\0')
4468 nl = addword(scopy(cl->w_words[i]), nl);
4469 }
4470 for (i = 0; i < cl->w_nword; i++)
4471 DELETE(cl->w_words[i]);
4472 DELETE(cl);
4473 }
4474 for (i = 0; i < cl->w_nword; i++)
4475 unquote(cl->w_words[i]);
4476 glob0((char *) cl->w_words, cl->w_nword, sizeof(char *), xstrcmp);
4477 if (cl->w_nword) {
4478 for (i = 0; i < cl->w_nword; i++)
4479 wb = addword(cl->w_words[i], wb);
4480 DELETE(cl);
4481 return (wb);
4482 }
4483 }
4484 wb = addword(unquote(cp), wb);
4485 return (wb);
4486}
4487
4488static void globname(we, pp)
4489char *we;
4490REGISTER char *pp;
4491{
4492 REGISTER char *np, *cp;
4493 char *name, *gp, *dp;
4494 int k;
4495 DIR *dirp;
4496 struct dirent *de;
4497 char dname[NAME_MAX + 1];
4498 struct stat dbuf;
4499
4500 for (np = we; np != pp; pp--)
4501 if (pp[-1] == '/')
4502 break;
4503 for (dp = cp = space((int) (pp - np) + 3); np < pp;)
4504 *cp++ = *np++;
4505 *cp++ = '.';
4506 *cp = '\0';
4507 for (gp = cp = space(strlen(pp) + 1); *np && *np != '/';)
4508 *cp++ = *np++;
4509 *cp = '\0';
4510 dirp = opendir(dp);
4511 if (dirp == 0) {
4512 DELETE(dp);
4513 DELETE(gp);
4514 return;
4515 }
4516 dname[NAME_MAX] = '\0';
4517 while ((de = readdir(dirp)) != NULL) {
4518 /* XXX Hmmm... What this could be? (abial) */
4519 /*
4520 if (ent[j].d_ino == 0)
4521 continue;
4522 */
4523 strncpy(dname, de->d_name, NAME_MAX);
4524 if (dname[0] == '.')
4525 if (*gp != '.')
4526 continue;
4527 for (k = 0; k < NAME_MAX; k++)
4528 if (any(dname[k], spcl))
4529 dname[k] |= QUOTE;
4530 if (gmatch(dname, gp)) {
4531 name = generate(we, pp, dname, np);
4532 if (*np && !anys(np, spcl)) {
4533 if (stat(name, &dbuf)) {
4534 DELETE(name);
4535 continue;
4536 }
4537 }
4538 nl = addword(name, nl);
4539 }
4540 }
4541 closedir(dirp);
4542 DELETE(dp);
4543 DELETE(gp);
4544}
4545
4546/*
4547 * generate a pathname as below.
4548 * start..end1 / middle end
4549 * the slashes come for free
4550 */
4551static char *generate(start1, end1, middle, end)
4552char *start1;
4553REGISTER char *end1;
4554char *middle, *end;
4555{
4556 char *p;
4557 REGISTER char *op, *xp;
4558
4559 p = op =
4560 space((int) (end1 - start1) + strlen(middle) + strlen(end) + 2);
4561 for (xp = start1; xp != end1;)
4562 *op++ = *xp++;
4563 for (xp = middle; (*op++ = *xp++) != '\0';);
4564 op--;
4565 for (xp = end; (*op++ = *xp++) != '\0';);
4566 return (p);
4567}
4568
4569static int anyspcl(wb)
4570REGISTER struct wdblock *wb;
4571{
4572 REGISTER int i;
4573 REGISTER char **wd;
4574
4575 wd = wb->w_words;
4576 for (i = 0; i < wb->w_nword; i++)
4577 if (anys(spcl, *wd++))
4578 return (1);
4579 return (0);
4580}
4581
4582static int xstrcmp(p1, p2)
4583char *p1, *p2;
4584{
4585 return (strcmp(*(char **) p1, *(char **) p2));
4586}
4587
4588/* -------- word.c -------- */
4589
4590static struct wdblock *newword(nw)
4591REGISTER int nw;
4592{
4593 REGISTER struct wdblock *wb;
4594
4595 wb = (struct wdblock *) space(sizeof(*wb) + nw * sizeof(char *));
4596 wb->w_bsize = nw;
4597 wb->w_nword = 0;
4598 return (wb);
4599}
4600
4601static struct wdblock *addword(wd, wb)
4602char *wd;
4603REGISTER struct wdblock *wb;
4604{
4605 REGISTER struct wdblock *wb2;
4606 REGISTER int nw;
4607
4608 if (wb == NULL)
4609 wb = newword(NSTART);
4610 if ((nw = wb->w_nword) >= wb->w_bsize) {
4611 wb2 = newword(nw * 2);
4612 memcpy((char *) wb2->w_words, (char *) wb->w_words,
4613 nw * sizeof(char *));
4614 wb2->w_nword = nw;
4615 DELETE(wb);
4616 wb = wb2;
4617 }
4618 wb->w_words[wb->w_nword++] = wd;
4619 return (wb);
4620}
4621
4622static
4623char **getwords(wb)
4624REGISTER struct wdblock *wb;
4625{
4626 REGISTER char **wd;
4627 REGISTER int nb;
4628
4629 if (wb == NULL)
4630 return ((char **) NULL);
4631 if (wb->w_nword == 0) {
4632 DELETE(wb);
4633 return ((char **) NULL);
4634 }
4635 wd = (char **) space(nb = sizeof(*wd) * wb->w_nword);
4636 memcpy((char *) wd, (char *) wb->w_words, nb);
4637 DELETE(wb); /* perhaps should done by caller */
4638 return (wd);
4639}
4640
4641int (*func) (char *, char *);
4642int globv;
4643
4644static void glob0(a0, a1, a2, a3)
4645char *a0;
4646unsigned a1;
4647int a2;
4648int (*a3) (char *, char *);
4649{
4650 func = a3;
4651 globv = a2;
4652 glob1(a0, a0 + a1 * a2);
4653}
4654
4655static void glob1(base, lim)
4656char *base, *lim;
4657{
4658 REGISTER char *i, *j;
4659 int v2;
4660 char *lptr, *hptr;
4661 int c;
4662 unsigned n;
4663
4664
4665 v2 = globv;
4666
4667 top:
4668 if ((n = (int) (lim - base)) <= v2)
4669 return;
4670 n = v2 * (n / (2 * v2));
4671 hptr = lptr = base + n;
4672 i = base;
4673 j = lim - v2;
4674 for (;;) {
4675 if (i < lptr) {
4676 if ((c = (*func) (i, lptr)) == 0) {
4677 glob2(i, lptr -= v2);
4678 continue;
4679 }
4680 if (c < 0) {
4681 i += v2;
4682 continue;
4683 }
4684 }
4685
4686 begin:
4687 if (j > hptr) {
4688 if ((c = (*func) (hptr, j)) == 0) {
4689 glob2(hptr += v2, j);
4690 goto begin;
4691 }
4692 if (c > 0) {
4693 if (i == lptr) {
4694 glob3(i, hptr += v2, j);
4695 i = lptr += v2;
4696 goto begin;
4697 }
4698 glob2(i, j);
4699 j -= v2;
4700 i += v2;
4701 continue;
4702 }
4703 j -= v2;
4704 goto begin;
4705 }
4706
4707
4708 if (i == lptr) {
4709 if (lptr - base >= lim - hptr) {
4710 glob1(hptr + v2, lim);
4711 lim = lptr;
4712 } else {
4713 glob1(base, lptr);
4714 base = hptr + v2;
4715 }
4716 goto top;
4717 }
4718
4719
4720 glob3(j, lptr -= v2, i);
4721 j = hptr -= v2;
4722 }
4723}
4724
4725static void glob2(i, j)
4726char *i, *j;
4727{
4728 REGISTER char *index1, *index2, c;
4729 int m;
4730
4731 m = globv;
4732 index1 = i;
4733 index2 = j;
4734 do {
4735 c = *index1;
4736 *index1++ = *index2;
4737 *index2++ = c;
4738 } while (--m);
4739}
4740
4741static void glob3(i, j, k)
4742char *i, *j, *k;
4743{
4744 REGISTER char *index1, *index2, *index3;
4745 int c;
4746 int m;
4747
4748 m = globv;
4749 index1 = i;
4750 index2 = j;
4751 index3 = k;
4752 do {
4753 c = *index1;
4754 *index1++ = *index3;
4755 *index3++ = *index2;
4756 *index2++ = c;
4757 } while (--m);
4758}
4759
4760/* -------- io.c -------- */
4761
4762/*
4763 * shell IO
4764 */
4765
4766static int my_getc(int ec)
4767{
4768 REGISTER int c;
4769
4770 if (e.linep > elinep) {
4771 while ((c = readc()) != '\n' && c);
4772 err("input line too long");
4773 gflg++;
4774 return (c);
4775 }
4776 c = readc();
4777 if ((ec != '\'') && (ec != '`') && (e.iop->task != XGRAVE)) {
4778 if (c == '\\') {
4779 c = readc();
4780 if (c == '\n' && ec != '\"')
4781 return (my_getc(ec));
4782 c |= QUOTE;
4783 }
4784 }
4785 return (c);
4786}
4787
4788static void unget(c)
4789int c;
4790{
4791 if (e.iop >= e.iobase)
4792 e.iop->peekc = c;
4793}
4794
4795static int eofc()
4796{
4797 return e.iop < e.iobase || (e.iop->peekc == 0 && e.iop->prev == 0);
4798}
4799
4800static int readc()
4801{
4802 REGISTER int c;
4803
4804 RCPRINTF(("READC: e.iop 0x%x, e.iobase 0x%x\n", e.iop, e.iobase));
4805
4806 for (; e.iop >= e.iobase; e.iop--) {
4807 RCPRINTF(("READC: e.iop 0x%x, peekc 0x%x\n", e.iop, e.iop->peekc));
4808 if ((c = e.iop->peekc) != '\0') {
4809 e.iop->peekc = 0;
4810 return (c);
4811 } else {
4812 if (e.iop->prev != 0) {
4813 if ((c = (*e.iop->iofn) (e.iop->argp, e.iop)) != '\0') {
4814 if (c == -1) {
4815 e.iop++;
4816 continue;
4817 }
4818 if (e.iop == iostack)
4819 ioecho(c);
4820 return (e.iop->prev = c);
4821 } else if (e.iop->task == XIO && e.iop->prev != '\n') {
4822 e.iop->prev = 0;
4823 if (e.iop == iostack)
4824 ioecho('\n');
4825 return '\n';
4826 }
4827 }
4828 if (e.iop->task == XIO) {
4829 if (multiline) {
4830 return e.iop->prev = 0;
4831 }
4832 if (interactive && e.iop == iostack + 1) {
4833#ifdef CONFIG_FEATURE_COMMAND_EDITING
4834 current_prompt = prompt->value;
4835#else
4836 prs(prompt->value);
4837#endif
4838 }
4839 }
4840 }
4841
4842 } /* FOR */
4843
4844 if (e.iop >= iostack) {
4845 RCPRINTF(("READC: return 0, e.iop 0x%x\n", e.iop));
4846 return (0);
4847 }
4848
4849 DBGPRINTF(("READC: leave()...\n"));
4850 leave();
4851
4852 /* NOTREACHED */
4853 return (0);
4854}
4855
4856static void ioecho(c)
4857char c;
4858{
4859 if (flag['v'])
4860 write(2, &c, sizeof c);
4861}
4862
4863
4864static void pushio(struct ioarg *argp, int (*fn) (struct ioarg *))
4865{
4866 DBGPRINTF(("PUSHIO: argp 0x%x, argp->afid 0x%x, e.iop 0x%x\n", argp,
4867 argp->afid, e.iop));
4868
4869 /* Set env ptr for io source to next array spot and check for array overflow */
4870 if (++e.iop >= &iostack[NPUSH]) {
4871 e.iop--;
4872 err("Shell input nested too deeply");
4873 gflg++;
4874 return;
4875 }
4876
4877 /* We did not overflow the NPUSH array spots so setup data structs */
4878
4879 e.iop->iofn = (int (*)(struct ioarg *, struct io *)) fn; /* Store data source func ptr */
4880
4881 if (argp->afid != AFID_NOBUF)
4882 e.iop->argp = argp;
4883 else {
4884
4885 e.iop->argp = ioargstack + (e.iop - iostack); /* MAL - index into stack */
4886 *e.iop->argp = *argp; /* copy data from temp area into stack spot */
4887
4888 /* MAL - mainbuf is for 1st data source (command line?) and all nested use a single shared buffer? */
4889
4890 if (e.iop == &iostack[0])
4891 e.iop->argp->afbuf = &mainbuf;
4892 else
4893 e.iop->argp->afbuf = &sharedbuf;
4894
4895 /* MAL - if not a termimal AND (commandline OR readable file) then give it a buffer id? */
4896 /* This line appears to be active when running scripts from command line */
4897 if ((isatty(e.iop->argp->afile) == 0)
4898 && (e.iop == &iostack[0]
4899 || lseek(e.iop->argp->afile, 0L, 1) != -1)) {
4900 if (++bufid == AFID_NOBUF) /* counter rollover check, AFID_NOBUF = 11111111 */
4901 bufid = AFID_ID; /* AFID_ID = 0 */
4902
4903 e.iop->argp->afid = bufid; /* assign buffer id */
4904 }
4905
4906 DBGPRINTF(("PUSHIO: iostack 0x%x, e.iop 0x%x, afbuf 0x%x\n",
4907 iostack, e.iop, e.iop->argp->afbuf));
4908 DBGPRINTF(("PUSHIO: mbuf 0x%x, sbuf 0x%x, bid %d, e.iop 0x%x\n",
4909 &mainbuf, &sharedbuf, bufid, e.iop));
4910
4911 }
4912
4913 e.iop->prev = ~'\n';
4914 e.iop->peekc = 0;
4915 e.iop->xchar = 0;
4916 e.iop->nlcount = 0;
4917
4918 if (fn == filechar || fn == linechar)
4919 e.iop->task = XIO;
4920 else if (fn == (int (*)(struct ioarg *)) gravechar
4921 || fn == (int (*)(struct ioarg *)) qgravechar)
4922 e.iop->task = XGRAVE;
4923 else
4924 e.iop->task = XOTHER;
4925
4926 return;
4927}
4928
4929static struct io *setbase(ip)
4930struct io *ip;
4931{
4932 REGISTER struct io *xp;
4933
4934 xp = e.iobase;
4935 e.iobase = ip;
4936 return (xp);
4937}
4938
4939/*
4940 * Input generating functions
4941 */
4942
4943/*
4944 * Produce the characters of a string, then a newline, then EOF.
4945 */
4946static int nlchar(ap)
4947REGISTER struct ioarg *ap;
4948{
4949 REGISTER int c;
4950
4951 if (ap->aword == NULL)
4952 return (0);
4953 if ((c = *ap->aword++) == 0) {
4954 ap->aword = NULL;
4955 return ('\n');
4956 }
4957 return (c);
4958}
4959
4960/*
4961 * Given a list of words, produce the characters
4962 * in them, with a space after each word.
4963 */
4964static int wdchar(ap)
4965REGISTER struct ioarg *ap;
4966{
4967 REGISTER char c;
4968 REGISTER char **wl;
4969
4970 if ((wl = ap->awordlist) == NULL)
4971 return (0);
4972 if (*wl != NULL) {
4973 if ((c = *(*wl)++) != 0)
4974 return (c & 0177);
4975 ap->awordlist++;
4976 return (' ');
4977 }
4978 ap->awordlist = NULL;
4979 return ('\n');
4980}
4981
4982/*
4983 * Return the characters of a list of words,
4984 * producing a space between them.
4985 */
4986static int dolchar(ap)
4987REGISTER struct ioarg *ap;
4988{
4989 REGISTER char *wp;
4990
4991 if ((wp = *ap->awordlist++) != NULL) {
4992 PUSHIO(aword, wp, *ap->awordlist == NULL ? strchar : xxchar);
4993 return (-1);
4994 }
4995 return (0);
4996}
4997
4998static int xxchar(ap)
4999REGISTER struct ioarg *ap;
5000{
5001 REGISTER int c;
5002
5003 if (ap->aword == NULL)
5004 return (0);
5005 if ((c = *ap->aword++) == '\0') {
5006 ap->aword = NULL;
5007 return (' ');
5008 }
5009 return (c);
5010}
5011
5012/*
5013 * Produce the characters from a single word (string).
5014 */
5015static int strchar(ap)
5016REGISTER struct ioarg *ap;
5017{
5018 REGISTER int c;
5019
5020 if (ap->aword == NULL || (c = *ap->aword++) == 0)
5021 return (0);
5022 return (c);
5023}
5024
5025/*
5026 * Produce quoted characters from a single word (string).
5027 */
5028static int qstrchar(ap)
5029REGISTER struct ioarg *ap;
5030{
5031 REGISTER int c;
5032
5033 if (ap->aword == NULL || (c = *ap->aword++) == 0)
5034 return (0);
5035 return (c | QUOTE);
5036}
5037
5038/*
5039 * Return the characters from a file.
5040 */
5041static int filechar(ap)
5042REGISTER struct ioarg *ap;
5043{
5044 REGISTER int i;
5045 char c;
5046 struct iobuf *bp = ap->afbuf;
5047
5048 if (ap->afid != AFID_NOBUF) {
5049 if ((i = ap->afid != bp->id) || bp->bufp == bp->ebufp) {
5050
5051 if (i)
5052 lseek(ap->afile, ap->afpos, 0);
5053
5054 i = safe_read(ap->afile, bp->buf, sizeof(bp->buf));
5055
5056 if (i <= 0) {
5057 closef(ap->afile);
5058 return 0;
5059 }
5060
5061 bp->id = ap->afid;
5062 bp->ebufp = (bp->bufp = bp->buf) + i;
5063 }
5064
5065 ap->afpos++;
5066 return *bp->bufp++ & 0177;
5067 }
5068#ifdef CONFIG_FEATURE_COMMAND_EDITING
5069 if (interactive && isatty(ap->afile)) {
5070 static char mycommand[BUFSIZ];
5071 static int position = 0, size = 0;
5072
5073 while (size == 0 || position >= size) {
5074 cmdedit_read_input(current_prompt, mycommand);
5075 size = strlen(mycommand);
5076 position = 0;
5077 }
5078 c = mycommand[position];
5079 position++;
5080 return (c);
5081 } else
5082#endif
5083
5084 {
5085 i = safe_read(ap->afile, &c, sizeof(c));
5086 return (i == sizeof(c) ? (c & 0x7f) : (closef(ap->afile), 0));
5087 }
5088}
5089
5090/*
5091 * Return the characters from a here temp file.
5092 */
5093static int herechar(ap)
5094REGISTER struct ioarg *ap;
5095{
5096 char c;
5097
5098
5099 if (read(ap->afile, &c, sizeof(c)) != sizeof(c)) {
5100 close(ap->afile);
5101 c = 0;
5102 }
5103 return (c);
5104
5105}
5106
5107/*
5108 * Return the characters produced by a process (`...`).
5109 * Quote them if required, and remove any trailing newline characters.
5110 */
5111static int gravechar(ap, iop)
5112struct ioarg *ap;
5113struct io *iop;
5114{
5115 REGISTER int c;
5116
5117 if ((c = qgravechar(ap, iop) & ~QUOTE) == '\n')
5118 c = ' ';
5119 return (c);
5120}
5121
5122static int qgravechar(ap, iop)
5123REGISTER struct ioarg *ap;
5124struct io *iop;
5125{
5126 REGISTER int c;
5127
5128 DBGPRINTF3(("QGRAVECHAR: enter, ap=0x%x, iop=0x%x\n", ap, iop));
5129
5130 if (iop->xchar) {
5131 if (iop->nlcount) {
5132 iop->nlcount--;
5133 return ('\n' | QUOTE);
5134 }
5135 c = iop->xchar;
5136 iop->xchar = 0;
5137 } else if ((c = filechar(ap)) == '\n') {
5138 iop->nlcount = 1;
5139 while ((c = filechar(ap)) == '\n')
5140 iop->nlcount++;
5141 iop->xchar = c;
5142 if (c == 0)
5143 return (c);
5144 iop->nlcount--;
5145 c = '\n';
5146 }
5147 return (c != 0 ? c | QUOTE : 0);
5148}
5149
5150/*
5151 * Return a single command (usually the first line) from a file.
5152 */
5153static int linechar(ap)
5154REGISTER struct ioarg *ap;
5155{
5156 REGISTER int c;
5157
5158 if ((c = filechar(ap)) == '\n') {
5159 if (!multiline) {
5160 closef(ap->afile);
5161 ap->afile = -1; /* illegal value */
5162 }
5163 }
5164 return (c);
5165}
5166
5167static void prs(s)
5168REGISTER char *s;
5169{
5170 if (*s)
5171 write(2, s, strlen(s));
5172}
5173
5174static void prn(u)
5175unsigned u;
5176{
5177 prs(itoa(u));
5178}
5179
5180static void closef(i)
5181REGISTER int i;
5182{
5183 if (i > 2)
5184 close(i);
5185}
5186
5187static void closeall()
5188{
5189 REGISTER int u;
5190
5191 for (u = NUFILE; u < NOFILE;)
5192 close(u++);
5193}
5194
5195
5196/*
5197 * remap fd into Shell's fd space
5198 */
5199static int remap(fd)
5200REGISTER int fd;
5201{
5202 REGISTER int i;
5203 int map[NOFILE];
5204 int newfd;
5205
5206
5207 DBGPRINTF(("REMAP: fd=%d, e.iofd=%d\n", fd, e.iofd));
5208
5209 if (fd < e.iofd) {
5210 for (i = 0; i < NOFILE; i++)
5211 map[i] = 0;
5212
5213 do {
5214 map[fd] = 1;
5215 newfd = dup(fd);
5216 fd = newfd;
5217 } while (fd >= 0 && fd < e.iofd);
5218
5219 for (i = 0; i < NOFILE; i++)
5220 if (map[i])
5221 close(i);
5222
5223 if (fd < 0)
5224 err("too many files open in shell");
5225 }
5226
5227 return (fd);
5228}
5229
5230static int openpipe(pv)
5231REGISTER int *pv;
5232{
5233 REGISTER int i;
5234
5235 if ((i = pipe(pv)) < 0)
5236 err("can't create pipe - try again");
5237 return (i);
5238}
5239
5240static void closepipe(pv)
5241REGISTER int *pv;
5242{
5243 if (pv != NULL) {
5244 close(*pv++);
5245 close(*pv);
5246 }
5247}
5248
5249/* -------- here.c -------- */
5250
5251/*
5252 * here documents
5253 */
5254
5255static void markhere(s, iop)
5256REGISTER char *s;
5257struct ioword *iop;
5258{
5259 REGISTER struct here *h, *lh;
5260
5261 DBGPRINTF7(("MARKHERE: enter, s=0x%x\n", s));
5262
5263 h = (struct here *) space(sizeof(struct here));
5264 if (h == 0)
5265 return;
5266
5267 h->h_tag = evalstr(s, DOSUB);
5268 if (h->h_tag == 0)
5269 return;
5270
5271 h->h_iop = iop;
5272 iop->io_name = 0;
5273 h->h_next = NULL;
5274 if (inhere == 0)
5275 inhere = h;
5276 else
5277 for (lh = inhere; lh != NULL; lh = lh->h_next)
5278 if (lh->h_next == 0) {
5279 lh->h_next = h;
5280 break;
5281 }
5282 iop->io_flag |= IOHERE | IOXHERE;
5283 for (s = h->h_tag; *s; s++)
5284 if (*s & QUOTE) {
5285 iop->io_flag &= ~IOXHERE;
5286 *s &= ~QUOTE;
5287 }
5288 h->h_dosub = iop->io_flag & IOXHERE;
5289}
5290
5291static void gethere()
5292{
5293 REGISTER struct here *h, *hp;
5294
5295 DBGPRINTF7(("GETHERE: enter...\n"));
5296
5297 /* Scan here files first leaving inhere list in place */
5298 for (hp = h = inhere; h != NULL; hp = h, h = h->h_next)
5299 readhere(&h->h_iop->io_name, h->h_tag, h->h_dosub ? 0 : '\'');
5300
5301 /* Make inhere list active - keep list intact for scraphere */
5302 if (hp != NULL) {
5303 hp->h_next = acthere;
5304 acthere = inhere;
5305 inhere = NULL;
5306 }
5307}
5308
5309static void readhere(name, s, ec)
5310char **name;
5311REGISTER char *s;
5312int ec;
5313{
5314 int tf;
5315 char tname[30] = ".msh_XXXXXX";
5316 REGISTER int c;
5317 jmp_buf ev;
5318 char myline[LINELIM + 1];
5319 char *thenext;
5320
5321 DBGPRINTF7(("READHERE: enter, name=0x%x, s=0x%x\n", name, s));
5322
5323 tf = mkstemp(tname);
5324 if (tf < 0)
5325 return;
5326
5327 *name = strsave(tname, areanum);
5328 if (newenv(setjmp(errpt = ev)) != 0)
5329 unlink(tname);
5330 else {
5331 pushio(e.iop->argp, (int (*)(struct ioarg *)) e.iop->iofn);
5332 e.iobase = e.iop;
5333 for (;;) {
5334 if (interactive && e.iop <= iostack) {
5335#ifdef CONFIG_FEATURE_COMMAND_EDITING
5336 current_prompt = cprompt->value;
5337#else
5338 prs(cprompt->value);
5339#endif
5340 }
5341 thenext = myline;
5342 while ((c = my_getc(ec)) != '\n' && c) {
5343 if (ec == '\'')
5344 c &= ~QUOTE;
5345 if (thenext >= &myline[LINELIM]) {
5346 c = 0;
5347 break;
5348 }
5349 *thenext++ = c;
5350 }
5351 *thenext = 0;
5352 if (strcmp(s, myline) == 0 || c == 0)
5353 break;
5354 *thenext++ = '\n';
5355 write(tf, myline, (int) (thenext - myline));
5356 }
5357 if (c == 0) {
5358 prs("here document `");
5359 prs(s);
5360 err("' unclosed");
5361 }
5362 quitenv();
5363 }
5364 close(tf);
5365}
5366
5367/*
5368 * open here temp file.
5369 * if unquoted here, expand here temp file into second temp file.
5370 */
5371static int herein(hname, xdoll)
5372char *hname;
5373int xdoll;
5374{
5375 REGISTER int hf;
5376 int tf;
5377
5378#if __GNUC__
5379 /* Avoid longjmp clobbering */
5380 (void) &tf;
5381#endif
5382 if (hname == NULL)
5383 return (-1);
5384
5385 DBGPRINTF7(("HEREIN: hname is %s, xdoll=%d\n", hname, xdoll));
5386
5387 hf = open(hname, 0);
5388 if (hf < 0)
5389 return (-1);
5390
5391 if (xdoll) {
5392 char c;
5393 char tname[30] = ".msh_XXXXXX";
5394 jmp_buf ev;
5395
5396 tf = mkstemp(tname);
5397 if (tf < 0)
5398 return (-1);
5399 if (newenv(setjmp(errpt = ev)) == 0) {
5400 PUSHIO(afile, hf, herechar);
5401 setbase(e.iop);
5402 while ((c = subgetc(0, 0)) != 0) {
5403 c &= ~QUOTE;
5404 write(tf, &c, sizeof c);
5405 }
5406 quitenv();
5407 } else
5408 unlink(tname);
5409 close(tf);
5410 tf = open(tname, 0);
5411 unlink(tname);
5412 return (tf);
5413 } else
5414 return (hf);
5415}
5416
5417static void scraphere()
5418{
5419 REGISTER struct here *h;
5420
5421 DBGPRINTF7(("SCRAPHERE: enter...\n"));
5422
5423 for (h = inhere; h != NULL; h = h->h_next) {
5424 if (h->h_iop && h->h_iop->io_name)
5425 unlink(h->h_iop->io_name);
5426 }
5427 inhere = NULL;
5428}
5429
5430/* unlink here temp files before a freearea(area) */
5431static void freehere(area)
5432int area;
5433{
5434 REGISTER struct here *h, *hl;
5435
5436 DBGPRINTF6(("FREEHERE: enter, area=%d\n", area));
5437
5438 hl = NULL;
5439 for (h = acthere; h != NULL; h = h->h_next)
5440 if (getarea((char *) h) >= area) {
5441 if (h->h_iop->io_name != NULL)
5442 unlink(h->h_iop->io_name);
5443 if (hl == NULL)
5444 acthere = h->h_next;
5445 else
5446 hl->h_next = h->h_next;
5447 } else
5448 hl = h;
5449}
5450
5451
5452
5453/*
5454 * Copyright (c) 1987,1997, Prentice Hall
5455 * All rights reserved.
5456 *
5457 * Redistribution and use of the MINIX operating system in source and
5458 * binary forms, with or without modification, are permitted provided
5459 * that the following conditions are met:
5460 *
5461 * Redistributions of source code must retain the above copyright
5462 * notice, this list of conditions and the following disclaimer.
5463 *
5464 * Redistributions in binary form must reproduce the above
5465 * copyright notice, this list of conditions and the following
5466 * disclaimer in the documentation and/or other materials provided
5467 * with the distribution.
5468 *
5469 * Neither the name of Prentice Hall nor the names of the software
5470 * authors or contributors may be used to endorse or promote
5471 * products derived from this software without specific prior
5472 * written permission.
5473 *
5474 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND
5475 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
5476 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
5477 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
5478 * IN NO EVENT SHALL PRENTICE HALL OR ANY AUTHORS OR CONTRIBUTORS BE
5479 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
5480 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
5481 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
5482 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
5483 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
5484 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
5485 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5486 *
5487 */