fsys.c 13 KB

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