source: MondoRescue/branches/2.2.2/mindi-busybox/shell/msh.c@ 1247

Last change on this file since 1247 was 902, checked in by Bruno Cornec, 17 years ago

mindi-busybox now uses busybox 1.2.2 (Thanks Rob for that last update and good lucck for your future projects).

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 char *name = c;
3218
3219 if (ENABLE_FEATURE_SH_STANDALONE_SHELL) {
3220 optind = 1;
3221 if (find_applet_by_name(name)) {
3222 /* We have to exec here since we vforked. Running
3223 * run_applet_by_name() won't work and bad things
3224 * will happen. */
3225 execve(CONFIG_BUSYBOX_EXEC_PATH, v, envp);
3226 }
3227 }
3228
3229 DBGPRINTF(("REXECVE: c=%p, v=%p, envp=%p\n", c, v, envp));
3230
3231 sp = any('/', c) ? "" : path->value;
3232 asis = *sp == '\0';
3233 while (asis || *sp != '\0') {
3234 asis = 0;
3235 tp = e.linep;
3236 for (; *sp != '\0'; tp++)
3237 if ((*tp = *sp++) == ':') {
3238 asis = *sp == '\0';
3239 break;
3240 }
3241 if (tp != e.linep)
3242 *tp++ = '/';
3243 for (i = 0; (*tp++ = c[i++]) != '\0';);
3244
3245 DBGPRINTF3(("REXECVE: e.linep is %s\n", e.linep));
3246
3247 execve(e.linep, v, envp);
3248
3249 switch (errno) {
3250 case ENOEXEC:
3251 *v = e.linep;
3252 tp = *--v;
3253 *v = e.linep;
3254 execve(DEFAULT_SHELL, v, envp);
3255 *v = tp;
3256 return ("no Shell");
3257
3258 case ENOMEM:
3259 return ((char *) bb_msg_memory_exhausted);
3260
3261 case E2BIG:
3262 return ("argument list too long");
3263
3264 case EACCES:
3265 eacces++;
3266 break;
3267 }
3268 }
3269 return (errno == ENOENT ? "not found" : "cannot execute");
3270}
3271
3272/*
3273 * Run the command produced by generator `f'
3274 * applied to stream `arg'.
3275 */
3276static int run(struct ioarg *argp, int (*f) (struct ioarg *))
3277{
3278 struct op *otree;
3279 struct wdblock *swdlist;
3280 struct wdblock *siolist;
3281 jmp_buf ev, rt;
3282 xint *ofail;
3283 int rv;
3284
3285#if __GNUC__
3286 /* Avoid longjmp clobbering */
3287 (void) &rv;
3288#endif
3289
3290 DBGPRINTF(("RUN: enter, areanum %d, outtree %p, failpt %p\n",
3291 areanum, outtree, failpt));
3292
3293 areanum++;
3294 swdlist = wdlist;
3295 siolist = iolist;
3296 otree = outtree;
3297 ofail = failpt;
3298 rv = -1;
3299
3300 if (newenv(setjmp(errpt = ev)) == 0) {
3301 wdlist = 0;
3302 iolist = 0;
3303 pushio(argp, f);
3304 e.iobase = e.iop;
3305 yynerrs = 0;
3306 if (setjmp(failpt = rt) == 0 && yyparse() == 0)
3307 rv = execute(outtree, NOPIPE, NOPIPE, 0);
3308 quitenv();
3309 } else {
3310 DBGPRINTF(("RUN: error from newenv()!\n"));
3311 }
3312
3313 wdlist = swdlist;
3314 iolist = siolist;
3315 failpt = ofail;
3316 outtree = otree;
3317 freearea(areanum--);
3318
3319 return (rv);
3320}
3321
3322/* -------- do.c -------- */
3323
3324/*
3325 * built-in commands: doX
3326 */
3327
3328static int dohelp(struct op *t)
3329{
3330 int col;
3331 const struct builtincmd *x;
3332
3333 printf("\nBuilt-in commands:\n");
3334 printf("-------------------\n");
3335
3336 for (col = 0, x = builtincmds; x->builtinfunc != NULL; x++) {
3337 if (!x->name)
3338 continue;
3339 col += printf("%s%s", ((col == 0) ? "\t" : " "), x->name);
3340 if (col > 60) {
3341 printf("\n");
3342 col = 0;
3343 }
3344 }
3345#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL
3346 {
3347 int i;
3348 const struct BB_applet *applet;
3349 extern const struct BB_applet applets[];
3350 extern const size_t NUM_APPLETS;
3351
3352 for (i = 0, applet = applets; i < NUM_APPLETS; applet++, i++) {
3353 if (!applet->name)
3354 continue;
3355
3356 col += printf("%s%s", ((col == 0) ? "\t" : " "), applet->name);
3357 if (col > 60) {
3358 printf("\n");
3359 col = 0;
3360 }
3361 }
3362 }
3363#endif
3364 printf("\n\n");
3365 return EXIT_SUCCESS;
3366}
3367
3368
3369
3370static int dolabel(struct op *t)
3371{
3372 return (0);
3373}
3374
3375static int dochdir(REGISTER struct op *t)
3376{
3377 REGISTER char *cp, *er;
3378
3379 if ((cp = t->words[1]) == NULL && (cp = homedir->value) == NULL)
3380 er = ": no home directory";
3381 else if (chdir(cp) < 0)
3382 er = ": bad directory";
3383 else
3384 return (0);
3385 prs(cp != NULL ? cp : "cd");
3386 err(er);
3387 return (1);
3388}
3389
3390static int doshift(REGISTER struct op *t)
3391{
3392 REGISTER int n;
3393
3394 n = t->words[1] ? getn(t->words[1]) : 1;
3395 if (dolc < n) {
3396 err("nothing to shift");
3397 return (1);
3398 }
3399 dolv[n] = dolv[0];
3400 dolv += n;
3401 dolc -= n;
3402 setval(lookup("#"), putn(dolc));
3403 return (0);
3404}
3405
3406/*
3407 * execute login and newgrp directly
3408 */
3409static int dologin(struct op *t)
3410{
3411 REGISTER char *cp;
3412
3413 if (interactive) {
3414 signal(SIGINT, SIG_DFL);
3415 signal(SIGQUIT, SIG_DFL);
3416 }
3417 cp = rexecve(t->words[0], t->words, makenv(0, NULL));
3418 prs(t->words[0]);
3419 prs(": ");
3420 err(cp);
3421 return (1);
3422}
3423
3424static int doumask(REGISTER struct op *t)
3425{
3426 REGISTER int i, n;
3427 REGISTER char *cp;
3428
3429 if ((cp = t->words[1]) == NULL) {
3430 i = umask(0);
3431 umask(i);
3432 for (n = 3 * 4; (n -= 3) >= 0;)
3433 putc('0' + ((i >> n) & 07), stderr);
3434 putc('\n', stderr);
3435 } else {
3436 for (n = 0; *cp >= '0' && *cp <= '9'; cp++)
3437 n = n * 8 + (*cp - '0');
3438 umask(n);
3439 }
3440 return (0);
3441}
3442
3443static int doexec(REGISTER struct op *t)
3444{
3445 REGISTER int i;
3446 jmp_buf ex;
3447 xint *ofail;
3448
3449 t->ioact = NULL;
3450 for (i = 0; (t->words[i] = t->words[i + 1]) != NULL; i++);
3451 if (i == 0)
3452 return (1);
3453 execflg = 1;
3454 ofail = failpt;
3455 if (setjmp(failpt = ex) == 0)
3456 execute(t, NOPIPE, NOPIPE, FEXEC);
3457 failpt = ofail;
3458 execflg = 0;
3459 return (1);
3460}
3461
3462static int dodot(struct op *t)
3463{
3464 REGISTER int i;
3465 REGISTER char *sp, *tp;
3466 char *cp;
3467 int maltmp;
3468
3469 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)));
3470
3471 if ((cp = t->words[1]) == NULL) {
3472 DBGPRINTF(("DODOT: bad args, ret 0\n"));
3473 return (0);
3474 } else {
3475 DBGPRINTF(("DODOT: cp is %s\n", cp));
3476 }
3477
3478 sp = any('/', cp) ? ":" : path->value;
3479
3480 DBGPRINTF(("DODOT: sp is %s, e.linep is %s\n",
3481 ((sp == NULL) ? "NULL" : sp),
3482 ((e.linep == NULL) ? "NULL" : e.linep)));
3483
3484 while (*sp) {
3485 tp = e.linep;
3486 while (*sp && (*tp = *sp++) != ':')
3487 tp++;
3488 if (tp != e.linep)
3489 *tp++ = '/';
3490
3491 for (i = 0; (*tp++ = cp[i++]) != '\0';);
3492
3493 /* Original code */
3494 if ((i = open(e.linep, 0)) >= 0) {
3495 exstat = 0;
3496 maltmp = remap(i);
3497 DBGPRINTF(("DODOT: remap=%d, exstat=%d, e.iofd %d, i %d, e.linep is %s\n", maltmp, exstat, e.iofd, i, e.linep));
3498
3499 next(maltmp); /* Basically a PUSHIO */
3500
3501 DBGPRINTF(("DODOT: returning exstat=%d\n", exstat));
3502
3503 return (exstat);
3504 }
3505
3506 } /* While */
3507
3508 prs(cp);
3509 err(": not found");
3510
3511 return (-1);
3512}
3513
3514static int dowait(struct op *t)
3515{
3516 REGISTER int i;
3517 REGISTER char *cp;
3518
3519 if ((cp = t->words[1]) != NULL) {
3520 i = getn(cp);
3521 if (i == 0)
3522 return (0);
3523 } else
3524 i = -1;
3525 setstatus(waitfor(i, 1));
3526 return (0);
3527}
3528
3529static int doread(struct op *t)
3530{
3531 REGISTER char *cp, **wp;
3532 REGISTER int nb = 0;
3533 REGISTER int nl = 0;
3534
3535 if (t->words[1] == NULL) {
3536 err("Usage: read name ...");
3537 return (1);
3538 }
3539 for (wp = t->words + 1; *wp; wp++) {
3540 for (cp = e.linep; !nl && cp < elinep - 1; cp++)
3541 if ((nb = read(0, cp, sizeof(*cp))) != sizeof(*cp) ||
3542 (nl = (*cp == '\n')) || (wp[1] && any(*cp, ifs->value)))
3543 break;
3544 *cp = 0;
3545 if (nb <= 0)
3546 break;
3547 setval(lookup(*wp), e.linep);
3548 }
3549 return (nb <= 0);
3550}
3551
3552static int doeval(REGISTER struct op *t)
3553{
3554 return (RUN(awordlist, t->words + 1, wdchar));
3555}
3556
3557static int dotrap(REGISTER struct op *t)
3558{
3559 REGISTER int n, i;
3560 REGISTER int resetsig;
3561
3562 if (t->words[1] == NULL) {
3563 for (i = 0; i <= _NSIG; i++)
3564 if (trap[i]) {
3565 prn(i);
3566 prs(": ");
3567 prs(trap[i]);
3568 prs("\n");
3569 }
3570 return (0);
3571 }
3572 resetsig = isdigit(*t->words[1]);
3573 for (i = resetsig ? 1 : 2; t->words[i] != NULL; ++i) {
3574 n = getsig(t->words[i]);
3575 freecell(trap[n]);
3576 trap[n] = 0;
3577 if (!resetsig) {
3578 if (*t->words[1] != '\0') {
3579 trap[n] = strsave(t->words[1], 0);
3580 setsig(n, sig);
3581 } else
3582 setsig(n, SIG_IGN);
3583 } else {
3584 if (interactive)
3585 if (n == SIGINT)
3586 setsig(n, onintr);
3587 else
3588 setsig(n, n == SIGQUIT ? SIG_IGN : SIG_DFL);
3589 else
3590 setsig(n, SIG_DFL);
3591 }
3592 }
3593 return (0);
3594}
3595
3596static int getsig(char *s)
3597{
3598 REGISTER int n;
3599
3600 if ((n = getn(s)) < 0 || n > _NSIG) {
3601 err("trap: bad signal number");
3602 n = 0;
3603 }
3604 return (n);
3605}
3606
3607static void setsig(REGISTER int n, sighandler_t f)
3608{
3609 if (n == 0)
3610 return;
3611 if (signal(n, SIG_IGN) != SIG_IGN || ourtrap[n]) {
3612 ourtrap[n] = 1;
3613 signal(n, f);
3614 }
3615}
3616
3617static int getn(char *as)
3618{
3619 REGISTER char *s;
3620 REGISTER int n, m;
3621
3622 s = as;
3623 m = 1;
3624 if (*s == '-') {
3625 m = -1;
3626 s++;
3627 }
3628 for (n = 0; isdigit(*s); s++)
3629 n = (n * 10) + (*s - '0');
3630 if (*s) {
3631 prs(as);
3632 err(": bad number");
3633 }
3634 return (n * m);
3635}
3636
3637static int dobreak(struct op *t)
3638{
3639 return (brkcontin(t->words[1], 1));
3640}
3641
3642static int docontinue(struct op *t)
3643{
3644 return (brkcontin(t->words[1], 0));
3645}
3646
3647static int brkcontin(REGISTER char *cp, int val)
3648{
3649 REGISTER struct brkcon *bc;
3650 REGISTER int nl;
3651
3652 nl = cp == NULL ? 1 : getn(cp);
3653 if (nl <= 0)
3654 nl = 999;
3655 do {
3656 if ((bc = brklist) == NULL)
3657 break;
3658 brklist = bc->nextlev;
3659 } while (--nl);
3660 if (nl) {
3661 err("bad break/continue level");
3662 return (1);
3663 }
3664 isbreak = val;
3665 longjmp(bc->brkpt, 1);
3666 /* NOTREACHED */
3667}
3668
3669static int doexit(struct op *t)
3670{
3671 REGISTER char *cp;
3672
3673 execflg = 0;
3674 if ((cp = t->words[1]) != NULL)
3675 setstatus(getn(cp));
3676
3677 DBGPRINTF(("DOEXIT: calling leave(), t=%p\n", t));
3678
3679 leave();
3680 /* NOTREACHED */
3681 return (0);
3682}
3683
3684static int doexport(struct op *t)
3685{
3686 rdexp(t->words + 1, export, EXPORT);
3687 return (0);
3688}
3689
3690static int doreadonly(struct op *t)
3691{
3692 rdexp(t->words + 1, ronly, RONLY);
3693 return (0);
3694}
3695
3696static void rdexp(char **wp, void (*f) (struct var *), int key)
3697{
3698 DBGPRINTF6(("RDEXP: enter, wp=%p, func=%p, key=%d\n", wp, f, key));
3699 DBGPRINTF6(("RDEXP: *wp=%s\n", *wp));
3700
3701 if (*wp != NULL) {
3702 for (; *wp != NULL; wp++) {
3703 if (isassign(*wp)) {
3704 char *cp;
3705
3706 assign(*wp, COPYV);
3707 for (cp = *wp; *cp != '='; cp++);
3708 *cp = '\0';
3709 }
3710 if (checkname(*wp))
3711 (*f) (lookup(*wp));
3712 else
3713 badid(*wp);
3714 }
3715 } else
3716 putvlist(key, 1);
3717}
3718
3719static void badid(REGISTER char *s)
3720{
3721 prs(s);
3722 err(": bad identifier");
3723}
3724
3725static int doset(REGISTER struct op *t)
3726{
3727 REGISTER struct var *vp;
3728 REGISTER char *cp;
3729 REGISTER int n;
3730
3731 if ((cp = t->words[1]) == NULL) {
3732 for (vp = vlist; vp; vp = vp->next)
3733 varput(vp->name, 1);
3734 return (0);
3735 }
3736 if (*cp == '-') {
3737 /* bad: t->words++; */
3738 for (n = 0; (t->words[n] = t->words[n + 1]) != NULL; n++);
3739 if (*++cp == 0)
3740 flag['x'] = flag['v'] = 0;
3741 else
3742 for (; *cp; cp++)
3743 switch (*cp) {
3744 case 'e':
3745 if (!interactive)
3746 flag['e']++;
3747 break;
3748
3749 default:
3750 if (*cp >= 'a' && *cp <= 'z')
3751 flag[(int) *cp]++;
3752 break;
3753 }
3754 setdash();
3755 }
3756 if (t->words[1]) {
3757 t->words[0] = dolv[0];
3758 for (n = 1; t->words[n]; n++)
3759 setarea((char *) t->words[n], 0);
3760 dolc = n - 1;
3761 dolv = t->words;
3762 setval(lookup("#"), putn(dolc));
3763 setarea((char *) (dolv - 1), 0);
3764 }
3765 return (0);
3766}
3767
3768static void varput(REGISTER char *s, int out)
3769{
3770 if (isalnum(*s) || *s == '_') {
3771 write(out, s, strlen(s));
3772 write(out, "\n", 1);
3773 }
3774}
3775
3776
3777/*
3778 * Copyright (c) 1999 Herbert Xu <herbert@debian.org>
3779 * This file contains code for the times builtin.
3780 */
3781static int dotimes(struct op *t)
3782{
3783 struct tms buf;
3784 long int clk_tck = sysconf(_SC_CLK_TCK);
3785
3786 times(&buf);
3787 printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n",
3788 (int) (buf.tms_utime / clk_tck / 60),
3789 ((double) buf.tms_utime) / clk_tck,
3790 (int) (buf.tms_stime / clk_tck / 60),
3791 ((double) buf.tms_stime) / clk_tck,
3792 (int) (buf.tms_cutime / clk_tck / 60),
3793 ((double) buf.tms_cutime) / clk_tck,
3794 (int) (buf.tms_cstime / clk_tck / 60),
3795 ((double) buf.tms_cstime) / clk_tck);
3796 return 0;
3797}
3798
3799
3800static int (*inbuilt(char *s)) (struct op *) {
3801 const struct builtincmd *bp;
3802
3803 for (bp = builtincmds; bp->name != NULL; bp++)
3804 if (strcmp(bp->name, s) == 0)
3805 return (bp->builtinfunc);
3806
3807 return (NULL);
3808}
3809
3810/* -------- eval.c -------- */
3811
3812/*
3813 * ${}
3814 * `command`
3815 * blank interpretation
3816 * quoting
3817 * glob
3818 */
3819
3820static char **eval(char **ap, int f)
3821{
3822 struct wdblock *wb;
3823 char **wp;
3824 char **wf;
3825 jmp_buf ev;
3826
3827#if __GNUC__
3828 /* Avoid longjmp clobbering */
3829 (void) &wp;
3830 (void) &ap;
3831#endif
3832
3833 DBGPRINTF4(("EVAL: enter, f=%d\n", f));
3834
3835 wp = NULL;
3836 wb = NULL;
3837 wf = NULL;
3838 if (newenv(setjmp(errpt = ev)) == 0) {
3839 while (*ap && isassign(*ap))
3840 expand(*ap++, &wb, f & ~DOGLOB);
3841 if (flag['k']) {
3842 for (wf = ap; *wf; wf++) {
3843 if (isassign(*wf))
3844 expand(*wf, &wb, f & ~DOGLOB);
3845 }
3846 }
3847 for (wb = addword((char *) 0, wb); *ap; ap++) {
3848 if (!flag['k'] || !isassign(*ap))
3849 expand(*ap, &wb, f & ~DOKEY);
3850 }
3851 wb = addword((char *) 0, wb);
3852 wp = getwords(wb);
3853 quitenv();
3854 } else
3855 gflg = 1;
3856
3857 return (gflg ? (char **) NULL : wp);
3858}
3859
3860/*
3861 * Make the exported environment from the exported
3862 * names in the dictionary. Keyword assignments
3863 * will already have been done.
3864 */
3865static char **makenv(int all, struct wdblock *wb)
3866{
3867 REGISTER struct var *vp;
3868
3869 DBGPRINTF5(("MAKENV: enter, all=%d\n", all));
3870
3871 for (vp = vlist; vp; vp = vp->next)
3872 if (all || vp->status & EXPORT)
3873 wb = addword(vp->name, wb);
3874 wb = addword((char *) 0, wb);
3875 return (getwords(wb));
3876}
3877
3878static char *evalstr(REGISTER char *cp, int f)
3879{
3880 struct wdblock *wb;
3881
3882 DBGPRINTF6(("EVALSTR: enter, cp=%p, f=%d\n", cp, f));
3883
3884 wb = NULL;
3885 if (expand(cp, &wb, f)) {
3886 if (wb == NULL || wb->w_nword == 0
3887 || (cp = wb->w_words[0]) == NULL)
3888 cp = "";
3889 DELETE(wb);
3890 } else
3891 cp = NULL;
3892 return (cp);
3893}
3894
3895static int expand(char *cp, REGISTER struct wdblock **wbp, int f)
3896{
3897 jmp_buf ev;
3898
3899#if __GNUC__
3900 /* Avoid longjmp clobbering */
3901 (void) &cp;
3902#endif
3903
3904 DBGPRINTF3(("EXPAND: enter, f=%d\n", f));
3905
3906 gflg = 0;
3907
3908 if (cp == NULL)
3909 return (0);
3910
3911 if (!anys("$`'\"", cp) &&
3912 !anys(ifs->value, cp) && ((f & DOGLOB) == 0 || !anys("[*?", cp))) {
3913 cp = strsave(cp, areanum);
3914 if (f & DOTRIM)
3915 unquote(cp);
3916 *wbp = addword(cp, *wbp);
3917 return (1);
3918 }
3919 if (newenv(setjmp(errpt = ev)) == 0) {
3920 PUSHIO(aword, cp, strchar);
3921 e.iobase = e.iop;
3922 while ((cp = blank(f)) && gflg == 0) {
3923 e.linep = cp;
3924 cp = strsave(cp, areanum);
3925 if ((f & DOGLOB) == 0) {
3926 if (f & DOTRIM)
3927 unquote(cp);
3928 *wbp = addword(cp, *wbp);
3929 } else
3930 *wbp = glob(cp, *wbp);
3931 }
3932 quitenv();
3933 } else
3934 gflg = 1;
3935 return (gflg == 0);
3936}
3937
3938/*
3939 * Blank interpretation and quoting
3940 */
3941static char *blank(int f)
3942{
3943 REGISTER int c, c1;
3944 REGISTER char *sp;
3945 int scanequals, foundequals;
3946
3947 DBGPRINTF3(("BLANK: enter, f=%d\n", f));
3948
3949 sp = e.linep;
3950 scanequals = f & DOKEY;
3951 foundequals = 0;
3952
3953 loop:
3954 switch (c = subgetc('"', foundequals)) {
3955 case 0:
3956 if (sp == e.linep)
3957 return (0);
3958 *e.linep++ = 0;
3959 return (sp);
3960
3961 default:
3962 if (f & DOBLANK && any(c, ifs->value))
3963 goto loop;
3964 break;
3965
3966 case '"':
3967 case '\'':
3968 scanequals = 0;
3969 if (INSUB())
3970 break;
3971 for (c1 = c; (c = subgetc(c1, 1)) != c1;) {
3972 if (c == 0)
3973 break;
3974 if (c == '\'' || !any(c, "$`\""))
3975 c |= QUOTE;
3976 *e.linep++ = c;
3977 }
3978 c = 0;
3979 }
3980 unget(c);
3981 if (!isalpha(c) && c != '_')
3982 scanequals = 0;
3983 for (;;) {
3984 c = subgetc('"', foundequals);
3985 if (c == 0 ||
3986 f & (DOBLANK && any(c, ifs->value)) ||
3987 (!INSUB() && any(c, "\"'"))) {
3988 scanequals = 0;
3989 unget(c);
3990 if (any(c, "\"'"))
3991 goto loop;
3992 break;
3993 }
3994 if (scanequals) {
3995 if (c == '=') {
3996 foundequals = 1;
3997 scanequals = 0;
3998 } else if (!isalnum(c) && c != '_')
3999 scanequals = 0;
4000 }
4001 *e.linep++ = c;
4002 }
4003 *e.linep++ = 0;
4004 return (sp);
4005}
4006
4007/*
4008 * Get characters, substituting for ` and $
4009 */
4010static int subgetc(REGISTER char ec, int quoted)
4011{
4012 REGISTER char c;
4013
4014 DBGPRINTF3(("SUBGETC: enter, quoted=%d\n", quoted));
4015
4016 again:
4017 c = my_getc(ec);
4018 if (!INSUB() && ec != '\'') {
4019 if (c == '`') {
4020 if (grave(quoted) == 0)
4021 return (0);
4022 e.iop->task = XGRAVE;
4023 goto again;
4024 }
4025 if (c == '$' && (c = dollar(quoted)) == 0) {
4026 e.iop->task = XDOLL;
4027 goto again;
4028 }
4029 }
4030 return (c);
4031}
4032
4033/*
4034 * Prepare to generate the string returned by ${} substitution.
4035 */
4036static int dollar(int quoted)
4037{
4038 int otask;
4039 struct io *oiop;
4040 char *dolp;
4041 REGISTER char *s, c, *cp = NULL;
4042 struct var *vp;
4043
4044 DBGPRINTF3(("DOLLAR: enter, quoted=%d\n", quoted));
4045
4046 c = readc();
4047 s = e.linep;
4048 if (c != '{') {
4049 *e.linep++ = c;
4050 if (isalpha(c) || c == '_') {
4051 while ((c = readc()) != 0 && (isalnum(c) || c == '_'))
4052 if (e.linep < elinep)
4053 *e.linep++ = c;
4054 unget(c);
4055 }
4056 c = 0;
4057 } else {
4058 oiop = e.iop;
4059 otask = e.iop->task;
4060
4061 e.iop->task = XOTHER;
4062 while ((c = subgetc('"', 0)) != 0 && c != '}' && c != '\n')
4063 if (e.linep < elinep)
4064 *e.linep++ = c;
4065 if (oiop == e.iop)
4066 e.iop->task = otask;
4067 if (c != '}') {
4068 err("unclosed ${");
4069 gflg++;
4070 return (c);
4071 }
4072 }
4073 if (e.linep >= elinep) {
4074 err("string in ${} too long");
4075 gflg++;
4076 e.linep -= 10;
4077 }
4078 *e.linep = 0;
4079 if (*s)
4080 for (cp = s + 1; *cp; cp++)
4081 if (any(*cp, "=-+?")) {
4082 c = *cp;
4083 *cp++ = 0;
4084 break;
4085 }
4086 if (s[1] == 0 && (*s == '*' || *s == '@')) {
4087 if (dolc > 1) {
4088 /* currently this does not distinguish $* and $@ */
4089 /* should check dollar */
4090 e.linep = s;
4091 PUSHIO(awordlist, dolv + 1, dolchar);
4092 return (0);
4093 } else { /* trap the nasty ${=} */
4094 s[0] = '1';
4095 s[1] = 0;
4096 }
4097 }
4098 vp = lookup(s);
4099 if ((dolp = vp->value) == null) {
4100 switch (c) {
4101 case '=':
4102 if (isdigit(*s)) {
4103 err("cannot use ${...=...} with $n");
4104 gflg++;
4105 break;
4106 }
4107 setval(vp, cp);
4108 dolp = vp->value;
4109 break;
4110
4111 case '-':
4112 dolp = strsave(cp, areanum);
4113 break;
4114
4115 case '?':
4116 if (*cp == 0) {
4117 prs("missing value for ");
4118 err(s);
4119 } else
4120 err(cp);
4121 gflg++;
4122 break;
4123 }
4124 } else if (c == '+')
4125 dolp = strsave(cp, areanum);
4126 if (flag['u'] && dolp == null) {
4127 prs("unset variable: ");
4128 err(s);
4129 gflg++;
4130 }
4131 e.linep = s;
4132 PUSHIO(aword, dolp, quoted ? qstrchar : strchar);
4133 return (0);
4134}
4135
4136/*
4137 * Run the command in `...` and read its output.
4138 */
4139
4140static int grave(int quoted)
4141{
4142 char *cp;
4143 REGISTER int i;
4144 int j;
4145 int pf[2];
4146 static char child_cmd[LINELIM];
4147 char *src;
4148 char *dest;
4149 int count;
4150 int ignore;
4151 int ignore_once;
4152 char *argument_list[4];
4153 struct wdblock *wb = NULL;
4154
4155#if __GNUC__
4156 /* Avoid longjmp clobbering */
4157 (void) &cp;
4158#endif
4159
4160 for (cp = e.iop->argp->aword; *cp != '`'; cp++)
4161 if (*cp == 0) {
4162 err("no closing `");
4163 return (0);
4164 }
4165
4166 /* string copy with dollar expansion */
4167 src = e.iop->argp->aword;
4168 dest = child_cmd;
4169 count = 0;
4170 ignore = 0;
4171 ignore_once = 0;
4172 while ((*src != '`') && (count < LINELIM)) {
4173 if (*src == '\'')
4174 ignore = !ignore;
4175 if (*src == '\\')
4176 ignore_once = 1;
4177 if (*src == '$' && !ignore && !ignore_once) {
4178 struct var *vp;
4179 char var_name[LINELIM];
4180 char alt_value[LINELIM];
4181 int var_index = 0;
4182 int alt_index = 0;
4183 char operator = 0;
4184 int braces = 0;
4185 char *value;
4186
4187 src++;
4188 if (*src == '{') {
4189 braces = 1;
4190 src++;
4191 }
4192
4193 var_name[var_index++] = *src++;
4194 while (isalnum(*src) || *src=='_')
4195 var_name[var_index++] = *src++;
4196 var_name[var_index] = 0;
4197
4198 if (braces) {
4199 switch (*src) {
4200 case '}':
4201 break;
4202 case '-':
4203 case '=':
4204 case '+':
4205 case '?':
4206 operator = * src;
4207 break;
4208 default:
4209 err("unclosed ${\n");
4210 return (0);
4211 }
4212 if (operator) {
4213 src++;
4214 while (*src && (*src != '}')) {
4215 alt_value[alt_index++] = *src++;
4216 }
4217 alt_value[alt_index] = 0;
4218 if (*src != '}') {
4219 err("unclosed ${\n");
4220 return (0);
4221 }
4222 }
4223 src++;
4224 }
4225
4226 if (isalpha(*var_name)) {
4227 /* let subshell handle it instead */
4228
4229 char *namep = var_name;
4230
4231 *dest++ = '$';
4232 if (braces)
4233 *dest++ = '{';
4234 while (*namep)
4235 *dest++ = *namep++;
4236 if (operator) {
4237 char *altp = alt_value;
4238 *dest++ = operator;
4239 while (*altp)
4240 *dest++ = *altp++;
4241 }
4242 if (braces)
4243 *dest++ = '}';
4244
4245 wb = addword(lookup(var_name)->name, wb);
4246 } else {
4247 /* expand */
4248
4249 vp = lookup(var_name);
4250 if (vp->value != null)
4251 value = (operator == '+') ?
4252 alt_value : vp->value;
4253 else if (operator == '?') {
4254 err(alt_value);
4255 return (0);
4256 } else if (alt_index && (operator != '+')) {
4257 value = alt_value;
4258 if (operator == '=')
4259 setval(vp, value);
4260 } else
4261 continue;
4262
4263 while (*value && (count < LINELIM)) {
4264 *dest++ = *value++;
4265 count++;
4266 }
4267 }
4268 } else {
4269 *dest++ = *src++;
4270 count++;
4271 ignore_once = 0;
4272 }
4273 }
4274 *dest = '\0';
4275
4276 if (openpipe(pf) < 0)
4277 return (0);
4278
4279 while ((i = vfork()) == -1 && errno == EAGAIN);
4280
4281 DBGPRINTF3(("GRAVE: i is %p\n", io));
4282
4283 if (i < 0) {
4284 closepipe(pf);
4285 err((char *) bb_msg_memory_exhausted);
4286 return (0);
4287 }
4288 if (i != 0) {
4289 waitpid(i, NULL, 0);
4290 e.iop->argp->aword = ++cp;
4291 close(pf[1]);
4292 PUSHIO(afile, remap(pf[0]),
4293 (int (*)(struct ioarg *)) ((quoted) ? qgravechar :
4294 gravechar));
4295 return (1);
4296 }
4297 /* allow trapped signals */
4298 /* XXX - Maybe this signal stuff should go as well? */
4299 for (j = 0; j <= _NSIG; j++)
4300 if (ourtrap[j] && signal(j, SIG_IGN) != SIG_IGN)
4301 signal(j, SIG_DFL);
4302
4303 dup2(pf[1], 1);
4304 closepipe(pf);
4305
4306 argument_list[0] = (char *) DEFAULT_SHELL;
4307 argument_list[1] = "-c";
4308 argument_list[2] = child_cmd;
4309 argument_list[3] = 0;
4310
4311 cp = rexecve(argument_list[0], argument_list, makenv(1, wb));
4312 prs(argument_list[0]);
4313 prs(": ");
4314 err(cp);
4315 _exit(1);
4316}
4317
4318
4319static char *unquote(REGISTER char *as)
4320{
4321 REGISTER char *s;
4322
4323 if ((s = as) != NULL)
4324 while (*s)
4325 *s++ &= ~QUOTE;
4326 return (as);
4327}
4328
4329/* -------- glob.c -------- */
4330
4331/*
4332 * glob
4333 */
4334
4335#define scopy(x) strsave((x), areanum)
4336#define BLKSIZ 512
4337#define NDENT ((BLKSIZ+sizeof(struct dirent)-1)/sizeof(struct dirent))
4338
4339static struct wdblock *cl, *nl;
4340static char spcl[] = "[?*";
4341
4342static struct wdblock *glob(char *cp, struct wdblock *wb)
4343{
4344 REGISTER int i;
4345 REGISTER char *pp;
4346
4347 if (cp == 0)
4348 return (wb);
4349 i = 0;
4350 for (pp = cp; *pp; pp++)
4351 if (any(*pp, spcl))
4352 i++;
4353 else if (!any(*pp & ~QUOTE, spcl))
4354 *pp &= ~QUOTE;
4355 if (i != 0) {
4356 for (cl = addword(scopy(cp), (struct wdblock *) 0); anyspcl(cl);
4357 cl = nl) {
4358 nl = newword(cl->w_nword * 2);
4359 for (i = 0; i < cl->w_nword; i++) { /* for each argument */
4360 for (pp = cl->w_words[i]; *pp; pp++)
4361 if (any(*pp, spcl)) {
4362 globname(cl->w_words[i], pp);
4363 break;
4364 }
4365 if (*pp == '\0')
4366 nl = addword(scopy(cl->w_words[i]), nl);
4367 }
4368 for (i = 0; i < cl->w_nword; i++)
4369 DELETE(cl->w_words[i]);
4370 DELETE(cl);
4371 }
4372 for (i = 0; i < cl->w_nword; i++)
4373 unquote(cl->w_words[i]);
4374 glob0((char *) cl->w_words, cl->w_nword, sizeof(char *), xstrcmp);
4375 if (cl->w_nword) {
4376 for (i = 0; i < cl->w_nword; i++)
4377 wb = addword(cl->w_words[i], wb);
4378 DELETE(cl);
4379 return (wb);
4380 }
4381 }
4382 wb = addword(unquote(cp), wb);
4383 return (wb);
4384}
4385
4386static void globname(char *we, REGISTER char *pp)
4387{
4388 REGISTER char *np, *cp;
4389 char *name, *gp, *dp;
4390 int k;
4391 DIR *dirp;
4392 struct dirent *de;
4393 char dname[NAME_MAX + 1];
4394 struct stat dbuf;
4395
4396 for (np = we; np != pp; pp--)
4397 if (pp[-1] == '/')
4398 break;
4399 for (dp = cp = space((int) (pp - np) + 3); np < pp;)
4400 *cp++ = *np++;
4401 *cp++ = '.';
4402 *cp = '\0';
4403 for (gp = cp = space(strlen(pp) + 1); *np && *np != '/';)
4404 *cp++ = *np++;
4405 *cp = '\0';
4406 dirp = opendir(dp);
4407 if (dirp == 0) {
4408 DELETE(dp);
4409 DELETE(gp);
4410 return;
4411 }
4412 dname[NAME_MAX] = '\0';
4413 while ((de = readdir(dirp)) != NULL) {
4414 /* XXX Hmmm... What this could be? (abial) */
4415 /*
4416 if (ent[j].d_ino == 0)
4417 continue;
4418 */
4419 strncpy(dname, de->d_name, NAME_MAX);
4420 if (dname[0] == '.')
4421 if (*gp != '.')
4422 continue;
4423 for (k = 0; k < NAME_MAX; k++)
4424 if (any(dname[k], spcl))
4425 dname[k] |= QUOTE;
4426 if (gmatch(dname, gp)) {
4427 name = generate(we, pp, dname, np);
4428 if (*np && !anys(np, spcl)) {
4429 if (stat(name, &dbuf)) {
4430 DELETE(name);
4431 continue;
4432 }
4433 }
4434 nl = addword(name, nl);
4435 }
4436 }
4437 closedir(dirp);
4438 DELETE(dp);
4439 DELETE(gp);
4440}
4441
4442/*
4443 * generate a pathname as below.
4444 * start..end1 / middle end
4445 * the slashes come for free
4446 */
4447static char *generate(char *start1, REGISTER char *end1, char *middle, char *end)
4448{
4449 char *p;
4450 REGISTER char *op, *xp;
4451
4452 p = op =
4453 space((int) (end1 - start1) + strlen(middle) + strlen(end) + 2);
4454 for (xp = start1; xp != end1;)
4455 *op++ = *xp++;
4456 for (xp = middle; (*op++ = *xp++) != '\0';);
4457 op--;
4458 for (xp = end; (*op++ = *xp++) != '\0';);
4459 return (p);
4460}
4461
4462static int anyspcl(REGISTER struct wdblock *wb)
4463{
4464 REGISTER int i;
4465 REGISTER char **wd;
4466
4467 wd = wb->w_words;
4468 for (i = 0; i < wb->w_nword; i++)
4469 if (anys(spcl, *wd++))
4470 return (1);
4471 return (0);
4472}
4473
4474static int xstrcmp(char *p1, char *p2)
4475{
4476 return (strcmp(*(char **) p1, *(char **) p2));
4477}
4478
4479/* -------- word.c -------- */
4480
4481static struct wdblock *newword(REGISTER int nw)
4482{
4483 REGISTER struct wdblock *wb;
4484
4485 wb = (struct wdblock *) space(sizeof(*wb) + nw * sizeof(char *));
4486 wb->w_bsize = nw;
4487 wb->w_nword = 0;
4488 return (wb);
4489}
4490
4491static struct wdblock *addword(char *wd, REGISTER struct wdblock *wb)
4492{
4493 REGISTER struct wdblock *wb2;
4494 REGISTER int nw;
4495
4496 if (wb == NULL)
4497 wb = newword(NSTART);
4498 if ((nw = wb->w_nword) >= wb->w_bsize) {
4499 wb2 = newword(nw * 2);
4500 memcpy((char *) wb2->w_words, (char *) wb->w_words,
4501 nw * sizeof(char *));
4502 wb2->w_nword = nw;
4503 DELETE(wb);
4504 wb = wb2;
4505 }
4506 wb->w_words[wb->w_nword++] = wd;
4507 return (wb);
4508}
4509
4510static
4511char **getwords(REGISTER struct wdblock *wb)
4512{
4513 REGISTER char **wd;
4514 REGISTER int nb;
4515
4516 if (wb == NULL)
4517 return ((char **) NULL);
4518 if (wb->w_nword == 0) {
4519 DELETE(wb);
4520 return ((char **) NULL);
4521 }
4522 wd = (char **) space(nb = sizeof(*wd) * wb->w_nword);
4523 memcpy((char *) wd, (char *) wb->w_words, nb);
4524 DELETE(wb); /* perhaps should done by caller */
4525 return (wd);
4526}
4527
4528static int (*func) (char *, char *);
4529static int globv;
4530
4531static void glob0(char *a0, unsigned a1, int a2, int (*a3) (char *, char *))
4532{
4533 func = a3;
4534 globv = a2;
4535 glob1(a0, a0 + a1 * a2);
4536}
4537
4538static void glob1(char *base, char *lim)
4539{
4540 REGISTER char *i, *j;
4541 int v2;
4542 char *lptr, *hptr;
4543 int c;
4544 unsigned n;
4545
4546
4547 v2 = globv;
4548
4549 top:
4550 if ((n = (int) (lim - base)) <= v2)
4551 return;
4552 n = v2 * (n / (2 * v2));
4553 hptr = lptr = base + n;
4554 i = base;
4555 j = lim - v2;
4556 for (;;) {
4557 if (i < lptr) {
4558 if ((c = (*func) (i, lptr)) == 0) {
4559 glob2(i, lptr -= v2);
4560 continue;
4561 }
4562 if (c < 0) {
4563 i += v2;
4564 continue;
4565 }
4566 }
4567
4568 begin:
4569 if (j > hptr) {
4570 if ((c = (*func) (hptr, j)) == 0) {
4571 glob2(hptr += v2, j);
4572 goto begin;
4573 }
4574 if (c > 0) {
4575 if (i == lptr) {
4576 glob3(i, hptr += v2, j);
4577 i = lptr += v2;
4578 goto begin;
4579 }
4580 glob2(i, j);
4581 j -= v2;
4582 i += v2;
4583 continue;
4584 }
4585 j -= v2;
4586 goto begin;
4587 }
4588
4589
4590 if (i == lptr) {
4591 if (lptr - base >= lim - hptr) {
4592 glob1(hptr + v2, lim);
4593 lim = lptr;
4594 } else {
4595 glob1(base, lptr);
4596 base = hptr + v2;
4597 }
4598 goto top;
4599 }
4600
4601
4602 glob3(j, lptr -= v2, i);
4603 j = hptr -= v2;
4604 }
4605}
4606
4607static void glob2(char *i, char *j)
4608{
4609 REGISTER char *index1, *index2, c;
4610 int m;
4611
4612 m = globv;
4613 index1 = i;
4614 index2 = j;
4615 do {
4616 c = *index1;
4617 *index1++ = *index2;
4618 *index2++ = c;
4619 } while (--m);
4620}
4621
4622static void glob3(char *i, char *j, char *k)
4623{
4624 REGISTER char *index1, *index2, *index3;
4625 int c;
4626 int m;
4627
4628 m = globv;
4629 index1 = i;
4630 index2 = j;
4631 index3 = k;
4632 do {
4633 c = *index1;
4634 *index1++ = *index3;
4635 *index3++ = *index2;
4636 *index2++ = c;
4637 } while (--m);
4638}
4639
4640/* -------- io.c -------- */
4641
4642/*
4643 * shell IO
4644 */
4645
4646static int my_getc(int ec)
4647{
4648 REGISTER int c;
4649
4650 if (e.linep > elinep) {
4651 while ((c = readc()) != '\n' && c);
4652 err("input line too long");
4653 gflg++;
4654 return (c);
4655 }
4656 c = readc();
4657 if ((ec != '\'') && (ec != '`') && (e.iop->task != XGRAVE)) {
4658 if (c == '\\') {
4659 c = readc();
4660 if (c == '\n' && ec != '\"')
4661 return (my_getc(ec));
4662 c |= QUOTE;
4663 }
4664 }
4665 return (c);
4666}
4667
4668static void unget(int c)
4669{
4670 if (e.iop >= e.iobase)
4671 e.iop->peekc = c;
4672}
4673
4674static int eofc(void)
4675{
4676 return e.iop < e.iobase || (e.iop->peekc == 0 && e.iop->prev == 0);
4677}
4678
4679static int readc(void)
4680{
4681 REGISTER int c;
4682
4683 RCPRINTF(("READC: e.iop %p, e.iobase %p\n", e.iop, e.iobase));
4684
4685 for (; e.iop >= e.iobase; e.iop--) {
4686 RCPRINTF(("READC: e.iop %p, peekc 0x%x\n", e.iop, e.iop->peekc));
4687 if ((c = e.iop->peekc) != '\0') {
4688 e.iop->peekc = 0;
4689 return (c);
4690 } else {
4691 if (e.iop->prev != 0) {
4692 if ((c = (*e.iop->iofn) (e.iop->argp, e.iop)) != '\0') {
4693 if (c == -1) {
4694 e.iop++;
4695 continue;
4696 }
4697 if (e.iop == iostack)
4698 ioecho(c);
4699 return (e.iop->prev = c);
4700 } else if (e.iop->task == XIO && e.iop->prev != '\n') {
4701 e.iop->prev = 0;
4702 if (e.iop == iostack)
4703 ioecho('\n');
4704 return '\n';
4705 }
4706 }
4707 if (e.iop->task == XIO) {
4708 if (multiline) {
4709 return e.iop->prev = 0;
4710 }
4711 if (interactive && e.iop == iostack + 1) {
4712#ifdef CONFIG_FEATURE_COMMAND_EDITING
4713 current_prompt = prompt->value;
4714#else
4715 prs(prompt->value);
4716#endif
4717 }
4718 }
4719 }
4720
4721 } /* FOR */
4722
4723 if (e.iop >= iostack) {
4724 RCPRINTF(("READC: return 0, e.iop %p\n", e.iop));
4725 return (0);
4726 }
4727
4728 DBGPRINTF(("READC: leave()...\n"));
4729 leave();
4730
4731 /* NOTREACHED */
4732 return (0);
4733}
4734
4735static void ioecho(char c)
4736{
4737 if (flag['v'])
4738 write(2, &c, sizeof c);
4739}
4740
4741
4742static void pushio(struct ioarg *argp, int (*fn) (struct ioarg *))
4743{
4744 DBGPRINTF(("PUSHIO: argp %p, argp->afid 0x%x, e.iop %p\n", argp,
4745 argp->afid, e.iop));
4746
4747 /* Set env ptr for io source to next array spot and check for array overflow */
4748 if (++e.iop >= &iostack[NPUSH]) {
4749 e.iop--;
4750 err("Shell input nested too deeply");
4751 gflg++;
4752 return;
4753 }
4754
4755 /* We did not overflow the NPUSH array spots so setup data structs */
4756
4757 e.iop->iofn = (int (*)(struct ioarg *, struct io *)) fn; /* Store data source func ptr */
4758
4759 if (argp->afid != AFID_NOBUF)
4760 e.iop->argp = argp;
4761 else {
4762
4763 e.iop->argp = ioargstack + (e.iop - iostack); /* MAL - index into stack */
4764 *e.iop->argp = *argp; /* copy data from temp area into stack spot */
4765
4766 /* MAL - mainbuf is for 1st data source (command line?) and all nested use a single shared buffer? */
4767
4768 if (e.iop == &iostack[0])
4769 e.iop->argp->afbuf = &mainbuf;
4770 else
4771 e.iop->argp->afbuf = &sharedbuf;
4772
4773 /* MAL - if not a termimal AND (commandline OR readable file) then give it a buffer id? */
4774 /* This line appears to be active when running scripts from command line */
4775 if ((isatty(e.iop->argp->afile) == 0)
4776 && (e.iop == &iostack[0]
4777 || lseek(e.iop->argp->afile, 0L, 1) != -1)) {
4778 if (++bufid == AFID_NOBUF) /* counter rollover check, AFID_NOBUF = 11111111 */
4779 bufid = AFID_ID; /* AFID_ID = 0 */
4780
4781 e.iop->argp->afid = bufid; /* assign buffer id */
4782 }
4783
4784 DBGPRINTF(("PUSHIO: iostack %p, e.iop %p, afbuf %p\n",
4785 iostack, e.iop, e.iop->argp->afbuf));
4786 DBGPRINTF(("PUSHIO: mbuf %p, sbuf %p, bid %d, e.iop %p\n",
4787 &mainbuf, &sharedbuf, bufid, e.iop));
4788
4789 }
4790
4791 e.iop->prev = ~'\n';
4792 e.iop->peekc = 0;
4793 e.iop->xchar = 0;
4794 e.iop->nlcount = 0;
4795
4796 if (fn == filechar || fn == linechar)
4797 e.iop->task = XIO;
4798 else if (fn == (int (*)(struct ioarg *)) gravechar
4799 || fn == (int (*)(struct ioarg *)) qgravechar)
4800 e.iop->task = XGRAVE;
4801 else
4802 e.iop->task = XOTHER;
4803
4804 return;
4805}
4806
4807static struct io *setbase(struct io *ip)
4808{
4809 REGISTER struct io *xp;
4810
4811 xp = e.iobase;
4812 e.iobase = ip;
4813 return (xp);
4814}
4815
4816/*
4817 * Input generating functions
4818 */
4819
4820/*
4821 * Produce the characters of a string, then a newline, then EOF.
4822 */
4823static int nlchar(REGISTER struct ioarg *ap)
4824{
4825 REGISTER int c;
4826
4827 if (ap->aword == NULL)
4828 return (0);
4829 if ((c = *ap->aword++) == 0) {
4830 ap->aword = NULL;
4831 return ('\n');
4832 }
4833 return (c);
4834}
4835
4836/*
4837 * Given a list of words, produce the characters
4838 * in them, with a space after each word.
4839 */
4840static int wdchar(REGISTER struct ioarg *ap)
4841{
4842 REGISTER char c;
4843 REGISTER char **wl;
4844
4845 if ((wl = ap->awordlist) == NULL)
4846 return (0);
4847 if (*wl != NULL) {
4848 if ((c = *(*wl)++) != 0)
4849 return (c & 0177);
4850 ap->awordlist++;
4851 return (' ');
4852 }
4853 ap->awordlist = NULL;
4854 return ('\n');
4855}
4856
4857/*
4858 * Return the characters of a list of words,
4859 * producing a space between them.
4860 */
4861static int dolchar(REGISTER struct ioarg *ap)
4862{
4863 REGISTER char *wp;
4864
4865 if ((wp = *ap->awordlist++) != NULL) {
4866 PUSHIO(aword, wp, *ap->awordlist == NULL ? strchar : xxchar);
4867 return (-1);
4868 }
4869 return (0);
4870}
4871
4872static int xxchar(REGISTER struct ioarg *ap)
4873{
4874 REGISTER int c;
4875
4876 if (ap->aword == NULL)
4877 return (0);
4878 if ((c = *ap->aword++) == '\0') {
4879 ap->aword = NULL;
4880 return (' ');
4881 }
4882 return (c);
4883}
4884
4885/*
4886 * Produce the characters from a single word (string).
4887 */
4888static int strchar(REGISTER struct ioarg *ap)
4889{
4890 REGISTER int c;
4891
4892 if (ap->aword == NULL || (c = *ap->aword++) == 0)
4893 return (0);
4894 return (c);
4895}
4896
4897/*
4898 * Produce quoted characters from a single word (string).
4899 */
4900static int qstrchar(REGISTER struct ioarg *ap)
4901{
4902 REGISTER int c;
4903
4904 if (ap->aword == NULL || (c = *ap->aword++) == 0)
4905 return (0);
4906 return (c | QUOTE);
4907}
4908
4909/*
4910 * Return the characters from a file.
4911 */
4912static int filechar(REGISTER struct ioarg *ap)
4913{
4914 REGISTER int i;
4915 char c;
4916 struct iobuf *bp = ap->afbuf;
4917
4918 if (ap->afid != AFID_NOBUF) {
4919 if ((i = ap->afid != bp->id) || bp->bufp == bp->ebufp) {
4920
4921 if (i)
4922 lseek(ap->afile, ap->afpos, 0);
4923
4924 i = safe_read(ap->afile, bp->buf, sizeof(bp->buf));
4925
4926 if (i <= 0) {
4927 closef(ap->afile);
4928 return 0;
4929 }
4930
4931 bp->id = ap->afid;
4932 bp->ebufp = (bp->bufp = bp->buf) + i;
4933 }
4934
4935 ap->afpos++;
4936 return *bp->bufp++ & 0177;
4937 }
4938#ifdef CONFIG_FEATURE_COMMAND_EDITING
4939 if (interactive && isatty(ap->afile)) {
4940 static char mycommand[BUFSIZ];
4941 static int position = 0, size = 0;
4942
4943 while (size == 0 || position >= size) {
4944 cmdedit_read_input(current_prompt, mycommand);
4945 size = strlen(mycommand);
4946 position = 0;
4947 }
4948 c = mycommand[position];
4949 position++;
4950 return (c);
4951 } else
4952#endif
4953
4954 {
4955 i = safe_read(ap->afile, &c, sizeof(c));
4956 return (i == sizeof(c) ? (c & 0x7f) : (closef(ap->afile), 0));
4957 }
4958}
4959
4960/*
4961 * Return the characters from a here temp file.
4962 */
4963static int herechar(REGISTER struct ioarg *ap)
4964{
4965 char c;
4966
4967
4968 if (read(ap->afile, &c, sizeof(c)) != sizeof(c)) {
4969 close(ap->afile);
4970 c = 0;
4971 }
4972 return (c);
4973
4974}
4975
4976/*
4977 * Return the characters produced by a process (`...`).
4978 * Quote them if required, and remove any trailing newline characters.
4979 */
4980static int gravechar(struct ioarg *ap, struct io *iop)
4981{
4982 REGISTER int c;
4983
4984 if ((c = qgravechar(ap, iop) & ~QUOTE) == '\n')
4985 c = ' ';
4986 return (c);
4987}
4988
4989static int qgravechar(REGISTER struct ioarg *ap, struct io *iop)
4990{
4991 REGISTER int c;
4992
4993 DBGPRINTF3(("QGRAVECHAR: enter, ap=%p, iop=%p\n", ap, iop));
4994
4995 if (iop->xchar) {
4996 if (iop->nlcount) {
4997 iop->nlcount--;
4998 return ('\n' | QUOTE);
4999 }
5000 c = iop->xchar;
5001 iop->xchar = 0;
5002 } else if ((c = filechar(ap)) == '\n') {
5003 iop->nlcount = 1;
5004 while ((c = filechar(ap)) == '\n')
5005 iop->nlcount++;
5006 iop->xchar = c;
5007 if (c == 0)
5008 return (c);
5009 iop->nlcount--;
5010 c = '\n';
5011 }
5012 return (c != 0 ? c | QUOTE : 0);
5013}
5014
5015/*
5016 * Return a single command (usually the first line) from a file.
5017 */
5018static int linechar(REGISTER struct ioarg *ap)
5019{
5020 REGISTER int c;
5021
5022 if ((c = filechar(ap)) == '\n') {
5023 if (!multiline) {
5024 closef(ap->afile);
5025 ap->afile = -1; /* illegal value */
5026 }
5027 }
5028 return (c);
5029}
5030
5031static void prs(REGISTER const char *s)
5032{
5033 if (*s)
5034 write(2, s, strlen(s));
5035}
5036
5037static void prn(unsigned u)
5038{
5039 prs(itoa(u));
5040}
5041
5042static void closef(REGISTER int i)
5043{
5044 if (i > 2)
5045 close(i);
5046}
5047
5048static void closeall(void)
5049{
5050 REGISTER int u;
5051
5052 for (u = NUFILE; u < NOFILE;)
5053 close(u++);
5054}
5055
5056
5057/*
5058 * remap fd into Shell's fd space
5059 */
5060static int remap(REGISTER int fd)
5061{
5062 REGISTER int i;
5063 int map[NOFILE];
5064 int newfd;
5065
5066
5067 DBGPRINTF(("REMAP: fd=%d, e.iofd=%d\n", fd, e.iofd));
5068
5069 if (fd < e.iofd) {
5070 for (i = 0; i < NOFILE; i++)
5071 map[i] = 0;
5072
5073 do {
5074 map[fd] = 1;
5075 newfd = dup(fd);
5076 fd = newfd;
5077 } while (fd >= 0 && fd < e.iofd);
5078
5079 for (i = 0; i < NOFILE; i++)
5080 if (map[i])
5081 close(i);
5082
5083 if (fd < 0)
5084 err("too many files open in shell");
5085 }
5086
5087 return (fd);
5088}
5089
5090static int openpipe(REGISTER int *pv)
5091{
5092 REGISTER int i;
5093
5094 if ((i = pipe(pv)) < 0)
5095 err("can't create pipe - try again");
5096 return (i);
5097}
5098
5099static void closepipe(REGISTER int *pv)
5100{
5101 if (pv != NULL) {
5102 close(*pv++);
5103 close(*pv);
5104 }
5105}
5106
5107/* -------- here.c -------- */
5108
5109/*
5110 * here documents
5111 */
5112
5113static void markhere(REGISTER char *s, struct ioword *iop)
5114{
5115 REGISTER struct here *h, *lh;
5116
5117 DBGPRINTF7(("MARKHERE: enter, s=%p\n", s));
5118
5119 h = (struct here *) space(sizeof(struct here));
5120 if (h == 0)
5121 return;
5122
5123 h->h_tag = evalstr(s, DOSUB);
5124 if (h->h_tag == 0)
5125 return;
5126
5127 h->h_iop = iop;
5128 iop->io_name = 0;
5129 h->h_next = NULL;
5130 if (inhere == 0)
5131 inhere = h;
5132 else
5133 for (lh = inhere; lh != NULL; lh = lh->h_next)
5134 if (lh->h_next == 0) {
5135 lh->h_next = h;
5136 break;
5137 }
5138 iop->io_flag |= IOHERE | IOXHERE;
5139 for (s = h->h_tag; *s; s++)
5140 if (*s & QUOTE) {
5141 iop->io_flag &= ~IOXHERE;
5142 *s &= ~QUOTE;
5143 }
5144 h->h_dosub = iop->io_flag & IOXHERE;
5145}
5146
5147static void gethere(void)
5148{
5149 REGISTER struct here *h, *hp;
5150
5151 DBGPRINTF7(("GETHERE: enter...\n"));
5152
5153 /* Scan here files first leaving inhere list in place */
5154 for (hp = h = inhere; h != NULL; hp = h, h = h->h_next)
5155 readhere(&h->h_iop->io_name, h->h_tag, h->h_dosub ? 0 : '\'');
5156
5157 /* Make inhere list active - keep list intact for scraphere */
5158 if (hp != NULL) {
5159 hp->h_next = acthere;
5160 acthere = inhere;
5161 inhere = NULL;
5162 }
5163}
5164
5165static void readhere(char **name, REGISTER char *s, int ec)
5166{
5167 int tf;
5168 char tname[30] = ".msh_XXXXXX";
5169 REGISTER int c;
5170 jmp_buf ev;
5171 char myline[LINELIM + 1];
5172 char *thenext;
5173
5174 DBGPRINTF7(("READHERE: enter, name=%p, s=%p\n", name, s));
5175
5176 tf = mkstemp(tname);
5177 if (tf < 0)
5178 return;
5179
5180 *name = strsave(tname, areanum);
5181 if (newenv(setjmp(errpt = ev)) != 0)
5182 unlink(tname);
5183 else {
5184 pushio(e.iop->argp, (int (*)(struct ioarg *)) e.iop->iofn);
5185 e.iobase = e.iop;
5186 for (;;) {
5187 if (interactive && e.iop <= iostack) {
5188#ifdef CONFIG_FEATURE_COMMAND_EDITING
5189 current_prompt = cprompt->value;
5190#else
5191 prs(cprompt->value);
5192#endif
5193 }
5194 thenext = myline;
5195 while ((c = my_getc(ec)) != '\n' && c) {
5196 if (ec == '\'')
5197 c &= ~QUOTE;
5198 if (thenext >= &myline[LINELIM]) {
5199 c = 0;
5200 break;
5201 }
5202 *thenext++ = c;
5203 }
5204 *thenext = 0;
5205 if (strcmp(s, myline) == 0 || c == 0)
5206 break;
5207 *thenext++ = '\n';
5208 write(tf, myline, (int) (thenext - myline));
5209 }
5210 if (c == 0) {
5211 prs("here document `");
5212 prs(s);
5213 err("' unclosed");
5214 }
5215 quitenv();
5216 }
5217 close(tf);
5218}
5219
5220/*
5221 * open here temp file.
5222 * if unquoted here, expand here temp file into second temp file.
5223 */
5224static int herein(char *hname, int xdoll)
5225{
5226 REGISTER int hf;
5227 int tf;
5228
5229#if __GNUC__
5230 /* Avoid longjmp clobbering */
5231 (void) &tf;
5232#endif
5233 if (hname == NULL)
5234 return (-1);
5235
5236 DBGPRINTF7(("HEREIN: hname is %s, xdoll=%d\n", hname, xdoll));
5237
5238 hf = open(hname, 0);
5239 if (hf < 0)
5240 return (-1);
5241
5242 if (xdoll) {
5243 char c;
5244 char tname[30] = ".msh_XXXXXX";
5245 jmp_buf ev;
5246
5247 tf = mkstemp(tname);
5248 if (tf < 0)
5249 return (-1);
5250 if (newenv(setjmp(errpt = ev)) == 0) {
5251 PUSHIO(afile, hf, herechar);
5252 setbase(e.iop);
5253 while ((c = subgetc(0, 0)) != 0) {
5254 c &= ~QUOTE;
5255 write(tf, &c, sizeof c);
5256 }
5257 quitenv();
5258 } else
5259 unlink(tname);
5260 close(tf);
5261 tf = open(tname, 0);
5262 unlink(tname);
5263 return (tf);
5264 } else
5265 return (hf);
5266}
5267
5268static void scraphere(void)
5269{
5270 REGISTER struct here *h;
5271
5272 DBGPRINTF7(("SCRAPHERE: enter...\n"));
5273
5274 for (h = inhere; h != NULL; h = h->h_next) {
5275 if (h->h_iop && h->h_iop->io_name)
5276 unlink(h->h_iop->io_name);
5277 }
5278 inhere = NULL;
5279}
5280
5281/* unlink here temp files before a freearea(area) */
5282static void freehere(int area)
5283{
5284 REGISTER struct here *h, *hl;
5285
5286 DBGPRINTF6(("FREEHERE: enter, area=%d\n", area));
5287
5288 hl = NULL;
5289 for (h = acthere; h != NULL; h = h->h_next)
5290 if (getarea((char *) h) >= area) {
5291 if (h->h_iop->io_name != NULL)
5292 unlink(h->h_iop->io_name);
5293 if (hl == NULL)
5294 acthere = h->h_next;
5295 else
5296 hl->h_next = h->h_next;
5297 } else
5298 hl = h;
5299}
5300
5301
5302
5303/*
5304 * Copyright (c) 1987,1997, Prentice Hall
5305 * All rights reserved.
5306 *
5307 * Redistribution and use of the MINIX operating system in source and
5308 * binary forms, with or without modification, are permitted provided
5309 * that the following conditions are met:
5310 *
5311 * Redistributions of source code must retain the above copyright
5312 * notice, this list of conditions and the following disclaimer.
5313 *
5314 * Redistributions in binary form must reproduce the above
5315 * copyright notice, this list of conditions and the following
5316 * disclaimer in the documentation and/or other materials provided
5317 * with the distribution.
5318 *
5319 * Neither the name of Prentice Hall nor the names of the software
5320 * authors or contributors may be used to endorse or promote
5321 * products derived from this software without specific prior
5322 * written permission.
5323 *
5324 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND
5325 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
5326 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
5327 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
5328 * IN NO EVENT SHALL PRENTICE HALL OR ANY AUTHORS OR CONTRIBUTORS BE
5329 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
5330 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
5331 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
5332 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
5333 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
5334 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
5335 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5336 *
5337 */
Note: See TracBrowser for help on using the repository browser.