exec.c 18 KB

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