simple.c 9.0 KB

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