simple.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  1. /*
  2. * Maybe `simple' is a misnomer.
  3. */
  4. #include "rc.h"
  5. #include "getflags.h"
  6. #include "exec.h"
  7. #include "io.h"
  8. #include "fns.h"
  9. /*
  10. * Search through the following code to see if we're just going to exit.
  11. */
  12. exitnext(void){
  13. union code *c=&runq->code[runq->pc];
  14. while(c->f==Xpopredir) c++;
  15. return c->f==Xexit;
  16. }
  17. void Xsimple(void){
  18. word *a;
  19. thread *p=runq;
  20. var *v;
  21. struct builtin *bp;
  22. int pid, n;
  23. char buf[ERRMAX];
  24. globlist();
  25. a=runq->argv->words;
  26. if(a==0){
  27. Xerror1("empty argument list");
  28. return;
  29. }
  30. if(flag['x'])
  31. pfmt(err, "%v\n", p->argv->words); /* wrong, should do redirs */
  32. v=gvlook(a->word);
  33. if(v->fn)
  34. execfunc(v);
  35. else{
  36. if(strcmp(a->word, "builtin")==0){
  37. if(count(a)==1){
  38. pfmt(err, "builtin: empty argument list\n");
  39. setstatus("empty arg list");
  40. poplist();
  41. return;
  42. }
  43. a=a->next;
  44. popword();
  45. }
  46. for(bp=Builtin;bp->name;bp++)
  47. if(strcmp(a->word, bp->name)==0){
  48. (*bp->fnc)();
  49. return;
  50. }
  51. if(exitnext()){
  52. /* fork and wait is redundant */
  53. pushword("exec");
  54. execexec();
  55. Xexit();
  56. }
  57. else{
  58. flush(err);
  59. Updenv(); /* necessary so changes don't go out again */
  60. switch(pid=fork()){
  61. case -1:
  62. Xerror("try again");
  63. return;
  64. case 0:
  65. pushword("exec");
  66. execexec();
  67. strcpy(buf, "can't exec: ");
  68. n = strlen(buf);
  69. errstr(buf+n, ERRMAX-n);
  70. Exit(buf);
  71. default:
  72. poplist();
  73. /* interrupts don't get us out */
  74. while(Waitfor(pid, 1) < 0)
  75. ;
  76. }
  77. }
  78. }
  79. }
  80. struct word nullpath={ "", 0};
  81. void doredir(redir *rp)
  82. {
  83. if(rp){
  84. doredir(rp->next);
  85. switch(rp->type){
  86. case ROPEN:
  87. if(rp->from!=rp->to){
  88. Dup(rp->from, rp->to);
  89. close(rp->from);
  90. }
  91. break;
  92. case RDUP: Dup(rp->from, rp->to); break;
  93. case RCLOSE: close(rp->from); break;
  94. }
  95. }
  96. }
  97. word *searchpath(char *w){
  98. word *path;
  99. if(strncmp(w, "/", 1)==0
  100. || strncmp(w, "#", 1)==0
  101. || strncmp(w, "./", 2)==0
  102. || strncmp(w, "../", 3)==0
  103. || (path=vlook("path")->val)==0)
  104. path=&nullpath;
  105. return path;
  106. }
  107. void execexec(void){
  108. popword(); /* "exec" */
  109. if(runq->argv->words==0){
  110. Xerror1("empty argument list");
  111. return;
  112. }
  113. doredir(runq->redir);
  114. Execute(runq->argv->words, searchpath(runq->argv->words->word));
  115. poplist();
  116. }
  117. void execfunc(var *func)
  118. {
  119. word *starval;
  120. popword();
  121. starval=runq->argv->words;
  122. runq->argv->words=0;
  123. poplist();
  124. start(func->fn, func->pc, (struct var *)0);
  125. runq->local=newvar(strdup("*"), runq->local);
  126. runq->local->val=starval;
  127. runq->local->changed=1;
  128. }
  129. int dochdir(char *word){
  130. /* report to /dev/wdir if it exists and we're interactive */
  131. static int wdirfd = -2;
  132. if(chdir(word)<0) return -1;
  133. if(flag['i']!=0){
  134. if(wdirfd==-2) /* try only once */
  135. wdirfd = open("/dev/wdir", OWRITE|OCEXEC);
  136. if(wdirfd>=0)
  137. write(wdirfd, word, strlen(word));
  138. }
  139. return 1;
  140. }
  141. void execcd(void){
  142. word *a=runq->argv->words;
  143. word *cdpath;
  144. char dir[512];
  145. setstatus("can't cd");
  146. cdpath=vlook("cdpath")->val;
  147. switch(count(a)){
  148. default:
  149. pfmt(err, "Usage: cd [directory]\n");
  150. break;
  151. case 2:
  152. if(a->next->word[0]=='/' || cdpath==0) cdpath=&nullpath;
  153. for(;cdpath;cdpath=cdpath->next){
  154. strcpy(dir, cdpath->word);
  155. if(dir[0]) strcat(dir, "/");
  156. strcat(dir, a->next->word);
  157. if(dochdir(dir)>=0){
  158. if(strlen(cdpath->word)
  159. && strcmp(cdpath->word, ".")!=0)
  160. pfmt(err, "%s\n", dir);
  161. setstatus("");
  162. break;
  163. }
  164. }
  165. if(cdpath==0) pfmt(err, "Can't cd %s: %r\n", a->next->word);
  166. break;
  167. case 1:
  168. a=vlook("home")->val;
  169. if(count(a)>=1){
  170. if(dochdir(a->word)>=0)
  171. setstatus("");
  172. else
  173. pfmt(err, "Can't cd %s: %r\n", a->word);
  174. }
  175. else
  176. pfmt(err, "Can't cd -- $home empty\n");
  177. break;
  178. }
  179. poplist();
  180. }
  181. void execexit(void){
  182. switch(count(runq->argv->words)){
  183. default: pfmt(err, "Usage: exit [status]\nExiting anyway\n");
  184. case 2: setstatus(runq->argv->words->next->word);
  185. case 1: Xexit();
  186. }
  187. }
  188. void execshift(void){
  189. int n;
  190. word *a;
  191. var *star;
  192. switch(count(runq->argv->words)){
  193. default:
  194. pfmt(err, "Usage: shift [n]\n");
  195. setstatus("shift usage");
  196. poplist();
  197. return;
  198. case 2: n=atoi(runq->argv->words->next->word); break;
  199. case 1: n=1; break;
  200. }
  201. star=vlook("*");
  202. for(;n && star->val;--n){
  203. a=star->val->next;
  204. efree(star->val->word);
  205. efree((char *)star->val);
  206. star->val=a;
  207. star->changed=1;
  208. }
  209. setstatus("");
  210. poplist();
  211. }
  212. int octal(char *s)
  213. {
  214. int n=0;
  215. while(*s==' ' || *s=='\t' || *s=='\n') s++;
  216. while('0'<=*s && *s<='7') n=n*8+*s++-'0';
  217. return n;
  218. }
  219. int mapfd(int fd)
  220. {
  221. redir *rp;
  222. for(rp=runq->redir;rp;rp=rp->next){
  223. switch(rp->type){
  224. case RCLOSE:
  225. if(rp->from==fd) fd=-1;
  226. break;
  227. case RDUP:
  228. case ROPEN:
  229. if(rp->to==fd) fd=rp->from;
  230. break;
  231. }
  232. }
  233. return fd;
  234. }
  235. union code rdcmds[4];
  236. void execcmds(io *f)
  237. {
  238. static int first=1;
  239. if(first){
  240. rdcmds[0].i=1;
  241. rdcmds[1].f=Xrdcmds;
  242. rdcmds[2].f=Xreturn;
  243. first=0;
  244. }
  245. start(rdcmds, 1, runq->local);
  246. runq->cmdfd=f;
  247. runq->iflast=0;
  248. }
  249. void execeval(void){
  250. char *cmdline, *s, *t;
  251. int len=0;
  252. word *ap;
  253. if(count(runq->argv->words)<=1){
  254. Xerror1("Usage: eval cmd ...");
  255. return;
  256. }
  257. eflagok=1;
  258. for(ap=runq->argv->words->next;ap;ap=ap->next)
  259. len+=1+strlen(ap->word);
  260. cmdline=emalloc(len);
  261. s=cmdline;
  262. for(ap=runq->argv->words->next;ap;ap=ap->next){
  263. for(t=ap->word;*t;) *s++=*t++;
  264. *s++=' ';
  265. }
  266. s[-1]='\n';
  267. poplist();
  268. execcmds(opencore(cmdline, len));
  269. efree(cmdline);
  270. }
  271. union code dotcmds[14];
  272. void execdot(void){
  273. int iflag=0;
  274. int fd;
  275. list *av;
  276. thread *p=runq;
  277. char *zero;
  278. static int first=1;
  279. char file[512];
  280. word *path;
  281. if(first){
  282. dotcmds[0].i=1;
  283. dotcmds[1].f=Xmark;
  284. dotcmds[2].f=Xword;
  285. dotcmds[3].s="0";
  286. dotcmds[4].f=Xlocal;
  287. dotcmds[5].f=Xmark;
  288. dotcmds[6].f=Xword;
  289. dotcmds[7].s="*";
  290. dotcmds[8].f=Xlocal;
  291. dotcmds[9].f=Xrdcmds;
  292. dotcmds[10].f=Xunlocal;
  293. dotcmds[11].f=Xunlocal;
  294. dotcmds[12].f=Xreturn;
  295. first=0;
  296. }
  297. else
  298. eflagok=1;
  299. popword();
  300. if(p->argv->words && strcmp(p->argv->words->word, "-i")==0){
  301. iflag=1;
  302. popword();
  303. }
  304. /* get input file */
  305. if(p->argv->words==0){
  306. Xerror1("Usage: . [-i] file [arg ...]");
  307. return;
  308. }
  309. zero=strdup(p->argv->words->word);
  310. popword();
  311. fd=-1;
  312. for(path=searchpath(zero);path;path=path->next){
  313. strcpy(file, path->word);
  314. if(file[0]) strcat(file, "/");
  315. strcat(file, zero);
  316. if((fd=open(file, 0))>=0) break;
  317. if(strcmp(file, "/dev/stdin")==0){ /* for sun & ucb */
  318. fd=Dup1(0);
  319. if(fd>=0) break;
  320. }
  321. }
  322. if(fd<0){
  323. pfmt(err, "%s: ", zero);
  324. setstatus("can't open");
  325. Xerror(".: can't open");
  326. return;
  327. }
  328. /* set up for a new command loop */
  329. start(dotcmds, 1, (struct var *)0);
  330. pushredir(RCLOSE, fd, 0);
  331. runq->cmdfile=zero;
  332. runq->cmdfd=openfd(fd);
  333. runq->iflag=iflag;
  334. runq->iflast=0;
  335. /* push $* value */
  336. pushlist();
  337. runq->argv->words=p->argv->words;
  338. /* free caller's copy of $* */
  339. av=p->argv;
  340. p->argv=av->next;
  341. efree((char *)av);
  342. /* push $0 value */
  343. pushlist();
  344. pushword(zero);
  345. ndot++;
  346. }
  347. void execflag(void){
  348. char *letter, *val;
  349. switch(count(runq->argv->words)){
  350. case 2:
  351. setstatus(flag[runq->argv->words->next->word[0]]?"":"flag not set");
  352. break;
  353. case 3:
  354. letter=runq->argv->words->next->word;
  355. val=runq->argv->words->next->next->word;
  356. if(strlen(letter)==1){
  357. if(strcmp(val, "+")==0){
  358. flag[letter[0]]=flagset;
  359. break;
  360. }
  361. if(strcmp(val, "-")==0){
  362. flag[letter[0]]=0;
  363. break;
  364. }
  365. }
  366. default:
  367. Xerror1("Usage: flag [letter] [+-]");
  368. return;
  369. }
  370. poplist();
  371. }
  372. void execwhatis(void){ /* mildly wrong -- should fork before writing */
  373. word *a, *b, *path;
  374. var *v;
  375. struct builtin *bp;
  376. char file[512];
  377. struct io out[1];
  378. int found, sep;
  379. a=runq->argv->words->next;
  380. if(a==0){
  381. Xerror1("Usage: whatis name ...");
  382. return;
  383. }
  384. setstatus("");
  385. out->fd=mapfd(1);
  386. out->bufp=out->buf;
  387. out->ebuf=&out->buf[NBUF];
  388. out->strp=0;
  389. for(;a;a=a->next){
  390. v=vlook(a->word);
  391. if(v->val){
  392. pfmt(out, "%s=", a->word);
  393. if(v->val->next==0)
  394. pfmt(out, "%q\n", v->val->word);
  395. else{
  396. sep='(';
  397. for(b=v->val;b && b->word;b=b->next){
  398. pfmt(out, "%c%q", sep, b->word);
  399. sep=' ';
  400. }
  401. pfmt(out, ")\n");
  402. }
  403. found=1;
  404. }
  405. else
  406. found=0;
  407. v=gvlook(a->word);
  408. if(v->fn) pfmt(out, "fn %s %s\n", v->name, v->fn[v->pc-1].s);
  409. else{
  410. for(bp=Builtin;bp->name;bp++)
  411. if(strcmp(a->word, bp->name)==0){
  412. pfmt(out, "builtin %s\n", a->word);
  413. break;
  414. }
  415. if(!bp->name){
  416. for(path=searchpath(a->word);path;path=path->next){
  417. strcpy(file, path->word);
  418. if(file[0]) strcat(file, "/");
  419. strcat(file, a->word);
  420. if(Executable(file)){
  421. pfmt(out, "%s\n", file);
  422. break;
  423. }
  424. }
  425. if(!path && !found){
  426. pfmt(err, "%s: not found\n", a->word);
  427. setstatus("not found");
  428. }
  429. }
  430. }
  431. }
  432. poplist();
  433. flush(err);
  434. }
  435. void execwait(void){
  436. switch(count(runq->argv->words)){
  437. default: Xerror1("Usage: wait [pid]"); return;
  438. case 2: Waitfor(atoi(runq->argv->words->next->word), 0); break;
  439. case 1: Waitfor(-1, 0); break;
  440. }
  441. poplist();
  442. }