1
2
3
4
5
6
7
8
9
10
11
12
13
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__))
47static int find_applet_by_name(const char *applet)
48{
49 return -1;
50}
51static 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}
69static 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}
78static char local_buf[12];
79static 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"
86#endif
87
88
89
90#ifdef MSHDEBUG
91static 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
105static 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
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
138
139
140
141
142#define LINELIM 2100
143#define NPUSH 8
144
145#undef NOFILE
146#define NOFILE 20
147#define NUFILE 10
148#define FDBASE 10
149
150
151
152
153#define WAITSIG(s) ((s) & 0177)
154#define WAITVAL(s) (((s) >> 8) & 0377)
155#define WAITCORE(s) (((s) & 0200) != 0)
156
157
158
159
160typedef void xint;
161
162
163
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
172
173struct ioword {
174 smallint io_flag;
175 int io_fd;
176 char *io_name;
177};
178
179#define IOREAD 1
180#define IOHERE 2
181#define IOWRITE 4
182#define IOCAT 8
183#define IOXHERE 16
184#define IODUP 32
185#define IOCLOSE 64
186
187#define IODEFAULT (-1)
188
189
190
191
192
193
194struct op {
195 smallint op_type;
196 char **op_words;
197 struct ioword **ioact;
198 struct op *left;
199 struct op *right;
200 char *str;
201};
202
203#define TCOM 1
204#define TPAREN 2
205#define TPIPE 3
206#define TLIST 4
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
217#define TBRACE 15
218#define TASYNC 16
219
220#define TDOT 17
221
222
223#ifdef MSHDEBUG
224static 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
250
251#define DOSUB 1
252#define DOBLANK 2
253#define DOGLOB 4
254#define DOKEY 8
255#define DOTRIM 16
256
257#define DOALL (DOSUB|DOBLANK|DOGLOB|DOKEY|DOTRIM)
258
259
260struct brkcon {
261 jmp_buf brkpt;
262 struct brkcon *nextlev;
263};
264
265
266static smallint trapset;
267
268static smallint yynerrs;
269
270
271
272#if ENABLE_FEATURE_EDITING
273static char *current_prompt;
274static line_input_t *line_input_state;
275#endif
276
277
278
279
280
281static const char *rexecve(char *c, char **v, char **envp);
282static char *evalstr(char *cp, int f);
283static char *putn(int n);
284static char *unquote(char *as);
285static int rlookup(char *n);
286static struct wdblock *glob(char *cp, struct wdblock *wb);
287static int my_getc(int ec);
288static int subgetc(char ec, int quoted);
289static char **makenv(int all, struct wdblock *wb);
290static char **eval(char **ap, int f);
291static int setstatus(int s);
292static int waitfor(int lastpid, int canintr);
293
294static void onintr(int s);
295
296static int newenv(int f);
297static void quitenv(void);
298static void next(int f);
299static void setdash(void);
300static void onecommand(void);
301static void runtrap(int i);
302
303
304
305
306#define REGSIZE sizeof(struct region)
307#define GROWBY (256)
308
309#undef SHRINKBY
310#define FREE (32767)
311#define BUSY (0)
312#define ALIGN (sizeof(int)-1)
313
314
315struct region {
316 struct region *next;
317 int area;
318};
319
320
321
322typedef 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
347#define DOT 273
348
349#define YYERRCODE 300
350
351
352#define CONTIN 01
353
354static struct op *pipeline(int cf);
355static struct op *andor(void);
356static struct op *c_list(void);
357static int synio(int cf);
358static void musthave(int c, int cf);
359static struct op *simple(void);
360static struct op *nested(int type, int mark);
361static struct op *command(int cf);
362static struct op *dogroup(int onlydone);
363static struct op *thenpart(void);
364static struct op *elsepart(void);
365static struct op *caselist(void);
366static struct op *casepart(void);
367static char **pattern(void);
368static char **wordlist(void);
369static struct op *list(struct op *t1, struct op *t2);
370static struct op *block(int type, struct op *t1, struct op *t2, char **wp);
371static struct op *newtp(void);
372static struct op *namelist(struct op *t);
373static char **copyw(void);
374static void word(char *cp);
375static struct ioword **copyio(void);
376static struct ioword *io(int u, int f, char *cp);
377static int yylex(int cf);
378static int collect(int c, int c1);
379static int dual(int c);
380static void diag(int ec);
381static char *tree(unsigned size);
382
383
384
385struct var {
386 char *value;
387 char *name;
388 struct var *next;
389 char status;
390};
391
392#define COPYV 1
393#define RONLY 01
394#define EXPORT 02
395#define GETCELL 04
396
397static int yyparse(void);
398
399
400
401
402struct iobuf {
403 unsigned id;
404 char buf[512];
405 char *bufp;
406 char *ebufp;
407};
408
409
410struct ioarg {
411 const char *aword;
412 char **awordlist;
413 int afile;
414 unsigned afid;
415 off_t afpos;
416 struct iobuf *afbuf;
417};
418
419
420struct io {
421 int (*iofn) (struct ioarg *, struct io *);
422 struct ioarg *argp;
423 int peekc;
424 char prev;
425 char nlcount;
426 char xchar;
427 char task;
428};
429
430#define XOTHER 0
431#define XDOLL 1
432#define XGRAVE 2
433#define XIO 3
434
435
436
437
438
439static int nlchar(struct ioarg *ap);
440static int strchar(struct ioarg *ap);
441static int qstrchar(struct ioarg *ap);
442static int filechar(struct ioarg *ap);
443static int herechar(struct ioarg *ap);
444static int linechar(struct ioarg *ap);
445static int gravechar(struct ioarg *ap, struct io *iop);
446static int qgravechar(struct ioarg *ap, struct io *iop);
447static int dolchar(struct ioarg *ap);
448static int wdchar(struct ioarg *ap);
449static void scraphere(void);
450static void freehere(int area);
451static void gethere(void);
452static void markhere(char *s, struct ioword *iop);
453static int herein(char *hname, int xdoll);
454static int run(struct ioarg *argp, int (*f) (struct ioarg *));
455
456
457static int eofc(void);
458static int readc(void);
459static void unget(int c);
460static void ioecho(char c);
461
462
463
464
465
466static void pushio(struct ioarg *argp, int (*f) (struct ioarg *));
467#define PUSHIO(what,arg,gen) ((temparg.what = (arg)), pushio(&temparg,(gen)))
468static int remap(int fd);
469static int openpipe(int *pv);
470static void closepipe(int *pv);
471static struct io *setbase(struct io *ip);
472
473
474
475#define NSTART 16
476
477struct wdblock {
478 short w_bsize;
479 short w_nword;
480
481 char *w_words[1];
482};
483
484static struct wdblock *addword(char *wd, struct wdblock *wb);
485static struct wdblock *newword(int nw);
486static char **getwords(struct wdblock *wb);
487
488
489
490static int dolabel(struct op *t, char **args);
491static int dohelp(struct op *t, char **args);
492static int dochdir(struct op *t, char **args);
493static int doshift(struct op *t, char **args);
494static int dologin(struct op *t, char **args);
495static int doumask(struct op *t, char **args);
496static int doexec(struct op *t, char **args);
497static int dodot(struct op *t, char **args);
498static int dowait(struct op *t, char **args);
499static int doread(struct op *t, char **args);
500static int doeval(struct op *t, char **args);
501static int dotrap(struct op *t, char **args);
502static int dobreak(struct op *t, char **args);
503static int doexit(struct op *t, char **args);
504static int doexport(struct op *t, char **args);
505static int doreadonly(struct op *t, char **args);
506static int doset(struct op *t, char **args);
507static int dotimes(struct op *t, char **args);
508static int docontinue(struct op *t, char **args);
509
510static int forkexec(struct op *t, int *pin, int *pout, int no_fork, char **wp);
511static int execute(struct op *t, int *pin, int *pout, int no_fork);
512static int iosetup(struct ioword *iop, int pipein, int pipeout);
513static void brkset(struct brkcon *bc);
514static int getsig(char *s);
515static void setsig(int n, sighandler_t f);
516static int getn(char *as);
517static int brkcontin(char *cp, int val);
518static void rdexp(char **wp, void (*f) (struct var *), int key);
519static void badid(char *s);
520static void varput(char *s, int out);
521static int expand(const char *cp, struct wdblock **wbp, int f);
522static char *blank(int f);
523static int dollar(int quoted);
524static int grave(int quoted);
525static void globname(char *we, char *pp);
526static char *generate(char *start1, char *end1, char *middle, char *end);
527static int anyspcl(struct wdblock *wb);
528static void readhere(char **name, char *s, int ec);
529static int xxchar(struct ioarg *ap);
530
531struct here {
532 char *h_tag;
533 char h_dosub;
534 struct ioword *h_iop;
535 struct here *h_next;
536};
537
538static const char *const signame[] = {
539 "Signal 0",
540 "Hangup",
541 NULL,
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,
553 "Alarm clock",
554 "Terminated"
555};
556
557
558typedef int (*builtin_func_ptr)(struct op *, char **);
559
560struct builtincmd {
561 const char *name;
562 builtin_func_ptr builtinfunc;
563};
564
565static 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
589static struct op *dowholefile(int );
590
591
592
593static char **dolv;
594static int dolc;
595static uint8_t exstat;
596static smallint gflg;
597static smallint interactive;
598static smallint execflg;
599static smallint isbreak;
600static int multiline;
601static struct op *outtree;
602static xint *failpt;
603static xint *errpt;
604static struct brkcon *brklist;
605static struct wdblock *wdlist;
606static struct wdblock *iolist;
607
608#ifdef MSHDEBUG
609static struct var *mshdbg_var;
610#endif
611static struct var *vlist;
612static struct var *homedir;
613static struct var *prompt;
614static struct var *cprompt;
615static struct var *path;
616static struct var *shell;
617static struct var *ifs;
618
619static int areanum;
620static smallint intr;
621static smallint heedint = 1;
622static int inparse;
623static char *null = (char*)"";
624static void (*qflag)(int) = SIG_IGN;
625static int startl;
626static int peeksym;
627static int nlseen;
628static int iounit = IODEFAULT;
629static YYSTYPE yylval;
630static char *elinep;
631
632static struct here *inhere;
633static struct here *acthere;
634static struct region *areabot;
635static struct region *areatop;
636static struct region *areanxt;
637static void *brktop;
638static void *brkaddr;
639
640#define AFID_NOBUF (~0)
641#define AFID_ID 0
642
643
644
645
646
647struct env {
648 char *linep;
649 struct io *iobase;
650 struct io *iop;
651 xint *errpt;
652 int iofd;
653 struct env *oenv;
654};
655
656
657struct globals {
658 struct env global_env;
659 struct ioarg temparg;
660 unsigned bufid;
661 char ourtrap[_NSIG + 1];
662 char *trap[_NSIG + 1];
663 struct iobuf sharedbuf;
664 struct iobuf mainbuf;
665 struct ioarg ioargstack[NPUSH];
666
667
668
669
670
671
672
673
674
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
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
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
719static 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
736
737
738
739
740
741static void prs(const char *s)
742{
743 if (*s)
744 xwrite_str(STDERR_FILENO, s);
745}
746
747static void prn(unsigned u)
748{
749 prs(itoa(u));
750}
751
752static 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
765static void closef(int i)
766{
767 if (i > 2)
768 close(i);
769}
770
771static void closeall(void)
772{
773 int u;
774
775 for (u = NUFILE; u < NOFILE;)
776 close(u++);
777}
778
779
780
781static void fail(void) NORETURN;
782static void fail(void)
783{
784 longjmp(failpt, 1);
785
786}
787
788
789static void leave(void) NORETURN;
790static 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
801}
802
803static 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
815static 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
830
831
832
833
834
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
846static 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
861static 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
872
873
874
875 nregio = (nbytes + (REGSIZE - 1)) / REGSIZE + 1;
876 p = areanxt;
877 for (;;) {
878 if (p->area > areanum) {
879
880
881
882 while ((q = p->next)->area > areanum && q != areanxt)
883 p->next = q->next;
884
885
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();
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
912
913 areanxt = p + nregio;
914 if (areanxt < q) {
915
916
917
918 if (areanxt + 1 > q) {
919 puts("OOM");
920 abort();
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
930static 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
944static 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
954static 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
963static int getarea(char *cp)
964{
965 return ((struct region *) cp - 1)->area;
966}
967
968static 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
990static 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
1000static char *strsave(const char *s, int a)
1001{
1002 char *cp;
1003
1004 cp = get_space(strlen(s) + 1);
1005 if (cp == NULL) {
1006
1007 return (char*)"";
1008 }
1009 setarea(cp, a);
1010 strcpy(cp, s);
1011 return cp;
1012}
1013
1014
1015
1016
1017static 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
1025static const char *findeq(const char *cp)
1026{
1027 while (*cp != '\0' && *cp != '=')
1028 cp++;
1029 return cp;
1030}
1031
1032
1033
1034
1035
1036
1037
1038static struct var *lookup(const char *n)
1039{
1040
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
1084
1085
1086
1087
1088
1089static 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
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);
1120 vp->name = (char*)name;
1121 vp->value = (char*)val;
1122 vp->status |= fl;
1123}
1124
1125
1126
1127
1128static void setval(struct var *vp, const char *val)
1129{
1130 nameval(vp, val, NULL);
1131}
1132
1133static void export(struct var *vp)
1134{
1135 vp->status |= EXPORT;
1136}
1137
1138static void ronly(struct var *vp)
1139{
1140 if (isalpha(vp->name[0]) || vp->name[0] == '_')
1141 vp->status |= RONLY;
1142}
1143
1144static int isassign(const char *s)
1145{
1146 unsigned char c;
1147 DBGPRINTF7(("ISASSIGN: enter, s=%s\n", s));
1148
1149 c = *s;
1150
1151
1152 if (c != '_' && (unsigned)((c|0x20) - 'a') > 25)
1153
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
1164 && (unsigned)((c|0x20) - 'a') > 25
1165 ) {
1166 return 0;
1167 }
1168 }
1169}
1170
1171static 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
1190static 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
1202static 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
1221
1222static void sig(int i)
1223{
1224 trapset = i;
1225 signal(i, sig);
1226}
1227
1228static 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
1243static 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
1257static 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
1280struct 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
1314static 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);
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, 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
1377static 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
1401static 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
1413 DELETE(ep);
1414 while (--fd >= global_env.iofd)
1415 close(fd);
1416 }
1417}
1418
1419
1420
1421
1422static 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
1432
1433static 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
1441static char *putn(int n)
1442{
1443 return itoa(n);
1444}
1445
1446static void next(int f)
1447{
1448 PUSHIO(afile, f, filechar);
1449}
1450
1451static void onintr(int s UNUSED_PARAM)
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
1468
1469
1470
1471
1472
1473
1474
1475#define CMASK 0377
1476#define QUOTE 0200
1477#define QMASK (CMASK & ~QUOTE)
1478#define NOT '!'
1479
1480static 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
1503static 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
1542
1543
1544
1545
1546static void yyerror(const char *s) NORETURN;
1547static 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
1559static void zzerr(void) NORETURN;
1560static void zzerr(void)
1561{
1562 yyerror("syntax error");
1563}
1564
1565int 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;
1575}
1576
1577static 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
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
1610static 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
1639static 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 }
1666
1667 peeksym = c;
1668 }
1669
1670 DBGPRINTF7(("C_LIST: returning t=%p\n", t));
1671 return t;
1672}
1673
1674static 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
1700static 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
1711static 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
1738static 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
1751static 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
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);
1847 DBGPRINTF7(("COMMAND: DOT clause, yylval.cp is %s\n", yylval.cp));
1848
1849 word(yylval.cp);
1850 word(NOWORD);
1851 t->op_words = copyw();
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
1867static struct op *dowholefile(int type )
1868{
1869 struct op *t;
1870
1871 DBGPRINTF(("DOWHOLEFILE: enter, type=%d\n", type ));
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
1881static 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
1896static 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
1908 t->left = c_list();
1909 if (t->left == NULL)
1910 zzerr();
1911 t->right = elsepart();
1912 return t;
1913}
1914
1915static 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
1940static 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
1954static 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
1974static 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
1991static 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
2010
2011static 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
2023static 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
2041static 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 { },
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;
2078 }
2079
2080 DBGPRINTF7(("RLOOKUP: NO match, returning 0\n"));
2081 return 0;
2082}
2083
2084static 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
2096static 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
2122static char **copyw(void)
2123{
2124 char **wd;
2125
2126 wd = getwords(wdlist);
2127 wdlist = NULL;
2128 return wd;
2129}
2130
2131static void word(char *cp)
2132{
2133 wdlist = addword(cp, wdlist);
2134}
2135
2136static struct ioword **copyio(void)
2137{
2138 struct ioword **iop;
2139
2140 iop = (struct ioword **) getwords(iolist);
2141 iolist = NULL;
2142 return iop;
2143}
2144
2145static 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
2157static 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
2177 line[LINELIM - 1] = '\0';
2178
2179 loop:
2180 while ((c = my_getc(0)) == ' ' || c == '\t')
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 '#':
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
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
2298static 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
2332
2333static 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;
2341 *cp++ = my_getc(0);
2342 *cp = '\0';
2343
2344 c = rlookup(s);
2345 if (c == 0)
2346 unget(*--cp);
2347
2348 return c;
2349}
2350
2351static 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
2371static 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
2381 }
2382 return t;
2383}
2384
2385
2386
2387
2388
2389
2390
2391static 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;
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
2429static 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
2439
2440
2441static 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
2453 (void) ℘
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 );
2481 t->right = NULL;
2482
2483 outtree = outtree_save;
2484
2485 if (t->left)
2486 rv = execute(t->left, pin, pout, 0);
2487 if (t->right)
2488 rv = execute(t->right, pin, pout, 0);
2489 break;
2490
2491 case TPAREN:
2492 rv = execute(t->left, pin, pout, 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, 0);
2509 rv = execute(t->right, pv, pout, 0);
2510 }
2511 break;
2512
2513 case TLIST:
2514 (void) execute(t->left, pin, pout, 0);
2515 rv = execute(t->right, pin, pout, 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) {
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, 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, 0);
2554 t1 = t->right;
2555 if (t1 != NULL && (rv == 0) == (t->op_type == TAND))
2556 rv = execute(t1, pin, pout, 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
2575
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, 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
2592
2593 areanum = a + 1;
2594 freearea(areanum + 1);
2595 brkset(&bc);
2596 t1 = t->left;
2597 while ((execute(t1, pin, pout, 0) == 0) == (t->op_type == TWHILE))
2598 rv = execute(t->right, pin, pout, 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, 0) ?
2606 execute(t->right->left, pin, pout, 0) :
2607 execute(t->right->right, pin, pout, 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, 0);
2624 DBGPRINTF7(("EXECUTE: TCASE, back from execute(t=%p, t1=%p)...\n", t, t1));
2625 }
2626 break;
2627
2628 case TBRACE:
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638 if (rv >= 0) {
2639 t1 = t->left;
2640 if (t1) {
2641 rv = execute(t1, pin, pout, 0);
2642 }
2643 }
2644 break;
2645
2646 };
2647
2648 broken:
2649
2650
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
2671static 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
2681static 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
2703 (void) &pin;
2704 (void) &pout;
2705 (void) ℘
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
2724
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 {
2739 bltin_name = cp;
2740 bltin = inbuilt(cp);
2741 }
2742 }
2743
2744 forked = 0;
2745
2746
2747
2748
2749
2750
2751
2752 DBGPRINTF(("FORKEXEC: bltin %p, no_fork %d, owp %p\n", bltin,
2753 no_fork, owp));
2754
2755
2756 if ((!bltin || pin || pout)
2757 && !no_fork
2758 ) {
2759
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) {
2776
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
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) {
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
2829 if (forked)
2830 _exit(-1);
2831 return -1;
2832 }
2833 }
2834 }
2835
2836 if (bltin) {
2837 if (forked || pin || pout) {
2838
2839
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
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
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, 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
2878 return 0;
2879}
2880
2881
2882
2883
2884
2885static 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)
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;
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
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
2966
2967static void brkset(struct brkcon *bc)
2968{
2969 bc->nextlev = brklist;
2970 brklist = bc;
2971}
2972
2973
2974
2975
2976
2977
2978
2979
2980static 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
3036static int setstatus(int s)
3037{
3038 exstat = s;
3039 setval(lookup("?"), putn(s));
3040 return s;
3041}
3042
3043
3044
3045
3046
3047
3048static 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
3058
3059
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
3089
3090
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;
3108 return "not found";
3109 }
3110 exstat = 126;
3111 return "can't execute";
3112}
3113
3114
3115
3116
3117
3118static 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
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, 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
3167
3168
3169
3170
3171
3172static int dohelp(struct op *t UNUSED_PARAM, char **args UNUSED_PARAM)
3173{
3174 int col;
3175 const struct builtincmd *x;
3176
3177 printf("\n"
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
3209static int dolabel(struct op *t UNUSED_PARAM, char **args UNUSED_PARAM)
3210{
3211 return 0;
3212}
3213
3214static 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
3235static 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
3253
3254static 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
3269static 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
3290static 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
3307
3308
3309 if (setjmp(failpt) == 0)
3310 execute(t, NOPIPE, NOPIPE, 1);
3311 t->op_words = sv_words;
3312
3313 failpt = ofail;
3314 execflg = 0;
3315
3316 return 1;
3317}
3318
3319static 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
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);
3360
3361 DBGPRINTF(("DODOT: returning exstat=%d\n", exstat));
3362
3363 return exstat;
3364 }
3365 }
3366
3367 prs(cp);
3368 err(": not found");
3369
3370 return -1;
3371}
3372
3373static 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
3389static 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
3416static int doeval(struct op *t UNUSED_PARAM, char **args)
3417{
3418 return RUN(awordlist, args + 1, wdchar);
3419}
3420
3421static 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
3460static 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
3472static 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
3482static 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
3502static int dobreak(struct op *t UNUSED_PARAM, char **args)
3503{
3504 return brkcontin(args[1], 1);
3505}
3506
3507static int docontinue(struct op *t UNUSED_PARAM, char **args)
3508{
3509 return brkcontin(args[1], 0);
3510}
3511
3512static 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
3533}
3534
3535static 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
3548 return 0;
3549}
3550
3551static int doexport(struct op *t UNUSED_PARAM, char **args)
3552{
3553 rdexp(args + 1, export, EXPORT);
3554 return 0;
3555}
3556
3557static int doreadonly(struct op *t UNUSED_PARAM, char **args)
3558{
3559 rdexp(args + 1, ronly, RONLY);
3560 return 0;
3561}
3562
3563static 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
3587static void badid(char *s)
3588{
3589 prs(s);
3590 err(": bad identifier");
3591}
3592
3593static 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
3638static 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
3649
3650
3651static 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 ((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
3668static 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
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
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699static 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
3708 (void) ℘
3709 (void) ≈
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
3743
3744
3745
3746static 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
3759static int expand(const char *cp, struct wdblock **wbp, int f)
3760{
3761 jmp_buf ev;
3762 char *xp;
3763
3764#if __GNUC__
3765
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
3805static 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
3817
3818
3819 cp = (char*)"";
3820 }
3821 DELETE(wb);
3822 } else
3823 cp = NULL;
3824 return cp;
3825}
3826
3827
3828
3829
3830
3831static 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
3900
3901static 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
3929
3930static 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
3983
3984 global_env.linep = s;
3985 PUSHIO(awordlist, dolv + 1, dolchar);
3986 return 0;
3987 } else {
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
4033
4034
4035static int grave(int quoted)
4036{
4037
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
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
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
4077
4078
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
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
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);
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
4201
4202 for (j = 0; j <= _NSIG; j++)
4203 if (ourtrap[j] && signal(j, SIG_IGN) != SIG_IGN)
4204 signal(j, SIG_DFL);
4205
4206
4207
4208
4209
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
4228static 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
4240
4241
4242
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
4249static struct wdblock *cl, *nl;
4250static const char spcl[] ALIGN1= "[?*";
4251
4252static 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++) {
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
4295static 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
4326
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
4353
4354
4355
4356static 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
4372static 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
4386
4387static 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
4397static 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
4417static 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);
4432 return wd;
4433}
4434
4435
4436
4437
4438
4439
4440
4441
4442static 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
4465static void unget(int c)
4466{
4467 if (global_env.iop >= global_env.iobase)
4468 global_env.iop->peekc = c;
4469}
4470
4471static int eofc(void)
4472{
4473 return global_env.iop < global_env.iobase || (global_env.iop->peekc == 0 && global_env.iop->prev == 0);
4474}
4475
4476static 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 }
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
4531 return 0;
4532}
4533
4534static void ioecho(char c)
4535{
4536 if (FLAG['v'])
4537 write(STDERR_FILENO, &c, sizeof c);
4538}
4539
4540static 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
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
4554
4555 global_env.iop->iofn = (int (*)(struct ioarg *, struct io *)) fn;
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);
4562 *global_env.iop->argp = *argp;
4563
4564
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
4572
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)
4577 bufid = AFID_ID;
4578
4579 global_env.iop->argp->afid = bufid;
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
4603static 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
4614
4615
4616
4617
4618
4619static 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
4635
4636
4637static 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
4658
4659
4660static 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
4672static 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
4688
4689static int strchar(struct ioarg *ap)
4690{
4691 if (ap->aword == NULL)
4692 return 0;
4693 return *ap->aword++;
4694}
4695
4696
4697
4698
4699static 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
4713
4714static 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
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)
4748 exit(EXIT_SUCCESS);
4749 position = 0;
4750
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
4763
4764static 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
4777
4778
4779static 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
4789static 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
4817
4818static 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;
4827 }
4828 }
4829 return c;
4830}
4831
4832
4833
4834
4835static 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
4864static 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
4874static void closepipe(int *pv)
4875{
4876 if (pv != NULL) {
4877 close(pv[0]);
4878 close(pv[1]);
4879 }
4880}
4881
4882
4883
4884
4885
4886
4887
4888
4889static 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
4926static void gethere(void)
4927{
4928 struct here *h, *hp;
4929
4930 DBGPRINTF7(("GETHERE: enter...\n"));
4931
4932
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 );
4935
4936
4937 if (hp != NULL) {
4938 hp->h_next = acthere;
4939 acthere = inhere;
4940 inhere = NULL;
4941 }
4942}
4943
4944static 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
5002
5003
5004static int herein(char *hname, int xdoll)
5005{
5006 int hf;
5007 int tf;
5008
5009#if __GNUC__
5010
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
5049static 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
5063static 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
5086
5087
5088
5089
5090int msh_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
5091int 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
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
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
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);
5228 }
5229 }
5230
5231 setdash();
5232
5233
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
5266
5267#if 0
5268 argv++;
5269
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
5294 setenv("PATH", path->value, 1);
5295 }
5296
5297 DBGPRINTF(("MSH_MAIN: returning.\n"));
5298}
5299
5300
5301
5302
5303
5304
5305
5306
5307
5308
5309
5310
5311
5312
5313
5314
5315
5316
5317
5318
5319
5320
5321
5322
5323
5324
5325
5326
5327
5328
5329
5330
5331
5332
5333
5334
5335
5336