vacfs.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789
  1. #include "stdinc.h"
  2. #include <fcall.h>
  3. #include "vac.h"
  4. #define convM2Su(a, b, c, d) convM2S(a, b, c)
  5. #define convS2Mu(a, b, c, d) convS2M(a, b, c)
  6. #define convM2Du(a, b, c, d) convM2D(a, b, c)
  7. #define convD2Mu(a, b, c, d) convD2M(a, b, c)
  8. typedef struct Fid Fid;
  9. enum
  10. {
  11. OPERM = 0x3 /* mask of all permission types in open mode */
  12. };
  13. struct Fid
  14. {
  15. short busy;
  16. short open;
  17. int fid;
  18. char *user;
  19. Qid qid;
  20. VacFile *file;
  21. VacDirEnum *vde;
  22. Fid *next;
  23. };
  24. enum
  25. {
  26. Pexec = 1,
  27. Pwrite = 2,
  28. Pread = 4,
  29. Pother = 1,
  30. Pgroup = 8,
  31. Powner = 64
  32. };
  33. Fid *fids;
  34. uchar *data;
  35. int mfd[2];
  36. int srvfd = -1;
  37. char *user;
  38. uchar mdata[8192+IOHDRSZ];
  39. int messagesize = sizeof mdata;
  40. Fcall rhdr;
  41. Fcall thdr;
  42. VacFs *fs;
  43. VtConn *conn;
  44. int noperm;
  45. int dotu;
  46. char *defmnt;
  47. Fid * newfid(int);
  48. void error(char*);
  49. void io(void);
  50. void vacshutdown(void);
  51. void usage(void);
  52. int perm(Fid*, int);
  53. int permf(VacFile*, char*, int);
  54. ulong getl(void *p);
  55. void init(char*, char*, long, int);
  56. int vacdirread(Fid *f, char *p, long off, long cnt);
  57. int vacstat(VacFile *parent, VacDir *vd, uchar *p, int np);
  58. void srv(void* a);
  59. char *rflush(Fid*), *rversion(Fid*),
  60. *rauth(Fid*), *rattach(Fid*), *rwalk(Fid*),
  61. *ropen(Fid*), *rcreate(Fid*),
  62. *rread(Fid*), *rwrite(Fid*), *rclunk(Fid*),
  63. *rremove(Fid*), *rstat(Fid*), *rwstat(Fid*);
  64. char *(*fcalls[Tmax])(Fid*);
  65. void
  66. initfcalls(void)
  67. {
  68. fcalls[Tflush]= rflush;
  69. fcalls[Tversion]= rversion;
  70. fcalls[Tattach]= rattach;
  71. fcalls[Tauth]= rauth;
  72. fcalls[Twalk]= rwalk;
  73. fcalls[Topen]= ropen;
  74. fcalls[Tcreate]= rcreate;
  75. fcalls[Tread]= rread;
  76. fcalls[Twrite]= rwrite;
  77. fcalls[Tclunk]= rclunk;
  78. fcalls[Tremove]= rremove;
  79. fcalls[Tstat]= rstat;
  80. fcalls[Twstat]= rwstat;
  81. }
  82. char Eperm[] = "permission denied";
  83. char Enotdir[] = "not a directory";
  84. char Enotexist[] = "file does not exist";
  85. char Einuse[] = "file in use";
  86. char Eexist[] = "file exists";
  87. char Enotowner[] = "not owner";
  88. char Eisopen[] = "file already open for I/O";
  89. char Excl[] = "exclusive use file already open";
  90. char Ename[] = "illegal name";
  91. char Erdonly[] = "read only file system";
  92. char Eio[] = "i/o error";
  93. char Eempty[] = "directory is not empty";
  94. char Emode[] = "illegal mode";
  95. int dflag;
  96. void
  97. notifyf(void *a, char *s)
  98. {
  99. USED(a);
  100. if(strncmp(s, "interrupt", 9) == 0)
  101. noted(NCONT);
  102. noted(NDFLT);
  103. }
  104. void
  105. threadmain(int argc, char *argv[])
  106. {
  107. char *defsrv, *srvname;
  108. int p[2], fd;
  109. int stdio;
  110. char *host = nil;
  111. long ncache;
  112. stdio = 0;
  113. ncache = 256;
  114. fmtinstall('H', encodefmt);
  115. fmtinstall('V', vtscorefmt);
  116. fmtinstall('F', vtfcallfmt);
  117. defmnt = nil;
  118. defsrv = nil;
  119. ARGBEGIN{
  120. case 'd':
  121. fmtinstall('F', fcallfmt);
  122. dflag = 1;
  123. break;
  124. case 'c':
  125. ncache = atoi(EARGF(usage()));
  126. break;
  127. case 'i':
  128. defmnt = nil;
  129. stdio = 1;
  130. mfd[0] = 0;
  131. mfd[1] = 1;
  132. break;
  133. case 'h':
  134. host = EARGF(usage());
  135. break;
  136. case 'S':
  137. defsrv = EARGF(usage());
  138. break;
  139. case 's':
  140. defsrv = "vacfs";
  141. break;
  142. case 'm':
  143. defmnt = EARGF(usage());
  144. break;
  145. case 'p':
  146. noperm = 1;
  147. break;
  148. case 'V':
  149. chattyventi = 1;
  150. break;
  151. default:
  152. usage();
  153. }ARGEND
  154. if(argc != 1)
  155. usage();
  156. if(defsrv == nil && defmnt == nil && !stdio)
  157. defmnt = "/n/vac";
  158. if(stdio && defmnt)
  159. sysfatal("cannot use -m with -i");
  160. initfcalls();
  161. notify(notifyf);
  162. user = getuser();
  163. conn = vtdial(host);
  164. if(conn == nil)
  165. sysfatal("could not connect to server: %r");
  166. if(vtconnect(conn) < 0)
  167. sysfatal("vtconnect: %r");
  168. fs = vacfsopen(conn, argv[0], VtOREAD, ncache);
  169. if(fs == nil)
  170. sysfatal("vacfsopen: %r");
  171. if(!stdio){
  172. if(pipe(p) < 0)
  173. sysfatal("pipe failed: %r");
  174. mfd[0] = p[0];
  175. mfd[1] = p[0];
  176. srvfd = p[1];
  177. }
  178. procrfork(srv, 0, 32 * 1024, RFFDG|RFNAMEG|RFNOTEG);
  179. if(!stdio){
  180. close(p[0]);
  181. if(defsrv){
  182. srvname = smprint("/srv/%s", defsrv);
  183. /* child doesn't share fd group, so can't use ORCLOSE */
  184. fd = create(srvname, OWRITE, 0666);
  185. if(fd < 0)
  186. sysfatal("create %s: %r", srvname);
  187. if(fprint(fd, "%d", srvfd) < 0)
  188. sysfatal("write %s: %r", srvname);
  189. free(srvname);
  190. }
  191. if(defmnt){
  192. if(mount(srvfd, -1, defmnt, MREPL|MCREATE, "") < 0)
  193. sysfatal("mount %s: %r", defmnt);
  194. }
  195. }
  196. threadexits(0);
  197. }
  198. void
  199. srv(void *a)
  200. {
  201. USED(a);
  202. io();
  203. vacshutdown();
  204. }
  205. void
  206. usage(void)
  207. {
  208. fprint(2, "usage: %s [-sd] [-c ncache] [-h host] [-m mountpoint] [-S svc] vacfile\n",
  209. argv0);
  210. threadexitsall("usage");
  211. }
  212. char*
  213. rversion(Fid *unused)
  214. {
  215. Fid *f;
  216. USED(unused);
  217. for(f = fids; f; f = f->next)
  218. if(f->busy)
  219. rclunk(f);
  220. if(rhdr.msize < 256)
  221. return vtstrdup("version: message size too small");
  222. messagesize = rhdr.msize;
  223. if(messagesize > sizeof mdata)
  224. messagesize = sizeof mdata;
  225. thdr.msize = messagesize;
  226. if(strncmp(rhdr.version, "9P2000", 6) != 0)
  227. return vtstrdup("unrecognized 9P version");
  228. thdr.version = "9P2000";
  229. if(strncmp(rhdr.version, "9P2000.u", 8) == 0){
  230. dotu = 1;
  231. thdr.version = "9P2000.u";
  232. }
  233. return nil;
  234. }
  235. char*
  236. rflush(Fid *f)
  237. {
  238. USED(f);
  239. return 0;
  240. }
  241. char*
  242. rauth(Fid *f)
  243. {
  244. USED(f);
  245. return vtstrdup("vacfs: authentication not required");
  246. }
  247. char*
  248. rattach(Fid *f)
  249. {
  250. /* no authentication for the momment */
  251. VacFile *file;
  252. char err[80];
  253. file = vacfsgetroot(fs);
  254. if(file == nil) {
  255. rerrstr(err, sizeof err);
  256. return vtstrdup(err);
  257. }
  258. f->busy = 1;
  259. f->file = file;
  260. f->qid.path = vacfilegetid(f->file);
  261. f->qid.vers = 0;
  262. f->qid.type = QTDIR;
  263. thdr.qid = f->qid;
  264. if(rhdr.uname[0])
  265. f->user = vtstrdup(rhdr.uname);
  266. else
  267. f->user = "none";
  268. return 0;
  269. }
  270. char*
  271. rwalk(Fid *f)
  272. {
  273. VacFile *file, *nfile;
  274. Fid *nf;
  275. int nqid, nwname;
  276. Qid qid;
  277. char *err = nil;
  278. if(f->busy == 0)
  279. return Enotexist;
  280. nf = nil;
  281. if(rhdr.fid != rhdr.newfid){
  282. if(f->open)
  283. return vtstrdup(Eisopen);
  284. if(f->busy == 0)
  285. return vtstrdup(Enotexist);
  286. nf = newfid(rhdr.newfid);
  287. if(nf->busy)
  288. return vtstrdup(Eisopen);
  289. nf->busy = 1;
  290. nf->open = 0;
  291. nf->qid = f->qid;
  292. nf->file = vacfileincref(f->file);
  293. nf->user = vtstrdup(f->user);
  294. f = nf;
  295. }
  296. nwname = rhdr.nwname;
  297. /* easy case */
  298. if(nwname == 0) {
  299. thdr.nwqid = 0;
  300. return 0;
  301. }
  302. file = f->file;
  303. vacfileincref(file);
  304. qid = f->qid;
  305. for(nqid = 0; nqid < nwname; nqid++){
  306. if((qid.type & QTDIR) == 0){
  307. err = Enotdir;
  308. break;
  309. }
  310. if(!permf(file, f->user, Pexec)) {
  311. err = Eperm;
  312. break;
  313. }
  314. nfile = vacfilewalk(file, rhdr.wname[nqid]);
  315. if(nfile == nil)
  316. break;
  317. vacfiledecref(file);
  318. file = nfile;
  319. qid.type = QTFILE;
  320. if(vacfileisdir(file))
  321. qid.type = QTDIR;
  322. qid.vers = vacfilegetmcount(file);
  323. qid.path = vacfilegetid(file);
  324. thdr.wqid[nqid] = qid;
  325. }
  326. thdr.nwqid = nqid;
  327. if(nqid == nwname){
  328. /* success */
  329. f->qid = thdr.wqid[nqid-1];
  330. vacfiledecref(f->file);
  331. f->file = file;
  332. return 0;
  333. }
  334. vacfiledecref(file);
  335. if(nf != nil)
  336. rclunk(nf);
  337. /* only error on the first element */
  338. if(nqid == 0)
  339. return vtstrdup(err);
  340. return 0;
  341. }
  342. char *
  343. ropen(Fid *f)
  344. {
  345. int mode, trunc;
  346. if(f->open)
  347. return vtstrdup(Eisopen);
  348. if(!f->busy)
  349. return vtstrdup(Enotexist);
  350. mode = rhdr.mode;
  351. thdr.iounit = messagesize - IOHDRSZ;
  352. if(f->qid.type & QTDIR){
  353. if(mode != OREAD)
  354. return vtstrdup(Eperm);
  355. if(!perm(f, Pread))
  356. return vtstrdup(Eperm);
  357. thdr.qid = f->qid;
  358. f->vde = nil;
  359. f->open = 1;
  360. return 0;
  361. }
  362. if(mode & ORCLOSE)
  363. return vtstrdup(Erdonly);
  364. trunc = mode & OTRUNC;
  365. mode &= OPERM;
  366. if(mode==OWRITE || mode==ORDWR || trunc)
  367. if(!perm(f, Pwrite))
  368. return vtstrdup(Eperm);
  369. if(mode==OREAD || mode==ORDWR)
  370. if(!perm(f, Pread))
  371. return vtstrdup(Eperm);
  372. if(mode==OEXEC)
  373. if(!perm(f, Pexec))
  374. return vtstrdup(Eperm);
  375. thdr.qid = f->qid;
  376. thdr.iounit = messagesize - IOHDRSZ;
  377. f->open = 1;
  378. return 0;
  379. }
  380. char*
  381. rcreate(Fid* fid)
  382. {
  383. VacFile *vf;
  384. ulong mode;
  385. if(fid->open)
  386. return vtstrdup(Eisopen);
  387. if(!fid->busy)
  388. return vtstrdup(Enotexist);
  389. if(fs->mode & ModeSnapshot)
  390. return vtstrdup(Erdonly);
  391. vf = fid->file;
  392. if(!vacfileisdir(vf))
  393. return vtstrdup(Enotdir);
  394. if(!permf(vf, fid->user, Pwrite))
  395. return vtstrdup(Eperm);
  396. mode = rhdr.perm & 0777;
  397. if(rhdr.perm & DMDIR){
  398. if((rhdr.mode & OTRUNC) || (rhdr.perm & DMAPPEND))
  399. return vtstrdup(Emode);
  400. switch(rhdr.mode & OPERM){
  401. default:
  402. return vtstrdup(Emode);
  403. case OEXEC:
  404. case OREAD:
  405. break;
  406. case OWRITE:
  407. case ORDWR:
  408. return vtstrdup(Eperm);
  409. }
  410. mode |= ModeDir;
  411. }
  412. vf = vacfilecreate(vf, rhdr.name, mode);
  413. if(vf == nil) {
  414. char err[80];
  415. rerrstr(err, sizeof err);
  416. return vtstrdup(err);
  417. }
  418. vacfiledecref(fid->file);
  419. fid->file = vf;
  420. fid->qid.type = QTFILE;
  421. if(vacfileisdir(vf))
  422. fid->qid.type = QTDIR;
  423. fid->qid.vers = vacfilegetmcount(vf);
  424. fid->qid.path = vacfilegetid(vf);
  425. thdr.qid = fid->qid;
  426. thdr.iounit = messagesize - IOHDRSZ;
  427. return 0;
  428. }
  429. char*
  430. rread(Fid *f)
  431. {
  432. char *buf;
  433. vlong off;
  434. int cnt;
  435. VacFile *vf;
  436. char err[80];
  437. int n;
  438. if(!f->busy)
  439. return vtstrdup(Enotexist);
  440. vf = f->file;
  441. thdr.count = 0;
  442. off = rhdr.offset;
  443. buf = thdr.data;
  444. cnt = rhdr.count;
  445. if(f->qid.type & QTDIR)
  446. n = vacdirread(f, buf, off, cnt);
  447. else if(vacfilegetmode(f->file)&ModeDevice)
  448. return vtstrdup("device");
  449. else if(vacfilegetmode(f->file)&ModeLink)
  450. return vtstrdup("symbolic link");
  451. else if(vacfilegetmode(f->file)&ModeNamedPipe)
  452. return vtstrdup("named pipe");
  453. else
  454. n = vacfileread(vf, buf, cnt, off);
  455. if(n < 0) {
  456. rerrstr(err, sizeof err);
  457. return vtstrdup(err);
  458. }
  459. thdr.count = n;
  460. return 0;
  461. }
  462. char*
  463. rwrite(Fid *f)
  464. {
  465. USED(f);
  466. return vtstrdup(Erdonly);
  467. }
  468. char *
  469. rclunk(Fid *f)
  470. {
  471. f->busy = 0;
  472. f->open = 0;
  473. vtfree(f->user);
  474. f->user = nil;
  475. if(f->file)
  476. vacfiledecref(f->file);
  477. f->file = nil;
  478. vdeclose(f->vde);
  479. f->vde = nil;
  480. return 0;
  481. }
  482. char *
  483. rremove(Fid *f)
  484. {
  485. VacFile *vf, *vfp;
  486. char errbuf[80];
  487. char *err = nil;
  488. if(!f->busy)
  489. return vtstrdup(Enotexist);
  490. vf = f->file;
  491. vfp = vacfilegetparent(vf);
  492. if(!permf(vfp, f->user, Pwrite)) {
  493. err = Eperm;
  494. goto Exit;
  495. }
  496. if(!vacfileremove(vf)) {
  497. rerrstr(errbuf, sizeof errbuf);
  498. err = errbuf;
  499. }
  500. Exit:
  501. vacfiledecref(vfp);
  502. rclunk(f);
  503. return vtstrdup(err);
  504. }
  505. char *
  506. rstat(Fid *f)
  507. {
  508. VacDir dir;
  509. static uchar statbuf[1024];
  510. VacFile *parent;
  511. if(!f->busy)
  512. return vtstrdup(Enotexist);
  513. parent = vacfilegetparent(f->file);
  514. vacfilegetdir(f->file, &dir);
  515. thdr.stat = statbuf;
  516. thdr.nstat = vacstat(parent, &dir, thdr.stat, sizeof statbuf);
  517. vdcleanup(&dir);
  518. vacfiledecref(parent);
  519. return 0;
  520. }
  521. char *
  522. rwstat(Fid *f)
  523. {
  524. if(!f->busy)
  525. return vtstrdup(Enotexist);
  526. return vtstrdup(Erdonly);
  527. }
  528. int
  529. vacstat(VacFile *parent, VacDir *vd, uchar *p, int np)
  530. {
  531. int ret;
  532. Dir dir;
  533. memset(&dir, 0, sizeof(dir));
  534. dir.qid.path = vd->qid + vacfilegetqidoffset(parent);
  535. if(vd->qidspace)
  536. dir.qid.path += vd->qidoffset;
  537. dir.qid.vers = vd->mcount;
  538. dir.mode = vd->mode & 0777;
  539. if(vd->mode & ModeAppend){
  540. dir.qid.type |= QTAPPEND;
  541. dir.mode |= DMAPPEND;
  542. }
  543. if(vd->mode & ModeExclusive){
  544. dir.qid.type |= QTEXCL;
  545. dir.mode |= DMEXCL;
  546. }
  547. if(vd->mode & ModeDir){
  548. dir.qid.type |= QTDIR;
  549. dir.mode |= DMDIR;
  550. }
  551. dir.atime = vd->atime;
  552. dir.mtime = vd->mtime;
  553. dir.length = vd->size;
  554. dir.name = vd->elem;
  555. dir.uid = vd->uid;
  556. dir.gid = vd->gid;
  557. dir.muid = vd->mid;
  558. ret = convD2Mu(&dir, p, np, dotu);
  559. return ret;
  560. }
  561. int
  562. vacdirread(Fid *f, char *p, long off, long cnt)
  563. {
  564. int i, n, nb;
  565. VacDir vd;
  566. /*
  567. * special case of rewinding a directory
  568. * otherwise ignore the offset
  569. */
  570. if(off == 0 && f->vde){
  571. vdeclose(f->vde);
  572. f->vde = nil;
  573. }
  574. if(f->vde == nil){
  575. f->vde = vdeopen(f->file);
  576. if(f->vde == nil)
  577. return -1;
  578. }
  579. for(nb = 0; nb < cnt; nb += n) {
  580. i = vderead(f->vde, &vd);
  581. if(i < 0)
  582. return -1;
  583. if(i == 0)
  584. break;
  585. n = vacstat(f->file, &vd, (uchar*)p, cnt-nb);
  586. if(n <= BIT16SZ) {
  587. vdeunread(f->vde);
  588. break;
  589. }
  590. vdcleanup(&vd);
  591. p += n;
  592. }
  593. return nb;
  594. }
  595. Fid *
  596. newfid(int fid)
  597. {
  598. Fid *f, *ff;
  599. ff = 0;
  600. for(f = fids; f; f = f->next)
  601. if(f->fid == fid)
  602. return f;
  603. else if(!ff && !f->busy)
  604. ff = f;
  605. if(ff){
  606. ff->fid = fid;
  607. return ff;
  608. }
  609. f = vtmallocz(sizeof *f);
  610. f->fid = fid;
  611. f->next = fids;
  612. fids = f;
  613. return f;
  614. }
  615. void
  616. io(void)
  617. {
  618. char *err;
  619. int n;
  620. for(;;){
  621. n = read9pmsg(mfd[0], mdata, sizeof mdata);
  622. if(n <= 0)
  623. break;
  624. if(convM2Su(mdata, n, &rhdr, dotu) != n)
  625. sysfatal("convM2S conversion error");
  626. if(dflag)
  627. fprint(2, "vacfs:<-%F\n", &rhdr);
  628. thdr.data = (char*)mdata + IOHDRSZ;
  629. if(!fcalls[rhdr.type])
  630. err = "bad fcall type";
  631. else
  632. err = (*fcalls[rhdr.type])(newfid(rhdr.fid));
  633. if(err){
  634. thdr.type = Rerror;
  635. thdr.ename = err;
  636. }else{
  637. thdr.type = rhdr.type + 1;
  638. thdr.fid = rhdr.fid;
  639. }
  640. thdr.tag = rhdr.tag;
  641. if(dflag)
  642. fprint(2, "vacfs:->%F\n", &thdr);
  643. n = convS2Mu(&thdr, mdata, messagesize, dotu);
  644. if(n <= BIT16SZ)
  645. sysfatal("convS2Mu conversion error");
  646. if(err)
  647. vtfree(err);
  648. if(write(mfd[1], mdata, n) != n)
  649. sysfatal("mount write: %r");
  650. }
  651. }
  652. int
  653. permf(VacFile *vf, char *user, int p)
  654. {
  655. VacDir dir;
  656. ulong perm;
  657. if(vacfilegetdir(vf, &dir))
  658. return 0;
  659. perm = dir.mode & 0777;
  660. if(noperm)
  661. goto Good;
  662. if((p*Pother) & perm)
  663. goto Good;
  664. if(strcmp(user, dir.gid)==0 && ((p*Pgroup) & perm))
  665. goto Good;
  666. if(strcmp(user, dir.uid)==0 && ((p*Powner) & perm))
  667. goto Good;
  668. vdcleanup(&dir);
  669. return 0;
  670. Good:
  671. vdcleanup(&dir);
  672. return 1;
  673. }
  674. int
  675. perm(Fid *f, int p)
  676. {
  677. return permf(f->file, f->user, p);
  678. }
  679. void
  680. vacshutdown(void)
  681. {
  682. Fid *f;
  683. for(f = fids; f; f = f->next) {
  684. if(!f->busy)
  685. continue;
  686. rclunk(f);
  687. }
  688. vacfsclose(fs);
  689. vthangup(conn);
  690. }