plan9.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670
  1. /*
  2. * Plan 9 versions of system-specific functions
  3. * By convention, exported routines herein have names beginning with an
  4. * upper case letter.
  5. */
  6. #include "rc.h"
  7. #include "exec.h"
  8. #include "io.h"
  9. #include "fns.h"
  10. #include "getflags.h"
  11. enum {
  12. Maxenvname = 256, /* undocumented limit */
  13. };
  14. char *Signame[] = {
  15. "sigexit", "sighup", "sigint", "sigquit",
  16. "sigalrm", "sigkill", "sigfpe", "sigterm",
  17. 0
  18. };
  19. char *syssigname[] = {
  20. "exit", /* can't happen */
  21. "hangup",
  22. "interrupt",
  23. "quit", /* can't happen */
  24. "alarm",
  25. "kill",
  26. "sys: fp: ",
  27. "term",
  28. 0
  29. };
  30. char Rcmain[]="/rc/lib/rcmain";
  31. char Fdprefix[]="/fd/";
  32. void execfinit(void);
  33. void execbind(void);
  34. void execmount(void);
  35. void execnewpgrp(void);
  36. builtin Builtin[] = {
  37. "cd", execcd,
  38. "whatis", execwhatis,
  39. "eval", execeval,
  40. "exec", execexec, /* but with popword first */
  41. "exit", execexit,
  42. "shift", execshift,
  43. "wait", execwait,
  44. ".", execdot,
  45. "finit", execfinit,
  46. "flag", execflag,
  47. "rfork", execnewpgrp,
  48. 0
  49. };
  50. void
  51. execnewpgrp(void)
  52. {
  53. int arg;
  54. char *s;
  55. switch(count(runq->argv->words)){
  56. case 1:
  57. arg = RFENVG|RFNAMEG|RFNOTEG;
  58. break;
  59. case 2:
  60. arg = 0;
  61. for(s = runq->argv->words->next->word;*s;s++) switch(*s){
  62. default:
  63. goto Usage;
  64. case 'n':
  65. arg|=RFNAMEG; break;
  66. case 'N':
  67. arg|=RFCNAMEG;
  68. break;
  69. case 'm':
  70. arg|=RFNOMNT; break;
  71. case 'e':
  72. arg|=RFENVG; break;
  73. case 'E':
  74. arg|=RFCENVG; break;
  75. case 's':
  76. arg|=RFNOTEG; break;
  77. case 'f':
  78. arg|=RFFDG; break;
  79. case 'F':
  80. arg|=RFCFDG; break;
  81. }
  82. break;
  83. default:
  84. Usage:
  85. pfmt(err, "Usage: %s [fnesFNEm]\n", runq->argv->words->word);
  86. setstatus("rfork usage");
  87. poplist();
  88. return;
  89. }
  90. if(rfork(arg)==-1){
  91. pfmt(err, "rc: %s failed\n", runq->argv->words->word);
  92. setstatus("rfork failed");
  93. }
  94. else
  95. setstatus("");
  96. poplist();
  97. }
  98. void
  99. Vinit(void)
  100. {
  101. int dir, f, len, i, n, nent;
  102. char *buf, *s;
  103. char envname[Maxenvname];
  104. word *val;
  105. Dir *ent;
  106. dir = open("/env", OREAD);
  107. if(dir<0){
  108. pfmt(err, "rc: can't open /env: %r\n");
  109. return;
  110. }
  111. ent = nil;
  112. for(;;){
  113. nent = dirread(dir, &ent);
  114. if(nent <= 0)
  115. break;
  116. for(i = 0; i<nent; i++){
  117. len = ent[i].length;
  118. if(len && strncmp(ent[i].name, "fn#", 3)!=0){
  119. snprint(envname, sizeof envname, "/env/%s", ent[i].name);
  120. if((f = open(envname, 0))>=0){
  121. buf = emalloc(len+1);
  122. n = readn(f, buf, len);
  123. if (n <= 0)
  124. buf[0] = '\0';
  125. else
  126. buf[n] = '\0';
  127. val = 0;
  128. /* Charitably add a 0 at the end if need be */
  129. if(buf[len-1])
  130. buf[len++]='\0';
  131. s = buf+len-1;
  132. for(;;){
  133. while(s!=buf && s[-1]!='\0') --s;
  134. val = newword(s, val);
  135. if(s==buf)
  136. break;
  137. --s;
  138. }
  139. setvar(ent[i].name, val);
  140. vlook(ent[i].name)->changed = 0;
  141. close(f);
  142. efree(buf);
  143. }
  144. }
  145. }
  146. free(ent);
  147. }
  148. close(dir);
  149. }
  150. int envdir;
  151. void
  152. Xrdfn(void)
  153. {
  154. int f, len;
  155. Dir *e;
  156. char envname[Maxenvname];
  157. static Dir *ent, *allocent;
  158. static int nent;
  159. for(;;){
  160. if(nent == 0){
  161. free(allocent);
  162. nent = dirread(envdir, &allocent);
  163. ent = allocent;
  164. }
  165. if(nent <= 0)
  166. break;
  167. while(nent){
  168. e = ent++;
  169. nent--;
  170. len = e->length;
  171. if(len && strncmp(e->name, "fn#", 3)==0){
  172. snprint(envname, sizeof envname, "/env/%s", e->name);
  173. if((f = open(envname, 0))>=0){
  174. execcmds(openfd(f));
  175. return;
  176. }
  177. }
  178. }
  179. }
  180. close(envdir);
  181. Xreturn();
  182. }
  183. union code rdfns[4];
  184. void
  185. execfinit(void)
  186. {
  187. static int first = 1;
  188. if(first){
  189. rdfns[0].i = 1;
  190. rdfns[1].f = Xrdfn;
  191. rdfns[2].f = Xjump;
  192. rdfns[3].i = 1;
  193. first = 0;
  194. }
  195. Xpopm();
  196. envdir = open("/env", 0);
  197. if(envdir<0){
  198. pfmt(err, "rc: can't open /env: %r\n");
  199. return;
  200. }
  201. start(rdfns, 1, runq->local);
  202. }
  203. int
  204. Waitfor(int pid, int)
  205. {
  206. thread *p;
  207. Waitmsg *w;
  208. char errbuf[ERRMAX];
  209. if(pid >= 0 && !havewaitpid(pid))
  210. return 0;
  211. while((w = wait()) != nil){
  212. delwaitpid(w->pid);
  213. if(w->pid==pid){
  214. setstatus(w->msg);
  215. free(w);
  216. return 0;
  217. }
  218. for(p = runq->ret;p;p = p->ret)
  219. if(p->pid==w->pid){
  220. p->pid=-1;
  221. strcpy(p->status, w->msg);
  222. }
  223. free(w);
  224. }
  225. errstr(errbuf, sizeof errbuf);
  226. if(strcmp(errbuf, "interrupted")==0) return -1;
  227. return 0;
  228. }
  229. char **
  230. mkargv(word *a)
  231. {
  232. char **argv = (char **)emalloc((count(a)+2)*sizeof(char *));
  233. char **argp = argv+1; /* leave one at front for runcoms */
  234. for(;a;a = a->next) *argp++=a->word;
  235. *argp = 0;
  236. return argv;
  237. }
  238. void
  239. addenv(var *v)
  240. {
  241. char envname[Maxenvname];
  242. word *w;
  243. int f;
  244. io *fd;
  245. if(v->changed){
  246. v->changed = 0;
  247. snprint(envname, sizeof envname, "/env/%s", v->name);
  248. if((f = Creat(envname))<0)
  249. pfmt(err, "rc: can't open %s: %r\n", envname);
  250. else{
  251. for(w = v->val;w;w = w->next)
  252. write(f, w->word, strlen(w->word)+1L);
  253. close(f);
  254. }
  255. }
  256. if(v->fnchanged){
  257. v->fnchanged = 0;
  258. snprint(envname, sizeof envname, "/env/fn#%s", v->name);
  259. if((f = Creat(envname))<0)
  260. pfmt(err, "rc: can't open %s: %r\n", envname);
  261. else{
  262. if(v->fn){
  263. fd = openfd(f);
  264. pfmt(fd, "fn %q %s\n", v->name, v->fn[v->pc-1].s);
  265. closeio(fd);
  266. }
  267. close(f);
  268. }
  269. }
  270. }
  271. void
  272. updenvlocal(var *v)
  273. {
  274. if(v){
  275. updenvlocal(v->next);
  276. addenv(v);
  277. }
  278. }
  279. void
  280. Updenv(void)
  281. {
  282. var *v, **h;
  283. for(h = gvar;h!=&gvar[NVAR];h++)
  284. for(v=*h;v;v = v->next)
  285. addenv(v);
  286. if(runq)
  287. updenvlocal(runq->local);
  288. }
  289. /* not used on plan 9 */
  290. int
  291. ForkExecute(char *file, char **argv, int sin, int sout, int serr)
  292. {
  293. int pid;
  294. if(access(file, 1) != 0)
  295. return -1;
  296. switch(pid = fork()){
  297. case -1:
  298. return -1;
  299. case 0:
  300. if(sin >= 0)
  301. dup(sin, 0);
  302. else
  303. close(0);
  304. if(sout >= 0)
  305. dup(sout, 1);
  306. else
  307. close(1);
  308. if(serr >= 0)
  309. dup(serr, 2);
  310. else
  311. close(2);
  312. exec(file, argv);
  313. exits(file);
  314. }
  315. return pid;
  316. }
  317. void
  318. Execute(word *args, word *path)
  319. {
  320. char **argv = mkargv(args);
  321. char file[1024], errstr[1024];
  322. int nc;
  323. Updenv();
  324. errstr[0] = '\0';
  325. for(;path;path = path->next){
  326. nc = strlen(path->word);
  327. if(nc < sizeof file - 1){ /* 1 for / */
  328. strcpy(file, path->word);
  329. if(file[0]){
  330. strcat(file, "/");
  331. nc++;
  332. }
  333. if(nc + strlen(argv[1]) < sizeof file){
  334. strcat(file, argv[1]);
  335. exec(file, argv+1);
  336. rerrstr(errstr, sizeof errstr);
  337. /*
  338. * if file exists and is executable, exec should
  339. * have worked, unless it's a directory or an
  340. * executable for another architecture. in
  341. * particular, if it failed due to lack of
  342. * swap/vm (e.g., arg. list too long) or other
  343. * allocation failure, stop searching and print
  344. * the reason for failure.
  345. */
  346. if (strstr(errstr, " allocat") != nil ||
  347. strstr(errstr, " full") != nil)
  348. break;
  349. }
  350. else werrstr("command name too long");
  351. }
  352. }
  353. pfmt(err, "%s: %s\n", argv[1], errstr);
  354. efree((char *)argv);
  355. }
  356. #define NDIR 256 /* shoud be a better way */
  357. int
  358. Globsize(char *p)
  359. {
  360. int isglob = 0, globlen = NDIR+1;
  361. for(;*p;p++){
  362. if(*p==GLOB){
  363. p++;
  364. if(*p!=GLOB)
  365. isglob++;
  366. globlen+=*p=='*'?NDIR:1;
  367. }
  368. else
  369. globlen++;
  370. }
  371. return isglob?globlen:0;
  372. }
  373. #define NFD 50
  374. struct{
  375. Dir *dbuf;
  376. int i;
  377. int n;
  378. }dir[NFD];
  379. int
  380. Opendir(char *name)
  381. {
  382. Dir *db;
  383. int f;
  384. f = open(name, 0);
  385. if(f==-1)
  386. return f;
  387. db = dirfstat(f);
  388. if(db!=nil && (db->mode&DMDIR)){
  389. if(f<NFD){
  390. dir[f].i = 0;
  391. dir[f].n = 0;
  392. }
  393. free(db);
  394. return f;
  395. }
  396. free(db);
  397. close(f);
  398. return -1;
  399. }
  400. static int
  401. trimdirs(Dir *d, int nd)
  402. {
  403. int r, w;
  404. for(r=w=0; r<nd; r++)
  405. if(d[r].mode&DMDIR)
  406. d[w++] = d[r];
  407. return w;
  408. }
  409. /*
  410. * onlydirs is advisory -- it means you only
  411. * need to return the directories. it's okay to
  412. * return files too (e.g., on unix where you can't
  413. * tell during the readdir), but that just makes
  414. * the globber work harder.
  415. */
  416. int
  417. Readdir(int f, void *p, int onlydirs)
  418. {
  419. int n;
  420. if(f<0 || f>=NFD)
  421. return 0;
  422. Again:
  423. if(dir[f].i==dir[f].n){ /* read */
  424. free(dir[f].dbuf);
  425. dir[f].dbuf = 0;
  426. n = dirread(f, &dir[f].dbuf);
  427. if(n>0){
  428. if(onlydirs){
  429. n = trimdirs(dir[f].dbuf, n);
  430. if(n == 0)
  431. goto Again;
  432. }
  433. dir[f].n = n;
  434. }else
  435. dir[f].n = 0;
  436. dir[f].i = 0;
  437. }
  438. if(dir[f].i == dir[f].n)
  439. return 0;
  440. strcpy(p, dir[f].dbuf[dir[f].i].name);
  441. dir[f].i++;
  442. return 1;
  443. }
  444. void
  445. Closedir(int f)
  446. {
  447. if(f>=0 && f<NFD){
  448. free(dir[f].dbuf);
  449. dir[f].i = 0;
  450. dir[f].n = 0;
  451. dir[f].dbuf = 0;
  452. }
  453. close(f);
  454. }
  455. int interrupted = 0;
  456. void
  457. notifyf(void*, char *s)
  458. {
  459. int i;
  460. for(i = 0;syssigname[i];i++) if(strncmp(s, syssigname[i], strlen(syssigname[i]))==0){
  461. if(strncmp(s, "sys: ", 5)!=0) interrupted = 1;
  462. goto Out;
  463. }
  464. pfmt(err, "rc: note: %s\n", s);
  465. noted(NDFLT);
  466. return;
  467. Out:
  468. if(strcmp(s, "interrupt")!=0 || trap[i]==0){
  469. trap[i]++;
  470. ntrap++;
  471. }
  472. if(ntrap>=32){ /* rc is probably in a trap loop */
  473. pfmt(err, "rc: Too many traps (trap %s), aborting\n", s);
  474. abort();
  475. }
  476. noted(NCONT);
  477. }
  478. void
  479. Trapinit(void)
  480. {
  481. notify(notifyf);
  482. }
  483. void
  484. Unlink(char *name)
  485. {
  486. remove(name);
  487. }
  488. long
  489. Write(int fd, void *buf, long cnt)
  490. {
  491. return write(fd, buf, cnt);
  492. }
  493. long
  494. Read(int fd, void *buf, long cnt)
  495. {
  496. return read(fd, buf, cnt);
  497. }
  498. long
  499. Seek(int fd, long cnt, long whence)
  500. {
  501. return seek(fd, cnt, whence);
  502. }
  503. int
  504. Executable(char *file)
  505. {
  506. Dir *statbuf;
  507. int ret;
  508. statbuf = dirstat(file);
  509. if(statbuf == nil)
  510. return 0;
  511. ret = ((statbuf->mode&0111)!=0 && (statbuf->mode&DMDIR)==0);
  512. free(statbuf);
  513. return ret;
  514. }
  515. int
  516. Creat(char *file)
  517. {
  518. return create(file, 1, 0666L);
  519. }
  520. int
  521. Dup(int a, int b)
  522. {
  523. return dup(a, b);
  524. }
  525. int
  526. Dup1(int)
  527. {
  528. return -1;
  529. }
  530. void
  531. Exit(char *stat)
  532. {
  533. Updenv();
  534. setstatus(stat);
  535. exits(truestatus()?"":getstatus());
  536. }
  537. int
  538. Eintr(void)
  539. {
  540. return interrupted;
  541. }
  542. void
  543. Noerror(void)
  544. {
  545. interrupted = 0;
  546. }
  547. int
  548. Isatty(int fd)
  549. {
  550. char buf[64];
  551. if(fd2path(fd, buf, sizeof buf) != 0)
  552. return 0;
  553. /* might be #c/cons during boot - fixed 22 april 2005, remove this later */
  554. if(strcmp(buf, "#c/cons") == 0)
  555. return 1;
  556. /* might be /mnt/term/dev/cons */
  557. return strlen(buf) >= 9 && strcmp(buf+strlen(buf)-9, "/dev/cons") == 0;
  558. }
  559. void
  560. Abort(void)
  561. {
  562. pfmt(err, "aborting\n");
  563. flush(err);
  564. Exit("aborting");
  565. }
  566. void
  567. Memcpy(void *a, void *b, long n)
  568. {
  569. memmove(a, b, n);
  570. }
  571. void*
  572. Malloc(ulong n)
  573. {
  574. return malloc(n);
  575. }
  576. int *waitpids;
  577. int nwaitpids;
  578. void
  579. addwaitpid(int pid)
  580. {
  581. waitpids = realloc(waitpids, (nwaitpids+1)*sizeof waitpids[0]);
  582. if(waitpids == 0)
  583. panic("Can't realloc %d waitpids", nwaitpids+1);
  584. waitpids[nwaitpids++] = pid;
  585. }
  586. void
  587. delwaitpid(int pid)
  588. {
  589. int r, w;
  590. for(r=w=0; r<nwaitpids; r++)
  591. if(waitpids[r] != pid)
  592. waitpids[w++] = waitpids[r];
  593. nwaitpids = w;
  594. }
  595. void
  596. clearwaitpids(void)
  597. {
  598. nwaitpids = 0;
  599. }
  600. int
  601. havewaitpid(int pid)
  602. {
  603. int i;
  604. for(i=0; i<nwaitpids; i++)
  605. if(waitpids[i] == pid)
  606. return 1;
  607. return 0;
  608. }
  609. /* avoid loading any floating-point library code */
  610. int
  611. _efgfmt(Fmt *)
  612. {
  613. return -1;
  614. }