Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


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