exportsrv.c 12 KB

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