source: MondoRescue/branches/stable/mindi-busybox/shell/msh.c@ 821

Last change on this file since 821 was 821, checked in by Bruno Cornec, 18 years ago

Addition of busybox 1.2.1 as a mindi-busybox new package
This should avoid delivering binary files in mindi not built there (Fedora and Debian are quite serious about that)

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