Magellan Linux

Contents of /trunk/mkinitrd-magellan/busybox/shell/msh.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 532 - (show annotations) (download)
Sat Sep 1 22:45:15 2007 UTC (16 years, 8 months ago) by niro
File MIME type: text/plain
File size: 99118 byte(s)
-import if magellan mkinitrd; it is a fork of redhats mkinitrd-5.0.8 with all magellan patches and features; deprecates magellan-src/mkinitrd

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