fsys.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <draw.h>
  4. #include <thread.h>
  5. #include <cursor.h>
  6. #include <mouse.h>
  7. #include <keyboard.h>
  8. #include <frame.h>
  9. #include <fcall.h>
  10. #include "dat.h"
  11. #include "fns.h"
  12. char Eperm[] = "permission denied";
  13. char Eexist[] = "file does not exist";
  14. char Enotdir[] = "not a directory";
  15. char Ebadfcall[] = "bad fcall type";
  16. char Eoffset[] = "illegal offset";
  17. int messagesize = 8192+IOHDRSZ; /* good start */
  18. enum{
  19. DEBUG = 0
  20. };
  21. Dirtab dirtab[]=
  22. {
  23. { ".", QTDIR, Qdir, 0500|DMDIR },
  24. { "cons", QTFILE, Qcons, 0600 },
  25. { "cursor", QTFILE, Qcursor, 0600 },
  26. { "consctl", QTFILE, Qconsctl, 0200 },
  27. { "winid", QTFILE, Qwinid, 0400 },
  28. { "winname", QTFILE, Qwinname, 0400 },
  29. { "kbdin", QTFILE, Qkbdin, 0200 },
  30. { "label", QTFILE, Qlabel, 0600 },
  31. { "mouse", QTFILE, Qmouse, 0600 },
  32. { "screen", QTFILE, Qscreen, 0400 },
  33. { "snarf", QTFILE, Qsnarf, 0600 },
  34. { "text", QTFILE, Qtext, 0400 },
  35. { "wdir", QTFILE, Qwdir, 0600 },
  36. { "wctl", QTFILE, Qwctl, 0600 },
  37. { "window", QTFILE, Qwindow, 0400 },
  38. { "wsys", QTDIR, Qwsys, 0500|DMDIR },
  39. { nil, }
  40. };
  41. static uint getclock(void);
  42. static void filsysproc(void*);
  43. static Fid* newfid(Filsys*, int);
  44. static int dostat(Filsys*, int, Dirtab*, uchar*, int, uint);
  45. int clockfd;
  46. int firstmessage = 1;
  47. char srvpipe[64];
  48. char srvwctl[64];
  49. static Xfid* filsysflush(Filsys*, Xfid*, Fid*);
  50. static Xfid* filsysversion(Filsys*, Xfid*, Fid*);
  51. static Xfid* filsysauth(Filsys*, Xfid*, Fid*);
  52. static Xfid* filsysnop(Filsys*, Xfid*, Fid*);
  53. static Xfid* filsysattach(Filsys*, Xfid*, Fid*);
  54. static Xfid* filsyswalk(Filsys*, Xfid*, Fid*);
  55. static Xfid* filsysopen(Filsys*, Xfid*, Fid*);
  56. static Xfid* filsyscreate(Filsys*, Xfid*, Fid*);
  57. static Xfid* filsysread(Filsys*, Xfid*, Fid*);
  58. static Xfid* filsyswrite(Filsys*, Xfid*, Fid*);
  59. static Xfid* filsysclunk(Filsys*, Xfid*, Fid*);
  60. static Xfid* filsysremove(Filsys*, Xfid*, Fid*);
  61. static Xfid* filsysstat(Filsys*, Xfid*, Fid*);
  62. static Xfid* filsyswstat(Filsys*, Xfid*, Fid*);
  63. Xfid* (*fcall[Tmax])(Filsys*, Xfid*, Fid*) =
  64. {
  65. [Tflush] = filsysflush,
  66. [Tversion] = filsysversion,
  67. [Tauth] = filsysauth,
  68. [Tattach] = filsysattach,
  69. [Twalk] = filsyswalk,
  70. [Topen] = filsysopen,
  71. [Tcreate] = filsyscreate,
  72. [Tread] = filsysread,
  73. [Twrite] = filsyswrite,
  74. [Tclunk] = filsysclunk,
  75. [Tremove]= filsysremove,
  76. [Tstat] = filsysstat,
  77. [Twstat] = filsyswstat,
  78. };
  79. void
  80. post(char *name, char *envname, int srvfd)
  81. {
  82. int fd;
  83. char buf[32];
  84. fd = create(name, OWRITE|ORCLOSE|OCEXEC, 0600);
  85. if(fd < 0)
  86. error(name);
  87. sprint(buf, "%d",srvfd);
  88. if(write(fd, buf, strlen(buf)) != strlen(buf))
  89. error("srv write");
  90. putenv(envname, name);
  91. }
  92. /*
  93. * Build pipe with OCEXEC set on second fd.
  94. * Can't put it on both because we want to post one in /srv.
  95. */
  96. int
  97. cexecpipe(int *p0, int *p1)
  98. {
  99. /* pipe the hard way to get close on exec */
  100. if(bind("#|", "/mnt/temp", MREPL) < 0)
  101. return -1;
  102. *p0 = open("/mnt/temp/data", ORDWR);
  103. *p1 = open("/mnt/temp/data1", ORDWR|OCEXEC);
  104. unmount(nil, "/mnt/temp");
  105. if(*p0<0 || *p1<0)
  106. return -1;
  107. return 0;
  108. }
  109. Filsys*
  110. filsysinit(Channel *cxfidalloc)
  111. {
  112. int n, fd, pid, p0;
  113. Filsys *fs;
  114. Channel *c;
  115. char buf[128];
  116. fs = emalloc(sizeof(Filsys));
  117. if(cexecpipe(&fs->cfd, &fs->sfd) < 0)
  118. goto Rescue;
  119. fmtinstall('F', fcallfmt);
  120. clockfd = open("/dev/time", OREAD|OCEXEC);
  121. fd = open("/dev/user", OREAD);
  122. strcpy(buf, "Jean-Paul_Belmondo");
  123. if(fd >= 0){
  124. n = read(fd, buf, sizeof buf-1);
  125. if(n > 0)
  126. buf[n] = 0;
  127. close(fd);
  128. }
  129. fs->user = estrdup(buf);
  130. fs->cxfidalloc = cxfidalloc;
  131. pid = getpid();
  132. /*
  133. * Create and post wctl pipe
  134. */
  135. if(cexecpipe(&p0, &wctlfd) < 0)
  136. goto Rescue;
  137. sprint(srvwctl, "/srv/riowctl.%s.%d", fs->user, pid);
  138. post(srvwctl, "wctl", p0);
  139. close(p0);
  140. /*
  141. * Start server processes
  142. */
  143. c = chancreate(sizeof(char*), 0);
  144. if(c == nil)
  145. error("wctl channel");
  146. proccreate(wctlproc, c, 4096);
  147. threadcreate(wctlthread, c, 4096);
  148. proccreate(filsysproc, fs, 10000);
  149. /*
  150. * Post srv pipe
  151. */
  152. sprint(srvpipe, "/srv/rio.%s.%d", fs->user, pid);
  153. post(srvpipe, "wsys", fs->cfd);
  154. return fs;
  155. Rescue:
  156. free(fs);
  157. return nil;
  158. }
  159. static
  160. void
  161. filsysproc(void *arg)
  162. {
  163. int n;
  164. Xfid *x;
  165. Fid *f;
  166. Fcall t;
  167. uchar *buf;
  168. Filsys *fs;
  169. threadsetname("FILSYSPROC");
  170. fs = arg;
  171. fs->pid = getpid();
  172. x = nil;
  173. for(;;){
  174. buf = emalloc(messagesize+UTFmax); /* UTFmax for appending partial rune in xfidwrite */
  175. n = read9pmsg(fs->sfd, buf, messagesize);
  176. if(n <= 0){
  177. yield(); /* if threadexitsall'ing, will not return */
  178. fprint(2, "rio: %d: read9pmsg: %d %r\n", getpid(), n);
  179. errorshouldabort = 0;
  180. error("eof or i/o error on server channel");
  181. }
  182. if(x == nil){
  183. send(fs->cxfidalloc, nil);
  184. recv(fs->cxfidalloc, &x);
  185. x->fs = fs;
  186. }
  187. x->buf = buf;
  188. if(convM2S(buf, n, x) != n)
  189. error("convert error in convM2S");
  190. if(DEBUG)
  191. fprint(2, "rio:<-%F\n", &x->Fcall);
  192. if(fcall[x->type] == nil)
  193. x = filsysrespond(fs, x, &t, Ebadfcall);
  194. else{
  195. if(x->type==Tversion || x->type==Tauth)
  196. f = nil;
  197. else
  198. f = newfid(fs, x->fid);
  199. x->f = f;
  200. x = (*fcall[x->type])(fs, x, f);
  201. }
  202. firstmessage = 0;
  203. }
  204. }
  205. /*
  206. * Called only from a different FD group
  207. */
  208. int
  209. filsysmount(Filsys *fs, int id)
  210. {
  211. char buf[32];
  212. close(fs->sfd); /* close server end so mount won't hang if exiting */
  213. sprint(buf, "%d", id);
  214. if(mount(fs->cfd, -1, "/mnt/wsys", MREPL, buf) < 0){
  215. fprint(2, "mount failed: %r\n");
  216. return -1;
  217. }
  218. if(bind("/mnt/wsys", "/dev", MBEFORE) < 0){
  219. fprint(2, "bind failed: %r\n");
  220. return -1;
  221. }
  222. return 0;
  223. }
  224. Xfid*
  225. filsysrespond(Filsys *fs, Xfid *x, Fcall *t, char *err)
  226. {
  227. int n;
  228. if(err){
  229. t->type = Rerror;
  230. t->ename = err;
  231. }else
  232. t->type = x->type+1;
  233. t->fid = x->fid;
  234. t->tag = x->tag;
  235. if(x->buf == nil)
  236. x->buf = malloc(messagesize);
  237. n = convS2M(t, x->buf, messagesize);
  238. if(n <= 0)
  239. error("convert error in convS2M");
  240. if(write(fs->sfd, x->buf, n) != n)
  241. error("write error in respond");
  242. if(DEBUG)
  243. fprint(2, "rio:->%F\n", t);
  244. free(x->buf);
  245. x->buf = nil;
  246. return x;
  247. }
  248. void
  249. filsyscancel(Xfid *x)
  250. {
  251. if(x->buf){
  252. free(x->buf);
  253. x->buf = nil;
  254. }
  255. }
  256. static
  257. Xfid*
  258. filsysversion(Filsys *fs, Xfid *x, Fid*)
  259. {
  260. Fcall t;
  261. if(!firstmessage)
  262. return filsysrespond(x->fs, x, &t, "version request not first message");
  263. if(x->msize < 256)
  264. return filsysrespond(x->fs, x, &t, "version: message size too small");
  265. messagesize = x->msize;
  266. t.msize = messagesize;
  267. if(strncmp(x->version, "9P2000", 6) != 0)
  268. return filsysrespond(x->fs, x, &t, "unrecognized 9P version");
  269. t.version = "9P2000";
  270. return filsysrespond(fs, x, &t, nil);
  271. }
  272. static
  273. Xfid*
  274. filsysauth(Filsys *fs, Xfid *x, Fid*)
  275. {
  276. Fcall t;
  277. return filsysrespond(fs, x, &t, "rio: authentication not required");
  278. }
  279. static
  280. Xfid*
  281. filsysflush(Filsys*, Xfid *x, Fid*)
  282. {
  283. sendp(x->c, xfidflush);
  284. return nil;
  285. }
  286. static
  287. Xfid*
  288. filsysattach(Filsys *, Xfid *x, Fid *f)
  289. {
  290. Fcall t;
  291. if(strcmp(x->uname, x->fs->user) != 0)
  292. return filsysrespond(x->fs, x, &t, Eperm);
  293. f->busy = TRUE;
  294. f->open = FALSE;
  295. f->qid.path = Qdir;
  296. f->qid.type = QTDIR;
  297. f->qid.vers = 0;
  298. f->dir = dirtab;
  299. f->nrpart = 0;
  300. sendp(x->c, xfidattach);
  301. return nil;
  302. }
  303. static
  304. int
  305. numeric(char *s)
  306. {
  307. for(; *s!='\0'; s++)
  308. if(*s<'0' || '9'<*s)
  309. return 0;
  310. return 1;
  311. }
  312. static
  313. Xfid*
  314. filsyswalk(Filsys *fs, Xfid *x, Fid *f)
  315. {
  316. Fcall t;
  317. Fid *nf;
  318. int i, id;
  319. uchar type;
  320. ulong path;
  321. Dirtab *d, *dir;
  322. Window *w;
  323. char *err;
  324. Qid qid;
  325. if(f->open)
  326. return filsysrespond(fs, x, &t, "walk of open file");
  327. nf = nil;
  328. if(x->fid != x->newfid){
  329. /* BUG: check exists */
  330. nf = newfid(fs, x->newfid);
  331. if(nf->busy)
  332. return filsysrespond(fs, x, &t, "clone to busy fid");
  333. nf->busy = TRUE;
  334. nf->open = FALSE;
  335. nf->dir = f->dir;
  336. nf->qid = f->qid;
  337. nf->w = f->w;
  338. incref(f->w);
  339. nf->nrpart = 0; /* not open, so must be zero */
  340. f = nf; /* walk f */
  341. }
  342. t.nwqid = 0;
  343. err = nil;
  344. /* update f->qid, f->dir only if walk completes */
  345. qid = f->qid;
  346. dir = f->dir;
  347. if(x->nwname > 0){
  348. for(i=0; i<x->nwname; i++){
  349. if((qid.type & QTDIR) == 0){
  350. err = Enotdir;
  351. break;
  352. }
  353. if(strcmp(x->wname[i], "..") == 0){
  354. type = QTDIR;
  355. path = Qdir;
  356. dir = dirtab;
  357. if(FILE(qid) == Qwsysdir)
  358. path = Qwsys;
  359. id = 0;
  360. Accept:
  361. if(i == MAXWELEM){
  362. err = "name too long";
  363. break;
  364. }
  365. qid.type = type;
  366. qid.vers = 0;
  367. qid.path = QID(id, path);
  368. t.wqid[t.nwqid++] = qid;
  369. continue;
  370. }
  371. if(qid.path == Qwsys){
  372. /* is it a numeric name? */
  373. if(!numeric(x->wname[i]))
  374. break;
  375. /* yes: it's a directory */
  376. id = atoi(x->wname[i]);
  377. qlock(&all);
  378. w = wlookid(id);
  379. if(w == nil){
  380. qunlock(&all);
  381. break;
  382. }
  383. path = Qwsysdir;
  384. type = QTDIR;
  385. qunlock(&all);
  386. incref(w);
  387. sendp(winclosechan, f->w);
  388. f->w = w;
  389. dir = dirtab;
  390. goto Accept;
  391. }
  392. if(snarffd>=0 && strcmp(x->wname[i], "snarf")==0)
  393. break; /* don't serve /dev/snarf if it's provided in the environment */
  394. id = WIN(f->qid);
  395. d = dirtab;
  396. d++; /* skip '.' */
  397. for(; d->name; d++)
  398. if(strcmp(x->wname[i], d->name) == 0){
  399. path = d->qid;
  400. type = d->type;
  401. dir = d;
  402. goto Accept;
  403. }
  404. break; /* file not found */
  405. }
  406. if(i==0 && err==nil)
  407. err = Eexist;
  408. }
  409. if(err!=nil || t.nwqid<x->nwname){
  410. if(nf){
  411. if(nf->w)
  412. sendp(winclosechan, nf->w);
  413. nf->open = FALSE;
  414. nf->busy = FALSE;
  415. }
  416. }else if(t.nwqid == x->nwname){
  417. f->dir = dir;
  418. f->qid = qid;
  419. }
  420. return filsysrespond(fs, x, &t, err);
  421. }
  422. static
  423. Xfid*
  424. filsysopen(Filsys *fs, Xfid *x, Fid *f)
  425. {
  426. Fcall t;
  427. int m;
  428. /* can't truncate anything, so just disregard */
  429. x->mode &= ~(OTRUNC|OCEXEC);
  430. /* can't execute or remove anything */
  431. if(x->mode==OEXEC || (x->mode&ORCLOSE))
  432. goto Deny;
  433. switch(x->mode){
  434. default:
  435. goto Deny;
  436. case OREAD:
  437. m = 0400;
  438. break;
  439. case OWRITE:
  440. m = 0200;
  441. break;
  442. case ORDWR:
  443. m = 0600;
  444. break;
  445. }
  446. if(((f->dir->perm&~(DMDIR|DMAPPEND))&m) != m)
  447. goto Deny;
  448. sendp(x->c, xfidopen);
  449. return nil;
  450. Deny:
  451. return filsysrespond(fs, x, &t, Eperm);
  452. }
  453. static
  454. Xfid*
  455. filsyscreate(Filsys *fs, Xfid *x, Fid*)
  456. {
  457. Fcall t;
  458. return filsysrespond(fs, x, &t, Eperm);
  459. }
  460. static
  461. int
  462. idcmp(void *a, void *b)
  463. {
  464. return *(int*)a - *(int*)b;
  465. }
  466. static
  467. Xfid*
  468. filsysread(Filsys *fs, Xfid *x, Fid *f)
  469. {
  470. Fcall t;
  471. uchar *b;
  472. int i, n, o, e, len, j, k, *ids;
  473. Dirtab *d, dt;
  474. uint clock;
  475. char buf[16];
  476. if((f->qid.type & QTDIR) == 0){
  477. sendp(x->c, xfidread);
  478. return nil;
  479. }
  480. o = x->offset;
  481. e = x->offset+x->count;
  482. clock = getclock();
  483. b = malloc(messagesize-IOHDRSZ); /* avoid memset of emalloc */
  484. if(b == nil)
  485. return filsysrespond(fs, x, &t, "out of memory");
  486. n = 0;
  487. switch(FILE(f->qid)){
  488. case Qdir:
  489. case Qwsysdir:
  490. d = dirtab;
  491. d++; /* first entry is '.' */
  492. for(i=0; d->name!=nil && i<e; i+=len){
  493. len = dostat(fs, WIN(x->f->qid), d, b+n, x->count-n, clock);
  494. if(len <= BIT16SZ)
  495. break;
  496. if(i >= o)
  497. n += len;
  498. d++;
  499. }
  500. break;
  501. case Qwsys:
  502. qlock(&all);
  503. ids = emalloc(nwindow*sizeof(int));
  504. for(j=0; j<nwindow; j++)
  505. ids[j] = window[j]->id;
  506. qunlock(&all);
  507. qsort(ids, nwindow, sizeof ids[0], idcmp);
  508. dt.name = buf;
  509. for(i=0, j=0; j<nwindow && i<e; i+=len){
  510. k = ids[j];
  511. sprint(dt.name, "%d", k);
  512. dt.qid = QID(k, Qdir);
  513. dt.type = QTDIR;
  514. dt.perm = DMDIR|0700;
  515. len = dostat(fs, k, &dt, b+n, x->count-n, clock);
  516. if(len == 0)
  517. break;
  518. if(i >= o)
  519. n += len;
  520. j++;
  521. }
  522. free(ids);
  523. break;
  524. }
  525. t.data = (char*)b;
  526. t.count = n;
  527. filsysrespond(fs, x, &t, nil);
  528. free(b);
  529. return x;
  530. }
  531. static
  532. Xfid*
  533. filsyswrite(Filsys*, Xfid *x, Fid*)
  534. {
  535. sendp(x->c, xfidwrite);
  536. return nil;
  537. }
  538. static
  539. Xfid*
  540. filsysclunk(Filsys *fs, Xfid *x, Fid *f)
  541. {
  542. Fcall t;
  543. if(f->open){
  544. f->busy = FALSE;
  545. f->open = FALSE;
  546. sendp(x->c, xfidclose);
  547. return nil;
  548. }
  549. if(f->w)
  550. sendp(winclosechan, f->w);
  551. f->busy = FALSE;
  552. f->open = FALSE;
  553. return filsysrespond(fs, x, &t, nil);
  554. }
  555. static
  556. Xfid*
  557. filsysremove(Filsys *fs, Xfid *x, Fid*)
  558. {
  559. Fcall t;
  560. return filsysrespond(fs, x, &t, Eperm);
  561. }
  562. static
  563. Xfid*
  564. filsysstat(Filsys *fs, Xfid *x, Fid *f)
  565. {
  566. Fcall t;
  567. t.stat = emalloc(messagesize-IOHDRSZ);
  568. t.nstat = dostat(fs, WIN(x->f->qid), f->dir, t.stat, messagesize-IOHDRSZ, getclock());
  569. x = filsysrespond(fs, x, &t, nil);
  570. free(t.stat);
  571. return x;
  572. }
  573. static
  574. Xfid*
  575. filsyswstat(Filsys *fs, Xfid *x, Fid*)
  576. {
  577. Fcall t;
  578. return filsysrespond(fs, x, &t, Eperm);
  579. }
  580. static
  581. Fid*
  582. newfid(Filsys *fs, int fid)
  583. {
  584. Fid *f, *ff, **fh;
  585. ff = nil;
  586. fh = &fs->fids[fid&(Nhash-1)];
  587. for(f=*fh; f; f=f->next)
  588. if(f->fid == fid)
  589. return f;
  590. else if(ff==nil && f->busy==FALSE)
  591. ff = f;
  592. if(ff){
  593. ff->fid = fid;
  594. return ff;
  595. }
  596. f = emalloc(sizeof *f);
  597. f->fid = fid;
  598. f->next = *fh;
  599. *fh = f;
  600. return f;
  601. }
  602. static
  603. uint
  604. getclock(void)
  605. {
  606. char buf[32];
  607. seek(clockfd, 0, 0);
  608. read(clockfd, buf, sizeof buf);
  609. return atoi(buf);
  610. }
  611. static
  612. int
  613. dostat(Filsys *fs, int id, Dirtab *dir, uchar *buf, int nbuf, uint clock)
  614. {
  615. Dir d;
  616. d.qid.path = QID(id, dir->qid);
  617. if(dir->qid == Qsnarf)
  618. d.qid.vers = snarfversion;
  619. else
  620. d.qid.vers = 0;
  621. d.qid.type = dir->type;
  622. d.mode = dir->perm;
  623. d.length = 0; /* would be nice to do better */
  624. d.name = dir->name;
  625. d.uid = fs->user;
  626. d.gid = fs->user;
  627. d.muid = fs->user;
  628. d.atime = clock;
  629. d.mtime = clock;
  630. return convD2M(&d, buf, nbuf);
  631. }