fsys.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <bio.h>
  4. #include <regexp.h>
  5. #include <thread.h>
  6. #include <auth.h>
  7. #include <fcall.h>
  8. #include <plumb.h>
  9. #include "plumber.h"
  10. enum
  11. {
  12. Stack = 8*1024
  13. };
  14. typedef struct Dirtab Dirtab;
  15. typedef struct Fid Fid;
  16. typedef struct Holdq Holdq;
  17. typedef struct Readreq Readreq;
  18. typedef struct Sendreq Sendreq;
  19. struct Dirtab
  20. {
  21. char *name;
  22. uchar type;
  23. uint qid;
  24. uint perm;
  25. int nopen; /* #fids open on this port */
  26. Fid *fopen;
  27. Holdq *holdq;
  28. Readreq *readq;
  29. Sendreq *sendq;
  30. };
  31. struct Fid
  32. {
  33. int fid;
  34. int busy;
  35. int open;
  36. int mode;
  37. Qid qid;
  38. Dirtab *dir;
  39. long offset; /* zeroed at beginning of each message, read or write */
  40. char *writebuf; /* partial message written so far; offset tells how much */
  41. Fid *next;
  42. Fid *nextopen;
  43. };
  44. struct Readreq
  45. {
  46. Fid *fid;
  47. Fcall *fcall;
  48. uchar *buf;
  49. Readreq *next;
  50. };
  51. struct Sendreq
  52. {
  53. int nfid; /* number of fids that should receive this message */
  54. int nleft; /* number left that haven't received it */
  55. Fid **fid; /* fid[nfid] */
  56. Plumbmsg *msg;
  57. char *pack; /* plumbpack()ed message */
  58. int npack; /* length of pack */
  59. Sendreq *next;
  60. };
  61. struct Holdq
  62. {
  63. Plumbmsg *msg;
  64. Holdq *next;
  65. };
  66. struct /* needed because incref() doesn't return value */
  67. {
  68. Lock;
  69. int ref;
  70. } rulesref;
  71. enum
  72. {
  73. DEBUG = 0,
  74. NDIR = 50,
  75. Nhash = 16,
  76. Qdir = 0,
  77. Qrules = 1,
  78. Qsend = 2,
  79. Qport = 3,
  80. NQID = Qport
  81. };
  82. static Dirtab dir[NDIR] =
  83. {
  84. { ".", QTDIR, Qdir, 0500|DMDIR },
  85. { "rules", QTFILE, Qrules, 0600 },
  86. { "send", QTFILE, Qsend, 0200 },
  87. };
  88. static int ndir = NQID;
  89. static int srvfd;
  90. static int srvclosefd; /* rock for end of pipe to close */
  91. static int clockfd;
  92. static int clock;
  93. static Fid *fids[Nhash];
  94. static QLock readlock;
  95. static QLock queue;
  96. static char srvfile[128];
  97. static int messagesize = 8192+IOHDRSZ; /* good start */
  98. static void fsysproc(void*);
  99. static void fsysrespond(Fcall*, uchar*, char*);
  100. static Fid* newfid(int);
  101. static Fcall* fsysflush(Fcall*, uchar*, Fid*);
  102. static Fcall* fsysversion(Fcall*, uchar*, Fid*);
  103. static Fcall* fsysauth(Fcall*, uchar*, Fid*);
  104. static Fcall* fsysattach(Fcall*, uchar*, Fid*);
  105. static Fcall* fsyswalk(Fcall*, uchar*, Fid*);
  106. static Fcall* fsysopen(Fcall*, uchar*, Fid*);
  107. static Fcall* fsyscreate(Fcall*, uchar*, Fid*);
  108. static Fcall* fsysread(Fcall*, uchar*, Fid*);
  109. static Fcall* fsyswrite(Fcall*, uchar*, Fid*);
  110. static Fcall* fsysclunk(Fcall*, uchar*, Fid*);
  111. static Fcall* fsysremove(Fcall*, uchar*, Fid*);
  112. static Fcall* fsysstat(Fcall*, uchar*, Fid*);
  113. static Fcall* fsyswstat(Fcall*, uchar*, Fid*);
  114. Fcall* (*fcall[Tmax])(Fcall*, uchar*, Fid*) =
  115. {
  116. [Tflush] = fsysflush,
  117. [Tversion] = fsysversion,
  118. [Tauth] = fsysauth,
  119. [Tattach] = fsysattach,
  120. [Twalk] = fsyswalk,
  121. [Topen] = fsysopen,
  122. [Tcreate] = fsyscreate,
  123. [Tread] = fsysread,
  124. [Twrite] = fsyswrite,
  125. [Tclunk] = fsysclunk,
  126. [Tremove]= fsysremove,
  127. [Tstat] = fsysstat,
  128. [Twstat] = fsyswstat,
  129. };
  130. char Ebadfcall[] = "bad fcall type";
  131. char Eperm[] = "permission denied";
  132. char Enomem[] = "malloc failed for buffer";
  133. char Enotdir[] = "not a directory";
  134. char Enoexist[] = "plumb file does not exist";
  135. char Eisdir[] = "file is a directory";
  136. char Ebadmsg[] = "bad plumb message format";
  137. char Enosuchport[] ="no such plumb port";
  138. char Enoport[] = "couldn't find destination for message";
  139. char Einuse[] = "file already open";
  140. /*
  141. * Add new port. A no-op if port already exists or is the null string
  142. */
  143. void
  144. addport(char *port)
  145. {
  146. int i;
  147. if(port == nil)
  148. return;
  149. for(i=NQID; i<ndir; i++)
  150. if(strcmp(port, dir[i].name) == 0)
  151. return;
  152. if(i == NDIR){
  153. fprint(2, "plumb: too many ports; max %d\n", NDIR);
  154. return;
  155. }
  156. ndir++;
  157. dir[i].name = estrdup(port);
  158. dir[i].qid = i;
  159. dir[i].perm = 0400;
  160. nports++;
  161. ports = erealloc(ports, nports*sizeof(char*));
  162. ports[nports-1] = dir[i].name;
  163. }
  164. static ulong
  165. getclock(void)
  166. {
  167. char buf[32];
  168. seek(clockfd, 0, 0);
  169. read(clockfd, buf, sizeof buf);
  170. return atoi(buf);
  171. }
  172. void
  173. startfsys(void)
  174. {
  175. int p[2], fd;
  176. fmtinstall('F', fcallfmt);
  177. clockfd = open("/dev/time", OREAD|OCEXEC);
  178. clock = getclock();
  179. if(pipe(p) < 0)
  180. error("can't create pipe: %r");
  181. /* 0 will be server end, 1 will be client end */
  182. srvfd = p[0];
  183. srvclosefd = p[1];
  184. sprint(srvfile, "/srv/plumb.%s.%d", user, getpid());
  185. if(putenv("plumbsrv", srvfile) < 0)
  186. error("can't write $plumbsrv: %r");
  187. fd = create(srvfile, OWRITE|OCEXEC|ORCLOSE, 0600);
  188. if(fd < 0)
  189. error("can't create /srv file: %r");
  190. if(fprint(fd, "%d", p[1]) <= 0)
  191. error("can't write /srv/file: %r");
  192. /* leave fd open; ORCLOSE will take care of it */
  193. procrfork(fsysproc, nil, Stack, RFFDG);
  194. close(p[0]);
  195. if(mount(p[1], -1, "/mnt/plumb", MREPL, "") < 0)
  196. error("can't mount /mnt/plumb: %r");
  197. close(p[1]);
  198. }
  199. static void
  200. fsysproc(void*)
  201. {
  202. int n;
  203. Fcall *t;
  204. Fid *f;
  205. uchar *buf;
  206. close(srvclosefd);
  207. srvclosefd = -1;
  208. t = nil;
  209. for(;;){
  210. buf = malloc(messagesize); /* avoid memset of emalloc */
  211. if(buf == nil)
  212. error("malloc failed: %r");
  213. qlock(&readlock);
  214. n = read9pmsg(srvfd, buf, messagesize);
  215. if(n <= 0){
  216. if(n < 0)
  217. error("i/o error on server channel");
  218. threadexitsall("unmounted");
  219. }
  220. if(readlock.head == nil) /* no other processes waiting to read; start one */
  221. proccreate(fsysproc, nil, Stack);
  222. qunlock(&readlock);
  223. if(t == nil)
  224. t = emalloc(sizeof(Fcall));
  225. if(convM2S(buf, n, t) != n)
  226. error("convert error in convM2S");
  227. if(DEBUG)
  228. fprint(2, "<= %F\n", t);
  229. if(fcall[t->type] == nil)
  230. fsysrespond(t, buf, Ebadfcall);
  231. else{
  232. if(t->type==Tversion || t->type==Tauth)
  233. f = nil;
  234. else
  235. f = newfid(t->fid);
  236. t = (*fcall[t->type])(t, buf, f);
  237. }
  238. }
  239. }
  240. static void
  241. fsysrespond(Fcall *t, uchar *buf, char *err)
  242. {
  243. int n;
  244. if(err){
  245. t->type = Rerror;
  246. t->ename = err;
  247. }else
  248. t->type++;
  249. if(buf == nil)
  250. buf = emalloc(messagesize);
  251. n = convS2M(t, buf, messagesize);
  252. if(n < 0)
  253. error("convert error in convS2M");
  254. if(write(srvfd, buf, n) != n)
  255. error("write error in respond");
  256. if(DEBUG)
  257. fprint(2, "=> %F\n", t);
  258. free(buf);
  259. }
  260. static
  261. Fid*
  262. newfid(int fid)
  263. {
  264. Fid *f, *ff, **fh;
  265. qlock(&queue);
  266. ff = nil;
  267. fh = &fids[fid&(Nhash-1)];
  268. for(f=*fh; f; f=f->next)
  269. if(f->fid == fid)
  270. goto Return;
  271. else if(ff==nil && !f->busy)
  272. ff = f;
  273. if(ff){
  274. ff->fid = fid;
  275. f = ff;
  276. goto Return;
  277. }
  278. f = emalloc(sizeof *f);
  279. f->fid = fid;
  280. f->next = *fh;
  281. *fh = f;
  282. Return:
  283. qunlock(&queue);
  284. return f;
  285. }
  286. static uint
  287. dostat(Dirtab *dir, uchar *buf, uint nbuf, uint clock)
  288. {
  289. Dir d;
  290. d.qid.type = dir->type;
  291. d.qid.path = dir->qid;
  292. d.qid.vers = 0;
  293. d.mode = dir->perm;
  294. d.length = 0; /* would be nice to do better */
  295. d.name = dir->name;
  296. d.uid = user;
  297. d.gid = user;
  298. d.muid = user;
  299. d.atime = clock;
  300. d.mtime = clock;
  301. return convD2M(&d, buf, nbuf);
  302. }
  303. static void
  304. queuesend(Dirtab *d, Plumbmsg *m)
  305. {
  306. Sendreq *s, *t;
  307. Fid *f;
  308. int i;
  309. s = emalloc(sizeof(Sendreq));
  310. s->nfid = d->nopen;
  311. s->nleft = s->nfid;
  312. s->fid = emalloc(s->nfid*sizeof(Fid*));
  313. i = 0;
  314. /* build array of fids open on this channel */
  315. for(f=d->fopen; f!=nil; f=f->nextopen)
  316. s->fid[i++] = f;
  317. s->msg = m;
  318. s->next = nil;
  319. /* link to end of queue; drainqueue() searches in sender order so this implements a FIFO */
  320. for(t=d->sendq; t!=nil; t=t->next)
  321. if(t->next == nil)
  322. break;
  323. if(t == nil)
  324. d->sendq = s;
  325. else
  326. t->next = s;
  327. }
  328. static void
  329. queueread(Dirtab *d, Fcall *t, uchar *buf, Fid *f)
  330. {
  331. Readreq *r;
  332. r = emalloc(sizeof(Readreq));
  333. r->fcall = t;
  334. r->buf = buf;
  335. r->fid = f;
  336. r->next = d->readq;
  337. d->readq = r;
  338. }
  339. static void
  340. drainqueue(Dirtab *d)
  341. {
  342. Readreq *r, *nextr, *prevr;
  343. Sendreq *s, *nexts, *prevs;
  344. int i, n;
  345. prevs = nil;
  346. for(s=d->sendq; s!=nil; s=nexts){
  347. nexts = s->next;
  348. for(i=0; i<s->nfid; i++){
  349. prevr = nil;
  350. for(r=d->readq; r!=nil; r=nextr){
  351. nextr = r->next;
  352. if(r->fid == s->fid[i]){
  353. /* pack the message if necessary */
  354. if(s->pack == nil)
  355. s->pack = plumbpack(s->msg, &s->npack);
  356. /* exchange the stuff... */
  357. r->fcall->data = s->pack+r->fid->offset;
  358. n = s->npack - r->fid->offset;
  359. if(n > messagesize-IOHDRSZ)
  360. n = messagesize-IOHDRSZ;
  361. if(n > r->fcall->count)
  362. n = r->fcall->count;
  363. r->fcall->count = n;
  364. fsysrespond(r->fcall, r->buf, nil);
  365. r->fid->offset += n;
  366. if(r->fid->offset >= s->npack){
  367. /* message transferred; delete this fid from send queue */
  368. r->fid->offset = 0;
  369. s->fid[i] = nil;
  370. s->nleft--;
  371. }
  372. /* delete read request from queue */
  373. if(prevr)
  374. prevr->next = r->next;
  375. else
  376. d->readq = r->next;
  377. free(r->fcall);
  378. free(r);
  379. break;
  380. }else
  381. prevr = r;
  382. }
  383. }
  384. /* if no fids left, delete this send from queue */
  385. if(s->nleft == 0){
  386. free(s->fid);
  387. plumbfree(s->msg);
  388. free(s->pack);
  389. if(prevs)
  390. prevs->next = s->next;
  391. else
  392. d->sendq = s->next;
  393. free(s);
  394. }else
  395. prevs = s;
  396. }
  397. }
  398. /* can't flush a send because they are always answered synchronously */
  399. static void
  400. flushqueue(Dirtab *d, int oldtag)
  401. {
  402. Readreq *r, *prevr;
  403. prevr = nil;
  404. for(r=d->readq; r!=nil; r=r->next){
  405. if(oldtag == r->fcall->tag){
  406. /* delete read request from queue */
  407. if(prevr)
  408. prevr->next = r->next;
  409. else
  410. d->readq = r->next;
  411. free(r->fcall);
  412. free(r->buf);
  413. free(r);
  414. return;
  415. }
  416. prevr = r;
  417. }
  418. }
  419. /* remove messages awaiting delivery to now-closing fid */
  420. static void
  421. removesenders(Dirtab *d, Fid *fid)
  422. {
  423. Sendreq *s, *nexts, *prevs;
  424. int i;
  425. prevs = nil;
  426. for(s=d->sendq; s!=nil; s=nexts){
  427. nexts = s->next;
  428. for(i=0; i<s->nfid; i++)
  429. if(fid == s->fid[i]){
  430. /* delete this fid from send queue */
  431. s->fid[i] = nil;
  432. s->nleft--;
  433. break;
  434. }
  435. /* if no fids left, delete this send from queue */
  436. if(s->nleft == 0){
  437. free(s->fid);
  438. plumbfree(s->msg);
  439. free(s->pack);
  440. if(prevs)
  441. prevs->next = s->next;
  442. else
  443. d->sendq = s->next;
  444. free(s);
  445. }else
  446. prevs = s;
  447. }
  448. }
  449. static void
  450. hold(Plumbmsg *m, Dirtab *d)
  451. {
  452. Holdq *h, *q;
  453. h = emalloc(sizeof(Holdq));
  454. h->msg = m;
  455. /* add to end of queue */
  456. if(d->holdq == nil)
  457. d->holdq = h;
  458. else{
  459. for(q=d->holdq; q->next!=nil; q=q->next)
  460. ;
  461. q->next = h;
  462. }
  463. }
  464. static void
  465. queueheld(Dirtab *d)
  466. {
  467. Holdq *h;
  468. while(d->holdq != nil){
  469. h = d->holdq;
  470. d->holdq = h->next;
  471. queuesend(d, h->msg);
  472. /* no need to drain queue because we know no-one is reading yet */
  473. free(h);
  474. }
  475. }
  476. static void
  477. dispose(Fcall *t, uchar *buf, Plumbmsg *m, Ruleset *rs, Exec *e)
  478. {
  479. int i;
  480. char *err;
  481. qlock(&queue);
  482. err = nil;
  483. if(m->dst==nil || m->dst[0]=='\0'){
  484. err = Enoport;
  485. if(rs != nil)
  486. err = startup(rs, e);
  487. plumbfree(m);
  488. }else
  489. for(i=NQID; i<ndir; i++)
  490. if(strcmp(m->dst, dir[i].name) == 0){
  491. if(dir[i].nopen == 0){
  492. err = startup(rs, e);
  493. if(e!=nil && e->holdforclient)
  494. hold(m, &dir[i]);
  495. else
  496. plumbfree(m);
  497. }else{
  498. queuesend(&dir[i], m);
  499. drainqueue(&dir[i]);
  500. }
  501. break;
  502. }
  503. freeexec(e);
  504. qunlock(&queue);
  505. fsysrespond(t, buf, err);
  506. free(t);
  507. }
  508. static Fcall*
  509. fsysversion(Fcall *t, uchar *buf, Fid*)
  510. {
  511. if(t->msize < 256){
  512. fsysrespond(t, buf, "version: message size too small");
  513. return t;
  514. }
  515. if(t->msize < messagesize)
  516. messagesize = t->msize;
  517. t->msize = messagesize;
  518. if(strncmp(t->version, "9P2000", 6) != 0){
  519. fsysrespond(t, buf, "unrecognized 9P version");
  520. return t;
  521. }
  522. t->version = "9P2000";
  523. fsysrespond(t, buf, nil);
  524. return t;
  525. }
  526. static Fcall*
  527. fsysauth(Fcall *t, uchar *buf, Fid*)
  528. {
  529. fsysrespond(t, buf, "plumber: authentication not required");
  530. return t;
  531. }
  532. static Fcall*
  533. fsysattach(Fcall *t, uchar *buf, Fid *f)
  534. {
  535. Fcall out;
  536. if(strcmp(t->uname, user) != 0){
  537. fsysrespond(&out, buf, Eperm);
  538. return t;
  539. }
  540. f->busy = 1;
  541. f->open = 0;
  542. f->qid.type = QTDIR;
  543. f->qid.path = Qdir;
  544. f->qid.vers = 0;
  545. f->dir = dir;
  546. memset(&out, 0, sizeof(Fcall));
  547. out.type = t->type;
  548. out.tag = t->tag;
  549. out.fid = f->fid;
  550. out.qid = f->qid;
  551. fsysrespond(&out, buf, nil);
  552. return t;
  553. }
  554. static Fcall*
  555. fsysflush(Fcall *t, uchar *buf, Fid*)
  556. {
  557. int i;
  558. qlock(&queue);
  559. for(i=NQID; i<ndir; i++)
  560. flushqueue(&dir[i], t->oldtag);
  561. qunlock(&queue);
  562. fsysrespond(t, buf, nil);
  563. return t;
  564. }
  565. static Fcall*
  566. fsyswalk(Fcall *t, uchar *buf, Fid *f)
  567. {
  568. Fcall out;
  569. Fid *nf;
  570. ulong path;
  571. Dirtab *d, *dir;
  572. Qid q;
  573. int i;
  574. uchar type;
  575. char *err;
  576. if(f->open){
  577. fsysrespond(t, buf, "clone of an open fid");
  578. return t;
  579. }
  580. nf = nil;
  581. if(t->fid != t->newfid){
  582. nf = newfid(t->newfid);
  583. if(nf->busy){
  584. fsysrespond(t, buf, "clone to a busy fid");
  585. return t;
  586. }
  587. nf->busy = 1;
  588. nf->open = 0;
  589. nf->dir = f->dir;
  590. nf->qid = f->qid;
  591. f = nf; /* walk f */
  592. }
  593. out.nwqid = 0;
  594. err = nil;
  595. dir = f->dir;
  596. q = f->qid;
  597. if(t->nwname > 0){
  598. for(i=0; i<t->nwname; i++){
  599. if((q.type & QTDIR) == 0){
  600. err = Enotdir;
  601. break;
  602. }
  603. if(strcmp(t->wname[i], "..") == 0){
  604. type = QTDIR;
  605. path = Qdir;
  606. Accept:
  607. q.type = type;
  608. q.vers = 0;
  609. q.path = path;
  610. out.wqid[out.nwqid++] = q;
  611. continue;
  612. }
  613. d = dir;
  614. d++; /* skip '.' */
  615. for(; d->name; d++)
  616. if(strcmp(t->wname[i], d->name) == 0){
  617. type = d->type;
  618. path = d->qid;
  619. dir = d;
  620. goto Accept;
  621. }
  622. err = Enoexist;
  623. break;
  624. }
  625. }
  626. out.type = t->type;
  627. out.tag = t->tag;
  628. if(err!=nil || out.nwqid<t->nwname){
  629. if(nf)
  630. nf->busy = 0;
  631. }else if(out.nwqid == t->nwname){
  632. f->qid = q;
  633. f->dir = dir;
  634. }
  635. fsysrespond(&out, buf, err);
  636. return t;
  637. }
  638. static Fcall*
  639. fsysopen(Fcall *t, uchar *buf, Fid *f)
  640. {
  641. int m, clearrules, mode;
  642. clearrules = 0;
  643. if(t->mode & OTRUNC){
  644. if(f->qid.path != Qrules)
  645. goto Deny;
  646. clearrules = 1;
  647. }
  648. /* can't truncate anything, so just disregard */
  649. mode = t->mode & ~(OTRUNC|OCEXEC);
  650. /* can't execute or remove anything */
  651. if(mode==OEXEC || (mode&ORCLOSE))
  652. goto Deny;
  653. switch(mode){
  654. default:
  655. goto Deny;
  656. case OREAD:
  657. m = 0400;
  658. break;
  659. case OWRITE:
  660. m = 0200;
  661. break;
  662. case ORDWR:
  663. m = 0600;
  664. break;
  665. }
  666. if(((f->dir->perm&~(DMDIR|DMAPPEND))&m) != m)
  667. goto Deny;
  668. if(f->qid.path==Qrules && (mode==OWRITE || mode==ORDWR)){
  669. lock(&rulesref);
  670. if(rulesref.ref++ != 0){
  671. rulesref.ref--;
  672. unlock(&rulesref);
  673. fsysrespond(t, buf, Einuse);
  674. return t;
  675. }
  676. unlock(&rulesref);
  677. }
  678. if(clearrules){
  679. writerules(nil, 0);
  680. rules[0] = nil;
  681. }
  682. t->qid = f->qid;
  683. t->iounit = 0;
  684. qlock(&queue);
  685. f->mode = mode;
  686. f->open = 1;
  687. f->dir->nopen++;
  688. f->nextopen = f->dir->fopen;
  689. f->dir->fopen = f;
  690. queueheld(f->dir);
  691. qunlock(&queue);
  692. fsysrespond(t, buf, nil);
  693. return t;
  694. Deny:
  695. fsysrespond(t, buf, Eperm);
  696. return t;
  697. }
  698. static Fcall*
  699. fsyscreate(Fcall *t, uchar *buf, Fid*)
  700. {
  701. fsysrespond(t, buf, Eperm);
  702. return t;
  703. }
  704. static Fcall*
  705. fsysreadrules(Fcall *t, uchar *buf)
  706. {
  707. char *p;
  708. int n;
  709. p = printrules();
  710. n = strlen(p);
  711. t->data = p;
  712. if(t->offset >= n)
  713. t->count = 0;
  714. else{
  715. t->data = p+t->offset;
  716. if(t->offset+t->count > n)
  717. t->count = n-t->offset;
  718. }
  719. fsysrespond(t, buf, nil);
  720. free(p);
  721. return t;
  722. }
  723. static Fcall*
  724. fsysread(Fcall *t, uchar *buf, Fid *f)
  725. {
  726. uchar *b;
  727. int i, n, o, e;
  728. uint len;
  729. Dirtab *d;
  730. uint clock;
  731. if(f->qid.path != Qdir){
  732. if(f->qid.path == Qrules)
  733. return fsysreadrules(t, buf);
  734. /* read from port */
  735. if(f->qid.path < NQID){
  736. fsysrespond(t, buf, "internal error: unknown read port");
  737. return t;
  738. }
  739. qlock(&queue);
  740. queueread(f->dir, t, buf, f);
  741. drainqueue(f->dir);
  742. qunlock(&queue);
  743. return nil;
  744. }
  745. o = t->offset;
  746. e = t->offset+t->count;
  747. clock = getclock();
  748. b = malloc(messagesize-IOHDRSZ);
  749. if(b == nil){
  750. fsysrespond(t, buf, Enomem);
  751. return t;
  752. }
  753. n = 0;
  754. d = dir;
  755. d++; /* first entry is '.' */
  756. for(i=0; d->name!=nil && i<e; i+=len){
  757. len = dostat(d, b+n, messagesize-IOHDRSZ-n, clock);
  758. if(len <= BIT16SZ)
  759. break;
  760. if(i >= o)
  761. n += len;
  762. d++;
  763. }
  764. t->data = (char*)b;
  765. t->count = n;
  766. fsysrespond(t, buf, nil);
  767. free(b);
  768. return t;
  769. }
  770. static Fcall*
  771. fsyswrite(Fcall *t, uchar *buf, Fid *f)
  772. {
  773. Plumbmsg *m;
  774. int i, n;
  775. long count;
  776. char *data;
  777. Exec *e;
  778. switch((int)f->qid.path){
  779. case Qdir:
  780. fsysrespond(t, buf, Eisdir);
  781. return t;
  782. case Qrules:
  783. clock = getclock();
  784. fsysrespond(t, buf, writerules(t->data, t->count));
  785. return t;
  786. case Qsend:
  787. if(f->offset == 0){
  788. data = t->data;
  789. count = t->count;
  790. }else{
  791. /* partial message already assembled */
  792. f->writebuf = erealloc(f->writebuf, f->offset + t->count);
  793. memmove(f->writebuf+f->offset, t->data, t->count);
  794. data = f->writebuf;
  795. count = f->offset+t->count;
  796. }
  797. m = plumbunpackpartial(data, count, &n);
  798. if(m == nil){
  799. if(n == 0){
  800. f->offset = 0;
  801. free(f->writebuf);
  802. f->writebuf = nil;
  803. fsysrespond(t, buf, Ebadmsg);
  804. return t;
  805. }
  806. /* can read more... */
  807. if(f->offset == 0){
  808. f->writebuf = emalloc(t->count);
  809. memmove(f->writebuf, t->data, t->count);
  810. }
  811. /* else buffer has already been grown */
  812. f->offset += t->count;
  813. fsysrespond(t, buf, nil);
  814. return t;
  815. }
  816. /* release partial buffer */
  817. f->offset = 0;
  818. free(f->writebuf);
  819. f->writebuf = nil;
  820. for(i=0; rules[i]; i++)
  821. if((e=matchruleset(m, rules[i])) != nil){
  822. dispose(t, buf, m, rules[i], e);
  823. return nil;
  824. }
  825. if(m->dst != nil){
  826. dispose(t, buf, m, nil, nil);
  827. return nil;
  828. }
  829. fsysrespond(t, buf, "no matching plumb rule");
  830. return t;
  831. }
  832. fsysrespond(t, buf, "internal error: write to unknown file");
  833. return t;
  834. }
  835. static Fcall*
  836. fsysstat(Fcall *t, uchar *buf, Fid *f)
  837. {
  838. t->stat = emalloc(messagesize-IOHDRSZ);
  839. t->nstat = dostat(f->dir, t->stat, messagesize-IOHDRSZ, clock);
  840. fsysrespond(t, buf, nil);
  841. free(t->stat);
  842. t->stat = nil;
  843. return t;
  844. }
  845. static Fcall*
  846. fsyswstat(Fcall *t, uchar *buf, Fid*)
  847. {
  848. fsysrespond(t, buf, Eperm);
  849. return t;
  850. }
  851. static Fcall*
  852. fsysremove(Fcall *t, uchar *buf, Fid*)
  853. {
  854. fsysrespond(t, buf, Eperm);
  855. return t;
  856. }
  857. static Fcall*
  858. fsysclunk(Fcall *t, uchar *buf, Fid *f)
  859. {
  860. Fid *prev, *p;
  861. Dirtab *d;
  862. qlock(&queue);
  863. if(f->open){
  864. d = f->dir;
  865. d->nopen--;
  866. if(d->qid==Qrules && (f->mode==OWRITE || f->mode==ORDWR)){
  867. /*
  868. * just to be sure last rule is parsed; error messages will be lost, though,
  869. * unless last write ended with a blank line
  870. */
  871. writerules(nil, 0);
  872. lock(&rulesref);
  873. rulesref.ref--;
  874. unlock(&rulesref);
  875. }
  876. prev = nil;
  877. for(p=d->fopen; p; p=p->nextopen){
  878. if(p == f){
  879. if(prev)
  880. prev->nextopen = f->nextopen;
  881. else
  882. d->fopen = f->nextopen;
  883. removesenders(d, f);
  884. break;
  885. }
  886. prev = p;
  887. }
  888. }
  889. f->busy = 0;
  890. f->open = 0;
  891. f->offset = 0;
  892. if(f->writebuf != nil){
  893. free(f->writebuf);
  894. f->writebuf = nil;
  895. }
  896. qunlock(&queue);
  897. fsysrespond(t, buf, nil);
  898. return t;
  899. }