simple.c 8.8 KB

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