16
7
* Start executing the given code at the given pc with the given redirection
19
void start(code *c, int pc, var *local)
12
start(code *c, int pc, var *local)
21
struct thread *p=new(struct thread);
25
p->redir=p->startredir=runq?runq->redir:0;
14
struct thread *p = new(struct thread);
16
p->code = codecopy(c);
19
p->redir = p->startredir = runq?runq->redir:0;
36
word *newword(char *wd, word *next)
31
newword(char *wd, word *next)
43
void pushword(char *wd)
45
if(runq->argv==0) panic("pushword but no argv!", 0);
46
runq->argv->words=newword(wd, runq->argv->words);
43
panic("pushword but no argv!", 0);
44
runq->argv->words = newword(wd, runq->argv->words);
50
if(runq->argv==0) panic("popword but no argv!", 0);
52
if(p==0) panic("popword but no word!", 0);
53
runq->argv->words=p->next;
52
panic("popword but no argv!", 0);
53
p = runq->argv->words;
55
panic("popword but no word!", 0);
56
runq->argv->words = p->next;
57
void freelist(word *w)
75
if(p==0) panic("poplist but no argv", 0);
87
panic("poplist but no argv", 0);
76
88
freelist(p->words);
83
for(n=0;w;n++) w=w->next;
97
for(n = 0;w;n++) w = w->next;
86
void pushredir(int type, int from, int to){
87
redir * rp=new(redir);
102
pushredir(int type, int from, int to)
104
redir * rp = new(redir);
108
rp->next = runq->redir;
94
var *newvar(char *name, var *next)
113
newvar(char *name, var *next)
117
136
char num[12], *rcmain;
120
argc=getflags(argc, argv, "srdiIlxepvVc:1m:1[command]", 1);
121
if(argc==-1) usage("[file [arg ...]]");
122
if(argv[0][0]=='-') flag['l']=flagset;
123
if(flag['I']) flag['i'] = 0;
139
/* needed for rcmain later */
140
putenv("PLAN9", unsharp("#9"));
142
argc = getflags(argc, argv, "SsrdiIlxepvVc:1m:1[command]", 1);
144
usage("[file [arg ...]]");
124
149
else if(flag['i']==0 && argc==1 && Isatty(0)) flag['i'] = flagset;
125
rcmain=flag['m']?flag['m'][0]:Rcmain();
150
rcmain = flag['m'] ? flag['m'][0] : Rcmain();
130
itoa(num, mypid=getpid());
155
inttoascii(num, mypid = getpid());
132
157
setvar("pid", newword(num, (word *)0));
133
158
setvar("cflag", flag['c']?newword(flag['c'][0], (word *)0)
135
160
setvar("rcname", newword(argv[0], (word *)0));
138
bootstrap[i++].f=Xmark;
139
bootstrap[i++].f=Xword;
140
bootstrap[i++].s="*";
141
bootstrap[i++].f=Xassign;
142
bootstrap[i++].f=Xmark;
143
bootstrap[i++].f=Xmark;
144
bootstrap[i++].f=Xword;
145
bootstrap[i++].s="*";
146
bootstrap[i++].f=Xdol;
147
bootstrap[i++].f=Xword;
148
bootstrap[i++].s=rcmain;
149
bootstrap[i++].f=Xword;
162
bootstrap[i++].i = 1;
163
bootstrap[i++].f = Xmark;
164
bootstrap[i++].f = Xword;
165
bootstrap[i++].s="*";
166
bootstrap[i++].f = Xassign;
167
bootstrap[i++].f = Xmark;
168
bootstrap[i++].f = Xmark;
169
bootstrap[i++].f = Xword;
170
bootstrap[i++].s="*";
171
bootstrap[i++].f = Xdol;
172
bootstrap[i++].f = Xword;
173
bootstrap[i++].s = rcmain;
174
bootstrap[i++].f = Xword;
150
175
bootstrap[i++].s=".";
151
bootstrap[i++].f=Xsimple;
152
bootstrap[i++].f=Xexit;
176
bootstrap[i++].f = Xsimple;
177
bootstrap[i++].f = Xexit;
154
179
start(bootstrap, 1, (var *)0);
155
180
/* prime bootstrap argv */
157
182
argv0 = strdup(argv[0]);
158
for(i=argc-1;i!=0;--i) pushword(argv[i]);
183
for(i = argc-1;i!=0;--i) pushword(argv[i]);
160
if(flag['r']) pfnc(err, runq);
162
188
(*runq->code[runq->pc-1].f)();
168
194
* Opcode routines
232
int null=open("/dev/null", 0);
237
Xerror("Can't open /dev/null\n");
240
switch(pid=rfork(RFFDG|RFPROC|RFNOTEG)){
247
* I don't know what the right thing to do here is,
248
* so this is all experimentally determined.
249
* If we just dup /dev/null onto 0, then running
250
* ssh foo & will reopen /dev/tty, try to read a password,
251
* get a signal, and repeat, in a tight loop, forever.
252
* Arguably this is a bug in ssh (it behaves the same
253
* way under bash as under rc) but I'm fixing it here
254
* anyway. If we dissociate the process from the tty,
255
* then it won't be able to open /dev/tty ever again.
256
* The SIG_IGN on SIGTTOU makes writing the tty
257
* (via fd 1 or 2, for example) succeed even though
258
* our pgrp is not the terminal's controlling pgrp.
260
if((tty=open("/dev/tty", OREAD)) >= 0){
262
* Should make reads of tty fail, writes succeed.
264
signal(SIGTTIN, SIG_IGN);
265
signal(SIGTTOU, SIG_IGN);
266
ioctl(tty, TIOCNOTTY);
270
pushredir(ROPEN, null, 0);
273
start(runq->code, runq->pc+1, runq->local);
278
runq->pc=runq->code[runq->pc].i;
280
setvar("apid", newword(npid, (word *)0));
288
276
setstatus(truestatus()?"false":"");
291
282
pushredir(RCLOSE, runq->code[runq->pc].i, 0);
295
289
pushredir(RDUP, runq->code[runq->pc].i, runq->code[runq->pc+1].i);
299
296
if(eflagok && !truestatus()) Xexit();
302
302
struct var *trapreq;
303
303
struct word *starval;
304
static int beenhere=0;
304
static int beenhere = 0;
305
305
if(getpid()==mypid && !beenhere){
306
trapreq=vlook("sigexit");
306
trapreq = vlook("sigexit");
310
starval=vlook("*")->val;
310
starval = vlook("*")->val;
311
311
start(trapreq->fn, trapreq->pc, (struct var *)0);
312
runq->local=newvar(strdup("*"), runq->local);
313
runq->local->val=copywords(starval, (struct word *)0);
314
runq->local->changed=1;
315
runq->redir=runq->startredir=0;
312
runq->local = newvar(strdup("*"), runq->local);
313
runq->local->val = copywords(starval, (struct word *)0);
314
runq->local->changed = 1;
315
runq->redir = runq->startredir = 0;
319
319
Exit(getstatus());
322
if(truestatus()) runq->pc=runq->code[runq->pc].i;
325
if(truestatus()) runq->pc = runq->code[runq->pc].i;
325
328
int ifnot; /* dynamic if not flag */
330
runq->pc=runq->code[runq->pc].i;
333
runq->pc=runq->code[runq->pc].i;
336
runq->pc = runq->code[runq->pc].i;
342
runq->pc = runq->code[runq->pc].i;
344
switch(count(runq->argv->words)){
345
default: Xerror1("< requires singleton\n"); return;
346
case 0: Xerror1("< requires file\n"); return;
349
file=runq->argv->words->word;
350
if((f=open(file, 0))<0){
351
pfmt(err, "%s: ", file);
352
Xerror("can't open");
355
pushredir(ROPEN, f, runq->code[runq->pc].i);
359
void turfredir(void){
362
switch(count(runq->argv->words)){
364
Xerror1("< requires singleton\n");
367
Xerror1("< requires file\n");
372
file = runq->argv->words->word;
373
if((f = open(file, 0))<0){
374
pfmt(err, "%s: ", file);
375
Xerror("can't open");
378
pushredir(ROPEN, f, runq->code[runq->pc].i);
389
switch(count(runq->argv->words)){
391
Xerror1("<> requires singleton\n");
394
Xerror1("<> requires file\n");
399
file = runq->argv->words->word;
400
if((f = open(file, ORDWR))<0){
401
pfmt(err, "%s: ", file);
402
Xerror("can't open");
405
pushredir(ROPEN, f, runq->code[runq->pc].i);
360
413
while(runq->redir!=runq->startredir)
363
void Xpopredir(void){
364
struct redir *rp=runq->redir;
365
if(rp==0) panic("turfredir null!", 0);
366
runq->redir=rp->next;
367
if(rp->type==ROPEN) close(rp->from);
420
struct redir *rp = runq->redir;
422
panic("turfredir null!", 0);
423
runq->redir = rp->next;
368
426
efree((char *)rp);
371
struct thread *p=runq;
432
struct thread *p = runq;
373
434
while(p->argv) poplist();
374
435
codefree(p->code);
376
437
efree((char *)p);
377
if(runq==0) Exit(getstatus());
380
if(truestatus()) runq->pc++;
381
else runq->pc=runq->code[runq->pc].i;
385
if(truestatus()) runq->pc++;
386
else runq->pc=runq->code[runq->pc].i;
445
if(truestatus()) runq->pc++;
446
else runq->pc = runq->code[runq->pc].i;
453
if(truestatus()) runq->pc++;
454
else runq->pc = runq->code[runq->pc].i;
392
466
pushword(runq->code[runq->pc++].s);
397
474
switch(count(runq->argv->words)){
398
default: Xerror1("> requires singleton\n"); return;
399
case 0: Xerror1("> requires file\n"); return;
476
Xerror1("> requires singleton\n");
479
Xerror1("> requires file\n");
402
file=runq->argv->words->word;
403
if((f=Creat(file))<0){
484
file = runq->argv->words->word;
485
if((f = Creat(file))<0){
404
486
pfmt(err, "%s: ", file);
405
487
Xerror("can't open");
460
runq->pc=runq->code[runq->pc].i;
549
runq->pc = runq->code[runq->pc].i;
463
word *conclist(word *lp, word *rp, word *tail)
554
conclist(word *lp, word *rp, word *tail)
467
558
if(lp->next || rp->next)
468
tail=conclist(lp->next==0?lp:lp->next, rp->next==0?rp:rp->next,
559
tail = conclist(lp->next==0?lp:lp->next, rp->next==0?rp:rp->next,
470
buf=emalloc(strlen(lp->word)+strlen(rp->word)+1);
561
buf = emalloc(strlen(lp->word)+strlen(rp->word)+1);
471
562
strcpy(buf, lp->word);
472
563
strcat(buf, rp->word);
473
v=newword(buf, tail);
564
v = newword(buf, tail);
478
word *lp=runq->argv->words;
479
word *rp=runq->argv->next->words;
480
word *vp=runq->argv->next->next->words;
481
int lc=count(lp), rc=count(rp);
572
word *lp = runq->argv->words;
573
word *rp = runq->argv->next->words;
574
word *vp = runq->argv->next->next->words;
575
int lc = count(lp), rc = count(rp);
482
576
if(lc!=0 || rc!=0){
483
577
if(lc==0 || rc==0){
484
578
Xerror1("null list in concatenation");
488
582
Xerror1("mismatched list lengths in concatenation");
491
vp=conclist(lp, rp, vp);
585
vp = conclist(lp, rp, vp);
495
runq->argv->words=vp;
589
runq->argv->words = vp;
499
596
if(count(runq->argv->words)!=1){
500
597
Xerror1("variable name not singleton!");
503
600
deglob(runq->argv->words->word);
504
v=vlook(runq->argv->words->word);
601
v = vlook(runq->argv->words->word);
507
604
freewords(v->val);
508
v->val=runq->argv->words;
605
v->val = runq->argv->words;
609
runq->argv->words = 0;
516
613
* copy arglist a, adding the copy to the front of tail
518
word *copywords(word *a, word *tail)
617
copywords(word *a, word *tail)
521
for(end=&v;a;a=a->next,end=&(*end)->next)
522
*end=newword(a->word, 0);
620
for(end=&v;a;a = a->next,end=&(*end)->next)
621
*end = newword(a->word, 0);
582
word *subwords(word *val, int len, word *sub, word *a)
689
copynwords(word *a, word *tail, int n)
696
*end = newword(a->word, 0);
705
subwords(word *val, int len, word *sub, word *a)
587
a=subwords(val, len, sub->next, a);
711
a = subwords(val, len, sub->next, a);
591
while('0'<=*s && *s<='9') n=n*10+ *s++ -'0';
592
if(n<1 || len<n) return a;
593
for(;n!=1;--n) val=val->next;
594
return newword(val->word, a);
716
while('0'<=*s && *s<='9')
722
while('0'<=*s && *s<='9')
727
if(n<1 || n>len || m<0)
733
return copynwords(val, a, m+1);
599
741
if(count(runq->argv->next->words)!=1){
600
742
Xerror1("variable name not singleton!");
603
s=runq->argv->next->words->word;
745
s = runq->argv->next->words->word;
605
a=runq->argv->next->next->words;
607
a=subwords(v, count(v), runq->argv->words, a);
747
a = runq->argv->next->next->words;
749
a = subwords(v, count(v), runq->argv->words, a);
752
runq->argv->words = a;
618
763
Xerror1("variable name not singleton!");
621
s=runq->argv->words->word;
766
s = runq->argv->words->word;
624
for(t=s;'0'<=*t && *t<='9';t++) n=n*10+*t-'0';
769
for(t = s;'0'<=*t && *t<='9';t++) n = n*10+*t-'0';
772
inttoascii(num, count(a));
631
itoa(num, a && 1<=n && n<=count(a)?1:0);
776
inttoascii(num, a && 1<=n && n<=count(a)?1:0);
637
785
if(count(runq->argv->words)!=1){
638
786
Xerror1("variable name must be singleton\n");
641
789
deglob(runq->argv->words->word);
642
runq->local=newvar(strdup(runq->argv->words->word), runq->local);
643
runq->local->val=copywords(runq->argv->next->words, (word *)0);
644
runq->local->changed=1;
790
runq->local = newvar(strdup(runq->argv->words->word), runq->local);
791
runq->local->val = copywords(runq->argv->next->words, (word *)0);
792
runq->local->changed = 1;
649
var *v=runq->local, *hid;
650
if(v==0) panic("Xunlocal: no locals!", 0);
800
var *v = runq->local, *hid;
802
panic("Xunlocal: no locals!", 0);
803
runq->local = v->next;
804
hid = vlook(v->name);
655
807
freewords(v->val);
656
808
efree((char *)v);
658
void freewords(word *w)
664
818
efree((char *)w);
672
end=runq->code[runq->pc].i;
673
for(a=runq->argv->words;a;a=a->next){
675
if(v->fn) codefree(v->fn);
676
v->fn=codecopy(runq->code);
829
end = runq->code[runq->pc].i;
830
for(a = runq->argv->words;a;a = a->next){
834
v->fn = codecopy(runq->code);
686
for(a=runq->argv->words;a;a=a->next){
688
if(v->fn) codefree(v->fn);
847
for(a = runq->argv->words;a;a = a->next){
695
struct thread *p=runq;
696
int pc=p->pc, forkid;
697
int lfd=p->code[pc++].i;
698
int rfd=p->code[pc++].i;
701
Xerror("can't get pipe");
704
switch(forkid=fork()){
709
start(p->code, pc+2, runq->local);
712
pushredir(ROPEN, pfd[PWR], lfd);
715
start(p->code, p->code[pc].i, runq->local);
717
pushredir(ROPEN, pfd[PRD], rfd);
718
p->pc=p->code[pc+1].i;
723
char *concstatus(char *s, char *t)
858
concstatus(char *s, char *t)
725
860
static char v[NSTATUS+1];
727
862
strncpy(v, s, NSTATUS);
800
946
setstatus("error");
801
947
while(!runq->iflag) Xreturn();
806
char *s, *ewd=&wd[8192], *stop;
808
var *ifs=vlook("ifs");
812
stop=ifs->val?ifs->val->word:"";
814
Xerror("can't make pipe");
818
case -1: Xerror("try again");
824
start(runq->code, runq->pc+1, runq->local);
825
pushredir(ROPEN, pfd[PWR], 1);
832
while((c=rchr(f))!=EOF){
833
if(strchr(stop, c) || s==ewd){
848
/* v points to reversed arglist -- reverse it onto argv */
851
v->next=runq->argv->words;
855
runq->pc=runq->code[runq->pc].i;
860
* Who should wait for the exit from the fork?
863
struct thread *p=runq;
869
Xerror("can't get pipe");
872
if(p->code[pc].i==READ){
885
start(p->code, pc+2, runq->local);
887
pushredir(ROPEN, sidefd, p->code[pc].i==READ?1:0);
892
pushredir(ROPEN, mainfd, mainfd); /* isn't this a noop? */
893
strcpy(name, Fdprefix);
894
itoa(name+strlen(name), mainfd);
896
p->pc=p->code[pc+1].i;
900
void Xsubshell(void){
907
start(runq->code, runq->pc+1, runq->local);
912
runq->pc=runq->code[runq->pc].i;
916
void setstatus(char *s)
918
953
setvar("status", newword(s, (word *)0));
920
char *getstatus(void){
921
var *status=vlook("status");
959
var *status = vlook("status");
922
960
return status->val?status->val->word:"";
924
int truestatus(void){
926
for(s=getstatus();*s;s++)
927
if(*s!='|' && *s!='0') return 0;
967
for(s = getstatus();*s;s++)
968
if(*s!='|' && *s!='0')
931
976
Unlink(runq->code[runq->pc++].s);
934
982
if(runq->argv->words==0){
936
runq->pc=runq->code[runq->pc].i;
984
runq->pc = runq->code[runq->pc].i;
939
987
freelist(runq->local->val);
940
runq->local->val=runq->argv->words;
941
runq->local->changed=1;
942
runq->argv->words=runq->argv->words->next;
943
runq->local->val->next=0;
988
runq->local->val = runq->argv->words;
989
runq->local->changed = 1;
990
runq->argv->words = runq->argv->words->next;
991
runq->local->val->next = 0;