blob: e6cde9e1ab18a0b80bc11c95bdd29f11d9da9732 [file] [log] [blame]
rsc4ee543e2005-03-18 19:03:25 +00001#include <u.h>
2#include <signal.h>
3#include <sys/ioctl.h>
rscf08fded2003-11-23 18:04:08 +00004#include "rc.h"
5#include "getflags.h"
6#include "exec.h"
7#include "io.h"
8#include "fns.h"
9/*
10 * Start executing the given code at the given pc with the given redirection
11 */
12char *argv0="rc";
13void start(code *c, int pc, var *local)
14{
15 struct thread *p=new(struct thread);
16 p->code=codecopy(c);
17 p->pc=pc;
18 p->argv=0;
19 p->redir=p->startredir=runq?runq->redir:0;
20 p->local=local;
21 p->cmdfile=0;
22 p->cmdfd=0;
23 p->eof=0;
24 p->iflag=0;
25 p->lineno=1;
rsc26a5fd52005-02-11 16:58:06 +000026 p->pid=-1;
rscf08fded2003-11-23 18:04:08 +000027 p->ret=runq;
28 runq=p;
29}
30word *newword(char *wd, word *next)
31{
32 word *p=new(word);
33 p->word=strdup(wd);
34 p->next=next;
35 return p;
36}
37void pushword(char *wd)
38{
39 if(runq->argv==0) panic("pushword but no argv!", 0);
40 runq->argv->words=newword(wd, runq->argv->words);
41}
42void popword(void){
43 word *p;
44 if(runq->argv==0) panic("popword but no argv!", 0);
45 p=runq->argv->words;
46 if(p==0) panic("popword but no word!", 0);
47 runq->argv->words=p->next;
48 efree(p->word);
49 efree((char *)p);
50}
51void freelist(word *w)
52{
53 word *nw;
54 while(w){
55 nw=w->next;
56 efree(w->word);
57 efree((char *)w);
58 w=nw;
59 }
60}
61void pushlist(void){
62 list *p=new(list);
63 p->next=runq->argv;
64 p->words=0;
65 runq->argv=p;
66}
67void poplist(void){
68 list *p=runq->argv;
69 if(p==0) panic("poplist but no argv", 0);
70 freelist(p->words);
71 runq->argv=p->next;
72 efree((char *)p);
73}
74int count(word *w)
75{
76 int n;
77 for(n=0;w;n++) w=w->next;
78 return n;
79}
80void pushredir(int type, int from, int to){
81 redir * rp=new(redir);
82 rp->type=type;
83 rp->from=from;
84 rp->to=to;
85 rp->next=runq->redir;
86 runq->redir=rp;
87}
88var *newvar(char *name, var *next)
89{
90 var *v=new(var);
91 v->name=name;
92 v->val=0;
93 v->fn=0;
94 v->changed=0;
95 v->fnchanged=0;
96 v->next=next;
rscc8b63422005-01-13 04:49:19 +000097 v->changefn = 0;
rscf08fded2003-11-23 18:04:08 +000098 return v;
99}
100/*
101 * get command line flags, initialize keywords & traps.
102 * get values from environment.
103 * set $pid, $cflag, $*
104 * fabricate bootstrap code and start it (*=(argv);. /usr/lib/rcmain $*)
105 * start interpreting code
106 */
107int
108main(int argc, char *argv[])
109{
110 code bootstrap[32];
111 char num[12], *rcmain;
112 int i;
113
114 argc=getflags(argc, argv, "srdiIlxepvVc:1m:1[command]", 1);
115 if(argc==-1) usage("[file [arg ...]]");
116 if(argv[0][0]=='-') flag['l']=flagset;
117 if(flag['I']) flag['i'] = 0;
118 else if(flag['i']==0 && argc==1 && Isatty(0)) flag['i'] = flagset;
119 rcmain=flag['m']?flag['m'][0]:Rcmain();
120 err=openfd(2);
121 kinit();
122 Trapinit();
123 Vinit();
124 itoa(num, mypid=getpid());
rsca9eaaa02005-01-12 16:59:50 +0000125 pathinit();
rscf08fded2003-11-23 18:04:08 +0000126 setvar("pid", newword(num, (word *)0));
127 setvar("cflag", flag['c']?newword(flag['c'][0], (word *)0)
128 :(word *)0);
129 setvar("rcname", newword(argv[0], (word *)0));
130 i=0;
131 bootstrap[i++].i=1;
132 bootstrap[i++].f=Xmark;
133 bootstrap[i++].f=Xword;
134 bootstrap[i++].s="*";
135 bootstrap[i++].f=Xassign;
136 bootstrap[i++].f=Xmark;
137 bootstrap[i++].f=Xmark;
138 bootstrap[i++].f=Xword;
139 bootstrap[i++].s="*";
140 bootstrap[i++].f=Xdol;
141 bootstrap[i++].f=Xword;
142 bootstrap[i++].s=rcmain;
143 bootstrap[i++].f=Xword;
144 bootstrap[i++].s=".";
145 bootstrap[i++].f=Xsimple;
146 bootstrap[i++].f=Xexit;
147 bootstrap[i].i=0;
148 start(bootstrap, 1, (var *)0);
149 /* prime bootstrap argv */
150 pushlist();
151 argv0 = strdup(argv[0]);
152 for(i=argc-1;i!=0;--i) pushword(argv[i]);
153 for(;;){
154 if(flag['r']) pfnc(err, runq);
155 runq->pc++;
156 (*runq->code[runq->pc-1].f)();
157 if(ntrap) dotrap();
158 }
159}
160/*
161 * Opcode routines
162 * Arguments on stack (...)
163 * Arguments in line [...]
164 * Code in line with jump around {...}
165 *
166 * Xappend(file)[fd] open file to append
167 * Xassign(name, val) assign val to name
168 * Xasync{... Xexit} make thread for {}, no wait
169 * Xbackq{... Xreturn} make thread for {}, push stdout
170 * Xbang complement condition
171 * Xcase(pat, value){...} exec code on match, leave (value) on
172 * stack
173 * Xclose[i] close file descriptor
174 * Xconc(left, right) concatenate, push results
175 * Xcount(name) push var count
176 * Xdelfn(name) delete function definition
177 * Xdeltraps(names) delete named traps
178 * Xdol(name) get variable value
179 * Xqdol(name) concatenate variable components
180 * Xdup[i j] dup file descriptor
181 * Xexit rc exits with status
182 * Xfalse{...} execute {} if false
183 * Xfn(name){... Xreturn} define function
184 * Xfor(var, list){... Xreturn} for loop
185 * Xjump[addr] goto
186 * Xlocal(name, val) create local variable, assign value
187 * Xmark mark stack
188 * Xmatch(pat, str) match pattern, set status
189 * Xpipe[i j]{... Xreturn}{... Xreturn} construct a pipe between 2 new threads,
190 * wait for both
191 * Xpipefd[type]{... Xreturn} connect {} to pipe (input or output,
192 * depending on type), push /dev/fd/??
193 * Xpopm(value) pop value from stack
194 * Xread(file)[fd] open file to read
195 * Xsettraps(names){... Xreturn} define trap functions
196 * Xshowtraps print trap list
197 * Xsimple(args) run command and wait
198 * Xreturn kill thread
199 * Xsubshell{... Xexit} execute {} in a subshell and wait
200 * Xtrue{...} execute {} if true
201 * Xunlocal delete local variable
202 * Xword[string] push string
203 * Xwrite(file)[fd] open file to write
204 */
205void Xappend(void){
206 char *file;
207 int f;
208 switch(count(runq->argv->words)){
209 default: Xerror1(">> requires singleton"); return;
210 case 0: Xerror1(">> requires file"); return;
211 case 1: break;
212 }
213 file=runq->argv->words->word;
214 if((f=open(file, 1))<0 && (f=Creat(file))<0){
215 pfmt(err, "%s: ", file);
216 Xerror("can't open");
217 return;
218 }
219 Seek(f, 0L, 2);
220 pushredir(ROPEN, f, runq->code[runq->pc].i);
221 runq->pc++;
222 poplist();
223}
224void Xasync(void){
225 int null=open("/dev/null", 0);
rsc4ee543e2005-03-18 19:03:25 +0000226 int tty;
rscf08fded2003-11-23 18:04:08 +0000227 int pid;
228 char npid[10];
229 if(null<0){
230 Xerror("Can't open /dev/null\n");
231 return;
232 }
233 switch(pid=rfork(RFFDG|RFPROC|RFNOTEG)){
234 case -1:
235 close(null);
236 Xerror("try again");
237 break;
238 case 0:
rsc4ee543e2005-03-18 19:03:25 +0000239 /*
240 * I don't know what the right thing to do here is,
241 * so this is all experimentally determined.
242 * If we just dup /dev/null onto 0, then running
243 * ssh foo & will reopen /dev/tty, try to read a password,
244 * get a signal, and repeat, in a tight loop, forever.
245 * Arguably this is a bug in ssh (it behaves the same
246 * way under bash as under rc) but I'm fixing it here
247 * anyway. If we dissociate the process from the tty,
248 * then it won't be able to open /dev/tty ever again.
249 * The SIG_IGN on SIGTTOU makes writing the tty
250 * (via fd 1 or 2, for example) succeed even though
251 * our pgrp is not the terminal's controlling pgrp.
252 */
253 if((tty=open("/dev/tty", OREAD)) >= 0){
254 /*
255 * Should make reads of tty fail, writes succeed.
256 */
257 signal(SIGTTIN, SIG_IGN);
258 signal(SIGTTOU, SIG_IGN);
259 ioctl(tty, TIOCNOTTY);
260 close(tty);
261 }
262 if(isatty(0))
263 pushredir(ROPEN, null, 0);
264 else
265 close(null);
rscf08fded2003-11-23 18:04:08 +0000266 start(runq->code, runq->pc+1, runq->local);
267 runq->ret=0;
268 break;
269 default:
270 close(null);
271 runq->pc=runq->code[runq->pc].i;
272 itoa(npid, pid);
273 setvar("apid", newword(npid, (word *)0));
274 break;
275 }
276}
277void Xsettrue(void){
278 setstatus("");
279}
280void Xbang(void){
281 setstatus(truestatus()?"false":"");
282}
283void Xclose(void){
284 pushredir(RCLOSE, runq->code[runq->pc].i, 0);
285 runq->pc++;
286}
287void Xdup(void){
288 pushredir(RDUP, runq->code[runq->pc].i, runq->code[runq->pc+1].i);
289 runq->pc+=2;
290}
291void Xeflag(void){
292 if(eflagok && !truestatus()) Xexit();
293}
294void Xexit(void){
295 struct var *trapreq;
296 struct word *starval;
297 static int beenhere=0;
298 if(getpid()==mypid && !beenhere){
299 trapreq=vlook("sigexit");
300 if(trapreq->fn){
301 beenhere=1;
302 --runq->pc;
303 starval=vlook("*")->val;
304 start(trapreq->fn, trapreq->pc, (struct var *)0);
305 runq->local=newvar(strdup("*"), runq->local);
306 runq->local->val=copywords(starval, (struct word *)0);
307 runq->local->changed=1;
308 runq->redir=runq->startredir=0;
309 return;
310 }
311 }
312 Exit(getstatus());
313}
314void Xfalse(void){
315 if(truestatus()) runq->pc=runq->code[runq->pc].i;
316 else runq->pc++;
317}
318int ifnot; /* dynamic if not flag */
319void Xifnot(void){
320 if(ifnot)
321 runq->pc++;
322 else
323 runq->pc=runq->code[runq->pc].i;
324}
325void Xjump(void){
326 runq->pc=runq->code[runq->pc].i;
327}
328void Xmark(void){
329 pushlist();
330}
331void Xpopm(void){
332 poplist();
333}
334void Xread(void){
335 char *file;
336 int f;
337 switch(count(runq->argv->words)){
338 default: Xerror1("< requires singleton\n"); return;
339 case 0: Xerror1("< requires file\n"); return;
340 case 1: break;
341 }
342 file=runq->argv->words->word;
343 if((f=open(file, 0))<0){
344 pfmt(err, "%s: ", file);
345 Xerror("can't open");
346 return;
347 }
348 pushredir(ROPEN, f, runq->code[runq->pc].i);
349 runq->pc++;
350 poplist();
351}
352void turfredir(void){
353 while(runq->redir!=runq->startredir)
354 Xpopredir();
355}
356void Xpopredir(void){
357 struct redir *rp=runq->redir;
358 if(rp==0) panic("turfredir null!", 0);
359 runq->redir=rp->next;
360 if(rp->type==ROPEN) close(rp->from);
361 efree((char *)rp);
362}
363void Xreturn(void){
364 struct thread *p=runq;
365 turfredir();
366 while(p->argv) poplist();
367 codefree(p->code);
368 runq=p->ret;
369 efree((char *)p);
370 if(runq==0) Exit(getstatus());
371}
372void Xtrue(void){
373 if(truestatus()) runq->pc++;
374 else runq->pc=runq->code[runq->pc].i;
375}
376void Xif(void){
377 ifnot=1;
378 if(truestatus()) runq->pc++;
379 else runq->pc=runq->code[runq->pc].i;
380}
381void Xwastrue(void){
382 ifnot=0;
383}
384void Xword(void){
385 pushword(runq->code[runq->pc++].s);
386}
387void Xwrite(void){
388 char *file;
389 int f;
390 switch(count(runq->argv->words)){
391 default: Xerror1("> requires singleton\n"); return;
392 case 0: Xerror1("> requires file\n"); return;
393 case 1: break;
394 }
395 file=runq->argv->words->word;
396 if((f=Creat(file))<0){
397 pfmt(err, "%s: ", file);
398 Xerror("can't open");
399 return;
400 }
401 pushredir(ROPEN, f, runq->code[runq->pc].i);
402 runq->pc++;
403 poplist();
404}
rsca9eaaa02005-01-12 16:59:50 +0000405char *_list2str(word *words, int c){
rscf08fded2003-11-23 18:04:08 +0000406 char *value, *s, *t;
407 int len=0;
408 word *ap;
409 for(ap=words;ap;ap=ap->next)
410 len+=1+strlen(ap->word);
411 value=emalloc(len+1);
412 s=value;
413 for(ap=words;ap;ap=ap->next){
414 for(t=ap->word;*t;) *s++=*t++;
rsca9eaaa02005-01-12 16:59:50 +0000415 *s++=c;
rscf08fded2003-11-23 18:04:08 +0000416 }
417 if(s==value) *s='\0';
418 else s[-1]='\0';
419 return value;
420}
rsca9eaaa02005-01-12 16:59:50 +0000421char *list2str(word *words){
422 return _list2str(words, ' ');
423}
rscf08fded2003-11-23 18:04:08 +0000424void Xmatch(void){
425 word *p;
426 char *subject;
427 subject=list2str(runq->argv->words);
428 setstatus("no match");
429 for(p=runq->argv->next->words;p;p=p->next)
430 if(match(subject, p->word, '\0')){
431 setstatus("");
432 break;
433 }
434 efree(subject);
435 poplist();
436 poplist();
437}
438void Xcase(void){
439 word *p;
440 char *s;
441 int ok=0;
442 s=list2str(runq->argv->next->words);
443 for(p=runq->argv->words;p;p=p->next){
444 if(match(s, p->word, '\0')){
445 ok=1;
446 break;
447 }
448 }
449 efree(s);
450 if(ok)
451 runq->pc++;
452 else
453 runq->pc=runq->code[runq->pc].i;
454 poplist();
455}
456word *conclist(word *lp, word *rp, word *tail)
457{
458 char *buf;
459 word *v;
460 if(lp->next || rp->next)
461 tail=conclist(lp->next==0?lp:lp->next, rp->next==0?rp:rp->next,
462 tail);
463 buf=emalloc(strlen(lp->word)+strlen(rp->word)+1);
464 strcpy(buf, lp->word);
465 strcat(buf, rp->word);
466 v=newword(buf, tail);
467 efree(buf);
468 return v;
469}
470void Xconc(void){
471 word *lp=runq->argv->words;
472 word *rp=runq->argv->next->words;
473 word *vp=runq->argv->next->next->words;
474 int lc=count(lp), rc=count(rp);
475 if(lc!=0 || rc!=0){
476 if(lc==0 || rc==0){
477 Xerror1("null list in concatenation");
478 return;
479 }
480 if(lc!=1 && rc!=1 && lc!=rc){
481 Xerror1("mismatched list lengths in concatenation");
482 return;
483 }
484 vp=conclist(lp, rp, vp);
485 }
486 poplist();
487 poplist();
488 runq->argv->words=vp;
489}
490void Xassign(void){
491 var *v;
492 if(count(runq->argv->words)!=1){
493 Xerror1("variable name not singleton!");
494 return;
495 }
496 deglob(runq->argv->words->word);
497 v=vlook(runq->argv->words->word);
498 poplist();
499 globlist();
500 freewords(v->val);
501 v->val=runq->argv->words;
502 v->changed=1;
rsca9eaaa02005-01-12 16:59:50 +0000503 if(v->changefn)
504 v->changefn(v);
rscf08fded2003-11-23 18:04:08 +0000505 runq->argv->words=0;
506 poplist();
507}
508/*
509 * copy arglist a, adding the copy to the front of tail
510 */
511word *copywords(word *a, word *tail)
512{
513 word *v=0, **end;
514 for(end=&v;a;a=a->next,end=&(*end)->next)
515 *end=newword(a->word, 0);
516 *end=tail;
517 return v;
518}
519void Xdol(void){
520 word *a, *star;
521 char *s, *t;
522 int n;
523 if(count(runq->argv->words)!=1){
524 Xerror1("variable name not singleton!");
525 return;
526 }
527 s=runq->argv->words->word;
528 deglob(s);
529 n=0;
530 for(t=s;'0'<=*t && *t<='9';t++) n=n*10+*t-'0';
531 a=runq->argv->next->words;
532 if(n==0 || *t)
533 a=copywords(vlook(s)->val, a);
534 else{
535 star=vlook("*")->val;
536 if(star && 1<=n && n<=count(star)){
537 while(--n) star=star->next;
538 a=newword(star->word, a);
539 }
540 }
541 poplist();
542 runq->argv->words=a;
543}
544void Xqdol(void){
545 word *a, *p;
546 char *s;
547 int n;
548 if(count(runq->argv->words)!=1){
549 Xerror1("variable name not singleton!");
550 return;
551 }
552 s=runq->argv->words->word;
553 deglob(s);
554 a=vlook(s)->val;
555 poplist();
556 n=count(a);
557 if(n==0){
558 pushword("");
559 return;
560 }
561 for(p=a;p;p=p->next) n+=strlen(p->word);
562 s=emalloc(n);
563 if(a){
564 strcpy(s, a->word);
565 for(p=a->next;p;p=p->next){
566 strcat(s, " ");
567 strcat(s, p->word);
568 }
569 }
570 else
571 s[0]='\0';
572 pushword(s);
573 efree(s);
574}
575word *subwords(word *val, int len, word *sub, word *a)
576{
577 int n;
578 char *s;
579 if(!sub) return a;
580 a=subwords(val, len, sub->next, a);
581 s=sub->word;
582 deglob(s);
583 n=0;
584 while('0'<=*s && *s<='9') n=n*10+ *s++ -'0';
585 if(n<1 || len<n) return a;
586 for(;n!=1;--n) val=val->next;
587 return newword(val->word, a);
588}
589void Xsub(void){
590 word *a, *v;
591 char *s;
592 if(count(runq->argv->next->words)!=1){
593 Xerror1("variable name not singleton!");
594 return;
595 }
596 s=runq->argv->next->words->word;
597 deglob(s);
598 a=runq->argv->next->next->words;
599 v=vlook(s)->val;
600 a=subwords(v, count(v), runq->argv->words, a);
601 poplist();
602 poplist();
603 runq->argv->words=a;
604}
605void Xcount(void){
606 word *a;
607 char *s, *t;
608 int n;
609 char num[12];
610 if(count(runq->argv->words)!=1){
611 Xerror1("variable name not singleton!");
612 return;
613 }
614 s=runq->argv->words->word;
615 deglob(s);
616 n=0;
617 for(t=s;'0'<=*t && *t<='9';t++) n=n*10+*t-'0';
618 if(n==0 || *t){
619 a=vlook(s)->val;
620 itoa(num, count(a));
621 }
622 else{
623 a=vlook("*")->val;
624 itoa(num, a && 1<=n && n<=count(a)?1:0);
625 }
626 poplist();
627 pushword(num);
628}
629void Xlocal(void){
630 if(count(runq->argv->words)!=1){
631 Xerror1("variable name must be singleton\n");
632 return;
633 }
634 deglob(runq->argv->words->word);
635 runq->local=newvar(strdup(runq->argv->words->word), runq->local);
636 runq->local->val=copywords(runq->argv->next->words, (word *)0);
637 runq->local->changed=1;
638 poplist();
639 poplist();
640}
641void Xunlocal(void){
642 var *v=runq->local, *hid;
643 if(v==0) panic("Xunlocal: no locals!", 0);
644 runq->local=v->next;
645 hid=vlook(v->name);
646 hid->changed=1;
647 efree(v->name);
648 freewords(v->val);
649 efree((char *)v);
650}
651void freewords(word *w)
652{
653 word *nw;
654 while(w){
655 efree(w->word);
656 nw=w->next;
657 efree((char *)w);
658 w=nw;
659 }
660}
661void Xfn(void){
662 var *v;
663 word *a;
664 int end;
665 end=runq->code[runq->pc].i;
666 for(a=runq->argv->words;a;a=a->next){
667 v=gvlook(a->word);
668 if(v->fn) codefree(v->fn);
669 v->fn=codecopy(runq->code);
670 v->pc=runq->pc+2;
671 v->fnchanged=1;
672 }
673 runq->pc=end;
674 poplist();
675}
676void Xdelfn(void){
677 var *v;
678 word *a;
679 for(a=runq->argv->words;a;a=a->next){
680 v=gvlook(a->word);
681 if(v->fn) codefree(v->fn);
682 v->fn=0;
683 v->fnchanged=1;
684 }
685 poplist();
686}
687void Xpipe(void){
688 struct thread *p=runq;
689 int pc=p->pc, forkid;
690 int lfd=p->code[pc++].i;
691 int rfd=p->code[pc++].i;
692 int pfd[2];
693 if(pipe(pfd)<0){
694 Xerror("can't get pipe");
695 return;
696 }
697 switch(forkid=fork()){
698 case -1:
699 Xerror("try again");
700 break;
701 case 0:
702 start(p->code, pc+2, runq->local);
703 runq->ret=0;
704 close(pfd[PRD]);
705 pushredir(ROPEN, pfd[PWR], lfd);
706 break;
707 default:
708 start(p->code, p->code[pc].i, runq->local);
709 close(pfd[PWR]);
710 pushredir(ROPEN, pfd[PRD], rfd);
711 p->pc=p->code[pc+1].i;
712 p->pid=forkid;
713 break;
714 }
715}
716char *concstatus(char *s, char *t)
717{
718 static char v[NSTATUS+1];
719 int n=strlen(s);
720 strncpy(v, s, NSTATUS);
721 if(n<NSTATUS){
722 v[n]='|';
723 strncpy(v+n+1, t, NSTATUS-n-1);
724 }
725 v[NSTATUS]='\0';
726 return v;
727}
728void Xpipewait(void){
729 char status[NSTATUS+1];
730 if(runq->pid==-1)
731 setstatus(concstatus(runq->status, getstatus()));
732 else{
733 strncpy(status, getstatus(), NSTATUS);
734 status[NSTATUS]='\0';
735 Waitfor(runq->pid, 1);
736 runq->pid=-1;
737 setstatus(concstatus(getstatus(), status));
738 }
739}
740void Xrdcmds(void){
741 struct thread *p=runq;
742 word *prompt;
743 flush(err);
744 nerror=0;
745 if(flag['s'] && !truestatus())
746 pfmt(err, "status=%v\n", vlook("status")->val);
747 if(runq->iflag){
748 prompt=vlook("prompt")->val;
749 if(prompt)
750 promptstr=prompt->word;
751 else
752 promptstr="% ";
753 }
754 Noerror();
755 if(yyparse()){
756 if(!p->iflag || p->eof && !Eintr()){
757 if(p->cmdfile) efree(p->cmdfile);
758 closeio(p->cmdfd);
759 Xreturn(); /* should this be omitted? */
760 }
761 else{
762 if(Eintr()){
763 pchr(err, '\n');
764 p->eof=0;
765 }
766 --p->pc; /* go back for next command */
767 }
768 }
769 else{
770 ntrap = 0; /* avoid double-interrupts during blocked writes */
771 --p->pc; /* re-execute Xrdcmds after codebuf runs */
772 start(codebuf, 1, runq->local);
773 }
774 freenodes();
775}
776void Xerror(char *s)
777{
778 if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0)
779 pfmt(err, "rc: %s: %r\n", s);
780 else
781 pfmt(err, "rc (%s): %s: %r\n", argv0, s);
782 flush(err);
783 while(!runq->iflag) Xreturn();
784}
785void Xerror1(char *s)
786{
787 if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0)
788 pfmt(err, "rc: %s\n", s);
789 else
790 pfmt(err, "rc (%s): %s\n", argv0, s);
791 flush(err);
792 while(!runq->iflag) Xreturn();
793}
794void Xbackq(void){
795 char wd[8193];
796 int c;
797 char *s, *ewd=&wd[8192], *stop;
798 struct io *f;
799 var *ifs=vlook("ifs");
800 word *v, *nextv;
801 int pfd[2];
802 int pid;
803 stop=ifs->val?ifs->val->word:"";
804 if(pipe(pfd)<0){
805 Xerror("can't make pipe");
806 return;
807 }
808 switch(pid=fork()){
809 case -1: Xerror("try again");
810 close(pfd[PRD]);
811 close(pfd[PWR]);
812 return;
813 case 0:
814 close(pfd[PRD]);
815 start(runq->code, runq->pc+1, runq->local);
816 pushredir(ROPEN, pfd[PWR], 1);
817 return;
818 default:
819 close(pfd[PWR]);
820 f=openfd(pfd[PRD]);
821 s=wd;
822 v=0;
823 while((c=rchr(f))!=EOF){
824 if(strchr(stop, c) || s==ewd){
825 if(s!=wd){
826 *s='\0';
827 v=newword(wd, v);
828 s=wd;
829 }
830 }
831 else *s++=c;
832 }
833 if(s!=wd){
834 *s='\0';
835 v=newword(wd, v);
836 }
837 closeio(f);
838 Waitfor(pid, 0);
839 /* v points to reversed arglist -- reverse it onto argv */
840 while(v){
841 nextv=v->next;
842 v->next=runq->argv->words;
843 runq->argv->words=v;
844 v=nextv;
845 }
846 runq->pc=runq->code[runq->pc].i;
847 return;
848 }
849}
850/*
851 * Who should wait for the exit from the fork?
852 */
853void Xpipefd(void){
854 struct thread *p=runq;
855 int pc=p->pc;
856 char name[40];
857 int pfd[2];
858 int sidefd, mainfd;
859 if(pipe(pfd)<0){
860 Xerror("can't get pipe");
861 return;
862 }
863 if(p->code[pc].i==READ){
864 sidefd=pfd[PWR];
865 mainfd=pfd[PRD];
866 }
867 else{
868 sidefd=pfd[PRD];
869 mainfd=pfd[PWR];
870 }
871 switch(fork()){
872 case -1:
873 Xerror("try again");
874 break;
875 case 0:
876 start(p->code, pc+2, runq->local);
877 close(mainfd);
878 pushredir(ROPEN, sidefd, p->code[pc].i==READ?1:0);
879 runq->ret=0;
880 break;
881 default:
882 close(sidefd);
883 pushredir(ROPEN, mainfd, mainfd); /* isn't this a noop? */
884 strcpy(name, Fdprefix);
885 itoa(name+strlen(name), mainfd);
886 pushword(name);
887 p->pc=p->code[pc+1].i;
888 break;
889 }
890}
891void Xsubshell(void){
892 int pid;
893 switch(pid=fork()){
894 case -1:
895 Xerror("try again");
896 break;
897 case 0:
898 start(runq->code, runq->pc+1, runq->local);
899 runq->ret=0;
900 break;
901 default:
902 Waitfor(pid, 1);
903 runq->pc=runq->code[runq->pc].i;
904 break;
905 }
906}
907void setstatus(char *s)
908{
909 setvar("status", newword(s, (word *)0));
910}
911char *getstatus(void){
912 var *status=vlook("status");
913 return status->val?status->val->word:"";
914}
915int truestatus(void){
916 char *s;
917 for(s=getstatus();*s;s++)
918 if(*s!='|' && *s!='0') return 0;
919 return 1;
920}
921void Xdelhere(void){
922 Unlink(runq->code[runq->pc++].s);
923}
924void Xfor(void){
925 if(runq->argv->words==0){
926 poplist();
927 runq->pc=runq->code[runq->pc].i;
928 }
929 else{
930 freelist(runq->local->val);
931 runq->local->val=runq->argv->words;
932 runq->local->changed=1;
933 runq->argv->words=runq->argv->words->next;
934 runq->local->val->next=0;
935 runq->pc++;
936 }
937}
938void Xglob(void){
939 globlist();
940}