exportsrv.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <fcall.h>
  4. #define Extern extern
  5. #include "exportfs.h"
  6. char Ebadfid[] = "Bad fid";
  7. char Enotdir[] = "Not a directory";
  8. char Edupfid[] = "Fid already in use";
  9. char Eopen[] = "Fid already opened";
  10. char Exmnt[] = "Cannot .. past mount point";
  11. char Emip[] = "Mount in progress";
  12. char Enopsmt[] = "Out of pseudo mount points";
  13. char Enomem[] = "No memory";
  14. char Eversion[] = "Bad 9P2000 version";
  15. int iounit(int x)
  16. {
  17. return 8192+IOHDRSZ;
  18. }
  19. void*
  20. emallocz(ulong n)
  21. {
  22. void *v;
  23. v = mallocz(n, 1);
  24. if(v == nil)
  25. panic("out of memory");
  26. return v;
  27. }
  28. void
  29. Xversion(Fsrpc *t)
  30. {
  31. Fcall rhdr;
  32. if(t->work.msize > messagesize)
  33. t->work.msize = messagesize;
  34. messagesize = t->work.msize;
  35. if(strncmp(t->work.version, "9P2000", 6) != 0){
  36. reply(&t->work, &rhdr, Eversion);
  37. return;
  38. }
  39. rhdr.version = "9P2000";
  40. rhdr.msize = t->work.msize;
  41. reply(&t->work, &rhdr, 0);
  42. t->busy = 0;
  43. }
  44. void
  45. Xauth(Fsrpc *t)
  46. {
  47. Fcall rhdr;
  48. reply(&t->work, &rhdr, "exportfs: authentication not required");
  49. t->busy = 0;
  50. }
  51. void
  52. Xflush(Fsrpc *t)
  53. {
  54. Fsrpc *w, *e;
  55. Fcall rhdr;
  56. e = &Workq[Nr_workbufs];
  57. for(w = Workq; w < e; w++) {
  58. if(w->work.tag == t->work.oldtag) {
  59. DEBUG(DFD, "\tQ busy %d pid %d can %d\n", w->busy, w->pid, w->canint);
  60. if(w->busy && w->pid) {
  61. w->flushtag = t->work.tag;
  62. DEBUG(DFD, "\tset flushtag %d\n", t->work.tag);
  63. // if(w->canint)
  64. // postnote(PNPROC, w->pid, "flush");
  65. t->busy = 0;
  66. return;
  67. }
  68. }
  69. }
  70. reply(&t->work, &rhdr, 0);
  71. DEBUG(DFD, "\tflush reply\n");
  72. t->busy = 0;
  73. }
  74. void
  75. Xattach(Fsrpc *t)
  76. {
  77. Fcall rhdr;
  78. Fid *f;
  79. f = newfid(t->work.fid);
  80. if(f == 0) {
  81. reply(&t->work, &rhdr, Ebadfid);
  82. t->busy = 0;
  83. return;
  84. }
  85. if(srvfd >= 0){
  86. /*
  87. if(psmpt == 0){
  88. Nomount:
  89. reply(&t->work, &rhdr, Enopsmt);
  90. t->busy = 0;
  91. freefid(t->work.fid);
  92. return;
  93. }
  94. for(i=0; i<Npsmpt; i++)
  95. if(psmap[i] == 0)
  96. break;
  97. if(i >= Npsmpt)
  98. goto Nomount;
  99. sprint(buf, "%d", i);
  100. f->f = file(psmpt, buf);
  101. if(f->f == nil)
  102. goto Nomount;
  103. sprint(buf, "/mnt/exportfs/%d", i);
  104. nfd = dup(srvfd, -1);
  105. if(amount(nfd, buf, MREPL|MCREATE, t->work.aname) < 0){
  106. errstr(buf, sizeof buf);
  107. reply(&t->work, &rhdr, buf);
  108. t->busy = 0;
  109. freefid(t->work.fid);
  110. close(nfd);
  111. return;
  112. }
  113. psmap[i] = 1;
  114. f->mid = i;
  115. */
  116. }else{
  117. f->f = root;
  118. f->f->ref++;
  119. }
  120. rhdr.qid = f->f->qid;
  121. reply(&t->work, &rhdr, 0);
  122. t->busy = 0;
  123. }
  124. Fid*
  125. clonefid(Fid *f, int new)
  126. {
  127. Fid *n;
  128. n = newfid(new);
  129. if(n == 0) {
  130. n = getfid(new);
  131. if(n == 0)
  132. fatal("inconsistent fids");
  133. if(n->fid >= 0)
  134. close(n->fid);
  135. freefid(new);
  136. n = newfid(new);
  137. if(n == 0)
  138. fatal("inconsistent fids2");
  139. }
  140. n->f = f->f;
  141. n->f->ref++;
  142. return n;
  143. }
  144. void
  145. Xwalk(Fsrpc *t)
  146. {
  147. char err[ERRMAX], *e;
  148. Fcall rhdr;
  149. Fid *f, *nf;
  150. File *wf;
  151. int i;
  152. f = getfid(t->work.fid);
  153. if(f == 0) {
  154. reply(&t->work, &rhdr, Ebadfid);
  155. t->busy = 0;
  156. return;
  157. }
  158. nf = nil;
  159. if(t->work.newfid != t->work.fid){
  160. nf = clonefid(f, t->work.newfid);
  161. f = nf;
  162. }
  163. rhdr.nwqid = 0;
  164. e = nil;
  165. for(i=0; i<t->work.nwname; i++){
  166. if(i == MAXWELEM){
  167. e = "Too many path elements";
  168. break;
  169. }
  170. if(strcmp(t->work.wname[i], "..") == 0) {
  171. if(f->f->parent == nil) {
  172. e = Exmnt;
  173. break;
  174. }
  175. wf = f->f->parent;
  176. wf->ref++;
  177. goto Accept;
  178. }
  179. wf = file(f->f, t->work.wname[i]);
  180. if(wf == 0){
  181. errstr(err, sizeof err);
  182. e = err;
  183. break;
  184. }
  185. Accept:
  186. freefile(f->f);
  187. rhdr.wqid[rhdr.nwqid++] = wf->qid;
  188. f->f = wf;
  189. continue;
  190. }
  191. if(nf!=nil && (e!=nil || rhdr.nwqid!=t->work.nwname))
  192. freefid(t->work.newfid);
  193. if(rhdr.nwqid > 0)
  194. e = nil;
  195. reply(&t->work, &rhdr, e);
  196. t->busy = 0;
  197. }
  198. void
  199. Xclunk(Fsrpc *t)
  200. {
  201. Fcall rhdr;
  202. Fid *f;
  203. f = getfid(t->work.fid);
  204. if(f == 0) {
  205. reply(&t->work, &rhdr, Ebadfid);
  206. t->busy = 0;
  207. return;
  208. }
  209. if(f->fid >= 0)
  210. close(f->fid);
  211. freefid(t->work.fid);
  212. reply(&t->work, &rhdr, 0);
  213. t->busy = 0;
  214. }
  215. void
  216. Xstat(Fsrpc *t)
  217. {
  218. char err[ERRMAX], *path;
  219. Fcall rhdr;
  220. Fid *f;
  221. Dir *d;
  222. int s;
  223. uchar *statbuf;
  224. f = getfid(t->work.fid);
  225. if(f == 0) {
  226. reply(&t->work, &rhdr, Ebadfid);
  227. t->busy = 0;
  228. return;
  229. }
  230. if(f->fid >= 0)
  231. d = dirfstat(f->fid);
  232. else {
  233. path = makepath(f->f, "");
  234. d = dirstat(path);
  235. free(path);
  236. }
  237. if(d == nil) {
  238. errstr(err, sizeof err);
  239. reply(&t->work, &rhdr, err);
  240. t->busy = 0;
  241. return;
  242. }
  243. d->qid.path = f->f->qidt->uniqpath;
  244. s = sizeD2M(d);
  245. statbuf = emallocz(s);
  246. s = convD2M(d, statbuf, s);
  247. free(d);
  248. rhdr.nstat = s;
  249. rhdr.stat = statbuf;
  250. reply(&t->work, &rhdr, 0);
  251. free(statbuf);
  252. t->busy = 0;
  253. }
  254. static int
  255. getiounit(int fd)
  256. {
  257. int n;
  258. n = iounit(fd);
  259. if(n > messagesize-IOHDRSZ)
  260. n = messagesize-IOHDRSZ;
  261. return n;
  262. }
  263. void
  264. Xcreate(Fsrpc *t)
  265. {
  266. char err[ERRMAX], *path;
  267. Fcall rhdr;
  268. Fid *f;
  269. File *nf;
  270. f = getfid(t->work.fid);
  271. if(f == 0) {
  272. reply(&t->work, &rhdr, Ebadfid);
  273. t->busy = 0;
  274. return;
  275. }
  276. path = makepath(f->f, t->work.name);
  277. f->fid = create(path, t->work.mode, t->work.perm);
  278. free(path);
  279. if(f->fid < 0) {
  280. errstr(err, sizeof err);
  281. reply(&t->work, &rhdr, err);
  282. t->busy = 0;
  283. return;
  284. }
  285. nf = file(f->f, t->work.name);
  286. if(nf == 0) {
  287. errstr(err, sizeof err);
  288. reply(&t->work, &rhdr, err);
  289. t->busy = 0;
  290. return;
  291. }
  292. f->mode = t->work.mode;
  293. freefile(f->f);
  294. f->f = nf;
  295. rhdr.qid = f->f->qid;
  296. rhdr.iounit = getiounit(f->fid);
  297. reply(&t->work, &rhdr, 0);
  298. t->busy = 0;
  299. }
  300. void
  301. Xremove(Fsrpc *t)
  302. {
  303. char err[ERRMAX], *path;
  304. Fcall rhdr;
  305. Fid *f;
  306. f = getfid(t->work.fid);
  307. if(f == 0) {
  308. reply(&t->work, &rhdr, Ebadfid);
  309. t->busy = 0;
  310. return;
  311. }
  312. path = makepath(f->f, "");
  313. DEBUG(DFD, "\tremove: %s\n", path);
  314. if(remove(path) < 0) {
  315. free(path);
  316. errstr(err, sizeof err);
  317. reply(&t->work, &rhdr, err);
  318. t->busy = 0;
  319. return;
  320. }
  321. free(path);
  322. f->f->inval = 1;
  323. if(f->fid >= 0)
  324. close(f->fid);
  325. freefid(t->work.fid);
  326. reply(&t->work, &rhdr, 0);
  327. t->busy = 0;
  328. }
  329. void
  330. Xwstat(Fsrpc *t)
  331. {
  332. char err[ERRMAX], *path;
  333. Fcall rhdr;
  334. Fid *f;
  335. int s;
  336. char *strings;
  337. Dir d;
  338. f = getfid(t->work.fid);
  339. if(f == 0) {
  340. reply(&t->work, &rhdr, Ebadfid);
  341. t->busy = 0;
  342. return;
  343. }
  344. strings = emallocz(t->work.nstat); /* ample */
  345. if(convM2D(t->work.stat, t->work.nstat, &d, strings) <= BIT16SZ){
  346. rerrstr(err, sizeof err);
  347. reply(&t->work, &rhdr, err);
  348. t->busy = 0;
  349. free(strings);
  350. return;
  351. }
  352. if(f->fid >= 0)
  353. s = dirfwstat(f->fid, &d);
  354. else {
  355. path = makepath(f->f, "");
  356. s = dirwstat(path, &d);
  357. free(path);
  358. }
  359. if(s < 0) {
  360. rerrstr(err, sizeof err);
  361. reply(&t->work, &rhdr, err);
  362. }
  363. else {
  364. /* wstat may really be rename */
  365. if(strcmp(d.name, f->f->name)!=0 && strcmp(d.name, "")!=0){
  366. free(f->f->name);
  367. f->f->name = estrdup(d.name);
  368. }
  369. reply(&t->work, &rhdr, 0);
  370. }
  371. free(strings);
  372. t->busy = 0;
  373. }
  374. void
  375. slave(Fsrpc *f)
  376. {
  377. Proc *p;
  378. int pid;
  379. static int nproc;
  380. for(;;) {
  381. for(p = Proclist; p; p = p->next) {
  382. if(p->busy == 0) {
  383. f->pid = p->pid;
  384. p->busy = 1;
  385. pid = (uintptr)rendezvous((void*)(uintptr)p->pid, f);
  386. if(pid != p->pid)
  387. fatal("rendezvous sync fail");
  388. return;
  389. }
  390. }
  391. if(++nproc > MAXPROC)
  392. fatal("too many procs");
  393. pid = kproc("slave", blockingslave, nil);
  394. DEBUG(DFD, "slave pid %d\n", pid);
  395. if(pid == -1)
  396. fatal("kproc");
  397. p = malloc(sizeof(Proc));
  398. if(p == 0)
  399. fatal("out of memory");
  400. p->busy = 0;
  401. p->pid = pid;
  402. p->next = Proclist;
  403. Proclist = p;
  404. DEBUG(DFD, "parent %d rendez\n", pid);
  405. rendezvous((void*)(uintptr)pid, p);
  406. DEBUG(DFD, "parent %d went\n", pid);
  407. }
  408. }
  409. void
  410. blockingslave(void *x)
  411. {
  412. Fsrpc *p;
  413. Fcall rhdr;
  414. Proc *m;
  415. int pid;
  416. USED(x);
  417. notify(flushaction);
  418. pid = getpid();
  419. DEBUG(DFD, "blockingslave %d rendez\n", pid);
  420. m = (Proc*)rendezvous((void*)(uintptr)pid, 0);
  421. DEBUG(DFD, "blockingslave %d rendez got %p\n", pid, m);
  422. for(;;) {
  423. p = rendezvous((void*)(uintptr)pid, (void*)(uintptr)pid);
  424. if((uintptr)p == ~(uintptr)0) /* Interrupted */
  425. continue;
  426. DEBUG(DFD, "\tslave: %d %F b %d p %d\n", pid, &p->work, p->busy, p->pid);
  427. if(p->flushtag != NOTAG)
  428. goto flushme;
  429. switch(p->work.type) {
  430. case Tread:
  431. slaveread(p);
  432. break;
  433. case Twrite:
  434. slavewrite(p);
  435. break;
  436. case Topen:
  437. slaveopen(p);
  438. break;
  439. default:
  440. reply(&p->work, &rhdr, "exportfs: slave type error");
  441. }
  442. if(p->flushtag != NOTAG) {
  443. flushme:
  444. p->work.type = Tflush;
  445. p->work.tag = p->flushtag;
  446. reply(&p->work, &rhdr, 0);
  447. }
  448. p->busy = 0;
  449. m->busy = 0;
  450. }
  451. }
  452. int
  453. openmount(int sfd)
  454. {
  455. werrstr("openmount not implemented");
  456. return -1;
  457. }
  458. void
  459. slaveopen(Fsrpc *p)
  460. {
  461. char err[ERRMAX], *path;
  462. Fcall *work, rhdr;
  463. Fid *f;
  464. Dir *d;
  465. work = &p->work;
  466. f = getfid(work->fid);
  467. if(f == 0) {
  468. reply(work, &rhdr, Ebadfid);
  469. return;
  470. }
  471. if(f->fid >= 0) {
  472. close(f->fid);
  473. f->fid = -1;
  474. }
  475. path = makepath(f->f, "");
  476. DEBUG(DFD, "\topen: %s %d\n", path, work->mode);
  477. p->canint = 1;
  478. if(p->flushtag != NOTAG){
  479. free(path);
  480. return;
  481. }
  482. /* There is a race here I ignore because there are no locks */
  483. f->fid = open(path, work->mode);
  484. free(path);
  485. p->canint = 0;
  486. if(f->fid < 0 || (d = dirfstat(f->fid)) == nil) {
  487. Error:
  488. errstr(err, sizeof err);
  489. reply(work, &rhdr, err);
  490. return;
  491. }
  492. f->f->qid = d->qid;
  493. free(d);
  494. if(f->f->qid.type & QTMOUNT){ /* fork new exportfs for this */
  495. f->fid = openmount(f->fid);
  496. if(f->fid < 0)
  497. goto Error;
  498. }
  499. DEBUG(DFD, "\topen: fd %d\n", f->fid);
  500. f->mode = work->mode;
  501. rhdr.iounit = getiounit(f->fid);
  502. rhdr.qid = f->f->qid;
  503. reply(work, &rhdr, 0);
  504. }
  505. void
  506. slaveread(Fsrpc *p)
  507. {
  508. Fid *f;
  509. int n, r;
  510. Fcall *work, rhdr;
  511. char *data, err[ERRMAX];
  512. work = &p->work;
  513. f = getfid(work->fid);
  514. if(f == 0) {
  515. reply(work, &rhdr, Ebadfid);
  516. return;
  517. }
  518. n = (work->count > messagesize-IOHDRSZ) ? messagesize-IOHDRSZ : work->count;
  519. p->canint = 1;
  520. if(p->flushtag != NOTAG)
  521. return;
  522. data = malloc(n);
  523. if(data == nil)
  524. fatal(Enomem);
  525. /* can't just call pread, since directories must update the offset */
  526. r = pread(f->fid, data, n, work->offset);
  527. p->canint = 0;
  528. if(r < 0) {
  529. free(data);
  530. errstr(err, sizeof err);
  531. reply(work, &rhdr, err);
  532. return;
  533. }
  534. DEBUG(DFD, "\tread: fd=%d %d bytes\n", f->fid, r);
  535. rhdr.data = data;
  536. rhdr.count = r;
  537. reply(work, &rhdr, 0);
  538. free(data);
  539. }
  540. void
  541. slavewrite(Fsrpc *p)
  542. {
  543. char err[ERRMAX];
  544. Fcall *work, rhdr;
  545. Fid *f;
  546. int n;
  547. work = &p->work;
  548. f = getfid(work->fid);
  549. if(f == 0) {
  550. reply(work, &rhdr, Ebadfid);
  551. return;
  552. }
  553. n = (work->count > messagesize-IOHDRSZ) ? messagesize-IOHDRSZ : work->count;
  554. p->canint = 1;
  555. if(p->flushtag != NOTAG)
  556. return;
  557. n = pwrite(f->fid, work->data, n, work->offset);
  558. p->canint = 0;
  559. if(n < 0) {
  560. errstr(err, sizeof err);
  561. reply(work, &rhdr, err);
  562. return;
  563. }
  564. DEBUG(DFD, "\twrite: %d bytes fd=%d\n", n, f->fid);
  565. rhdr.count = n;
  566. reply(work, &rhdr, 0);
  567. }
  568. void
  569. reopen(Fid *f)
  570. {
  571. USED(f);
  572. fatal("reopen");
  573. }
  574. void
  575. flushaction(void *a, char *cause)
  576. {
  577. USED(a);
  578. if(strncmp(cause, "sys:", 4) == 0 && !strstr(cause, "pipe")) {
  579. fprint(2, "exportsrv: note: %s\n", cause);
  580. exits("noted");
  581. }
  582. if(strncmp(cause, "kill", 4) == 0)
  583. noted(NDFLT);
  584. noted(NCONT);
  585. }