Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


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