exportsrv.c 11 KB

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